apex-code 0.0.1-alpha.1 → 0.0.1-alpha.11

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 (798) hide show
  1. package/CHANGELOG.md +482 -0
  2. package/README.md +75 -680
  3. package/dist/cli/args.d.ts +21 -1
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +119 -15
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/auth-command.d.ts.map +1 -1
  8. package/dist/cli/auth-command.js +3 -3
  9. package/dist/cli/auth-command.js.map +1 -1
  10. package/dist/cli/concurrent-session.d.ts +3 -0
  11. package/dist/cli/concurrent-session.d.ts.map +1 -0
  12. package/dist/cli/concurrent-session.js +13 -0
  13. package/dist/cli/concurrent-session.js.map +1 -0
  14. package/dist/cli/cost-command.d.ts +19 -0
  15. package/dist/cli/cost-command.d.ts.map +1 -0
  16. package/dist/cli/cost-command.js +107 -0
  17. package/dist/cli/cost-command.js.map +1 -0
  18. package/dist/cli/file-processor.d.ts.map +1 -1
  19. package/dist/cli/file-processor.js +2 -1
  20. package/dist/cli/file-processor.js.map +1 -1
  21. package/dist/cli/startup-ui.d.ts +1 -1
  22. package/dist/cli/startup-ui.d.ts.map +1 -1
  23. package/dist/cli/startup-ui.js +1 -2
  24. package/dist/cli/startup-ui.js.map +1 -1
  25. package/dist/cli.d.ts.map +1 -1
  26. package/dist/cli.js +99 -16
  27. package/dist/cli.js.map +1 -1
  28. package/dist/config.d.ts +5 -4
  29. package/dist/config.d.ts.map +1 -1
  30. package/dist/config.js +58 -24
  31. package/dist/config.js.map +1 -1
  32. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  33. package/dist/core/agent-session-runtime.js +2 -0
  34. package/dist/core/agent-session-runtime.js.map +1 -1
  35. package/dist/core/agent-session-services.d.ts +28 -0
  36. package/dist/core/agent-session-services.d.ts.map +1 -1
  37. package/dist/core/agent-session-services.js +140 -4
  38. package/dist/core/agent-session-services.js.map +1 -1
  39. package/dist/core/agent-session.d.ts +147 -9
  40. package/dist/core/agent-session.d.ts.map +1 -1
  41. package/dist/core/agent-session.js +440 -123
  42. package/dist/core/agent-session.js.map +1 -1
  43. package/dist/core/auth-storage.d.ts +4 -1
  44. package/dist/core/auth-storage.d.ts.map +1 -1
  45. package/dist/core/auth-storage.js +17 -14
  46. package/dist/core/auth-storage.js.map +1 -1
  47. package/dist/core/bash-executor.d.ts.map +1 -1
  48. package/dist/core/bash-executor.js +18 -10
  49. package/dist/core/bash-executor.js.map +1 -1
  50. package/dist/core/checkpoints/git-checkpoints.d.ts +33 -0
  51. package/dist/core/checkpoints/git-checkpoints.d.ts.map +1 -0
  52. package/dist/core/checkpoints/git-checkpoints.js +230 -0
  53. package/dist/core/checkpoints/git-checkpoints.js.map +1 -0
  54. package/dist/core/checkpoints/session-checkpoints.d.ts +23 -0
  55. package/dist/core/checkpoints/session-checkpoints.d.ts.map +1 -0
  56. package/dist/core/checkpoints/session-checkpoints.js +29 -0
  57. package/dist/core/checkpoints/session-checkpoints.js.map +1 -0
  58. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  59. package/dist/core/compaction/branch-summarization.js +3 -0
  60. package/dist/core/compaction/branch-summarization.js.map +1 -1
  61. package/dist/core/compaction/compaction.d.ts +4 -3
  62. package/dist/core/compaction/compaction.d.ts.map +1 -1
  63. package/dist/core/compaction/compaction.js +41 -32
  64. package/dist/core/compaction/compaction.js.map +1 -1
  65. package/dist/core/context/deferred-schemas.d.ts +92 -0
  66. package/dist/core/context/deferred-schemas.d.ts.map +1 -0
  67. package/dist/core/context/deferred-schemas.js +74 -0
  68. package/dist/core/context/deferred-schemas.js.map +1 -0
  69. package/dist/core/context/eviction.d.ts +47 -0
  70. package/dist/core/context/eviction.d.ts.map +1 -0
  71. package/dist/core/context/eviction.js +83 -0
  72. package/dist/core/context/eviction.js.map +1 -0
  73. package/dist/core/context/pipeline.d.ts +90 -0
  74. package/dist/core/context/pipeline.d.ts.map +1 -0
  75. package/dist/core/context/pipeline.js +109 -0
  76. package/dist/core/context/pipeline.js.map +1 -0
  77. package/dist/core/credential-failover.d.ts +30 -0
  78. package/dist/core/credential-failover.d.ts.map +1 -0
  79. package/dist/core/credential-failover.js +46 -0
  80. package/dist/core/credential-failover.js.map +1 -0
  81. package/dist/core/credential-pool.d.ts +60 -0
  82. package/dist/core/credential-pool.d.ts.map +1 -0
  83. package/dist/core/credential-pool.js +84 -0
  84. package/dist/core/credential-pool.js.map +1 -0
  85. package/dist/core/defaults.d.ts +1 -0
  86. package/dist/core/defaults.d.ts.map +1 -1
  87. package/dist/core/defaults.js +9 -0
  88. package/dist/core/defaults.js.map +1 -1
  89. package/dist/core/delegation/agents.d.ts +15 -0
  90. package/dist/core/delegation/agents.d.ts.map +1 -0
  91. package/dist/core/delegation/agents.js +55 -0
  92. package/dist/core/delegation/agents.js.map +1 -0
  93. package/dist/core/delegation/ceiling.d.ts +29 -0
  94. package/dist/core/delegation/ceiling.d.ts.map +1 -0
  95. package/dist/core/delegation/ceiling.js +34 -0
  96. package/dist/core/delegation/ceiling.js.map +1 -0
  97. package/dist/core/delegation/runtime.d.ts +94 -0
  98. package/dist/core/delegation/runtime.d.ts.map +1 -0
  99. package/dist/core/delegation/runtime.js +117 -0
  100. package/dist/core/delegation/runtime.js.map +1 -0
  101. package/dist/core/durable-state/daemon.d.ts +37 -0
  102. package/dist/core/durable-state/daemon.d.ts.map +1 -0
  103. package/dist/core/durable-state/daemon.js +62 -0
  104. package/dist/core/durable-state/daemon.js.map +1 -0
  105. package/dist/core/durable-state/provenance.d.ts +7 -0
  106. package/dist/core/durable-state/provenance.d.ts.map +1 -0
  107. package/dist/core/durable-state/provenance.js +24 -0
  108. package/dist/core/durable-state/provenance.js.map +1 -0
  109. package/dist/core/durable-state/sqlite.d.ts +84 -0
  110. package/dist/core/durable-state/sqlite.d.ts.map +1 -0
  111. package/dist/core/durable-state/sqlite.js +355 -0
  112. package/dist/core/durable-state/sqlite.js.map +1 -0
  113. package/dist/core/environment.d.ts +12 -0
  114. package/dist/core/environment.d.ts.map +1 -0
  115. package/dist/core/environment.js +69 -0
  116. package/dist/core/environment.js.map +1 -0
  117. package/dist/core/evidence-policy.d.ts +17 -0
  118. package/dist/core/evidence-policy.d.ts.map +1 -0
  119. package/dist/core/evidence-policy.js +25 -0
  120. package/dist/core/evidence-policy.js.map +1 -0
  121. package/dist/core/evidence.d.ts +16 -0
  122. package/dist/core/evidence.d.ts.map +1 -0
  123. package/dist/core/evidence.js +51 -0
  124. package/dist/core/evidence.js.map +1 -0
  125. package/dist/core/exec.d.ts.map +1 -1
  126. package/dist/core/exec.js +5 -2
  127. package/dist/core/exec.js.map +1 -1
  128. package/dist/core/experimental.d.ts +4 -0
  129. package/dist/core/experimental.d.ts.map +1 -1
  130. package/dist/core/experimental.js +6 -1
  131. package/dist/core/experimental.js.map +1 -1
  132. package/dist/core/extensions/index.d.ts +2 -2
  133. package/dist/core/extensions/index.d.ts.map +1 -1
  134. package/dist/core/extensions/index.js +1 -1
  135. package/dist/core/extensions/index.js.map +1 -1
  136. package/dist/core/extensions/loader.d.ts.map +1 -1
  137. package/dist/core/extensions/loader.js +122 -49
  138. package/dist/core/extensions/loader.js.map +1 -1
  139. package/dist/core/extensions/types.d.ts +44 -9
  140. package/dist/core/extensions/types.d.ts.map +1 -1
  141. package/dist/core/extensions/types.js +3 -0
  142. package/dist/core/extensions/types.js.map +1 -1
  143. package/dist/core/footer-data-provider.d.ts +1 -1
  144. package/dist/core/footer-data-provider.d.ts.map +1 -1
  145. package/dist/core/footer-data-provider.js +1 -1
  146. package/dist/core/footer-data-provider.js.map +1 -1
  147. package/dist/core/http-dispatcher.d.ts +1 -2
  148. package/dist/core/http-dispatcher.d.ts.map +1 -1
  149. package/dist/core/http-dispatcher.js +2 -17
  150. package/dist/core/http-dispatcher.js.map +1 -1
  151. package/dist/core/http-idle-timeout.d.ts +12 -0
  152. package/dist/core/http-idle-timeout.d.ts.map +1 -0
  153. package/dist/core/http-idle-timeout.js +27 -0
  154. package/dist/core/http-idle-timeout.js.map +1 -0
  155. package/dist/core/index.d.ts +1 -0
  156. package/dist/core/index.d.ts.map +1 -1
  157. package/dist/core/index.js +1 -0
  158. package/dist/core/index.js.map +1 -1
  159. package/dist/core/keybindings.d.ts +38 -13
  160. package/dist/core/keybindings.d.ts.map +1 -1
  161. package/dist/core/keybindings.js +26 -5
  162. package/dist/core/keybindings.js.map +1 -1
  163. package/dist/core/lsp/client.d.ts +78 -0
  164. package/dist/core/lsp/client.d.ts.map +1 -0
  165. package/dist/core/lsp/client.js +494 -0
  166. package/dist/core/lsp/client.js.map +1 -0
  167. package/dist/core/lsp/diagnostics.d.ts +47 -0
  168. package/dist/core/lsp/diagnostics.d.ts.map +1 -0
  169. package/dist/core/lsp/diagnostics.js +224 -0
  170. package/dist/core/lsp/diagnostics.js.map +1 -0
  171. package/dist/core/lsp/pool.d.ts +48 -0
  172. package/dist/core/lsp/pool.d.ts.map +1 -0
  173. package/dist/core/lsp/pool.js +150 -0
  174. package/dist/core/lsp/pool.js.map +1 -0
  175. package/dist/core/lsp/registry.d.ts +49 -0
  176. package/dist/core/lsp/registry.d.ts.map +1 -0
  177. package/dist/core/lsp/registry.js +215 -0
  178. package/dist/core/lsp/registry.js.map +1 -0
  179. package/dist/core/lsp/status.d.ts +23 -0
  180. package/dist/core/lsp/status.d.ts.map +1 -0
  181. package/dist/core/lsp/status.js +35 -0
  182. package/dist/core/lsp/status.js.map +1 -0
  183. package/dist/core/lsp/sync.d.ts +13 -0
  184. package/dist/core/lsp/sync.d.ts.map +1 -0
  185. package/dist/core/lsp/sync.js +71 -0
  186. package/dist/core/lsp/sync.js.map +1 -0
  187. package/dist/core/mcp/config.d.ts +16 -0
  188. package/dist/core/mcp/config.d.ts.map +1 -0
  189. package/dist/core/mcp/config.js +152 -0
  190. package/dist/core/mcp/config.js.map +1 -0
  191. package/dist/core/mcp/connector.d.ts +10 -0
  192. package/dist/core/mcp/connector.d.ts.map +1 -0
  193. package/dist/core/mcp/connector.js +70 -0
  194. package/dist/core/mcp/connector.js.map +1 -0
  195. package/dist/core/mcp/contract.d.ts +19 -0
  196. package/dist/core/mcp/contract.d.ts.map +1 -0
  197. package/dist/core/mcp/contract.js +89 -0
  198. package/dist/core/mcp/contract.js.map +1 -0
  199. package/dist/core/mcp/mcp-tool.d.ts +32 -0
  200. package/dist/core/mcp/mcp-tool.d.ts.map +1 -0
  201. package/dist/core/mcp/mcp-tool.js +165 -0
  202. package/dist/core/mcp/mcp-tool.js.map +1 -0
  203. package/dist/core/mcp/metadata-cache.d.ts +29 -0
  204. package/dist/core/mcp/metadata-cache.d.ts.map +1 -0
  205. package/dist/core/mcp/metadata-cache.js +99 -0
  206. package/dist/core/mcp/metadata-cache.js.map +1 -0
  207. package/dist/core/mcp/runtime.d.ts +18 -0
  208. package/dist/core/mcp/runtime.d.ts.map +1 -0
  209. package/dist/core/mcp/runtime.js +35 -0
  210. package/dist/core/mcp/runtime.js.map +1 -0
  211. package/dist/core/mcp/schema.d.ts +22 -0
  212. package/dist/core/mcp/schema.d.ts.map +1 -0
  213. package/dist/core/mcp/schema.js +20 -0
  214. package/dist/core/mcp/schema.js.map +1 -0
  215. package/dist/core/mcp/server-manager.d.ts +43 -0
  216. package/dist/core/mcp/server-manager.d.ts.map +1 -0
  217. package/dist/core/mcp/server-manager.js +142 -0
  218. package/dist/core/mcp/server-manager.js.map +1 -0
  219. package/dist/core/mcp/types.d.ts +98 -0
  220. package/dist/core/mcp/types.d.ts.map +1 -0
  221. package/dist/core/mcp/types.js +8 -0
  222. package/dist/core/mcp/types.js.map +1 -0
  223. package/dist/core/model-config.d.ts +18 -0
  224. package/dist/core/model-config.d.ts.map +1 -1
  225. package/dist/core/model-config.js +25 -6
  226. package/dist/core/model-config.js.map +1 -1
  227. package/dist/core/model-resolver.d.ts +21 -0
  228. package/dist/core/model-resolver.d.ts.map +1 -1
  229. package/dist/core/model-resolver.js +73 -8
  230. package/dist/core/model-resolver.js.map +1 -1
  231. package/dist/core/model-runtime.d.ts +73 -0
  232. package/dist/core/model-runtime.d.ts.map +1 -1
  233. package/dist/core/model-runtime.js +225 -8
  234. package/dist/core/model-runtime.js.map +1 -1
  235. package/dist/core/models-store.d.ts.map +1 -1
  236. package/dist/core/models-store.js +2 -1
  237. package/dist/core/models-store.js.map +1 -1
  238. package/dist/core/observability/aggregate.d.ts +21 -0
  239. package/dist/core/observability/aggregate.d.ts.map +1 -0
  240. package/dist/core/observability/aggregate.js +36 -0
  241. package/dist/core/observability/aggregate.js.map +1 -0
  242. package/dist/core/observability/otlp.d.ts +66 -0
  243. package/dist/core/observability/otlp.d.ts.map +1 -0
  244. package/dist/core/observability/otlp.js +95 -0
  245. package/dist/core/observability/otlp.js.map +1 -0
  246. package/dist/core/package-manager.d.ts.map +1 -1
  247. package/dist/core/package-manager.js +40 -16
  248. package/dist/core/package-manager.js.map +1 -1
  249. package/dist/core/permissions/gate.d.ts +42 -0
  250. package/dist/core/permissions/gate.d.ts.map +1 -0
  251. package/dist/core/permissions/gate.js +72 -0
  252. package/dist/core/permissions/gate.js.map +1 -0
  253. package/dist/core/permissions/modes.d.ts +18 -0
  254. package/dist/core/permissions/modes.d.ts.map +1 -0
  255. package/dist/core/permissions/modes.js +57 -0
  256. package/dist/core/permissions/modes.js.map +1 -0
  257. package/dist/core/permissions/responder.d.ts +30 -0
  258. package/dist/core/permissions/responder.d.ts.map +1 -0
  259. package/dist/core/permissions/responder.js +32 -0
  260. package/dist/core/permissions/responder.js.map +1 -0
  261. package/dist/core/permissions/rules.d.ts +34 -0
  262. package/dist/core/permissions/rules.d.ts.map +1 -0
  263. package/dist/core/permissions/rules.js +74 -0
  264. package/dist/core/permissions/rules.js.map +1 -0
  265. package/dist/core/permissions/startup.d.ts +45 -0
  266. package/dist/core/permissions/startup.d.ts.map +1 -0
  267. package/dist/core/permissions/startup.js +63 -0
  268. package/dist/core/permissions/startup.js.map +1 -0
  269. package/dist/core/permissions/store.d.ts +114 -0
  270. package/dist/core/permissions/store.d.ts.map +1 -0
  271. package/dist/core/permissions/store.js +229 -0
  272. package/dist/core/permissions/store.js.map +1 -0
  273. package/dist/core/pi-manifest.d.ts.map +1 -1
  274. package/dist/core/pi-manifest.js +2 -1
  275. package/dist/core/pi-manifest.js.map +1 -1
  276. package/dist/core/project-trust.d.ts.map +1 -1
  277. package/dist/core/project-trust.js +1 -1
  278. package/dist/core/project-trust.js.map +1 -1
  279. package/dist/core/provider-attribution.d.ts.map +1 -1
  280. package/dist/core/provider-attribution.js +6 -7
  281. package/dist/core/provider-attribution.js.map +1 -1
  282. package/dist/core/remote-catalog-provider.d.ts +2 -2
  283. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  284. package/dist/core/remote-catalog-provider.js +22 -17
  285. package/dist/core/remote-catalog-provider.js.map +1 -1
  286. package/dist/core/resource-loader.d.ts.map +1 -1
  287. package/dist/core/resource-loader.js +3 -2
  288. package/dist/core/resource-loader.js.map +1 -1
  289. package/dist/core/sandbox/bwrap-arguments.d.ts +52 -0
  290. package/dist/core/sandbox/bwrap-arguments.d.ts.map +1 -0
  291. package/dist/core/sandbox/bwrap-arguments.js +86 -0
  292. package/dist/core/sandbox/bwrap-arguments.js.map +1 -0
  293. package/dist/core/sandbox/child-entry.d.ts +2 -0
  294. package/dist/core/sandbox/child-entry.d.ts.map +1 -0
  295. package/dist/core/sandbox/child-entry.js +22 -0
  296. package/dist/core/sandbox/child-entry.js.map +1 -0
  297. package/dist/core/sandbox/cli-launch.d.ts +88 -0
  298. package/dist/core/sandbox/cli-launch.d.ts.map +1 -0
  299. package/dist/core/sandbox/cli-launch.js +272 -0
  300. package/dist/core/sandbox/cli-launch.js.map +1 -0
  301. package/dist/core/sandbox/cli-supervisor.d.ts +30 -0
  302. package/dist/core/sandbox/cli-supervisor.d.ts.map +1 -0
  303. package/dist/core/sandbox/cli-supervisor.js +123 -0
  304. package/dist/core/sandbox/cli-supervisor.js.map +1 -0
  305. package/dist/core/sandbox/default-hosts.d.ts +28 -0
  306. package/dist/core/sandbox/default-hosts.d.ts.map +1 -0
  307. package/dist/core/sandbox/default-hosts.js +69 -0
  308. package/dist/core/sandbox/default-hosts.js.map +1 -0
  309. package/dist/core/sandbox/full-access.d.ts +28 -0
  310. package/dist/core/sandbox/full-access.d.ts.map +1 -0
  311. package/dist/core/sandbox/full-access.js +63 -0
  312. package/dist/core/sandbox/full-access.js.map +1 -0
  313. package/dist/core/sandbox/git-identity.d.ts +57 -0
  314. package/dist/core/sandbox/git-identity.d.ts.map +1 -0
  315. package/dist/core/sandbox/git-identity.js +78 -0
  316. package/dist/core/sandbox/git-identity.js.map +1 -0
  317. package/dist/core/sandbox/host-approval.d.ts +42 -0
  318. package/dist/core/sandbox/host-approval.d.ts.map +1 -0
  319. package/dist/core/sandbox/host-approval.js +99 -0
  320. package/dist/core/sandbox/host-approval.js.map +1 -0
  321. package/dist/core/sandbox/linux-backend.d.ts +46 -0
  322. package/dist/core/sandbox/linux-backend.d.ts.map +1 -0
  323. package/dist/core/sandbox/linux-backend.js +304 -0
  324. package/dist/core/sandbox/linux-backend.js.map +1 -0
  325. package/dist/core/sandbox/macos-backend.d.ts +28 -0
  326. package/dist/core/sandbox/macos-backend.d.ts.map +1 -0
  327. package/dist/core/sandbox/macos-backend.js +313 -0
  328. package/dist/core/sandbox/macos-backend.js.map +1 -0
  329. package/dist/core/sandbox/network-proxy.d.ts +38 -0
  330. package/dist/core/sandbox/network-proxy.d.ts.map +1 -0
  331. package/dist/core/sandbox/network-proxy.js +153 -0
  332. package/dist/core/sandbox/network-proxy.js.map +1 -0
  333. package/dist/core/sandbox/network-refusal.d.ts +24 -0
  334. package/dist/core/sandbox/network-refusal.d.ts.map +1 -0
  335. package/dist/core/sandbox/network-refusal.js +72 -0
  336. package/dist/core/sandbox/network-refusal.js.map +1 -0
  337. package/dist/core/sandbox/policy.d.ts +40 -0
  338. package/dist/core/sandbox/policy.d.ts.map +1 -0
  339. package/dist/core/sandbox/policy.js +55 -0
  340. package/dist/core/sandbox/policy.js.map +1 -0
  341. package/dist/core/sandbox/profiles.d.ts +25 -0
  342. package/dist/core/sandbox/profiles.d.ts.map +1 -0
  343. package/dist/core/sandbox/profiles.js +23 -0
  344. package/dist/core/sandbox/profiles.js.map +1 -0
  345. package/dist/core/sandbox/rpc/command-client.d.ts +28 -0
  346. package/dist/core/sandbox/rpc/command-client.d.ts.map +1 -0
  347. package/dist/core/sandbox/rpc/command-client.js +86 -0
  348. package/dist/core/sandbox/rpc/command-client.js.map +1 -0
  349. package/dist/core/sandbox/rpc/command-proxy.d.ts +48 -0
  350. package/dist/core/sandbox/rpc/command-proxy.d.ts.map +1 -0
  351. package/dist/core/sandbox/rpc/command-proxy.js +120 -0
  352. package/dist/core/sandbox/rpc/command-proxy.js.map +1 -0
  353. package/dist/core/sandbox/rpc/credential-client.d.ts +20 -0
  354. package/dist/core/sandbox/rpc/credential-client.d.ts.map +1 -0
  355. package/dist/core/sandbox/rpc/credential-client.js +170 -0
  356. package/dist/core/sandbox/rpc/credential-client.js.map +1 -0
  357. package/dist/core/sandbox/rpc/credential-proxy.d.ts +44 -0
  358. package/dist/core/sandbox/rpc/credential-proxy.d.ts.map +1 -0
  359. package/dist/core/sandbox/rpc/credential-proxy.js +287 -0
  360. package/dist/core/sandbox/rpc/credential-proxy.js.map +1 -0
  361. package/dist/core/sandbox/rpc/framing.d.ts +35 -0
  362. package/dist/core/sandbox/rpc/framing.d.ts.map +1 -0
  363. package/dist/core/sandbox/rpc/framing.js +114 -0
  364. package/dist/core/sandbox/rpc/framing.js.map +1 -0
  365. package/dist/core/sandbox/rpc/git-credential-helper.d.ts +40 -0
  366. package/dist/core/sandbox/rpc/git-credential-helper.d.ts.map +1 -0
  367. package/dist/core/sandbox/rpc/git-credential-helper.js +152 -0
  368. package/dist/core/sandbox/rpc/git-credential-helper.js.map +1 -0
  369. package/dist/core/sandbox/rpc/git-credential-proxy.d.ts +48 -0
  370. package/dist/core/sandbox/rpc/git-credential-proxy.d.ts.map +1 -0
  371. package/dist/core/sandbox/rpc/git-credential-proxy.js +142 -0
  372. package/dist/core/sandbox/rpc/git-credential-proxy.js.map +1 -0
  373. package/dist/core/sandbox/supervisor-temp.d.ts +18 -0
  374. package/dist/core/sandbox/supervisor-temp.d.ts.map +1 -0
  375. package/dist/core/sandbox/supervisor-temp.js +21 -0
  376. package/dist/core/sandbox/supervisor-temp.js.map +1 -0
  377. package/dist/core/sandbox/supervisor.d.ts +51 -0
  378. package/dist/core/sandbox/supervisor.d.ts.map +1 -0
  379. package/dist/core/sandbox/supervisor.js +18 -0
  380. package/dist/core/sandbox/supervisor.js.map +1 -0
  381. package/dist/core/sandbox/terminal-handoff.d.ts +45 -0
  382. package/dist/core/sandbox/terminal-handoff.d.ts.map +1 -0
  383. package/dist/core/sandbox/terminal-handoff.js +176 -0
  384. package/dist/core/sandbox/terminal-handoff.js.map +1 -0
  385. package/dist/core/sandbox/terminal-size.d.ts +40 -0
  386. package/dist/core/sandbox/terminal-size.d.ts.map +1 -0
  387. package/dist/core/sandbox/terminal-size.js +105 -0
  388. package/dist/core/sandbox/terminal-size.js.map +1 -0
  389. package/dist/core/sandbox/violations.d.ts +23 -0
  390. package/dist/core/sandbox/violations.d.ts.map +1 -0
  391. package/dist/core/sandbox/violations.js +30 -0
  392. package/dist/core/sandbox/violations.js.map +1 -0
  393. package/dist/core/sdk.d.ts +32 -41
  394. package/dist/core/sdk.d.ts.map +1 -1
  395. package/dist/core/sdk.js +174 -6
  396. package/dist/core/sdk.js.map +1 -1
  397. package/dist/core/session-export.d.ts +4 -0
  398. package/dist/core/session-export.d.ts.map +1 -0
  399. package/dist/core/session-export.js +32 -0
  400. package/dist/core/session-export.js.map +1 -0
  401. package/dist/core/session-lease.d.ts +31 -0
  402. package/dist/core/session-lease.d.ts.map +1 -0
  403. package/dist/core/session-lease.js +138 -0
  404. package/dist/core/session-lease.js.map +1 -0
  405. package/dist/core/session-manager.d.ts +58 -2
  406. package/dist/core/session-manager.d.ts.map +1 -1
  407. package/dist/core/session-manager.js +92 -7
  408. package/dist/core/session-manager.js.map +1 -1
  409. package/dist/core/session-share.d.ts +31 -0
  410. package/dist/core/session-share.d.ts.map +1 -0
  411. package/dist/core/session-share.js +45 -0
  412. package/dist/core/session-share.js.map +1 -0
  413. package/dist/core/settings-diagnostics.d.ts +9 -0
  414. package/dist/core/settings-diagnostics.d.ts.map +1 -0
  415. package/dist/core/settings-diagnostics.js +21 -0
  416. package/dist/core/settings-diagnostics.js.map +1 -0
  417. package/dist/core/settings-manager.d.ts +99 -9
  418. package/dist/core/settings-manager.d.ts.map +1 -1
  419. package/dist/core/settings-manager.js +141 -36
  420. package/dist/core/settings-manager.js.map +1 -1
  421. package/dist/core/skills.d.ts +19 -7
  422. package/dist/core/skills.d.ts.map +1 -1
  423. package/dist/core/skills.js +128 -52
  424. package/dist/core/skills.js.map +1 -1
  425. package/dist/core/slash-commands.d.ts.map +1 -1
  426. package/dist/core/slash-commands.js +6 -2
  427. package/dist/core/slash-commands.js.map +1 -1
  428. package/dist/core/system-prompt.d.ts +2 -2
  429. package/dist/core/system-prompt.d.ts.map +1 -1
  430. package/dist/core/system-prompt.js +59 -68
  431. package/dist/core/system-prompt.js.map +1 -1
  432. package/dist/core/timings.d.ts +1 -1
  433. package/dist/core/timings.d.ts.map +1 -1
  434. package/dist/core/timings.js +3 -2
  435. package/dist/core/timings.js.map +1 -1
  436. package/dist/core/tools/ask-user.d.ts +25 -0
  437. package/dist/core/tools/ask-user.d.ts.map +1 -0
  438. package/dist/core/tools/ask-user.js +49 -0
  439. package/dist/core/tools/ask-user.js.map +1 -0
  440. package/dist/core/tools/bash-command-segments.d.ts +22 -0
  441. package/dist/core/tools/bash-command-segments.d.ts.map +1 -0
  442. package/dist/core/tools/bash-command-segments.js +128 -0
  443. package/dist/core/tools/bash-command-segments.js.map +1 -0
  444. package/dist/core/tools/bash.d.ts +40 -4
  445. package/dist/core/tools/bash.d.ts.map +1 -1
  446. package/dist/core/tools/bash.js +183 -32
  447. package/dist/core/tools/bash.js.map +1 -1
  448. package/dist/core/tools/contract-snapshot.d.ts +58 -0
  449. package/dist/core/tools/contract-snapshot.d.ts.map +1 -0
  450. package/dist/core/tools/contract-snapshot.js +51 -0
  451. package/dist/core/tools/contract-snapshot.js.map +1 -0
  452. package/dist/core/tools/contract.d.ts +185 -0
  453. package/dist/core/tools/contract.d.ts.map +1 -0
  454. package/dist/core/tools/contract.js +50 -0
  455. package/dist/core/tools/contract.js.map +1 -0
  456. package/dist/core/tools/delegate.d.ts +38 -0
  457. package/dist/core/tools/delegate.d.ts.map +1 -0
  458. package/dist/core/tools/delegate.js +90 -0
  459. package/dist/core/tools/delegate.js.map +1 -0
  460. package/dist/core/tools/diagnostics.d.ts +39 -0
  461. package/dist/core/tools/diagnostics.d.ts.map +1 -0
  462. package/dist/core/tools/diagnostics.js +62 -0
  463. package/dist/core/tools/diagnostics.js.map +1 -0
  464. package/dist/core/tools/edit-diff.d.ts +0 -5
  465. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  466. package/dist/core/tools/edit-diff.js +2 -5
  467. package/dist/core/tools/edit-diff.js.map +1 -1
  468. package/dist/core/tools/edit.d.ts +12 -2
  469. package/dist/core/tools/edit.d.ts.map +1 -1
  470. package/dist/core/tools/edit.js +61 -10
  471. package/dist/core/tools/edit.js.map +1 -1
  472. package/dist/core/tools/find.d.ts +2 -2
  473. package/dist/core/tools/find.d.ts.map +1 -1
  474. package/dist/core/tools/find.js +13 -1
  475. package/dist/core/tools/find.js.map +1 -1
  476. package/dist/core/tools/grep.d.ts +4 -2
  477. package/dist/core/tools/grep.d.ts.map +1 -1
  478. package/dist/core/tools/grep.js +47 -10
  479. package/dist/core/tools/grep.js.map +1 -1
  480. package/dist/core/tools/index.d.ts +60 -6
  481. package/dist/core/tools/index.d.ts.map +1 -1
  482. package/dist/core/tools/index.js +148 -2
  483. package/dist/core/tools/index.js.map +1 -1
  484. package/dist/core/tools/ls.d.ts +4 -2
  485. package/dist/core/tools/ls.d.ts.map +1 -1
  486. package/dist/core/tools/ls.js +17 -1
  487. package/dist/core/tools/ls.js.map +1 -1
  488. package/dist/core/tools/lsp.d.ts +62 -0
  489. package/dist/core/tools/lsp.d.ts.map +1 -0
  490. package/dist/core/tools/lsp.js +216 -0
  491. package/dist/core/tools/lsp.js.map +1 -0
  492. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  493. package/dist/core/tools/output-accumulator.js +1 -1
  494. package/dist/core/tools/output-accumulator.js.map +1 -1
  495. package/dist/core/tools/path-permission.d.ts +18 -0
  496. package/dist/core/tools/path-permission.d.ts.map +1 -0
  497. package/dist/core/tools/path-permission.js +28 -0
  498. package/dist/core/tools/path-permission.js.map +1 -0
  499. package/dist/core/tools/plan-present.d.ts +27 -0
  500. package/dist/core/tools/plan-present.d.ts.map +1 -0
  501. package/dist/core/tools/plan-present.js +55 -0
  502. package/dist/core/tools/plan-present.js.map +1 -0
  503. package/dist/core/tools/powershell.d.ts +16 -0
  504. package/dist/core/tools/powershell.d.ts.map +1 -0
  505. package/dist/core/tools/powershell.js +39 -0
  506. package/dist/core/tools/powershell.js.map +1 -0
  507. package/dist/core/tools/read.d.ts +2 -2
  508. package/dist/core/tools/read.d.ts.map +1 -1
  509. package/dist/core/tools/read.js +14 -0
  510. package/dist/core/tools/read.js.map +1 -1
  511. package/dist/core/tools/skill-search.d.ts +32 -0
  512. package/dist/core/tools/skill-search.d.ts.map +1 -0
  513. package/dist/core/tools/skill-search.js +56 -0
  514. package/dist/core/tools/skill-search.js.map +1 -0
  515. package/dist/core/tools/test.d.ts +34 -0
  516. package/dist/core/tools/test.d.ts.map +1 -0
  517. package/dist/core/tools/test.js +75 -0
  518. package/dist/core/tools/test.js.map +1 -0
  519. package/dist/core/tools/todo-write.d.ts +31 -0
  520. package/dist/core/tools/todo-write.d.ts.map +1 -0
  521. package/dist/core/tools/todo-write.js +51 -0
  522. package/dist/core/tools/todo-write.js.map +1 -0
  523. package/dist/core/tools/tool-definition-wrapper.d.ts +13 -2
  524. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  525. package/dist/core/tools/tool-definition-wrapper.js +11 -1
  526. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  527. package/dist/core/tools/tool-schema.d.ts +22 -0
  528. package/dist/core/tools/tool-schema.d.ts.map +1 -0
  529. package/dist/core/tools/tool-schema.js +45 -0
  530. package/dist/core/tools/tool-schema.js.map +1 -0
  531. package/dist/core/tools/web-fetch.d.ts +26 -0
  532. package/dist/core/tools/web-fetch.d.ts.map +1 -0
  533. package/dist/core/tools/web-fetch.js +62 -0
  534. package/dist/core/tools/web-fetch.js.map +1 -0
  535. package/dist/core/tools/web-search-exa.d.ts +33 -0
  536. package/dist/core/tools/web-search-exa.d.ts.map +1 -0
  537. package/dist/core/tools/web-search-exa.js +128 -0
  538. package/dist/core/tools/web-search-exa.js.map +1 -0
  539. package/dist/core/tools/web-search.d.ts +26 -0
  540. package/dist/core/tools/web-search.d.ts.map +1 -0
  541. package/dist/core/tools/web-search.js +53 -0
  542. package/dist/core/tools/web-search.js.map +1 -0
  543. package/dist/core/tools/write.d.ts +16 -2
  544. package/dist/core/tools/write.d.ts.map +1 -1
  545. package/dist/core/tools/write.js +48 -2
  546. package/dist/core/tools/write.js.map +1 -1
  547. package/dist/core/trust-manager.d.ts.map +1 -1
  548. package/dist/core/trust-manager.js +2 -1
  549. package/dist/core/trust-manager.js.map +1 -1
  550. package/dist/core/usage-performance-store.d.ts +56 -0
  551. package/dist/core/usage-performance-store.d.ts.map +1 -0
  552. package/dist/core/usage-performance-store.js +85 -0
  553. package/dist/core/usage-performance-store.js.map +1 -0
  554. package/dist/core/web-search-provider.d.ts +64 -0
  555. package/dist/core/web-search-provider.d.ts.map +1 -0
  556. package/dist/core/web-search-provider.js +149 -0
  557. package/dist/core/web-search-provider.js.map +1 -0
  558. package/dist/extensions/llama/index.d.ts.map +1 -1
  559. package/dist/extensions/llama/index.js +2 -0
  560. package/dist/extensions/llama/index.js.map +1 -1
  561. package/dist/extensions/llama/provider.d.ts.map +1 -1
  562. package/dist/extensions/llama/provider.js +6 -2
  563. package/dist/extensions/llama/provider.js.map +1 -1
  564. package/dist/index.d.ts +9 -6
  565. package/dist/index.d.ts.map +1 -1
  566. package/dist/index.js +7 -4
  567. package/dist/index.js.map +1 -1
  568. package/dist/main.d.ts +5 -0
  569. package/dist/main.d.ts.map +1 -1
  570. package/dist/main.js +87 -22
  571. package/dist/main.js.map +1 -1
  572. package/dist/migrations.d.ts.map +1 -1
  573. package/dist/migrations.js +6 -5
  574. package/dist/migrations.js.map +1 -1
  575. package/dist/modes/interactive/components/assistant-message.d.ts +29 -0
  576. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  577. package/dist/modes/interactive/components/assistant-message.js +182 -23
  578. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  579. package/dist/modes/interactive/components/bash-execution.d.ts +7 -0
  580. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  581. package/dist/modes/interactive/components/bash-execution.js +20 -0
  582. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  583. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  584. package/dist/modes/interactive/components/config-selector.js +9 -6
  585. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  586. package/dist/modes/interactive/components/custom-editor.d.ts +72 -1
  587. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  588. package/dist/modes/interactive/components/custom-editor.js +338 -1
  589. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  590. package/dist/modes/interactive/components/dynamic-border.d.ts +7 -1
  591. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  592. package/dist/modes/interactive/components/dynamic-border.js +11 -2
  593. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  594. package/dist/modes/interactive/components/extension-selector.d.ts +4 -0
  595. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  596. package/dist/modes/interactive/components/extension-selector.js +24 -6
  597. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  598. package/dist/modes/interactive/components/first-time-setup.d.ts +1 -4
  599. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  600. package/dist/modes/interactive/components/first-time-setup.js +17 -41
  601. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  602. package/dist/modes/interactive/components/first-use-hints.d.ts +8 -0
  603. package/dist/modes/interactive/components/first-use-hints.d.ts.map +1 -0
  604. package/dist/modes/interactive/components/first-use-hints.js +22 -0
  605. package/dist/modes/interactive/components/first-use-hints.js.map +1 -0
  606. package/dist/modes/interactive/components/footer.d.ts +31 -1
  607. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  608. package/dist/modes/interactive/components/footer.js +205 -24
  609. package/dist/modes/interactive/components/footer.js.map +1 -1
  610. package/dist/modes/interactive/components/index.d.ts +2 -0
  611. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  612. package/dist/modes/interactive/components/index.js +2 -0
  613. package/dist/modes/interactive/components/index.js.map +1 -1
  614. package/dist/modes/interactive/components/model-selector.d.ts +31 -9
  615. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  616. package/dist/modes/interactive/components/model-selector.js +236 -96
  617. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  618. package/dist/modes/interactive/components/settings-selector.d.ts +25 -5
  619. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  620. package/dist/modes/interactive/components/settings-selector.js +226 -58
  621. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  622. package/dist/modes/interactive/components/settings-submenu.d.ts +72 -0
  623. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -0
  624. package/dist/modes/interactive/components/settings-submenu.js +165 -0
  625. package/dist/modes/interactive/components/settings-submenu.js.map +1 -0
  626. package/dist/modes/interactive/components/splash-header.d.ts +66 -0
  627. package/dist/modes/interactive/components/splash-header.d.ts.map +1 -0
  628. package/dist/modes/interactive/components/splash-header.js +180 -0
  629. package/dist/modes/interactive/components/splash-header.js.map +1 -0
  630. package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
  631. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  632. package/dist/modes/interactive/components/thinking-selector.js +74 -17
  633. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  634. package/dist/modes/interactive/components/tool-execution.d.ts +28 -1
  635. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  636. package/dist/modes/interactive/components/tool-execution.js +144 -35
  637. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  638. package/dist/modes/interactive/components/tool-panel.d.ts +30 -0
  639. package/dist/modes/interactive/components/tool-panel.d.ts.map +1 -0
  640. package/dist/modes/interactive/components/tool-panel.js +130 -0
  641. package/dist/modes/interactive/components/tool-panel.js.map +1 -0
  642. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  643. package/dist/modes/interactive/external-editor.js +60 -10
  644. package/dist/modes/interactive/external-editor.js.map +1 -1
  645. package/dist/modes/interactive/interactive-mode.d.ts +90 -5
  646. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  647. package/dist/modes/interactive/interactive-mode.js +729 -206
  648. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  649. package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
  650. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
  651. package/dist/modes/interactive/model-catalog-refresh.js +34 -0
  652. package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
  653. package/dist/modes/interactive/theme/apex.json +93 -0
  654. package/dist/modes/interactive/theme/dark.json +2 -0
  655. package/dist/modes/interactive/theme/light.json +3 -1
  656. package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
  657. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  658. package/dist/modes/interactive/theme/theme-controller.js +25 -11
  659. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  660. package/dist/modes/interactive/theme/theme-schema.json +11 -3
  661. package/dist/modes/interactive/theme/theme.d.ts +14 -3
  662. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  663. package/dist/modes/interactive/theme/theme.js +65 -10
  664. package/dist/modes/interactive/theme/theme.js.map +1 -1
  665. package/dist/modes/json-event.d.ts +18 -12
  666. package/dist/modes/json-event.d.ts.map +1 -1
  667. package/dist/modes/json-event.js +22 -5
  668. package/dist/modes/json-event.js.map +1 -1
  669. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  670. package/dist/modes/rpc/rpc-mode.js +2 -1
  671. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  672. package/dist/package-manager-cli.d.ts +1 -0
  673. package/dist/package-manager-cli.d.ts.map +1 -1
  674. package/dist/package-manager-cli.js +210 -19
  675. package/dist/package-manager-cli.js.map +1 -1
  676. package/dist/rpc-entry.d.ts.map +1 -1
  677. package/dist/rpc-entry.js +2 -1
  678. package/dist/rpc-entry.js.map +1 -1
  679. package/dist/testing/replay/metrics.d.ts +24 -0
  680. package/dist/testing/replay/metrics.d.ts.map +1 -0
  681. package/dist/testing/replay/metrics.js +35 -0
  682. package/dist/testing/replay/metrics.js.map +1 -0
  683. package/dist/testing/replay/recorded-provider.d.ts +10 -0
  684. package/dist/testing/replay/recorded-provider.d.ts.map +1 -0
  685. package/dist/testing/replay/recorded-provider.js +108 -0
  686. package/dist/testing/replay/recorded-provider.js.map +1 -0
  687. package/dist/testing/replay/runner.d.ts +56 -0
  688. package/dist/testing/replay/runner.d.ts.map +1 -0
  689. package/dist/testing/replay/runner.js +406 -0
  690. package/dist/testing/replay/runner.js.map +1 -0
  691. package/dist/themes/apex-logo.d.ts +41 -0
  692. package/dist/themes/apex-logo.d.ts.map +1 -0
  693. package/dist/themes/apex-logo.js +35 -0
  694. package/dist/themes/apex-logo.js.map +1 -0
  695. package/dist/utils/apex-code-user-agent.d.ts +2 -0
  696. package/dist/utils/apex-code-user-agent.d.ts.map +1 -0
  697. package/dist/utils/apex-code-user-agent.js +5 -0
  698. package/dist/utils/apex-code-user-agent.js.map +1 -0
  699. package/dist/utils/changelog.d.ts +7 -2
  700. package/dist/utils/changelog.d.ts.map +1 -1
  701. package/dist/utils/changelog.js +82 -13
  702. package/dist/utils/changelog.js.map +1 -1
  703. package/dist/utils/clipboard-image.d.ts.map +1 -1
  704. package/dist/utils/clipboard-image.js +1 -1
  705. package/dist/utils/clipboard-image.js.map +1 -1
  706. package/dist/utils/frontmatter.d.ts.map +1 -1
  707. package/dist/utils/frontmatter.js +2 -1
  708. package/dist/utils/frontmatter.js.map +1 -1
  709. package/dist/utils/management-http.d.ts +5 -3
  710. package/dist/utils/management-http.d.ts.map +1 -1
  711. package/dist/utils/management-http.js +14 -10
  712. package/dist/utils/management-http.js.map +1 -1
  713. package/dist/utils/shell.d.ts +3 -0
  714. package/dist/utils/shell.d.ts.map +1 -1
  715. package/dist/utils/shell.js +17 -5
  716. package/dist/utils/shell.js.map +1 -1
  717. package/dist/utils/syntax-highlight.d.ts +1 -0
  718. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  719. package/dist/utils/syntax-highlight.js +60 -1
  720. package/dist/utils/syntax-highlight.js.map +1 -1
  721. package/dist/utils/text.d.ts +8 -0
  722. package/dist/utils/text.d.ts.map +1 -0
  723. package/dist/utils/text.js +9 -0
  724. package/dist/utils/text.js.map +1 -0
  725. package/dist/utils/tools-manager.d.ts +70 -2
  726. package/dist/utils/tools-manager.d.ts.map +1 -1
  727. package/dist/utils/tools-manager.js +280 -124
  728. package/dist/utils/tools-manager.js.map +1 -1
  729. package/dist/utils/version-check.d.ts +7 -5
  730. package/dist/utils/version-check.d.ts.map +1 -1
  731. package/dist/utils/version-check.js +27 -14
  732. package/dist/utils/version-check.js.map +1 -1
  733. package/dist/utils/windows-self-update.d.ts.map +1 -1
  734. package/dist/utils/windows-self-update.js +1 -1
  735. package/dist/utils/windows-self-update.js.map +1 -1
  736. package/docs/compaction.md +41 -24
  737. package/docs/containerization.md +24 -21
  738. package/docs/custom-provider.md +15 -12
  739. package/docs/development.md +11 -11
  740. package/docs/environment-variables.md +37 -77
  741. package/docs/extensions.md +68 -54
  742. package/docs/index.md +12 -24
  743. package/docs/json.md +18 -11
  744. package/docs/keybindings.md +18 -12
  745. package/docs/llama-cpp.md +9 -7
  746. package/docs/models.md +17 -11
  747. package/docs/packages.md +47 -43
  748. package/docs/prompt-templates.md +3 -3
  749. package/docs/providers.md +10 -10
  750. package/docs/quickstart.md +49 -32
  751. package/docs/rpc.md +35 -18
  752. package/docs/sdk.md +20 -6
  753. package/docs/security.md +18 -18
  754. package/docs/session-format.md +9 -9
  755. package/docs/sessions.md +13 -13
  756. package/docs/settings.md +83 -16
  757. package/docs/shell-aliases.md +1 -1
  758. package/docs/skills.md +66 -15
  759. package/docs/terminal-setup.md +44 -19
  760. package/docs/termux.md +4 -4
  761. package/docs/themes.md +32 -11
  762. package/docs/tmux.md +4 -4
  763. package/docs/tui.md +5 -5
  764. package/docs/usage.md +61 -53
  765. package/docs/windows.md +24 -2
  766. package/examples/extensions/border-status-editor.ts +1 -1
  767. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  768. package/examples/extensions/custom-provider-anthropic/package.json +2 -2
  769. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  770. package/examples/extensions/git-checkpoint.ts +24 -36
  771. package/examples/extensions/gondolin/package-lock.json +2 -2
  772. package/examples/extensions/gondolin/package.json +1 -1
  773. package/examples/extensions/notify.ts +3 -1
  774. package/examples/extensions/sandbox/package-lock.json +2 -2
  775. package/examples/extensions/sandbox/package.json +1 -1
  776. package/examples/extensions/subagent/README.md +3 -1
  777. package/examples/extensions/subagent/agents.ts +40 -9
  778. package/examples/extensions/subagent/index.ts +27 -4
  779. package/examples/extensions/titlebar-spinner.ts +1 -1
  780. package/examples/extensions/with-deps/package-lock.json +2 -2
  781. package/examples/extensions/with-deps/package.json +1 -1
  782. package/examples/rpc-extension-ui.ts +1 -1
  783. package/examples/sdk/06-extensions.ts +1 -1
  784. package/examples/sdk/README.md +1 -1
  785. package/npm-shrinkwrap.json +435 -452
  786. package/package.json +17 -18
  787. package/dist/core/telemetry.d.ts +0 -3
  788. package/dist/core/telemetry.d.ts.map +0 -1
  789. package/dist/core/telemetry.js +0 -9
  790. package/dist/core/telemetry.js.map +0 -1
  791. package/dist/server/create-harness.d.ts +0 -26
  792. package/dist/server/create-harness.d.ts.map +0 -1
  793. package/dist/server/create-harness.js +0 -104
  794. package/dist/server/create-harness.js.map +0 -1
  795. package/dist/utils/pi-user-agent.d.ts +0 -2
  796. package/dist/utils/pi-user-agent.d.ts.map +0 -1
  797. package/dist/utils/pi-user-agent.js +0 -5
  798. package/dist/utils/pi-user-agent.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-schema.d.ts","sourceRoot":"","sources":["../../../src/core/tools/tool-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGxD,QAAA,MAAM,UAAU;;EAEd,CAAC;AAIH,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IAClC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAC;IACpD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAO3F;AAED,mEAAmE;AACnE,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,kBAAkB,GAAG,kBAAkB,CAAC,OAAO,UAAU,CAAC,CAyBlH;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB;;aAEhE","sourcesContent":["import type { AgentToolResult } from \"apex-code-agent-core\";\nimport { type Static, Type } from \"typebox\";\nimport type { ApexToolDefinition } from \"./contract.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst toolSchema = Type.Object({\n\tname: Type.String({ description: \"Name of the active tool whose parameter schema is needed.\" }),\n});\n\ntype ToolSchemaInput = Static<typeof toolSchema>;\n\nexport interface ToolSchemaTarget {\n\tname: string;\n\tparameters: unknown;\n}\n\nexport interface ToolSchemaResolver {\n\tgetTool(name: string): ToolSchemaTarget | undefined;\n\tmarkLoaded(name: string): void;\n}\n\n/** Resolve one active tool schema and record that it is available on the next request. */\nexport function loadToolSchema(resolver: ToolSchemaResolver, name: string): ToolSchemaTarget {\n\tconst target = resolver.getTool(name);\n\tif (!target) {\n\t\tthrow new Error(`Cannot load schema for inactive or unknown tool \"${name}\"`);\n\t}\n\tresolver.markLoaded(name);\n\treturn target;\n}\n\n/** Create the model-callable schema loader settled by ADR 0011. */\nexport function createToolSchemaToolDefinition(resolver: ToolSchemaResolver): ApexToolDefinition<typeof toolSchema> {\n\treturn {\n\t\tname: \"tool_schema\",\n\t\tlabel: \"tool_schema\",\n\t\tdescription: \"Load the full parameter schema for an active tool before calling it.\",\n\t\tparameters: toolSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set(),\n\t\t\tpermission: {\n\t\t\t\tdefaultBehavior: \"allow\",\n\t\t\t\tmatches: () => false,\n\t\t\t\tdescribe: () => \"Loading a tool parameter schema\",\n\t\t\t\truleForCall: () => null,\n\t\t\t},\n\t\t\tcontext: { resultRecoverable: true, deferSchema: false },\n\t\t\tevidence: { emits: new Set(), capture: () => [] },\n\t\t},\n\t\tasync execute(_toolCallId, { name }: ToolSchemaInput): Promise<AgentToolResult<unknown>> {\n\t\t\tconst target = loadToolSchema(resolver, name);\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify({ name: target.name, parameters: target.parameters }) }],\n\t\t\t\tdetails: { name: target.name, parameters: target.parameters },\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport function createToolSchemaTool(resolver: ToolSchemaResolver) {\n\treturn wrapToolDefinition(createToolSchemaToolDefinition(resolver));\n}\n"]}
