@xopcai/xopc 0.0.244 → 0.0.245

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 (239) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-CAah-_8h.js → activity-store-BlxqErph.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BhXGsupm.js → agent-avatar-dicebear-DRQnogaU.js} +1 -1
  5. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-Blzn2H6t.js → agent-defaults-settings-panel-CpOxGbMD.js} +1 -1
  6. package/dist/gateway/static/root/assets/{agents-Cmp-z8Y_.js → agents-flnXZLaT.js} +1 -1
  7. package/dist/gateway/static/root/assets/{api-B2tKxbcz.js → api-BbXzyQMj.js} +1 -1
  8. package/dist/gateway/static/root/assets/{app-management-settings-panel-CezjAP1K.js → app-management-settings-panel-CZl6n2xi.js} +1 -1
  9. package/dist/gateway/static/root/assets/{appearance-settings-C-CfS05x.js → appearance-settings-Bglp-pn6.js} +1 -1
  10. package/dist/gateway/static/root/assets/{apps-page-7Y13_bqZ.js → apps-page-CmsWarVB.js} +1 -1
  11. package/dist/gateway/static/root/assets/{archive-plugin-BmSx7wzY.js → archive-plugin-DD2SweEH.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-DI4CoIga.js → attachment-load-G0HenUmG.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-D04Xceck.js → automations-page-B78bFjH2.js} +1 -1
  14. package/dist/gateway/static/root/assets/{automations-workspace-wEO1OWk0.js → automations-workspace-BMQGmn50.js} +1 -1
  15. package/dist/gateway/static/root/assets/{binary-plugins-BJQe8TRu.js → binary-plugins-BbSQmXqn.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-BSzGjJC6.js → block-editor-DutTIH81.js} +1 -1
  17. package/dist/gateway/static/root/assets/{browser-settings-page-DjAZ_LF2.js → browser-settings-page-CALiFKm4.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflow-inputs-CRnkgZHI.js → browser-workflow-inputs-BAAc151l.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-workflows-page-CwbxA3B7.js → browser-workflows-page-DE5HPrHZ.js} +1 -1
  20. package/dist/gateway/static/root/assets/{capabilities-settings-panel-jt9bqUMK.js → capabilities-settings-panel-Dts7XtP3.js} +1 -1
  21. package/dist/gateway/static/root/assets/{channels-settings-Cz_TWY3a.js → channels-settings-CWEd3wzh.js} +1 -1
  22. package/dist/gateway/static/root/assets/{channels-status-swr-DuY4MGxe.js → channels-status-swr-CCBCtLDg.js} +1 -1
  23. package/dist/gateway/static/root/assets/{chat-terminal-dock-D3gj2D3U.js → chat-terminal-dock-Bp1fXQm1.js} +1 -1
  24. package/dist/gateway/static/root/assets/{connectors-page-Shs5vbzx.js → connectors-page-CQ6wVNLm.js} +1 -1
  25. package/dist/gateway/static/root/assets/{cron-expression-DgWHw0jX.js → cron-expression-B8HA5IRb.js} +1 -1
  26. package/dist/gateway/static/root/assets/{date-picker-CKg-RPbs.js → date-picker-DD8b7oad.js} +1 -1
  27. package/dist/gateway/static/root/assets/{dependency-picker-CVYkw-NN.js → dependency-picker-BC9zwIyH.js} +1 -1
  28. package/dist/gateway/static/root/assets/{desktop-pet-Bf46oXTY.js → desktop-pet-DsrsPZTW.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-settings-BJO_klc7.js → desktop-pet-settings-D7gp_HNA.js} +1 -1
  30. package/dist/gateway/static/root/assets/{extension-debug-page-T2PmFFOW.js → extension-debug-page-BoKbOX7x.js} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-page-2wAE2RCe.js → extension-page-BegL4FW8.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-settings-page-Y9ZiCJ21.js → extension-settings-page-CjPqq57s.js} +1 -1
  33. package/dist/gateway/static/root/assets/{gateway-config-api-DaYY1Gkn.js → gateway-config-api-DaG57o4X.js} +1 -1
  34. package/dist/gateway/static/root/assets/{gateway-config-swr-BC3pgb_P.js → gateway-config-swr-826dipyU.js} +1 -1
  35. package/dist/gateway/static/root/assets/{gateway-settings-eO3IzW_J.js → gateway-settings-DkJGpgm6.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-startup-retry-uMcSfLru.js → gateway-startup-retry-DyvcAIMm.js} +1 -1
  37. package/dist/gateway/static/root/assets/{heartbeat-settings-BAgrkyHc.js → heartbeat-settings-BLZ48kSU.js} +1 -1
  38. package/dist/gateway/static/root/assets/{home-page-GTjKH7LK.js → home-page-Dtw7Ipt1.js} +1 -1
  39. package/dist/gateway/static/root/assets/{image-generation-api-D1qlQA-A.js → image-generation-api-D7cyfks6.js} +1 -1
  40. package/dist/gateway/static/root/assets/{index-DUz0O54y.js → index-DG5CfYat.js} +10 -10
  41. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CWGqL6o5.js → keyboard-shortcuts-settings-D2Has7-N.js} +1 -1
  42. package/dist/gateway/static/root/assets/{local-app-workbench-page-DKJ-rks0.js → local-app-workbench-page-BWidWY93.js} +1 -1
  43. package/dist/gateway/static/root/assets/{local-apps-page-Bfidv29d.js → local-apps-page-Bkekjoxf.js} +1 -1
  44. package/dist/gateway/static/root/assets/{locale-store-CMZljTJx.js → locale-store-CBoCuIMx.js} +1 -1
  45. package/dist/gateway/static/root/assets/{logs-page-DwAHrPbF.js → logs-page-C5zSSgvA.js} +1 -1
  46. package/dist/gateway/static/root/assets/{management-settings-BG7j1I9f.js → management-settings-B8c62vRS.js} +1 -1
  47. package/dist/gateway/static/root/assets/{markdown-split-AnmmpLs6.js → markdown-split-3kxTTGO7.js} +1 -1
  48. package/dist/gateway/static/root/assets/{markdown-view-PPCLt7fu.js → markdown-view-BXsHghJd.js} +1 -1
  49. package/dist/gateway/static/root/assets/{media-plugins-CGS-05cE.js → media-plugins-BW8J1nCG.js} +1 -1
  50. package/dist/gateway/static/root/assets/messages-BbdwoxVo.js +3 -0
  51. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-DoKK5GfV.js → mobile-pairing-wizard-nwQ8iUcd.js} +1 -1
  52. package/dist/gateway/static/root/assets/models-hub-cache-88f4fzYS.js +1 -0
  53. package/dist/gateway/static/root/assets/{notes-page-Lr8rsFAR.js → notes-page-DdybD0QM.js} +1 -1
  54. package/dist/gateway/static/root/assets/{notes-workbench-ISWnKLxO.js → notes-workbench-IYfpy2Jx.js} +2 -2
  55. package/dist/gateway/static/root/assets/{oauth-api-4VeMbkTJ.js → oauth-api-BjSUDIgq.js} +1 -1
  56. package/dist/gateway/static/root/assets/{product-open-page-BU0HiZtv.js → product-open-page-CAJeUXeU.js} +1 -1
  57. package/dist/gateway/static/root/assets/{project-detail-page-BZqr4yam.js → project-detail-page-4wjw-b7h.js} +1 -1
  58. package/dist/gateway/static/root/assets/{projects-page-Dau8733A.js → projects-page-CCMj9PeL.js} +1 -1
  59. package/dist/gateway/static/root/assets/{registry-api-CWOtPFrE.js → registry-api-BhGKnvLP.js} +1 -1
  60. package/dist/gateway/static/root/assets/{remote-access-hub-DdChlvGP.js → remote-access-hub-DsBJqWIk.js} +1 -1
  61. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-CmZTNv1W.js → runtime-tools-settings-panel-B4IDcqx0.js} +1 -1
  62. package/dist/gateway/static/root/assets/{schema-form-XlVPyiVQ.js → schema-form-DiGUUjO6.js} +1 -1
  63. package/dist/gateway/static/root/assets/{sessions-page-C3kADsd4.js → sessions-page-BwGj0t-2.js} +1 -1
  64. package/dist/gateway/static/root/assets/settings-advanced-gate-BJCfUghk.js +1 -0
  65. package/dist/gateway/static/root/assets/{settings-page-DblUeM3V.js → settings-page-CVQUsAhd.js} +1 -1
  66. package/dist/gateway/static/root/assets/{setup-status-panel-bDfRfSnq.js → setup-status-panel-CQACRh1i.js} +1 -1
  67. package/dist/gateway/static/root/assets/{share-preview-page-DBMWFMN-.js → share-preview-page-DTP1dtuS.js} +1 -1
  68. package/dist/gateway/static/root/assets/{shares-settings-Bu6lIStj.js → shares-settings-D_YPh6Rw.js} +1 -1
  69. package/dist/gateway/static/root/assets/skill-reload-api-B43xlJlX.js +1 -0
  70. package/dist/gateway/static/root/assets/{skills-page-CSOseeQe.js → skills-page-Czpn7Y28.js} +1 -1
  71. package/dist/gateway/static/root/assets/{skills-page.utils-CniRGhkJ.js → skills-page.utils-d39rm3hb.js} +1 -1
  72. package/dist/gateway/static/root/assets/{system-settings-panel-D0GqNpKy.js → system-settings-panel-CXXySCSp.js} +1 -1
  73. package/dist/gateway/static/root/assets/{task-detail-page-BRCq-nR7.js → task-detail-page-DHiOqQMx.js} +1 -1
  74. package/dist/gateway/static/root/assets/{theme-store-uxUwr10D.js → theme-store-hybK3oC9.js} +1 -1
  75. package/dist/gateway/static/root/assets/{tunnel-api-BtjS2nrM.js → tunnel-api-BiBGK7O2.js} +1 -1
  76. package/dist/gateway/static/root/assets/{use-autosave-TwuAycG8.js → use-autosave-DjpzpeIm.js} +1 -1
  77. package/dist/gateway/static/root/assets/{user-context-page-CbqPu8xZ.js → user-context-page-1XBRV5gX.js} +1 -1
  78. package/dist/gateway/static/root/assets/{voice-api-key-field-CzwG5plu.js → voice-api-key-field-CUIPNmOc.js} +1 -1
  79. package/dist/gateway/static/root/assets/{voice-config-api-MqyI6cgq.js → voice-config-api-CBbiF1T3.js} +1 -1
  80. package/dist/gateway/static/root/assets/{work-discovery-overlay-DS15FzQA.js → work-discovery-overlay-DVNxhb1x.js} +1 -1
  81. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-C_boCemi.js → workflow-run-setup-panel-HxxFQFY7.js} +1 -1
  82. package/dist/gateway/static/root/assets/{workflows-page-CaI2ruyy.js → workflows-page-BCgL7PRm.js} +1 -1
  83. package/dist/gateway/static/root/index.html +11 -11
  84. package/dist/package.js +1 -1
  85. package/dist/packages/gateway-contract/src/turn-outcome.js +3 -1
  86. package/dist/src/agent/agent-instance-gateway.d.ts +3 -1
  87. package/dist/src/agent/agent-manager.d.ts +2 -4
  88. package/dist/src/agent/agent-manager.js +28 -32
  89. package/dist/src/agent/background-review/coordinator.js +1 -1
  90. package/dist/src/agent/background-review/run-background-review.js +2 -2
  91. package/dist/src/agent/child-agent-factory.d.ts +10 -7
  92. package/dist/src/agent/child-agent-factory.js +112 -158
  93. package/dist/src/agent/coding/index.d.ts +1 -1
  94. package/dist/src/agent/coding/index.js +2 -2
  95. package/dist/src/agent/coding/repository-instructions.d.ts +12 -0
  96. package/dist/src/agent/coding/repository-instructions.js +76 -0
  97. package/dist/src/agent/coding/run-verification.d.ts +34 -0
  98. package/dist/src/agent/coding/run-verification.js +134 -0
  99. package/dist/src/agent/coding/verification-command.d.ts +3 -0
  100. package/dist/src/agent/coding/verification-command.js +50 -0
  101. package/dist/src/agent/coding/workspace-revision.d.ts +2 -0
  102. package/dist/src/agent/coding/workspace-revision.js +77 -0
  103. package/dist/src/agent/commands/command-isolation.d.ts +21 -0
  104. package/dist/src/agent/commands/command-isolation.js +71 -0
  105. package/dist/src/agent/commands/command-registry.d.ts +56 -0
  106. package/dist/src/agent/commands/command-registry.js +259 -0
  107. package/dist/src/agent/embedded/index.js +1 -1
  108. package/dist/src/agent/embedded/model-runtime.js +1 -1
  109. package/dist/src/agent/embedded/run-for-session.js +3 -2
  110. package/dist/src/agent/embedded/run-turn.js +88 -25
  111. package/dist/src/agent/embedded/session-tool-result-guard.js +2 -2
  112. package/dist/src/agent/embedded/subscribe-session.d.ts +2 -1
  113. package/dist/src/agent/embedded/subscribe-session.js +2 -1
  114. package/dist/src/agent/embedded/types.d.ts +3 -1
  115. package/dist/src/agent/embedded/xopc-tools-bridge.js +4 -1
  116. package/dist/src/agent/image/index.js +1 -1
  117. package/dist/src/agent/image/tool-model-config.js +1 -1
  118. package/dist/src/agent/index.js +3 -3
  119. package/dist/src/agent/ipc/inbox.js +1 -1
  120. package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
  121. package/dist/src/agent/memory/user-context-coordinator.js +1 -1
  122. package/dist/src/agent/middleware/index.d.ts +0 -5
  123. package/dist/src/agent/middleware/index.js +1 -2
  124. package/dist/src/agent/orchestration/agent-event-handler.d.ts +0 -5
  125. package/dist/src/agent/orchestration/agent-event-handler.js +1 -96
  126. package/dist/src/agent/orchestration/agent-orchestrator.js +1 -1
  127. package/dist/src/agent/orchestration/agent-turn-policy.js +5 -5
  128. package/dist/src/agent/orchestration/index.d.ts +1 -1
  129. package/dist/src/agent/orchestration/index.js +2 -2
  130. package/dist/src/agent/orchestration/loop-guard.d.ts +4 -31
  131. package/dist/src/agent/orchestration/loop-guard.js +14 -99
  132. package/dist/src/agent/prompt/sections/tooling.js +2 -4
  133. package/dist/src/agent/sandbox/types.d.ts +2 -2
  134. package/dist/src/agent/sandbox/types.js +1 -1
  135. package/dist/src/agent/service/direct-turn-helpers.js +1 -1
  136. package/dist/src/agent/service/process-direct-streaming.js +1 -1
  137. package/dist/src/agent/service.d.ts +0 -2
  138. package/dist/src/agent/service.js +8 -25
  139. package/dist/src/agent/session/session-inspector.js +1 -1
  140. package/dist/src/agent/skills/hub-lock.js +1 -1
  141. package/dist/src/agent/tasks/task-judge-service.d.ts +7 -0
  142. package/dist/src/agent/tasks/task-judge-service.js +27 -5
  143. package/dist/src/agent/tools/delegate-tool.d.ts +2 -1
  144. package/dist/src/agent/tools/delegate-tool.js +102 -124
  145. package/dist/src/agent/tools/exec-command.d.ts +8 -1
  146. package/dist/src/agent/tools/exec-command.js +77 -169
  147. package/dist/src/agent/tools/executor.js +9 -2
  148. package/dist/src/agent/tools/factory.js +50 -5
  149. package/dist/src/agent/tools/find.d.ts +10 -13
  150. package/dist/src/agent/tools/find.js +33 -80
  151. package/dist/src/agent/tools/grep.d.ts +14 -18
  152. package/dist/src/agent/tools/grep.js +56 -144
  153. package/dist/src/agent/tools/index.d.ts +0 -1
  154. package/dist/src/agent/tools/index.js +2 -3
  155. package/dist/src/agent/tools/language-diagnostics.d.ts +11 -0
  156. package/dist/src/agent/tools/language-diagnostics.js +62 -0
  157. package/dist/src/agent/tools/managed-job-tool.d.ts +2 -1
  158. package/dist/src/agent/tools/managed-job-tool.js +58 -118
  159. package/dist/src/agent/tools/read.js +24 -7
  160. package/dist/src/agent/tools/repository-search.d.ts +5 -0
  161. package/dist/src/agent/tools/repository-search.js +56 -0
  162. package/dist/src/agent/tools/review-workspace.d.ts +2 -0
  163. package/dist/src/agent/tools/review-workspace.js +103 -0
  164. package/dist/src/agent/tools/write.js +4 -4
  165. package/dist/src/agent/transcript/index.js +2 -2
  166. package/dist/src/agent/transcript/transcript-hygiene.js +2 -2
  167. package/dist/src/agent/workflow/subagent-runner.d.ts +0 -2
  168. package/dist/src/agent/workflow/subagent-runner.js +12 -31
  169. package/dist/src/agent-config/schema.d.ts +42 -0
  170. package/dist/src/agent-config/schema.js +5 -0
  171. package/dist/src/ai-assist/text-assist.js +1 -1
  172. package/dist/src/auth/credentials.js +2 -2
  173. package/dist/src/auth/profiles/store.js +1 -1
  174. package/dist/src/auth/sync-provider-auth.js +2 -2
  175. package/dist/src/browser/providers/browser-ext-install.js +1 -1
  176. package/dist/src/cli/commands/agent.js +2 -2
  177. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  178. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  179. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  180. package/dist/src/cli/commands/models.js +2 -2
  181. package/dist/src/cli/commands/onboard.js +1 -1
  182. package/dist/src/cli/commands/profile.js +1 -1
  183. package/dist/src/cli/commands/tunnel.js +1 -1
  184. package/dist/src/cli/commands/update.js +1 -1
  185. package/dist/src/cli/extension-cli-register.js +1 -1
  186. package/dist/src/config/index.js +5 -5
  187. package/dist/src/config/loader.js +1 -1
  188. package/dist/src/config/models-json.js +1 -1
  189. package/dist/src/config/schema.d.ts +28 -0
  190. package/dist/src/execution-environments/local-worktree-manager.d.ts +3 -1
  191. package/dist/src/execution-environments/local-worktree-manager.js +8 -3
  192. package/dist/src/execution-environments/session-environment-service.js +5 -3
  193. package/dist/src/extensions/lockfile.js +1 -1
  194. package/dist/src/extensions/update.js +1 -1
  195. package/dist/src/gateway/agents-admin.js +1 -1
  196. package/dist/src/gateway/file-path-classifier.js +1 -1
  197. package/dist/src/gateway/heartbeat/service.js +1 -1
  198. package/dist/src/gateway/hono/lib/config-payload.d.ts +7 -0
  199. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  200. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  201. package/dist/src/gateway/hono/routes/models.js +1 -1
  202. package/dist/src/gateway/hono/routes/sessions.js +1 -1
  203. package/dist/src/gateway/media-access.js +1 -1
  204. package/dist/src/gateway/run-loop.js +1 -1
  205. package/dist/src/gateway/service/config-coordinator.js +2 -2
  206. package/dist/src/gateway/service/run-gateway-agent.js +4 -1
  207. package/dist/src/gateway/service.js +7 -7
  208. package/dist/src/gateway/session-reset-service.js +1 -1
  209. package/dist/src/gateway/workspace-ripgrep.d.ts +0 -6
  210. package/dist/src/gateway/workspace-ripgrep.js +2 -40
  211. package/dist/src/heartbeat/index.js +1 -1
  212. package/dist/src/infra/ripgrep.d.ts +13 -0
  213. package/dist/src/infra/ripgrep.js +46 -0
  214. package/dist/src/infra/update-runner.js +1 -1
  215. package/dist/src/proactive/execution/agent-executor.js +1 -1
  216. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
  217. package/dist/src/providers/index.js +2 -2
  218. package/dist/src/providers/model-registry.js +1 -1
  219. package/dist/src/providers/register-runtime-providers.js +1 -1
  220. package/dist/src/session/store.js +1 -1
  221. package/dist/src/session/turn-outcome-projector.js +26 -6
  222. package/dist/src/share/hosted-session-share.js +1 -1
  223. package/dist/src/tasks/task-run-coordinator.d.ts +2 -2
  224. package/dist/src/tasks/task-run-coordinator.js +14 -12
  225. package/dist/src/tui/backends/embedded-backend.js +1 -1
  226. package/dist/src/tui/tui-startup-resources.js +1 -1
  227. package/dist/src/tui/tui.js +1 -1
  228. package/dist/src/workflows/service/workflow-run-service.js +1 -1
  229. package/package.json +1 -1
  230. package/dist/gateway/static/root/assets/messages-CTSgFlE4.js +0 -3
  231. package/dist/gateway/static/root/assets/models-hub-cache-ZrbGRiGY.js +0 -1
  232. package/dist/gateway/static/root/assets/settings-advanced-gate-CSYy6SUa.js +0 -1
  233. package/dist/gateway/static/root/assets/skill-reload-api-BNMc4l04.js +0 -1
  234. package/dist/src/agent/coding/turn-diff-tracker.d.ts +0 -67
  235. package/dist/src/agent/coding/turn-diff-tracker.js +0 -231
  236. package/dist/src/agent/middleware/self-verify.d.ts +0 -136
  237. package/dist/src/agent/middleware/self-verify.js +0 -380
  238. package/dist/src/agent/tools/execute-code-tool.d.ts +0 -11
  239. package/dist/src/agent/tools/execute-code-tool.js +0 -208
