@caupulican/pi-adaptative 0.80.85 → 0.80.88

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 (340) hide show
  1. package/CHANGELOG.md +160 -1
  2. package/dist/core/agent-session.d.ts +394 -1
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +1862 -46
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/autonomy/approval-gate.d.ts +4 -0
  7. package/dist/core/autonomy/approval-gate.d.ts.map +1 -0
  8. package/dist/core/autonomy/approval-gate.js +27 -0
  9. package/dist/core/autonomy/approval-gate.js.map +1 -0
  10. package/dist/core/autonomy/bounded-completion.d.ts +27 -0
  11. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -0
  12. package/dist/core/autonomy/bounded-completion.js +44 -0
  13. package/dist/core/autonomy/bounded-completion.js.map +1 -0
  14. package/dist/core/autonomy/contracts.d.ts +129 -0
  15. package/dist/core/autonomy/contracts.d.ts.map +1 -0
  16. package/dist/core/autonomy/contracts.js +2 -0
  17. package/dist/core/autonomy/contracts.js.map +1 -0
  18. package/dist/core/autonomy/gates.d.ts +15 -0
  19. package/dist/core/autonomy/gates.d.ts.map +1 -0
  20. package/dist/core/autonomy/gates.js +205 -0
  21. package/dist/core/autonomy/gates.js.map +1 -0
  22. package/dist/core/autonomy/lane-tracker.d.ts +48 -0
  23. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -0
  24. package/dist/core/autonomy/lane-tracker.js +125 -0
  25. package/dist/core/autonomy/lane-tracker.js.map +1 -0
  26. package/dist/core/autonomy/path-scope.d.ts +9 -0
  27. package/dist/core/autonomy/path-scope.d.ts.map +1 -0
  28. package/dist/core/autonomy/path-scope.js +122 -0
  29. package/dist/core/autonomy/path-scope.js.map +1 -0
  30. package/dist/core/autonomy/risk-assessment.d.ts +3 -0
  31. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -0
  32. package/dist/core/autonomy/risk-assessment.js +122 -0
  33. package/dist/core/autonomy/risk-assessment.js.map +1 -0
  34. package/dist/core/autonomy/session-lane-record.d.ts +10 -0
  35. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -0
  36. package/dist/core/autonomy/session-lane-record.js +36 -0
  37. package/dist/core/autonomy/session-lane-record.js.map +1 -0
  38. package/dist/core/autonomy/status.d.ts +40 -0
  39. package/dist/core/autonomy/status.d.ts.map +1 -0
  40. package/dist/core/autonomy/status.js +107 -0
  41. package/dist/core/autonomy/status.js.map +1 -0
  42. package/dist/core/autonomy/subagent-prompt.d.ts +21 -0
  43. package/dist/core/autonomy/subagent-prompt.d.ts.map +1 -0
  44. package/dist/core/autonomy/subagent-prompt.js +28 -0
  45. package/dist/core/autonomy/subagent-prompt.js.map +1 -0
  46. package/dist/core/autonomy/telemetry-events.d.ts +18 -0
  47. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -0
  48. package/dist/core/autonomy/telemetry-events.js +60 -0
  49. package/dist/core/autonomy/telemetry-events.js.map +1 -0
  50. package/dist/core/context/artifact-retrieval.d.ts +49 -0
  51. package/dist/core/context/artifact-retrieval.d.ts.map +1 -0
  52. package/dist/core/context/artifact-retrieval.js +49 -0
  53. package/dist/core/context/artifact-retrieval.js.map +1 -0
  54. package/dist/core/context/context-artifacts.d.ts +94 -0
  55. package/dist/core/context/context-artifacts.d.ts.map +1 -0
  56. package/dist/core/context/context-artifacts.js +307 -0
  57. package/dist/core/context/context-artifacts.js.map +1 -0
  58. package/dist/core/context/context-audit.d.ts +66 -0
  59. package/dist/core/context/context-audit.d.ts.map +1 -0
  60. package/dist/core/context/context-audit.js +173 -0
  61. package/dist/core/context/context-audit.js.map +1 -0
  62. package/dist/core/context/context-item.d.ts +117 -0
  63. package/dist/core/context/context-item.d.ts.map +1 -0
  64. package/dist/core/context/context-item.js +36 -0
  65. package/dist/core/context/context-item.js.map +1 -0
  66. package/dist/core/context/context-prompt-enforcement.d.ts +73 -0
  67. package/dist/core/context/context-prompt-enforcement.d.ts.map +1 -0
  68. package/dist/core/context/context-prompt-enforcement.js +153 -0
  69. package/dist/core/context/context-prompt-enforcement.js.map +1 -0
  70. package/dist/core/context/context-prompt-policy.d.ts +90 -0
  71. package/dist/core/context/context-prompt-policy.d.ts.map +1 -0
  72. package/dist/core/context/context-prompt-policy.js +73 -0
  73. package/dist/core/context/context-prompt-policy.js.map +1 -0
  74. package/dist/core/context/context-retention.d.ts +36 -0
  75. package/dist/core/context/context-retention.d.ts.map +1 -0
  76. package/dist/core/context/context-retention.js +108 -0
  77. package/dist/core/context/context-retention.js.map +1 -0
  78. package/dist/core/context/context-store.d.ts +37 -0
  79. package/dist/core/context/context-store.d.ts.map +1 -0
  80. package/dist/core/context/context-store.js +45 -0
  81. package/dist/core/context/context-store.js.map +1 -0
  82. package/dist/core/context/memory-diagnostics.d.ts +50 -0
  83. package/dist/core/context/memory-diagnostics.d.ts.map +1 -0
  84. package/dist/core/context/memory-diagnostics.js +43 -0
  85. package/dist/core/context/memory-diagnostics.js.map +1 -0
  86. package/dist/core/context/memory-index-store.d.ts +28 -0
  87. package/dist/core/context/memory-index-store.d.ts.map +1 -0
  88. package/dist/core/context/memory-index-store.js +38 -0
  89. package/dist/core/context/memory-index-store.js.map +1 -0
  90. package/dist/core/context/memory-prompt-block.d.ts +34 -0
  91. package/dist/core/context/memory-prompt-block.d.ts.map +1 -0
  92. package/dist/core/context/memory-prompt-block.js +58 -0
  93. package/dist/core/context/memory-prompt-block.js.map +1 -0
  94. package/dist/core/context/memory-provider-contract.d.ts +114 -0
  95. package/dist/core/context/memory-provider-contract.d.ts.map +1 -0
  96. package/dist/core/context/memory-provider-contract.js +121 -0
  97. package/dist/core/context/memory-provider-contract.js.map +1 -0
  98. package/dist/core/context/memory-retrieval.d.ts +27 -0
  99. package/dist/core/context/memory-retrieval.d.ts.map +1 -0
  100. package/dist/core/context/memory-retrieval.js +91 -0
  101. package/dist/core/context/memory-retrieval.js.map +1 -0
  102. package/dist/core/context/okf-memory-provider.d.ts +26 -0
  103. package/dist/core/context/okf-memory-provider.d.ts.map +1 -0
  104. package/dist/core/context/okf-memory-provider.js +154 -0
  105. package/dist/core/context/okf-memory-provider.js.map +1 -0
  106. package/dist/core/context/okf-memory.d.ts +42 -0
  107. package/dist/core/context/okf-memory.d.ts.map +1 -0
  108. package/dist/core/context/okf-memory.js +175 -0
  109. package/dist/core/context/okf-memory.js.map +1 -0
  110. package/dist/core/context/policy-engine.d.ts +66 -0
  111. package/dist/core/context/policy-engine.d.ts.map +1 -0
  112. package/dist/core/context/policy-engine.js +171 -0
  113. package/dist/core/context/policy-engine.js.map +1 -0
  114. package/dist/core/context/policy-types.d.ts +102 -0
  115. package/dist/core/context/policy-types.d.ts.map +1 -0
  116. package/dist/core/context/policy-types.js +7 -0
  117. package/dist/core/context/policy-types.js.map +1 -0
  118. package/dist/core/context/sqlite-runtime-index.d.ts +19 -0
  119. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -0
  120. package/dist/core/context/sqlite-runtime-index.js +344 -0
  121. package/dist/core/context/sqlite-runtime-index.js.map +1 -0
  122. package/dist/core/context/storage-authority.d.ts +20 -0
  123. package/dist/core/context/storage-authority.d.ts.map +1 -0
  124. package/dist/core/context/storage-authority.js +51 -0
  125. package/dist/core/context/storage-authority.js.map +1 -0
  126. package/dist/core/context/tool-output-packer.d.ts +75 -0
  127. package/dist/core/context/tool-output-packer.d.ts.map +1 -0
  128. package/dist/core/context/tool-output-packer.js +77 -0
  129. package/dist/core/context/tool-output-packer.js.map +1 -0
  130. package/dist/core/cost/session-usage.d.ts +20 -0
  131. package/dist/core/cost/session-usage.d.ts.map +1 -0
  132. package/dist/core/cost/session-usage.js +164 -0
  133. package/dist/core/cost/session-usage.js.map +1 -0
  134. package/dist/core/delegation/session-worker-result.d.ts +10 -0
  135. package/dist/core/delegation/session-worker-result.d.ts.map +1 -0
  136. package/dist/core/delegation/session-worker-result.js +36 -0
  137. package/dist/core/delegation/session-worker-result.js.map +1 -0
  138. package/dist/core/delegation/worker-result.d.ts +9 -0
  139. package/dist/core/delegation/worker-result.d.ts.map +1 -0
  140. package/dist/core/delegation/worker-result.js +152 -0
  141. package/dist/core/delegation/worker-result.js.map +1 -0
  142. package/dist/core/delegation/worker-runner.d.ts +58 -0
  143. package/dist/core/delegation/worker-runner.d.ts.map +1 -0
  144. package/dist/core/delegation/worker-runner.js +188 -0
  145. package/dist/core/delegation/worker-runner.js.map +1 -0
  146. package/dist/core/extensions/builtin.d.ts +5 -1
  147. package/dist/core/extensions/builtin.d.ts.map +1 -1
  148. package/dist/core/extensions/builtin.js +23 -1
  149. package/dist/core/extensions/builtin.js.map +1 -1
  150. package/dist/core/footer-data-provider.d.ts +5 -1
  151. package/dist/core/footer-data-provider.d.ts.map +1 -1
  152. package/dist/core/footer-data-provider.js +13 -0
  153. package/dist/core/footer-data-provider.js.map +1 -1
  154. package/dist/core/goals/goal-continuation-controller.d.ts +22 -0
  155. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -0
  156. package/dist/core/goals/goal-continuation-controller.js +88 -0
  157. package/dist/core/goals/goal-continuation-controller.js.map +1 -0
  158. package/dist/core/goals/goal-continuation-defaults.d.ts +10 -0
  159. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -0
  160. package/dist/core/goals/goal-continuation-defaults.js +10 -0
  161. package/dist/core/goals/goal-continuation-defaults.js.map +1 -0
  162. package/dist/core/goals/goal-continuation-prompt.d.ts +18 -0
  163. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -0
  164. package/dist/core/goals/goal-continuation-prompt.js +141 -0
  165. package/dist/core/goals/goal-continuation-prompt.js.map +1 -0
  166. package/dist/core/goals/goal-runtime-snapshot.d.ts +19 -0
  167. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -0
  168. package/dist/core/goals/goal-runtime-snapshot.js +23 -0
  169. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -0
  170. package/dist/core/goals/goal-state.d.ts +87 -0
  171. package/dist/core/goals/goal-state.d.ts.map +1 -0
  172. package/dist/core/goals/goal-state.js +259 -0
  173. package/dist/core/goals/goal-state.js.map +1 -0
  174. package/dist/core/goals/goal-tool-core.d.ts +66 -0
  175. package/dist/core/goals/goal-tool-core.d.ts.map +1 -0
  176. package/dist/core/goals/goal-tool-core.js +146 -0
  177. package/dist/core/goals/goal-tool-core.js.map +1 -0
  178. package/dist/core/goals/session-goal-state.d.ts +10 -0
  179. package/dist/core/goals/session-goal-state.d.ts.map +1 -0
  180. package/dist/core/goals/session-goal-state.js +35 -0
  181. package/dist/core/goals/session-goal-state.js.map +1 -0
  182. package/dist/core/learning/learning-audit.d.ts +45 -0
  183. package/dist/core/learning/learning-audit.d.ts.map +1 -0
  184. package/dist/core/learning/learning-audit.js +139 -0
  185. package/dist/core/learning/learning-audit.js.map +1 -0
  186. package/dist/core/learning/learning-gate.d.ts +29 -0
  187. package/dist/core/learning/learning-gate.d.ts.map +1 -0
  188. package/dist/core/learning/learning-gate.js +150 -0
  189. package/dist/core/learning/learning-gate.js.map +1 -0
  190. package/dist/core/learning/session-learning-decision.d.ts +10 -0
  191. package/dist/core/learning/session-learning-decision.d.ts.map +1 -0
  192. package/dist/core/learning/session-learning-decision.js +36 -0
  193. package/dist/core/learning/session-learning-decision.js.map +1 -0
  194. package/dist/core/model-capability.d.ts +41 -0
  195. package/dist/core/model-capability.d.ts.map +1 -0
  196. package/dist/core/model-capability.js +101 -0
  197. package/dist/core/model-capability.js.map +1 -0
  198. package/dist/core/model-router/config-diagnostics.d.ts.map +1 -1
  199. package/dist/core/model-router/config-diagnostics.js +1 -0
  200. package/dist/core/model-router/config-diagnostics.js.map +1 -1
  201. package/dist/core/model-router/intent-classifier.d.ts +2 -0
  202. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  203. package/dist/core/model-router/intent-classifier.js +154 -9
  204. package/dist/core/model-router/intent-classifier.js.map +1 -1
  205. package/dist/core/model-router/route-judge.d.ts +54 -0
  206. package/dist/core/model-router/route-judge.d.ts.map +1 -0
  207. package/dist/core/model-router/route-judge.js +128 -0
  208. package/dist/core/model-router/route-judge.js.map +1 -0
  209. package/dist/core/model-router/status.d.ts +4 -1
  210. package/dist/core/model-router/status.d.ts.map +1 -1
  211. package/dist/core/model-router/status.js +30 -6
  212. package/dist/core/model-router/status.js.map +1 -1
  213. package/dist/core/model-router/tool-escalation.d.ts +4 -6
  214. package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
  215. package/dist/core/model-router/tool-escalation.js +1 -1
  216. package/dist/core/model-router/tool-escalation.js.map +1 -1
  217. package/dist/core/models/fitness-store.d.ts +40 -0
  218. package/dist/core/models/fitness-store.d.ts.map +1 -0
  219. package/dist/core/models/fitness-store.js +61 -0
  220. package/dist/core/models/fitness-store.js.map +1 -0
  221. package/dist/core/profile-registry.d.ts.map +1 -1
  222. package/dist/core/profile-registry.js +1 -1
  223. package/dist/core/profile-registry.js.map +1 -1
  224. package/dist/core/prompt-templates.d.ts +2 -0
  225. package/dist/core/prompt-templates.d.ts.map +1 -1
  226. package/dist/core/prompt-templates.js +12 -4
  227. package/dist/core/prompt-templates.js.map +1 -1
  228. package/dist/core/research/automata-provider.d.ts +5 -0
  229. package/dist/core/research/automata-provider.d.ts.map +1 -0
  230. package/dist/core/research/automata-provider.js +15 -0
  231. package/dist/core/research/automata-provider.js.map +1 -0
  232. package/dist/core/research/evidence-bundle.d.ts +10 -0
  233. package/dist/core/research/evidence-bundle.d.ts.map +1 -0
  234. package/dist/core/research/evidence-bundle.js +116 -0
  235. package/dist/core/research/evidence-bundle.js.map +1 -0
  236. package/dist/core/research/model-fitness.d.ts +79 -0
  237. package/dist/core/research/model-fitness.d.ts.map +1 -0
  238. package/dist/core/research/model-fitness.js +257 -0
  239. package/dist/core/research/model-fitness.js.map +1 -0
  240. package/dist/core/research/research-gate.d.ts +11 -0
  241. package/dist/core/research/research-gate.d.ts.map +1 -0
  242. package/dist/core/research/research-gate.js +82 -0
  243. package/dist/core/research/research-gate.js.map +1 -0
  244. package/dist/core/research/research-runner.d.ts +59 -0
  245. package/dist/core/research/research-runner.d.ts.map +1 -0
  246. package/dist/core/research/research-runner.js +155 -0
  247. package/dist/core/research/research-runner.js.map +1 -0
  248. package/dist/core/research/session-evidence-bundle.d.ts +11 -0
  249. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -0
  250. package/dist/core/research/session-evidence-bundle.js +55 -0
  251. package/dist/core/research/session-evidence-bundle.js.map +1 -0
  252. package/dist/core/resource-loader.d.ts.map +1 -1
  253. package/dist/core/resource-loader.js +7 -1
  254. package/dist/core/resource-loader.js.map +1 -1
  255. package/dist/core/settings-manager.d.ts +147 -4
  256. package/dist/core/settings-manager.d.ts.map +1 -1
  257. package/dist/core/settings-manager.js +285 -9
  258. package/dist/core/settings-manager.js.map +1 -1
  259. package/dist/core/skills.d.ts +4 -0
  260. package/dist/core/skills.d.ts.map +1 -1
  261. package/dist/core/skills.js +18 -6
  262. package/dist/core/skills.js.map +1 -1
  263. package/dist/core/slash-commands.d.ts.map +1 -1
  264. package/dist/core/slash-commands.js +4 -0
  265. package/dist/core/slash-commands.js.map +1 -1
  266. package/dist/core/toolkit/script-registry.d.ts +34 -0
  267. package/dist/core/toolkit/script-registry.d.ts.map +1 -0
  268. package/dist/core/toolkit/script-registry.js +71 -0
  269. package/dist/core/toolkit/script-registry.js.map +1 -0
  270. package/dist/core/toolkit/script-runner.d.ts +28 -0
  271. package/dist/core/toolkit/script-runner.d.ts.map +1 -0
  272. package/dist/core/toolkit/script-runner.js +48 -0
  273. package/dist/core/toolkit/script-runner.js.map +1 -0
  274. package/dist/core/tools/artifact-retrieve.d.ts +23 -0
  275. package/dist/core/tools/artifact-retrieve.d.ts.map +1 -0
  276. package/dist/core/tools/artifact-retrieve.js +110 -0
  277. package/dist/core/tools/artifact-retrieve.js.map +1 -0
  278. package/dist/core/tools/delegate.d.ts +32 -0
  279. package/dist/core/tools/delegate.d.ts.map +1 -0
  280. package/dist/core/tools/delegate.js +60 -0
  281. package/dist/core/tools/delegate.js.map +1 -0
  282. package/dist/core/tools/fff-search-backend.d.ts +103 -0
  283. package/dist/core/tools/fff-search-backend.d.ts.map +1 -0
  284. package/dist/core/tools/fff-search-backend.js +151 -0
  285. package/dist/core/tools/fff-search-backend.js.map +1 -0
  286. package/dist/core/tools/find.d.ts +21 -1
  287. package/dist/core/tools/find.d.ts.map +1 -1
  288. package/dist/core/tools/find.js +183 -10
  289. package/dist/core/tools/find.js.map +1 -1
  290. package/dist/core/tools/goal.d.ts +35 -0
  291. package/dist/core/tools/goal.d.ts.map +1 -0
  292. package/dist/core/tools/goal.js +122 -0
  293. package/dist/core/tools/goal.js.map +1 -0
  294. package/dist/core/tools/grep.d.ts +21 -1
  295. package/dist/core/tools/grep.d.ts.map +1 -1
  296. package/dist/core/tools/grep.js +272 -27
  297. package/dist/core/tools/grep.js.map +1 -1
  298. package/dist/core/tools/index.d.ts +4 -1
  299. package/dist/core/tools/index.d.ts.map +1 -1
  300. package/dist/core/tools/index.js +9 -0
  301. package/dist/core/tools/index.js.map +1 -1
  302. package/dist/core/tools/model-fitness.d.ts +30 -0
  303. package/dist/core/tools/model-fitness.d.ts.map +1 -0
  304. package/dist/core/tools/model-fitness.js +38 -0
  305. package/dist/core/tools/model-fitness.js.map +1 -0
  306. package/dist/core/tools/run-toolkit-script.d.ts +24 -0
  307. package/dist/core/tools/run-toolkit-script.d.ts.map +1 -0
  308. package/dist/core/tools/run-toolkit-script.js +103 -0
  309. package/dist/core/tools/run-toolkit-script.js.map +1 -0
  310. package/dist/core/tools/search-router.d.ts +75 -0
  311. package/dist/core/tools/search-router.d.ts.map +1 -0
  312. package/dist/core/tools/search-router.js +85 -0
  313. package/dist/core/tools/search-router.js.map +1 -0
  314. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  315. package/dist/modes/interactive/components/footer.js +18 -16
  316. package/dist/modes/interactive/components/footer.js.map +1 -1
  317. package/dist/modes/interactive/components/settings-selector.d.ts +13 -1
  318. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  319. package/dist/modes/interactive/components/settings-selector.js +471 -11
  320. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  321. package/dist/modes/interactive/interactive-mode.d.ts +4 -0
  322. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  323. package/dist/modes/interactive/interactive-mode.js +220 -39
  324. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  325. package/dist/modes/print-mode.d.ts.map +1 -1
  326. package/dist/modes/print-mode.js +3 -0
  327. package/dist/modes/print-mode.js.map +1 -1
  328. package/dist/utils/tools-manager.d.ts +2 -0
  329. package/dist/utils/tools-manager.d.ts.map +1 -1
  330. package/dist/utils/tools-manager.js +154 -2
  331. package/dist/utils/tools-manager.js.map +1 -1
  332. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  333. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  334. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  335. package/examples/extensions/sandbox/package-lock.json +2 -2
  336. package/examples/extensions/sandbox/package.json +1 -1
  337. package/examples/extensions/with-deps/package-lock.json +2 -2
  338. package/examples/extensions/with-deps/package.json +1 -1
  339. package/npm-shrinkwrap.json +368 -12
  340. package/package.json +5 -4