@@ -0,0 +1,45 @@
1
+ import { Type } from "typebox";
2
+ import { wrapToolDefinition } from "./tool-definition-wrapper.js";
3
+ const toolSchema = Type.Object({
4
+ name: Type.String({ description: "Name of the active tool whose parameter schema is needed." }),
5
+ });
6
+ /** Resolve one active tool schema and record that it is available on the next request. */
7
+ export function loadToolSchema(resolver, name) {
8
+ const target = resolver.getTool(name);
9
+ if (!target) {
10
+ throw new Error(`Cannot load schema for inactive or unknown tool "${name}"`);
11
+ }
12
+ resolver.markLoaded(name);
13
+ return target;
14
+ }
15
+ /** Create the model-callable schema loader settled by ADR 0011. */
16
+ export function createToolSchemaToolDefinition(resolver) {
17
+ return {
18
+ name: "tool_schema",
19
+ label: "tool_schema",
20
+ description: "Load the full parameter schema for an active tool before calling it.",
21
+ parameters: toolSchema,
22
+ contract: {
23
+ capabilities: new Set(),
24
+ permission: {
25
+ defaultBehavior: "allow",
26
+ matches: () => false,
27
+ describe: () => "Loading a tool parameter schema",
28
+ ruleForCall: () => null,
29
+ },
30
+ context: { resultRecoverable: true, deferSchema: false },
31
+ evidence: { emits: new Set(), capture: () => [] },
32
+ },
33
+ async execute(_toolCallId, { name }) {
34
+ const target = loadToolSchema(resolver, name);
35
+ return {
36
+ content: [{ type: "text", text: JSON.stringify({ name: target.name, parameters: target.parameters }) }],
37
+ details: { name: target.name, parameters: target.parameters },
38
+ };
39
+ },
40
+ };
41
+ }
42
+ export function createToolSchemaTool(resolver) {
43
+ return wrapToolDefinition(createToolSchemaToolDefinition(resolver));
44
+ }
45
+ //# sourceMappingURL=tool-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-schema.js","sourceRoot":"","sources":["../../../src/core/tools/tool-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;IAC9B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,2DAA2D,EAAE,CAAC;CAC/F,CAAC,CAAC;AAcH,0FAA0F;AAC1F,MAAM,UAAU,cAAc,CAAC,QAA4B,EAAE,IAAY,EAAoB;IAC5F,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,oDAAoD,IAAI,GAAG,CAAC,CAAC;IAC9E,CAAC;IACD,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC1B,OAAO,MAAM,CAAC;AAAA,CACd;AAED,mEAAmE;AACnE,MAAM,UAAU,8BAA8B,CAAC,QAA4B,EAAyC;IACnH,OAAO;QACN,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,sEAAsE;QACnF,UAAU,EAAE,UAAU;QACtB,QAAQ,EAAE;YACT,YAAY,EAAE,IAAI,GAAG,EAAE;YACvB,UAAU,EAAE;gBACX,eAAe,EAAE,OAAO;gBACxB,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK;gBACpB,QAAQ,EAAE,GAAG,EAAE,CAAC,iCAAiC;gBACjD,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI;aACvB;YACD,OAAO,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE;YACxD,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE;SACjD;QACD,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,IAAI,EAAmB,EAAqC;YACxF,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC9C,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;gBACvG,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE;aAC7D,CAAC;QAAA,CACF;KACD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,oBAAoB,CAAC,QAA4B,EAAE;IAClE,OAAO,kBAAkB,CAAC,8BAA8B,CAAC,QAAQ,CAAC,CAAC,CAAC;AAAA,CACpE","sourcesContent":["import type { AgentToolResult } from \"apex-code-agent-core\";\nimport { type Static, Type } from \"typebox\";\nimport type { ApexToolDefinition } from \"./contract.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst toolSchema = Type.Object({\n\tname: Type.String({ description: \"Name of the active tool whose parameter schema is needed.\" }),\n});\n\ntype ToolSchemaInput = Static<typeof toolSchema>;\n\nexport interface ToolSchemaTarget {\n\tname: string;\n\tparameters: unknown;\n}\n\nexport interface ToolSchemaResolver {\n\tgetTool(name: string): ToolSchemaTarget | undefined;\n\tmarkLoaded(name: string): void;\n}\n\n/** Resolve one active tool schema and record that it is available on the next request. */\nexport function loadToolSchema(resolver: ToolSchemaResolver, name: string): ToolSchemaTarget {\n\tconst target = resolver.getTool(name);\n\tif (!target) {\n\t\tthrow new Error(`Cannot load schema for inactive or unknown tool \"${name}\"`);\n\t}\n\tresolver.markLoaded(name);\n\treturn target;\n}\n\n/** Create the model-callable schema loader settled by ADR 0011. */\nexport function createToolSchemaToolDefinition(resolver: ToolSchemaResolver): ApexToolDefinition<typeof toolSchema> {\n\treturn {\n\t\tname: \"tool_schema\",\n\t\tlabel: \"tool_schema\",\n\t\tdescription: \"Load the full parameter schema for an active tool before calling it.\",\n\t\tparameters: toolSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set(),\n\t\t\tpermission: {\n\t\t\t\tdefaultBehavior: \"allow\",\n\t\t\t\tmatches: () => false,\n\t\t\t\tdescribe: () => \"Loading a tool parameter schema\",\n\t\t\t\truleForCall: () => null,\n\t\t\t},\n\t\t\tcontext: { resultRecoverable: true, deferSchema: false },\n\t\t\tevidence: { emits: new Set(), capture: () => [] },\n\t\t},\n\t\tasync execute(_toolCallId, { name }: ToolSchemaInput): Promise<AgentToolResult<unknown>> {\n\t\t\tconst target = loadToolSchema(resolver, name);\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify({ name: target.name, parameters: target.parameters }) }],\n\t\t\t\tdetails: { name: target.name, parameters: target.parameters },\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport function createToolSchemaTool(resolver: ToolSchemaResolver) {\n\treturn wrapToolDefinition(createToolSchemaToolDefinition(resolver));\n}\n"]}
@@ -0,0 +1,26 @@
1
+ import { type Static, Type } from "typebox";
2
+ import type { ApexToolDefinition } from "./contract.ts";
3
+ declare const webFetchSchema: Type.TObject<{
4
+ url: Type.TString;
5
+ }>;
6
+ export type WebFetchInput = Static<typeof webFetchSchema>;
7
+ export interface WebFetchDetails {
8
+ url: string;
9
+ status: number;
10
+ truncated: boolean;
11
+ }
12
+ export interface WebFetchOperations {
13
+ fetch(url: string, signal?: AbortSignal): Promise<{
14
+ status: number;
15
+ text: string;
16
+ }>;
17
+ }
18
+ export interface WebFetchToolOptions {
19
+ operations?: WebFetchOperations;
20
+ }
21
+ export declare function createWebFetchToolDefinition(options?: WebFetchToolOptions): ApexToolDefinition<typeof webFetchSchema, WebFetchDetails>;
22
+ export declare function createWebFetchTool(options?: WebFetchToolOptions): import("apex-code-agent-core").AgentTool<Type.TObject<{
23
+ url: Type.TString;
24
+ }>, WebFetchDetails>;
25
+ export {};
26
+ //# sourceMappingURL=web-fetch.d.ts.map
@@ -0,0 +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"]}
@@ -0,0 +1,62 @@
1
+ import { minimatch } from "minimatch";
2
+ import { Type } from "typebox";
3
+ import { wrapToolDefinition } from "./tool-definition-wrapper.js";
4
+ import { DEFAULT_MAX_BYTES, formatSize, truncateHead } from "./truncate.js";
5
+ const webFetchSchema = Type.Object({
6
+ url: Type.String({ description: "The absolute URL to fetch (including scheme, e.g. https://)." }),
7
+ });
8
+ /**
9
+ * Runs in the same process as every other tool -- the sandboxed child, not the
10
+ * supervisor. `globalThis.fetch` is undici's global fetch, made proxy-aware by
11
+ * `configureHttpDispatcher` (an `EnvHttpProxyAgent` reading HTTP_PROXY/HTTPS_PROXY)
12
+ * at CLI startup, including in `core/sandbox/child-entry.ts`'s sandboxed launch.
13
+ * That is what routes an allowed host through the sandbox's allowlist proxy and
14
+ * leaves a disallowed one with no route at all -- this tool does not implement or
15
+ * bypass that boundary itself; it only participates in it via the ordinary fetch
16
+ * path, deliberately never opening a raw socket that could sidestep the proxy.
17
+ */
18
+ const defaultWebFetchOperations = {
19
+ async fetch(url, signal) {
20
+ const response = await fetch(url, { signal });
21
+ return { status: response.status, text: await response.text() };
22
+ },
23
+ };
24
+ function hostAndPath(url) {
25
+ const parsed = new URL(url);
26
+ return `${parsed.hostname}${parsed.pathname}`;
27
+ }
28
+ export function createWebFetchToolDefinition(options) {
29
+ const ops = options?.operations ?? defaultWebFetchOperations;
30
+ return {
31
+ name: "web_fetch",
32
+ label: "web_fetch",
33
+ description: "Fetch the text contents of a URL over HTTP(S).",
34
+ parameters: webFetchSchema,
35
+ contract: {
36
+ capabilities: new Set(["net"]),
37
+ permission: {
38
+ defaultBehavior: "ask",
39
+ matches: (ruleContent, params) => minimatch(hostAndPath(params.url), ruleContent, { dot: true }),
40
+ describe: (ruleContent) => `Fetch URLs matching "${ruleContent}"`,
41
+ ruleForCall: (params) => hostAndPath(params.url),
42
+ },
43
+ context: { resultRecoverable: false, deferSchema: true },
44
+ evidence: { emits: new Set(), capture: () => [] },
45
+ },
46
+ async execute(_toolCallId, { url }, signal) {
47
+ const { status, text } = await ops.fetch(url, signal);
48
+ const truncation = truncateHead(text, { maxBytes: DEFAULT_MAX_BYTES });
49
+ const suffix = truncation.truncated
50
+ ? `\n\n[truncated: showing ${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}]`
51
+ : "";
52
+ return {
53
+ content: [{ type: "text", text: `${truncation.content}${suffix}` }],
54
+ details: { url, status, truncated: truncation.truncated },
55
+ };
56
+ },
57
+ };
58
+ }
59
+ export function createWebFetchTool(options) {
60
+ return wrapToolDefinition(createWebFetchToolDefinition(options));
61
+ }
62
+ //# sourceMappingURL=web-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-fetch.js","sourceRoot":"","sources":["../../../src/core/tools/web-fetch.ts"],"names":[],"mappings":"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","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"]}
@@ -0,0 +1,33 @@
1
+ import type { WebSearchOperations } from "./web-search.ts";
2
+ /** Exa's hosted search endpoint. */
3
+ export declare const EXA_SEARCH_ENDPOINT = "https://api.exa.ai/search";
4
+ /** Host of {@link EXA_SEARCH_ENDPOINT}, for the sandbox network allowlist. */
5
+ export declare const EXA_SEARCH_HOST = "api.exa.ai";
6
+ /** Exa's own default is 10; matching it keeps an unconfigured session predictable. */
7
+ export declare const DEFAULT_EXA_RESULT_COUNT = 10;
8
+ /**
9
+ * Snippet budget per result. Exa returns whole page text when asked, which is the
10
+ * wrong unit for a search result -- ten full pages would dwarf every other tool
11
+ * result in the context window. 800 characters is roughly a paragraph, enough for
12
+ * the model to judge relevance and decide whether to spend a `web_fetch` on it.
13
+ */
14
+ export declare const DEFAULT_EXA_SNIPPET_CHARACTERS = 800;
15
+ export interface ExaWebSearchOptions {
16
+ /** Resolved key, never a `$VAR` reference -- resolution happens before this call. */
17
+ apiKey: string;
18
+ /** Override for an Exa-compatible endpoint. Defaults to {@link EXA_SEARCH_ENDPOINT}. */
19
+ endpoint?: string;
20
+ numResults?: number;
21
+ snippetMaxCharacters?: number;
22
+ }
23
+ /**
24
+ * Exa-backed `web_search` backend.
25
+ *
26
+ * Reaches the network through `globalThis.fetch` for the same reason `web_fetch`
27
+ * does: that is the dispatcher `configureHttpDispatcher` made proxy-aware, so an
28
+ * allowlisted host routes through the sandbox proxy and a disallowed one has no
29
+ * route at all. Opening a raw socket here would sidestep a boundary this tool is
30
+ * supposed to sit behind.
31
+ */
32
+ export declare function createExaWebSearchOperations(options: ExaWebSearchOptions): WebSearchOperations;
33
+ //# sourceMappingURL=web-search-exa.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-search-exa.d.ts","sourceRoot":"","sources":["../../../src/core/tools/web-search-exa.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAmB,MAAM,iBAAiB,CAAC;AAE5E,oCAAoC;AACpC,eAAO,MAAM,mBAAmB,8BAA8B,CAAC;AAE/D,8EAA8E;AAC9E,eAAO,MAAM,eAAe,eAAe,CAAC;AAE5C,sFAAsF;AACtF,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD,MAAM,WAAW,mBAAmB;IACnC,qFAAqF;IACrF,MAAM,EAAE,MAAM,CAAC;IACf,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAwED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,mBAAmB,GAAG,mBAAmB,CAgD9F","sourcesContent":["import type { WebSearchOperations, WebSearchResult } from \"./web-search.ts\";\n\n/** Exa's hosted search endpoint. */\nexport const EXA_SEARCH_ENDPOINT = \"https://api.exa.ai/search\";\n\n/** Host of {@link EXA_SEARCH_ENDPOINT}, for the sandbox network allowlist. */\nexport const EXA_SEARCH_HOST = \"api.exa.ai\";\n\n/** Exa's own default is 10; matching it keeps an unconfigured session predictable. */\nexport const DEFAULT_EXA_RESULT_COUNT = 10;\n\n/**\n * Snippet budget per result. Exa returns whole page text when asked, which is the\n * wrong unit for a search result -- ten full pages would dwarf every other tool\n * result in the context window. 800 characters is roughly a paragraph, enough for\n * the model to judge relevance and decide whether to spend a `web_fetch` on it.\n */\nexport const DEFAULT_EXA_SNIPPET_CHARACTERS = 800;\n\nexport interface ExaWebSearchOptions {\n\t/** Resolved key, never a `$VAR` reference -- resolution happens before this call. */\n\tapiKey: string;\n\t/** Override for an Exa-compatible endpoint. Defaults to {@link EXA_SEARCH_ENDPOINT}. */\n\tendpoint?: string;\n\tnumResults?: number;\n\tsnippetMaxCharacters?: number;\n}\n\n/** Separator between highlights, which are non-contiguous passages rather than prose. */\nconst HIGHLIGHT_SEPARATOR = \" … \";\n\n/** The subset of Exa's `/search` response this adapter reads. */\ninterface ExaSearchResult {\n\ttitle?: string | null;\n\turl?: string | null;\n\ttext?: string | null;\n\thighlights?: string[] | null;\n}\n\ninterface ExaSearchResponse {\n\tresults?: ExaSearchResult[] | null;\n}\n\nfunction isAbortError(error: unknown): boolean {\n\treturn error instanceof Error && error.name === \"AbortError\";\n}\n\nfunction hostOf(endpoint: string): string {\n\ttry {\n\t\treturn new URL(endpoint).host;\n\t} catch {\n\t\treturn endpoint;\n\t}\n}\n\n/**\n * Text arrives with the source document's line structure intact. Collapsing it to a\n * single line costs nothing in meaning and keeps a ten-result list readable as a list\n * rather than ten wrapped blocks.\n */\nfunction toSnippet(text: string | null | undefined, maxCharacters: number): string {\n\tif (!text) return \"\";\n\tconst collapsed = text.replace(/\\s+/g, \" \").trim();\n\tif (collapsed.length <= maxCharacters) return collapsed;\n\tconst capped = collapsed.slice(0, maxCharacters);\n\t// End on a whole word when one fits: a snippet cut mid-word (\"specificatio\")\n\t// reads as corruption rather than truncation. A cap that lands inside the first\n\t// word has no boundary to retreat to, so the hard cut stands.\n\tconst boundary = capped.lastIndexOf(\" \");\n\treturn boundary > 0 ? capped.slice(0, boundary) : capped;\n}\n\n/**\n * Prefer highlights, fall back to page text.\n *\n * `contents.text` returns the top of the document, which on a real page is navigation\n * chrome and a repeat of the title before any content. Highlights are the passages Exa\n * judged relevant to the query, so they are both shorter and more useful. Text remains\n * the fallback because a page can yield no highlights, and an empty snippet is worse\n * than a boilerplate one.\n */\nfunction snippetFor(result: ExaSearchResult, maxCharacters: number): string {\n\tconst highlights = (result.highlights ?? []).map((highlight) => highlight?.trim()).filter(Boolean);\n\tif (highlights.length > 0) return toSnippet(highlights.join(HIGHLIGHT_SEPARATOR), maxCharacters);\n\treturn toSnippet(result.text, maxCharacters);\n}\n\nfunction toWebSearchResults(payload: ExaSearchResponse, maxCharacters: number): WebSearchResult[] {\n\tconst results: WebSearchResult[] = [];\n\tfor (const result of payload.results ?? []) {\n\t\tconst url = result?.url?.trim();\n\t\t// A result the model cannot cite or fetch is worse than one fewer result.\n\t\tif (!url) continue;\n\t\tresults.push({ title: result.title?.trim() || url, url, snippet: snippetFor(result, maxCharacters) });\n\t}\n\treturn results;\n}\n\n/**\n * Exa-backed `web_search` backend.\n *\n * Reaches the network through `globalThis.fetch` for the same reason `web_fetch`\n * does: that is the dispatcher `configureHttpDispatcher` made proxy-aware, so an\n * allowlisted host routes through the sandbox proxy and a disallowed one has no\n * route at all. Opening a raw socket here would sidestep a boundary this tool is\n * supposed to sit behind.\n */\nexport function createExaWebSearchOperations(options: ExaWebSearchOptions): WebSearchOperations {\n\tconst apiKey = options.apiKey?.trim();\n\tif (!apiKey) {\n\t\tthrow new Error(\"Exa web search requires an API key; none was resolved.\");\n\t}\n\tconst endpoint = options.endpoint ?? EXA_SEARCH_ENDPOINT;\n\tconst host = hostOf(endpoint);\n\tconst numResults = options.numResults ?? DEFAULT_EXA_RESULT_COUNT;\n\tconst snippetMaxCharacters = options.snippetMaxCharacters ?? DEFAULT_EXA_SNIPPET_CHARACTERS;\n\n\treturn {\n\t\tasync search(query, signal) {\n\t\t\tlet response: Response;\n\t\t\ttry {\n\t\t\t\tresponse = await fetch(endpoint, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: { \"content-type\": \"application/json\", \"x-api-key\": apiKey },\n\t\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t\tquery,\n\t\t\t\t\t\tnumResults,\n\t\t\t\t\t\tcontents: {\n\t\t\t\t\t\t\t// `query` steers which passages Exa picks. The deprecated\n\t\t\t\t\t\t\t// `numSentences` and `highlightsPerUrl` options are deliberately\n\t\t\t\t\t\t\t// unused; the latter is documented as ignored.\n\t\t\t\t\t\t\thighlights: { query, maxCharacters: snippetMaxCharacters },\n\t\t\t\t\t\t\ttext: { maxCharacters: snippetMaxCharacters },\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (isAbortError(error)) throw error;\n\t\t\t\t// `fetch failed` alone names neither the host nor the remedy. The sandbox\n\t\t\t\t// refusal wrapper's message, when it produced one, is preserved verbatim here.\n\t\t\t\tconst detail = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(`web_search request to ${host} failed: ${detail}`, { cause: error });\n\t\t\t}\n\n\t\t\tif (!response.ok) {\n\t\t\t\t// The body can echo request fields, so only the status is reported -- a\n\t\t\t\t// pasted-through body is how an API key ends up in a transcript.\n\t\t\t\tthrow new Error(`web_search request to ${host} failed with HTTP ${response.status}.`);\n\t\t\t}\n\n\t\t\tconst payload = (await response.json()) as ExaSearchResponse;\n\t\t\treturn toWebSearchResults(payload, snippetMaxCharacters);\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,128 @@
1
+ /** Exa's hosted search endpoint. */
2
+ export const EXA_SEARCH_ENDPOINT = "https://api.exa.ai/search";
3
+ /** Host of {@link EXA_SEARCH_ENDPOINT}, for the sandbox network allowlist. */
4
+ export const EXA_SEARCH_HOST = "api.exa.ai";
5
+ /** Exa's own default is 10; matching it keeps an unconfigured session predictable. */
6
+ export const DEFAULT_EXA_RESULT_COUNT = 10;
7
+ /**
8
+ * Snippet budget per result. Exa returns whole page text when asked, which is the
9
+ * wrong unit for a search result -- ten full pages would dwarf every other tool
10
+ * result in the context window. 800 characters is roughly a paragraph, enough for
11
+ * the model to judge relevance and decide whether to spend a `web_fetch` on it.
12
+ */
13
+ export const DEFAULT_EXA_SNIPPET_CHARACTERS = 800;
14
+ /** Separator between highlights, which are non-contiguous passages rather than prose. */
15
+ const HIGHLIGHT_SEPARATOR = " … ";
16
+ function isAbortError(error) {
17
+ return error instanceof Error && error.name === "AbortError";
18
+ }
19
+ function hostOf(endpoint) {
20
+ try {
21
+ return new URL(endpoint).host;
22
+ }
23
+ catch {
24
+ return endpoint;
25
+ }
26
+ }
27
+ /**
28
+ * Text arrives with the source document's line structure intact. Collapsing it to a
29
+ * single line costs nothing in meaning and keeps a ten-result list readable as a list
30
+ * rather than ten wrapped blocks.
31
+ */
32
+ function toSnippet(text, maxCharacters) {
33
+ if (!text)
34
+ return "";
35
+ const collapsed = text.replace(/\s+/g, " ").trim();
36
+ if (collapsed.length <= maxCharacters)
37
+ return collapsed;
38
+ const capped = collapsed.slice(0, maxCharacters);
39
+ // End on a whole word when one fits: a snippet cut mid-word ("specificatio")
40
+ // reads as corruption rather than truncation. A cap that lands inside the first
41
+ // word has no boundary to retreat to, so the hard cut stands.
42
+ const boundary = capped.lastIndexOf(" ");
43
+ return boundary > 0 ? capped.slice(0, boundary) : capped;
44
+ }
45
+ /**
46
+ * Prefer highlights, fall back to page text.
47
+ *
48
+ * `contents.text` returns the top of the document, which on a real page is navigation
49
+ * chrome and a repeat of the title before any content. Highlights are the passages Exa
50
+ * judged relevant to the query, so they are both shorter and more useful. Text remains
51
+ * the fallback because a page can yield no highlights, and an empty snippet is worse
52
+ * than a boilerplate one.
53
+ */
54
+ function snippetFor(result, maxCharacters) {
55
+ const highlights = (result.highlights ?? []).map((highlight) => highlight?.trim()).filter(Boolean);
56
+ if (highlights.length > 0)
57
+ return toSnippet(highlights.join(HIGHLIGHT_SEPARATOR), maxCharacters);
58
+ return toSnippet(result.text, maxCharacters);
59
+ }
60
+ function toWebSearchResults(payload, maxCharacters) {
61
+ const results = [];
62
+ for (const result of payload.results ?? []) {
63
+ const url = result?.url?.trim();
64
+ // A result the model cannot cite or fetch is worse than one fewer result.
65
+ if (!url)
66
+ continue;
67
+ results.push({ title: result.title?.trim() || url, url, snippet: snippetFor(result, maxCharacters) });
68
+ }
69
+ return results;
70
+ }
71
+ /**
72
+ * Exa-backed `web_search` backend.
73
+ *
74
+ * Reaches the network through `globalThis.fetch` for the same reason `web_fetch`
75
+ * does: that is the dispatcher `configureHttpDispatcher` made proxy-aware, so an
76
+ * allowlisted host routes through the sandbox proxy and a disallowed one has no
77
+ * route at all. Opening a raw socket here would sidestep a boundary this tool is
78
+ * supposed to sit behind.
79
+ */
80
+ export function createExaWebSearchOperations(options) {
81
+ const apiKey = options.apiKey?.trim();
82
+ if (!apiKey) {
83
+ throw new Error("Exa web search requires an API key; none was resolved.");
84
+ }
85
+ const endpoint = options.endpoint ?? EXA_SEARCH_ENDPOINT;
86
+ const host = hostOf(endpoint);
87
+ const numResults = options.numResults ?? DEFAULT_EXA_RESULT_COUNT;
88
+ const snippetMaxCharacters = options.snippetMaxCharacters ?? DEFAULT_EXA_SNIPPET_CHARACTERS;
89
+ return {
90
+ async search(query, signal) {
91
+ let response;
92
+ try {
93
+ response = await fetch(endpoint, {
94
+ method: "POST",
95
+ headers: { "content-type": "application/json", "x-api-key": apiKey },
96
+ body: JSON.stringify({
97
+ query,
98
+ numResults,
99
+ contents: {
100
+ // `query` steers which passages Exa picks. The deprecated
101
+ // `numSentences` and `highlightsPerUrl` options are deliberately
102
+ // unused; the latter is documented as ignored.
103
+ highlights: { query, maxCharacters: snippetMaxCharacters },
104
+ text: { maxCharacters: snippetMaxCharacters },
105
+ },
106
+ }),
107
+ signal,
108
+ });
109
+ }
110
+ catch (error) {
111
+ if (isAbortError(error))
112
+ throw error;
113
+ // `fetch failed` alone names neither the host nor the remedy. The sandbox
114
+ // refusal wrapper's message, when it produced one, is preserved verbatim here.
115
+ const detail = error instanceof Error ? error.message : String(error);
116
+ throw new Error(`web_search request to ${host} failed: ${detail}`, { cause: error });
117
+ }
118
+ if (!response.ok) {
119
+ // The body can echo request fields, so only the status is reported -- a
120
+ // pasted-through body is how an API key ends up in a transcript.
121
+ throw new Error(`web_search request to ${host} failed with HTTP ${response.status}.`);
122
+ }
123
+ const payload = (await response.json());
124
+ return toWebSearchResults(payload, snippetMaxCharacters);
125
+ },
126
+ };
127
+ }
128
+ //# sourceMappingURL=web-search-exa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-search-exa.js","sourceRoot":"","sources":["../../../src/core/tools/web-search-exa.ts"],"names":[],"mappings":"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","sourcesContent":["import type { WebSearchOperations, WebSearchResult } from \"./web-search.ts\";\n\n/** Exa's hosted search endpoint. */\nexport const EXA_SEARCH_ENDPOINT = \"https://api.exa.ai/search\";\n\n/** Host of {@link EXA_SEARCH_ENDPOINT}, for the sandbox network allowlist. */\nexport const EXA_SEARCH_HOST = \"api.exa.ai\";\n\n/** Exa's own default is 10; matching it keeps an unconfigured session predictable. */\nexport const DEFAULT_EXA_RESULT_COUNT = 10;\n\n/**\n * Snippet budget per result. Exa returns whole page text when asked, which is the\n * wrong unit for a search result -- ten full pages would dwarf every other tool\n * result in the context window. 800 characters is roughly a paragraph, enough for\n * the model to judge relevance and decide whether to spend a `web_fetch` on it.\n */\nexport const DEFAULT_EXA_SNIPPET_CHARACTERS = 800;\n\nexport interface ExaWebSearchOptions {\n\t/** Resolved key, never a `$VAR` reference -- resolution happens before this call. */\n\tapiKey: string;\n\t/** Override for an Exa-compatible endpoint. Defaults to {@link EXA_SEARCH_ENDPOINT}. */\n\tendpoint?: string;\n\tnumResults?: number;\n\tsnippetMaxCharacters?: number;\n}\n\n/** Separator between highlights, which are non-contiguous passages rather than prose. */\nconst HIGHLIGHT_SEPARATOR = \" … \";\n\n/** The subset of Exa's `/search` response this adapter reads. */\ninterface ExaSearchResult {\n\ttitle?: string | null;\n\turl?: string | null;\n\ttext?: string | null;\n\thighlights?: string[] | null;\n}\n\ninterface ExaSearchResponse {\n\tresults?: ExaSearchResult[] | null;\n}\n\nfunction isAbortError(error: unknown): boolean {\n\treturn error instanceof Error && error.name === \"AbortError\";\n}\n\nfunction hostOf(endpoint: string): string {\n\ttry {\n\t\treturn new URL(endpoint).host;\n\t} catch {\n\t\treturn endpoint;\n\t}\n}\n\n/**\n * Text arrives with the source document's line structure intact. Collapsing it to a\n * single line costs nothing in meaning and keeps a ten-result list readable as a list\n * rather than ten wrapped blocks.\n */\nfunction toSnippet(text: string | null | undefined, maxCharacters: number): string {\n\tif (!text) return \"\";\n\tconst collapsed = text.replace(/\\s+/g, \" \").trim();\n\tif (collapsed.length <= maxCharacters) return collapsed;\n\tconst capped = collapsed.slice(0, maxCharacters);\n\t// End on a whole word when one fits: a snippet cut mid-word (\"specificatio\")\n\t// reads as corruption rather than truncation. A cap that lands inside the first\n\t// word has no boundary to retreat to, so the hard cut stands.\n\tconst boundary = capped.lastIndexOf(\" \");\n\treturn boundary > 0 ? capped.slice(0, boundary) : capped;\n}\n\n/**\n * Prefer highlights, fall back to page text.\n *\n * `contents.text` returns the top of the document, which on a real page is navigation\n * chrome and a repeat of the title before any content. Highlights are the passages Exa\n * judged relevant to the query, so they are both shorter and more useful. Text remains\n * the fallback because a page can yield no highlights, and an empty snippet is worse\n * than a boilerplate one.\n */\nfunction snippetFor(result: ExaSearchResult, maxCharacters: number): string {\n\tconst highlights = (result.highlights ?? []).map((highlight) => highlight?.trim()).filter(Boolean);\n\tif (highlights.length > 0) return toSnippet(highlights.join(HIGHLIGHT_SEPARATOR), maxCharacters);\n\treturn toSnippet(result.text, maxCharacters);\n}\n\nfunction toWebSearchResults(payload: ExaSearchResponse, maxCharacters: number): WebSearchResult[] {\n\tconst results: WebSearchResult[] = [];\n\tfor (const result of payload.results ?? []) {\n\t\tconst url = result?.url?.trim();\n\t\t// A result the model cannot cite or fetch is worse than one fewer result.\n\t\tif (!url) continue;\n\t\tresults.push({ title: result.title?.trim() || url, url, snippet: snippetFor(result, maxCharacters) });\n\t}\n\treturn results;\n}\n\n/**\n * Exa-backed `web_search` backend.\n *\n * Reaches the network through `globalThis.fetch` for the same reason `web_fetch`\n * does: that is the dispatcher `configureHttpDispatcher` made proxy-aware, so an\n * allowlisted host routes through the sandbox proxy and a disallowed one has no\n * route at all. Opening a raw socket here would sidestep a boundary this tool is\n * supposed to sit behind.\n */\nexport function createExaWebSearchOperations(options: ExaWebSearchOptions): WebSearchOperations {\n\tconst apiKey = options.apiKey?.trim();\n\tif (!apiKey) {\n\t\tthrow new Error(\"Exa web search requires an API key; none was resolved.\");\n\t}\n\tconst endpoint = options.endpoint ?? EXA_SEARCH_ENDPOINT;\n\tconst host = hostOf(endpoint);\n\tconst numResults = options.numResults ?? DEFAULT_EXA_RESULT_COUNT;\n\tconst snippetMaxCharacters = options.snippetMaxCharacters ?? DEFAULT_EXA_SNIPPET_CHARACTERS;\n\n\treturn {\n\t\tasync search(query, signal) {\n\t\t\tlet response: Response;\n\t\t\ttry {\n\t\t\t\tresponse = await fetch(endpoint, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: { \"content-type\": \"application/json\", \"x-api-key\": apiKey },\n\t\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t\tquery,\n\t\t\t\t\t\tnumResults,\n\t\t\t\t\t\tcontents: {\n\t\t\t\t\t\t\t// `query` steers which passages Exa picks. The deprecated\n\t\t\t\t\t\t\t// `numSentences` and `highlightsPerUrl` options are deliberately\n\t\t\t\t\t\t\t// unused; the latter is documented as ignored.\n\t\t\t\t\t\t\thighlights: { query, maxCharacters: snippetMaxCharacters },\n\t\t\t\t\t\t\ttext: { maxCharacters: snippetMaxCharacters },\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (isAbortError(error)) throw error;\n\t\t\t\t// `fetch failed` alone names neither the host nor the remedy. The sandbox\n\t\t\t\t// refusal wrapper's message, when it produced one, is preserved verbatim here.\n\t\t\t\tconst detail = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(`web_search request to ${host} failed: ${detail}`, { cause: error });\n\t\t\t}\n\n\t\t\tif (!response.ok) {\n\t\t\t\t// The body can echo request fields, so only the status is reported -- a\n\t\t\t\t// pasted-through body is how an API key ends up in a transcript.\n\t\t\t\tthrow new Error(`web_search request to ${host} failed with HTTP ${response.status}.`);\n\t\t\t}\n\n\t\t\tconst payload = (await response.json()) as ExaSearchResponse;\n\t\t\treturn toWebSearchResults(payload, snippetMaxCharacters);\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,26 @@
1
+ import { type Static, Type } from "typebox";
2
+ import type { ApexToolDefinition } from "./contract.ts";
3
+ declare const webSearchSchema: Type.TObject<{
4
+ query: Type.TString;
5
+ }>;
6
+ export type WebSearchInput = Static<typeof webSearchSchema>;
7
+ export interface WebSearchResult {
8
+ title: string;
9
+ url: string;
10
+ snippet: string;
11
+ }
12
+ export interface WebSearchDetails {
13
+ results: WebSearchResult[];
14
+ }
15
+ export interface WebSearchOperations {
16
+ search(query: string, signal?: AbortSignal): Promise<WebSearchResult[]>;
17
+ }
18
+ export interface WebSearchToolOptions {
19
+ operations?: WebSearchOperations;
20
+ }
21
+ export declare function createWebSearchToolDefinition(options?: WebSearchToolOptions): ApexToolDefinition<typeof webSearchSchema, WebSearchDetails>;
22
+ export declare function createWebSearchTool(options?: WebSearchToolOptions): import("apex-code-agent-core").AgentTool<Type.TObject<{
23
+ query: Type.TString;
24
+ }>, WebSearchDetails>;
25
+ export {};
26
+ //# sourceMappingURL=web-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../../src/core/tools/web-search.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGxD,QAAA,MAAM,eAAe;;EAEnB,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,eAAe,CAAC,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IACnC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CACxE;AAoBD,MAAM,WAAW,oBAAoB;IACpC,UAAU,CAAC,EAAE,mBAAmB,CAAC;CACjC;AAED,wBAAgB,6BAA6B,CAC5C,OAAO,CAAC,EAAE,oBAAoB,GAC5B,kBAAkB,CAAC,OAAO,eAAe,EAAE,gBAAgB,CAAC,CAgC9D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,oBAAoB;;sBAEjE","sourcesContent":["import type { AgentToolResult } from \"apex-code-agent-core\";\nimport { type Static, Type } from \"typebox\";\nimport type { ApexToolDefinition } from \"./contract.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst webSearchSchema = Type.Object({\n\tquery: Type.String({ description: \"The search query.\" }),\n});\n\nexport type WebSearchInput = Static<typeof webSearchSchema>;\n\nexport interface WebSearchResult {\n\ttitle: string;\n\turl: string;\n\tsnippet: string;\n}\n\nexport interface WebSearchDetails {\n\tresults: WebSearchResult[];\n}\n\nexport interface WebSearchOperations {\n\tsearch(query: string, signal?: AbortSignal): Promise<WebSearchResult[]>;\n}\n\n/**\n * No search vendor is wired into this repo (unlike web_fetch, which needs only an\n * HTTP GET). A deployment supplies its own provider via `WebSearchToolOptions`;\n * failing loudly here beats a silent no-op that would look like zero results.\n */\nconst unconfiguredWebSearchOperations: WebSearchOperations = {\n\tasync search() {\n\t\tthrow new Error(\n\t\t\t\"web_search is not configured: no search provider was supplied. Pass WebSearchToolOptions.operations.\",\n\t\t);\n\t},\n};\n\nfunction formatResults(results: WebSearchResult[]): string {\n\tif (results.length === 0) return \"No results found.\";\n\treturn results.map((result) => `${result.title}\\n${result.url}\\n${result.snippet}`).join(\"\\n\\n\");\n}\n\nexport interface WebSearchToolOptions {\n\toperations?: WebSearchOperations;\n}\n\nexport function createWebSearchToolDefinition(\n\toptions?: WebSearchToolOptions,\n): ApexToolDefinition<typeof webSearchSchema, WebSearchDetails> {\n\tconst ops = options?.operations ?? unconfiguredWebSearchOperations;\n\treturn {\n\t\tname: \"web_search\",\n\t\tlabel: \"web_search\",\n\t\tdescription: \"Search the web and return a list of results.\",\n\t\tparameters: webSearchSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"net\"]),\n\t\t\tpermission: {\n\t\t\t\tdefaultBehavior: \"ask\",\n\t\t\t\t// A query is not a generalizable rule (ruleForCall returns null); the only\n\t\t\t\t// rule content worth recognizing is a hand-authored blanket \"*\".\n\t\t\t\tmatches: (ruleContent) => ruleContent === \"*\",\n\t\t\t\tdescribe: () => \"Web search (any query)\",\n\t\t\t\truleForCall: () => null,\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{ query }: WebSearchInput,\n\t\t\tsignal?: AbortSignal,\n\t\t): Promise<AgentToolResult<WebSearchDetails>> {\n\t\t\tconst results = await ops.search(query, signal);\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: formatResults(results) }],\n\t\t\t\tdetails: { results },\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport function createWebSearchTool(options?: WebSearchToolOptions) {\n\treturn wrapToolDefinition(createWebSearchToolDefinition(options));\n}\n"]}
@@ -0,0 +1,53 @@
1
+ import { Type } from "typebox";
2
+ import { wrapToolDefinition } from "./tool-definition-wrapper.js";
3
+ const webSearchSchema = Type.Object({
4
+ query: Type.String({ description: "The search query." }),
5
+ });
6
+ /**
7
+ * No search vendor is wired into this repo (unlike web_fetch, which needs only an
8
+ * HTTP GET). A deployment supplies its own provider via `WebSearchToolOptions`;
9
+ * failing loudly here beats a silent no-op that would look like zero results.
10
+ */
11
+ const unconfiguredWebSearchOperations = {
12
+ async search() {
13
+ throw new Error("web_search is not configured: no search provider was supplied. Pass WebSearchToolOptions.operations.");
14
+ },
15
+ };
16
+ function formatResults(results) {
17
+ if (results.length === 0)
18
+ return "No results found.";
19
+ return results.map((result) => `${result.title}\n${result.url}\n${result.snippet}`).join("\n\n");
20
+ }
21
+ export function createWebSearchToolDefinition(options) {
22
+ const ops = options?.operations ?? unconfiguredWebSearchOperations;
23
+ return {
24
+ name: "web_search",
25
+ label: "web_search",
26
+ description: "Search the web and return a list of results.",
27
+ parameters: webSearchSchema,
28
+ contract: {
29
+ capabilities: new Set(["net"]),
30
+ permission: {
31
+ defaultBehavior: "ask",
32
+ // A query is not a generalizable rule (ruleForCall returns null); the only
33
+ // rule content worth recognizing is a hand-authored blanket "*".
34
+ matches: (ruleContent) => ruleContent === "*",
35
+ describe: () => "Web search (any query)",
36
+ ruleForCall: () => null,
37
+ },
38
+ context: { resultRecoverable: false, deferSchema: true },
39
+ evidence: { emits: new Set(), capture: () => [] },
40
+ },
41
+ async execute(_toolCallId, { query }, signal) {
42
+ const results = await ops.search(query, signal);
43
+ return {
44
+ content: [{ type: "text", text: formatResults(results) }],
45
+ details: { results },
46
+ };
47
+ },
48
+ };
49
+ }
50
+ export function createWebSearchTool(options) {
51
+ return wrapToolDefinition(createWebSearchToolDefinition(options));
52
+ }
53
+ //# sourceMappingURL=web-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-search.js","sourceRoot":"","sources":["../../../src/core/tools/web-search.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC;IACnC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC;CACxD,CAAC,CAAC;AAkBH;;;;GAIG;AACH,MAAM,+BAA+B,GAAwB;IAC5D,KAAK,CAAC,MAAM,GAAG;QACd,MAAM,IAAI,KAAK,CACd,sGAAsG,CACtG,CAAC;IAAA,CACF;CACD,CAAC;AAEF,SAAS,aAAa,CAAC,OAA0B,EAAU;IAC1D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,mBAAmB,CAAC;IACrD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,GAAG,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAAA,CACjG;AAMD,MAAM,UAAU,6BAA6B,CAC5C,OAA8B,EACiC;IAC/D,MAAM,GAAG,GAAG,OAAO,EAAE,UAAU,IAAI,+BAA+B,CAAC;IACnE,OAAO;QACN,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,YAAY;QACnB,WAAW,EAAE,8CAA8C;QAC3D,UAAU,EAAE,eAAe;QAC3B,QAAQ,EAAE;YACT,YAAY,EAAE,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;YAC9B,UAAU,EAAE;gBACX,eAAe,EAAE,KAAK;gBACtB,2EAA2E;gBAC3E,iEAAiE;gBACjE,OAAO,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,KAAK,GAAG;gBAC7C,QAAQ,EAAE,GAAG,EAAE,CAAC,wBAAwB;gBACxC,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI;aACvB;YACD,OAAO,EAAE,EAAE,iBAAiB,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE;YACxD,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE;SACjD;QACD,KAAK,CAAC,OAAO,CACZ,WAAW,EACX,EAAE,KAAK,EAAkB,EACzB,MAAoB,EACyB;YAC7C,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAChD,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzD,OAAO,EAAE,EAAE,OAAO,EAAE;aACpB,CAAC;QAAA,CACF;KACD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,mBAAmB,CAAC,OAA8B,EAAE;IACnE,OAAO,kBAAkB,CAAC,6BAA6B,CAAC,OAAO,CAAC,CAAC,CAAC;AAAA,CAClE","sourcesContent":["import type { AgentToolResult } from \"apex-code-agent-core\";\nimport { type Static, Type } from \"typebox\";\nimport type { ApexToolDefinition } from \"./contract.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst webSearchSchema = Type.Object({\n\tquery: Type.String({ description: \"The search query.\" }),\n});\n\nexport type WebSearchInput = Static<typeof webSearchSchema>;\n\nexport interface WebSearchResult {\n\ttitle: string;\n\turl: string;\n\tsnippet: string;\n}\n\nexport interface WebSearchDetails {\n\tresults: WebSearchResult[];\n}\n\nexport interface WebSearchOperations {\n\tsearch(query: string, signal?: AbortSignal): Promise<WebSearchResult[]>;\n}\n\n/**\n * No search vendor is wired into this repo (unlike web_fetch, which needs only an\n * HTTP GET). A deployment supplies its own provider via `WebSearchToolOptions`;\n * failing loudly here beats a silent no-op that would look like zero results.\n */\nconst unconfiguredWebSearchOperations: WebSearchOperations = {\n\tasync search() {\n\t\tthrow new Error(\n\t\t\t\"web_search is not configured: no search provider was supplied. Pass WebSearchToolOptions.operations.\",\n\t\t);\n\t},\n};\n\nfunction formatResults(results: WebSearchResult[]): string {\n\tif (results.length === 0) return \"No results found.\";\n\treturn results.map((result) => `${result.title}\\n${result.url}\\n${result.snippet}`).join(\"\\n\\n\");\n}\n\nexport interface WebSearchToolOptions {\n\toperations?: WebSearchOperations;\n}\n\nexport function createWebSearchToolDefinition(\n\toptions?: WebSearchToolOptions,\n): ApexToolDefinition<typeof webSearchSchema, WebSearchDetails> {\n\tconst ops = options?.operations ?? unconfiguredWebSearchOperations;\n\treturn {\n\t\tname: \"web_search\",\n\t\tlabel: \"web_search\",\n\t\tdescription: \"Search the web and return a list of results.\",\n\t\tparameters: webSearchSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"net\"]),\n\t\t\tpermission: {\n\t\t\t\tdefaultBehavior: \"ask\",\n\t\t\t\t// A query is not a generalizable rule (ruleForCall returns null); the only\n\t\t\t\t// rule content worth recognizing is a hand-authored blanket \"*\".\n\t\t\t\tmatches: (ruleContent) => ruleContent === \"*\",\n\t\t\t\tdescribe: () => \"Web search (any query)\",\n\t\t\t\truleForCall: () => null,\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{ query }: WebSearchInput,\n\t\t\tsignal?: AbortSignal,\n\t\t): Promise<AgentToolResult<WebSearchDetails>> {\n\t\t\tconst results = await ops.search(query, signal);\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: formatResults(results) }],\n\t\t\t\tdetails: { results },\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport function createWebSearchTool(options?: WebSearchToolOptions) {\n\treturn wrapToolDefinition(createWebSearchToolDefinition(options));\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import type { AgentTool } from "apex-code-agent-core";
2
2
  import { type Static, Type } from "typebox";