@@ -1,9 +1,12 @@
1
+ import { readWorkspaceRevision } from "../coding/workspace-revision.js";
1
2
  import { EXTERNAL_TOOL_NAMES } from "../external-tools/gateway-tools.js";
2
3
  import "../external-tools/index.js";
3
4
  import { createDelegateChildHandle } from "../child-agent-factory.js";
5
+ import { runGit } from "../../execution-environments/git.js";
6
+ import { LocalWorktreeManager } from "../../execution-environments/local-worktree-manager.js";
7
+ import { SessionEnvironmentService } from "../../execution-environments/session-environment-service.js";
4
8
  import { Type } from "@sinclair/typebox";
5
9
  //#region src/agent/tools/delegate-tool.ts
6
- const DEFAULT_MAX_ITERATIONS = 30;
7
10
  const DEFAULT_DELEGATE_TOOLS = [
8
11
  "exec_command",
9
12
  "read_file",
@@ -36,160 +39,135 @@ const DELEGATE_BLOCKED_TOOLS = new Set([
36
39
  EXTERNAL_TOOL_NAMES.execute,
37
40
  "managed_job"
38
41
  ]);
42
+ const INSPECTION_TOOLS = new Set([
43
+ "read_file",
44
+ "grep",
45
+ "find",
46
+ "list_dir",
47
+ "review_workspace"
48
+ ]);
39
49
  const DelegateTaskSchema = Type.Object({
40
- goal: Type.String({ description: "Clear description of what the sub-agent should accomplish" }),
41
- context: Type.Optional(Type.String({ description: "Additional context the sub-agent needs (file paths, constraints, etc.)" })),
42
- toolset: Type.Optional(Type.Array(Type.String(), { description: "Tool names the sub-agent may use. Defaults to exec_command, read_file, write_file, apply_patch, grep, find, list_dir, web_search, web_fetch. Dangerous or interactive tools are always removed." })),
43
- maxIterations: Type.Optional(Type.Number({
44
- description: "Maximum tool executions in the sub-agent (default: 30)",
45
- default: DEFAULT_MAX_ITERATIONS
50
+ goal: Type.String({ minLength: 1 }),
51
+ context: Type.Optional(Type.String()),
52
+ mode: Type.Optional(Type.Union([
53
+ Type.Literal("inspect"),
54
+ Type.Literal("review"),
55
+ Type.Literal("implement")
56
+ ])),
57
+ toolset: Type.Optional(Type.Array(Type.String())),
58
+ maxIterations: Type.Optional(Type.Integer({
59
+ minimum: 1,
60
+ maximum: 60
46
61
  }))
47
62
  });
63
+ function delegateToolNames(mode, requested) {
64
+ const available = mode === "implement" ? new Set([
65
+ ...DEFAULT_DELEGATE_TOOLS,
66
+ "review_workspace",
67
+ "language_diagnostics"
68
+ ]) : INSPECTION_TOOLS;
69
+ return [...new Set(requested ?? [...available])].filter((name) => available.has(name) && !DELEGATE_BLOCKED_TOOLS.has(name));
70
+ }
48
71
  function createDelegateTool(deps) {
49
72
  return {
50
73
  name: "delegate_task",
51
- label: "🤖 Delegate",
52
- description: "Spawn a sub-agent for an isolated subtask with a fresh conversation (no parent transcript).\n\nThe sub-agent returns a text summary only — tool traces stay out of your context.\n\nWHEN TO USE:\n- Independent work (research, multi-file exploration) where you only need the task\n- Avoiding context bloat from long intermediate tool output\n\nWHEN NOT TO USE:\n- Tasks that need this chat history or user clarification\n- Single trivial steps\n\nSub-agents cannot use clarify, messaging, memory tools, todo, or nested delegate_task.",
74
+ label: "Delegate task",
53
75
  parameters: DelegateTaskSchema,
54
- async execute(_toolCallId, params, signal) {
55
- const p = params;
56
- const maxIterations = p.maxIterations ?? DEFAULT_MAX_ITERATIONS;
57
- if (!Number.isFinite(maxIterations) || maxIterations < 1 || maxIterations > 200) return {
58
- content: [{
59
- type: "text",
60
- text: "Invalid maxIterations (use 1–200)."
61
- }],
62
- details: {
63
- summary: "",
64
- iterations: 0
65
- }
66
- };
67
- const requested = p.toolset ?? [...DEFAULT_DELEGATE_TOOLS];
68
- const allowedNames = [...new Set(requested.map((t) => String(t).trim()).filter(Boolean).filter((t) => !DELEGATE_BLOCKED_TOOLS.has(t)))];
69
- if (allowedNames.length === 0) return {
70
- content: [{
71
- type: "text",
72
- text: "No allowed tools remain after applying the delegation blocklist. Expand `toolset` with safe tools."
73
- }],
74
- details: {
75
- summary: "",
76
- iterations: 0
77
- }
78
- };
79
- let model;
80
- try {
81
- model = deps.getSubagentModel();
82
- } catch (e) {
83
- return {
84
- content: [{
85
- type: "text",
86
- text: `delegate_task: ${e instanceof Error ? e.message : String(e)}`
87
- }],
88
- details: {
89
- summary: "",
90
- iterations: 0
91
- }
92
- };
76
+ description: "Run one bounded leaf worker with a fresh context. inspect/review receive only read tools; review reports findings against a workspace revision. implement requires an attached project and clean Git workspace, creates a separate managed worktree, and returns its patch for parent review. Child changes are never merged automatically. No nested delegation, external messages or background jobs. Up to 60 tool calls, 100k tokens and five minutes per child.",
77
+ supportsParallel: false,
78
+ idempotent: false,
79
+ async execute(_id, input, signal) {
80
+ signal?.throwIfAborted();
81
+ const mode = input.mode ?? "inspect";
82
+ const tools = delegateToolNames(mode, input.toolset);
83
+ if (!tools.length) throw new Error("No permitted tools in the requested toolset");
84
+ const parentSessionKey = deps.getCurrentContext?.()?.sessionKey;
85
+ const model = deps.getSubagentModel();
86
+ let workspace = deps.workspace, environmentId;
87
+ if (mode === "implement") {
88
+ if (!parentSessionKey) throw new Error("Implementation delegation requires a project session");
89
+ const parent = new SessionEnvironmentService().get(parentSessionKey);
90
+ if (!parent?.projectId) throw new Error("Attach this session to a project before implementation delegation");
91
+ const environment = await new LocalWorktreeManager().provisionManagedWorktree({
92
+ projectId: parent.projectId,
93
+ repositoryPath: workspace
94
+ });
95
+ workspace = environment.rootPath;
96
+ environmentId = environment.id;
93
97
  }
94
- const ctx = deps.getCurrentContext?.() ?? null;
95
- const parentSessionKey = ctx?.sessionKey;
96
- const childOptions = {
97
- workspace: deps.workspace,
98
- goal: p.goal,
99
- context: p.context,
98
+ const revision = await readWorkspaceRevision(workspace);
99
+ const child = createDelegateChildHandle({
100
+ workspace,
101
+ goal: mode === "review" ? `Independently review the actual changes. Inspect review_workspace and relevant source/tests. Report actionable defects with file and line evidence, severity and a concrete failure example. If there are no findings, state the checks and remaining uncertainty. Do not treat the parent's completion claim as evidence.\n\n${input.goal}` : input.goal,
102
+ context: input.context,
100
103
  requesterSessionKey: parentSessionKey,
101
- allowedToolNames: allowedNames,
102
- maxIterations,
104
+ allowedToolNames: tools,
105
+ maxIterations: input.maxIterations ?? 30,
103
106
  model,
104
107
  bus: deps.bus,
105
108
  getConfig: deps.getConfig,
106
109
  toolExecutorConfig: deps.toolExecutorConfig,
107
- buildChildTools: deps.buildChildTools
108
- };
109
- let childSessionKey;
110
- try {
111
- if (deps.hookRunner && parentSessionKey) {
112
- const { parseSessionKey, buildSessionKey } = await import("../../routing/session-key.js");
113
- const parsed = parseSessionKey(parentSessionKey);
114
- if (parsed) childSessionKey = buildSessionKey({
115
- agentId: "subagent",
116
- source: parsed.agentId,
117
- accountId: parsed.accountId,
118
- peerKind: parsed.peerKind,
119
- peerId: parsed.peerId,
120
- threadId: parsed.threadId,
121
- scopeId: parsed.scopeId
122
- });
123
- if (childSessionKey) {
124
- const r = await deps.hookRunner.runHooksWithResult("subagent_spawning", {
125
- childSessionKey,
126
- requester: {
127
- channel: ctx?.channel,
128
- accountId: ctx?.accountId,
129
- to: ctx?.to,
130
- threadId: ctx?.threadId
131
- },
132
- threadRequested: true,
133
- agentId: "subagent",
134
- label: "delegate_task"
135
- }, {
136
- sessionKey: parentSessionKey,
137
- agentId: ctx?.channel
138
- });
139
- if (r && r.status === "error") return {
140
- content: [{
141
- type: "text",
142
- text: `delegate_task: ${String(r.error || "subagent spawn blocked")}`
143
- }],
144
- details: {
145
- summary: "",
146
- iterations: 0
147
- }
148
- };
149
- }
150
- }
151
- } catch {}
152
- const child = createDelegateChildHandle(childOptions);
153
- if (signal) signal.addEventListener("abort", () => child.abort(), { once: true });
110
+ buildChildTools: deps.buildChildTools,
111
+ verifyChanges: mode === "implement"
112
+ });
113
+ const abort = () => child.abort();
114
+ signal?.addEventListener("abort", abort, { once: true });
115
+ if (signal?.aborted) abort();
154
116
  try {
155
- const { summary, toolIterations } = await child.run();
156
- try {
157
- if (deps.hookRunner && childSessionKey) await deps.hookRunner.runHooks("subagent_ended", {
158
- targetSessionKey: childSessionKey,
159
- accountId: ctx?.accountId
160
- }, { sessionKey: parentSessionKey });
161
- } catch {}
117
+ const result = await child.run();
118
+ const currentRevision = await readWorkspaceRevision(workspace);
119
+ const stale = mode !== "implement" && (!revision || revision !== currentRevision);
120
+ const patch = mode === "implement" ? await runGit(workspace, [
121
+ "diff",
122
+ "--no-ext-diff",
123
+ "--no-textconv",
124
+ "--binary",
125
+ "HEAD"
126
+ ]).catch(() => "") : void 0;
162
127
  return {
163
128
  content: [{
164
129
  type: "text",
165
- text: `Sub-agent completed:\n\n${summary}`
130
+ text: [
131
+ result.summary,
132
+ stale ? "Workspace changed or could not be fingerprinted; review findings require revalidation." : "",
133
+ environmentId ? `Changes retained in ${workspace} (environment ${environmentId}). Review and integrate from this workspace, then verify the parent workspace again.` : "",
134
+ patch ? `Patch preview:\n${patch.slice(0, 3e4)}` : ""
135
+ ].filter(Boolean).join("\n\n")
166
136
  }],
167
137
  details: {
168
- summary,
169
- iterations: toolIterations
138
+ status: stale && result.status === "success" ? "partial" : result.status,
139
+ mode,
140
+ summary: result.summary,
141
+ iterations: result.toolIterations,
142
+ revision: currentRevision,
143
+ reviewedRevision: revision,
144
+ ...result.verification ? { childVerification: result.verification } : {},
145
+ ...environmentId ? {
146
+ environmentId,
147
+ workspace,
148
+ patchTruncated: (patch?.length ?? 0) > 3e4
149
+ } : {}
170
150
  }
171
151
  };
172
152
  } catch (error) {
173
- child.abort();
174
- try {
175
- if (deps.hookRunner && childSessionKey) await deps.hookRunner.runHooks("subagent_ended", {
176
- targetSessionKey: childSessionKey,
177
- accountId: ctx?.accountId
178
- }, { sessionKey: parentSessionKey });
179
- } catch {}
180
153
  return {
181
154
  content: [{
182
155
  type: "text",
183
- text: `Sub-agent failed: ${error instanceof Error ? error.message : String(error)}`
156
+ text: `Delegation failed: ${String(error)}${environmentId ? `; work retained in ${workspace} (${environmentId})` : ""}`
184
157
  }],
185
158
  details: {
186
- summary: "",
187
- iterations: 0
159
+ status: signal?.aborted ? "cancelled" : "failed",
160
+ ...environmentId ? {
161
+ environmentId,
162
+ workspace
163
+ } : {}
188
164
  }
189
165
  };
166
+ } finally {
167
+ signal?.removeEventListener("abort", abort);
190
168
  }
191
169
  }
192
170
  };
193
171
  }
194
172
  //#endregion
195
- export { DEFAULT_DELEGATE_TOOLS, DELEGATE_BLOCKED_TOOLS, createDelegateTool };
173
+ export { DEFAULT_DELEGATE_TOOLS, DELEGATE_BLOCKED_TOOLS, INSPECTION_TOOLS, createDelegateTool, delegateToolNames };
@@ -1,9 +1,14 @@
1
1
  import type { AgentTool } from '@earendil-works/pi-agent-core';
2
2
  import type { TurnOutcomeDeliverable } from '@xopcai/gateway-contract';
3
+ import type { CommandIsolation } from '../commands/command-isolation.js';
4
+ import { type CommandStatus } from '../commands/command-registry.js';
3
5
  export interface ExecCommandDetails {
4
6
  command: string;
5
7
  cwd: string;
6
- status: 'success' | 'failed' | 'timed_out' | 'blocked';
8
+ status: CommandStatus | 'blocked';
9
+ id?: string;
10
+ logPath?: string;
11
+ logTruncated?: boolean;
7
12
  exitCode: number | null;
8
13
  durationMs: number;
9
14
  timedOut: boolean;
@@ -27,6 +32,8 @@ export interface ExecCommandUpdateDetails {
27
32
  }
28
33
  export interface CreateExecCommandToolOptions {
29
34
  /** Env var names allowed through prepareSafeToolEnv even if they match secret heuristics. */
35
+ getCommandIsolation?: () => CommandIsolation | undefined;
36
+ getSessionKey?: () => string | undefined;
30
37
  getSkillPassthroughEnvVarNames?: () => string[];
31
38
  prepareEnv?: (baseEnv: Record<string, string>, cwd: string) => Promise<Record<string, string>>;
32
39
  }
@@ -1,76 +1,32 @@
1
+ import { commandRegistry, commandTimeout } from "../commands/command-registry.js";
1
2
  import { formatSize, truncateTail } from "./truncate.js";
2
3
  import { evaluateExecPolicy } from "../sandbox/exec-policy.js";
3
4
  import { publishArtifactPaths } from "./publish-artifacts.js";
4
5
  import { resolve } from "node:path";
5
- import { spawn } from "node:child_process";
6
6
  import { Type } from "@sinclair/typebox";
7
7
  //#region src/agent/tools/exec-command.ts
8
- const MAX_COMMAND_TIMEOUT_MS = 14400 * 1e3;
9
- const DEFAULT_TIMEOUT_MS = 1800 * 1e3;
10
8
  const DEFAULT_MAX_OUTPUT_CHARS = 5e4;
11
- const STREAM_DELTA_MAX_CHARS = 16e3;
12
9
  const ExecCommandSchema = Type.Object({
13
10
  cmd: Type.String({ description: "Shell command to execute." }),
14
11
  cwd: Type.Optional(Type.String({ description: "Working directory. Relative paths are resolved under the agent workspace." })),
15
12
  timeoutMs: Type.Optional(Type.Number({ description: "Command timeout in milliseconds. Defaults to 1800000 (30m) and is capped at 14400000 (4h)." })),
16
13
  maxOutputChars: Type.Optional(Type.Number({ description: "Maximum characters returned to the model. UI streaming still receives output deltas." })),
14
+ yieldTimeMs: Type.Optional(Type.Number({
15
+ minimum: 0,
16
+ maximum: 6e4,
17
+ description: "Return a running job after this wait; manage it with managed_job. Omit to wait for completion. Cannot be combined with outputs."
18
+ })),
17
19
  outputs: Type.Optional(Type.Array(Type.String({ minLength: 1 }), {
18
20
  maxItems: 50,
19
21
  description: "Final user-facing files created by this command. Relative paths resolve under the effective cwd and are persisted as chat deliverables after a successful command."
20
22
  }))
21
23
  });
22
- function clampTimeoutMs(raw) {
23
- return Math.min(MAX_COMMAND_TIMEOUT_MS, Math.max(1e3, Math.floor(typeof raw === "number" && Number.isFinite(raw) ? raw : DEFAULT_TIMEOUT_MS)));
24
- }
25
24
  function clampMaxOutputChars(raw) {
26
25
  return Math.max(1e3, Math.min(5e5, Math.floor(typeof raw === "number" && Number.isFinite(raw) ? raw : DEFAULT_MAX_OUTPUT_CHARS)));
27
26
  }
28
- function commandStatus(exitCode, timedOut) {
29
- if (timedOut) return "timed_out";
30
- if (exitCode === 0) return "success";
31
- return "failed";
32
- }
33
- function appendBoundedTail(current, chunk, maxChars) {
34
- const combined = current + chunk;
35
- if (combined.length <= maxChars) return {
36
- value: combined,
37
- truncated: false
38
- };
39
- return {
40
- value: combined.slice(-maxChars),
41
- truncated: true
42
- };
43
- }
44
- function terminateProcessTree(proc) {
45
- if (!proc.pid) return;
46
- if (process.platform === "win32") {
47
- const killer = spawn("taskkill", [
48
- "/pid",
49
- String(proc.pid),
50
- "/t",
51
- "/f"
52
- ], {
53
- stdio: "ignore",
54
- windowsHide: true
55
- });
56
- killer.once("error", () => {
57
- try {
58
- proc.kill("SIGKILL");
59
- } catch {}
60
- });
61
- killer.unref();
62
- return;
63
- }
64
- try {
65
- process.kill(-proc.pid, "SIGKILL");
66
- return;
67
- } catch {}
68
- try {
69
- proc.kill("SIGKILL");
70
- } catch {}
71
- }
72
27
  function commandFailureHint(details) {
73
- if (details.status === "success") return void 0;
28
+ if (details.status === "success" || details.status === "running") return void 0;
29
+ if (details.status === "cancelled") return "The command was cancelled. Inspect its partial output before deciding whether to restart.";
74
30
  if (details.status === "timed_out") return "The command timed out. Re-run a narrower command, increase timeoutMs if the long run is expected, or inspect partial output before retrying.";
75
31
  if (details.exitCode !== 0 && details.stderr.trim()) return "The command failed. Inspect stderr first, fix the underlying issue, then re-run the narrowest relevant verification command.";
76
32
  if (details.exitCode !== 0 && details.stdout.trim()) return "The command failed. Inspect stdout for the failure location, then re-run the narrowest relevant verification command.";
@@ -80,7 +36,7 @@ function formatOutputForModel(details, maxOutputChars) {
80
36
  let prefix = "";
81
37
  if (details.timedOut) prefix += `Command timed out after ${Math.round(details.durationMs / 1e3)}s\n`;
82
38
  if (details.exitCode !== 0 && details.exitCode != null) prefix += `Command exited with code ${details.exitCode}\n`;
83
- if (details.captureTruncated) prefix += `Earlier command output was discarded after ${formatSize(details.totalOutputBytes)}; showing the latest captured output.\n`;
39
+ if (details.captureTruncated) prefix += `Earlier command output was discarded from model context after ${formatSize(details.totalOutputBytes)}; showing the latest captured output.\n`;
84
40
  const truncation = truncateTail(details.aggregatedOutput, { maxBytes: Math.min(maxOutputChars, DEFAULT_MAX_OUTPUT_CHARS) });
85
41
  let text = `${prefix}${truncation.content}`.trimEnd();
86
42
  if (!text) text = "(no output)";
@@ -109,7 +65,8 @@ function createExecCommandTool(workspaceCwd, options) {
109
65
  idempotent: false,
110
66
  finalGuardRelevant: true,
111
67
  async execute(toolCallId, params, signal, onUpdate) {
112
- const command = (params.cmd ?? params.command ?? "").trim();
68
+ const command = (params.cmd ?? "").trim();
69
+ if (params.yieldTimeMs !== void 0 && params.outputs?.length) throw new Error("yieldTimeMs cannot be combined with outputs; publish files after the job completes.");
113
70
  if (!command) return {
114
71
  content: [{
115
72
  type: "text",
@@ -163,127 +120,78 @@ function createExecCommandTool(workspaceCwd, options) {
163
120
  }
164
121
  };
165
122
  }
166
- const timeoutMs = Math.min(clampTimeoutMs(params.timeoutMs), policy.timeoutMs);
123
+ const timeoutMs = commandTimeout(params.timeoutMs, policy.timeoutMs);
167
124
  const maxOutputChars = clampMaxOutputChars(params.maxOutputChars);
168
- const startTime = Date.now();
169
125
  const runtimeEnv = options?.prepareEnv ? await options.prepareEnv(policy.sanitizedEnv, policy.effectiveCwd) : policy.sanitizedEnv;
170
- let stdout = "";
171
- let stderr = "";
172
- let aggregatedOutput = "";
173
- let totalOutputBytes = 0;
174
- let captureTruncated = false;
175
- let timedOut = false;
176
- let settled = false;
177
- return new Promise((resolveTool) => {
178
- const proc = spawn(command, [], {
179
- shell: true,
180
- detached: process.platform !== "win32",
181
- cwd: policy.effectiveCwd,
182
- env: {
183
- ...runtimeEnv,
184
- COLUMNS: "200"
185
- }
186
- });
187
- const publishDelta = (stream, raw) => {
188
- const text = raw.toString();
189
- if (!text) return;
190
- totalOutputBytes += Buffer.byteLength(text);
191
- if (stream === "stdout") {
192
- const next = appendBoundedTail(stdout, text, maxOutputChars);
193
- stdout = next.value;
194
- captureTruncated ||= next.truncated;
195
- } else {
196
- const next = appendBoundedTail(stderr, text, maxOutputChars);
197
- stderr = next.value;
198
- captureTruncated ||= next.truncated;
199
- }
200
- const nextAggregate = appendBoundedTail(aggregatedOutput, text, maxOutputChars);
201
- aggregatedOutput = nextAggregate.value;
202
- captureTruncated ||= nextAggregate.truncated;
203
- const delta = text.length > STREAM_DELTA_MAX_CHARS ? `${text.slice(0, STREAM_DELTA_MAX_CHARS)}\n[stream delta truncated]` : text;
204
- onUpdate?.({
205
- content: [],
206
- details: {
207
- kind: "command_output_delta",
208
- command,
209
- cwd: policy.effectiveCwd,
210
- stream,
211
- delta
212
- }
213
- });
214
- };
215
- const finish = async (exitCode, errorText) => {
216
- if (settled) return;
217
- settled = true;
218
- clearTimeout(timeout);
219
- signal?.removeEventListener("abort", abort);
220
- if (errorText) {
221
- totalOutputBytes += Buffer.byteLength(errorText);
222
- const nextStderr = appendBoundedTail(stderr, errorText, maxOutputChars);
223
- stderr = nextStderr.value;
224
- const nextAggregate = appendBoundedTail(aggregatedOutput, errorText, maxOutputChars);
225
- aggregatedOutput = nextAggregate.value;
226
- captureTruncated ||= nextStderr.truncated || nextAggregate.truncated;
227
- }
228
- const durationMs = Date.now() - startTime;
229
- const baseDetails = {
126
+ const owner = options?.getSessionKey?.() ?? workspaceCwd;
127
+ const registry = commandRegistry();
128
+ let commandResult = await registry.start({
129
+ workspace: workspaceCwd,
130
+ isolation: options?.getCommandIsolation?.(),
131
+ owner,
132
+ command,
133
+ cwd: policy.effectiveCwd,
134
+ env: {
135
+ ...runtimeEnv,
136
+ COLUMNS: "200"
137
+ },
138
+ timeoutMs,
139
+ maxOutputChars,
140
+ signal,
141
+ snapshot: true,
142
+ onOutput: (stream, delta) => onUpdate?.({
143
+ content: [],
144
+ details: {
145
+ kind: "command_output_delta",
230
146
  command,
231
147
  cwd: policy.effectiveCwd,
232
- status: commandStatus(exitCode, timedOut),
233
- exitCode,
234
- durationMs,
235
- timedOut,
236
- truncated: false,
237
- outputBytes: Buffer.byteLength(aggregatedOutput),
238
- totalOutputBytes,
239
- captureTruncated,
240
- stdout,
241
- stderr,
242
- aggregatedOutput
243
- };
244
- baseDetails.failureHint = commandFailureHint(baseDetails);
245
- const formatted = formatOutputForModel(baseDetails, maxOutputChars);
246
- const details = {
247
- ...baseDetails,
248
- truncated: formatted.truncated,
249
- truncatedBy: formatted.truncatedBy,
250
- outputBytes: formatted.outputBytes
251
- };
252
- let resultText = formatted.text;
253
- if (details.status === "success" && params.outputs?.length) {
254
- details.artifacts = await publishArtifactPaths({
255
- paths: params.outputs,
256
- baseDir: policy.effectiveCwd,
257
- workspaceRoot: workspaceCwd,
258
- toolCallId
259
- });
260
- const published = details.artifacts.filter((item) => item.availability === "available").length;
261
- const failed = details.artifacts.length - published;
262
- resultText += `\n\nArtifacts: ${published} published${failed > 0 ? `, ${failed} failed` : ""}.`;
148
+ stream,
149
+ delta
263
150
  }
264
- resolveTool({
265
- content: [{
266
- type: "text",
267
- text: resultText
268
- }],
269
- details
270
- });
271
- };
272
- const abort = () => {
273
- timedOut = true;
274
- terminateProcessTree(proc);
275
- };
276
- const timeout = setTimeout(() => {
277
- timedOut = true;
278
- terminateProcessTree(proc);
279
- }, timeoutMs);
280
- if (signal?.aborted) abort();
281
- else signal?.addEventListener("abort", abort, { once: true });
282
- proc.stdout?.on("data", (data) => publishDelta("stdout", data));
283
- proc.stderr?.on("data", (data) => publishDelta("stderr", data));
284
- proc.on("error", (err) => void finish(null, `Error: ${err.message}`));
285
- proc.on("close", (code) => void finish(code));
151
+ })
286
152
  });
153
+ try {
154
+ do
155
+ commandResult = await registry.wait(owner, commandResult.id, params.yieldTimeMs ?? 6e4, signal);
156
+ while (params.yieldTimeMs === void 0 && commandResult.status === "running");
157
+ } catch (error) {
158
+ if (!signal?.aborted) throw error;
159
+ commandResult = await registry.cancel(owner, commandResult.id);
160
+ }
161
+ const baseDetails = {
162
+ ...commandResult,
163
+ truncated: false,
164
+ outputBytes: Buffer.byteLength(commandResult.aggregatedOutput)
165
+ };
166
+ baseDetails.failureHint = commandFailureHint(baseDetails);
167
+ const formatted = formatOutputForModel(baseDetails, maxOutputChars);
168
+ const details = {
169
+ ...baseDetails,
170
+ truncated: formatted.truncated,
171
+ truncatedBy: formatted.truncatedBy,
172
+ outputBytes: formatted.outputBytes
173
+ };
174
+ let resultText = formatted.text;
175
+ if (details.status === "running") resultText += `\n\nCommand is running (jobId: ${details.id}). Use managed_job wait/status/stdin/cancel.`;
176
+ if (details.logPath) resultText += `\n\nLog: ${details.logPath}${details.logTruncated ? " (truncated)" : ""}`;
177
+ if (details.status === "success" && params.outputs?.length) {
178
+ details.artifacts = await publishArtifactPaths({
179
+ paths: params.outputs,
180
+ baseDir: policy.effectiveCwd,
181
+ workspaceRoot: workspaceCwd,
182
+ toolCallId
183
+ });
184
+ const published = details.artifacts.filter((item) => item.availability === "available").length;
185
+ const failed = details.artifacts.length - published;
186
+ resultText += `\n\nArtifacts: ${published} published${failed > 0 ? `, ${failed} failed` : ""}.`;
187
+ }
188
+ return {
189
+ content: [{
190
+ type: "text",
191
+ text: resultText
192
+ }],
193
+ details
194
+ };
287
195
  }
288
196
  };
289
197
  }
@@ -1,5 +1,6 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { commandTimeout } from "../commands/command-registry.js";
3
4
  import { DEFAULT_TOOL_EXECUTION_TIMEOUT_MS, TimeoutError, executeWithTimeout } from "../lifecycle/timeout-wrapper.js";
4
5
  import { withRetry } from "../../infra/retry.js";
5
6
  import { ToolConcurrencyController, resolveToolLockMode } from "./concurrency.js";
@@ -41,8 +42,14 @@ async function executeToolWithProtection(tool, toolCallId, params, signal, onUpd
41
42
  const onParentAbort = () => controller.abort(signal?.reason);
42
43
  if (signal?.aborted) onParentAbort();
43
44
  else signal?.addEventListener("abort", onParentAbort, { once: true });
44
- const execute = () => tool.execute(toolCallId, params, controller.signal, onUpdate);
45
- return (fullConfig.enableTimeout ? executeWithTimeout(execute, {
45
+ const policyDeadline = fullConfig.resolveTimeoutMs?.(toolName);
46
+ const commandDeadlineField = toolName === "exec_command" ? "timeoutMs" : toolName === "managed_job" && params.action === "start" ? "maxRuntimeMs" : void 0;
47
+ const executionParams = commandDeadlineField && policyDeadline ? {
48
+ ...params,
49
+ [commandDeadlineField]: Math.min(commandTimeout(params[commandDeadlineField]), policyDeadline)
50
+ } : params;
51
+ const execute = () => tool.execute(toolCallId, executionParams, controller.signal, onUpdate);
52
+ return (fullConfig.enableTimeout && toolName !== "exec_command" ? executeWithTimeout(execute, {
46
53
  toolName,
47
54
  timeoutMs: resolveTimeoutMs(tool, fullConfig),
48
55
  description: `Executing ${toolName}`,