apex-code 0.0.1-alpha.9 → 0.0.5

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 (513) hide show
  1. package/CHANGELOG.md +150 -2
  2. package/README.md +9 -8
  3. package/dist/cli/args.d.ts +25 -1
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +43 -1
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/mcp-command.d.ts +9 -0
  8. package/dist/cli/mcp-command.d.ts.map +1 -0
  9. package/dist/cli/mcp-command.js +53 -0
  10. package/dist/cli/mcp-command.js.map +1 -0
  11. package/dist/cli/project-trust.d.ts.map +1 -1
  12. package/dist/cli/project-trust.js +3 -1
  13. package/dist/cli/project-trust.js.map +1 -1
  14. package/dist/cli/startup-ui.d.ts.map +1 -1
  15. package/dist/cli/startup-ui.js +2 -1
  16. package/dist/cli/startup-ui.js.map +1 -1
  17. package/dist/cli.d.ts.map +1 -1
  18. package/dist/cli.js +94 -5
  19. package/dist/cli.js.map +1 -1
  20. package/dist/config.d.ts.map +1 -1
  21. package/dist/config.js +24 -5
  22. package/dist/config.js.map +1 -1
  23. package/dist/core/agent-session-services.d.ts +3 -0
  24. package/dist/core/agent-session-services.d.ts.map +1 -1
  25. package/dist/core/agent-session-services.js +1 -0
  26. package/dist/core/agent-session-services.js.map +1 -1
  27. package/dist/core/agent-session.d.ts +157 -8
  28. package/dist/core/agent-session.d.ts.map +1 -1
  29. package/dist/core/agent-session.js +565 -22
  30. package/dist/core/agent-session.js.map +1 -1
  31. package/dist/core/bash-executor.d.ts.map +1 -1
  32. package/dist/core/bash-executor.js +7 -0
  33. package/dist/core/bash-executor.js.map +1 -1
  34. package/dist/core/checkpoints/git-checkpoints.d.ts +39 -0
  35. package/dist/core/checkpoints/git-checkpoints.d.ts.map +1 -0
  36. package/dist/core/checkpoints/git-checkpoints.js +251 -0
  37. package/dist/core/checkpoints/git-checkpoints.js.map +1 -0
  38. package/dist/core/checkpoints/session-checkpoints.d.ts +23 -0
  39. package/dist/core/checkpoints/session-checkpoints.d.ts.map +1 -0
  40. package/dist/core/checkpoints/session-checkpoints.js +36 -0
  41. package/dist/core/checkpoints/session-checkpoints.js.map +1 -0
  42. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  43. package/dist/core/compaction/branch-summarization.js +4 -3
  44. package/dist/core/compaction/branch-summarization.js.map +1 -1
  45. package/dist/core/compaction/compaction.d.ts +5 -0
  46. package/dist/core/compaction/compaction.d.ts.map +1 -1
  47. package/dist/core/compaction/compaction.js +19 -5
  48. package/dist/core/compaction/compaction.js.map +1 -1
  49. package/dist/core/delegation/runtime.d.ts +6 -5
  50. package/dist/core/delegation/runtime.d.ts.map +1 -1
  51. package/dist/core/delegation/runtime.js +4 -3
  52. package/dist/core/delegation/runtime.js.map +1 -1
  53. package/dist/core/exec.d.ts.map +1 -1
  54. package/dist/core/exec.js +5 -2
  55. package/dist/core/exec.js.map +1 -1
  56. package/dist/core/extensions/index.d.ts +1 -1
  57. package/dist/core/extensions/index.d.ts.map +1 -1
  58. package/dist/core/extensions/index.js.map +1 -1
  59. package/dist/core/extensions/loader.d.ts.map +1 -1
  60. package/dist/core/extensions/loader.js +8 -2
  61. package/dist/core/extensions/loader.js.map +1 -1
  62. package/dist/core/extensions/runner.d.ts +5 -0
  63. package/dist/core/extensions/runner.d.ts.map +1 -1
  64. package/dist/core/extensions/runner.js +45 -1
  65. package/dist/core/extensions/runner.js.map +1 -1
  66. package/dist/core/extensions/source-runtime.d.ts +14 -0
  67. package/dist/core/extensions/source-runtime.d.ts.map +1 -0
  68. package/dist/core/extensions/source-runtime.js +56 -0
  69. package/dist/core/extensions/source-runtime.js.map +1 -0
  70. package/dist/core/extensions/types.d.ts +22 -2
  71. package/dist/core/extensions/types.d.ts.map +1 -1
  72. package/dist/core/extensions/types.js.map +1 -1
  73. package/dist/core/formatter-lifecycle.d.ts +69 -0
  74. package/dist/core/formatter-lifecycle.d.ts.map +1 -0
  75. package/dist/core/formatter-lifecycle.js +360 -0
  76. package/dist/core/formatter-lifecycle.js.map +1 -0
  77. package/dist/core/hooks/command-handler.d.ts +19 -0
  78. package/dist/core/hooks/command-handler.d.ts.map +1 -0
  79. package/dist/core/hooks/command-handler.js +112 -0
  80. package/dist/core/hooks/command-handler.js.map +1 -0
  81. package/dist/core/hooks/http-handler.d.ts +10 -0
  82. package/dist/core/hooks/http-handler.d.ts.map +1 -0
  83. package/dist/core/hooks/http-handler.js +36 -0
  84. package/dist/core/hooks/http-handler.js.map +1 -0
  85. package/dist/core/hooks/loader.d.ts +29 -0
  86. package/dist/core/hooks/loader.d.ts.map +1 -0
  87. package/dist/core/hooks/loader.js +139 -0
  88. package/dist/core/hooks/loader.js.map +1 -0
  89. package/dist/core/hooks/runtime.d.ts +13 -0
  90. package/dist/core/hooks/runtime.d.ts.map +1 -0
  91. package/dist/core/hooks/runtime.js +63 -0
  92. package/dist/core/hooks/runtime.js.map +1 -0
  93. package/dist/core/hooks/types.d.ts +83 -0
  94. package/dist/core/hooks/types.d.ts.map +1 -0
  95. package/dist/core/hooks/types.js +24 -0
  96. package/dist/core/hooks/types.js.map +1 -0
  97. package/dist/core/mcp/config.d.ts +16 -0
  98. package/dist/core/mcp/config.d.ts.map +1 -0
  99. package/dist/core/mcp/config.js +166 -0
  100. package/dist/core/mcp/config.js.map +1 -0
  101. package/dist/core/mcp/connector.d.ts +35 -0
  102. package/dist/core/mcp/connector.d.ts.map +1 -0
  103. package/dist/core/mcp/connector.js +105 -0
  104. package/dist/core/mcp/connector.js.map +1 -0
  105. package/dist/core/mcp/contract.d.ts +19 -0
  106. package/dist/core/mcp/contract.d.ts.map +1 -0
  107. package/dist/core/mcp/contract.js +89 -0
  108. package/dist/core/mcp/contract.js.map +1 -0
  109. package/dist/core/mcp/mcp-tool.d.ts +32 -0
  110. package/dist/core/mcp/mcp-tool.d.ts.map +1 -0
  111. package/dist/core/mcp/mcp-tool.js +171 -0
  112. package/dist/core/mcp/mcp-tool.js.map +1 -0
  113. package/dist/core/mcp/metadata-cache.d.ts +29 -0
  114. package/dist/core/mcp/metadata-cache.d.ts.map +1 -0
  115. package/dist/core/mcp/metadata-cache.js +99 -0
  116. package/dist/core/mcp/metadata-cache.js.map +1 -0
  117. package/dist/core/mcp/oauth/authorize.d.ts +21 -0
  118. package/dist/core/mcp/oauth/authorize.d.ts.map +1 -0
  119. package/dist/core/mcp/oauth/authorize.js +32 -0
  120. package/dist/core/mcp/oauth/authorize.js.map +1 -0
  121. package/dist/core/mcp/oauth/discover.d.ts +27 -0
  122. package/dist/core/mcp/oauth/discover.d.ts.map +1 -0
  123. package/dist/core/mcp/oauth/discover.js +116 -0
  124. package/dist/core/mcp/oauth/discover.js.map +1 -0
  125. package/dist/core/mcp/oauth/flow.d.ts +31 -0
  126. package/dist/core/mcp/oauth/flow.d.ts.map +1 -0
  127. package/dist/core/mcp/oauth/flow.js +175 -0
  128. package/dist/core/mcp/oauth/flow.js.map +1 -0
  129. package/dist/core/mcp/oauth/mcp-token.d.ts +51 -0
  130. package/dist/core/mcp/oauth/mcp-token.d.ts.map +1 -0
  131. package/dist/core/mcp/oauth/mcp-token.js +129 -0
  132. package/dist/core/mcp/oauth/mcp-token.js.map +1 -0
  133. package/dist/core/mcp/oauth/pkce.d.ts +12 -0
  134. package/dist/core/mcp/oauth/pkce.d.ts.map +1 -0
  135. package/dist/core/mcp/oauth/pkce.js +11 -0
  136. package/dist/core/mcp/oauth/pkce.js.map +1 -0
  137. package/dist/core/mcp/oauth/register.d.ts +16 -0
  138. package/dist/core/mcp/oauth/register.d.ts.map +1 -0
  139. package/dist/core/mcp/oauth/register.js +42 -0
  140. package/dist/core/mcp/oauth/register.js.map +1 -0
  141. package/dist/core/mcp/oauth/token-client.d.ts +33 -0
  142. package/dist/core/mcp/oauth/token-client.d.ts.map +1 -0
  143. package/dist/core/mcp/oauth/token-client.js +65 -0
  144. package/dist/core/mcp/oauth/token-client.js.map +1 -0
  145. package/dist/core/mcp/runtime.d.ts +20 -0
  146. package/dist/core/mcp/runtime.d.ts.map +1 -0
  147. package/dist/core/mcp/runtime.js +37 -0
  148. package/dist/core/mcp/runtime.js.map +1 -0
  149. package/dist/core/mcp/schema.d.ts +22 -0
  150. package/dist/core/mcp/schema.d.ts.map +1 -0
  151. package/dist/core/mcp/schema.js +20 -0
  152. package/dist/core/mcp/schema.js.map +1 -0
  153. package/dist/core/mcp/server-manager.d.ts +43 -0
  154. package/dist/core/mcp/server-manager.d.ts.map +1 -0
  155. package/dist/core/mcp/server-manager.js +142 -0
  156. package/dist/core/mcp/server-manager.js.map +1 -0
  157. package/dist/core/mcp/types.d.ts +100 -0
  158. package/dist/core/mcp/types.d.ts.map +1 -0
  159. package/dist/core/mcp/types.js +8 -0
  160. package/dist/core/mcp/types.js.map +1 -0
  161. package/dist/core/permissions/gate.d.ts.map +1 -1
  162. package/dist/core/permissions/gate.js +45 -4
  163. package/dist/core/permissions/gate.js.map +1 -1
  164. package/dist/core/permissions/operations.d.ts +20 -0
  165. package/dist/core/permissions/operations.d.ts.map +1 -0
  166. package/dist/core/permissions/operations.js +9 -0
  167. package/dist/core/permissions/operations.js.map +1 -0
  168. package/dist/core/permissions/policy-command.d.ts +42 -0
  169. package/dist/core/permissions/policy-command.d.ts.map +1 -0
  170. package/dist/core/permissions/policy-command.js +44 -0
  171. package/dist/core/permissions/policy-command.js.map +1 -0
  172. package/dist/core/permissions/responder.d.ts +49 -2
  173. package/dist/core/permissions/responder.d.ts.map +1 -1
  174. package/dist/core/permissions/responder.js +20 -8
  175. package/dist/core/permissions/responder.js.map +1 -1
  176. package/dist/core/permissions/rules.d.ts.map +1 -1
  177. package/dist/core/permissions/rules.js +11 -1
  178. package/dist/core/permissions/rules.js.map +1 -1
  179. package/dist/core/permissions/store.d.ts +18 -0
  180. package/dist/core/permissions/store.d.ts.map +1 -1
  181. package/dist/core/permissions/store.js +89 -8
  182. package/dist/core/permissions/store.js.map +1 -1
  183. package/dist/core/policy-executor.d.ts +47 -0
  184. package/dist/core/policy-executor.d.ts.map +1 -0
  185. package/dist/core/policy-executor.js +228 -0
  186. package/dist/core/policy-executor.js.map +1 -0
  187. package/dist/core/policy-loader.d.ts +72 -0
  188. package/dist/core/policy-loader.d.ts.map +1 -0
  189. package/dist/core/policy-loader.js +195 -0
  190. package/dist/core/policy-loader.js.map +1 -0
  191. package/dist/core/project-trust.d.ts +1 -1
  192. package/dist/core/project-trust.d.ts.map +1 -1
  193. package/dist/core/project-trust.js.map +1 -1
  194. package/dist/core/sandbox/bwrap-arguments.d.ts +41 -0
  195. package/dist/core/sandbox/bwrap-arguments.d.ts.map +1 -0
  196. package/dist/core/sandbox/bwrap-arguments.js +136 -0
  197. package/dist/core/sandbox/bwrap-arguments.js.map +1 -0
  198. package/dist/core/sandbox/child-entry.d.ts.map +1 -1
  199. package/dist/core/sandbox/child-entry.js +3 -1
  200. package/dist/core/sandbox/child-entry.js.map +1 -1
  201. package/dist/core/sandbox/cli-launch.d.ts +84 -4
  202. package/dist/core/sandbox/cli-launch.d.ts.map +1 -1
  203. package/dist/core/sandbox/cli-launch.js +115 -16
  204. package/dist/core/sandbox/cli-launch.js.map +1 -1
  205. package/dist/core/sandbox/cli-supervisor.d.ts +2 -0
  206. package/dist/core/sandbox/cli-supervisor.d.ts.map +1 -1
  207. package/dist/core/sandbox/cli-supervisor.js +50 -2
  208. package/dist/core/sandbox/cli-supervisor.js.map +1 -1
  209. package/dist/core/sandbox/full-access.d.ts +28 -0
  210. package/dist/core/sandbox/full-access.d.ts.map +1 -0
  211. package/dist/core/sandbox/full-access.js +63 -0
  212. package/dist/core/sandbox/full-access.js.map +1 -0
  213. package/dist/core/sandbox/git-identity.d.ts +57 -0
  214. package/dist/core/sandbox/git-identity.d.ts.map +1 -0
  215. package/dist/core/sandbox/git-identity.js +78 -0
  216. package/dist/core/sandbox/git-identity.js.map +1 -0
  217. package/dist/core/sandbox/host-approval.d.ts +42 -0
  218. package/dist/core/sandbox/host-approval.d.ts.map +1 -0
  219. package/dist/core/sandbox/host-approval.js +99 -0
  220. package/dist/core/sandbox/host-approval.js.map +1 -0
  221. package/dist/core/sandbox/linux-backend.d.ts +14 -0
  222. package/dist/core/sandbox/linux-backend.d.ts.map +1 -1
  223. package/dist/core/sandbox/linux-backend.js +158 -80
  224. package/dist/core/sandbox/linux-backend.js.map +1 -1
  225. package/dist/core/sandbox/macos-backend.d.ts +5 -0
  226. package/dist/core/sandbox/macos-backend.d.ts.map +1 -1
  227. package/dist/core/sandbox/macos-backend.js +164 -5
  228. package/dist/core/sandbox/macos-backend.js.map +1 -1
  229. package/dist/core/sandbox/network-proxy.d.ts +19 -0
  230. package/dist/core/sandbox/network-proxy.d.ts.map +1 -1
  231. package/dist/core/sandbox/network-proxy.js +93 -19
  232. package/dist/core/sandbox/network-proxy.js.map +1 -1
  233. package/dist/core/sandbox/policy.d.ts +8 -0
  234. package/dist/core/sandbox/policy.d.ts.map +1 -1
  235. package/dist/core/sandbox/policy.js +29 -12
  236. package/dist/core/sandbox/policy.js.map +1 -1
  237. package/dist/core/sandbox/profiles.d.ts +25 -0
  238. package/dist/core/sandbox/profiles.d.ts.map +1 -0
  239. package/dist/core/sandbox/profiles.js +23 -0
  240. package/dist/core/sandbox/profiles.js.map +1 -0
  241. package/dist/core/sandbox/rpc/command-client.d.ts +28 -0
  242. package/dist/core/sandbox/rpc/command-client.d.ts.map +1 -0
  243. package/dist/core/sandbox/rpc/command-client.js +86 -0
  244. package/dist/core/sandbox/rpc/command-client.js.map +1 -0
  245. package/dist/core/sandbox/rpc/command-proxy.d.ts +48 -0
  246. package/dist/core/sandbox/rpc/command-proxy.d.ts.map +1 -0
  247. package/dist/core/sandbox/rpc/command-proxy.js +120 -0
  248. package/dist/core/sandbox/rpc/command-proxy.js.map +1 -0
  249. package/dist/core/sandbox/rpc/credential-proxy.d.ts.map +1 -1
  250. package/dist/core/sandbox/rpc/credential-proxy.js +2 -96
  251. package/dist/core/sandbox/rpc/credential-proxy.js.map +1 -1
  252. package/dist/core/sandbox/rpc/framing.d.ts +35 -0
  253. package/dist/core/sandbox/rpc/framing.d.ts.map +1 -0
  254. package/dist/core/sandbox/rpc/framing.js +114 -0
  255. package/dist/core/sandbox/rpc/framing.js.map +1 -0
  256. package/dist/core/sandbox/rpc/git-credential-helper.d.ts +47 -0
  257. package/dist/core/sandbox/rpc/git-credential-helper.d.ts.map +1 -0
  258. package/dist/core/sandbox/rpc/git-credential-helper.js +222 -0
  259. package/dist/core/sandbox/rpc/git-credential-helper.js.map +1 -0
  260. package/dist/core/sandbox/rpc/git-credential-proxy.d.ts +66 -0
  261. package/dist/core/sandbox/rpc/git-credential-proxy.d.ts.map +1 -0
  262. package/dist/core/sandbox/rpc/git-credential-proxy.js +209 -0
  263. package/dist/core/sandbox/rpc/git-credential-proxy.js.map +1 -0
  264. package/dist/core/sandbox/supervisor-temp.d.ts +18 -0
  265. package/dist/core/sandbox/supervisor-temp.d.ts.map +1 -0
  266. package/dist/core/sandbox/supervisor-temp.js +21 -0
  267. package/dist/core/sandbox/supervisor-temp.js.map +1 -0
  268. package/dist/core/sandbox/supervisor.d.ts +12 -1
  269. package/dist/core/sandbox/supervisor.d.ts.map +1 -1
  270. package/dist/core/sandbox/supervisor.js +15 -1
  271. package/dist/core/sandbox/supervisor.js.map +1 -1
  272. package/dist/core/sandbox/terminal-handoff.d.ts +68 -0
  273. package/dist/core/sandbox/terminal-handoff.d.ts.map +1 -0
  274. package/dist/core/sandbox/terminal-handoff.js +221 -0
  275. package/dist/core/sandbox/terminal-handoff.js.map +1 -0
  276. package/dist/core/sandbox/terminal-size.d.ts +13 -0
  277. package/dist/core/sandbox/terminal-size.d.ts.map +1 -1
  278. package/dist/core/sandbox/terminal-size.js +23 -2
  279. package/dist/core/sandbox/terminal-size.js.map +1 -1
  280. package/dist/core/sdk.d.ts +22 -0
  281. package/dist/core/sdk.d.ts.map +1 -1
  282. package/dist/core/sdk.js +53 -1
  283. package/dist/core/sdk.js.map +1 -1
  284. package/dist/core/session-manager.d.ts +13 -1
  285. package/dist/core/session-manager.d.ts.map +1 -1
  286. package/dist/core/session-manager.js +32 -5
  287. package/dist/core/session-manager.js.map +1 -1
  288. package/dist/core/settings-manager.d.ts +163 -1
  289. package/dist/core/settings-manager.d.ts.map +1 -1
  290. package/dist/core/settings-manager.js +107 -0
  291. package/dist/core/settings-manager.js.map +1 -1
  292. package/dist/core/slash-commands.d.ts.map +1 -1
  293. package/dist/core/slash-commands.js +2 -0
  294. package/dist/core/slash-commands.js.map +1 -1
  295. package/dist/core/tools/background-shell.d.ts +39 -0
  296. package/dist/core/tools/background-shell.d.ts.map +1 -0
  297. package/dist/core/tools/background-shell.js +81 -0
  298. package/dist/core/tools/background-shell.js.map +1 -0
  299. package/dist/core/tools/bash-command-segments.d.ts.map +1 -1
  300. package/dist/core/tools/bash-command-segments.js +2 -0
  301. package/dist/core/tools/bash-command-segments.js.map +1 -1
  302. package/dist/core/tools/bash.d.ts +30 -15
  303. package/dist/core/tools/bash.d.ts.map +1 -1
  304. package/dist/core/tools/bash.js +228 -12
  305. package/dist/core/tools/bash.js.map +1 -1
  306. package/dist/core/tools/contract-snapshot.d.ts +58 -0
  307. package/dist/core/tools/contract-snapshot.d.ts.map +1 -0
  308. package/dist/core/tools/contract-snapshot.js +51 -0
  309. package/dist/core/tools/contract-snapshot.js.map +1 -0
  310. package/dist/core/tools/contract.d.ts +53 -5
  311. package/dist/core/tools/contract.d.ts.map +1 -1
  312. package/dist/core/tools/contract.js +22 -2
  313. package/dist/core/tools/contract.js.map +1 -1
  314. package/dist/core/tools/delegate.d.ts +6 -4
  315. package/dist/core/tools/delegate.d.ts.map +1 -1
  316. package/dist/core/tools/delegate.js +21 -11
  317. package/dist/core/tools/delegate.js.map +1 -1
  318. package/dist/core/tools/edit-diff.d.ts +48 -0
  319. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  320. package/dist/core/tools/edit-diff.js +215 -3
  321. package/dist/core/tools/edit-diff.js.map +1 -1
  322. package/dist/core/tools/edit.d.ts +8 -0
  323. package/dist/core/tools/edit.d.ts.map +1 -1
  324. package/dist/core/tools/edit.js +53 -7
  325. package/dist/core/tools/edit.js.map +1 -1
  326. package/dist/core/tools/find.d.ts.map +1 -1
  327. package/dist/core/tools/find.js +5 -2
  328. package/dist/core/tools/find.js.map +1 -1
  329. package/dist/core/tools/grep.d.ts.map +1 -1
  330. package/dist/core/tools/grep.js +5 -2
  331. package/dist/core/tools/grep.js.map +1 -1
  332. package/dist/core/tools/index.d.ts +10 -1
  333. package/dist/core/tools/index.d.ts.map +1 -1
  334. package/dist/core/tools/index.js +3 -0
  335. package/dist/core/tools/index.js.map +1 -1
  336. package/dist/core/tools/ls.d.ts.map +1 -1
  337. package/dist/core/tools/ls.js +5 -2
  338. package/dist/core/tools/ls.js.map +1 -1
  339. package/dist/core/tools/lsp.d.ts +19 -1
  340. package/dist/core/tools/lsp.d.ts.map +1 -1
  341. package/dist/core/tools/lsp.js +163 -10
  342. package/dist/core/tools/lsp.js.map +1 -1
  343. package/dist/core/tools/path-permission.d.ts +3 -0
  344. package/dist/core/tools/path-permission.d.ts.map +1 -1
  345. package/dist/core/tools/path-permission.js +16 -4
  346. package/dist/core/tools/path-permission.js.map +1 -1
  347. package/dist/core/tools/path-utils.d.ts +27 -2
  348. package/dist/core/tools/path-utils.d.ts.map +1 -1
  349. package/dist/core/tools/path-utils.js +221 -4
  350. package/dist/core/tools/path-utils.js.map +1 -1
  351. package/dist/core/tools/read.d.ts.map +1 -1
  352. package/dist/core/tools/read.js +20 -11
  353. package/dist/core/tools/read.js.map +1 -1
  354. package/dist/core/tools/test.d.ts +54 -9
  355. package/dist/core/tools/test.d.ts.map +1 -1
  356. package/dist/core/tools/test.js +239 -19
  357. package/dist/core/tools/test.js.map +1 -1
  358. package/dist/core/tools/write.d.ts +7 -0
  359. package/dist/core/tools/write.d.ts.map +1 -1
  360. package/dist/core/tools/write.js +64 -9
  361. package/dist/core/tools/write.js.map +1 -1
  362. package/dist/core/verification-lifecycle.d.ts +77 -0
  363. package/dist/core/verification-lifecycle.d.ts.map +1 -0
  364. package/dist/core/verification-lifecycle.js +146 -0
  365. package/dist/core/verification-lifecycle.js.map +1 -0
  366. package/dist/core/workspace/artifacts.d.ts +45 -0
  367. package/dist/core/workspace/artifacts.d.ts.map +1 -0
  368. package/dist/core/workspace/artifacts.js +165 -0
  369. package/dist/core/workspace/artifacts.js.map +1 -0
  370. package/dist/core/workspace/comparison.d.ts +27 -0
  371. package/dist/core/workspace/comparison.d.ts.map +1 -0
  372. package/dist/core/workspace/comparison.js +94 -0
  373. package/dist/core/workspace/comparison.js.map +1 -0
  374. package/dist/core/workspace/git-observer.d.ts +48 -0
  375. package/dist/core/workspace/git-observer.d.ts.map +1 -0
  376. package/dist/core/workspace/git-observer.js +346 -0
  377. package/dist/core/workspace/git-observer.js.map +1 -0
  378. package/dist/core/workspace/projection.d.ts +3 -0
  379. package/dist/core/workspace/projection.d.ts.map +1 -0
  380. package/dist/core/workspace/projection.js +56 -0
  381. package/dist/core/workspace/projection.js.map +1 -0
  382. package/dist/core/workspace/state.d.ts +133 -0
  383. package/dist/core/workspace/state.d.ts.map +1 -0
  384. package/dist/core/workspace/state.js +96 -0
  385. package/dist/core/workspace/state.js.map +1 -0
  386. package/dist/extensions/llama/client.d.ts +6 -0
  387. package/dist/extensions/llama/client.d.ts.map +1 -1
  388. package/dist/extensions/llama/client.js +7 -0
  389. package/dist/extensions/llama/client.js.map +1 -1
  390. package/dist/extensions/llama/provider.d.ts +3 -1
  391. package/dist/extensions/llama/provider.d.ts.map +1 -1
  392. package/dist/extensions/llama/provider.js +27 -6
  393. package/dist/extensions/llama/provider.js.map +1 -1
  394. package/dist/index.d.ts +4 -1
  395. package/dist/index.d.ts.map +1 -1
  396. package/dist/index.js +3 -0
  397. package/dist/index.js.map +1 -1
  398. package/dist/main.d.ts +3 -1
  399. package/dist/main.d.ts.map +1 -1
  400. package/dist/main.js +41 -9
  401. package/dist/main.js.map +1 -1
  402. package/dist/modes/acp/server.d.ts +55 -0
  403. package/dist/modes/acp/server.d.ts.map +1 -0
  404. package/dist/modes/acp/server.js +244 -0
  405. package/dist/modes/acp/server.js.map +1 -0
  406. package/dist/modes/acp/translate.d.ts +37 -0
  407. package/dist/modes/acp/translate.d.ts.map +1 -0
  408. package/dist/modes/acp/translate.js +50 -0
  409. package/dist/modes/acp/translate.js.map +1 -0
  410. package/dist/modes/index.d.ts +1 -0
  411. package/dist/modes/index.d.ts.map +1 -1
  412. package/dist/modes/index.js +1 -0
  413. package/dist/modes/index.js.map +1 -1
  414. package/dist/modes/interactive/components/assistant-message.d.ts +29 -0
  415. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  416. package/dist/modes/interactive/components/assistant-message.js +182 -23
  417. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  418. package/dist/modes/interactive/components/bash-execution.d.ts +7 -0
  419. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  420. package/dist/modes/interactive/components/bash-execution.js +20 -0
  421. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  422. package/dist/modes/interactive/components/custom-editor.d.ts +9 -4
  423. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  424. package/dist/modes/interactive/components/custom-editor.js +20 -9
  425. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  426. package/dist/modes/interactive/components/extension-selector.d.ts +7 -1
  427. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  428. package/dist/modes/interactive/components/extension-selector.js +7 -3
  429. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  430. package/dist/modes/interactive/components/footer.d.ts +19 -0
  431. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  432. package/dist/modes/interactive/components/footer.js +70 -10
  433. package/dist/modes/interactive/components/footer.js.map +1 -1
  434. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  435. package/dist/modes/interactive/components/model-selector.js +6 -6
  436. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  437. package/dist/modes/interactive/components/permission-preview.d.ts +15 -0
  438. package/dist/modes/interactive/components/permission-preview.d.ts.map +1 -0
  439. package/dist/modes/interactive/components/permission-preview.js +33 -0
  440. package/dist/modes/interactive/components/permission-preview.js.map +1 -0
  441. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  442. package/dist/modes/interactive/components/session-selector.js +2 -2
  443. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  444. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  445. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  446. package/dist/modes/interactive/components/settings-selector.js +10 -0
  447. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  448. package/dist/modes/interactive/components/tool-execution.d.ts +23 -1
  449. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  450. package/dist/modes/interactive/components/tool-execution.js +64 -10
  451. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  452. package/dist/modes/interactive/interactive-mode.d.ts +34 -0
  453. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  454. package/dist/modes/interactive/interactive-mode.js +231 -26
  455. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  456. package/dist/modes/interactive/theme/theme.d.ts +12 -0
  457. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  458. package/dist/modes/interactive/theme/theme.js +15 -5
  459. package/dist/modes/interactive/theme/theme.js.map +1 -1
  460. package/dist/modes/print-mode.d.ts.map +1 -1
  461. package/dist/modes/print-mode.js +27 -12
  462. package/dist/modes/print-mode.js.map +1 -1
  463. package/dist/modes/rpc/rpc-client.d.ts +7 -0
  464. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  465. package/dist/modes/rpc/rpc-client.js +7 -0
  466. package/dist/modes/rpc/rpc-client.js.map +1 -1
  467. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  468. package/dist/modes/rpc/rpc-mode.js +3 -0
  469. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  470. package/dist/modes/rpc/rpc-types.d.ts +12 -0
  471. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  472. package/dist/modes/rpc/rpc-types.js.map +1 -1
  473. package/dist/package-manager-cli.d.ts.map +1 -1
  474. package/dist/package-manager-cli.js +0 -6
  475. package/dist/package-manager-cli.js.map +1 -1
  476. package/dist/utils/shell.d.ts.map +1 -1
  477. package/dist/utils/shell.js +6 -4
  478. package/dist/utils/shell.js.map +1 -1
  479. package/dist/utils/version-check.d.ts.map +1 -1
  480. package/dist/utils/version-check.js +6 -4
  481. package/dist/utils/version-check.js.map +1 -1
  482. package/docs/compaction.md +4 -0
  483. package/docs/custom-provider.md +7 -7
  484. package/docs/environment-variables.md +1 -1
  485. package/docs/extensions.md +18 -0
  486. package/docs/keybindings.md +1 -1
  487. package/docs/quickstart.md +1 -1
  488. package/docs/rpc.md +23 -0
  489. package/docs/sdk.md +25 -0
  490. package/docs/settings.md +12 -4
  491. package/docs/terminal-setup.md +12 -0
  492. package/docs/usage.md +4 -3
  493. package/examples/extensions/built-in-tool-renderer.ts +8 -4
  494. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  495. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  496. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  497. package/examples/extensions/git-checkpoint.ts +24 -36
  498. package/examples/extensions/gondolin/package-lock.json +2 -2
  499. package/examples/extensions/gondolin/package.json +1 -1
  500. package/examples/extensions/minimal-mode.ts +2 -2
  501. package/examples/extensions/permission-gate.ts +1 -1
  502. package/examples/extensions/plan-mode/index.ts +1 -1
  503. package/examples/extensions/rpc-demo.ts +1 -1
  504. package/examples/extensions/sandbox/package-lock.json +2 -2
  505. package/examples/extensions/sandbox/package.json +1 -1
  506. package/examples/extensions/with-deps/package-lock.json +2 -2
  507. package/examples/extensions/with-deps/package.json +1 -1
  508. package/npm-shrinkwrap.json +194 -46
  509. package/package.json +14 -12
  510. package/dist/server/create-harness.d.ts +0 -26
  511. package/dist/server/create-harness.d.ts.map +0 -1
  512. package/dist/server/create-harness.js +0 -107
  513. package/dist/server/create-harness.js.map +0 -1
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The one projection ADR 0010 names. `AGENTS.md` § Tools states the rule this file
3
+ * implements: never re-derive a tool's capability, risk, or permission
4
+ * classification, because a second independent classification is the drift ADR 0010
5
+ * exists to prevent.
6
+ *
7
+ * This describes; it never enforces. Nothing it returns is an authorization input,
8
+ * and the enforcement paths stay where they are: `core/context/pipeline.ts` and
9
+ * `core/context/eviction.ts` consume a `contractLookup` directly and apply their own
10
+ * conservative defaults, which ADR 0010 permits precisely because they enforce.
11
+ *
12
+ * It computes no classification of its own. Every value below is either read off the
13
+ * declared `contract` or taken from the shared `UNCLASSIFIED` fallback. A future
14
+ * change that adds a branch here inspecting a tool's name or behaviour to decide
15
+ * something has turned the projection into the second classifier it replaces.
16
+ */
17
+ import type { Capability, EvidenceKind, PermissionBehavior, ToolContract } from "./contract.ts";
18
+ /** One tool as every describing surface sees it. Arrays, not sets, so it is comparable and serializable. */
19
+ export interface ToolContractSnapshotEntry {
20
+ readonly name: string;
21
+ /**
22
+ * True when the tool declared no contract and is standing on `UNCLASSIFIED`.
23
+ *
24
+ * Reported rather than merely applied: contracts.md invariant 1 requires it to be
25
+ * visible wherever the registry is described, because a conservative default nobody
26
+ * can see is indistinguishable from a bug.
27
+ */
28
+ readonly unclassified: boolean;
29
+ readonly capabilities: readonly Capability[];
30
+ readonly permission: {
31
+ readonly defaultBehavior: PermissionBehavior;
32
+ };
33
+ readonly context: {
34
+ readonly resultRecoverable: boolean;
35
+ readonly deferSchema: boolean;
36
+ readonly outputBudgetTokens?: number;
37
+ };
38
+ readonly evidence: {
39
+ readonly emits: readonly EvidenceKind[];
40
+ };
41
+ }
42
+ /** The shape this reads. Anything without `contract` is foreign and lands on the fallback. */
43
+ interface MaybeContracted {
44
+ readonly name: string;
45
+ readonly contract?: ToolContract;
46
+ }
47
+ /**
48
+ * The one place that decides whether a tool declared a contract.
49
+ *
50
+ * Exported because `getAllTools` needs the same answer. Two `!("contract" in x)` checks
51
+ * in two files is the shape of the drift ADR 0010 names, even while they agree.
52
+ */
53
+ export declare function isUnclassifiedTool(tool: MaybeContracted): boolean;
54
+ export declare function buildToolContractSnapshot(tools: readonly MaybeContracted[]): ToolContractSnapshotEntry[];
55
+ /** The names a describing surface must report, per contracts.md invariant 1. */
56
+ export declare function unclassifiedToolNames(snapshot: readonly ToolContractSnapshotEntry[]): string[];
57
+ export {};
58
+ //# sourceMappingURL=contract-snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-snapshot.d.ts","sourceRoot":"","sources":["../../../src/core/tools/contract-snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGhG,4GAA4G;AAC5G,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,SAAS,UAAU,EAAE,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE;QAAE,QAAQ,CAAC,eAAe,EAAE,kBAAkB,CAAA;KAAE,CAAC;IACtE,QAAQ,CAAC,OAAO,EAAE;QACjB,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;QACpC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;QAC9B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;KACrC,CAAC;IACF,QAAQ,CAAC,QAAQ,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;KAAE,CAAC;CAC/D;AAED,8FAA8F;AAC9F,UAAU,eAAe;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;CACjC;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAEjE;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,GAAG,yBAAyB,EAAE,CAoBxG;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,SAAS,yBAAyB,EAAE,GAAG,MAAM,EAAE,CAE9F","sourcesContent":["/**\n * The one projection ADR 0010 names. `AGENTS.md` § Tools states the rule this file\n * implements: never re-derive a tool's capability, risk, or permission\n * classification, because a second independent classification is the drift ADR 0010\n * exists to prevent.\n *\n * This describes; it never enforces. Nothing it returns is an authorization input,\n * and the enforcement paths stay where they are: `core/context/pipeline.ts` and\n * `core/context/eviction.ts` consume a `contractLookup` directly and apply their own\n * conservative defaults, which ADR 0010 permits precisely because they enforce.\n *\n * It computes no classification of its own. Every value below is either read off the\n * declared `contract` or taken from the shared `UNCLASSIFIED` fallback. A future\n * change that adds a branch here inspecting a tool's name or behaviour to decide\n * something has turned the projection into the second classifier it replaces.\n */\n\nimport type { Capability, EvidenceKind, PermissionBehavior, ToolContract } from \"./contract.ts\";\nimport { UNCLASSIFIED } from \"./contract.ts\";\n\n/** One tool as every describing surface sees it. Arrays, not sets, so it is comparable and serializable. */\nexport interface ToolContractSnapshotEntry {\n\treadonly name: string;\n\t/**\n\t * True when the tool declared no contract and is standing on `UNCLASSIFIED`.\n\t *\n\t * Reported rather than merely applied: contracts.md invariant 1 requires it to be\n\t * visible wherever the registry is described, because a conservative default nobody\n\t * can see is indistinguishable from a bug.\n\t */\n\treadonly unclassified: boolean;\n\treadonly capabilities: readonly Capability[];\n\treadonly permission: { readonly defaultBehavior: PermissionBehavior };\n\treadonly context: {\n\t\treadonly resultRecoverable: boolean;\n\t\treadonly deferSchema: boolean;\n\t\treadonly outputBudgetTokens?: number;\n\t};\n\treadonly evidence: { readonly emits: readonly EvidenceKind[] };\n}\n\n/** The shape this reads. Anything without `contract` is foreign and lands on the fallback. */\ninterface MaybeContracted {\n\treadonly name: string;\n\treadonly contract?: ToolContract;\n}\n\n/**\n * The one place that decides whether a tool declared a contract.\n *\n * Exported because `getAllTools` needs the same answer. Two `!(\"contract\" in x)` checks\n * in two files is the shape of the drift ADR 0010 names, even while they agree.\n */\nexport function isUnclassifiedTool(tool: MaybeContracted): boolean {\n\treturn !(\"contract\" in tool) || tool.contract === undefined;\n}\n\nexport function buildToolContractSnapshot(tools: readonly MaybeContracted[]): ToolContractSnapshotEntry[] {\n\treturn tools.map((tool) => {\n\t\tconst unclassified = isUnclassifiedTool(tool);\n\t\tconst contract = unclassified ? UNCLASSIFIED : (tool.contract as ToolContract);\n\n\t\treturn {\n\t\t\tname: tool.name,\n\t\t\tunclassified,\n\t\t\tcapabilities: [...contract.capabilities],\n\t\t\tpermission: { defaultBehavior: contract.permission.defaultBehavior },\n\t\t\tcontext: {\n\t\t\t\tresultRecoverable: contract.context.resultRecoverable,\n\t\t\t\tdeferSchema: contract.context.deferSchema,\n\t\t\t\t...(contract.context.outputBudgetTokens === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { outputBudgetTokens: contract.context.outputBudgetTokens }),\n\t\t\t},\n\t\t\tevidence: { emits: [...contract.evidence.emits] },\n\t\t};\n\t});\n}\n\n/** The names a describing surface must report, per contracts.md invariant 1. */\nexport function unclassifiedToolNames(snapshot: readonly ToolContractSnapshotEntry[]): string[] {\n\treturn snapshot.filter((entry) => entry.unclassified).map((entry) => entry.name);\n}\n"]}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The one projection ADR 0010 names. `AGENTS.md` § Tools states the rule this file
3
+ * implements: never re-derive a tool's capability, risk, or permission
4
+ * classification, because a second independent classification is the drift ADR 0010
5
+ * exists to prevent.
6
+ *
7
+ * This describes; it never enforces. Nothing it returns is an authorization input,
8
+ * and the enforcement paths stay where they are: `core/context/pipeline.ts` and
9
+ * `core/context/eviction.ts` consume a `contractLookup` directly and apply their own
10
+ * conservative defaults, which ADR 0010 permits precisely because they enforce.
11
+ *
12
+ * It computes no classification of its own. Every value below is either read off the
13
+ * declared `contract` or taken from the shared `UNCLASSIFIED` fallback. A future
14
+ * change that adds a branch here inspecting a tool's name or behaviour to decide
15
+ * something has turned the projection into the second classifier it replaces.
16
+ */
17
+ import { UNCLASSIFIED } from "./contract.js";
18
+ /**
19
+ * The one place that decides whether a tool declared a contract.
20
+ *
21
+ * Exported because `getAllTools` needs the same answer. Two `!("contract" in x)` checks
22
+ * in two files is the shape of the drift ADR 0010 names, even while they agree.
23
+ */
24
+ export function isUnclassifiedTool(tool) {
25
+ return !("contract" in tool) || tool.contract === undefined;
26
+ }
27
+ export function buildToolContractSnapshot(tools) {
28
+ return tools.map((tool) => {
29
+ const unclassified = isUnclassifiedTool(tool);
30
+ const contract = unclassified ? UNCLASSIFIED : tool.contract;
31
+ return {
32
+ name: tool.name,
33
+ unclassified,
34
+ capabilities: [...contract.capabilities],
35
+ permission: { defaultBehavior: contract.permission.defaultBehavior },
36
+ context: {
37
+ resultRecoverable: contract.context.resultRecoverable,
38
+ deferSchema: contract.context.deferSchema,
39
+ ...(contract.context.outputBudgetTokens === undefined
40
+ ? {}
41
+ : { outputBudgetTokens: contract.context.outputBudgetTokens }),
42
+ },
43
+ evidence: { emits: [...contract.evidence.emits] },
44
+ };
45
+ });
46
+ }
47
+ /** The names a describing surface must report, per contracts.md invariant 1. */
48
+ export function unclassifiedToolNames(snapshot) {
49
+ return snapshot.filter((entry) => entry.unclassified).map((entry) => entry.name);
50
+ }
51
+ //# sourceMappingURL=contract-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-snapshot.js","sourceRoot":"","sources":["../../../src/core/tools/contract-snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AA6B7C;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAqB,EAAW;IAClE,OAAO,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC;AAAA,CAC5D;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAiC,EAA+B;IACzG,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC1B,MAAM,YAAY,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAE,IAAI,CAAC,QAAyB,CAAC;QAE/E,OAAO;YACN,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,YAAY;YACZ,YAAY,EAAE,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC;YACxC,UAAU,EAAE,EAAE,eAAe,EAAE,QAAQ,CAAC,UAAU,CAAC,eAAe,EAAE;YACpE,OAAO,EAAE;gBACR,iBAAiB,EAAE,QAAQ,CAAC,OAAO,CAAC,iBAAiB;gBACrD,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW;gBACzC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,kBAAkB,KAAK,SAAS;oBACpD,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,EAAE,kBAAkB,EAAE,QAAQ,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC;aAC/D;YACD,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;SACjD,CAAC;IAAA,CACF,CAAC,CAAC;AAAA,CACH;AAED,gFAAgF;AAChF,MAAM,UAAU,qBAAqB,CAAC,QAA8C,EAAY;IAC/F,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAAA,CACjF","sourcesContent":["/**\n * The one projection ADR 0010 names. `AGENTS.md` § Tools states the rule this file\n * implements: never re-derive a tool's capability, risk, or permission\n * classification, because a second independent classification is the drift ADR 0010\n * exists to prevent.\n *\n * This describes; it never enforces. Nothing it returns is an authorization input,\n * and the enforcement paths stay where they are: `core/context/pipeline.ts` and\n * `core/context/eviction.ts` consume a `contractLookup` directly and apply their own\n * conservative defaults, which ADR 0010 permits precisely because they enforce.\n *\n * It computes no classification of its own. Every value below is either read off the\n * declared `contract` or taken from the shared `UNCLASSIFIED` fallback. A future\n * change that adds a branch here inspecting a tool's name or behaviour to decide\n * something has turned the projection into the second classifier it replaces.\n */\n\nimport type { Capability, EvidenceKind, PermissionBehavior, ToolContract } from \"./contract.ts\";\nimport { UNCLASSIFIED } from \"./contract.ts\";\n\n/** One tool as every describing surface sees it. Arrays, not sets, so it is comparable and serializable. */\nexport interface ToolContractSnapshotEntry {\n\treadonly name: string;\n\t/**\n\t * True when the tool declared no contract and is standing on `UNCLASSIFIED`.\n\t *\n\t * Reported rather than merely applied: contracts.md invariant 1 requires it to be\n\t * visible wherever the registry is described, because a conservative default nobody\n\t * can see is indistinguishable from a bug.\n\t */\n\treadonly unclassified: boolean;\n\treadonly capabilities: readonly Capability[];\n\treadonly permission: { readonly defaultBehavior: PermissionBehavior };\n\treadonly context: {\n\t\treadonly resultRecoverable: boolean;\n\t\treadonly deferSchema: boolean;\n\t\treadonly outputBudgetTokens?: number;\n\t};\n\treadonly evidence: { readonly emits: readonly EvidenceKind[] };\n}\n\n/** The shape this reads. Anything without `contract` is foreign and lands on the fallback. */\ninterface MaybeContracted {\n\treadonly name: string;\n\treadonly contract?: ToolContract;\n}\n\n/**\n * The one place that decides whether a tool declared a contract.\n *\n * Exported because `getAllTools` needs the same answer. Two `!(\"contract\" in x)` checks\n * in two files is the shape of the drift ADR 0010 names, even while they agree.\n */\nexport function isUnclassifiedTool(tool: MaybeContracted): boolean {\n\treturn !(\"contract\" in tool) || tool.contract === undefined;\n}\n\nexport function buildToolContractSnapshot(tools: readonly MaybeContracted[]): ToolContractSnapshotEntry[] {\n\treturn tools.map((tool) => {\n\t\tconst unclassified = isUnclassifiedTool(tool);\n\t\tconst contract = unclassified ? UNCLASSIFIED : (tool.contract as ToolContract);\n\n\t\treturn {\n\t\t\tname: tool.name,\n\t\t\tunclassified,\n\t\t\tcapabilities: [...contract.capabilities],\n\t\t\tpermission: { defaultBehavior: contract.permission.defaultBehavior },\n\t\t\tcontext: {\n\t\t\t\tresultRecoverable: contract.context.resultRecoverable,\n\t\t\t\tdeferSchema: contract.context.deferSchema,\n\t\t\t\t...(contract.context.outputBudgetTokens === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { outputBudgetTokens: contract.context.outputBudgetTokens }),\n\t\t\t},\n\t\t\tevidence: { emits: [...contract.evidence.emits] },\n\t\t};\n\t});\n}\n\n/** The names a describing surface must report, per contracts.md invariant 1. */\nexport function unclassifiedToolNames(snapshot: readonly ToolContractSnapshotEntry[]): string[] {\n\treturn snapshot.filter((entry) => entry.unclassified).map((entry) => entry.name);\n}\n"]}
@@ -7,8 +7,9 @@
7
7
  * defaulting into "unclassified".