3
- import type { ToolDefinition } from "../extensions/types.ts";
3
+ import type { ApexToolDefinition } from "./contract.ts";
4
+ import type { DiagnosticsOperations, DiagnosticsOutcome } from "./diagnostics.ts";
4
5
  declare const writeSchema: Type.TObject<{
5
6
  path: Type.TString;
6
7
  content: Type.TString;
@@ -10,6 +11,12 @@ export declare const writeToolSystemPromptContribution: {
10
11
  readonly guidelines: readonly ["Use write only for new files or complete rewrites."];
11
12
  };
12
13
  export type WriteToolInput = Static<typeof writeSchema>;
14
+ export interface WriteToolDetails {
15
+ byteCount: number;
16
+ contentHash: string;
17
+ /** Present only when `WriteToolOptions.diagnosticsOperations` is configured (LSP.4). */
18
+ diagnostics?: DiagnosticsOutcome;
19
+ }
13
20
  /**
14
21
  * Pluggable operations for the write tool.
15
22
  * Override these to delegate file writing to remote systems (for example SSH).
@@ -23,8 +30,15 @@ export interface WriteOperations {
23
30
  export interface WriteToolOptions {
24
31
  /** Custom operations for file writing. Default: local filesystem */
25
32
  operations?: WriteOperations;
33
+ /**
34
+ * Optional post-mutation diagnostics (LSP.4). Absent by default -- byte-identical
35
+ * existing behavior. When present, called inside `withFileMutationQueue` after the
36
+ * write succeeds and before the queue releases, matching `TestOperations`/
37
+ * `GrepOperations`' injection pattern (`test.ts:28`, `grep.ts:58`).
38
+ */
39
+ diagnosticsOperations?: DiagnosticsOperations;
26
40
  }
