praxis-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +534 -0
  3. package/dist/application/background-agent-manager.d.ts +66 -0
  4. package/dist/application/background-agent-manager.d.ts.map +1 -0
  5. package/dist/application/background-agent-manager.js +362 -0
  6. package/dist/application/background-agent-manager.js.map +1 -0
  7. package/dist/application/background-bash-manager.d.ts +54 -0
  8. package/dist/application/background-bash-manager.d.ts.map +1 -0
  9. package/dist/application/background-bash-manager.js +354 -0
  10. package/dist/application/background-bash-manager.js.map +1 -0
  11. package/dist/application/background-task-id.d.ts +5 -0
  12. package/dist/application/background-task-id.d.ts.map +1 -0
  13. package/dist/application/background-task-id.js +25 -0
  14. package/dist/application/background-task-id.js.map +1 -0
  15. package/dist/application/claude-project-purge.d.ts +50 -0
  16. package/dist/application/claude-project-purge.d.ts.map +1 -0
  17. package/dist/application/claude-project-purge.js +459 -0
  18. package/dist/application/claude-project-purge.js.map +1 -0
  19. package/dist/application/managed-worktree.d.ts +15 -0
  20. package/dist/application/managed-worktree.d.ts.map +1 -0
  21. package/dist/application/managed-worktree.js +127 -0
  22. package/dist/application/managed-worktree.js.map +1 -0
  23. package/dist/application/model-compactor.d.ts +8 -0
  24. package/dist/application/model-compactor.d.ts.map +1 -0
  25. package/dist/application/model-compactor.js +70 -0
  26. package/dist/application/model-compactor.js.map +1 -0
  27. package/dist/application/scheduled-prompt-manager.d.ts +69 -0
  28. package/dist/application/scheduled-prompt-manager.d.ts.map +1 -0
  29. package/dist/application/scheduled-prompt-manager.js +387 -0
  30. package/dist/application/scheduled-prompt-manager.js.map +1 -0
  31. package/dist/application/session-service.d.ts +142 -0
  32. package/dist/application/session-service.d.ts.map +1 -0
  33. package/dist/application/session-service.js +1690 -0
  34. package/dist/application/session-service.js.map +1 -0
  35. package/dist/application/session-worktree.d.ts +55 -0
  36. package/dist/application/session-worktree.d.ts.map +1 -0
  37. package/dist/application/session-worktree.js +311 -0
  38. package/dist/application/session-worktree.js.map +1 -0
  39. package/dist/application/subagent-service.d.ts +98 -0
  40. package/dist/application/subagent-service.d.ts.map +1 -0
  41. package/dist/application/subagent-service.js +1305 -0
  42. package/dist/application/subagent-service.js.map +1 -0
  43. package/dist/application/tool-use-summary.d.ts +8 -0
  44. package/dist/application/tool-use-summary.d.ts.map +1 -0
  45. package/dist/application/tool-use-summary.js +53 -0
  46. package/dist/application/tool-use-summary.js.map +1 -0
  47. package/dist/application/top-level-agent-manager.d.ts +58 -0
  48. package/dist/application/top-level-agent-manager.d.ts.map +1 -0
  49. package/dist/application/top-level-agent-manager.js +907 -0
  50. package/dist/application/top-level-agent-manager.js.map +1 -0
  51. package/dist/application/workflow-manager.d.ts +61 -0
  52. package/dist/application/workflow-manager.d.ts.map +1 -0
  53. package/dist/application/workflow-manager.js +582 -0
  54. package/dist/application/workflow-manager.js.map +1 -0
  55. package/dist/application/workflow-meta.d.ts +18 -0
  56. package/dist/application/workflow-meta.d.ts.map +1 -0
  57. package/dist/application/workflow-meta.js +146 -0
  58. package/dist/application/workflow-meta.js.map +1 -0
  59. package/dist/application/workflow-runtime.d.ts +29 -0
  60. package/dist/application/workflow-runtime.d.ts.map +1 -0
  61. package/dist/application/workflow-runtime.js +176 -0
  62. package/dist/application/workflow-runtime.js.map +1 -0
  63. package/dist/application/workflow-worktree.d.ts +9 -0
  64. package/dist/application/workflow-worktree.d.ts.map +1 -0
  65. package/dist/application/workflow-worktree.js +11 -0
  66. package/dist/application/workflow-worktree.js.map +1 -0
  67. package/dist/cli/agents-dashboard.d.ts +37 -0
  68. package/dist/cli/agents-dashboard.d.ts.map +1 -0
  69. package/dist/cli/agents-dashboard.js +408 -0
  70. package/dist/cli/agents-dashboard.js.map +1 -0
  71. package/dist/cli/controls.d.ts +15 -0
  72. package/dist/cli/controls.d.ts.map +1 -0
  73. package/dist/cli/controls.js +219 -0
  74. package/dist/cli/controls.js.map +1 -0
  75. package/dist/cli/debug.d.ts +13 -0
  76. package/dist/cli/debug.d.ts.map +1 -0
  77. package/dist/cli/debug.js +37 -0
  78. package/dist/cli/debug.js.map +1 -0
  79. package/dist/cli/interactive.d.ts +63 -0
  80. package/dist/cli/interactive.d.ts.map +1 -0
  81. package/dist/cli/interactive.js +600 -0
  82. package/dist/cli/interactive.js.map +1 -0
  83. package/dist/cli/protocol.d.ts +251 -0
  84. package/dist/cli/protocol.d.ts.map +1 -0
  85. package/dist/cli/protocol.js +2146 -0
  86. package/dist/cli/protocol.js.map +1 -0
  87. package/dist/cli.d.ts +116 -0
  88. package/dist/cli.d.ts.map +1 -0
  89. package/dist/cli.js +3901 -0
  90. package/dist/cli.js.map +1 -0
  91. package/dist/compatibility/claude/compaction.d.ts +19 -0
  92. package/dist/compatibility/claude/compaction.d.ts.map +1 -0
  93. package/dist/compatibility/claude/compaction.js +82 -0
  94. package/dist/compatibility/claude/compaction.js.map +1 -0
  95. package/dist/compatibility/claude/context.d.ts +24 -0
  96. package/dist/compatibility/claude/context.d.ts.map +1 -0
  97. package/dist/compatibility/claude/context.js +92 -0
  98. package/dist/compatibility/claude/context.js.map +1 -0
  99. package/dist/compatibility/claude/dynamic-context.d.ts +20 -0
  100. package/dist/compatibility/claude/dynamic-context.d.ts.map +1 -0
  101. package/dist/compatibility/claude/dynamic-context.js +168 -0
  102. package/dist/compatibility/claude/dynamic-context.js.map +1 -0
  103. package/dist/compatibility/claude/file-history.d.ts +14 -0
  104. package/dist/compatibility/claude/file-history.d.ts.map +1 -0
  105. package/dist/compatibility/claude/file-history.js +340 -0
  106. package/dist/compatibility/claude/file-history.js.map +1 -0
  107. package/dist/compatibility/claude/file-resources.d.ts +28 -0
  108. package/dist/compatibility/claude/file-resources.d.ts.map +1 -0
  109. package/dist/compatibility/claude/file-resources.js +168 -0
  110. package/dist/compatibility/claude/file-resources.js.map +1 -0
  111. package/dist/compatibility/claude/fork.d.ts +9 -0
  112. package/dist/compatibility/claude/fork.d.ts.map +1 -0
  113. package/dist/compatibility/claude/fork.js +225 -0
  114. package/dist/compatibility/claude/fork.js.map +1 -0
  115. package/dist/compatibility/claude/history.d.ts +4 -0
  116. package/dist/compatibility/claude/history.d.ts.map +1 -0
  117. package/dist/compatibility/claude/history.js +86 -0
  118. package/dist/compatibility/claude/history.js.map +1 -0
  119. package/dist/compatibility/claude/ownership.d.ts +87 -0
  120. package/dist/compatibility/claude/ownership.d.ts.map +1 -0
  121. package/dist/compatibility/claude/ownership.js +100 -0
  122. package/dist/compatibility/claude/ownership.js.map +1 -0
  123. package/dist/compatibility/claude/paths.d.ts +17 -0
  124. package/dist/compatibility/claude/paths.d.ts.map +1 -0
  125. package/dist/compatibility/claude/paths.js +54 -0
  126. package/dist/compatibility/claude/paths.js.map +1 -0
  127. package/dist/compatibility/claude/pr-links.d.ts +25 -0
  128. package/dist/compatibility/claude/pr-links.d.ts.map +1 -0
  129. package/dist/compatibility/claude/pr-links.js +80 -0
  130. package/dist/compatibility/claude/pr-links.js.map +1 -0
  131. package/dist/compatibility/claude/projection.d.ts +11 -0
  132. package/dist/compatibility/claude/projection.d.ts.map +1 -0
  133. package/dist/compatibility/claude/projection.js +325 -0
  134. package/dist/compatibility/claude/projection.js.map +1 -0
  135. package/dist/compatibility/claude/schema.d.ts +18 -0
  136. package/dist/compatibility/claude/schema.d.ts.map +1 -0
  137. package/dist/compatibility/claude/schema.js +983 -0
  138. package/dist/compatibility/claude/schema.js.map +1 -0
  139. package/dist/compatibility/claude/shared-resources.d.ts +51 -0
  140. package/dist/compatibility/claude/shared-resources.d.ts.map +1 -0
  141. package/dist/compatibility/claude/shared-resources.js +382 -0
  142. package/dist/compatibility/claude/shared-resources.js.map +1 -0
  143. package/dist/compatibility/claude/sidechain.d.ts +50 -0
  144. package/dist/compatibility/claude/sidechain.d.ts.map +1 -0
  145. package/dist/compatibility/claude/sidechain.js +90 -0
  146. package/dist/compatibility/claude/sidechain.js.map +1 -0
  147. package/dist/compatibility/claude/tool-links.d.ts +13 -0
  148. package/dist/compatibility/claude/tool-links.d.ts.map +1 -0
  149. package/dist/compatibility/claude/tool-links.js +61 -0
  150. package/dist/compatibility/claude/tool-links.js.map +1 -0
  151. package/dist/compatibility/claude/translation.d.ts +71 -0
  152. package/dist/compatibility/claude/translation.d.ts.map +1 -0
  153. package/dist/compatibility/claude/translation.js +443 -0
  154. package/dist/compatibility/claude/translation.js.map +1 -0
  155. package/dist/compatibility/claude/workflow-replay.d.ts +10 -0
  156. package/dist/compatibility/claude/workflow-replay.d.ts.map +1 -0
  157. package/dist/compatibility/claude/workflow-replay.js +66 -0
  158. package/dist/compatibility/claude/workflow-replay.js.map +1 -0
  159. package/dist/compatibility/claude/workflow.d.ts +33 -0
  160. package/dist/compatibility/claude/workflow.d.ts.map +1 -0
  161. package/dist/compatibility/claude/workflow.js +76 -0
  162. package/dist/compatibility/claude/workflow.js.map +1 -0
  163. package/dist/core/compaction.d.ts +16 -0
  164. package/dist/core/compaction.d.ts.map +1 -0
  165. package/dist/core/compaction.js +2 -0
  166. package/dist/core/compaction.js.map +1 -0
  167. package/dist/core/context-budget.d.ts +28 -0
  168. package/dist/core/context-budget.d.ts.map +1 -0
  169. package/dist/core/context-budget.js +108 -0
  170. package/dist/core/context-budget.js.map +1 -0
  171. package/dist/core/context.d.ts +16 -0
  172. package/dist/core/context.d.ts.map +1 -0
  173. package/dist/core/context.js +13 -0
  174. package/dist/core/context.js.map +1 -0
  175. package/dist/core/runtime.d.ts +394 -0
  176. package/dist/core/runtime.d.ts.map +1 -0
  177. package/dist/core/runtime.js +507 -0
  178. package/dist/core/runtime.js.map +1 -0
  179. package/dist/core/usage.d.ts +26 -0
  180. package/dist/core/usage.d.ts.map +1 -0
  181. package/dist/core/usage.js +133 -0
  182. package/dist/core/usage.js.map +1 -0
  183. package/dist/extensions/claude-extension-tools.d.ts +16 -0
  184. package/dist/extensions/claude-extension-tools.d.ts.map +1 -0
  185. package/dist/extensions/claude-extension-tools.js +78 -0
  186. package/dist/extensions/claude-extension-tools.js.map +1 -0
  187. package/dist/extensions/claude-extensions.d.ts +41 -0
  188. package/dist/extensions/claude-extensions.d.ts.map +1 -0
  189. package/dist/extensions/claude-extensions.js +270 -0
  190. package/dist/extensions/claude-extensions.js.map +1 -0
  191. package/dist/hooks/claude-hook-tools.d.ts +26 -0
  192. package/dist/hooks/claude-hook-tools.d.ts.map +1 -0
  193. package/dist/hooks/claude-hook-tools.js +129 -0
  194. package/dist/hooks/claude-hook-tools.js.map +1 -0
  195. package/dist/hooks/claude-hooks.d.ts +87 -0
  196. package/dist/hooks/claude-hooks.d.ts.map +1 -0
  197. package/dist/hooks/claude-hooks.js +411 -0
  198. package/dist/hooks/claude-hooks.js.map +1 -0
  199. package/dist/maintenance/doctor.d.ts +33 -0
  200. package/dist/maintenance/doctor.d.ts.map +1 -0
  201. package/dist/maintenance/doctor.js +391 -0
  202. package/dist/maintenance/doctor.js.map +1 -0
  203. package/dist/maintenance/self-update.d.ts +31 -0
  204. package/dist/maintenance/self-update.d.ts.map +1 -0
  205. package/dist/maintenance/self-update.js +81 -0
  206. package/dist/maintenance/self-update.js.map +1 -0
  207. package/dist/mcp/claude-mcp-management.d.ts +28 -0
  208. package/dist/mcp/claude-mcp-management.d.ts.map +1 -0
  209. package/dist/mcp/claude-mcp-management.js +169 -0
  210. package/dist/mcp/claude-mcp-management.js.map +1 -0
  211. package/dist/mcp/claude-mcp-oauth.d.ts +113 -0
  212. package/dist/mcp/claude-mcp-oauth.d.ts.map +1 -0
  213. package/dist/mcp/claude-mcp-oauth.js +1053 -0
  214. package/dist/mcp/claude-mcp-oauth.js.map +1 -0
  215. package/dist/mcp/claude-mcp-tools.d.ts +98 -0
  216. package/dist/mcp/claude-mcp-tools.d.ts.map +1 -0
  217. package/dist/mcp/claude-mcp-tools.js +1246 -0
  218. package/dist/mcp/claude-mcp-tools.js.map +1 -0
  219. package/dist/mcp/praxis-mcp-server.d.ts +35 -0
  220. package/dist/mcp/praxis-mcp-server.d.ts.map +1 -0
  221. package/dist/mcp/praxis-mcp-server.js +520 -0
  222. package/dist/mcp/praxis-mcp-server.js.map +1 -0
  223. package/dist/permissions/claude-auto-classifier.d.ts +20 -0
  224. package/dist/permissions/claude-auto-classifier.d.ts.map +1 -0
  225. package/dist/permissions/claude-auto-classifier.js +140 -0
  226. package/dist/permissions/claude-auto-classifier.js.map +1 -0
  227. package/dist/permissions/claude-permission-resolver.d.ts +30 -0
  228. package/dist/permissions/claude-permission-resolver.d.ts.map +1 -0
  229. package/dist/permissions/claude-permission-resolver.js +334 -0
  230. package/dist/permissions/claude-permission-resolver.js.map +1 -0
  231. package/dist/persistence/claude-job-store.d.ts +68 -0
  232. package/dist/persistence/claude-job-store.d.ts.map +1 -0
  233. package/dist/persistence/claude-job-store.js +311 -0
  234. package/dist/persistence/claude-job-store.js.map +1 -0
  235. package/dist/persistence/claude-scheduled-task-store.d.ts +29 -0
  236. package/dist/persistence/claude-scheduled-task-store.d.ts.map +1 -0
  237. package/dist/persistence/claude-scheduled-task-store.js +163 -0
  238. package/dist/persistence/claude-scheduled-task-store.js.map +1 -0
  239. package/dist/persistence/claude-sidechain-store.d.ts +18 -0
  240. package/dist/persistence/claude-sidechain-store.d.ts.map +1 -0
  241. package/dist/persistence/claude-sidechain-store.js +107 -0
  242. package/dist/persistence/claude-sidechain-store.js.map +1 -0
  243. package/dist/persistence/claude-task-store.d.ts +72 -0
  244. package/dist/persistence/claude-task-store.d.ts.map +1 -0
  245. package/dist/persistence/claude-task-store.js +440 -0
  246. package/dist/persistence/claude-task-store.js.map +1 -0
  247. package/dist/persistence/claude-transcript-store.d.ts +85 -0
  248. package/dist/persistence/claude-transcript-store.d.ts.map +1 -0
  249. package/dist/persistence/claude-transcript-store.js +385 -0
  250. package/dist/persistence/claude-transcript-store.js.map +1 -0
  251. package/dist/persistence/claude-workflow-store.d.ts +41 -0
  252. package/dist/persistence/claude-workflow-store.d.ts.map +1 -0
  253. package/dist/persistence/claude-workflow-store.js +263 -0
  254. package/dist/persistence/claude-workflow-store.js.map +1 -0
  255. package/dist/persistence/in-memory-sidechain-store.d.ts +12 -0
  256. package/dist/persistence/in-memory-sidechain-store.d.ts.map +1 -0
  257. package/dist/persistence/in-memory-sidechain-store.js +30 -0
  258. package/dist/persistence/in-memory-sidechain-store.js.map +1 -0
  259. package/dist/persistence/in-memory-transcript-store.d.ts +15 -0
  260. package/dist/persistence/in-memory-transcript-store.d.ts.map +1 -0
  261. package/dist/persistence/in-memory-transcript-store.js +95 -0
  262. package/dist/persistence/in-memory-transcript-store.js.map +1 -0
  263. package/dist/platform/atomic-write.d.ts +5 -0
  264. package/dist/platform/atomic-write.d.ts.map +1 -0
  265. package/dist/platform/atomic-write.js +25 -0
  266. package/dist/platform/atomic-write.js.map +1 -0
  267. package/dist/platform/bounded-process-runner.d.ts +28 -0
  268. package/dist/platform/bounded-process-runner.d.ts.map +1 -0
  269. package/dist/platform/bounded-process-runner.js +209 -0
  270. package/dist/platform/bounded-process-runner.js.map +1 -0
  271. package/dist/platform/claude-version.d.ts +5 -0
  272. package/dist/platform/claude-version.d.ts.map +1 -0
  273. package/dist/platform/claude-version.js +17 -0
  274. package/dist/platform/claude-version.js.map +1 -0
  275. package/dist/platform/command-shell.d.ts +3 -0
  276. package/dist/platform/command-shell.d.ts.map +1 -0
  277. package/dist/platform/command-shell.js +15 -0
  278. package/dist/platform/command-shell.js.map +1 -0
  279. package/dist/platform/exclusive-file-lease.d.ts +15 -0
  280. package/dist/platform/exclusive-file-lease.d.ts.map +1 -0
  281. package/dist/platform/exclusive-file-lease.js +265 -0
  282. package/dist/platform/exclusive-file-lease.js.map +1 -0
  283. package/dist/platform/sensitive-data.d.ts +8 -0
  284. package/dist/platform/sensitive-data.d.ts.map +1 -0
  285. package/dist/platform/sensitive-data.js +138 -0
  286. package/dist/platform/sensitive-data.js.map +1 -0
  287. package/dist/platform/tmux-worktree.d.ts +30 -0
  288. package/dist/platform/tmux-worktree.d.ts.map +1 -0
  289. package/dist/platform/tmux-worktree.js +138 -0
  290. package/dist/platform/tmux-worktree.js.map +1 -0
  291. package/dist/plugins/claude-plugin-eval-discovery.d.ts +20 -0
  292. package/dist/plugins/claude-plugin-eval-discovery.d.ts.map +1 -0
  293. package/dist/plugins/claude-plugin-eval-discovery.js +128 -0
  294. package/dist/plugins/claude-plugin-eval-discovery.js.map +1 -0
  295. package/dist/plugins/claude-plugin-eval-graders.d.ts +49 -0
  296. package/dist/plugins/claude-plugin-eval-graders.d.ts.map +1 -0
  297. package/dist/plugins/claude-plugin-eval-graders.js +137 -0
  298. package/dist/plugins/claude-plugin-eval-graders.js.map +1 -0
  299. package/dist/plugins/claude-plugin-eval-runner.d.ts +50 -0
  300. package/dist/plugins/claude-plugin-eval-runner.d.ts.map +1 -0
  301. package/dist/plugins/claude-plugin-eval-runner.js +189 -0
  302. package/dist/plugins/claude-plugin-eval-runner.js.map +1 -0
  303. package/dist/plugins/claude-plugin-eval-schema.d.ts +80 -0
  304. package/dist/plugins/claude-plugin-eval-schema.d.ts.map +1 -0
  305. package/dist/plugins/claude-plugin-eval-schema.js +436 -0
  306. package/dist/plugins/claude-plugin-eval-schema.js.map +1 -0
  307. package/dist/plugins/claude-plugin-eval.d.ts +66 -0
  308. package/dist/plugins/claude-plugin-eval.d.ts.map +1 -0
  309. package/dist/plugins/claude-plugin-eval.js +438 -0
  310. package/dist/plugins/claude-plugin-eval.js.map +1 -0
  311. package/dist/plugins/claude-plugin-maintenance.d.ts +39 -0
  312. package/dist/plugins/claude-plugin-maintenance.d.ts.map +1 -0
  313. package/dist/plugins/claude-plugin-maintenance.js +336 -0
  314. package/dist/plugins/claude-plugin-maintenance.js.map +1 -0
  315. package/dist/plugins/claude-plugin-marketplace.d.ts +97 -0
  316. package/dist/plugins/claude-plugin-marketplace.d.ts.map +1 -0
  317. package/dist/plugins/claude-plugin-marketplace.js +1433 -0
  318. package/dist/plugins/claude-plugin-marketplace.js.map +1 -0
  319. package/dist/plugins/claude-plugin-mcpb.d.ts +71 -0
  320. package/dist/plugins/claude-plugin-mcpb.d.ts.map +1 -0
  321. package/dist/plugins/claude-plugin-mcpb.js +885 -0
  322. package/dist/plugins/claude-plugin-mcpb.js.map +1 -0
  323. package/dist/plugins/claude-plugin-runtime.d.ts +120 -0
  324. package/dist/plugins/claude-plugin-runtime.d.ts.map +1 -0
  325. package/dist/plugins/claude-plugin-runtime.js +1263 -0
  326. package/dist/plugins/claude-plugin-runtime.js.map +1 -0
  327. package/dist/providers/anthropic-compatible.d.ts +35 -0
  328. package/dist/providers/anthropic-compatible.d.ts.map +1 -0
  329. package/dist/providers/anthropic-compatible.js +733 -0
  330. package/dist/providers/anthropic-compatible.js.map +1 -0
  331. package/dist/providers/environment.d.ts +14 -0
  332. package/dist/providers/environment.d.ts.map +1 -0
  333. package/dist/providers/environment.js +67 -0
  334. package/dist/providers/environment.js.map +1 -0
  335. package/dist/providers/fallback-provider.d.ts +17 -0
  336. package/dist/providers/fallback-provider.d.ts.map +1 -0
  337. package/dist/providers/fallback-provider.js +70 -0
  338. package/dist/providers/fallback-provider.js.map +1 -0
  339. package/dist/providers/openai-compatible.d.ts +30 -0
  340. package/dist/providers/openai-compatible.d.ts.map +1 -0
  341. package/dist/providers/openai-compatible.js +409 -0
  342. package/dist/providers/openai-compatible.js.map +1 -0
  343. package/dist/tools/claude-interactive-tools.d.ts +58 -0
  344. package/dist/tools/claude-interactive-tools.d.ts.map +1 -0
  345. package/dist/tools/claude-interactive-tools.js +390 -0
  346. package/dist/tools/claude-interactive-tools.js.map +1 -0
  347. package/dist/tools/claude-lsp-formatters.d.ts +2 -0
  348. package/dist/tools/claude-lsp-formatters.d.ts.map +1 -0
  349. package/dist/tools/claude-lsp-formatters.js +291 -0
  350. package/dist/tools/claude-lsp-formatters.js.map +1 -0
  351. package/dist/tools/claude-lsp-tool.d.ts +22 -0
  352. package/dist/tools/claude-lsp-tool.d.ts.map +1 -0
  353. package/dist/tools/claude-lsp-tool.js +744 -0
  354. package/dist/tools/claude-lsp-tool.js.map +1 -0
  355. package/dist/tools/claude-scheduled-tools.d.ts +20 -0
  356. package/dist/tools/claude-scheduled-tools.d.ts.map +1 -0
  357. package/dist/tools/claude-scheduled-tools.js +344 -0
  358. package/dist/tools/claude-scheduled-tools.js.map +1 -0
  359. package/dist/tools/claude-task-tools.d.ts +30 -0
  360. package/dist/tools/claude-task-tools.d.ts.map +1 -0
  361. package/dist/tools/claude-task-tools.js +503 -0
  362. package/dist/tools/claude-task-tools.js.map +1 -0
  363. package/dist/tools/claude-user-message.d.ts +16 -0
  364. package/dist/tools/claude-user-message.d.ts.map +1 -0
  365. package/dist/tools/claude-user-message.js +98 -0
  366. package/dist/tools/claude-user-message.js.map +1 -0
  367. package/dist/tools/claude-workflow-tools.d.ts +27 -0
  368. package/dist/tools/claude-workflow-tools.d.ts.map +1 -0
  369. package/dist/tools/claude-workflow-tools.js +257 -0
  370. package/dist/tools/claude-workflow-tools.js.map +1 -0
  371. package/dist/tools/claude-worktree-tools.d.ts +17 -0
  372. package/dist/tools/claude-worktree-tools.d.ts.map +1 -0
  373. package/dist/tools/claude-worktree-tools.js +135 -0
  374. package/dist/tools/claude-worktree-tools.js.map +1 -0
  375. package/dist/tools/filtered-tool-registry.d.ts +16 -0
  376. package/dist/tools/filtered-tool-registry.d.ts.map +1 -0
  377. package/dist/tools/filtered-tool-registry.js +51 -0
  378. package/dist/tools/filtered-tool-registry.js.map +1 -0
  379. package/dist/tools/glob.d.ts +9 -0
  380. package/dist/tools/glob.d.ts.map +1 -0
  381. package/dist/tools/glob.js +88 -0
  382. package/dist/tools/glob.js.map +1 -0
  383. package/dist/tools/local-tools.d.ts +47 -0
  384. package/dist/tools/local-tools.d.ts.map +1 -0
  385. package/dist/tools/local-tools.js +1082 -0
  386. package/dist/tools/local-tools.js.map +1 -0
  387. package/dist/tools/notebook.d.ts +22 -0
  388. package/dist/tools/notebook.d.ts.map +1 -0
  389. package/dist/tools/notebook.js +154 -0
  390. package/dist/tools/notebook.js.map +1 -0
  391. package/dist/tools/web.d.ts +48 -0
  392. package/dist/tools/web.d.ts.map +1 -0
  393. package/dist/tools/web.js +726 -0
  394. package/dist/tools/web.js.map +1 -0
  395. package/package.json +145 -0