8
8
  */
9
9
  import type { AgentToolResult } from "apex-code-agent-core";
10
- import type { Static, TSchema } from "typebox";
10
+ import { type Static, type TSchema, Type } from "typebox";
11
11
  import type { ToolDefinition } from "../extensions/types.ts";
12
+ import type { PermissionPreview } from "../permissions/responder.ts";
12
13
  /** What class of thing a tool does. A set, not a single value — `bash` is `{exec}`. */
13
14
  export type Capability = "fs.read" | "fs.write" | "exec" | "net" | "delegate" | "ui" | "state";
14
15
  export declare const ALL_CAPABILITIES: ReadonlySet<Capability>;
@@ -21,8 +22,32 @@ export type PermissionBehavior = "allow" | "deny" | "ask";
21
22
  export interface PermissionSpec<TParams extends TSchema = TSchema> {
22
23
  /** Behavior when no rule matches. Read-only tools may default to "allow". */
23
24
  defaultBehavior: PermissionBehavior;
24
- /** Does this call match this rule's content? The tool owns the grammar. */
25
+ /**
26
+ * Per-call behavior when no rule matches, for tools whose calls differ in
27
+ * nature (bash: launching a command is "ask", retrieving or killing an
28
+ * already-approved background command is "allow"). Return undefined to fall
29
+ * back to `defaultBehavior`. Floors and matching rules still outrank it --
30
+ * this only replaces the fallthrough, never a rule or a mode floor.
31
+ */
32
+ defaultBehaviorFor?(params: Static<TParams>): PermissionBehavior | undefined;
33
+ /** Prepare canonical operation facts on the validated call before authorization and execution. */
34
+ prepareCall?(params: Static<TParams>): void;
35
+ /**
36
+ * Describe, for a human about to approve it, what this call would change.
37
+ *
38
+ * Called by the gate only once it has resolved to `ask`, so an allowed or denied
39
+ * call never pays for it. It must read through the value `prepareCall` stored
40
+ * rather than re-deriving a target, which is what keeps the diff the user
41
+ * approves and the bytes execution writes the same file (ADR 0029). It must not
42
+ * execute the tool, write, or widen what the gate already validated.
43
+ */
44
+ previewCall?(params: Static<TParams>): PermissionPreview;
45
+ /** Does this call match this rule's content as an allow rule? */
25
46
  matches(ruleContent: string, params: Static<TParams>): boolean;
47
+ /** Optional deny matcher. It may identify any prohibited part of a structured call. */
48
+ matchesDeny?(ruleContent: string, params: Static<TParams>): boolean;
49
+ /** True when the call contains grammar that cannot be safely authorized by an allow. */
50
+ isUnknown?(params: Static<TParams>): boolean;
26
51
  /** Human-readable rendering of a rule, for prompts and denial messages. */
27
52
  describe(ruleContent: string): string;
28
53
  /**
@@ -94,13 +119,19 @@ export type DiagnosticEvidenceRecord = {
94
119
  serverId?: string;
95
120
  unavailableKind: DiagnosticUnavailableKind;
96
121
  };
97
- /** Normalized argv-based test execution facts. */
122
+ /** How a `test` run actually ended. */
123
+ export type TestProcessOutcome = "exit" | "signal" | "timeout" | "cancelled" | "spawn-failed";
124
+ /** Bounded argv-based test execution facts. Full output never enters evidence; it lives in artifacts. */
98
125
  export interface TestEvidenceRecord {
99
126
  kind: "test";
100
127
  cwd: string;
101
128
  executable: string;
102
129
  argv: string[];
103
130
  exitCode: number | null;
131
+ /** How the run ended. Unset means a legacy record; derive from `exitCode` when reading. */
132
+ outcome?: TestProcessOutcome;
133
+ /** True when the model-facing view omitted part of a stream (full output lives in artifacts). */
134
+ outputTruncated?: boolean;
104
135
  }
105
136
  /** Explicit human attestation; policy decides how, or whether, it is sufficient. */
106
137
  export interface ManualEvidenceRecord {
@@ -165,8 +196,10 @@ export interface ApexToolDefinition<TParams extends TSchema = TSchema, TDetails
165
196
  contract: ToolContract<TParams, TDetails>;
166
197
  }
167
198
  /**
168
- * Conservative contract for a tool registered without one MCP servers and
169
- * third-party extensions cannot supply a `contract`. Full capability set (so it can
199
+ * Conservative contract for a tool registered without one -- third-party extension
200
+ * tools, which cannot supply a `contract`. MCP tools no longer land here: they reach
201
+ * the model through the built-in `mcp` proxy, whose contract is declared in
202
+ * `core/mcp/contract.ts`. Full capability set (so it can
170
203
  * never widen a delegation ceiling), `ask` by default, never evicted, schema
171
204
  * deferred, emits nothing. Matching is exact-argument only: a foreign tool's rule
172
205
  * authorizes exactly the call it was generated from, never a pattern.
@@ -180,4 +213,19 @@ export declare const UNCLASSIFIED: ToolContract<TSchema, unknown>;
180
213
  export declare function resolveToolContract(lookup: (toolName: string) => ToolContract | undefined, toolName: string): ToolContract;
181
214
  /** Resolve the context projection using the same canonical foreign-tool fallback. */
182
215
  export declare function resolveToolContext(lookup: (toolName: string) => Pick<ToolContract, "context"> | undefined, toolName: string): Pick<ToolContract, "context">;
216
+ /**
217
+ * A tool whose call shapes differ, declared so a provider can still see its fields.
218
+ *
219
+ * `Type.Union` compiles to `{ anyOf: [...] }`, which carries no top-level
220
+ * `properties`. The Anthropic request builder reads `properties` and `required`
221
+ * directly (`anthropic-messages.js`, `legacyInputSchema`), so a union reached the
222
+ * model as an object with no fields at all. It then guessed, and our own
223
+ * validation rejected the guess.
224
+ *
225
+ * The union still decides what is valid. `properties` is advertisement, listing
226
+ * every field across the variants so a provider that ignores `anyOf` has
227
+ * something to work from. It deliberately carries no `required`, because no field
228
+ * is required by every variant.
229
+ */
230
+ export declare function toolUnion<T extends TSchema[]>(variants: [...T], properties: Record<string, TSchema>): Type.TUnion<T>;
183
231
  //# sourceMappingURL=contract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/core/tools/contract.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The canonical tool contract. Settled by ADR 0010 and specified in full at\n * docs/architecture/contracts.md § 1 — this module implements that shape, it does\n * not redesign it. `contract` is required on every registered tool, and so is every\n * sub-field: a tool cannot compile without answering all four axes (capabilities,\n * permission, context, evidence), which is what keeps a new tool from silently\n * defaulting into \"unclassified\".\n */\n\nimport type { AgentToolResult } from \"apex-code-agent-core\";\nimport type { Static, TSchema } from \"typebox\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\n\n/** What class of thing a tool does. A set, not a single value — `bash` is `{exec}`. */\nexport type Capability = \"fs.read\" | \"fs.write\" | \"exec\" | \"net\" | \"delegate\" | \"ui\" | \"state\";\n\nexport const ALL_CAPABILITIES: ReadonlySet<Capability> = new Set<Capability>([\n\t\"fs.read\",\n\t\"fs.write\",\n\t\"exec\",\n\t\"net\",\n\t\"delegate\",\n\t\"ui\",\n\t\"state\",\n]);\n\nexport type PermissionBehavior = \"allow\" | \"deny\" | \"ask\";\n\n/**\n * `ruleContent` is interpreted by the tool, never by the rule engine (ADR 0010).\n * That is what lets `Bash(git commit:*)` and `Read(~/.ssh/**)` mean entirely\n * different things while the engine that resolves precedence stays tool-agnostic.\n */\nexport interface PermissionSpec<TParams extends TSchema = TSchema> {\n\t/** Behavior when no rule matches. Read-only tools may default to \"allow\". */\n\tdefaultBehavior: PermissionBehavior;\n\n\t/** Does this call match this rule's content? The tool owns the grammar. */\n\tmatches(ruleContent: string, params: Static<TParams>): boolean;\n\n\t/** Human-readable rendering of a rule, for prompts and denial messages. */\n\tdescribe(ruleContent: string): string;\n\n\t/**\n\t * The rule that would allow this exact call — what \"always allow this\"\n\t * persists. Return null when the call is not generalizable into a rule.\n\t */\n\truleForCall(params: Static<TParams>): string | null;\n}\n\nexport interface ContextSpec {\n\t/**\n\t * True when the result's information is recoverable — the same content can be\n\t * obtained again by re-running the tool or reading the workspace.\n\t *\n\t * ONLY recoverable results may be evicted (Phase 3). A tool whose result cannot\n\t * be regenerated (a nondeterministic command, a consumed one-shot resource)\n\t * must set this false, or eviction would silently destroy information the\n\t * transcript is the only record of.\n\t */\n\tresultRecoverable: boolean;\n\n\t/** Marker substituted for an evicted result. */\n\tevictionMarker?: string;\n\n\t/** Announce by name only; load the parameter schema on demand. */\n\tdeferSchema: boolean;\n\n\t/** Soft cap on result tokens before truncation. */\n\toutputBudgetTokens?: number;\n}\n\nexport type EvidenceKind = \"diff\" | \"test\" | \"command\" | \"manual\" | \"workflow\" | \"diagnostic\";\n\n/** Source-observed command facts. `exitCode` is absent only when execution never began. */\nexport interface CommandEvidenceRecord {\n\tkind: \"command\";\n\tcommand: string;\n\tcwd?: string;\n\texecutable?: string;\n\targv?: string[];\n\texitCode?: number | null;\n}\n\n/** A file mutation is identified by hashes and paths, never raw file or patch contents. */\nexport interface DiffEvidenceRecord {\n\tkind: \"diff\";\n\tpath: string;\n\tpatchHash?: string;\n\tcontentHash?: string;\n\tbyteCount?: number;\n}\n\n/** Zero-filled diagnostic severity buckets for one bounded language-server outcome. */\nexport interface DiagnosticSeverityCounts {\n\terror: number;\n\twarning: number;\n\tinformation: number;\n\thint: number;\n\tunspecified: number;\n\tother: number;\n}\n\n/** Stable durable classification. Free-form server and process errors never enter evidence. */\nexport type DiagnosticUnavailableKind =\n\t| \"no-server\"\n\t| \"disposed\"\n\t| \"unsupported-sync\"\n\t| \"timed-out\"\n\t| \"aborted\"\n\t| \"superseded\"\n\t| \"server-failed\";\n\n/** Bounded post-mutation diagnostic facts, never diagnostic messages or rendered failure reasons. */\nexport type DiagnosticEvidenceRecord =\n\t| {\n\t\t\tkind: \"diagnostic\";\n\t\t\tpath: string;\n\t\t\tstatus: \"ok\";\n\t\t\tserverId: string;\n\t\t\tdiagnosticCount: number;\n\t\t\tseverityCounts: DiagnosticSeverityCounts;\n\t\t\ttruncated: boolean;\n\t }\n\t| {\n\t\t\tkind: \"diagnostic\";\n\t\t\tpath: string;\n\t\t\tstatus: \"unavailable\";\n\t\t\tserverId?: string;\n\t\t\tunavailableKind: DiagnosticUnavailableKind;\n\t };\n\n/** Normalized argv-based test execution facts. */\nexport interface TestEvidenceRecord {\n\tkind: \"test\";\n\tcwd: string;\n\texecutable: string;\n\targv: string[];\n\texitCode: number | null;\n}\n\n/** Explicit human attestation; policy decides how, or whether, it is sufficient. */\nexport interface ManualEvidenceRecord {\n\tkind: \"manual\";\n\tvalue?: unknown;\n\tobserved?: unknown;\n\tstatus?: string;\n}\n\n/** Source facts from approval and delegation workflows. */\nexport interface WorkflowEvidenceRecord {\n\tkind: \"workflow\";\n\tplan?: string;\n\tapproved?: boolean;\n\tagentType?: string;\n\ttask?: string;\n\thandle?: string;\n}\n\n/** A structured source record. Policy is a separate consumer, not an additional variant. */\nexport type EvidenceRecord =\n\t| CommandEvidenceRecord\n\t| DiffEvidenceRecord\n\t| DiagnosticEvidenceRecord\n\t| TestEvidenceRecord\n\t| ManualEvidenceRecord\n\t| WorkflowEvidenceRecord;\n\n/** Durable destination for source-level tool evidence. Policy is deliberately not part of this boundary. */\nexport interface EvidenceSink {\n\trecord(entry: { toolName: string; records: EvidenceRecord[] }): void;\n\trecordDiagnostic?(diagnostic: EvidenceCaptureDiagnostic): void;\n}\n\n/** A capture failure is observable but never changes an already-completed tool result. */\nexport interface EvidenceCaptureDiagnostic {\n\ttoolName: string;\n\treason: string;\n}\n\nexport interface EvidenceSpec<TParams extends TSchema = TSchema, TDetails = unknown> {\n\t/** Kinds this tool can emit. Empty set is valid and explicit. */\n\temits: ReadonlySet<EvidenceKind>;\n\n\t/**\n\t * Derive evidence from a completed call. Runs inside the tool's own execution\n\t * path, with access to what actually happened, not a reconstruction from\n\t * rendered output.\n\t */\n\tcapture(params: Static<TParams>, result: AgentToolResult<TDetails>): EvidenceRecord[];\n}\n\nexport interface ToolContract<TParams extends TSchema = TSchema, TDetails = unknown> {\n\tcapabilities: ReadonlySet<Capability>;\n\tpermission: PermissionSpec<TParams>;\n\tcontext: ContextSpec;\n\tevidence: EvidenceSpec<TParams, TDetails>;\n}\n\n/**\n * Apex Code extends upstream ToolDefinition with exactly one required field.\n *\n * `TState` defaults to `any`, matching upstream `ToolDefinition` exactly (not\n * `unknown`). That default is load-bearing: TypeScript compares two instantiations\n * of the *same* generic interface (here, both rooted in `ToolDefinition`) using each\n * type parameter's declared variance, without expanding `Static<TParams>`\n * structurally — but only when every type argument lines up, including the ones a\n * caller left defaulted. A mismatched default reintroduces a full structural check,\n * where `Static<any>` does not behave like `any`, and breaks every pre-existing\n * `ToolDefinition<any, X>`-typed consumer across the codebase.\n */\nexport interface ApexToolDefinition<TParams extends TSchema = TSchema, TDetails = unknown, TState = any>\n\textends ToolDefinition<TParams, TDetails, TState> {\n\tcontract: ToolContract<TParams, TDetails>;\n}\n\n/**\n * Conservative contract for a tool registered without one — MCP servers and\n * third-party extensions cannot supply a `contract`. Full capability set (so it can\n * never widen a delegation ceiling), `ask` by default, never evicted, schema\n * deferred, emits nothing. Matching is exact-argument only: a foreign tool's rule\n * authorizes exactly the call it was generated from, never a pattern.\n *\n * This must also be reported as unclassified wherever a consumer describes the tool\n * registry (contracts.md invariant 1) — a conservative default nobody can see is\n * indistinguishable from a bug.\n */\nexport const UNCLASSIFIED: ToolContract<TSchema, unknown> = {\n\tcapabilities: ALL_CAPABILITIES,\n\tpermission: {\n\t\tdefaultBehavior: \"ask\",\n\t\tmatches: (ruleContent, params) => ruleContent === JSON.stringify(params),\n\t\tdescribe: (ruleContent) => `Exact call: ${ruleContent}`,\n\t\truleForCall: (params) => JSON.stringify(params),\n\t},\n\tcontext: { resultRecoverable: false, deferSchema: false },\n\tevidence: { emits: new Set(), capture: () => [] },\n};\n\n/** Resolve a complete tool contract for enforcement consumers. */\nexport function resolveToolContract(\n\tlookup: (toolName: string) => ToolContract | undefined,\n\ttoolName: string,\n): ToolContract {\n\treturn lookup(toolName) ?? UNCLASSIFIED;\n}\n\n/** Resolve the context projection using the same canonical foreign-tool fallback. */\nexport function resolveToolContext(\n\tlookup: (toolName: string) => Pick<ToolContract, \"context\"> | undefined,\n\ttoolName: string,\n): Pick<ToolContract, \"context\"> {\n\treturn lookup(toolName) ?? UNCLASSIFIED;\n}\n"]}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/core/tools/contract.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The canonical tool contract. Settled by ADR 0010 and specified in full at\n * docs/architecture/contracts.md § 1 — this module implements that shape, it does\n * not redesign it. `contract` is required on every registered tool, and so is every\n * sub-field: a tool cannot compile without answering all four axes (capabilities,\n * permission, context, evidence), which is what keeps a new tool from silently\n * defaulting into \"unclassified\".\n */\n\nimport type { AgentToolResult } from \"apex-code-agent-core\";\nimport { type Static, type TSchema, Type } from \"typebox\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport type { PermissionPreview } from \"../permissions/responder.ts\";\n\n/** What class of thing a tool does. A set, not a single value — `bash` is `{exec}`. */\nexport type Capability = \"fs.read\" | \"fs.write\" | \"exec\" | \"net\" | \"delegate\" | \"ui\" | \"state\";\n\nexport const ALL_CAPABILITIES: ReadonlySet<Capability> = new Set<Capability>([\n\t\"fs.read\",\n\t\"fs.write\",\n\t\"exec\",\n\t\"net\",\n\t\"delegate\",\n\t\"ui\",\n\t\"state\",\n]);\n\nexport type PermissionBehavior = \"allow\" | \"deny\" | \"ask\";\n\n/**\n * `ruleContent` is interpreted by the tool, never by the rule engine (ADR 0010).\n * That is what lets `Bash(git commit:*)` and `Read(~/.ssh/**)` mean entirely\n * different things while the engine that resolves precedence stays tool-agnostic.\n */\nexport interface PermissionSpec<TParams extends TSchema = TSchema> {\n\t/** Behavior when no rule matches. Read-only tools may default to \"allow\". */\n\tdefaultBehavior: PermissionBehavior;\n\n\t/**\n\t * Per-call behavior when no rule matches, for tools whose calls differ in\n\t * nature (bash: launching a command is \"ask\", retrieving or killing an\n\t * already-approved background command is \"allow\"). Return undefined to fall\n\t * back to `defaultBehavior`. Floors and matching rules still outrank it --\n\t * this only replaces the fallthrough, never a rule or a mode floor.\n\t */\n\tdefaultBehaviorFor?(params: Static<TParams>): PermissionBehavior | undefined;\n\n\t/** Prepare canonical operation facts on the validated call before authorization and execution. */\n\tprepareCall?(params: Static<TParams>): void;\n\n\t/**\n\t * Describe, for a human about to approve it, what this call would change.\n\t *\n\t * Called by the gate only once it has resolved to `ask`, so an allowed or denied\n\t * call never pays for it. It must read through the value `prepareCall` stored\n\t * rather than re-deriving a target, which is what keeps the diff the user\n\t * approves and the bytes execution writes the same file (ADR 0029). It must not\n\t * execute the tool, write, or widen what the gate already validated.\n\t */\n\tpreviewCall?(params: Static<TParams>): PermissionPreview;\n\t/** Does this call match this rule's content as an allow rule? */\n\tmatches(ruleContent: string, params: Static<TParams>): boolean;\n\t/** Optional deny matcher. It may identify any prohibited part of a structured call. */\n\tmatchesDeny?(ruleContent: string, params: Static<TParams>): boolean;\n\t/** True when the call contains grammar that cannot be safely authorized by an allow. */\n\tisUnknown?(params: Static<TParams>): boolean;\n\n\t/** Human-readable rendering of a rule, for prompts and denial messages. */\n\tdescribe(ruleContent: string): string;\n\n\t/**\n\t * The rule that would allow this exact call — what \"always allow this\"\n\t * persists. Return null when the call is not generalizable into a rule.\n\t */\n\truleForCall(params: Static<TParams>): string | null;\n}\n\nexport interface ContextSpec {\n\t/**\n\t * True when the result's information is recoverable — the same content can be\n\t * obtained again by re-running the tool or reading the workspace.\n\t *\n\t * ONLY recoverable results may be evicted (Phase 3). A tool whose result cannot\n\t * be regenerated (a nondeterministic command, a consumed one-shot resource)\n\t * must set this false, or eviction would silently destroy information the\n\t * transcript is the only record of.\n\t */\n\tresultRecoverable: boolean;\n\n\t/** Marker substituted for an evicted result. */\n\tevictionMarker?: string;\n\n\t/** Announce by name only; load the parameter schema on demand. */\n\tdeferSchema: boolean;\n\n\t/** Soft cap on result tokens before truncation. */\n\toutputBudgetTokens?: number;\n}\n\nexport type EvidenceKind = \"diff\" | \"test\" | \"command\" | \"manual\" | \"workflow\" | \"diagnostic\";\n\n/** Source-observed command facts. `exitCode` is absent only when execution never began. */\nexport interface CommandEvidenceRecord {\n\tkind: \"command\";\n\tcommand: string;\n\tcwd?: string;\n\texecutable?: string;\n\targv?: string[];\n\texitCode?: number | null;\n}\n\n/** A file mutation is identified by hashes and paths, never raw file or patch contents. */\nexport interface DiffEvidenceRecord {\n\tkind: \"diff\";\n\tpath: string;\n\tpatchHash?: string;\n\tcontentHash?: string;\n\tbyteCount?: number;\n}\n\n/** Zero-filled diagnostic severity buckets for one bounded language-server outcome. */\nexport interface DiagnosticSeverityCounts {\n\terror: number;\n\twarning: number;\n\tinformation: number;\n\thint: number;\n\tunspecified: number;\n\tother: number;\n}\n\n/** Stable durable classification. Free-form server and process errors never enter evidence. */\nexport type DiagnosticUnavailableKind =\n\t| \"no-server\"\n\t| \"disposed\"\n\t| \"unsupported-sync\"\n\t| \"timed-out\"\n\t| \"aborted\"\n\t| \"superseded\"\n\t| \"server-failed\";\n\n/** Bounded post-mutation diagnostic facts, never diagnostic messages or rendered failure reasons. */\nexport type DiagnosticEvidenceRecord =\n\t| {\n\t\t\tkind: \"diagnostic\";\n\t\t\tpath: string;\n\t\t\tstatus: \"ok\";\n\t\t\tserverId: string;\n\t\t\tdiagnosticCount: number;\n\t\t\tseverityCounts: DiagnosticSeverityCounts;\n\t\t\ttruncated: boolean;\n\t }\n\t| {\n\t\t\tkind: \"diagnostic\";\n\t\t\tpath: string;\n\t\t\tstatus: \"unavailable\";\n\t\t\tserverId?: string;\n\t\t\tunavailableKind: DiagnosticUnavailableKind;\n\t };\n\n/** How a `test` run actually ended. */\nexport type TestProcessOutcome = \"exit\" | \"signal\" | \"timeout\" | \"cancelled\" | \"spawn-failed\";\n\n/** Bounded argv-based test execution facts. Full output never enters evidence; it lives in artifacts. */\nexport interface TestEvidenceRecord {\n\tkind: \"test\";\n\tcwd: string;\n\texecutable: string;\n\targv: string[];\n\texitCode: number | null;\n\t/** How the run ended. Unset means a legacy record; derive from `exitCode` when reading. */\n\toutcome?: TestProcessOutcome;\n\t/** True when the model-facing view omitted part of a stream (full output lives in artifacts). */\n\toutputTruncated?: boolean;\n}\n\n/** Explicit human attestation; policy decides how, or whether, it is sufficient. */\nexport interface ManualEvidenceRecord {\n\tkind: \"manual\";\n\tvalue?: unknown;\n\tobserved?: unknown;\n\tstatus?: string;\n}\n\n/** Source facts from approval and delegation workflows. */\nexport interface WorkflowEvidenceRecord {\n\tkind: \"workflow\";\n\tplan?: string;\n\tapproved?: boolean;\n\tagentType?: string;\n\ttask?: string;\n\thandle?: string;\n}\n\n/** A structured source record. Policy is a separate consumer, not an additional variant. */\nexport type EvidenceRecord =\n\t| CommandEvidenceRecord\n\t| DiffEvidenceRecord\n\t| DiagnosticEvidenceRecord\n\t| TestEvidenceRecord\n\t| ManualEvidenceRecord\n\t| WorkflowEvidenceRecord;\n\n/** Durable destination for source-level tool evidence. Policy is deliberately not part of this boundary. */\nexport interface EvidenceSink {\n\trecord(entry: { toolName: string; records: EvidenceRecord[] }): void;\n\trecordDiagnostic?(diagnostic: EvidenceCaptureDiagnostic): void;\n}\n\n/** A capture failure is observable but never changes an already-completed tool result. */\nexport interface EvidenceCaptureDiagnostic {\n\ttoolName: string;\n\treason: string;\n}\n\nexport interface EvidenceSpec<TParams extends TSchema = TSchema, TDetails = unknown> {\n\t/** Kinds this tool can emit. Empty set is valid and explicit. */\n\temits: ReadonlySet<EvidenceKind>;\n\n\t/**\n\t * Derive evidence from a completed call. Runs inside the tool's own execution\n\t * path, with access to what actually happened, not a reconstruction from\n\t * rendered output.\n\t */\n\tcapture(params: Static<TParams>, result: AgentToolResult<TDetails>): EvidenceRecord[];\n}\n\nexport interface ToolContract<TParams extends TSchema = TSchema, TDetails = unknown> {\n\tcapabilities: ReadonlySet<Capability>;\n\tpermission: PermissionSpec<TParams>;\n\tcontext: ContextSpec;\n\tevidence: EvidenceSpec<TParams, TDetails>;\n}\n\n/**\n * Apex Code extends upstream ToolDefinition with exactly one required field.\n *\n * `TState` defaults to `any`, matching upstream `ToolDefinition` exactly (not\n * `unknown`). That default is load-bearing: TypeScript compares two instantiations\n * of the *same* generic interface (here, both rooted in `ToolDefinition`) using each\n * type parameter's declared variance, without expanding `Static<TParams>`\n * structurally — but only when every type argument lines up, including the ones a\n * caller left defaulted. A mismatched default reintroduces a full structural check,\n * where `Static<any>` does not behave like `any`, and breaks every pre-existing\n * `ToolDefinition<any, X>`-typed consumer across the codebase.\n */\nexport interface ApexToolDefinition<TParams extends TSchema = TSchema, TDetails = unknown, TState = any>\n\textends ToolDefinition<TParams, TDetails, TState> {\n\tcontract: ToolContract<TParams, TDetails>;\n}\n\n/**\n * Conservative contract for a tool registered without one -- third-party extension\n * tools, which cannot supply a `contract`. MCP tools no longer land here: they reach\n * the model through the built-in `mcp` proxy, whose contract is declared in\n * `core/mcp/contract.ts`. Full capability set (so it can\n * never widen a delegation ceiling), `ask` by default, never evicted, schema\n * deferred, emits nothing. Matching is exact-argument only: a foreign tool's rule\n * authorizes exactly the call it was generated from, never a pattern.\n *\n * This must also be reported as unclassified wherever a consumer describes the tool\n * registry (contracts.md invariant 1) — a conservative default nobody can see is\n * indistinguishable from a bug.\n */\nexport const UNCLASSIFIED: ToolContract<TSchema, unknown> = {\n\tcapabilities: ALL_CAPABILITIES,\n\tpermission: {\n\t\tdefaultBehavior: \"ask\",\n\t\tmatches: (ruleContent, params) => ruleContent === JSON.stringify(params),\n\t\tdescribe: (ruleContent) => `Exact call: ${ruleContent}`,\n\t\truleForCall: (params) => JSON.stringify(params),\n\t},\n\tcontext: { resultRecoverable: false, deferSchema: false },\n\tevidence: { emits: new Set(), capture: () => [] },\n};\n\n/** Resolve a complete tool contract for enforcement consumers. */\nexport function resolveToolContract(\n\tlookup: (toolName: string) => ToolContract | undefined,\n\ttoolName: string,\n): ToolContract {\n\treturn lookup(toolName) ?? UNCLASSIFIED;\n}\n\n/** Resolve the context projection using the same canonical foreign-tool fallback. */\nexport function resolveToolContext(\n\tlookup: (toolName: string) => Pick<ToolContract, \"context\"> | undefined,\n\ttoolName: string,\n): Pick<ToolContract, \"context\"> {\n\treturn lookup(toolName) ?? UNCLASSIFIED;\n}\n\n/**\n * A tool whose call shapes differ, declared so a provider can still see its fields.\n *\n * `Type.Union` compiles to `{ anyOf: [...] }`, which carries no top-level\n * `properties`. The Anthropic request builder reads `properties` and `required`\n * directly (`anthropic-messages.js`, `legacyInputSchema`), so a union reached the\n * model as an object with no fields at all. It then guessed, and our own\n * validation rejected the guess.\n *\n * The union still decides what is valid. `properties` is advertisement, listing\n * every field across the variants so a provider that ignores `anyOf` has\n * something to work from. It deliberately carries no `required`, because no field\n * is required by every variant.\n */\nexport function toolUnion<T extends TSchema[]>(variants: [...T], properties: Record<string, TSchema>) {\n\treturn Type.Union(variants, { type: \"object\", properties });\n}\n"]}
@@ -6,6 +6,7 @@
6
6
  * permission, context, evidence), which is what keeps a new tool from silently