27
- export declare function createWriteToolDefinition(cwd: string, options?: WriteToolOptions): ToolDefinition<typeof writeSchema, undefined>;
41
+ export declare function createWriteToolDefinition(cwd: string, options?: WriteToolOptions): ApexToolDefinition<typeof writeSchema, WriteToolDetails>;
28
42
  export declare function createWriteTool(cwd: string, options?: WriteToolOptions): AgentTool<typeof writeSchema>;
29
43
  export {};
30
44
  //# sourceMappingURL=write.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/core/tools/write.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAMtF,QAAA,MAAM,WAAW;;;EAGf,CAAC;AAEH,eAAO,MAAM,iCAAiC;;;CAGpC,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,8BAA8B;IAC9B,SAAS,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,mCAAmC;IACnC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAOD,MAAM,WAAW,gBAAgB;IAChC,oEAAoE;IACpE,UAAU,CAAC,EAAE,eAAe,CAAC;CAC7B;AA6ID,wBAAgB,yBAAyB,CACxC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,gBAAgB,GACxB,cAAc,CAAC,OAAO,WAAW,EAAE,SAAS,CAAC,CA+E/C;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,OAAO,WAAW,CAAC,CAEtG","sourcesContent":["import { Container, Text } from \"@earendil-works/pi-tui\";\nimport type { AgentTool } from \"apex-code-agent-core\";\nimport { mkdir as fsMkdir, writeFile as fsWriteFile } from \"fs/promises\";\nimport { dirname } from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getLanguageFromPath, highlightCode, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { normalizeDisplayText, renderToolPath, replaceTabs, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst writeSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to write (relative or absolute)\" }),\n\tcontent: Type.String({ description: \"Content to write to the file\" }),\n});\n\nexport const writeToolSystemPromptContribution = {\n\tsnippet: \"Create or overwrite files\",\n\tguidelines: [\"Use write only for new files or complete rewrites.\"],\n} as const;\n\nexport type WriteToolInput = Static<typeof writeSchema>;\n\n/**\n * Pluggable operations for the write tool.\n * Override these to delegate file writing to remote systems (for example SSH).\n */\nexport interface WriteOperations {\n\t/** Write content to a file */\n\twriteFile: (absolutePath: string, content: string) => Promise<void>;\n\t/** Create directory recursively */\n\tmkdir: (dir: string) => Promise<void>;\n}\n\nconst defaultWriteOperations: WriteOperations = {\n\twriteFile: (path, content) => fsWriteFile(path, content, \"utf-8\"),\n\tmkdir: (dir) => fsMkdir(dir, { recursive: true }).then(() => {}),\n};\n\nexport interface WriteToolOptions {\n\t/** Custom operations for file writing. Default: local filesystem */\n\toperations?: WriteOperations;\n}\n\ntype WriteHighlightCache = {\n\trawPath: string | null;\n\tlang: string;\n\trawContent: string;\n\tnormalizedLines: string[];\n\thighlightedLines: string[];\n};\n\nclass WriteCallRenderComponent extends Text {\n\tcache?: WriteHighlightCache;\n\n\tconstructor() {\n\t\tsuper(\"\", 0, 0);\n\t}\n}\n\nconst WRITE_PARTIAL_FULL_HIGHLIGHT_LINES = 50;\n\nfunction highlightSingleLine(line: string, lang: string): string {\n\tconst highlighted = highlightCode(line, lang);\n\treturn highlighted[0] ?? \"\";\n}\n\nfunction refreshWriteHighlightPrefix(cache: WriteHighlightCache): void {\n\tconst prefixCount = Math.min(WRITE_PARTIAL_FULL_HIGHLIGHT_LINES, cache.normalizedLines.length);\n\tif (prefixCount === 0) return;\n\tconst prefixSource = cache.normalizedLines.slice(0, prefixCount).join(\"\\n\");\n\tconst prefixHighlighted = highlightCode(prefixSource, cache.lang);\n\tfor (let i = 0; i < prefixCount; i++) {\n\t\tcache.highlightedLines[i] =\n\t\t\tprefixHighlighted[i] ?? highlightSingleLine(cache.normalizedLines[i] ?? \"\", cache.lang);\n\t}\n}\n\nfunction rebuildWriteHighlightCacheFull(rawPath: string | null, fileContent: string): WriteHighlightCache | undefined {\n\tconst lang = rawPath ? getLanguageFromPath(rawPath) : undefined;\n\tif (!lang) return undefined;\n\tconst displayContent = normalizeDisplayText(fileContent);\n\tconst normalized = replaceTabs(displayContent);\n\treturn {\n\t\trawPath,\n\t\tlang,\n\t\trawContent: fileContent,\n\t\tnormalizedLines: normalized.split(\"\\n\"),\n\t\thighlightedLines: highlightCode(normalized, lang),\n\t};\n}\n\nfunction updateWriteHighlightCacheIncremental(\n\tcache: WriteHighlightCache | undefined,\n\trawPath: string | null,\n\tfileContent: string,\n): WriteHighlightCache | undefined {\n\tconst lang = rawPath ? getLanguageFromPath(rawPath) : undefined;\n\tif (!lang) return undefined;\n\tif (!cache) return rebuildWriteHighlightCacheFull(rawPath, fileContent);\n\tif (cache.lang !== lang || cache.rawPath !== rawPath) return rebuildWriteHighlightCacheFull(rawPath, fileContent);\n\tif (!fileContent.startsWith(cache.rawContent)) return rebuildWriteHighlightCacheFull(rawPath, fileContent);\n\tif (fileContent.length === cache.rawContent.length) return cache;\n\n\tconst deltaRaw = fileContent.slice(cache.rawContent.length);\n\tconst deltaDisplay = normalizeDisplayText(deltaRaw);\n\tconst deltaNormalized = replaceTabs(deltaDisplay);\n\tcache.rawContent = fileContent;\n\tif (cache.normalizedLines.length === 0) {\n\t\tcache.normalizedLines.push(\"\");\n\t\tcache.highlightedLines.push(\"\");\n\t}\n\n\tconst segments = deltaNormalized.split(\"\\n\");\n\tconst lastIndex = cache.normalizedLines.length - 1;\n\tcache.normalizedLines[lastIndex] += segments[0];\n\tcache.highlightedLines[lastIndex] = highlightSingleLine(cache.normalizedLines[lastIndex], cache.lang);\n\tfor (let i = 1; i < segments.length; i++) {\n\t\tcache.normalizedLines.push(segments[i]);\n\t\tcache.highlightedLines.push(highlightSingleLine(segments[i], cache.lang));\n\t}\n\trefreshWriteHighlightPrefix(cache);\n\treturn cache;\n}\n\nfunction trimTrailingEmptyLines(lines: string[]): string[] {\n\tlet end = lines.length;\n\twhile (end > 0 && lines[end - 1] === \"\") {\n\t\tend--;\n\t}\n\treturn lines.slice(0, end);\n}\n\nfunction formatWriteCall(\n\targs: { path?: string; file_path?: string; content?: string } | undefined,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tcache: WriteHighlightCache | undefined,\n\tcwd: string,\n): string {\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tconst fileContent = str(args?.content);\n\tconst pathDisplay = renderToolPath(rawPath, theme, cwd);\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"write\"))} ${pathDisplay}`;\n\n\tif (fileContent === null) {\n\t\ttext += `\\n\\n${theme.fg(\"error\", \"[invalid content arg - expected string]\")}`;\n\t} else if (fileContent) {\n\t\tconst lang = rawPath ? getLanguageFromPath(rawPath) : undefined;\n\t\tconst renderedLines = lang\n\t\t\t? (cache?.highlightedLines ?? highlightCode(replaceTabs(normalizeDisplayText(fileContent)), lang))\n\t\t\t: normalizeDisplayText(fileContent).split(\"\\n\");\n\t\tconst lines = trimTrailingEmptyLines(renderedLines);\n\t\tconst totalLines = lines.length;\n\t\tconst maxLines = options.expanded ? lines.length : 10;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n\\n${displayLines.map((line) => (lang ? line : theme.fg(\"toolOutput\", replaceTabs(line)))).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines, ${totalLines} total,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t\t}\n\t}\n\n\treturn text;\n}\n\nfunction formatWriteResult(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }>; isError?: boolean },\n\ttheme: Theme,\n): string | undefined {\n\tif (!result.isError) {\n\t\treturn undefined;\n\t}\n\tconst output = result.content\n\t\t.filter((c) => c.type === \"text\")\n\t\t.map((c) => c.text || \"\")\n\t\t.join(\"\\n\");\n\tif (!output) {\n\t\treturn undefined;\n\t}\n\treturn `\\n${theme.fg(\"error\", output)}`;\n}\n\nexport function createWriteToolDefinition(\n\tcwd: string,\n\toptions?: WriteToolOptions,\n): ToolDefinition<typeof writeSchema, undefined> {\n\tconst ops = options?.operations ?? defaultWriteOperations;\n\treturn {\n\t\tname: \"write\",\n\t\tlabel: \"write\",\n\t\tdescription:\n\t\t\t\"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n\t\tpromptSnippet: writeToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: [...writeToolSystemPromptContribution.guidelines],\n\t\tparameters: writeSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, content }: { path: string; content: string },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\tconst absolutePath = resolveToCwd(path, cwd);\n\t\t\tconst dir = dirname(absolutePath);\n\t\t\treturn withFileMutationQueue(absolutePath, async () => {\n\t\t\t\t// Do not reject from an abort event listener here: that would release the\n\t\t\t\t// mutation queue while an in-flight filesystem operation may still finish.\n\t\t\t\t// Checking signal.aborted after each await observes the same aborts while\n\t\t\t\t// keeping the queue locked until the current operation has settled.\n\t\t\t\tconst throwIfAborted = (): void => {\n\t\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\t};\n\n\t\t\t\tthrowIfAborted();\n\t\t\t\t// Create parent directories if needed.\n\t\t\t\tawait ops.mkdir(dir);\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\t// Write the file contents.\n\t\t\t\tawait ops.writeFile(absolutePath, content);\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Successfully wrote ${content.length} bytes to ${path}` }],\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst renderArgs = args as { path?: string; file_path?: string; content?: string } | undefined;\n\t\t\tconst rawPath = str(renderArgs?.file_path ?? renderArgs?.path);\n\t\t\tconst fileContent = str(renderArgs?.content);\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as WriteCallRenderComponent | undefined) ?? new WriteCallRenderComponent();\n\t\t\tif (fileContent !== null) {\n\t\t\t\tcomponent.cache = context.argsComplete\n\t\t\t\t\t? rebuildWriteHighlightCacheFull(rawPath, fileContent)\n\t\t\t\t\t: updateWriteHighlightCacheIncremental(component.cache, rawPath, fileContent);\n\t\t\t} else {\n\t\t\t\tcomponent.cache = undefined;\n\t\t\t}\n\t\t\tcomponent.setText(\n\t\t\t\tformatWriteCall(\n\t\t\t\t\trenderArgs,\n\t\t\t\t\t{ expanded: context.expanded, isPartial: context.isPartial },\n\t\t\t\t\ttheme,\n\t\t\t\t\tcomponent.cache,\n\t\t\t\t\tcontext.cwd,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn component;\n\t\t},\n\t\trenderResult(result, _options, theme, context) {\n\t\t\tconst output = formatWriteResult({ ...result, isError: context.isError }, theme);\n\t\t\tif (!output) {\n\t\t\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\t\t\tcomponent.clear();\n\t\t\t\treturn component;\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(output);\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createWriteTool(cwd: string, options?: WriteToolOptions): AgentTool<typeof writeSchema> {\n\treturn wrapToolDefinition(createWriteToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/core/tools/write.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAK5C,OAAO,KAAK,EAAE,kBAAkB,EAAkB,MAAM,eAAe,CAAC;AACxE,OAAO,KAAK,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAQlF,QAAA,MAAM,WAAW;;;EAGf,CAAC;AAEH,eAAO,MAAM,iCAAiC;;;CAGpC,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,wFAAwF;IACxF,WAAW,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAMD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,8BAA8B;IAC9B,SAAS,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,mCAAmC;IACnC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAOD,MAAM,WAAW,gBAAgB;IAChC,oEAAoE;IACpE,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;CAC9C;AA6ID,wBAAgB,yBAAyB,CACxC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,gBAAgB,GACxB,kBAAkB,CAAC,OAAO,WAAW,EAAE,gBAAgB,CAAC,CAuH1D;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,OAAO,WAAW,CAAC,CAEtG","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { Container, Text } from \"@earendil-works/pi-tui\";\nimport type { AgentTool } from \"apex-code-agent-core\";\nimport { mkdir as fsMkdir, writeFile as fsWriteFile } from \"fs/promises\";\nimport { dirname } from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getLanguageFromPath, highlightCode, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { getExperimentalToolSampling } from \"../experimental.ts\";\nimport type { ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport type { ApexToolDefinition, EvidenceRecord } from \"./contract.ts\";\nimport type { DiagnosticsOperations, DiagnosticsOutcome } from \"./diagnostics.ts\";\nimport { diagnosticEvidenceForPath, formatDiagnosticsOutcome } from \"./diagnostics.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { createPathPermissionSpec } from \"./path-permission.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { normalizeDisplayText, renderToolPath, replaceTabs, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst writeSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to write (relative or absolute)\" }),\n\tcontent: Type.String({ description: \"Content to write to the file\" }),\n});\n\nexport const writeToolSystemPromptContribution = {\n\tsnippet: \"Create or overwrite files\",\n\tguidelines: [\"Use write only for new files or complete rewrites.\"],\n} as const;\n\nexport type WriteToolInput = Static<typeof writeSchema>;\n\nexport interface WriteToolDetails {\n\tbyteCount: number;\n\tcontentHash: string;\n\t/** Present only when `WriteToolOptions.diagnosticsOperations` is configured (LSP.4). */\n\tdiagnostics?: DiagnosticsOutcome;\n}\n\nfunction sha256(value: string): string {\n\treturn createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\n/**\n * Pluggable operations for the write tool.\n * Override these to delegate file writing to remote systems (for example SSH).\n */\nexport interface WriteOperations {\n\t/** Write content to a file */\n\twriteFile: (absolutePath: string, content: string) => Promise<void>;\n\t/** Create directory recursively */\n\tmkdir: (dir: string) => Promise<void>;\n}\n\nconst defaultWriteOperations: WriteOperations = {\n\twriteFile: (path, content) => fsWriteFile(path, content, \"utf-8\"),\n\tmkdir: (dir) => fsMkdir(dir, { recursive: true }).then(() => {}),\n};\n\nexport interface WriteToolOptions {\n\t/** Custom operations for file writing. Default: local filesystem */\n\toperations?: WriteOperations;\n\t/**\n\t * Optional post-mutation diagnostics (LSP.4). Absent by default -- byte-identical\n\t * existing behavior. When present, called inside `withFileMutationQueue` after the\n\t * write succeeds and before the queue releases, matching `TestOperations`/\n\t * `GrepOperations`' injection pattern (`test.ts:28`, `grep.ts:58`).\n\t */\n\tdiagnosticsOperations?: DiagnosticsOperations;\n}\n\ntype WriteHighlightCache = {\n\trawPath: string | null;\n\tlang: string;\n\trawContent: string;\n\tnormalizedLines: string[];\n\thighlightedLines: string[];\n};\n\nclass WriteCallRenderComponent extends Text {\n\tcache?: WriteHighlightCache;\n\n\tconstructor() {\n\t\tsuper(\"\", 0, 0);\n\t}\n}\n\nconst WRITE_PARTIAL_FULL_HIGHLIGHT_LINES = 50;\n\nfunction highlightSingleLine(line: string, lang: string): string {\n\tconst highlighted = highlightCode(line, lang);\n\treturn highlighted[0] ?? \"\";\n}\n\nfunction refreshWriteHighlightPrefix(cache: WriteHighlightCache): void {\n\tconst prefixCount = Math.min(WRITE_PARTIAL_FULL_HIGHLIGHT_LINES, cache.normalizedLines.length);\n\tif (prefixCount === 0) return;\n\tconst prefixSource = cache.normalizedLines.slice(0, prefixCount).join(\"\\n\");\n\tconst prefixHighlighted = highlightCode(prefixSource, cache.lang);\n\tfor (let i = 0; i < prefixCount; i++) {\n\t\tcache.highlightedLines[i] =\n\t\t\tprefixHighlighted[i] ?? highlightSingleLine(cache.normalizedLines[i] ?? \"\", cache.lang);\n\t}\n}\n\nfunction rebuildWriteHighlightCacheFull(rawPath: string | null, fileContent: string): WriteHighlightCache | undefined {\n\tconst lang = rawPath ? getLanguageFromPath(rawPath) : undefined;\n\tif (!lang) return undefined;\n\tconst displayContent = normalizeDisplayText(fileContent);\n\tconst normalized = replaceTabs(displayContent);\n\treturn {\n\t\trawPath,\n\t\tlang,\n\t\trawContent: fileContent,\n\t\tnormalizedLines: normalized.split(\"\\n\"),\n\t\thighlightedLines: highlightCode(normalized, lang),\n\t};\n}\n\nfunction updateWriteHighlightCacheIncremental(\n\tcache: WriteHighlightCache | undefined,\n\trawPath: string | null,\n\tfileContent: string,\n): WriteHighlightCache | undefined {\n\tconst lang = rawPath ? getLanguageFromPath(rawPath) : undefined;\n\tif (!lang) return undefined;\n\tif (!cache) return rebuildWriteHighlightCacheFull(rawPath, fileContent);\n\tif (cache.lang !== lang || cache.rawPath !== rawPath) return rebuildWriteHighlightCacheFull(rawPath, fileContent);\n\tif (!fileContent.startsWith(cache.rawContent)) return rebuildWriteHighlightCacheFull(rawPath, fileContent);\n\tif (fileContent.length === cache.rawContent.length) return cache;\n\n\tconst deltaRaw = fileContent.slice(cache.rawContent.length);\n\tconst deltaDisplay = normalizeDisplayText(deltaRaw);\n\tconst deltaNormalized = replaceTabs(deltaDisplay);\n\tcache.rawContent = fileContent;\n\tif (cache.normalizedLines.length === 0) {\n\t\tcache.normalizedLines.push(\"\");\n\t\tcache.highlightedLines.push(\"\");\n\t}\n\n\tconst segments = deltaNormalized.split(\"\\n\");\n\tconst lastIndex = cache.normalizedLines.length - 1;\n\tcache.normalizedLines[lastIndex] += segments[0];\n\tcache.highlightedLines[lastIndex] = highlightSingleLine(cache.normalizedLines[lastIndex], cache.lang);\n\tfor (let i = 1; i < segments.length; i++) {\n\t\tcache.normalizedLines.push(segments[i]);\n\t\tcache.highlightedLines.push(highlightSingleLine(segments[i], cache.lang));\n\t}\n\trefreshWriteHighlightPrefix(cache);\n\treturn cache;\n}\n\nfunction trimTrailingEmptyLines(lines: string[]): string[] {\n\tlet end = lines.length;\n\twhile (end > 0 && lines[end - 1] === \"\") {\n\t\tend--;\n\t}\n\treturn lines.slice(0, end);\n}\n\nfunction formatWriteCall(\n\targs: { path?: string; file_path?: string; content?: string } | undefined,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tcache: WriteHighlightCache | undefined,\n\tcwd: string,\n): string {\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tconst fileContent = str(args?.content);\n\tconst pathDisplay = renderToolPath(rawPath, theme, cwd);\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"write\"))} ${pathDisplay}`;\n\n\tif (fileContent === null) {\n\t\ttext += `\\n\\n${theme.fg(\"error\", \"[invalid content arg - expected string]\")}`;\n\t} else if (fileContent) {\n\t\tconst lang = rawPath ? getLanguageFromPath(rawPath) : undefined;\n\t\tconst renderedLines = lang\n\t\t\t? (cache?.highlightedLines ?? highlightCode(replaceTabs(normalizeDisplayText(fileContent)), lang))\n\t\t\t: normalizeDisplayText(fileContent).split(\"\\n\");\n\t\tconst lines = trimTrailingEmptyLines(renderedLines);\n\t\tconst totalLines = lines.length;\n\t\tconst maxLines = options.expanded ? lines.length : 10;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n\\n${displayLines.map((line) => (lang ? line : theme.fg(\"toolOutput\", replaceTabs(line)))).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines, ${totalLines} total,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t\t}\n\t}\n\n\treturn text;\n}\n\nfunction formatWriteResult(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }>; isError?: boolean },\n\ttheme: Theme,\n): string | undefined {\n\tif (!result.isError) {\n\t\treturn undefined;\n\t}\n\tconst output = result.content\n\t\t.filter((c) => c.type === \"text\")\n\t\t.map((c) => c.text || \"\")\n\t\t.join(\"\\n\");\n\tif (!output) {\n\t\treturn undefined;\n\t}\n\treturn `\\n${theme.fg(\"error\", output)}`;\n}\n\nexport function createWriteToolDefinition(\n\tcwd: string,\n\toptions?: WriteToolOptions,\n): ApexToolDefinition<typeof writeSchema, WriteToolDetails> {\n\tconst ops = options?.operations ?? defaultWriteOperations;\n\tconst diagnosticsOperations = options?.diagnosticsOperations;\n\treturn {\n\t\tname: \"write\",\n\t\tlabel: \"write\",\n\t\tdescription:\n\t\t\t\"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n\t\tpromptSnippet: writeToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: [...writeToolSystemPromptContribution.guidelines],\n\t\tparameters: writeSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"fs.write\"]),\n\t\t\tpermission: createPathPermissionSpec({\n\t\t\t\tcwd,\n\t\t\t\tdefaultBehavior: \"ask\",\n\t\t\t\tverb: \"Write\",\n\t\t\t\tgetPath: (params) => params.path,\n\t\t\t}),\n\t\t\tcontext: { resultRecoverable: true, deferSchema: false },\n\t\t\tevidence: {\n\t\t\t\temits: new Set(diagnosticsOperations ? [\"diff\", \"diagnostic\"] : [\"diff\"]),\n\t\t\t\tcapture: (params, result) => {\n\t\t\t\t\tconst details = result.details;\n\t\t\t\t\tconst records: EvidenceRecord[] = details\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tkind: \"diff\",\n\t\t\t\t\t\t\t\t\tpath: params.path,\n\t\t\t\t\t\t\t\t\tbyteCount: details.byteCount,\n\t\t\t\t\t\t\t\t\tcontentHash: details.contentHash,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: [{ kind: \"diff\", path: params.path }];\n\t\t\t\t\tif (details?.diagnostics) records.push(diagnosticEvidenceForPath(params.path, details.diagnostics));\n\t\t\t\t\treturn records;\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tconstrainedSampling: getExperimentalToolSampling(),\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, content }: { path: string; content: string },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\tconst absolutePath = resolveToCwd(path, cwd);\n\t\t\tconst dir = dirname(absolutePath);\n\t\t\treturn withFileMutationQueue(absolutePath, async () => {\n\t\t\t\t// Do not reject from an abort event listener here: that would release the\n\t\t\t\t// mutation queue while an in-flight filesystem operation may still finish.\n\t\t\t\t// Checking signal.aborted after each await observes the same aborts while\n\t\t\t\t// keeping the queue locked until the current operation has settled.\n\t\t\t\tconst throwIfAborted = (): void => {\n\t\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\t};\n\n\t\t\t\tthrowIfAborted();\n\t\t\t\t// Create parent directories if needed.\n\t\t\t\tawait ops.mkdir(dir);\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\t// Write the file contents.\n\t\t\t\tawait ops.writeFile(absolutePath, content);\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\tconst successText = `Successfully wrote ${content.length} bytes to ${path}`;\n\n\t\t\t\tif (diagnosticsOperations) {\n\t\t\t\t\tconst diagnostics = await diagnosticsOperations.afterMutation(absolutePath, signal);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: `${successText}\\n\\n${formatDiagnosticsOutcome(diagnostics)}` }],\n\t\t\t\t\t\tdetails: { byteCount: Buffer.byteLength(content), contentHash: sha256(content), diagnostics },\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: successText }],\n\t\t\t\t\tdetails: { byteCount: Buffer.byteLength(content), contentHash: sha256(content) },\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst renderArgs = args as { path?: string; file_path?: string; content?: string } | undefined;\n\t\t\tconst rawPath = str(renderArgs?.file_path ?? renderArgs?.path);\n\t\t\tconst fileContent = str(renderArgs?.content);\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as WriteCallRenderComponent | undefined) ?? new WriteCallRenderComponent();\n\t\t\tif (fileContent !== null) {\n\t\t\t\tcomponent.cache = context.argsComplete\n\t\t\t\t\t? rebuildWriteHighlightCacheFull(rawPath, fileContent)\n\t\t\t\t\t: updateWriteHighlightCacheIncremental(component.cache, rawPath, fileContent);\n\t\t\t} else {\n\t\t\t\tcomponent.cache = undefined;\n\t\t\t}\n\t\t\tcomponent.setText(\n\t\t\t\tformatWriteCall(\n\t\t\t\t\trenderArgs,\n\t\t\t\t\t{ expanded: context.expanded, isPartial: context.isPartial },\n\t\t\t\t\ttheme,\n\t\t\t\t\tcomponent.cache,\n\t\t\t\t\tcontext.cwd,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn component;\n\t\t},\n\t\trenderResult(result, _options, theme, context) {\n\t\t\tconst output = formatWriteResult({ ...result, isError: context.isError }, theme);\n\t\t\tif (!output) {\n\t\t\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\t\t\tcomponent.clear();\n\t\t\t\treturn component;\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(output);\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createWriteTool(cwd: string, options?: WriteToolOptions): AgentTool<typeof writeSchema> {\n\treturn wrapToolDefinition(createWriteToolDefinition(cwd, options));\n}\n"]}