@@ -0,0 +1,1082 @@
1
+ import { constants } from 'node:fs';
2
+ import { mkdir, mkdtemp, open, realpath, stat, writeFile, } from 'node:fs/promises';
3
+ import { basename, dirname, extname, isAbsolute, join, relative, resolve, } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import { pdf } from 'pdf-to-img';
6
+ import sharp from 'sharp';
7
+ import { commandShell, commandShellArguments, } from '../platform/command-shell.js';
8
+ import { BoundedProcessRunner, joinedProcessOutput, } from '../platform/bounded-process-runner.js';
9
+ import { globFiles } from './glob.js';
10
+ import { editNotebook, formatNotebookForRead } from './notebook.js';
11
+ const REPORT_FINDINGS_DEFINITION = {
12
+ name: 'ReportFindings',
13
+ description: "Report code-review findings as a typed list so the host UI can render them. Use this only when the active code-review instructions tell you to report findings with this tool; otherwise follow whatever output format those instructions specify. When reporting a review's results, call it once with the verified findings ranked most-severe first (empty array if nothing survived verification) and do not also print the findings as text. When re-reporting after applying fixes (only if the apply instructions ask for it), set outcome on each finding to what actually happened.",
14
+ inputSchema: {
15
+ type: 'object',
16
+ properties: {
17
+ level: {
18
+ description: 'Effort level the review ran at',
19
+ type: 'string',
20
+ enum: ['low', 'medium', 'high', 'xhigh', 'max'],
21
+ },
22
+ findings: {
23
+ description: 'Verified findings, most-severe first; empty if none survived',
24
+ maxItems: 32,
25
+ type: 'array',
26
+ items: {
27
+ type: 'object',
28
+ properties: {
29
+ file: {
30
+ description: 'Repo-relative path of the file the finding is in',
31
+ type: 'string',
32
+ },
33
+ line: {
34
+ description: '1-indexed line the finding anchors to',
35
+ type: 'integer',
36
+ minimum: Number.MIN_SAFE_INTEGER,
37
+ maximum: Number.MAX_SAFE_INTEGER,
38
+ },
39
+ summary: {
40
+ description: 'One-sentence statement of the defect',
41
+ type: 'string',
42
+ },
43
+ failure_scenario: {
44
+ description: 'Concrete inputs/state → wrong output/crash',
45
+ type: 'string',
46
+ },
47
+ category: {
48
+ description: 'Short kebab-case slug of the finding type, e.g. "correctness", "simplification", "efficiency", "test-coverage"',
49
+ type: 'string',
50
+ maxLength: 40,
51
+ },
52
+ verdict: {
53
+ description: 'Set when a verify pass ran; absent on inline-only reviews',
54
+ type: 'string',
55
+ enum: ['CONFIRMED', 'PLAUSIBLE'],
56
+ },
57
+ outcome: {
58
+ description: 'Set ONLY when re-reporting after applying fixes: what happened to this finding',
59
+ type: 'string',
60
+ enum: ['fixed', 'skipped', 'no_change_needed'],
61
+ },
62
+ },
63
+ required: ['file', 'summary', 'failure_scenario'],
64
+ additionalProperties: false,
65
+ },
66
+ },
67
+ },
68
+ required: ['findings'],
69
+ additionalProperties: false,
70
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
71
+ },
72
+ };
73
+ const TOOL_DEFINITIONS = [
74
+ {
75
+ name: 'Read',
76
+ description: 'Reads a file from the local filesystem. You can access any file directly by using this tool.\nAssume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.\n\nUsage:\n- The file_path parameter must be an absolute path, not a relative path\n- By default, it reads up to 2000 lines starting from the beginning of the file\n- You can optionally specify a line offset and limit (especially handy for long files), but it\'s recommended to read the whole file by not providing these parameters\n- Results are returned using cat -n format, with line numbers starting at 1\n- This tool allows Claude Code to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as Claude Code is a multimodal LLM.\n- This tool can read PDF files (.pdf). For large PDFs (more than 10 pages), you MUST provide the pages parameter to read specific page ranges (e.g., pages: "1-5"). Reading a large PDF without the pages parameter will fail. Maximum 20 pages per request.\n- This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations.\n- This tool can only read files, not directories. To list files in a directory, use the registered shell tool.\n- You will regularly be asked to read screenshots. If the user provides a path to a screenshot, ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths.\n- If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.\n- Do NOT re-read a file you just edited to verify — Edit/Write would have errored if the change failed, and the harness tracks file state for you.',
77
+ inputSchema: {
78
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
79
+ type: 'object',
80
+ properties: {
81
+ file_path: {
82
+ description: 'The absolute path to the file to read',
83
+ type: 'string',
84
+ },
85
+ offset: {
86
+ description: 'The line number to start reading from. Only provide if the file is too large to read at once',
87
+ type: 'integer',
88
+ minimum: 0,
89
+ maximum: Number.MAX_SAFE_INTEGER,
90
+ },
91
+ limit: {
92
+ description: 'The number of lines to read. Only provide if the file is too large to read at once.',
93
+ type: 'integer',
94
+ exclusiveMinimum: 0,
95
+ maximum: Number.MAX_SAFE_INTEGER,
96
+ },
97
+ pages: {
98
+ description: 'Page range for PDF files (e.g., "1-5", "3", "10-20"). Only applicable to PDF files. Maximum 20 pages per request.',
99
+ type: 'string',
100
+ },
101
+ },
102
+ required: ['file_path'],
103
+ additionalProperties: false,
104
+ },
105
+ },
106
+ {
107
+ name: 'Write',
108
+ description: "Writes a file to the local filesystem.\n\nUsage:\n- This tool will overwrite the existing file if there is one at the provided path.\n- If this is an existing file, you MUST use the Read tool first to read the file's contents. This tool will fail if you did not read the file first.\n- Prefer the Edit tool for modifying existing files — it only sends the diff. Only use this tool to create new files or for complete rewrites.\n- NEVER create documentation files (*.md) or README files unless explicitly requested by the User.\n- Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.",
109
+ inputSchema: {
110
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
111
+ type: 'object',
112
+ properties: {
113
+ file_path: {
114
+ description: 'The absolute path to the file to write (must be absolute, not relative)',
115
+ type: 'string',
116
+ },
117
+ content: {
118
+ description: 'The content to write to the file',
119
+ type: 'string',
120
+ },
121
+ },
122
+ required: ['file_path', 'content'],
123
+ additionalProperties: false,
124
+ },
125
+ },
126
+ {
127
+ name: 'Edit',
128
+ description: 'Performs exact string replacements in files.\n\nUsage:\n- You must use your `Read` tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file.\n- When editing text from Read tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: line number + tab. Everything after that is the actual file content to match. Never include any part of the line number prefix in the old_string or new_string.\n- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.\n- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.\n- The edit will FAIL if `old_string` is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use `replace_all` to change every instance of `old_string`.\n- Use `replace_all` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.',
129
+ inputSchema: {
130
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
131
+ type: 'object',
132
+ properties: {
133
+ file_path: {
134
+ description: 'The absolute path to the file to modify',
135
+ type: 'string',
136
+ },
137
+ old_string: { description: 'The text to replace', type: 'string' },
138
+ new_string: {
139
+ description: 'The text to replace it with (must be different from old_string)',
140
+ type: 'string',
141
+ },
142
+ replace_all: {
143
+ description: 'Replace all occurrences of old_string (default false)',
144
+ default: false,
145
+ type: 'boolean',
146
+ },
147
+ },
148
+ required: ['file_path', 'old_string', 'new_string'],
149
+ additionalProperties: false,
150
+ },
151
+ },
152
+ {
153
+ name: 'NotebookEdit',
154
+ description: 'Replace, insert, or delete one cell in a Jupyter notebook after reading it.',
155
+ inputSchema: {
156
+ type: 'object',
157
+ properties: {
158
+ notebook_path: { type: 'string' },
159
+ cell_id: { type: 'string' },
160
+ new_source: { type: 'string' },
161
+ cell_type: { type: 'string', enum: ['code', 'markdown'] },
162
+ edit_mode: {
163
+ type: 'string',
164
+ enum: ['replace', 'insert', 'delete'],
165
+ },
166
+ },
167
+ required: ['notebook_path', 'new_source'],
168
+ additionalProperties: false,
169
+ },
170
+ },
171
+ {
172
+ name: 'Glob',
173
+ description: '- Fast file pattern matching tool that works with any codebase size\n- Supports glob patterns like "**/*.js" or "src/**/*.ts"\n- Returns matching file paths sorted by modification time\n- Use this tool when you need to find files by name patterns\n- When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the Agent tool instead',
174
+ inputSchema: {
175
+ type: 'object',
176
+ properties: {
177
+ pattern: {
178
+ type: 'string',
179
+ description: 'The glob pattern to match files against',
180
+ },
181
+ path: {
182
+ type: 'string',
183
+ description: 'The directory to search in. If not specified, the current working directory will be used. IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null" - simply omit it for the default behavior. Must be a valid directory path if provided.',
184
+ },
185
+ },
186
+ required: ['pattern'],
187
+ additionalProperties: false,
188
+ },
189
+ },
190
+ {
191
+ name: 'Grep',
192
+ description: 'Search text with ripgrep inside the active workspace.',
193
+ inputSchema: {
194
+ type: 'object',
195
+ properties: {
196
+ pattern: { type: 'string' },
197
+ path: { type: 'string' },
198
+ glob: { type: 'string' },
199
+ },
200
+ required: ['pattern'],
201
+ additionalProperties: false,
202
+ },
203
+ },
204
+ {
205
+ name: 'Bash',
206
+ description: "Executes a given bash command and returns its output.\n\nThe working directory persists between commands, but shell state does not. The shell environment is initialized from the user's profile (bash or zsh).",
207
+ inputSchema: {
208
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
209
+ type: 'object',
210
+ properties: {
211
+ command: { description: 'The command to execute', type: 'string' },
212
+ timeout: {
213
+ description: 'Optional timeout in milliseconds (max 600000)',
214
+ type: 'number',
215
+ },
216
+ description: {
217
+ description: 'Clear, concise description of what this command does in active voice. Never use words like "complex" or "risk" in the description - just describe what it does.\n\nFor simple commands (git, npm, standard CLI tools), keep it brief (5-10 words):\n- ls → "List files in current directory"\n- git status → "Show working tree status"\n- npm install → "Install package dependencies"\n\nFor commands that are harder to parse at a glance (piped commands, obscure flags, etc.), add enough context to clarify what it does:\n- find . -name "*.tmp" -exec rm {} \\; → "Find and delete all .tmp files recursively"\n- git reset --hard origin/main → "Discard all local changes and match remote main"\n- curl -s url | jq \'.data[]\' → "Fetch JSON from URL and extract data array elements"',
218
+ type: 'string',
219
+ },
220
+ run_in_background: {
221
+ description: 'Set to true to run this command in the background.',
222
+ type: 'boolean',
223
+ },
224
+ dangerouslyDisableSandbox: {
225
+ description: 'Set this to true to dangerously override sandbox mode and run commands without sandboxing.',
226
+ type: 'boolean',
227
+ },
228
+ },
229
+ required: ['command'],
230
+ additionalProperties: false,
231
+ },
232
+ },
233
+ ];
234
+ function stringInput(input, name, allowEmpty = false) {
235
+ const value = input[name];
236
+ if (typeof value !== 'string' || (!allowEmpty && value.length === 0)) {
237
+ throw new Error(`${name} must be a${allowEmpty ? '' : ' non-empty'} string`);
238
+ }
239
+ return value;
240
+ }
241
+ function optionalString(input, name) {
242
+ const value = input[name];
243
+ if (value === undefined)
244
+ return undefined;
245
+ if (typeof value !== 'string' || value.length === 0) {
246
+ throw new Error(`${name} must be a non-empty string`);
247
+ }
248
+ return value;
249
+ }
250
+ function optionalPositiveInteger(input, name) {
251
+ const value = input[name];
252
+ if (value === undefined)
253
+ return undefined;
254
+ if (!Number.isInteger(value) || typeof value !== 'number' || value <= 0) {
255
+ throw new Error(`${name} must be a positive integer`);
256
+ }
257
+ return value;
258
+ }
259
+ function optionalNonNegativeInteger(input, name) {
260
+ const value = input[name];
261
+ if (value === undefined)
262
+ return undefined;
263
+ if (!Number.isInteger(value) || typeof value !== 'number' || value < 0) {
264
+ throw new Error(`${name} must be a non-negative integer`);
265
+ }
266
+ return value;
267
+ }
268
+ function isRecord(value) {
269
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
270
+ }
271
+ const REPORT_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max'];
272
+ const REPORT_VERDICTS = ['CONFIRMED', 'PLAUSIBLE'];
273
+ const REPORT_OUTCOMES = ['fixed', 'skipped', 'no_change_needed'];
274
+ function reportFindingsInput(input) {
275
+ for (const key of Object.keys(input)) {
276
+ if (key !== 'level' && key !== 'findings') {
277
+ throw new Error(`Unknown ReportFindings input field ${key}`);
278
+ }
279
+ }
280
+ const level = input.level;
281
+ if (level !== undefined &&
282
+ (typeof level !== 'string' || !REPORT_LEVELS.includes(level))) {
283
+ throw new Error('level must be one of low, medium, high, xhigh, max');
284
+ }
285
+ const findings = input.findings;
286
+ if (!Array.isArray(findings)) {
287
+ throw new Error('findings must be an array');
288
+ }
289
+ if (findings.length > 32)
290
+ throw new Error('findings must contain at most 32 items');
291
+ const normalized = findings.map((finding, index) => {
292
+ if (!isRecord(finding))
293
+ throw new Error(`finding ${index} must be an object`);
294
+ const allowed = new Set([
295
+ 'file',
296
+ 'line',
297
+ 'summary',
298
+ 'failure_scenario',
299
+ 'category',
300
+ 'verdict',
301
+ 'outcome',
302
+ ]);
303
+ for (const key of Object.keys(finding)) {
304
+ if (!allowed.has(key)) {
305
+ throw new Error(`Unknown ReportFindings finding field ${key}`);
306
+ }
307
+ }
308
+ for (const key of ['file', 'summary', 'failure_scenario']) {
309
+ if (typeof finding[key] !== 'string') {
310
+ throw new Error(`finding ${index}.${key} must be a string`);
311
+ }
312
+ }
313
+ if (finding.line !== undefined &&
314
+ (!Number.isSafeInteger(finding.line) || typeof finding.line !== 'number')) {
315
+ throw new Error(`finding ${index}.line must be an integer`);
316
+ }
317
+ if (finding.category !== undefined &&
318
+ (typeof finding.category !== 'string' ||
319
+ [...finding.category].length > 40)) {
320
+ throw new Error(`finding ${index}.category must be at most 40 characters`);
321
+ }
322
+ if (finding.verdict !== undefined &&
323
+ (typeof finding.verdict !== 'string' ||
324
+ !REPORT_VERDICTS.includes(finding.verdict))) {
325
+ throw new Error(`finding ${index}.verdict is invalid`);
326
+ }
327
+ if (finding.outcome !== undefined &&
328
+ (typeof finding.outcome !== 'string' ||
329
+ !REPORT_OUTCOMES.includes(finding.outcome))) {
330
+ throw new Error(`finding ${index}.outcome is invalid`);
331
+ }
332
+ return {
333
+ file: finding.file,
334
+ ...(finding.line === undefined ? {} : { line: finding.line }),
335
+ summary: finding.summary,
336
+ failure_scenario: finding.failure_scenario,
337
+ ...(finding.category === undefined ? {} : { category: finding.category }),
338
+ ...(finding.verdict === undefined ? {} : { verdict: finding.verdict }),
339
+ ...(finding.outcome === undefined ? {} : { outcome: finding.outcome }),
340
+ };
341
+ });
342
+ return {
343
+ ...(level === undefined ? {} : { level }),
344
+ findings: normalized,
345
+ };
346
+ }
347
+ function isWithin(root, target) {
348
+ const pathFromRoot = relative(root, target);
349
+ return (pathFromRoot === '' ||
350
+ (!pathFromRoot.startsWith('..') && !isAbsolute(pathFromRoot)));
351
+ }
352
+ function takeUtf8Prefix(content, maxBytes) {
353
+ const encodedBytes = Buffer.byteLength(content);
354
+ if (encodedBytes <= maxBytes) {
355
+ return { content, bytes: encodedBytes, truncated: false };
356
+ }
357
+ let prefix = '';
358
+ let bytes = 0;
359
+ for (const character of content) {
360
+ const characterBytes = Buffer.byteLength(character);
361
+ if (bytes + characterBytes > maxBytes)
362
+ break;
363
+ prefix += character;
364
+ bytes += characterBytes;
365
+ }
366
+ return { content: prefix, bytes, truncated: true };
367
+ }
368
+ function truncateOutput(content, maxBytes) {
369
+ const retained = takeUtf8Prefix(content, maxBytes);
370
+ return retained.truncated
371
+ ? `${retained.content}\n[output truncated]`
372
+ : retained.content;
373
+ }
374
+ function abortError() {
375
+ return new DOMException('Tool execution aborted', 'AbortError');
376
+ }
377
+ function imageMediaType(content) {
378
+ if (content.length >= 8 &&
379
+ content
380
+ .subarray(0, 8)
381
+ .equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))) {
382
+ return 'image/png';
383
+ }
384
+ if (content.length >= 3 &&
385
+ content[0] === 0xff &&
386
+ content[1] === 0xd8 &&
387
+ content[2] === 0xff) {
388
+ return 'image/jpeg';
389
+ }
390
+ const header = content.subarray(0, 6).toString('ascii');
391
+ if (header === 'GIF87a' || header === 'GIF89a')
392
+ return 'image/gif';
393
+ if (content.length >= 12 &&
394
+ content.subarray(0, 4).toString('ascii') === 'RIFF' &&
395
+ content.subarray(8, 12).toString('ascii') === 'WEBP') {
396
+ return 'image/webp';
397
+ }
398
+ return null;
399
+ }
400
+ function isPdf(content) {
401
+ return content.subarray(0, 5).toString('ascii') === '%PDF-';
402
+ }
403
+ function formatKilobytes(bytes) {
404
+ const value = bytes / 1024;
405
+ return `${value < 10 ? value.toFixed(1) : Math.round(value)}KB`.replace('.0KB', 'KB');
406
+ }
407
+ function parsePdfPages(value) {
408
+ const match = /^(\d+)(?:-(\d+))?$/u.exec(value);
409
+ if (!match)
410
+ throw new Error(`Invalid PDF page range: ${value}`);
411
+ const start = Number(match[1]);
412
+ const end = Number(match[2] ?? match[1]);
413
+ if (!Number.isSafeInteger(start) ||
414
+ !Number.isSafeInteger(end) ||
415
+ start < 1 ||
416
+ end < start) {
417
+ throw new Error(`Invalid PDF page range: ${value}`);
418
+ }
419
+ if (end - start + 1 > 20) {
420
+ throw new Error('PDF page range cannot exceed 20 pages');
421
+ }
422
+ return { start, end };
423
+ }
424
+ export class LocalToolRegistry {
425
+ cwd;
426
+ cwdProvider;
427
+ sharedMemoryDirectory;
428
+ additionalDirectories;
429
+ additionalReadDirectories;
430
+ maxOutputBytes;
431
+ maxFileBytes;
432
+ maxShellTimeoutMs;
433
+ processRunner;
434
+ enableReportFindings;
435
+ environment;
436
+ constructor(options) {
437
+ this.cwd = resolve(options.cwd);
438
+ this.cwdProvider = options.cwdProvider;
439
+ this.sharedMemoryDirectory = options.sharedMemoryDirectory
440
+ ? resolve(options.sharedMemoryDirectory)
441
+ : undefined;
442
+ this.additionalDirectories = (options.additionalDirectories ?? []).map((directory) => resolve(directory));
443
+ this.additionalReadDirectories = (options.additionalReadDirectories ?? []).map((directory) => resolve(directory));
444
+ this.maxOutputBytes = options.maxOutputBytes ?? 128 * 1024;
445
+ this.maxFileBytes = options.maxFileBytes ?? 10 * 1024 * 1024;
446
+ this.maxShellTimeoutMs = options.maxShellTimeoutMs ?? 120_000;
447
+ this.enableReportFindings = options.enableReportFindings ?? false;
448
+ this.environment = options.environment;
449
+ this.processRunner = new BoundedProcessRunner({
450
+ cwd: this.cwd,
451
+ maxOutputBytes: this.maxOutputBytes,
452
+ });
453
+ }
454
+ currentCwd(context) {
455
+ return resolve(context?.cwd || this.cwdProvider?.() || this.cwd);
456
+ }
457
+ definitions() {
458
+ const definitions = this.enableReportFindings
459
+ ? [...TOOL_DEFINITIONS, REPORT_FINDINGS_DEFINITION]
460
+ : TOOL_DEFINITIONS;
461
+ if (!this.sharedMemoryDirectory &&
462
+ this.additionalDirectories.length === 0 &&
463
+ this.additionalReadDirectories.length === 0) {
464
+ return definitions;
465
+ }
466
+ return definitions.map((definition) => ['Read', 'Write', 'Edit', 'NotebookEdit', 'Glob', 'Grep'].includes(definition.name)
467
+ ? {
468
+ ...definition,
469
+ description: `${definition.description}${this.additionalDirectories.length === 0
470
+ ? ''
471
+ : ` Additional allowed directories: ${this.additionalDirectories.join(', ')}.`}${definition.name !== 'Read' ||
472
+ this.additionalReadDirectories.length === 0
473
+ ? ''
474
+ : ` Additional read-only directories: ${this.additionalReadDirectories.join(', ')}.`}${!this.sharedMemoryDirectory ||
475
+ definition.name === 'Glob' ||
476
+ definition.name === 'Grep'
477
+ ? ''
478
+ : ` Shared auto-memory files under ${this.sharedMemoryDirectory} are also allowed.`}`,
479
+ }
480
+ : definition);
481
+ }
482
+ async prepare(call, context) {
483
+ if (context.signal?.aborted)
484
+ throw abortError();
485
+ switch (call.name) {
486
+ case 'Read': {
487
+ const offset = optionalNonNegativeInteger(call.input, 'offset');
488
+ const limit = optionalPositiveInteger(call.input, 'limit');
489
+ const pages = optionalString(call.input, 'pages');
490
+ return {
491
+ ...call,
492
+ input: {
493
+ file_path: await this.filePath(stringInput(call.input, 'file_path'), false, true, context),
494
+ ...(offset === undefined ? {} : { offset }),
495
+ ...(limit === undefined ? {} : { limit }),
496
+ ...(pages === undefined ? {} : { pages }),
497
+ },
498
+ };
499
+ }
500
+ case 'Write':
501
+ return {
502
+ ...call,
503
+ input: {
504
+ file_path: await this.filePath(stringInput(call.input, 'file_path'), true, false, context),
505
+ content: stringInput(call.input, 'content', true),
506
+ },
507
+ };
508
+ case 'Edit': {
509
+ const replaceAll = call.input.replace_all;
510
+ if (replaceAll !== undefined && typeof replaceAll !== 'boolean') {
511
+ throw new Error('replace_all must be a boolean');
512
+ }
513
+ return {
514
+ ...call,
515
+ input: {
516
+ file_path: await this.filePath(stringInput(call.input, 'file_path'), false, false, context),
517
+ old_string: stringInput(call.input, 'old_string'),
518
+ new_string: stringInput(call.input, 'new_string', true),
519
+ replace_all: replaceAll ?? false,
520
+ },
521
+ };
522
+ }
523
+ case 'NotebookEdit': {
524
+ const requestedPath = stringInput(call.input, 'notebook_path');
525
+ if (!isAbsolute(requestedPath)) {
526
+ throw new Error('notebook_path must be an absolute path');
527
+ }
528
+ const filePath = await this.filePath(requestedPath, false, false, context);
529
+ if (extname(filePath).toLowerCase() !== '.ipynb') {
530
+ throw new Error('notebook_path must reference an .ipynb file');
531
+ }
532
+ if (!(await this.wasSuccessfullyRead(filePath, context.messages ?? [], context))) {
533
+ throw new Error('<tool_use_error>File has not been read yet. Read it first before writing to it.</tool_use_error>');
534
+ }
535
+ const cellId = optionalString(call.input, 'cell_id');
536
+ const cellType = optionalString(call.input, 'cell_type');
537
+ if (cellType !== undefined &&
538
+ cellType !== 'code' &&
539
+ cellType !== 'markdown') {
540
+ throw new Error('cell_type must be code or markdown');
541
+ }
542
+ const editMode = optionalString(call.input, 'edit_mode') ?? 'replace';
543
+ if (!['replace', 'insert', 'delete'].includes(editMode)) {
544
+ throw new Error('edit_mode must be replace, insert, or delete');
545
+ }
546
+ if (editMode === 'insert' && cellType === undefined) {
547
+ throw new Error('cell_type is required for insert');
548
+ }
549
+ if (editMode !== 'insert' && cellId === undefined) {
550
+ throw new Error(`cell_id is required for ${editMode}`);
551
+ }
552
+ return {
553
+ ...call,
554
+ input: {
555
+ notebook_path: filePath,
556
+ ...(cellId === undefined ? {} : { cell_id: cellId }),
557
+ new_source: stringInput(call.input, 'new_source', true),
558
+ ...(cellType === undefined ? {} : { cell_type: cellType }),
559
+ edit_mode: editMode,
560
+ },
561
+ };
562
+ }
563
+ case 'Glob': {
564
+ const pathInput = call.input.path;
565
+ const requestedPath = pathInput === undefined ? '.' : stringInput(call.input, 'path');
566
+ await this.globRoot(requestedPath, context);
567
+ return {
568
+ ...call,
569
+ input: {
570
+ pattern: stringInput(call.input, 'pattern', true),
571
+ ...(pathInput === undefined ? {} : { path: requestedPath }),
572
+ },
573
+ };
574
+ }
575
+ case 'Grep': {
576
+ const glob = optionalString(call.input, 'glob');
577
+ return {
578
+ ...call,
579
+ input: {
580
+ pattern: stringInput(call.input, 'pattern'),
581
+ path: await this.workspacePath(optionalString(call.input, 'path') ?? '.', false, context),
582
+ ...(glob === undefined ? {} : { glob }),
583
+ },
584
+ };
585
+ }
586
+ case 'Bash': {
587
+ const requestedTimeout = optionalPositiveInteger(call.input, 'timeout');
588
+ return {
589
+ ...call,
590
+ input: {
591
+ command: stringInput(call.input, 'command'),
592
+ timeout: Math.min(requestedTimeout ?? this.maxShellTimeoutMs, this.maxShellTimeoutMs),
593
+ },
594
+ };
595
+ }
596
+ case 'ReportFindings':
597
+ return { ...call, input: reportFindingsInput(call.input) };
598
+ default:
599
+ throw new Error(`Unknown tool ${call.name}`);
600
+ }
601
+ }
602
+ async execute(call, context) {
603
+ if (context.signal?.aborted)
604
+ throw abortError();
605
+ const prepared = await this.prepare(call, context);
606
+ if (JSON.stringify(prepared.input) !== JSON.stringify(call.input)) {
607
+ throw new Error('Tool input changed after permission approval');
608
+ }
609
+ switch (prepared.name) {
610
+ case 'Read':
611
+ return this.read(prepared, context);
612
+ case 'Write':
613
+ return this.write(prepared);
614
+ case 'Edit':
615
+ return this.edit(prepared);
616
+ case 'NotebookEdit':
617
+ return this.notebookEdit(prepared);
618
+ case 'Glob':
619
+ return this.glob(prepared, context);
620
+ case 'Grep':
621
+ return this.grep(prepared, context);
622
+ case 'Bash':
623
+ return this.bash(prepared, context);
624
+ case 'ReportFindings':
625
+ return {
626
+ content: JSON.stringify({
627
+ count: prepared.input.findings.length,
628
+ ...(prepared.input.level === undefined
629
+ ? {}
630
+ : { level: prepared.input.level }),
631
+ findings: prepared.input.findings,
632
+ }),
633
+ isError: false,
634
+ };
635
+ default:
636
+ throw new Error(`Unknown tool ${prepared.name}`);
637
+ }
638
+ }
639
+ async workspacePath(requestedPath, allowMissing, context) {
640
+ return this.resolvePath(requestedPath, allowMissing, false, false, context);
641
+ }
642
+ async filePath(requestedPath, allowMissing, includeReadOnly = false, context) {
643
+ return this.resolvePath(requestedPath, allowMissing, true, includeReadOnly, context);
644
+ }
645
+ async resolvePath(requestedPath, allowMissing, includeSharedMemory, includeReadOnly = false, context) {
646
+ const workspaceRoot = await realpath(this.currentCwd(context));
647
+ const workspaceRoots = [
648
+ workspaceRoot,
649
+ ...(await Promise.all(this.additionalDirectories.map((directory) => realpath(directory)))),
650
+ ];
651
+ const writableRoots = includeSharedMemory && this.sharedMemoryDirectory
652
+ ? [...workspaceRoots, await realpath(this.sharedMemoryDirectory)]
653
+ : workspaceRoots;
654
+ const roots = includeReadOnly
655
+ ? [
656
+ ...writableRoots,
657
+ ...(await Promise.all(this.additionalReadDirectories.map(async (directory) => {
658
+ try {
659
+ return [await realpath(directory)];
660
+ }
661
+ catch (error) {
662
+ if (error.code === 'ENOENT') {
663
+ return [];
664
+ }
665
+ throw error;
666
+ }
667
+ }))).flat(),
668
+ ]
669
+ : writableRoots;
670
+ const candidate = isAbsolute(requestedPath)
671
+ ? resolve(requestedPath)
672
+ : resolve(workspaceRoot, requestedPath);
673
+ try {
674
+ const canonical = await realpath(candidate);
675
+ if (!roots.some((root) => isWithin(root, canonical))) {
676
+ throw new Error(`Path is outside workspace: ${requestedPath}`);
677
+ }
678
+ return canonical;
679
+ }
680
+ catch (error) {
681
+ if (error.code !== 'ENOENT' || !allowMissing) {
682
+ throw error;
683
+ }
684
+ const parent = await realpath(dirname(candidate));
685
+ if (!roots.some((root) => isWithin(root, parent))) {
686
+ throw new Error(`Path is outside workspace: ${requestedPath}`);
687
+ }
688
+ return join(parent, basename(candidate));
689
+ }
690
+ }
691
+ async assertStablePath(filePath) {
692
+ if ((await realpath(filePath)) !== filePath) {
693
+ throw new Error('Tool input changed after permission approval');
694
+ }
695
+ }
696
+ async globRoot(requestedPath, context) {
697
+ const displayedPath = isAbsolute(requestedPath)
698
+ ? resolve(requestedPath)
699
+ : resolve(this.currentCwd(context), requestedPath);
700
+ let root;
701
+ try {
702
+ root = await this.workspacePath(requestedPath, false, context);
703
+ }
704
+ catch (error) {
705
+ if (error.code !== 'ENOENT')
706
+ throw error;
707
+ throw new Error(`<tool_use_error>Directory does not exist: ${displayedPath}. Note: your current working directory is ${await realpath(this.currentCwd(context))}.</tool_use_error>`);
708
+ }
709
+ if (!(await stat(root)).isDirectory()) {
710
+ throw new Error(`<tool_use_error>Path is not a directory: ${displayedPath}</tool_use_error>`);
711
+ }
712
+ return root;
713
+ }
714
+ async wasSuccessfullyRead(filePath, messages, context) {
715
+ const successfulCalls = new Set(messages.flatMap((message) => message.role === 'tool' && !message.isError ? [message.toolCallId] : []));
716
+ for (const message of messages) {
717
+ if (message.role !== 'assistant')
718
+ continue;
719
+ for (const call of message.toolCalls ?? []) {
720
+ if (call.name !== 'Read' || !successfulCalls.has(call.id))
721
+ continue;
722
+ const requestedPath = call.input.file_path;
723
+ if (typeof requestedPath !== 'string')
724
+ continue;
725
+ try {
726
+ if ((await this.filePath(requestedPath, false, true, context)) ===
727
+ filePath) {
728
+ return true;
729
+ }
730
+ }
731
+ catch {
732
+ continue;
733
+ }
734
+ }
735
+ }
736
+ return false;
737
+ }
738
+ async read(call, context) {
739
+ const filePath = stringInput(call.input, 'file_path');
740
+ const handle = await open(filePath, constants.O_RDONLY | constants.O_NOFOLLOW);
741
+ try {
742
+ await this.assertStablePath(filePath);
743
+ const metadata = await handle.stat();
744
+ if (!metadata.isFile())
745
+ throw new Error(`Not a file: ${filePath}`);
746
+ if (metadata.size > this.maxFileBytes) {
747
+ throw new Error(`File exceeds ${this.maxFileBytes} byte read limit`);
748
+ }
749
+ const source = await handle.readFile();
750
+ const requestedOffset = optionalNonNegativeInteger(call.input, 'offset');
751
+ const offset = requestedOffset ?? 1;
752
+ const limit = optionalPositiveInteger(call.input, 'limit');
753
+ const mediaType = imageMediaType(source);
754
+ if (mediaType) {
755
+ if (requestedOffset !== undefined || limit !== undefined) {
756
+ throw new Error('offset and limit are not supported for images');
757
+ }
758
+ const base64 = source.toString('base64');
759
+ return {
760
+ content: '',
761
+ images: [{ type: 'image', mediaType, data: base64 }],
762
+ isError: false,
763
+ accessedPaths: [filePath],
764
+ };
765
+ }
766
+ if (isPdf(source)) {
767
+ return this.readPdf(source, filePath, call.input.pages, context);
768
+ }
769
+ const text = source.toString('utf8');
770
+ const notebook = extname(filePath).toLowerCase() === '.ipynb';
771
+ const lines = (notebook ? formatNotebookForRead(text) : text).split('\n');
772
+ const start = offset === 0 ? 0 : offset - 1;
773
+ const effectiveLimit = notebook ? limit : (limit ?? 2000);
774
+ const selected = lines.slice(start, effectiveLimit === undefined ? undefined : start + effectiveLimit);
775
+ const rawContent = selected.join('\n');
776
+ const content = notebook
777
+ ? rawContent
778
+ : selected
779
+ .map((line, index) => `${(offset === 0 ? 0 : offset) + index}\t${line}`)
780
+ .join('\n');
781
+ return {
782
+ content: truncateOutput(content, this.maxOutputBytes),
783
+ isError: false,
784
+ accessedPaths: [filePath],
785
+ ...(notebook
786
+ ? {}
787
+ : {
788
+ nativeToolUseResult: {
789
+ type: 'text',
790
+ file: {
791
+ filePath,
792
+ content: rawContent,
793
+ numLines: selected.length,
794
+ startLine: offset,
795
+ totalLines: lines.length,
796
+ },
797
+ },
798
+ }),
799
+ };
800
+ }
801
+ finally {
802
+ await handle.close();
803
+ }
804
+ }
805
+ async readPdf(source, filePath, pagesInput, context) {
806
+ const document = await pdf(source);
807
+ try {
808
+ const pages = pagesInput === undefined
809
+ ? undefined
810
+ : parsePdfPages(stringInput({ pages: pagesInput }, 'pages'));
811
+ if (pages === undefined) {
812
+ if (document.length > 10) {
813
+ throw new Error('PDF has more than 10 pages; provide pages to read a maximum of 20 pages per request');
814
+ }
815
+ return {
816
+ content: `PDF file read: ${filePath} (${formatKilobytes(source.length)})`,
817
+ documents: [
818
+ {
819
+ type: 'document',
820
+ mediaType: 'application/pdf',
821
+ data: source.toString('base64'),
822
+ },
823
+ ],
824
+ isError: false,
825
+ accessedPaths: [filePath],
826
+ nativeToolUseResult: {
827
+ type: 'pdf',
828
+ file: {
829
+ filePath,
830
+ base64: source.toString('base64'),
831
+ originalSize: source.length,
832
+ },
833
+ },
834
+ };
835
+ }
836
+ if (pages.end > document.length) {
837
+ throw new Error(`PDF page range ${pages.start}-${pages.end} exceeds document page count ${document.length}`);
838
+ }
839
+ const images = [];
840
+ const outputDirectory = await this.createPdfOutputDirectory(context);
841
+ for (let pageNumber = pages.start; pageNumber <= pages.end; pageNumber += 1) {
842
+ if (context.signal?.aborted)
843
+ throw abortError();
844
+ const png = await document.getPage(pageNumber);
845
+ const jpeg = await sharp(png).jpeg({ quality: 90 }).toBuffer();
846
+ if (jpeg.length > this.maxFileBytes) {
847
+ throw new Error(`Rendered PDF page exceeds ${this.maxFileBytes} byte read limit`);
848
+ }
849
+ const data = jpeg.toString('base64');
850
+ images.push({ type: 'image', mediaType: 'image/jpeg', data });
851
+ await writeFile(join(outputDirectory, `page-${pageNumber}.jpg`), jpeg);
852
+ }
853
+ return {
854
+ content: `PDF pages extracted: ${images.length} page(s) from ${filePath} (${formatKilobytes(source.length)})`,
855
+ images,
856
+ isError: false,
857
+ accessedPaths: [filePath],
858
+ nativeToolUseResult: {
859
+ type: 'parts',
860
+ file: {
861
+ filePath,
862
+ originalSize: source.length,
863
+ outputDir: outputDirectory,
864
+ count: images.length,
865
+ },
866
+ },
867
+ };
868
+ }
869
+ finally {
870
+ await document.destroy();
871
+ }
872
+ }
873
+ async createPdfOutputDirectory(context) {
874
+ const parent = context.toolResultDirectory
875
+ ? resolve(context.toolResultDirectory)
876
+ : tmpdir();
877
+ await mkdir(parent, { recursive: true });
878
+ return mkdtemp(join(parent, 'pdf-'));
879
+ }
880
+ async write(call) {
881
+ const filePath = stringInput(call.input, 'file_path');
882
+ const content = stringInput(call.input, 'content', true);
883
+ if (Buffer.byteLength(content) > this.maxFileBytes) {
884
+ throw new Error(`Content exceeds ${this.maxFileBytes} byte write limit`);
885
+ }
886
+ const handle = await open(filePath, constants.O_WRONLY | constants.O_CREAT | constants.O_NOFOLLOW, 0o666);
887
+ try {
888
+ await this.assertStablePath(filePath);
889
+ const metadata = await handle.stat();
890
+ if (!metadata.isFile())
891
+ throw new Error(`Not a file: ${filePath}`);
892
+ const encoded = Buffer.from(content);
893
+ await handle.write(encoded, 0, encoded.length, 0);
894
+ await handle.truncate(encoded.length);
895
+ await handle.sync();
896
+ return {
897
+ content: `Wrote ${encoded.length} bytes`,
898
+ isError: false,
899
+ };
900
+ }
901
+ finally {
902
+ await handle.close();
903
+ }
904
+ }
905
+ async edit(call) {
906
+ const filePath = stringInput(call.input, 'file_path');
907
+ const oldString = stringInput(call.input, 'old_string');
908
+ const newString = stringInput(call.input, 'new_string', true);
909
+ const handle = await open(filePath, constants.O_RDWR | constants.O_NOFOLLOW);
910
+ try {
911
+ await this.assertStablePath(filePath);
912
+ const metadata = await handle.stat();
913
+ if (!metadata.isFile())
914
+ throw new Error(`Not a file: ${filePath}`);
915
+ if (metadata.size > this.maxFileBytes) {
916
+ throw new Error(`File exceeds ${this.maxFileBytes} byte edit limit`);
917
+ }
918
+ const source = await handle.readFile('utf8');
919
+ const occurrences = source.split(oldString).length - 1;
920
+ if (occurrences === 0)
921
+ throw new Error('old_string was not found');
922
+ if (call.input.replace_all !== true && occurrences !== 1) {
923
+ throw new Error(`old_string matched ${occurrences} times; set replace_all`);
924
+ }
925
+ const replacementCount = call.input.replace_all === true ? occurrences : 1;
926
+ const outputBytes = Buffer.byteLength(source) +
927
+ replacementCount *
928
+ (Buffer.byteLength(newString) - Buffer.byteLength(oldString));
929
+ if (outputBytes > this.maxFileBytes) {
930
+ throw new Error(`Edited content exceeds ${this.maxFileBytes} bytes`);
931
+ }
932
+ const output = call.input.replace_all === true
933
+ ? source.replaceAll(oldString, newString)
934
+ : source.replace(oldString, newString);
935
+ const encoded = Buffer.from(output);
936
+ await handle.write(encoded, 0, encoded.length, 0);
937
+ await handle.truncate(encoded.length);
938
+ await handle.sync();
939
+ return {
940
+ content: `Replaced ${replacementCount} occurrence(s)`,
941
+ isError: false,
942
+ };
943
+ }
944
+ finally {
945
+ await handle.close();
946
+ }
947
+ }
948
+ async notebookEdit(call) {
949
+ const filePath = stringInput(call.input, 'notebook_path');
950
+ const handle = await open(filePath, constants.O_RDWR | constants.O_NOFOLLOW);
951
+ try {
952
+ await this.assertStablePath(filePath);
953
+ const metadata = await handle.stat();
954
+ if (!metadata.isFile())
955
+ throw new Error(`Not a file: ${filePath}`);
956
+ if (metadata.size > this.maxFileBytes) {
957
+ throw new Error(`File exceeds ${this.maxFileBytes} byte edit limit`);
958
+ }
959
+ const result = editNotebook(await handle.readFile('utf8'), {
960
+ ...(call.input.cell_id === undefined
961
+ ? {}
962
+ : { cellId: stringInput(call.input, 'cell_id') }),
963
+ ...(call.input.cell_type === undefined
964
+ ? {}
965
+ : {
966
+ cellType: stringInput(call.input, 'cell_type'),
967
+ }),
968
+ editMode: stringInput(call.input, 'edit_mode'),
969
+ newSource: stringInput(call.input, 'new_source', true),
970
+ });
971
+ const encoded = Buffer.from(result.source);
972
+ if (encoded.length > this.maxFileBytes) {
973
+ throw new Error(`Content exceeds ${this.maxFileBytes} byte write limit`);
974
+ }
975
+ await handle.write(encoded, 0, encoded.length, 0);
976
+ await handle.truncate(encoded.length);
977
+ await handle.sync();
978
+ return { content: result.content, isError: false };
979
+ }
980
+ finally {
981
+ await handle.close();
982
+ }
983
+ }
984
+ async glob(call, context) {
985
+ const requestedPath = call.input.path === undefined ? '.' : stringInput(call.input, 'path');
986
+ const root = await this.globRoot(requestedPath, context);
987
+ const timeoutSignal = AbortSignal.timeout(this.maxShellTimeoutMs);
988
+ const searchSignal = context.signal
989
+ ? AbortSignal.any([context.signal, timeoutSignal])
990
+ : timeoutSignal;
991
+ try {
992
+ const content = await globFiles({
993
+ root,
994
+ displayRoot: call.input.path === undefined ? '.' : requestedPath,
995
+ absoluteRoot: isAbsolute(requestedPath)
996
+ ? resolve(requestedPath)
997
+ : resolve(this.currentCwd(context), requestedPath),
998
+ pattern: stringInput(call.input, 'pattern', true),
999
+ signal: searchSignal,
1000
+ });
1001
+ return {
1002
+ content: truncateOutput(content, this.maxOutputBytes),
1003
+ isError: false,
1004
+ };
1005
+ }
1006
+ catch (error) {
1007
+ if (context.signal?.aborted)
1008
+ throw abortError();
1009
+ if (timeoutSignal.aborted) {
1010
+ return {
1011
+ content: `Search timed out after ${this.maxShellTimeoutMs}ms`,
1012
+ isError: true,
1013
+ };
1014
+ }
1015
+ throw error;
1016
+ }
1017
+ }
1018
+ async grep(call, context) {
1019
+ const workspaceRoot = await realpath(this.currentCwd(context));
1020
+ const searchPath = stringInput(call.input, 'path');
1021
+ const relativeSearchPath = relative(workspaceRoot, searchPath) || '.';
1022
+ const args = [
1023
+ '--line-number',
1024
+ '--with-filename',
1025
+ '--color=never',
1026
+ '--',
1027
+ stringInput(call.input, 'pattern'),
1028
+ relativeSearchPath,
1029
+ ];
1030
+ const glob = optionalString(call.input, 'glob');
1031
+ if (glob)
1032
+ args.splice(3, 0, '--glob', glob);
1033
+ const result = await this.processRunner.run({
1034
+ command: 'rg',
1035
+ args,
1036
+ timeoutMs: this.maxShellTimeoutMs,
1037
+ cwd: this.currentCwd(context),
1038
+ ...(this.environment ? { env: this.environment } : {}),
1039
+ ...(context.signal ? { signal: context.signal } : {}),
1040
+ });
1041
+ if (result.timedOut) {
1042
+ return {
1043
+ content: `Search timed out after ${this.maxShellTimeoutMs}ms`,
1044
+ isError: true,
1045
+ };
1046
+ }
1047
+ const content = joinedProcessOutput(result);
1048
+ if (result.code === 0 || result.code === 1) {
1049
+ return { content, isError: false };
1050
+ }
1051
+ return {
1052
+ content: content || `Search exited with code ${result.code}`,
1053
+ isError: true,
1054
+ };
1055
+ }
1056
+ async bash(call, context) {
1057
+ const timeout = optionalPositiveInteger(call.input, 'timeout');
1058
+ if (timeout === undefined)
1059
+ throw new Error('Prepared Bash call has no timeout');
1060
+ const result = await this.processRunner.run({
1061
+ command: commandShell(),
1062
+ args: commandShellArguments(stringInput(call.input, 'command')),
1063
+ timeoutMs: timeout,
1064
+ cwd: this.currentCwd(context),
1065
+ ...(this.environment ? { env: this.environment } : {}),
1066
+ ...(context.signal ? { signal: context.signal } : {}),
1067
+ });
1068
+ if (result.timedOut) {
1069
+ return {
1070
+ content: `Command timed out after ${timeout}ms`,
1071
+ isError: true,
1072
+ };
1073
+ }
1074
+ const content = joinedProcessOutput(result);
1075
+ return {
1076
+ content: content ||
1077
+ (result.code === 0 ? '' : `Command exited with code ${result.code}`),
1078
+ isError: result.code !== 0,
1079
+ };
1080
+ }
1081
+ }
1082
+ //# sourceMappingURL=local-tools.js.map