7
7
  * defaulting into "unclassified".
8
8
  */
9
+ import { Type } from "typebox";
9
10
  export const ALL_CAPABILITIES = new Set([
10
11
  "fs.read",
11
12
  "fs.write",
@@ -16,8 +17,10 @@ export const ALL_CAPABILITIES = new Set([
16
17
  "state",
17
18
  ]);
18
19
  /**
19
- * Conservative contract for a tool registered without one MCP servers and
20
- * third-party extensions cannot supply a `contract`. Full capability set (so it can
20
+ * Conservative contract for a tool registered without one -- third-party extension
21
+ * tools, which cannot supply a `contract`. MCP tools no longer land here: they reach
22
+ * the model through the built-in `mcp` proxy, whose contract is declared in
23
+ * `core/mcp/contract.ts`. Full capability set (so it can
21
24
  * never widen a delegation ceiling), `ask` by default, never evicted, schema
22
25
  * deferred, emits nothing. Matching is exact-argument only: a foreign tool's rule
23
26
  * authorizes exactly the call it was generated from, never a pattern.
@@ -45,4 +48,21 @@ export function resolveToolContract(lookup, toolName) {
45
48
  export function resolveToolContext(lookup, toolName) {
46
49
  return lookup(toolName) ?? UNCLASSIFIED;
47
50
  }
51
+ /**
52
+ * A tool whose call shapes differ, declared so a provider can still see its fields.
53
+ *
54
+ * `Type.Union` compiles to `{ anyOf: [...] }`, which carries no top-level
55
+ * `properties`. The Anthropic request builder reads `properties` and `required`
56
+ * directly (`anthropic-messages.js`, `legacyInputSchema`), so a union reached the
57
+ * model as an object with no fields at all. It then guessed, and our own
58
+ * validation rejected the guess.
59
+ *
60
+ * The union still decides what is valid. `properties` is advertisement, listing
61
+ * every field across the variants so a provider that ignores `anyOf` has
62
+ * something to work from. It deliberately carries no `required`, because no field
63
+ * is required by every variant.
64
+ */
65
+ export function toolUnion(variants, properties) {
66
+ return Type.Union(variants, { type: "object", properties });
67
+ }
48
68
  //# sourceMappingURL=contract.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/core/tools/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,MAAM,CAAC,MAAM,gBAAgB,GAA4B,IAAI,GAAG,CAAa;IAC5E,SAAS;IACT,UAAU;IACV,MAAM;IACN,KAAK;IACL,UAAU;IACV,IAAI;IACJ,OAAO;CACP,CAAC,CAAC;AAgMH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,YAAY,GAAmC;IAC3D,YAAY,EAAE,gBAAgB;IAC9B,UAAU,EAAE;QACX,eAAe,EAAE,KAAK;QACtB,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC,WAAW,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;QACxE,QAAQ,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,eAAe,WAAW,EAAE;QACvD,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;KAC/C;IACD,OAAO,EAAE,EAAE,iBAAiB,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE;IACzD,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE;CACjD,CAAC;AAEF,kEAAkE;AAClE,MAAM,UAAU,mBAAmB,CAClC,MAAsD,EACtD,QAAgB,EACD;IACf,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC;AAAA,CACxC;AAED,qFAAqF;AACrF,MAAM,UAAU,kBAAkB,CACjC,MAAuE,EACvE,QAAgB,EACgB;IAChC,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC;AAAA,CACxC","sourcesContent":["/**\n * The canonical tool contract. Settled by ADR 0010 and specified in full at\n * docs/architecture/contracts.md § 1 — this module implements that shape, it does\n * not redesign it. `contract` is required on every registered tool, and so is every\n * sub-field: a tool cannot compile without answering all four axes (capabilities,\n * permission, context, evidence), which is what keeps a new tool from silently\n * defaulting into \"unclassified\".\n */\n\nimport type { AgentToolResult } from \"apex-code-agent-core\";\nimport type { Static, TSchema } from \"typebox\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\n\n/** What class of thing a tool does. A set, not a single value — `bash` is `{exec}`. */\nexport type Capability = \"fs.read\" | \"fs.write\" | \"exec\" | \"net\" | \"delegate\" | \"ui\" | \"state\";\n\nexport const ALL_CAPABILITIES: ReadonlySet<Capability> = new Set<Capability>([\n\t\"fs.read\",\n\t\"fs.write\",\n\t\"exec\",\n\t\"net\",\n\t\"delegate\",\n\t\"ui\",\n\t\"state\",\n]);\n\nexport type PermissionBehavior = \"allow\" | \"deny\" | \"ask\";\n\n/**\n * `ruleContent` is interpreted by the tool, never by the rule engine (ADR 0010).\n * That is what lets `Bash(git commit:*)` and `Read(~/.ssh/**)` mean entirely\n * different things while the engine that resolves precedence stays tool-agnostic.\n */\nexport interface PermissionSpec<TParams extends TSchema = TSchema> {\n\t/** Behavior when no rule matches. Read-only tools may default to \"allow\". */\n\tdefaultBehavior: PermissionBehavior;\n\n\t/** Does this call match this rule's content? The tool owns the grammar. */\n\tmatches(ruleContent: string, params: Static<TParams>): boolean;\n\n\t/** Human-readable rendering of a rule, for prompts and denial messages. */\n\tdescribe(ruleContent: string): string;\n\n\t/**\n\t * The rule that would allow this exact call — what \"always allow this\"\n\t * persists. Return null when the call is not generalizable into a rule.\n\t */\n\truleForCall(params: Static<TParams>): string | null;\n}\n\nexport interface ContextSpec {\n\t/**\n\t * True when the result's information is recoverable — the same content can be\n\t * obtained again by re-running the tool or reading the workspace.\n\t *\n\t * ONLY recoverable results may be evicted (Phase 3). A tool whose result cannot\n\t * be regenerated (a nondeterministic command, a consumed one-shot resource)\n\t * must set this false, or eviction would silently destroy information the\n\t * transcript is the only record of.\n\t */\n\tresultRecoverable: boolean;\n\n\t/** Marker substituted for an evicted result. */\n\tevictionMarker?: string;\n\n\t/** Announce by name only; load the parameter schema on demand. */\n\tdeferSchema: boolean;\n\n\t/** Soft cap on result tokens before truncation. */\n\toutputBudgetTokens?: number;\n}\n\nexport type EvidenceKind = \"diff\" | \"test\" | \"command\" | \"manual\" | \"workflow\" | \"diagnostic\";\n\n/** Source-observed command facts. `exitCode` is absent only when execution never began. */\nexport interface CommandEvidenceRecord {\n\tkind: \"command\";\n\tcommand: string;\n\tcwd?: string;\n\texecutable?: string;\n\targv?: string[];\n\texitCode?: number | null;\n}\n\n/** A file mutation is identified by hashes and paths, never raw file or patch contents. */\nexport interface DiffEvidenceRecord {\n\tkind: \"diff\";\n\tpath: string;\n\tpatchHash?: string;\n\tcontentHash?: string;\n\tbyteCount?: number;\n}\n\n/** Zero-filled diagnostic severity buckets for one bounded language-server outcome. */\nexport interface DiagnosticSeverityCounts {\n\terror: number;\n\twarning: number;\n\tinformation: number;\n\thint: number;\n\tunspecified: number;\n\tother: number;\n}\n\n/** Stable durable classification. Free-form server and process errors never enter evidence. */\nexport type DiagnosticUnavailableKind =\n\t| \"no-server\"\n\t| \"disposed\"\n\t| \"unsupported-sync\"\n\t| \"timed-out\"\n\t| \"aborted\"\n\t| \"superseded\"\n\t| \"server-failed\";\n\n/** Bounded post-mutation diagnostic facts, never diagnostic messages or rendered failure reasons. */\nexport type DiagnosticEvidenceRecord =\n\t| {\n\t\t\tkind: \"diagnostic\";\n\t\t\tpath: string;\n\t\t\tstatus: \"ok\";\n\t\t\tserverId: string;\n\t\t\tdiagnosticCount: number;\n\t\t\tseverityCounts: DiagnosticSeverityCounts;\n\t\t\ttruncated: boolean;\n\t }\n\t| {\n\t\t\tkind: \"diagnostic\";\n\t\t\tpath: string;\n\t\t\tstatus: \"unavailable\";\n\t\t\tserverId?: string;\n\t\t\tunavailableKind: DiagnosticUnavailableKind;\n\t };\n\n/** Normalized argv-based test execution facts. */\nexport interface TestEvidenceRecord {\n\tkind: \"test\";\n\tcwd: string;\n\texecutable: string;\n\targv: string[];\n\texitCode: number | null;\n}\n\n/** Explicit human attestation; policy decides how, or whether, it is sufficient. */\nexport interface ManualEvidenceRecord {\n\tkind: \"manual\";\n\tvalue?: unknown;\n\tobserved?: unknown;\n\tstatus?: string;\n}\n\n/** Source facts from approval and delegation workflows. */\nexport interface WorkflowEvidenceRecord {\n\tkind: \"workflow\";\n\tplan?: string;\n\tapproved?: boolean;\n\tagentType?: string;\n\ttask?: string;\n\thandle?: string;\n}\n\n/** A structured source record. Policy is a separate consumer, not an additional variant. */\nexport type EvidenceRecord =\n\t| CommandEvidenceRecord\n\t| DiffEvidenceRecord\n\t| DiagnosticEvidenceRecord\n\t| TestEvidenceRecord\n\t| ManualEvidenceRecord\n\t| WorkflowEvidenceRecord;\n\n/** Durable destination for source-level tool evidence. Policy is deliberately not part of this boundary. */\nexport interface EvidenceSink {\n\trecord(entry: { toolName: string; records: EvidenceRecord[] }): void;\n\trecordDiagnostic?(diagnostic: EvidenceCaptureDiagnostic): void;\n}\n\n/** A capture failure is observable but never changes an already-completed tool result. */\nexport interface EvidenceCaptureDiagnostic {\n\ttoolName: string;\n\treason: string;\n}\n\nexport interface EvidenceSpec<TParams extends TSchema = TSchema, TDetails = unknown> {\n\t/** Kinds this tool can emit. Empty set is valid and explicit. */\n\temits: ReadonlySet<EvidenceKind>;\n\n\t/**\n\t * Derive evidence from a completed call. Runs inside the tool's own execution\n\t * path, with access to what actually happened, not a reconstruction from\n\t * rendered output.\n\t */\n\tcapture(params: Static<TParams>, result: AgentToolResult<TDetails>): EvidenceRecord[];\n}\n\nexport interface ToolContract<TParams extends TSchema = TSchema, TDetails = unknown> {\n\tcapabilities: ReadonlySet<Capability>;\n\tpermission: PermissionSpec<TParams>;\n\tcontext: ContextSpec;\n\tevidence: EvidenceSpec<TParams, TDetails>;\n}\n\n/**\n * Apex Code extends upstream ToolDefinition with exactly one required field.\n *\n * `TState` defaults to `any`, matching upstream `ToolDefinition` exactly (not\n * `unknown`). That default is load-bearing: TypeScript compares two instantiations\n * of the *same* generic interface (here, both rooted in `ToolDefinition`) using each\n * type parameter's declared variance, without expanding `Static<TParams>`\n * structurally — but only when every type argument lines up, including the ones a\n * caller left defaulted. A mismatched default reintroduces a full structural check,\n * where `Static<any>` does not behave like `any`, and breaks every pre-existing\n * `ToolDefinition<any, X>`-typed consumer across the codebase.\n */\nexport interface ApexToolDefinition<TParams extends TSchema = TSchema, TDetails = unknown, TState = any>\n\textends ToolDefinition<TParams, TDetails, TState> {\n\tcontract: ToolContract<TParams, TDetails>;\n}\n\n/**\n * Conservative contract for a tool registered without one — MCP servers and\n * third-party extensions cannot supply a `contract`. Full capability set (so it can\n * never widen a delegation ceiling), `ask` by default, never evicted, schema\n * deferred, emits nothing. Matching is exact-argument only: a foreign tool's rule\n * authorizes exactly the call it was generated from, never a pattern.\n *\n * This must also be reported as unclassified wherever a consumer describes the tool\n * registry (contracts.md invariant 1) — a conservative default nobody can see is\n * indistinguishable from a bug.\n */\nexport const UNCLASSIFIED: ToolContract<TSchema, unknown> = {\n\tcapabilities: ALL_CAPABILITIES,\n\tpermission: {\n\t\tdefaultBehavior: \"ask\",\n\t\tmatches: (ruleContent, params) => ruleContent === JSON.stringify(params),\n\t\tdescribe: (ruleContent) => `Exact call: ${ruleContent}`,\n\t\truleForCall: (params) => JSON.stringify(params),\n\t},\n\tcontext: { resultRecoverable: false, deferSchema: false },\n\tevidence: { emits: new Set(), capture: () => [] },\n};\n\n/** Resolve a complete tool contract for enforcement consumers. */\nexport function resolveToolContract(\n\tlookup: (toolName: string) => ToolContract | undefined,\n\ttoolName: string,\n): ToolContract {\n\treturn lookup(toolName) ?? UNCLASSIFIED;\n}\n\n/** Resolve the context projection using the same canonical foreign-tool fallback. */\nexport function resolveToolContext(\n\tlookup: (toolName: string) => Pick<ToolContract, \"context\"> | undefined,\n\ttoolName: string,\n): Pick<ToolContract, \"context\"> {\n\treturn lookup(toolName) ?? UNCLASSIFIED;\n}\n"]}
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/core/tools/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAA6B,IAAI,EAAE,MAAM,SAAS,CAAC;AAO1D,MAAM,CAAC,MAAM,gBAAgB,GAA4B,IAAI,GAAG,CAAa;IAC5E,SAAS;IACT,UAAU;IACV,MAAM;IACN,KAAK;IACL,UAAU;IACV,IAAI;IACJ,OAAO;CACP,CAAC,CAAC;AAiOH;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,YAAY,GAAmC;IAC3D,YAAY,EAAE,gBAAgB;IAC9B,UAAU,EAAE;QACX,eAAe,EAAE,KAAK;QACtB,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC,WAAW,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;QACxE,QAAQ,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,eAAe,WAAW,EAAE;QACvD,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;KAC/C;IACD,OAAO,EAAE,EAAE,iBAAiB,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE;IACzD,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE;CACjD,CAAC;AAEF,kEAAkE;AAClE,MAAM,UAAU,mBAAmB,CAClC,MAAsD,EACtD,QAAgB,EACD;IACf,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC;AAAA,CACxC;AAED,qFAAqF;AACrF,MAAM,UAAU,kBAAkB,CACjC,MAAuE,EACvE,QAAgB,EACgB;IAChC,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC;AAAA,CACxC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,SAAS,CAAsB,QAAgB,EAAE,UAAmC,EAAE;IACrG,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;AAAA,CAC5D","sourcesContent":["/**\n * The canonical tool contract. Settled by ADR 0010 and specified in full at\n * docs/architecture/contracts.md § 1 — this module implements that shape, it does\n * not redesign it. `contract` is required on every registered tool, and so is every\n * sub-field: a tool cannot compile without answering all four axes (capabilities,\n * permission, context, evidence), which is what keeps a new tool from silently\n * defaulting into \"unclassified\".\n */\n\nimport type { AgentToolResult } from \"apex-code-agent-core\";\nimport { type Static, type TSchema, Type } from \"typebox\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport type { PermissionPreview } from \"../permissions/responder.ts\";\n\n/** What class of thing a tool does. A set, not a single value — `bash` is `{exec}`. */\nexport type Capability = \"fs.read\" | \"fs.write\" | \"exec\" | \"net\" | \"delegate\" | \"ui\" | \"state\";\n\nexport const ALL_CAPABILITIES: ReadonlySet<Capability> = new Set<Capability>([\n\t\"fs.read\",\n\t\"fs.write\",\n\t\"exec\",\n\t\"net\",\n\t\"delegate\",\n\t\"ui\",\n\t\"state\",\n]);\n\nexport type PermissionBehavior = \"allow\" | \"deny\" | \"ask\";\n\n/**\n * `ruleContent` is interpreted by the tool, never by the rule engine (ADR 0010).\n * That is what lets `Bash(git commit:*)` and `Read(~/.ssh/**)` mean entirely\n * different things while the engine that resolves precedence stays tool-agnostic.\n */\nexport interface PermissionSpec<TParams extends TSchema = TSchema> {\n\t/** Behavior when no rule matches. Read-only tools may default to \"allow\". */\n\tdefaultBehavior: PermissionBehavior;\n\n\t/**\n\t * Per-call behavior when no rule matches, for tools whose calls differ in\n\t * nature (bash: launching a command is \"ask\", retrieving or killing an\n\t * already-approved background command is \"allow\"). Return undefined to fall\n\t * back to `defaultBehavior`. Floors and matching rules still outrank it --\n\t * this only replaces the fallthrough, never a rule or a mode floor.\n\t */\n\tdefaultBehaviorFor?(params: Static<TParams>): PermissionBehavior | undefined;\n\n\t/** Prepare canonical operation facts on the validated call before authorization and execution. */\n\tprepareCall?(params: Static<TParams>): void;\n\n\t/**\n\t * Describe, for a human about to approve it, what this call would change.\n\t *\n\t * Called by the gate only once it has resolved to `ask`, so an allowed or denied\n\t * call never pays for it. It must read through the value `prepareCall` stored\n\t * rather than re-deriving a target, which is what keeps the diff the user\n\t * approves and the bytes execution writes the same file (ADR 0029). It must not\n\t * execute the tool, write, or widen what the gate already validated.\n\t */\n\tpreviewCall?(params: Static<TParams>): PermissionPreview;\n\t/** Does this call match this rule's content as an allow rule? */\n\tmatches(ruleContent: string, params: Static<TParams>): boolean;\n\t/** Optional deny matcher. It may identify any prohibited part of a structured call. */\n\tmatchesDeny?(ruleContent: string, params: Static<TParams>): boolean;\n\t/** True when the call contains grammar that cannot be safely authorized by an allow. */\n\tisUnknown?(params: Static<TParams>): boolean;\n\n\t/** Human-readable rendering of a rule, for prompts and denial messages. */\n\tdescribe(ruleContent: string): string;\n\n\t/**\n\t * The rule that would allow this exact call — what \"always allow this\"\n\t * persists. Return null when the call is not generalizable into a rule.\n\t */\n\truleForCall(params: Static<TParams>): string | null;\n}\n\nexport interface ContextSpec {\n\t/**\n\t * True when the result's information is recoverable — the same content can be\n\t * obtained again by re-running the tool or reading the workspace.\n\t *\n\t * ONLY recoverable results may be evicted (Phase 3). A tool whose result cannot\n\t * be regenerated (a nondeterministic command, a consumed one-shot resource)\n\t * must set this false, or eviction would silently destroy information the\n\t * transcript is the only record of.\n\t */\n\tresultRecoverable: boolean;\n\n\t/** Marker substituted for an evicted result. */\n\tevictionMarker?: string;\n\n\t/** Announce by name only; load the parameter schema on demand. */\n\tdeferSchema: boolean;\n\n\t/** Soft cap on result tokens before truncation. */\n\toutputBudgetTokens?: number;\n}\n\nexport type EvidenceKind = \"diff\" | \"test\" | \"command\" | \"manual\" | \"workflow\" | \"diagnostic\";\n\n/** Source-observed command facts. `exitCode` is absent only when execution never began. */\nexport interface CommandEvidenceRecord {\n\tkind: \"command\";\n\tcommand: string;\n\tcwd?: string;\n\texecutable?: string;\n\targv?: string[];\n\texitCode?: number | null;\n}\n\n/** A file mutation is identified by hashes and paths, never raw file or patch contents. */\nexport interface DiffEvidenceRecord {\n\tkind: \"diff\";\n\tpath: string;\n\tpatchHash?: string;\n\tcontentHash?: string;\n\tbyteCount?: number;\n}\n\n/** Zero-filled diagnostic severity buckets for one bounded language-server outcome. */\nexport interface DiagnosticSeverityCounts {\n\terror: number;\n\twarning: number;\n\tinformation: number;\n\thint: number;\n\tunspecified: number;\n\tother: number;\n}\n\n/** Stable durable classification. Free-form server and process errors never enter evidence. */\nexport type DiagnosticUnavailableKind =\n\t| \"no-server\"\n\t| \"disposed\"\n\t| \"unsupported-sync\"\n\t| \"timed-out\"\n\t| \"aborted\"\n\t| \"superseded\"\n\t| \"server-failed\";\n\n/** Bounded post-mutation diagnostic facts, never diagnostic messages or rendered failure reasons. */\nexport type DiagnosticEvidenceRecord =\n\t| {\n\t\t\tkind: \"diagnostic\";\n\t\t\tpath: string;\n\t\t\tstatus: \"ok\";\n\t\t\tserverId: string;\n\t\t\tdiagnosticCount: number;\n\t\t\tseverityCounts: DiagnosticSeverityCounts;\n\t\t\ttruncated: boolean;\n\t }\n\t| {\n\t\t\tkind: \"diagnostic\";\n\t\t\tpath: string;\n\t\t\tstatus: \"unavailable\";\n\t\t\tserverId?: string;\n\t\t\tunavailableKind: DiagnosticUnavailableKind;\n\t };\n\n/** How a `test` run actually ended. */\nexport type TestProcessOutcome = \"exit\" | \"signal\" | \"timeout\" | \"cancelled\" | \"spawn-failed\";\n\n/** Bounded argv-based test execution facts. Full output never enters evidence; it lives in artifacts. */\nexport interface TestEvidenceRecord {\n\tkind: \"test\";\n\tcwd: string;\n\texecutable: string;\n\targv: string[];\n\texitCode: number | null;\n\t/** How the run ended. Unset means a legacy record; derive from `exitCode` when reading. */\n\toutcome?: TestProcessOutcome;\n\t/** True when the model-facing view omitted part of a stream (full output lives in artifacts). */\n\toutputTruncated?: boolean;\n}\n\n/** Explicit human attestation; policy decides how, or whether, it is sufficient. */\nexport interface ManualEvidenceRecord {\n\tkind: \"manual\";\n\tvalue?: unknown;\n\tobserved?: unknown;\n\tstatus?: string;\n}\n\n/** Source facts from approval and delegation workflows. */\nexport interface WorkflowEvidenceRecord {\n\tkind: \"workflow\";\n\tplan?: string;\n\tapproved?: boolean;\n\tagentType?: string;\n\ttask?: string;\n\thandle?: string;\n}\n\n/** A structured source record. Policy is a separate consumer, not an additional variant. */\nexport type EvidenceRecord =\n\t| CommandEvidenceRecord\n\t| DiffEvidenceRecord\n\t| DiagnosticEvidenceRecord\n\t| TestEvidenceRecord\n\t| ManualEvidenceRecord\n\t| WorkflowEvidenceRecord;\n\n/** Durable destination for source-level tool evidence. Policy is deliberately not part of this boundary. */\nexport interface EvidenceSink {\n\trecord(entry: { toolName: string; records: EvidenceRecord[] }): void;\n\trecordDiagnostic?(diagnostic: EvidenceCaptureDiagnostic): void;\n}\n\n/** A capture failure is observable but never changes an already-completed tool result. */\nexport interface EvidenceCaptureDiagnostic {\n\ttoolName: string;\n\treason: string;\n}\n\nexport interface EvidenceSpec<TParams extends TSchema = TSchema, TDetails = unknown> {\n\t/** Kinds this tool can emit. Empty set is valid and explicit. */\n\temits: ReadonlySet<EvidenceKind>;\n\n\t/**\n\t * Derive evidence from a completed call. Runs inside the tool's own execution\n\t * path, with access to what actually happened, not a reconstruction from\n\t * rendered output.\n\t */\n\tcapture(params: Static<TParams>, result: AgentToolResult<TDetails>): EvidenceRecord[];\n}\n\nexport interface ToolContract<TParams extends TSchema = TSchema, TDetails = unknown> {\n\tcapabilities: ReadonlySet<Capability>;\n\tpermission: PermissionSpec<TParams>;\n\tcontext: ContextSpec;\n\tevidence: EvidenceSpec<TParams, TDetails>;\n}\n\n/**\n * Apex Code extends upstream ToolDefinition with exactly one required field.\n *\n * `TState` defaults to `any`, matching upstream `ToolDefinition` exactly (not\n * `unknown`). That default is load-bearing: TypeScript compares two instantiations\n * of the *same* generic interface (here, both rooted in `ToolDefinition`) using each\n * type parameter's declared variance, without expanding `Static<TParams>`\n * structurally — but only when every type argument lines up, including the ones a\n * caller left defaulted. A mismatched default reintroduces a full structural check,\n * where `Static<any>` does not behave like `any`, and breaks every pre-existing\n * `ToolDefinition<any, X>`-typed consumer across the codebase.\n */\nexport interface ApexToolDefinition<TParams extends TSchema = TSchema, TDetails = unknown, TState = any>\n\textends ToolDefinition<TParams, TDetails, TState> {\n\tcontract: ToolContract<TParams, TDetails>;\n}\n\n/**\n * Conservative contract for a tool registered without one -- third-party extension\n * tools, which cannot supply a `contract`. MCP tools no longer land here: they reach\n * the model through the built-in `mcp` proxy, whose contract is declared in\n * `core/mcp/contract.ts`. Full capability set (so it can\n * never widen a delegation ceiling), `ask` by default, never evicted, schema\n * deferred, emits nothing. Matching is exact-argument only: a foreign tool's rule\n * authorizes exactly the call it was generated from, never a pattern.\n *\n * This must also be reported as unclassified wherever a consumer describes the tool\n * registry (contracts.md invariant 1) — a conservative default nobody can see is\n * indistinguishable from a bug.\n */\nexport const UNCLASSIFIED: ToolContract<TSchema, unknown> = {\n\tcapabilities: ALL_CAPABILITIES,\n\tpermission: {\n\t\tdefaultBehavior: \"ask\",\n\t\tmatches: (ruleContent, params) => ruleContent === JSON.stringify(params),\n\t\tdescribe: (ruleContent) => `Exact call: ${ruleContent}`,\n\t\truleForCall: (params) => JSON.stringify(params),\n\t},\n\tcontext: { resultRecoverable: false, deferSchema: false },\n\tevidence: { emits: new Set(), capture: () => [] },\n};\n\n/** Resolve a complete tool contract for enforcement consumers. */\nexport function resolveToolContract(\n\tlookup: (toolName: string) => ToolContract | undefined,\n\ttoolName: string,\n): ToolContract {\n\treturn lookup(toolName) ?? UNCLASSIFIED;\n}\n\n/** Resolve the context projection using the same canonical foreign-tool fallback. */\nexport function resolveToolContext(\n\tlookup: (toolName: string) => Pick<ToolContract, \"context\"> | undefined,\n\ttoolName: string,\n): Pick<ToolContract, \"context\"> {\n\treturn lookup(toolName) ?? UNCLASSIFIED;\n}\n\n/**\n * A tool whose call shapes differ, declared so a provider can still see its fields.\n *\n * `Type.Union` compiles to `{ anyOf: [...] }`, which carries no top-level\n * `properties`. The Anthropic request builder reads `properties` and `required`\n * directly (`anthropic-messages.js`, `legacyInputSchema`), so a union reached the\n * model as an object with no fields at all. It then guessed, and our own\n * validation rejected the guess.\n *\n * The union still decides what is valid. `properties` is advertisement, listing\n * every field across the variants so a provider that ignores `anyOf` has\n * something to work from. It deliberately carries no `required`, because no field\n * is required by every variant.\n */\nexport function toolUnion<T extends TSchema[]>(variants: [...T], properties: Record<string, TSchema>) {\n\treturn Type.Union(variants, { type: \"object\", properties });\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { type Static, Type } from "typebox";
2
2
  import type { DelegationRuntimeOptions } from "../delegation/runtime.ts";
3
- import type { ApexToolDefinition } from "./contract.ts";
3
+ import { type ApexToolDefinition } from "./contract.ts";
4
4
  declare const delegateSchema: Type.TUnion<[Type.TObject<{
5
5
  agentType: Type.TString;
6
6
  task: Type.TString;
@@ -21,9 +21,11 @@ export interface DelegateDetails {
21
21
  * real child through the injected `DelegationRuntimeOptions` -- capability ceiling,
22
22
  * derived permission store, and child-session construction all live behind that
23
23
  * injection (ADR 0008), matching the `todo_write`/`tool_schema` convention of
24
- * injecting collaborators rather than reaching for global state. Recursion depth
25
- * (task 5.3), artifact isolation (task 5.4), and real agent discovery (task 5.5,
26
- * replacing the resolver a test or caller injects here) are not yet wired.
24
+ * injecting collaborators rather than reaching for global state. Recursion
25
+ * depth, artifact isolation, and real agent discovery are wired:
26
+ * `../delegation/runtime.ts` bounds depth and roots per-child artifact
27
+ * directories, and `../delegation/agents.ts` supplies production markdown
28
+ * discovery through the injected resolver.
27
29
  */
28
30
  export declare function createDelegateToolDefinition(runtime: DelegationRuntimeOptions): ApexToolDefinition<typeof delegateSchema, DelegateDetails>;
29
31
  export declare function createDelegateTool(runtime: DelegationRuntimeOptions): import("apex-code-agent-core").AgentTool<Type.TUnion<[Type.TObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"delegate.d.ts","sourceRoot":"","sources":["../../../src/core/tools/delegate.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEzE,OAAO,KAAK,EAAE,kBAAkB,EAAkB,MAAM,eAAe,CAAC;AAGxE,QAAA,MAAM,cAAc;;;;;;;IAYlB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAgBD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,wBAAwB,GAC/B,kBAAkB,CAAC,OAAO,cAAc,EAAE,eAAe,CAAC,CAiD5D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,wBAAwB;;;;;;;uBAEnE","sourcesContent":["import { Text } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult } from \"apex-code-agent-core\";\nimport { minimatch } from \"minimatch\";\nimport { type Static, Type } from \"typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { DelegationRuntimeOptions } from \"../delegation/runtime.ts\";\nimport { retrieveDelegationResult, runDelegation } from \"../delegation/runtime.ts\";\nimport type { ApexToolDefinition, EvidenceRecord } from \"./contract.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst delegateSchema = Type.Union([\n\tType.Object({\n\t\tagentType: Type.String({ description: \"The type of subagent to delegate to.\" }),\n\t\ttask: Type.String({ description: \"The task to delegate.\" }),\n\t\tbackground: Type.Optional(\n\t\t\tType.Boolean({ description: \"Return a handle immediately instead of waiting for the child.\" }),\n\t\t),\n\t}),\n\tType.Object({\n\t\tagentType: Type.String({ description: \"The agent type that produced the background result.\" }),\n\t\thandle: Type.String({ description: \"A background delegation handle returned by an earlier call.\" }),\n\t}),\n]);\n\nexport type DelegateInput = Static<typeof delegateSchema>;\n\nexport interface DelegateDetails {\n\tagentType: string;\n\ttask: string;\n\toutput: string;\n\thandle?: string;\n}\n\nfunction formatDelegateCall(input: DelegateInput, theme: Theme): string {\n\tif (\"handle\" in input) {\n\t\treturn `${theme.fg(\"toolTitle\", theme.bold(\"delegate\"))} ${theme.fg(\"accent\", input.agentType)} · retrieve`;\n\t}\n\tconst task = input.task.replace(/\\s+/g, \" \").trim();\n\treturn `${theme.fg(\"toolTitle\", theme.bold(\"delegate\"))} ${theme.fg(\"accent\", input.agentType)} · ${theme.fg(\"toolOutput\", task)}`;\n}\n\nfunction formatDelegateResult(details: DelegateDetails, expanded: boolean, theme: Theme): string {\n\tif (expanded) return theme.fg(\"toolOutput\", details.output);\n\tconst lineCount = details.output ? details.output.split(\"\\n\").length : 0;\n\treturn `${theme.fg(\"accent\", details.agentType)} · ${lineCount} ${lineCount === 1 ? \"line\" : \"lines\"}`;\n}\n\n/**\n * The delegation entry point (task 4.6's contract, task 5.2's execution). Runs a\n * real child through the injected `DelegationRuntimeOptions` -- capability ceiling,\n * derived permission store, and child-session construction all live behind that\n * injection (ADR 0008), matching the `todo_write`/`tool_schema` convention of\n * injecting collaborators rather than reaching for global state. Recursion depth\n * (task 5.3), artifact isolation (task 5.4), and real agent discovery (task 5.5,\n * replacing the resolver a test or caller injects here) are not yet wired.\n */\nexport function createDelegateToolDefinition(\n\truntime: DelegationRuntimeOptions,\n): ApexToolDefinition<typeof delegateSchema, DelegateDetails> {\n\treturn {\n\t\tname: \"delegate\",\n\t\tlabel: \"delegate\",\n\t\tdescription: \"Delegate a task to a subagent.\",\n\t\tparameters: delegateSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"delegate\"]),\n\t\t\tpermission: {\n\t\t\t\tdefaultBehavior: \"ask\",\n\t\t\t\tmatches: (ruleContent, params) => minimatch(params.agentType, ruleContent),\n\t\t\t\tdescribe: (ruleContent) => `Delegate to agent types matching \"${ruleContent}\"`,\n\t\t\t\truleForCall: (params) => params.agentType,\n\t\t\t},\n\t\t\tcontext: { resultRecoverable: false, deferSchema: true },\n\t\t\tevidence: {\n\t\t\t\temits: new Set([\"workflow\"]),\n\t\t\t\tcapture: (params): EvidenceRecord[] =>\n\t\t\t\t\t\"task\" in params\n\t\t\t\t\t\t? [{ kind: \"workflow\", agentType: params.agentType, task: params.task }]\n\t\t\t\t\t\t: [{ kind: \"workflow\", agentType: params.agentType, handle: params.handle }],\n\t\t\t},\n\t\t},\n\t\tasync execute(_toolCallId, input: DelegateInput): Promise<AgentToolResult<DelegateDetails>> {\n\t\t\tconst result =\n\t\t\t\t\"task\" in input\n\t\t\t\t\t? await runDelegation(runtime, input.agentType, input.task, { background: input.background })\n\t\t\t\t\t: await retrieveDelegationResult(runtime, input.handle, input.agentType);\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: result.output }],\n\t\t\t\tdetails: {\n\t\t\t\t\tagentType: result.agentType,\n\t\t\t\t\ttask: result.task,\n\t\t\t\t\toutput: result.output,\n\t\t\t\t\thandle: result.handleId,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\trenderCall(input, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDelegateCall(input, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDelegateResult(result.details, options.expanded, theme));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDelegateTool(runtime: DelegationRuntimeOptions) {\n\treturn wrapToolDefinition(createDelegateToolDefinition(runtime));\n}\n"]}
1
+ {"version":3,"file":"delegate.d.ts","sourceRoot":"","sources":["../../../src/core/tools/delegate.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEzE,OAAO,EAAE,KAAK,kBAAkB,EAAkC,MAAM,eAAe,CAAC;AAgBxF,QAAA,MAAM,cAAc;;;;;;;IAUnB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAgBD;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,wBAAwB,GAC/B,kBAAkB,CAAC,OAAO,cAAc,EAAE,eAAe,CAAC,CAiD5D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,wBAAwB;;;;;;;uBAEnE","sourcesContent":["import { Text } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult } from \"apex-code-agent-core\";\nimport { minimatch } from \"minimatch\";\nimport { type Static, Type } from \"typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { DelegationRuntimeOptions } from \"../delegation/runtime.ts\";\nimport { retrieveDelegationResult, runDelegation } from \"../delegation/runtime.ts\";\nimport { type ApexToolDefinition, type EvidenceRecord, toolUnion } from \"./contract.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst delegateSchemaProperties = {\n\tagentType: Type.String({\n\t\tdescription: \"The subagent type. Required both to launch a task and to retrieve a background result.\",\n\t}),\n\ttask: Type.String({ description: \"The task to delegate. Supply it to launch a delegation.\" }),\n\tbackground: Type.Optional(\n\t\tType.Boolean({ description: \"Return a handle immediately instead of waiting for the child.\" }),\n\t),\n\thandle: Type.String({\n\t\tdescription: \"A background delegation handle returned by an earlier call. Supply it to retrieve the result.\",\n\t}),\n};\n\nconst delegateSchema = toolUnion(\n\t[\n\t\tType.Object({\n\t\t\tagentType: Type.String(),\n\t\t\ttask: Type.String(),\n\t\t\tbackground: Type.Optional(Type.Boolean()),\n\t\t}),\n\t\tType.Object({ agentType: Type.String(), handle: Type.String() }),\n\t],\n\tdelegateSchemaProperties,\n);\n\nexport type DelegateInput = Static<typeof delegateSchema>;\n\nexport interface DelegateDetails {\n\tagentType: string;\n\ttask: string;\n\toutput: string;\n\thandle?: string;\n}\n\nfunction formatDelegateCall(input: DelegateInput, theme: Theme): string {\n\tif (\"handle\" in input) {\n\t\treturn `${theme.fg(\"toolTitle\", theme.bold(\"delegate\"))} ${theme.fg(\"accent\", input.agentType)} · retrieve`;\n\t}\n\tconst task = input.task.replace(/\\s+/g, \" \").trim();\n\treturn `${theme.fg(\"toolTitle\", theme.bold(\"delegate\"))} ${theme.fg(\"accent\", input.agentType)} · ${theme.fg(\"toolOutput\", task)}`;\n}\n\nfunction formatDelegateResult(details: DelegateDetails, expanded: boolean, theme: Theme): string {\n\tif (expanded) return theme.fg(\"toolOutput\", details.output);\n\tconst lineCount = details.output ? details.output.split(\"\\n\").length : 0;\n\treturn `${theme.fg(\"accent\", details.agentType)} · ${lineCount} ${lineCount === 1 ? \"line\" : \"lines\"}`;\n}\n\n/**\n * The delegation entry point (task 4.6's contract, task 5.2's execution). Runs a\n * real child through the injected `DelegationRuntimeOptions` -- capability ceiling,\n * derived permission store, and child-session construction all live behind that\n * injection (ADR 0008), matching the `todo_write`/`tool_schema` convention of\n * injecting collaborators rather than reaching for global state. Recursion\n * depth, artifact isolation, and real agent discovery are wired:\n * `../delegation/runtime.ts` bounds depth and roots per-child artifact\n * directories, and `../delegation/agents.ts` supplies production markdown\n * discovery through the injected resolver.\n */\nexport function createDelegateToolDefinition(\n\truntime: DelegationRuntimeOptions,\n): ApexToolDefinition<typeof delegateSchema, DelegateDetails> {\n\treturn {\n\t\tname: \"delegate\",\n\t\tlabel: \"delegate\",\n\t\tdescription: \"Delegate a task to a subagent.\",\n\t\tparameters: delegateSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"delegate\"]),\n\t\t\tpermission: {\n\t\t\t\tdefaultBehavior: \"ask\",\n\t\t\t\tmatches: (ruleContent, params) => minimatch(params.agentType, ruleContent),\n\t\t\t\tdescribe: (ruleContent) => `Delegate to agent types matching \"${ruleContent}\"`,\n\t\t\t\truleForCall: (params) => params.agentType,\n\t\t\t},\n\t\t\tcontext: { resultRecoverable: false, deferSchema: true },\n\t\t\tevidence: {\n\t\t\t\temits: new Set([\"workflow\"]),\n\t\t\t\tcapture: (params): EvidenceRecord[] =>\n\t\t\t\t\t\"task\" in params\n\t\t\t\t\t\t? [{ kind: \"workflow\", agentType: params.agentType, task: params.task }]\n\t\t\t\t\t\t: [{ kind: \"workflow\", agentType: params.agentType, handle: params.handle }],\n\t\t\t},\n\t\t},\n\t\tasync execute(_toolCallId, input: DelegateInput): Promise<AgentToolResult<DelegateDetails>> {\n\t\t\tconst result =\n\t\t\t\t\"task\" in input\n\t\t\t\t\t? await runDelegation(runtime, input.agentType, input.task, { background: input.background })\n\t\t\t\t\t: await retrieveDelegationResult(runtime, input.handle, input.agentType);\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: result.output }],\n\t\t\t\tdetails: {\n\t\t\t\t\tagentType: result.agentType,\n\t\t\t\t\ttask: result.task,\n\t\t\t\t\toutput: result.output,\n\t\t\t\t\thandle: result.handleId,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\trenderCall(input, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDelegateCall(input, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDelegateResult(result.details, options.expanded, theme));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDelegateTool(runtime: DelegationRuntimeOptions) {\n\treturn wrapToolDefinition(createDelegateToolDefinition(runtime));\n}\n"]}
@@ -2,18 +2,26 @@ import { Text } from "@earendil-works/pi-tui";
2
2
  import { minimatch } from "minimatch";
3
3
  import { Type } from "typebox";
4
4
  import { retrieveDelegationResult, runDelegation } from "../delegation/runtime.js";
5
+ import { toolUnion } from "./contract.js";
5
6
  import { wrapToolDefinition } from "./tool-definition-wrapper.js";
6
- const delegateSchema = Type.Union([
7
- Type.Object({
8
- agentType: Type.String({ description: "The type of subagent to delegate to." }),
9
- task: Type.String({ description: "The task to delegate." }),
10
- background: Type.Optional(Type.Boolean({ description: "Return a handle immediately instead of waiting for the child." })),
7
+ const delegateSchemaProperties = {
8
+ agentType: Type.String({
9
+ description: "The subagent type. Required both to launch a task and to retrieve a background result.",
10
+ }),
11
+ task: Type.String({ description: "The task to delegate. Supply it to launch a delegation." }),
12
+ background: Type.Optional(Type.Boolean({ description: "Return a handle immediately instead of waiting for the child." })),
13
+ handle: Type.String({
14
+ description: "A background delegation handle returned by an earlier call. Supply it to retrieve the result.",
11
15
  }),
16
+ };
17
+ const delegateSchema = toolUnion([
12
18
  Type.Object({
13
- agentType: Type.String({ description: "The agent type that produced the background result." }),
14
- handle: Type.String({ description: "A background delegation handle returned by an earlier call." }),
19
+ agentType: Type.String(),
20
+ task: Type.String(),
21
+ background: Type.Optional(Type.Boolean()),
15
22
  }),
16
- ]);
23
+ Type.Object({ agentType: Type.String(), handle: Type.String() }),
24
+ ], delegateSchemaProperties);
17
25
  function formatDelegateCall(input, theme) {
18
26
  if ("handle" in input) {
19
27
  return `${theme.fg("toolTitle", theme.bold("delegate"))} ${theme.fg("accent", input.agentType)} · retrieve`;
@@ -32,9 +40,11 @@ function formatDelegateResult(details, expanded, theme) {
32
40
  * real child through the injected `DelegationRuntimeOptions` -- capability ceiling,
33
41
  * derived permission store, and child-session construction all live behind that
34
42
  * injection (ADR 0008), matching the `todo_write`/`tool_schema` convention of
35
- * injecting collaborators rather than reaching for global state. Recursion depth
36
- * (task 5.3), artifact isolation (task 5.4), and real agent discovery (task 5.5,
37
- * replacing the resolver a test or caller injects here) are not yet wired.
43
+ * injecting collaborators rather than reaching for global state. Recursion
44
+ * depth, artifact isolation, and real agent discovery are wired:
45
+ * `../delegation/runtime.ts` bounds depth and roots per-child artifact
46
+ * directories, and `../delegation/agents.ts` supplies production markdown
47
+ * discovery through the injected resolver.
38
48
  */
39
49
  export function createDelegateToolDefinition(runtime) {
40
50
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"delegate.js","sourceRoot":"","sources":["../../../src/core/tools/delegate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAE9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC;IACjC,IAAI,CAAC,MAAM,CAAC;QACX,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,sCAAsC,EAAE,CAAC;QAC/E,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,uBAAuB,EAAE,CAAC;QAC3D,UAAU,EAAE,IAAI,CAAC,QAAQ,CACxB,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,+DAA+D,EAAE,CAAC,CAC9F;KACD,CAAC;IACF,IAAI,CAAC,MAAM,CAAC;QACX,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,qDAAqD,EAAE,CAAC;QAC9F,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,6DAA6D,EAAE,CAAC;KACnG,CAAC;CACF,CAAC,CAAC;AAWH,SAAS,kBAAkB,CAAC,KAAoB,EAAE,KAAY,EAAU;IACvE,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;QACvB,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,cAAa,CAAC;IAC7G,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,OAAM,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC;AAAA,CACnI;AAED,SAAS,oBAAoB,CAAC,OAAwB,EAAE,QAAiB,EAAE,KAAY,EAAU;IAChG,IAAI,QAAQ;QAAE,OAAO,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,OAAM,SAAS,IAAI,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;AAAA,CACvG;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,4BAA4B,CAC3C,OAAiC,EAC4B;IAC7D,OAAO;QACN,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,gCAAgC;QAC7C,UAAU,EAAE,cAAc;QAC1B,QAAQ,EAAE;YACT,YAAY,EAAE,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;YACnC,UAAU,EAAE;gBACX,eAAe,EAAE,KAAK;gBACtB,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC;gBAC1E,QAAQ,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,qCAAqC,WAAW,GAAG;gBAC9E,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS;aACzC;YACD,OAAO,EAAE,EAAE,iBAAiB,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE;YACxD,QAAQ,EAAE;gBACT,KAAK,EAAE,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;gBAC5B,OAAO,EAAE,CAAC,MAAM,EAAoB,EAAE,CACrC,MAAM,IAAI,MAAM;oBACf,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;oBACxE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;aAC9E;SACD;QACD,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAoB,EAA6C;YAC3F,MAAM,MAAM,GACX,MAAM,IAAI,KAAK;gBACd,CAAC,CAAC,MAAM,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC;gBAC7F,CAAC,CAAC,MAAM,wBAAwB,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;YAC3E,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;gBAChD,OAAO,EAAE;oBACR,SAAS,EAAE,MAAM,CAAC,SAAS;oBAC3B,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,MAAM,EAAE,MAAM,CAAC,QAAQ;iBACvB;aACD,CAAC;QAAA,CACF;QACD,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE;YACjC,MAAM,IAAI,GAAI,OAAO,CAAC,aAAkC,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/E,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC;QAAA,CACZ;QACD,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;YAC7C,MAAM,IAAI,GAAI,OAAO,CAAC,aAAkC,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/E,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;YAC5E,OAAO,IAAI,CAAC;QAAA,CACZ;KACD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAiC,EAAE;IACrE,OAAO,kBAAkB,CAAC,4BAA4B,CAAC,OAAO,CAAC,CAAC,CAAC;AAAA,CACjE","sourcesContent":["import { Text } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult } from \"apex-code-agent-core\";\nimport { minimatch } from \"minimatch\";\nimport { type Static, Type } from \"typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { DelegationRuntimeOptions } from \"../delegation/runtime.ts\";\nimport { retrieveDelegationResult, runDelegation } from \"../delegation/runtime.ts\";\nimport type { ApexToolDefinition, EvidenceRecord } from \"./contract.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst delegateSchema = Type.Union([\n\tType.Object({\n\t\tagentType: Type.String({ description: \"The type of subagent to delegate to.\" }),\n\t\ttask: Type.String({ description: \"The task to delegate.\" }),\n\t\tbackground: Type.Optional(\n\t\t\tType.Boolean({ description: \"Return a handle immediately instead of waiting for the child.\" }),\n\t\t),\n\t}),\n\tType.Object({\n\t\tagentType: Type.String({ description: \"The agent type that produced the background result.\" }),\n\t\thandle: Type.String({ description: \"A background delegation handle returned by an earlier call.\" }),\n\t}),\n]);\n\nexport type DelegateInput = Static<typeof delegateSchema>;\n\nexport interface DelegateDetails {\n\tagentType: string;\n\ttask: string;\n\toutput: string;\n\thandle?: string;\n}\n\nfunction formatDelegateCall(input: DelegateInput, theme: Theme): string {\n\tif (\"handle\" in input) {\n\t\treturn `${theme.fg(\"toolTitle\", theme.bold(\"delegate\"))} ${theme.fg(\"accent\", input.agentType)} · retrieve`;\n\t}\n\tconst task = input.task.replace(/\\s+/g, \" \").trim();\n\treturn `${theme.fg(\"toolTitle\", theme.bold(\"delegate\"))} ${theme.fg(\"accent\", input.agentType)} · ${theme.fg(\"toolOutput\", task)}`;\n}\n\nfunction formatDelegateResult(details: DelegateDetails, expanded: boolean, theme: Theme): string {\n\tif (expanded) return theme.fg(\"toolOutput\", details.output);\n\tconst lineCount = details.output ? details.output.split(\"\\n\").length : 0;\n\treturn `${theme.fg(\"accent\", details.agentType)} · ${lineCount} ${lineCount === 1 ? \"line\" : \"lines\"}`;\n}\n\n/**\n * The delegation entry point (task 4.6's contract, task 5.2's execution). Runs a\n * real child through the injected `DelegationRuntimeOptions` -- capability ceiling,\n * derived permission store, and child-session construction all live behind that\n * injection (ADR 0008), matching the `todo_write`/`tool_schema` convention of\n * injecting collaborators rather than reaching for global state. Recursion depth\n * (task 5.3), artifact isolation (task 5.4), and real agent discovery (task 5.5,\n * replacing the resolver a test or caller injects here) are not yet wired.\n */\nexport function createDelegateToolDefinition(\n\truntime: DelegationRuntimeOptions,\n): ApexToolDefinition<typeof delegateSchema, DelegateDetails> {\n\treturn {\n\t\tname: \"delegate\",\n\t\tlabel: \"delegate\",\n\t\tdescription: \"Delegate a task to a subagent.\",\n\t\tparameters: delegateSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"delegate\"]),\n\t\t\tpermission: {\n\t\t\t\tdefaultBehavior: \"ask\",\n\t\t\t\tmatches: (ruleContent, params) => minimatch(params.agentType, ruleContent),\n\t\t\t\tdescribe: (ruleContent) => `Delegate to agent types matching \"${ruleContent}\"`,\n\t\t\t\truleForCall: (params) => params.agentType,\n\t\t\t},\n\t\t\tcontext: { resultRecoverable: false, deferSchema: true },\n\t\t\tevidence: {\n\t\t\t\temits: new Set([\"workflow\"]),\n\t\t\t\tcapture: (params): EvidenceRecord[] =>\n\t\t\t\t\t\"task\" in params\n\t\t\t\t\t\t? [{ kind: \"workflow\", agentType: params.agentType, task: params.task }]\n\t\t\t\t\t\t: [{ kind: \"workflow\", agentType: params.agentType, handle: params.handle }],\n\t\t\t},\n\t\t},\n\t\tasync execute(_toolCallId, input: DelegateInput): Promise<AgentToolResult<DelegateDetails>> {\n\t\t\tconst result =\n\t\t\t\t\"task\" in input\n\t\t\t\t\t? await runDelegation(runtime, input.agentType, input.task, { background: input.background })\n\t\t\t\t\t: await retrieveDelegationResult(runtime, input.handle, input.agentType);\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: result.output }],\n\t\t\t\tdetails: {\n\t\t\t\t\tagentType: result.agentType,\n\t\t\t\t\ttask: result.task,\n\t\t\t\t\toutput: result.output,\n\t\t\t\t\thandle: result.handleId,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\trenderCall(input, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDelegateCall(input, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDelegateResult(result.details, options.expanded, theme));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDelegateTool(runtime: DelegationRuntimeOptions) {\n\treturn wrapToolDefinition(createDelegateToolDefinition(runtime));\n}\n"]}
1
+ {"version":3,"file":"delegate.js","sourceRoot":"","sources":["../../../src/core/tools/delegate.ts"],"names":[],"mappings":"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","sourcesContent":["import { Text } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult } from \"apex-code-agent-core\";\nimport { minimatch } from \"minimatch\";\nimport { type Static, Type } from \"typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { DelegationRuntimeOptions } from \"../delegation/runtime.ts\";\nimport { retrieveDelegationResult, runDelegation } from \"../delegation/runtime.ts\";\nimport { type ApexToolDefinition, type EvidenceRecord, toolUnion } from \"./contract.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst delegateSchemaProperties = {\n\tagentType: Type.String({\n\t\tdescription: \"The subagent type. Required both to launch a task and to retrieve a background result.\",\n\t}),\n\ttask: Type.String({ description: \"The task to delegate. Supply it to launch a delegation.\" }),\n\tbackground: Type.Optional(\n\t\tType.Boolean({ description: \"Return a handle immediately instead of waiting for the child.\" }),\n\t),\n\thandle: Type.String({\n\t\tdescription: \"A background delegation handle returned by an earlier call. Supply it to retrieve the result.\",\n\t}),\n};\n\nconst delegateSchema = toolUnion(\n\t[\n\t\tType.Object({\n\t\t\tagentType: Type.String(),\n\t\t\ttask: Type.String(),\n\t\t\tbackground: Type.Optional(Type.Boolean()),\n\t\t}),\n\t\tType.Object({ agentType: Type.String(), handle: Type.String() }),\n\t],\n\tdelegateSchemaProperties,\n);\n\nexport type DelegateInput = Static<typeof delegateSchema>;\n\nexport interface DelegateDetails {\n\tagentType: string;\n\ttask: string;\n\toutput: string;\n\thandle?: string;\n}\n\nfunction formatDelegateCall(input: DelegateInput, theme: Theme): string {\n\tif (\"handle\" in input) {\n\t\treturn `${theme.fg(\"toolTitle\", theme.bold(\"delegate\"))} ${theme.fg(\"accent\", input.agentType)} · retrieve`;\n\t}\n\tconst task = input.task.replace(/\\s+/g, \" \").trim();\n\treturn `${theme.fg(\"toolTitle\", theme.bold(\"delegate\"))} ${theme.fg(\"accent\", input.agentType)} · ${theme.fg(\"toolOutput\", task)}`;\n}\n\nfunction formatDelegateResult(details: DelegateDetails, expanded: boolean, theme: Theme): string {\n\tif (expanded) return theme.fg(\"toolOutput\", details.output);\n\tconst lineCount = details.output ? details.output.split(\"\\n\").length : 0;\n\treturn `${theme.fg(\"accent\", details.agentType)} · ${lineCount} ${lineCount === 1 ? \"line\" : \"lines\"}`;\n}\n\n/**\n * The delegation entry point (task 4.6's contract, task 5.2's execution). Runs a\n * real child through the injected `DelegationRuntimeOptions` -- capability ceiling,\n * derived permission store, and child-session construction all live behind that\n * injection (ADR 0008), matching the `todo_write`/`tool_schema` convention of\n * injecting collaborators rather than reaching for global state. Recursion\n * depth, artifact isolation, and real agent discovery are wired:\n * `../delegation/runtime.ts` bounds depth and roots per-child artifact\n * directories, and `../delegation/agents.ts` supplies production markdown\n * discovery through the injected resolver.\n */\nexport function createDelegateToolDefinition(\n\truntime: DelegationRuntimeOptions,\n): ApexToolDefinition<typeof delegateSchema, DelegateDetails> {\n\treturn {\n\t\tname: \"delegate\",\n\t\tlabel: \"delegate\",\n\t\tdescription: \"Delegate a task to a subagent.\",\n\t\tparameters: delegateSchema,\n\t\tcontract: {\n\t\t\tcapabilities: new Set([\"delegate\"]),\n\t\t\tpermission: {\n\t\t\t\tdefaultBehavior: \"ask\",\n\t\t\t\tmatches: (ruleContent, params) => minimatch(params.agentType, ruleContent),\n\t\t\t\tdescribe: (ruleContent) => `Delegate to agent types matching \"${ruleContent}\"`,\n\t\t\t\truleForCall: (params) => params.agentType,\n\t\t\t},\n\t\t\tcontext: { resultRecoverable: false, deferSchema: true },\n\t\t\tevidence: {\n\t\t\t\temits: new Set([\"workflow\"]),\n\t\t\t\tcapture: (params): EvidenceRecord[] =>\n\t\t\t\t\t\"task\" in params\n\t\t\t\t\t\t? [{ kind: \"workflow\", agentType: params.agentType, task: params.task }]\n\t\t\t\t\t\t: [{ kind: \"workflow\", agentType: params.agentType, handle: params.handle }],\n\t\t\t},\n\t\t},\n\t\tasync execute(_toolCallId, input: DelegateInput): Promise<AgentToolResult<DelegateDetails>> {\n\t\t\tconst result =\n\t\t\t\t\"task\" in input\n\t\t\t\t\t? await runDelegation(runtime, input.agentType, input.task, { background: input.background })\n\t\t\t\t\t: await retrieveDelegationResult(runtime, input.handle, input.agentType);\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: result.output }],\n\t\t\t\tdetails: {\n\t\t\t\t\tagentType: result.agentType,\n\t\t\t\t\ttask: result.task,\n\t\t\t\t\toutput: result.output,\n\t\t\t\t\thandle: result.handleId,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\trenderCall(input, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDelegateCall(input, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDelegateResult(result.details, options.expanded, theme));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDelegateTool(runtime: DelegationRuntimeOptions) {\n\treturn wrapToolDefinition(createDelegateToolDefinition(runtime));\n}\n"]}