@@ -0,0 +1,48 @@
1
+ import { execFile } from "node:child_process";
2
+ export function buildScriptArgv(script, args) {
3
+ switch (script.runner) {
4
+ case "uv":
5
+ return { command: "uv", argv: ["run", script.path, ...args] };
6
+ case "powershell":
7
+ return {
8
+ command: "powershell.exe",
9
+ argv: ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", script.path, ...args],
10
+ };
11
+ case "bash":
12
+ return { command: "bash", argv: [script.path, ...args] };
13
+ }
14
+ }
15
+ const MAX_OUTPUT_BYTES = 512 * 1024;
16
+ /** Default executor: real process spawn, no shell interpolation, bounded output and time. */
17
+ export const spawnScriptExecutor = (command, argv, cwd, timeoutMs) => new Promise((resolve) => {
18
+ const started = Date.now();
19
+ execFile(command, argv, { cwd, timeout: timeoutMs, maxBuffer: MAX_OUTPUT_BYTES, encoding: "utf-8" }, (error, stdout, stderr) => {
20
+ const durationMs = Date.now() - started;
21
+ const err = error;
22
+ // error.code is a NUMBER for a non-zero exit but a STRING for spawn-level failures
23
+ // (ENOENT, EACCES) and for the maxBuffer kill — which also sets killed=true and must
24
+ // not be mislabeled as a timeout.
25
+ const maxBufferExceeded = err?.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER";
26
+ const timedOut = Boolean(err?.killed) && !maxBufferExceeded;
27
+ const exitCode = err ? (typeof err.code === "number" ? err.code : null) : 0;
28
+ // Spawn-level failures never produce their own stderr; surface the error message so
29
+ // the cause (missing runner, permission, output overflow) is never silently dropped.
30
+ let capturedStderr = stderr ?? "";
31
+ if (err && !timedOut && typeof err.code !== "number" && capturedStderr.length === 0) {
32
+ capturedStderr = err.message;
33
+ }
34
+ resolve({
35
+ exitCode,
36
+ stdout: stdout ?? "",
37
+ stderr: capturedStderr,
38
+ durationMs,
39
+ timedOut,
40
+ });
41
+ });
42
+ });
43
+ export async function executeToolkitScript(args) {
44
+ const { command, argv } = buildScriptArgv(args.script, args.scriptArgs);
45
+ const executor = args.executor ?? spawnScriptExecutor;
46
+ return executor(command, argv, args.cwd, args.timeoutMs ?? 120_000);
47
+ }
48
+ //# sourceMappingURL=script-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-runner.js","sourceRoot":"","sources":["../../../src/core/toolkit/script-runner.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile } from \"node:child_process\";\nimport type { ToolkitScript } from \"./script-registry.ts\";\n\n/**\n * Toolkit script invocation: the harness owns execution. Fixed argv per runner (never a shell\n * string), captured exit/stdout/stderr ALWAYS — the structural error contract that makes\n * false-success impossible regardless of what the model narrates.\n */\n\nexport interface ScriptExecution {\n\texitCode: number | null;\n\tstdout: string;\n\tstderr: string;\n\tdurationMs: number;\n\ttimedOut: boolean;\n}\n\nexport type ScriptExecutor = (\n\tcommand: string,\n\targv: string[],\n\tcwd: string,\n\ttimeoutMs: number,\n) => Promise<ScriptExecution>;\n\nexport function buildScriptArgv(script: ToolkitScript, args: readonly string[]): { command: string; argv: string[] } {\n\tswitch (script.runner) {\n\t\tcase \"uv\":\n\t\t\treturn { command: \"uv\", argv: [\"run\", script.path, ...args] };\n\t\tcase \"powershell\":\n\t\t\treturn {\n\t\t\t\tcommand: \"powershell.exe\",\n\t\t\t\targv: [\"-NoProfile\", \"-ExecutionPolicy\", \"Bypass\", \"-File\", script.path, ...args],\n\t\t\t};\n\t\tcase \"bash\":\n\t\t\treturn { command: \"bash\", argv: [script.path, ...args] };\n\t}\n}\n\nconst MAX_OUTPUT_BYTES = 512 * 1024;\n\n/** Default executor: real process spawn, no shell interpolation, bounded output and time. */\nexport const spawnScriptExecutor: ScriptExecutor = (command, argv, cwd, timeoutMs) =>\n\tnew Promise((resolve) => {\n\t\tconst started = Date.now();\n\t\texecFile(\n\t\t\tcommand,\n\t\t\targv,\n\t\t\t{ cwd, timeout: timeoutMs, maxBuffer: MAX_OUTPUT_BYTES, encoding: \"utf-8\" },\n\t\t\t(error, stdout, stderr) => {\n\t\t\t\tconst durationMs = Date.now() - started;\n\t\t\t\tconst err = error as (Error & { killed?: boolean; code?: number | string }) | null;\n\t\t\t\t// error.code is a NUMBER for a non-zero exit but a STRING for spawn-level failures\n\t\t\t\t// (ENOENT, EACCES) and for the maxBuffer kill — which also sets killed=true and must\n\t\t\t\t// not be mislabeled as a timeout.\n\t\t\t\tconst maxBufferExceeded = err?.code === \"ERR_CHILD_PROCESS_STDIO_MAXBUFFER\";\n\t\t\t\tconst timedOut = Boolean(err?.killed) && !maxBufferExceeded;\n\t\t\t\tconst exitCode = err ? (typeof err.code === \"number\" ? err.code : null) : 0;\n\t\t\t\t// Spawn-level failures never produce their own stderr; surface the error message so\n\t\t\t\t// the cause (missing runner, permission, output overflow) is never silently dropped.\n\t\t\t\tlet capturedStderr = stderr ?? \"\";\n\t\t\t\tif (err && !timedOut && typeof err.code !== \"number\" && capturedStderr.length === 0) {\n\t\t\t\t\tcapturedStderr = err.message;\n\t\t\t\t}\n\t\t\t\tresolve({\n\t\t\t\t\texitCode,\n\t\t\t\t\tstdout: stdout ?? \"\",\n\t\t\t\t\tstderr: capturedStderr,\n\t\t\t\t\tdurationMs,\n\t\t\t\t\ttimedOut,\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\t});\n\nexport async function executeToolkitScript(args: {\n\tscript: ToolkitScript;\n\tscriptArgs: readonly string[];\n\tcwd: string;\n\ttimeoutMs?: number;\n\texecutor?: ScriptExecutor;\n}): Promise<ScriptExecution> {\n\tconst { command, argv } = buildScriptArgv(args.script, args.scriptArgs);\n\tconst executor = args.executor ?? spawnScriptExecutor;\n\treturn executor(command, argv, args.cwd, args.timeoutMs ?? 120_000);\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import type { AgentTool } from "@caupulican/pi-agent-core";
2
+ import { type Static, Type } from "typebox";
3
+ import { type ArtifactRetrievalMode } from "../context/artifact-retrieval.ts";
4
+ import type { ArtifactStore } from "../context/context-artifacts.ts";
5
+ import type { ToolDefinition } from "../extensions/types.ts";
6
+ declare const artifactRetrieveSchema: Type.TObject<{
7
+ artifactId: Type.TString;
8
+ mode: Type.TOptional<Type.TUnion<[Type.TLiteral<"metadata">, Type.TLiteral<"head">, Type.TLiteral<"tail">]>>;
9
+ maxLines: Type.TOptional<Type.TNumber>;
10
+ }>;
11
+ export type ArtifactRetrieveToolInput = Static<typeof artifactRetrieveSchema>;
12
+ export interface ArtifactRetrieveToolDetails {
13
+ found: boolean;
14
+ mode: ArtifactRetrievalMode;
15
+ }
16
+ export interface ArtifactRetrieveToolOptions {
17
+ /** Session-scoped artifact store to resolve ids against. Omitted: the tool reports unavailable. */
18
+ artifactStore?: ArtifactStore;
19
+ }
20
+ export declare function createArtifactRetrieveToolDefinition(_cwd: string, options?: ArtifactRetrieveToolOptions): ToolDefinition<typeof artifactRetrieveSchema, ArtifactRetrieveToolDetails | undefined>;
21
+ export declare function createArtifactRetrieveTool(cwd: string, options?: ArtifactRetrieveToolOptions): AgentTool<typeof artifactRetrieveSchema>;
22
+ export {};
23
+ //# sourceMappingURL=artifact-retrieve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-retrieve.d.ts","sourceRoot":"","sources":["../../../src/core/tools/artifact-retrieve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EACN,KAAK,qBAAqB,EAG1B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAO7D,QAAA,MAAM,sBAAsB;;;;EAc1B,CAAC;AAEH,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAE9E,MAAM,WAAW,2BAA2B;IAC3C,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,qBAAqB,CAAC;CAC5B;AAED,MAAM,WAAW,2BAA2B;IAC3C,mGAAmG;IACnG,aAAa,CAAC,EAAE,aAAa,CAAC;CAC9B;AAkCD,wBAAgB,oCAAoC,CACnD,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,2BAA2B,GACnC,cAAc,CAAC,OAAO,sBAAsB,EAAE,2BAA2B,GAAG,SAAS,CAAC,CA2ExF;AAED,wBAAgB,0BAA0B,CACzC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,2BAA2B,GACnC,SAAS,CAAC,OAAO,sBAAsB,CAAC,CAE1C","sourcesContent":["import type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport { Text } from \"@caupulican/pi-tui\";\nimport { type Static, Type } from \"typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport {\n\ttype ArtifactRetrievalMode,\n\tDEFAULT_RETRIEVAL_MAX_LINES,\n\tretrieveArtifactSlice,\n} from \"../context/artifact-retrieval.ts\";\nimport type { ArtifactStore } from \"../context/context-artifacts.ts\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport { invalidArgText, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { formatSize } from \"./truncate.ts\";\n\nconst ARTIFACT_ID_PREFIX = \"tool-output:\";\n\nconst artifactRetrieveSchema = Type.Object({\n\tartifactId: Type.String({\n\t\tdescription:\n\t\t\t\"Artifact id from a 'Full output: artifact tool-output:<id>' reference in a prior tool result. The 'tool-output:' prefix is optional.\",\n\t}),\n\tmode: Type.Optional(\n\t\tType.Union([Type.Literal(\"metadata\"), Type.Literal(\"head\"), Type.Literal(\"tail\")], {\n\t\t\tdescription:\n\t\t\t\t\"'metadata' for tool/path/size info only (no content); 'head' (default) for the first lines; 'tail' for the last lines.\",\n\t\t}),\n\t),\n\tmaxLines: Type.Optional(\n\t\tType.Number({ description: `Maximum lines to return for head/tail (default: ${DEFAULT_RETRIEVAL_MAX_LINES})` }),\n\t),\n});\n\nexport type ArtifactRetrieveToolInput = Static<typeof artifactRetrieveSchema>;\n\nexport interface ArtifactRetrieveToolDetails {\n\tfound: boolean;\n\tmode: ArtifactRetrievalMode;\n}\n\nexport interface ArtifactRetrieveToolOptions {\n\t/** Session-scoped artifact store to resolve ids against. Omitted: the tool reports unavailable. */\n\tartifactStore?: ArtifactStore;\n}\n\nfunction normalizeArtifactId(input: string): string {\n\treturn input.startsWith(ARTIFACT_ID_PREFIX) ? input.slice(ARTIFACT_ID_PREFIX.length) : input;\n}\n\nfunction formatMetadataText(ref: {\n\tkind: string;\n\ttoolName?: string;\n\tcommand?: string;\n\tpath?: string;\n\tbyteLength: number;\n\tlineCount?: number;\n\treproducible: boolean;\n}): string {\n\tconst lines = [\n\t\t`kind: ${ref.kind}`,\n\t\tref.toolName ? `tool: ${ref.toolName}` : undefined,\n\t\tref.command ? `command: ${ref.command}` : undefined,\n\t\tref.path ? `path: ${ref.path}` : undefined,\n\t\t`size: ${formatSize(ref.byteLength)}`,\n\t\tref.lineCount !== undefined ? `lines: ${ref.lineCount}` : undefined,\n\t\t`reproducible: ${ref.reproducible}`,\n\t];\n\treturn lines.filter((line): line is string => line !== undefined).join(\"\\n\");\n}\n\nfunction formatCall(args: { artifactId: string; mode?: string } | undefined, theme: Theme): string {\n\tconst artifactId = str(args?.artifactId);\n\tconst mode = args?.mode ?? \"head\";\n\tconst idText = artifactId === null ? invalidArgText(theme) : theme.fg(\"accent\", artifactId);\n\treturn `${theme.fg(\"toolTitle\", theme.bold(\"artifact_retrieve\"))} ${idText}${theme.fg(\"toolOutput\", ` (${mode})`)}`;\n}\n\nexport function createArtifactRetrieveToolDefinition(\n\t_cwd: string,\n\toptions?: ArtifactRetrieveToolOptions,\n): ToolDefinition<typeof artifactRetrieveSchema, ArtifactRetrieveToolDetails | undefined> {\n\tconst artifactStore = options?.artifactStore;\n\treturn {\n\t\tname: \"artifact_retrieve\",\n\t\tlabel: \"artifact_retrieve\",\n\t\tdescription:\n\t\t\t\"Retrieve a bounded slice of a packed tool-output artifact by id, from a 'Full output: artifact tool-output:<id>' reference in a prior tool result. Returns metadata, or a bounded head/tail slice -- never the full raw payload in one call.\",\n\t\tpromptSnippet: \"Retrieve a bounded slice of a packed tool-output artifact\",\n\t\tparameters: artifactRetrieveSchema,\n\t\ttoolGroup: \"explore\",\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ artifactId, mode, maxLines }: { artifactId: string; mode?: ArtifactRetrievalMode; maxLines?: number },\n\t\t) {\n\t\t\tconst effectiveMode = mode ?? \"head\";\n\t\t\tif (!artifactStore) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: \"No artifact store is configured for this session.\" }],\n\t\t\t\t\tdetails: { found: false, mode: effectiveMode },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst result = retrieveArtifactSlice(artifactStore, {\n\t\t\t\tartifactId: normalizeArtifactId(artifactId),\n\t\t\t\tmode,\n\t\t\t\tmaxLines,\n\t\t\t});\n\n\t\t\tif (!result.found) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Artifact not found: ${artifactId} (${result.missingReason}). It may have been cleaned up, or the id may be incorrect.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { found: false, mode: effectiveMode },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (result.mode === \"metadata\") {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: formatMetadataText(result.ref) }],\n\t\t\t\t\tdetails: { found: true, mode: \"metadata\" },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tlet text = result.slice;\n\t\t\tif (result.truncation.truncated) {\n\t\t\t\ttext += `\\n\\n[Showing ${result.mode} ${result.truncation.outputLines} of ${result.truncation.totalLines} lines. Full artifact: ${formatSize(result.ref.byteLength)}. Retrieve again with a different mode/maxLines for another slice.]`;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\t\tdetails: { found: true, mode: result.mode },\n\t\t\t};\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatCall(args, 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\tconst content = result.content.find((part) => part.type === \"text\");\n\t\t\tconst body = content && \"text\" in content ? content.text : \"\";\n\t\t\tconst lines = body.split(\"\\n\");\n\t\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\tconst remaining = lines.length - maxLines;\n\t\t\tlet rendered = displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\tif (remaining > 0) rendered += `\\n${theme.fg(\"muted\", `... (${remaining} more lines)`)}`;\n\t\t\ttext.setText(rendered);\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createArtifactRetrieveTool(\n\tcwd: string,\n\toptions?: ArtifactRetrieveToolOptions,\n): AgentTool<typeof artifactRetrieveSchema> {\n\treturn wrapToolDefinition(createArtifactRetrieveToolDefinition(cwd, options));\n}\n"]}
@@ -0,0 +1,110 @@
1
+ import { Text } from "@caupulican/pi-tui";
2
+ import { Type } from "typebox";
3
+ import { DEFAULT_RETRIEVAL_MAX_LINES, retrieveArtifactSlice, } from "../context/artifact-retrieval.js";
4
+ import { invalidArgText, str } from "./render-utils.js";
5
+ import { wrapToolDefinition } from "./tool-definition-wrapper.js";
6
+ import { formatSize } from "./truncate.js";
7
+ const ARTIFACT_ID_PREFIX = "tool-output:";
8
+ const artifactRetrieveSchema = Type.Object({
9
+ artifactId: Type.String({
10
+ description: "Artifact id from a 'Full output: artifact tool-output:<id>' reference in a prior tool result. The 'tool-output:' prefix is optional.",
11
+ }),
12
+ mode: Type.Optional(Type.Union([Type.Literal("metadata"), Type.Literal("head"), Type.Literal("tail")], {
13
+ description: "'metadata' for tool/path/size info only (no content); 'head' (default) for the first lines; 'tail' for the last lines.",
14
+ })),
15
+ maxLines: Type.Optional(Type.Number({ description: `Maximum lines to return for head/tail (default: ${DEFAULT_RETRIEVAL_MAX_LINES})` })),
16
+ });
17
+ function normalizeArtifactId(input) {
18
+ return input.startsWith(ARTIFACT_ID_PREFIX) ? input.slice(ARTIFACT_ID_PREFIX.length) : input;
19
+ }
20
+ function formatMetadataText(ref) {
21
+ const lines = [
22
+ `kind: ${ref.kind}`,
23
+ ref.toolName ? `tool: ${ref.toolName}` : undefined,
24
+ ref.command ? `command: ${ref.command}` : undefined,
25
+ ref.path ? `path: ${ref.path}` : undefined,
26
+ `size: ${formatSize(ref.byteLength)}`,
27
+ ref.lineCount !== undefined ? `lines: ${ref.lineCount}` : undefined,
28
+ `reproducible: ${ref.reproducible}`,
29
+ ];
30
+ return lines.filter((line) => line !== undefined).join("\n");
31
+ }
32
+ function formatCall(args, theme) {
33
+ const artifactId = str(args?.artifactId);
34
+ const mode = args?.mode ?? "head";
35
+ const idText = artifactId === null ? invalidArgText(theme) : theme.fg("accent", artifactId);
36
+ return `${theme.fg("toolTitle", theme.bold("artifact_retrieve"))} ${idText}${theme.fg("toolOutput", ` (${mode})`)}`;
37
+ }
38
+ export function createArtifactRetrieveToolDefinition(_cwd, options) {
39
+ const artifactStore = options?.artifactStore;
40
+ return {
41
+ name: "artifact_retrieve",
42
+ label: "artifact_retrieve",
43
+ description: "Retrieve a bounded slice of a packed tool-output artifact by id, from a 'Full output: artifact tool-output:<id>' reference in a prior tool result. Returns metadata, or a bounded head/tail slice -- never the full raw payload in one call.",
44
+ promptSnippet: "Retrieve a bounded slice of a packed tool-output artifact",
45
+ parameters: artifactRetrieveSchema,
46
+ toolGroup: "explore",
47
+ async execute(_toolCallId, { artifactId, mode, maxLines }) {
48
+ const effectiveMode = mode ?? "head";
49
+ if (!artifactStore) {
50
+ return {
51
+ content: [{ type: "text", text: "No artifact store is configured for this session." }],
52
+ details: { found: false, mode: effectiveMode },
53
+ };
54
+ }
55
+ const result = retrieveArtifactSlice(artifactStore, {
56
+ artifactId: normalizeArtifactId(artifactId),
57
+ mode,
58
+ maxLines,
59
+ });
60
+ if (!result.found) {
61
+ return {
62
+ content: [
63
+ {
64
+ type: "text",
65
+ text: `Artifact not found: ${artifactId} (${result.missingReason}). It may have been cleaned up, or the id may be incorrect.`,
66
+ },
67
+ ],
68
+ details: { found: false, mode: effectiveMode },
69
+ };
70
+ }
71
+ if (result.mode === "metadata") {
72
+ return {
73
+ content: [{ type: "text", text: formatMetadataText(result.ref) }],
74
+ details: { found: true, mode: "metadata" },
75
+ };
76
+ }
77
+ let text = result.slice;
78
+ if (result.truncation.truncated) {
79
+ text += `\n\n[Showing ${result.mode} ${result.truncation.outputLines} of ${result.truncation.totalLines} lines. Full artifact: ${formatSize(result.ref.byteLength)}. Retrieve again with a different mode/maxLines for another slice.]`;
80
+ }
81
+ return {
82
+ content: [{ type: "text", text }],
83
+ details: { found: true, mode: result.mode },
84
+ };
85
+ },
86
+ renderCall(args, theme, context) {
87
+ const text = context.lastComponent ?? new Text("", 0, 0);
88
+ text.setText(formatCall(args, theme));
89
+ return text;
90
+ },
91
+ renderResult(result, options, theme, context) {
92
+ const text = context.lastComponent ?? new Text("", 0, 0);
93
+ const content = result.content.find((part) => part.type === "text");
94
+ const body = content && "text" in content ? content.text : "";
95
+ const lines = body.split("\n");
96
+ const maxLines = options.expanded ? lines.length : 20;
97
+ const displayLines = lines.slice(0, maxLines);
98
+ const remaining = lines.length - maxLines;
99
+ let rendered = displayLines.map((line) => theme.fg("toolOutput", line)).join("\n");
100
+ if (remaining > 0)
101
+ rendered += `\n${theme.fg("muted", `... (${remaining} more lines)`)}`;
102
+ text.setText(rendered);
103
+ return text;
104
+ },
105
+ };
106
+ }
107
+ export function createArtifactRetrieveTool(cwd, options) {
108
+ return wrapToolDefinition(createArtifactRetrieveToolDefinition(cwd, options));
109
+ }
110
+ //# sourceMappingURL=artifact-retrieve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-retrieve.js","sourceRoot":"","sources":["../../../src/core/tools/artifact-retrieve.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport { Text } from \"@caupulican/pi-tui\";\nimport { type Static, Type } from \"typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport {\n\ttype ArtifactRetrievalMode,\n\tDEFAULT_RETRIEVAL_MAX_LINES,\n\tretrieveArtifactSlice,\n} from \"../context/artifact-retrieval.ts\";\nimport type { ArtifactStore } from \"../context/context-artifacts.ts\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport { invalidArgText, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { formatSize } from \"./truncate.ts\";\n\nconst ARTIFACT_ID_PREFIX = \"tool-output:\";\n\nconst artifactRetrieveSchema = Type.Object({\n\tartifactId: Type.String({\n\t\tdescription:\n\t\t\t\"Artifact id from a 'Full output: artifact tool-output:<id>' reference in a prior tool result. The 'tool-output:' prefix is optional.\",\n\t}),\n\tmode: Type.Optional(\n\t\tType.Union([Type.Literal(\"metadata\"), Type.Literal(\"head\"), Type.Literal(\"tail\")], {\n\t\t\tdescription:\n\t\t\t\t\"'metadata' for tool/path/size info only (no content); 'head' (default) for the first lines; 'tail' for the last lines.\",\n\t\t}),\n\t),\n\tmaxLines: Type.Optional(\n\t\tType.Number({ description: `Maximum lines to return for head/tail (default: ${DEFAULT_RETRIEVAL_MAX_LINES})` }),\n\t),\n});\n\nexport type ArtifactRetrieveToolInput = Static<typeof artifactRetrieveSchema>;\n\nexport interface ArtifactRetrieveToolDetails {\n\tfound: boolean;\n\tmode: ArtifactRetrievalMode;\n}\n\nexport interface ArtifactRetrieveToolOptions {\n\t/** Session-scoped artifact store to resolve ids against. Omitted: the tool reports unavailable. */\n\tartifactStore?: ArtifactStore;\n}\n\nfunction normalizeArtifactId(input: string): string {\n\treturn input.startsWith(ARTIFACT_ID_PREFIX) ? input.slice(ARTIFACT_ID_PREFIX.length) : input;\n}\n\nfunction formatMetadataText(ref: {\n\tkind: string;\n\ttoolName?: string;\n\tcommand?: string;\n\tpath?: string;\n\tbyteLength: number;\n\tlineCount?: number;\n\treproducible: boolean;\n}): string {\n\tconst lines = [\n\t\t`kind: ${ref.kind}`,\n\t\tref.toolName ? `tool: ${ref.toolName}` : undefined,\n\t\tref.command ? `command: ${ref.command}` : undefined,\n\t\tref.path ? `path: ${ref.path}` : undefined,\n\t\t`size: ${formatSize(ref.byteLength)}`,\n\t\tref.lineCount !== undefined ? `lines: ${ref.lineCount}` : undefined,\n\t\t`reproducible: ${ref.reproducible}`,\n\t];\n\treturn lines.filter((line): line is string => line !== undefined).join(\"\\n\");\n}\n\nfunction formatCall(args: { artifactId: string; mode?: string } | undefined, theme: Theme): string {\n\tconst artifactId = str(args?.artifactId);\n\tconst mode = args?.mode ?? \"head\";\n\tconst idText = artifactId === null ? invalidArgText(theme) : theme.fg(\"accent\", artifactId);\n\treturn `${theme.fg(\"toolTitle\", theme.bold(\"artifact_retrieve\"))} ${idText}${theme.fg(\"toolOutput\", ` (${mode})`)}`;\n}\n\nexport function createArtifactRetrieveToolDefinition(\n\t_cwd: string,\n\toptions?: ArtifactRetrieveToolOptions,\n): ToolDefinition<typeof artifactRetrieveSchema, ArtifactRetrieveToolDetails | undefined> {\n\tconst artifactStore = options?.artifactStore;\n\treturn {\n\t\tname: \"artifact_retrieve\",\n\t\tlabel: \"artifact_retrieve\",\n\t\tdescription:\n\t\t\t\"Retrieve a bounded slice of a packed tool-output artifact by id, from a 'Full output: artifact tool-output:<id>' reference in a prior tool result. Returns metadata, or a bounded head/tail slice -- never the full raw payload in one call.\",\n\t\tpromptSnippet: \"Retrieve a bounded slice of a packed tool-output artifact\",\n\t\tparameters: artifactRetrieveSchema,\n\t\ttoolGroup: \"explore\",\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ artifactId, mode, maxLines }: { artifactId: string; mode?: ArtifactRetrievalMode; maxLines?: number },\n\t\t) {\n\t\t\tconst effectiveMode = mode ?? \"head\";\n\t\t\tif (!artifactStore) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: \"No artifact store is configured for this session.\" }],\n\t\t\t\t\tdetails: { found: false, mode: effectiveMode },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst result = retrieveArtifactSlice(artifactStore, {\n\t\t\t\tartifactId: normalizeArtifactId(artifactId),\n\t\t\t\tmode,\n\t\t\t\tmaxLines,\n\t\t\t});\n\n\t\t\tif (!result.found) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Artifact not found: ${artifactId} (${result.missingReason}). It may have been cleaned up, or the id may be incorrect.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { found: false, mode: effectiveMode },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (result.mode === \"metadata\") {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: formatMetadataText(result.ref) }],\n\t\t\t\t\tdetails: { found: true, mode: \"metadata\" },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tlet text = result.slice;\n\t\t\tif (result.truncation.truncated) {\n\t\t\t\ttext += `\\n\\n[Showing ${result.mode} ${result.truncation.outputLines} of ${result.truncation.totalLines} lines. Full artifact: ${formatSize(result.ref.byteLength)}. Retrieve again with a different mode/maxLines for another slice.]`;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\t\tdetails: { found: true, mode: result.mode },\n\t\t\t};\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatCall(args, 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\tconst content = result.content.find((part) => part.type === \"text\");\n\t\t\tconst body = content && \"text\" in content ? content.text : \"\";\n\t\t\tconst lines = body.split(\"\\n\");\n\t\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\tconst remaining = lines.length - maxLines;\n\t\t\tlet rendered = displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\tif (remaining > 0) rendered += `\\n${theme.fg(\"muted\", `... (${remaining} more lines)`)}`;\n\t\t\ttext.setText(rendered);\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createArtifactRetrieveTool(\n\tcwd: string,\n\toptions?: ArtifactRetrieveToolOptions,\n): AgentTool<typeof artifactRetrieveSchema> {\n\treturn wrapToolDefinition(createArtifactRetrieveToolDefinition(cwd, options));\n}\n"]}
@@ -0,0 +1,32 @@
1
+ import { type Static, Type } from "typebox";
2
+ import type { LaneRecord } from "../autonomy/lane-tracker.ts";
3
+ import type { WorkerRunOutcome } from "../delegation/worker-runner.ts";
4
+ import type { ToolDefinition } from "../extensions/types.ts";
5
+ declare const delegateSchema: Type.TObject<{
6
+ instructions: Type.TString;
7
+ systemPrompt: Type.TOptional<Type.TString>;
8
+ }>;
9
+ export type DelegateToolInput = Static<typeof delegateSchema>;
10
+ export interface DelegateRunOutcome {
11
+ started: boolean;
12
+ skipReason?: string;
13
+ record?: LaneRecord;
14
+ outcome?: WorkerRunOutcome;
15
+ }
16
+ export interface DelegateToolDetails {
17
+ started: boolean;
18
+ skipReason?: string;
19
+ laneId?: string;
20
+ status?: string;
21
+ accepted?: boolean;
22
+ costUsd?: number;
23
+ }
24
+ export interface DelegateToolDependencies {
25
+ runWorkerDelegation: (args: {
26
+ instructions: string;
27
+ systemPrompt?: string;
28
+ }) => Promise<DelegateRunOutcome>;
29
+ }
30
+ export declare function createDelegateToolDefinition(deps: DelegateToolDependencies): ToolDefinition;
31
+ export {};
32
+ //# sourceMappingURL=delegate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delegate.d.ts","sourceRoot":"","sources":["../../../src/core/tools/delegate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,QAAA,MAAM,cAAc;;;EAcnB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACxC,mBAAmB,EAAE,CAAC,IAAI,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC5G;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,wBAAwB,GAAG,cAAc,CA6D3F","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { LaneRecord } from \"../autonomy/lane-tracker.ts\";\nimport type { WorkerRunOutcome } from \"../delegation/worker-runner.ts\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\n\nconst delegateSchema = Type.Object(\n\t{\n\t\tinstructions: Type.String({\n\t\t\tdescription:\n\t\t\t\t\"The self-contained task to delegate to a bounded read-only scout worker. Include all context the worker needs; it cannot see this conversation, run tools, or change files.\",\n\t\t}),\n\t\tsystemPrompt: Type.Optional(\n\t\t\tType.String({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Optional replacement for the worker's role prompt — useful to hand a small model a minimal, purpose-built prompt. A short non-negotiable core (read-only, no invention, untrusted output, exact format) always remains.\",\n\t\t\t}),\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\nexport type DelegateToolInput = Static<typeof delegateSchema>;\n\nexport interface DelegateRunOutcome {\n\tstarted: boolean;\n\tskipReason?: string;\n\trecord?: LaneRecord;\n\toutcome?: WorkerRunOutcome;\n}\n\nexport interface DelegateToolDetails {\n\tstarted: boolean;\n\tskipReason?: string;\n\tlaneId?: string;\n\tstatus?: string;\n\taccepted?: boolean;\n\tcostUsd?: number;\n}\n\nexport interface DelegateToolDependencies {\n\trunWorkerDelegation: (args: { instructions: string; systemPrompt?: string }) => Promise<DelegateRunOutcome>;\n}\n\nexport function createDelegateToolDefinition(deps: DelegateToolDependencies): ToolDefinition {\n\treturn {\n\t\tname: \"delegate\",\n\t\tlabel: \"delegate\",\n\t\tdescription:\n\t\t\t\"Delegate one bounded, self-contained analysis task to a read-only scout worker running on a cheap model lane. The worker cannot run tools or change files; it returns a structured summary (untrusted until you verify it) plus optional findings. Use it to parallelize research/analysis subtasks without spending foreground context.\",\n\t\tpromptSnippet: \"Delegate a bounded read-only analysis subtask to a scout worker.\",\n\t\tpromptGuidelines: [\n\t\t\t\"Delegate only self-contained analysis/summarization subtasks; include all needed context in the instructions.\",\n\t\t\t\"Worker output is untrusted evidence - verify it against the repo before acting on it.\",\n\t\t\t\"If the worker reports blockers, resolve them yourself or ask the user; do not re-delegate the same task blindly.\",\n\t\t],\n\t\tparameters: delegateSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\tinput: DelegateToolInput,\n\t\t): Promise<{\n\t\t\tcontent: Array<{ type: \"text\"; text: string }>;\n\t\t\tdetails: DelegateToolDetails;\n\t\t}> {\n\t\t\tconst run = await deps.runWorkerDelegation({\n\t\t\t\tinstructions: input.instructions,\n\t\t\t\t...(input.systemPrompt ? { systemPrompt: input.systemPrompt } : {}),\n\t\t\t});\n\t\t\tif (!run.started) {\n\t\t\t\tconst reason = run.skipReason ?? \"unknown\";\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\" as const, text: `delegate skipped: ${reason}` }],\n\t\t\t\t\tdetails: { started: false, skipReason: reason },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst outcome = run.outcome;\n\t\t\tconst lines: string[] = [\n\t\t\t\t`delegate ${run.record?.status ?? \"unknown\"}${run.record?.reasonCode ? ` (${run.record.reasonCode})` : \"\"}`,\n\t\t\t];\n\t\t\tif (outcome) {\n\t\t\t\tlines.push(\n\t\t\t\t\t`accepted: ${outcome.accepted} [${outcome.acceptance.outcome}/${outcome.acceptance.reasonCode}]`,\n\t\t\t\t\t\"Worker output (UNTRUSTED - verify before acting on it):\",\n\t\t\t\t\toutcome.result.summary,\n\t\t\t\t);\n\t\t\t\tif (outcome.result.blockers && outcome.result.blockers.length > 0) {\n\t\t\t\t\tlines.push(`Blockers: ${outcome.result.blockers.join(\"; \")}`);\n\t\t\t\t}\n\t\t\t\tfor (const finding of outcome.result.evidence?.findings ?? []) {\n\t\t\t\t\tlines.push(`- Finding: ${finding.summary}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: lines.join(\"\\n\") }],\n\t\t\t\tdetails: {\n\t\t\t\t\tstarted: true,\n\t\t\t\t\tlaneId: run.record?.laneId,\n\t\t\t\t\tstatus: run.record?.status,\n\t\t\t\t\taccepted: outcome?.accepted,\n\t\t\t\t\tcostUsd: outcome?.costUsd,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,60 @@
1
+ import { Type } from "typebox";
2
+ const delegateSchema = Type.Object({
3
+ instructions: Type.String({
4
+ description: "The self-contained task to delegate to a bounded read-only scout worker. Include all context the worker needs; it cannot see this conversation, run tools, or change files.",
5
+ }),
6
+ systemPrompt: Type.Optional(Type.String({
7
+ description: "Optional replacement for the worker's role prompt — useful to hand a small model a minimal, purpose-built prompt. A short non-negotiable core (read-only, no invention, untrusted output, exact format) always remains.",
8
+ })),
9
+ }, { additionalProperties: false });
10
+ export function createDelegateToolDefinition(deps) {
11
+ return {
12
+ name: "delegate",
13
+ label: "delegate",
14
+ description: "Delegate one bounded, self-contained analysis task to a read-only scout worker running on a cheap model lane. The worker cannot run tools or change files; it returns a structured summary (untrusted until you verify it) plus optional findings. Use it to parallelize research/analysis subtasks without spending foreground context.",
15
+ promptSnippet: "Delegate a bounded read-only analysis subtask to a scout worker.",
16
+ promptGuidelines: [
17
+ "Delegate only self-contained analysis/summarization subtasks; include all needed context in the instructions.",
18
+ "Worker output is untrusted evidence - verify it against the repo before acting on it.",
19
+ "If the worker reports blockers, resolve them yourself or ask the user; do not re-delegate the same task blindly.",
20
+ ],
21
+ parameters: delegateSchema,
22
+ async execute(_toolCallId, input) {
23
+ const run = await deps.runWorkerDelegation({
24
+ instructions: input.instructions,
25
+ ...(input.systemPrompt ? { systemPrompt: input.systemPrompt } : {}),
26
+ });
27
+ if (!run.started) {
28
+ const reason = run.skipReason ?? "unknown";
29
+ return {
30
+ content: [{ type: "text", text: `delegate skipped: ${reason}` }],
31
+ details: { started: false, skipReason: reason },
32
+ };
33
+ }
34
+ const outcome = run.outcome;
35
+ const lines = [
36
+ `delegate ${run.record?.status ?? "unknown"}${run.record?.reasonCode ? ` (${run.record.reasonCode})` : ""}`,
37
+ ];
38
+ if (outcome) {
39
+ lines.push(`accepted: ${outcome.accepted} [${outcome.acceptance.outcome}/${outcome.acceptance.reasonCode}]`, "Worker output (UNTRUSTED - verify before acting on it):", outcome.result.summary);
40
+ if (outcome.result.blockers && outcome.result.blockers.length > 0) {
41
+ lines.push(`Blockers: ${outcome.result.blockers.join("; ")}`);
42
+ }
43
+ for (const finding of outcome.result.evidence?.findings ?? []) {
44
+ lines.push(`- Finding: ${finding.summary}`);
45
+ }
46
+ }
47
+ return {
48
+ content: [{ type: "text", text: lines.join("\n") }],
49
+ details: {
50
+ started: true,
51
+ laneId: run.record?.laneId,
52
+ status: run.record?.status,
53
+ accepted: outcome?.accepted,
54
+ costUsd: outcome?.costUsd,
55
+ },
56
+ };
57
+ },
58
+ };
59
+ }
60
+ //# sourceMappingURL=delegate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delegate.js","sourceRoot":"","sources":["../../../src/core/tools/delegate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAK5C,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CACjC;IACC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC;QACzB,WAAW,EACV,6KAA6K;KAC9K,CAAC;IACF,YAAY,EAAE,IAAI,CAAC,QAAQ,CAC1B,IAAI,CAAC,MAAM,CAAC;QACX,WAAW,EACV,2NAAyN;KAC1N,CAAC,CACF;CACD,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAC/B,CAAC;AAwBF,MAAM,UAAU,4BAA4B,CAAC,IAA8B,EAAkB;IAC5F,OAAO;QACN,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,UAAU;QACjB,WAAW,EACV,0UAA0U;QAC3U,aAAa,EAAE,kEAAkE;QACjF,gBAAgB,EAAE;YACjB,+GAA+G;YAC/G,uFAAuF;YACvF,kHAAkH;SAClH;QACD,UAAU,EAAE,cAAc;QAC1B,KAAK,CAAC,OAAO,CACZ,WAAW,EACX,KAAwB,EAItB;YACF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC;gBAC1C,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACnE,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;gBAClB,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,IAAI,SAAS,CAAC;gBAC3C,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,qBAAqB,MAAM,EAAE,EAAE,CAAC;oBACzE,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE;iBAC/C,CAAC;YACH,CAAC;YAED,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;YAC5B,MAAM,KAAK,GAAa;gBACvB,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,IAAI,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;aAC3G,CAAC;YACF,IAAI,OAAO,EAAE,CAAC;gBACb,KAAK,CAAC,IAAI,CACT,aAAa,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,UAAU,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,UAAU,GAAG,EAChG,yDAAyD,EACzD,OAAO,CAAC,MAAM,CAAC,OAAO,CACtB,CAAC;gBACF,IAAI,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACnE,KAAK,CAAC,IAAI,CAAC,aAAa,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC/D,CAAC;gBACD,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC;oBAC/D,KAAK,CAAC,IAAI,CAAC,cAAc,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC7C,CAAC;YACF,CAAC;YACD,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5D,OAAO,EAAE;oBACR,OAAO,EAAE,IAAI;oBACb,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM;oBAC1B,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM;oBAC1B,QAAQ,EAAE,OAAO,EAAE,QAAQ;oBAC3B,OAAO,EAAE,OAAO,EAAE,OAAO;iBACzB;aACD,CAAC;QAAA,CACF;KACD,CAAC;AAAA,CACF","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { LaneRecord } from \"../autonomy/lane-tracker.ts\";\nimport type { WorkerRunOutcome } from \"../delegation/worker-runner.ts\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\n\nconst delegateSchema = Type.Object(\n\t{\n\t\tinstructions: Type.String({\n\t\t\tdescription:\n\t\t\t\t\"The self-contained task to delegate to a bounded read-only scout worker. Include all context the worker needs; it cannot see this conversation, run tools, or change files.\",\n\t\t}),\n\t\tsystemPrompt: Type.Optional(\n\t\t\tType.String({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Optional replacement for the worker's role prompt — useful to hand a small model a minimal, purpose-built prompt. A short non-negotiable core (read-only, no invention, untrusted output, exact format) always remains.\",\n\t\t\t}),\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\nexport type DelegateToolInput = Static<typeof delegateSchema>;\n\nexport interface DelegateRunOutcome {\n\tstarted: boolean;\n\tskipReason?: string;\n\trecord?: LaneRecord;\n\toutcome?: WorkerRunOutcome;\n}\n\nexport interface DelegateToolDetails {\n\tstarted: boolean;\n\tskipReason?: string;\n\tlaneId?: string;\n\tstatus?: string;\n\taccepted?: boolean;\n\tcostUsd?: number;\n}\n\nexport interface DelegateToolDependencies {\n\trunWorkerDelegation: (args: { instructions: string; systemPrompt?: string }) => Promise<DelegateRunOutcome>;\n}\n\nexport function createDelegateToolDefinition(deps: DelegateToolDependencies): ToolDefinition {\n\treturn {\n\t\tname: \"delegate\",\n\t\tlabel: \"delegate\",\n\t\tdescription:\n\t\t\t\"Delegate one bounded, self-contained analysis task to a read-only scout worker running on a cheap model lane. The worker cannot run tools or change files; it returns a structured summary (untrusted until you verify it) plus optional findings. Use it to parallelize research/analysis subtasks without spending foreground context.\",\n\t\tpromptSnippet: \"Delegate a bounded read-only analysis subtask to a scout worker.\",\n\t\tpromptGuidelines: [\n\t\t\t\"Delegate only self-contained analysis/summarization subtasks; include all needed context in the instructions.\",\n\t\t\t\"Worker output is untrusted evidence - verify it against the repo before acting on it.\",\n\t\t\t\"If the worker reports blockers, resolve them yourself or ask the user; do not re-delegate the same task blindly.\",\n\t\t],\n\t\tparameters: delegateSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\tinput: DelegateToolInput,\n\t\t): Promise<{\n\t\t\tcontent: Array<{ type: \"text\"; text: string }>;\n\t\t\tdetails: DelegateToolDetails;\n\t\t}> {\n\t\t\tconst run = await deps.runWorkerDelegation({\n\t\t\t\tinstructions: input.instructions,\n\t\t\t\t...(input.systemPrompt ? { systemPrompt: input.systemPrompt } : {}),\n\t\t\t});\n\t\t\tif (!run.started) {\n\t\t\t\tconst reason = run.skipReason ?? \"unknown\";\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\" as const, text: `delegate skipped: ${reason}` }],\n\t\t\t\t\tdetails: { started: false, skipReason: reason },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst outcome = run.outcome;\n\t\t\tconst lines: string[] = [\n\t\t\t\t`delegate ${run.record?.status ?? \"unknown\"}${run.record?.reasonCode ? ` (${run.record.reasonCode})` : \"\"}`,\n\t\t\t];\n\t\t\tif (outcome) {\n\t\t\t\tlines.push(\n\t\t\t\t\t`accepted: ${outcome.accepted} [${outcome.acceptance.outcome}/${outcome.acceptance.reasonCode}]`,\n\t\t\t\t\t\"Worker output (UNTRUSTED - verify before acting on it):\",\n\t\t\t\t\toutcome.result.summary,\n\t\t\t\t);\n\t\t\t\tif (outcome.result.blockers && outcome.result.blockers.length > 0) {\n\t\t\t\t\tlines.push(`Blockers: ${outcome.result.blockers.join(\"; \")}`);\n\t\t\t\t}\n\t\t\t\tfor (const finding of outcome.result.evidence?.findings ?? []) {\n\t\t\t\t\tlines.push(`- Finding: ${finding.summary}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: lines.join(\"\\n\") }],\n\t\t\t\tdetails: {\n\t\t\t\t\tstarted: true,\n\t\t\t\t\tlaneId: run.record?.laneId,\n\t\t\t\t\tstatus: run.record?.status,\n\t\t\t\t\taccepted: outcome?.accepted,\n\t\t\t\t\tcostUsd: outcome?.costUsd,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,103 @@
1
+ export type FffResult<T> = {
2
+ ok: true;
3
+ value: T;
4
+ } | {
5
+ ok: false;
6
+ error: string;
7
+ };
8
+ export type FffGrepMode = "plain" | "regex" | "fuzzy";
9
+ export interface FffFileItem {
10
+ relativePath: string;
11
+ fileName: string;
12
+ size: number;
13
+ modified: number;
14
+ gitStatus: string;
15
+ accessFrecencyScore?: number;
16
+ modificationFrecencyScore?: number;
17
+ totalFrecencyScore?: number;
18
+ }
19
+ export interface FffScore {
20
+ total: number;
21
+ baseScore: number;
22
+ matchType: string;
23
+ }
24
+ export interface FffSearchResult {
25
+ items: FffFileItem[];
26
+ scores: FffScore[];
27
+ totalMatched: number;
28
+ totalFiles: number;
29
+ }
30
+ export interface FffSearchOptions {
31
+ pageIndex?: number;
32
+ pageSize?: number;
33
+ }
34
+ export interface FffGlobOptions {
35
+ pageIndex?: number;
36
+ pageSize?: number;
37
+ }
38
+ export interface FffGrepOptions {
39
+ maxMatchesPerFile?: number;
40
+ smartCase?: boolean;
41
+ mode?: FffGrepMode;
42
+ beforeContext?: number;
43
+ afterContext?: number;
44
+ pageSize?: number;
45
+ }
46
+ export interface FffGrepMatch {
47
+ relativePath: string;
48
+ fileName: string;
49
+ gitStatus: string;
50
+ size: number;
51
+ modified: number;
52
+ isBinary: boolean;
53
+ totalFrecencyScore: number;
54
+ accessFrecencyScore: number;
55
+ modificationFrecencyScore: number;
56
+ lineNumber: number;
57
+ col: number;
58
+ byteOffset: number;
59
+ lineContent: string;
60
+ matchRanges: [number, number][];
61
+ contextBefore?: string[];
62
+ contextAfter?: string[];
63
+ }
64
+ export interface FffGrepResult {
65
+ items: FffGrepMatch[];
66
+ totalMatched: number;
67
+ totalFilesSearched: number;
68
+ totalFiles: number;
69
+ filteredFileCount: number;
70
+ nextCursor: unknown | null;
71
+ regexFallbackError?: string;
72
+ }
73
+ export interface FffFileFinder {
74
+ readonly isDestroyed: boolean;
75
+ destroy(): void;
76
+ fileSearch(query: string, options?: FffSearchOptions): FffResult<FffSearchResult>;
77
+ glob(pattern: string, options?: FffGlobOptions): FffResult<FffSearchResult>;
78
+ grep(query: string, options?: FffGrepOptions): FffResult<FffGrepResult>;
79
+ waitForScan(timeoutMs?: number): Promise<FffResult<boolean>>;
80
+ }
81
+ interface FffInitOptions {
82
+ basePath: string;
83
+ aiMode?: boolean;
84
+ enableHomeDirScanning?: boolean;
85
+ enableFsRootScanning?: boolean;
86
+ }
87
+ interface FffFileFinderConstructor {
88
+ create(options: FffInitOptions): FffResult<FffFileFinder>;
89
+ isAvailable?: () => boolean;
90
+ }
91
+ interface FffModule {
92
+ FileFinder: FffFileFinderConstructor;
93
+ }
94
+ export interface FffSearchBackend {
95
+ getFinder(basePath: string): Promise<FffFileFinder | undefined>;
96
+ }
97
+ type ModuleRequire = (id: string) => unknown;
98
+ export declare function loadFffModule(requires?: readonly ModuleRequire[]): FffModule | null;
99
+ export declare function relativePathInside(basePath: string, targetPath: string): string | undefined;
100
+ export declare function hasGitignoreInTree(rootPath: string): Promise<boolean>;
101
+ export declare const defaultFffSearchBackend: FffSearchBackend;
102
+ export {};
103
+ //# sourceMappingURL=fff-search-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fff-search-backend.d.ts","sourceRoot":"","sources":["../../../src/core/tools/fff-search-backend.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Dirent } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { ensureFffNodePackage, loadAvailableFffNodePackage } from \"../../utils/tools-manager.ts\";\n\nexport type FffResult<T> = { ok: true; value: T } | { ok: false; error: string };\nexport type FffGrepMode = \"plain\" | \"regex\" | \"fuzzy\";\n\nexport interface FffFileItem {\n\trelativePath: string;\n\tfileName: string;\n\tsize: number;\n\tmodified: number;\n\tgitStatus: string;\n\taccessFrecencyScore?: number;\n\tmodificationFrecencyScore?: number;\n\ttotalFrecencyScore?: number;\n}\n\nexport interface FffScore {\n\ttotal: number;\n\tbaseScore: number;\n\tmatchType: string;\n}\n\nexport interface FffSearchResult {\n\titems: FffFileItem[];\n\tscores: FffScore[];\n\ttotalMatched: number;\n\ttotalFiles: number;\n}\n\nexport interface FffSearchOptions {\n\tpageIndex?: number;\n\tpageSize?: number;\n}\n\nexport interface FffGlobOptions {\n\tpageIndex?: number;\n\tpageSize?: number;\n}\n\nexport interface FffGrepOptions {\n\tmaxMatchesPerFile?: number;\n\tsmartCase?: boolean;\n\tmode?: FffGrepMode;\n\tbeforeContext?: number;\n\tafterContext?: number;\n\tpageSize?: number;\n}\n\nexport interface FffGrepMatch {\n\trelativePath: string;\n\tfileName: string;\n\tgitStatus: string;\n\tsize: number;\n\tmodified: number;\n\tisBinary: boolean;\n\ttotalFrecencyScore: number;\n\taccessFrecencyScore: number;\n\tmodificationFrecencyScore: number;\n\tlineNumber: number;\n\tcol: number;\n\tbyteOffset: number;\n\tlineContent: string;\n\tmatchRanges: [number, number][];\n\tcontextBefore?: string[];\n\tcontextAfter?: string[];\n}\n\nexport interface FffGrepResult {\n\titems: FffGrepMatch[];\n\ttotalMatched: number;\n\ttotalFilesSearched: number;\n\ttotalFiles: number;\n\tfilteredFileCount: number;\n\tnextCursor: unknown | null;\n\tregexFallbackError?: string;\n}\n\nexport interface FffFileFinder {\n\treadonly isDestroyed: boolean;\n\tdestroy(): void;\n\tfileSearch(query: string, options?: FffSearchOptions): FffResult<FffSearchResult>;\n\tglob(pattern: string, options?: FffGlobOptions): FffResult<FffSearchResult>;\n\tgrep(query: string, options?: FffGrepOptions): FffResult<FffGrepResult>;\n\twaitForScan(timeoutMs?: number): Promise<FffResult<boolean>>;\n}\n\ninterface FffInitOptions {\n\tbasePath: string;\n\taiMode?: boolean;\n\tenableHomeDirScanning?: boolean;\n\tenableFsRootScanning?: boolean;\n}\n\ninterface FffFileFinderConstructor {\n\tcreate(options: FffInitOptions): FffResult<FffFileFinder>;\n\tisAvailable?: () => boolean;\n}\n\ninterface FffModule {\n\tFileFinder: FffFileFinderConstructor;\n}\n\nexport interface FffSearchBackend {\n\tgetFinder(basePath: string): Promise<FffFileFinder | undefined>;\n}\n\ntype ModuleRequire = (id: string) => unknown;\n\nconst DEFAULT_WAIT_FOR_SCAN_MS = 15_000;\nconst MAX_FINDER_CACHE_SIZE = 8;\nconst FFF_GITIGNORE_SKIP_DIRS = new Set([\".git\", \"node_modules\"]);\n\nlet loadedFffModule: FffModule | null | undefined;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\";\n}\n\nfunction hasProperties(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && (typeof value === \"object\" || typeof value === \"function\");\n}\n\nfunction isFffResult<T>(value: unknown): value is FffResult<T> {\n\tif (!isRecord(value)) return false;\n\treturn value.ok === true || value.ok === false;\n}\n\nfunction isFffModule(value: unknown): value is FffModule {\n\tif (!isRecord(value)) return false;\n\tconst fileFinder = value.FileFinder;\n\treturn hasProperties(fileFinder) && typeof fileFinder.create === \"function\";\n}\n\nexport function loadFffModule(requires?: readonly ModuleRequire[]): FffModule | null {\n\tif (requires) {\n\t\tfor (const requireFff of requires) {\n\t\t\ttry {\n\t\t\t\tconst loaded = requireFff(\"@ff-labs/fff-node\");\n\t\t\t\tif (isFffModule(loaded)) return loaded;\n\t\t\t} catch {\n\t\t\t\t// Try the next resolution root.\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tif (loadedFffModule !== undefined) return loadedFffModule;\n\tconst loaded = loadAvailableFffNodePackage();\n\tloadedFffModule = isFffModule(loaded) ? loaded : null;\n\treturn loadedFffModule;\n}\n\nasync function ensureFffModule(): Promise<FffModule | null> {\n\tconst loaded = loadFffModule();\n\tif (loaded) return loaded;\n\tconst installed = await ensureFffNodePackage(true);\n\tloadedFffModule = isFffModule(installed) ? installed : null;\n\treturn loadedFffModule;\n}\n\nfunction isFffRuntimeDisabled(): boolean {\n\tconst value = process.env.PI_FFF_DISABLED ?? process.env.PI_SEARCH_BACKEND;\n\tif (!value) return false;\n\treturn value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"disabled\";\n}\n\nfunction isRootScanningEnabled(): boolean {\n\tconst value = process.env.PI_FFF_ENABLE_ROOT_SCAN;\n\treturn value === \"1\" || value?.toLowerCase() === \"true\";\n}\n\nfunction destroyFinder(finder: FffFileFinder | undefined): void {\n\tif (finder && !finder.isDestroyed) {\n\t\tfinder.destroy();\n\t}\n}\n\nexport function relativePathInside(basePath: string, targetPath: string): string | undefined {\n\tconst relative = path.relative(path.resolve(basePath), path.resolve(targetPath));\n\tif (relative === \"\") return \"\";\n\tif (relative.startsWith(\"..\") || path.isAbsolute(relative)) return undefined;\n\treturn relative.split(path.sep).join(\"/\");\n}\n\nexport async function hasGitignoreInTree(rootPath: string): Promise<boolean> {\n\tconst stack = [path.resolve(rootPath)];\n\twhile (stack.length > 0) {\n\t\tconst current = stack.pop();\n\t\tif (!current) continue;\n\n\t\tlet entries: Dirent[];\n\t\ttry {\n\t\t\tentries = await readdir(current, { withFileTypes: true });\n\t\t} catch {\n\t\t\treturn true;\n\t\t}\n\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.isFile() && entry.name === \".gitignore\") return true;\n\t\t\tif (entry.isDirectory() && !FFF_GITIGNORE_SKIP_DIRS.has(entry.name)) {\n\t\t\t\tstack.push(path.join(current, entry.name));\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nclass DefaultFffSearchBackend implements FffSearchBackend {\n\tprivate readonly finders = new Map<string, Promise<FffFileFinder | undefined>>();\n\n\tasync getFinder(basePath: string): Promise<FffFileFinder | undefined> {\n\t\tif (isFffRuntimeDisabled()) return undefined;\n\n\t\tconst normalizedBasePath = path.resolve(basePath);\n\t\tconst cached = this.finders.get(normalizedBasePath);\n\t\tif (cached) return cached;\n\n\t\tconst created = this.createFinder(normalizedBasePath);\n\t\tthis.finders.set(normalizedBasePath, created);\n\t\tthis.evictIfNeeded();\n\t\treturn created;\n\t}\n\n\tprivate evictIfNeeded(): void {\n\t\twhile (this.finders.size > MAX_FINDER_CACHE_SIZE) {\n\t\t\tconst firstKey = this.finders.keys().next().value;\n\t\t\tif (!firstKey) return;\n\t\t\tconst first = this.finders.get(firstKey);\n\t\t\tthis.finders.delete(firstKey);\n\t\t\tvoid first?.then(destroyFinder, () => undefined);\n\t\t}\n\t}\n\n\tprivate async createFinder(basePath: string): Promise<FffFileFinder | undefined> {\n\t\tlet fff = await ensureFffModule();\n\t\tif (!fff) return undefined;\n\t\tif (fff.FileFinder.isAvailable && !fff.FileFinder.isAvailable()) {\n\t\t\tconst installed = await ensureFffNodePackage(true, true);\n\t\t\tloadedFffModule = isFffModule(installed) ? installed : null;\n\t\t\tfff = loadedFffModule;\n\t\t\tif (!fff || (fff.FileFinder.isAvailable && !fff.FileFinder.isAvailable())) return undefined;\n\t\t}\n\n\t\tconst created = fff.FileFinder.create({\n\t\t\tbasePath,\n\t\t\taiMode: true,\n\t\t\tenableHomeDirScanning: true,\n\t\t\tenableFsRootScanning: isRootScanningEnabled(),\n\t\t});\n\t\tif (!isFffResult<FffFileFinder>(created) || !created.ok) return undefined;\n\n\t\tconst scan = await created.value.waitForScan(DEFAULT_WAIT_FOR_SCAN_MS);\n\t\tif (!scan.ok) {\n\t\t\tdestroyFinder(created.value);\n\t\t\treturn undefined;\n\t\t}\n\t\treturn created.value;\n\t}\n}\n\nexport const defaultFffSearchBackend: FffSearchBackend = new DefaultFffSearchBackend();\n"]}