@xopcai/xopc 0.0.123 → 0.0.124

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 (264) hide show
  1. package/README.md +28 -11
  2. package/README.zh-CN.md +28 -11
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/telegram/xopc.extension.json +1 -1
  5. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Bicr3ZBg.js → agent-avatar-dicebear-B5uSVAyJ.js} +1 -1
  6. package/dist/gateway/static/root/assets/agents-BjIxt67Z.js +2 -0
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-CbEy9sR1.js → app-management-settings-panel-CYCONLIL.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-CTHja6n9.js → appearance-settings-Clw3ryKg.js} +1 -1
  9. package/dist/gateway/static/root/assets/apps-page-QICTeGjX.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-Bpy64GjU.js → archive-plugin-CXUGRp2i.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-DMkp4xSb.js → attachment-load-Cmiub3Wg.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automation-suggestion-card-KnYaP7NT.js → automation-suggestion-card-CU0-4nQ-.js} +1 -1
  13. package/dist/gateway/static/root/assets/automations-page-Car-jtiz.js +1 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-DA9C5mCw.js → binary-plugins-0Izz-N3p.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-CiSXk_YC.js → block-editor-C1Kv0IkJ.js} +6 -6
  16. package/dist/gateway/static/root/assets/browser-settings-page-CMeBJzlS.js +8 -0
  17. package/dist/gateway/static/root/assets/{capability-presets-api-CEJ44WCU.js → capability-presets-api-BmQTM9Il.js} +1 -1
  18. package/dist/gateway/static/root/assets/capability-presets-settings-panel-DZEJEoCF.js +1 -0
  19. package/dist/gateway/static/root/assets/{channel-recipient-api-CDhrhfhN.js → channel-recipient-api-BeA2aVor.js} +1 -1
  20. package/dist/gateway/static/root/assets/channels-settings-kkW-xFau.js +1 -0
  21. package/dist/gateway/static/root/assets/connectors-page-BvaQvO5F.js +2 -0
  22. package/dist/gateway/static/root/assets/{directory-picker-path-field-7jKfbH0J.js → directory-picker-path-field-2rjzUu57.js} +1 -1
  23. package/dist/gateway/static/root/assets/{dreaming-settings-m1-wmz4o.js → dreaming-settings-DnHO686d.js} +1 -1
  24. package/dist/gateway/static/root/assets/{extension-debug-page-C9qQQrBS.js → extension-debug-page-BGLRuWVN.js} +1 -1
  25. package/dist/gateway/static/root/assets/{extension-page-DcBBMEGl.js → extension-page-D978ePp9.js} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-settings-page-BQ-jMMP9.js → extension-settings-page-B6Ih4Swx.js} +1 -1
  27. package/dist/gateway/static/root/assets/{fetch-Dtpbbe0s.js → fetch-BU5S0Sn7.js} +1 -1
  28. package/dist/gateway/static/root/assets/{gateway-config-api-BN6pyX2c.js → gateway-config-api-BIPGwrl1.js} +1 -1
  29. package/dist/gateway/static/root/assets/gateway-settings-CMEA3r5u.js +1 -0
  30. package/dist/gateway/static/root/assets/{gateway-startup-retry-BIET2x3y.js → gateway-startup-retry-Cd0Zz30N.js} +1 -1
  31. package/dist/gateway/static/root/assets/{goal-create-dialog-BuIMDx6C.js → goal-create-dialog-B-KHKeXN.js} +1 -1
  32. package/dist/gateway/static/root/assets/goal-detail-page-BxrSoWdj.js +1 -0
  33. package/dist/gateway/static/root/assets/{goals-config-api-CQm2r1Ty.js → goals-config-api-B95KdGMj.js} +1 -1
  34. package/dist/gateway/static/root/assets/goals-page-BTJzIl28.js +2 -0
  35. package/dist/gateway/static/root/assets/{goals-settings-DDrdRMxB.js → goals-settings-BJyEuLLm.js} +1 -1
  36. package/dist/gateway/static/root/assets/heartbeat-settings-wkOjYNQT.js +1 -0
  37. package/dist/gateway/static/root/assets/{index-CBDr5xjB.css → index-BLaXr6Ev.css} +1 -1
  38. package/dist/gateway/static/root/assets/index-c_9TVr_C.js +191 -0
  39. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-C2TuQppb.js → keyboard-shortcuts-settings-BT8T4DyC.js} +1 -1
  40. package/dist/gateway/static/root/assets/logs-page-CrxBJUgI.js +2 -0
  41. package/dist/gateway/static/root/assets/{markdown-split-DhONQ81k.js → markdown-split-Dv66bO2b.js} +1 -1
  42. package/dist/gateway/static/root/assets/{media-plugins-DS44pJzr.js → media-plugins-BhIQU5yS.js} +1 -1
  43. package/dist/gateway/static/root/assets/messages-O6TAtdFC.js +3 -0
  44. package/dist/gateway/static/root/assets/models-hub-panel-DOOpz6y1.js +2 -0
  45. package/dist/gateway/static/root/assets/notes-page-Br16pK9v.js +1 -0
  46. package/dist/gateway/static/root/assets/notes-workbench-PSJAi0ZC.js +2 -0
  47. package/dist/gateway/static/root/assets/{preview-open-alternatives-Dej6zHnr.js → preview-open-alternatives-DGzet1d7.js} +1 -1
  48. package/dist/gateway/static/root/assets/project-detail-page-CIGGgKuw.js +1 -0
  49. package/dist/gateway/static/root/assets/projects-page-B2grhsBt.js +1 -0
  50. package/dist/gateway/static/root/assets/remote-access-hub-CXMORxBD.js +1 -0
  51. package/dist/gateway/static/root/assets/{save-bar-controls-Zu1FzH6z.js → save-bar-controls-Cqgb-jqa.js} +1 -1
  52. package/dist/gateway/static/root/assets/{schedule-field-BW78mKc0.js → schedule-field-DVZcI8Yt.js} +1 -1
  53. package/dist/gateway/static/root/assets/{schema-form-Cc-IOydE.js → schema-form-Bj7sOxC8.js} +1 -1
  54. package/dist/gateway/static/root/assets/sessions-page-Bi2wkBzU.js +1 -0
  55. package/dist/gateway/static/root/assets/settings-advanced-gate-B1L3G4IA.js +1 -0
  56. package/dist/gateway/static/root/assets/{settings-collapsible-section-DIpIYht_.js → settings-collapsible-section-BmXn-8N6.js} +1 -1
  57. package/dist/gateway/static/root/assets/{settings-form-section-BFxBNxOG.js → settings-form-section-BnqYMWHR.js} +1 -1
  58. package/dist/gateway/static/root/assets/settings-page-BfRSHJmO.js +1 -0
  59. package/dist/gateway/static/root/assets/{settings-page-layout-CLx4o2PN.js → settings-page-layout-CdWZU1hd.js} +1 -1
  60. package/dist/gateway/static/root/assets/setup-status-panel-CWtPM7RK.js +1 -0
  61. package/dist/gateway/static/root/assets/{share-preview-page-ZswWCrDu.js → share-preview-page-IB1v8i86.js} +1 -1
  62. package/dist/gateway/static/root/assets/shares-settings-ngbsBgij.js +1 -0
  63. package/dist/gateway/static/root/assets/skill-reload-api-BIe442Gv.js +1 -0
  64. package/dist/gateway/static/root/assets/skills-page-BfchZRVa.js +2 -0
  65. package/dist/gateway/static/root/assets/{system-settings-panel-3ZNcGRhS.js → system-settings-panel-BxQ384RC.js} +1 -1
  66. package/dist/gateway/static/root/assets/{typed-models-lib-bpzZjiVF.js → typed-models-lib-BkcpvFYO.js} +1 -1
  67. package/dist/gateway/static/root/assets/{use-channel-catalog-BCjZLZ3O.js → use-channel-catalog-Cd0FaEQ4.js} +1 -1
  68. package/dist/gateway/static/root/assets/{user-profile-settings-panel-CIXafITi.js → user-profile-settings-panel-DQ7NnRSY.js} +1 -1
  69. package/dist/gateway/static/root/assets/{utils-DXMtz5j_.js → utils-YKhVf7Ka.js} +1 -1
  70. package/dist/gateway/static/root/assets/voice-api-key-field-C5Ov8Uk_.js +1 -0
  71. package/dist/gateway/static/root/assets/workflow-run-setup-panel-BYD9BtOq.js +3 -0
  72. package/dist/gateway/static/root/assets/{workflow-start-dialog-B4sZpTDQ.js → workflow-start-dialog-BNJVCWoS.js} +1 -1
  73. package/dist/gateway/static/root/assets/workflows-page-BYF29ANm.js +18 -0
  74. package/dist/gateway/static/root/index.html +5 -5
  75. package/dist/package.js +1 -1
  76. package/dist/src/agent/agent-manager.d.ts +6 -1
  77. package/dist/src/agent/agent-manager.js +28 -12
  78. package/dist/src/agent/agent-manager.js.map +1 -1
  79. package/dist/src/agent/context/workspace-templates/AGENTS.md +1 -1
  80. package/dist/src/agent/embedded/xopc-tools-bridge.js +11 -7
  81. package/dist/src/agent/embedded/xopc-tools-bridge.js.map +1 -1
  82. package/dist/src/agent/lifecycle/progress.js +3 -1
  83. package/dist/src/agent/lifecycle/progress.js.map +1 -1
  84. package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +2 -2
  85. package/dist/src/agent/lifecycle/timeout-wrapper.js +4 -4
  86. package/dist/src/agent/lifecycle/timeout-wrapper.js.map +1 -1
  87. package/dist/src/agent/memory/summary-generator.d.ts +1 -1
  88. package/dist/src/agent/memory/summary-generator.js +1 -2
  89. package/dist/src/agent/memory/summary-generator.js.map +1 -1
  90. package/dist/src/agent/middleware/index.d.ts +1 -1
  91. package/dist/src/agent/middleware/self-verify.d.ts +44 -14
  92. package/dist/src/agent/middleware/self-verify.js +214 -44
  93. package/dist/src/agent/middleware/self-verify.js.map +1 -1
  94. package/dist/src/agent/orchestration/agent-event-handler.js +57 -15
  95. package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
  96. package/dist/src/agent/prompt/sections/tooling.js +18 -13
  97. package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
  98. package/dist/src/agent/prompt/system-reminder.js +2 -2
  99. package/dist/src/agent/prompt/system-reminder.js.map +1 -1
  100. package/dist/src/agent/sandbox/sanitize-env-vars.d.ts +2 -2
  101. package/dist/src/agent/sandbox/sanitize-env-vars.js +2 -2
  102. package/dist/src/agent/sandbox/sanitize-env-vars.js.map +1 -1
  103. package/dist/src/agent/sandbox/types.d.ts +2 -2
  104. package/dist/src/agent/sandbox/types.js.map +1 -1
  105. package/dist/src/agent/service/btw-query.js +1 -1
  106. package/dist/src/agent/service/btw-query.js.map +1 -1
  107. package/dist/src/agent/service/process-direct-one-shot.js +6 -2
  108. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  109. package/dist/src/agent/service/process-direct-streaming.js +12 -7
  110. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  111. package/dist/src/agent/service.js +2 -1
  112. package/dist/src/agent/service.js.map +1 -1
  113. package/dist/src/agent/skills/skill-tool-gating.js +1 -1
  114. package/dist/src/agent/skills/skill-tool-gating.js.map +1 -1
  115. package/dist/src/agent/starter-agents.js +9 -9
  116. package/dist/src/agent/starter-agents.js.map +1 -1
  117. package/dist/src/agent/tools/apply-patch.d.ts +25 -0
  118. package/dist/src/agent/tools/apply-patch.js +256 -0
  119. package/dist/src/agent/tools/apply-patch.js.map +1 -0
  120. package/dist/src/agent/tools/delegate-tool.d.ts +1 -1
  121. package/dist/src/agent/tools/delegate-tool.js +3 -3
  122. package/dist/src/agent/tools/delegate-tool.js.map +1 -1
  123. package/dist/src/agent/tools/exec-command.d.ts +30 -0
  124. package/dist/src/agent/tools/exec-command.js +224 -0
  125. package/dist/src/agent/tools/exec-command.js.map +1 -0
  126. package/dist/src/agent/tools/execute-code-tool.js +7 -4
  127. package/dist/src/agent/tools/execute-code-tool.js.map +1 -1
  128. package/dist/src/agent/tools/factory.d.ts +3 -3
  129. package/dist/src/agent/tools/factory.js +7 -8
  130. package/dist/src/agent/tools/factory.js.map +1 -1
  131. package/dist/src/agent/tools/index.d.ts +3 -2
  132. package/dist/src/agent/tools/index.js +5 -4
  133. package/dist/src/agent/tools/skills-tools.d.ts +1 -1
  134. package/dist/src/agent/tools/skills-tools.js.map +1 -1
  135. package/dist/src/agent/tools/update-plan-tool.d.ts +11 -0
  136. package/dist/src/agent/tools/update-plan-tool.js +72 -0
  137. package/dist/src/agent/tools/update-plan-tool.js.map +1 -0
  138. package/dist/src/agent/workflow/builtins/debug-incident.d.ts +1 -1
  139. package/dist/src/agent/workflow/builtins/debug-incident.js +1 -1
  140. package/dist/src/agent/workflow/builtins/debug-incident.js.map +1 -1
  141. package/dist/src/agent/workflow/builtins/pr-review.d.ts +1 -1
  142. package/dist/src/agent/workflow/builtins/pr-review.js +1 -1
  143. package/dist/src/agent/workflow/builtins/pr-review.js.map +1 -1
  144. package/dist/src/agent/workflow/builtins/release-check.d.ts +1 -1
  145. package/dist/src/agent/workflow/builtins/release-check.js +1 -1
  146. package/dist/src/agent/workflow/builtins/release-check.js.map +1 -1
  147. package/dist/src/agent/workflow/step-labels.js +7 -3
  148. package/dist/src/agent/workflow/step-labels.js.map +1 -1
  149. package/dist/src/chat-commands/agent-edit.js +1 -1
  150. package/dist/src/chat-commands/agent-edit.js.map +1 -1
  151. package/dist/src/chat-commands/builtins/review.d.ts +1 -0
  152. package/dist/src/chat-commands/builtins/review.js +167 -0
  153. package/dist/src/chat-commands/builtins/review.js.map +1 -0
  154. package/dist/src/chat-commands/index.d.ts +1 -0
  155. package/dist/src/chat-commands/index.js +3 -1
  156. package/dist/src/chat-commands/index.js.map +1 -1
  157. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  158. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  159. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  160. package/dist/src/gateway/agent-builtin-tools.js +3 -2
  161. package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
  162. package/dist/src/gateway/chat-stream/mapper.d.ts +6 -0
  163. package/dist/src/gateway/chat-stream/mapper.js +149 -6
  164. package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
  165. package/dist/src/gateway/chat-stream/protocol.d.ts +51 -1
  166. package/dist/src/gateway/hono/routes/commands-skills.js +21 -0
  167. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  168. package/dist/src/gateway/hono/routes/index.js +2 -0
  169. package/dist/src/gateway/hono/routes/index.js.map +1 -1
  170. package/dist/src/gateway/hono/routes/lazy-bundles.js +1 -0
  171. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  172. package/dist/src/gateway/hono/routes/projects.js +40 -2
  173. package/dist/src/gateway/hono/routes/projects.js.map +1 -1
  174. package/dist/src/gateway/hono/routes/search.d.ts +3 -0
  175. package/dist/src/gateway/hono/routes/search.js +47 -0
  176. package/dist/src/gateway/hono/routes/search.js.map +1 -0
  177. package/dist/src/gateway/security/dangerous-tools.js +1 -1
  178. package/dist/src/gateway/security/dangerous-tools.js.map +1 -1
  179. package/dist/src/infra/update-restart.js +1 -1
  180. package/dist/src/mcp/channel-bridge.js +1 -1
  181. package/dist/src/projects/index.d.ts +2 -0
  182. package/dist/src/projects/index.js +3 -1
  183. package/dist/src/projects/project-agent-suggestion.d.ts +14 -0
  184. package/dist/src/projects/project-agent-suggestion.js +19 -0
  185. package/dist/src/projects/project-agent-suggestion.js.map +1 -0
  186. package/dist/src/projects/project-kind.d.ts +13 -0
  187. package/dist/src/projects/project-kind.js +147 -0
  188. package/dist/src/projects/project-kind.js.map +1 -0
  189. package/dist/src/projects/project-service.d.ts +1 -0
  190. package/dist/src/projects/project-service.js +1 -1
  191. package/dist/src/projects/project-service.js.map +1 -1
  192. package/dist/src/projects/project-store.js +32 -8
  193. package/dist/src/projects/project-store.js.map +1 -1
  194. package/dist/src/projects/types.d.ts +1 -0
  195. package/dist/src/review/review-git.d.ts +48 -0
  196. package/dist/src/review/review-git.js +333 -0
  197. package/dist/src/review/review-git.js.map +1 -0
  198. package/dist/src/review/review-types.d.ts +22 -0
  199. package/dist/src/review/review-types.js +29 -0
  200. package/dist/src/review/review-types.js.map +1 -0
  201. package/dist/src/session/session-context-for-llm.js +151 -0
  202. package/dist/src/session/session-context-for-llm.js.map +1 -1
  203. package/dist/src/storage/sqlite/migrations/021_projects_fts.sql +21 -0
  204. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  205. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  206. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  207. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  208. package/dist/src/storage/sqlite/schema.js +1 -1
  209. package/dist/src/tui/backends/embedded-backend.d.ts +1 -0
  210. package/dist/src/tui/backends/embedded-backend.js +20 -0
  211. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  212. package/dist/src/tui/backends/gateway-sse-backend.d.ts +2 -0
  213. package/dist/src/tui/backends/gateway-sse-backend.js +7 -0
  214. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  215. package/dist/src/tui/components/assistant-message.js +35 -0
  216. package/dist/src/tui/components/assistant-message.js.map +1 -1
  217. package/dist/src/tui/tui-agent-events.js +25 -0
  218. package/dist/src/tui/tui-agent-events.js.map +1 -1
  219. package/dist/src/tui/tui-backend.d.ts +4 -0
  220. package/dist/src/tui/tui-commands.d.ts +1 -0
  221. package/dist/src/tui/tui-commands.js +110 -4
  222. package/dist/src/tui/tui-commands.js.map +1 -1
  223. package/dist/src/tui/tui-picker-overlay.d.ts +2 -0
  224. package/dist/src/tui/tui-picker-overlay.js +153 -1
  225. package/dist/src/tui/tui-picker-overlay.js.map +1 -1
  226. package/dist/src/tui/tui.js +16 -3
  227. package/dist/src/tui/tui.js.map +1 -1
  228. package/package.json +1 -1
  229. package/dist/gateway/static/root/assets/agents-CxDSFHGx.js +0 -2
  230. package/dist/gateway/static/root/assets/apps-page-CyZdgqvm.js +0 -1
  231. package/dist/gateway/static/root/assets/automations-page-8VLKM4au.js +0 -1
  232. package/dist/gateway/static/root/assets/browser-settings-page-5tPg0DcP.js +0 -8
  233. package/dist/gateway/static/root/assets/capability-presets-settings-panel-BJW3aVST.js +0 -1
  234. package/dist/gateway/static/root/assets/channels-settings-CorUCTrs.js +0 -1
  235. package/dist/gateway/static/root/assets/connectors-page-VKstC3sP.js +0 -2
  236. package/dist/gateway/static/root/assets/gateway-settings-hQtgVmSR.js +0 -1
  237. package/dist/gateway/static/root/assets/goal-detail-page-FEypCq74.js +0 -1
  238. package/dist/gateway/static/root/assets/goals-page-C4-2_MLG.js +0 -2
  239. package/dist/gateway/static/root/assets/heartbeat-settings-BJVok3Sl.js +0 -1
  240. package/dist/gateway/static/root/assets/index-T0SaNd5a.js +0 -191
  241. package/dist/gateway/static/root/assets/logs-page-DwkwPgid.js +0 -2
  242. package/dist/gateway/static/root/assets/messages-avfvyZuQ.js +0 -3
  243. package/dist/gateway/static/root/assets/models-hub-panel-huNY4A1G.js +0 -2
  244. package/dist/gateway/static/root/assets/notes-page-DdfGuEZ1.js +0 -1
  245. package/dist/gateway/static/root/assets/notes-workbench-B0bT9Hqa.js +0 -2
  246. package/dist/gateway/static/root/assets/project-detail-page-CjxhPorG.js +0 -1
  247. package/dist/gateway/static/root/assets/projects-page-C4Z5OJMF.js +0 -1
  248. package/dist/gateway/static/root/assets/remote-access-hub-CVCOPUVd.js +0 -1
  249. package/dist/gateway/static/root/assets/sessions-page-B4qExXHC.js +0 -1
  250. package/dist/gateway/static/root/assets/settings-advanced-gate-Ce8yLTBi.js +0 -1
  251. package/dist/gateway/static/root/assets/settings-page-C4fivemT.js +0 -1
  252. package/dist/gateway/static/root/assets/setup-status-panel-Kyc4eUf0.js +0 -1
  253. package/dist/gateway/static/root/assets/shares-settings-Bu76CMiC.js +0 -1
  254. package/dist/gateway/static/root/assets/skill-reload-api-D-CFg86j.js +0 -1
  255. package/dist/gateway/static/root/assets/skills-page-CUU4f6Ss.js +0 -2
  256. package/dist/gateway/static/root/assets/voice-api-key-field-C1MrQD8R.js +0 -1
  257. package/dist/gateway/static/root/assets/workflow-run-setup-panel-DqizIcY5.js +0 -3
  258. package/dist/gateway/static/root/assets/workflows-page-B3sVNPFk.js +0 -18
  259. package/dist/src/agent/tools/edit.d.ts +0 -14
  260. package/dist/src/agent/tools/edit.js +0 -132
  261. package/dist/src/agent/tools/edit.js.map +0 -1
  262. package/dist/src/agent/tools/shell.d.ts +0 -15
  263. package/dist/src/agent/tools/shell.js +0 -158
  264. package/dist/src/agent/tools/shell.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, GREP_MAX_LINE_LENGTH, formatSize, truncateHead, truncateLine, truncateTail } from "./truncate.js";
2
2
  import { createReadFileTool } from "./read.js";
3
3
  import { createWriteFileTool, writeFileTool } from "./write.js";
4
- import { fuzzyFindText, generateDiffString, normalizeForFuzzyMatch, normalizeToLF, restoreLineEndings, stripBom } from "./edit-diff.js";
5
- import { createEditFileTool, editFileTool } from "./edit.js";
6
4
  import { createListDirTool, listDirTool } from "./list-dir.js";
7
- import { createShellTool } from "./shell.js";
5
+ import { createExecCommandTool } from "./exec-command.js";
6
+ import { fuzzyFindText, generateDiffString, normalizeForFuzzyMatch, normalizeToLF, restoreLineEndings, stripBom } from "./edit-diff.js";
7
+ import { createApplyPatchTool } from "./apply-patch.js";
8
8
  import { createMemoryGetTool, createMemorySearchTool } from "./memory-tool.js";
9
9
  import { createCuratedMemoryTool } from "./curated-memory-tool.js";
10
10
  import { createSessionSearchTool } from "./session-search-tool.js";
@@ -18,6 +18,7 @@ import { createSendMediaTool } from "./send-media.js";
18
18
  import { createReadMediaTool } from "./media-read-tool.js";
19
19
  import { createCreateShareTool, isShareToolAvailable } from "./create-share-tool.js";
20
20
  import { TodoStore, createTodoTool } from "./todo-tool.js";
21
+ import { createUpdatePlanTool } from "./update-plan-tool.js";
21
22
  import { createSessionStatusTool } from "./session-status-tool.js";
22
23
  import { createDreamingTool } from "./dreaming-tool.js";
23
24
  import { createClarifyTool } from "./clarify-tool.js";
@@ -35,4 +36,4 @@ import { createToolManualTool } from "./tool-manual-tool.js";
35
36
  import { resolveImageModelConfigForTool } from "../image/tool-model-config.js";
36
37
  import { createImageTool } from "./image-tool.js";
37
38
  import { createImageGenerateTool, resolveImageGenerationModelConfigForTool } from "./image-generate-tool.js";
38
- export { BrowserManager, DEFAULT_DELEGATE_TOOLS, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_WEB_EXTRACT_MAX_LENGTH, DELEGATE_BLOCKED_TOOLS, GREP_MAX_LINE_LENGTH, MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT, SANDBOX_ALLOWED_TOOLS, TodoStore, assertBrowserUrlAllowed, buildSandboxToolMap, createAutomationTool, createClarifyTool, createComposioExecuteTool, createCreateShareTool, createCuratedMemoryTool, createDelegateTool, createDreamingTool, createEditFileTool, createExecuteCodeTool, createFindTool, createGoalTool, createGrepTool, createImageGenerateTool, createImageTool, createListDirTool, createMemoryGetTool, createMemorySearchTool, createMessageTool, createReadFileTool, createReadMediaTool, createSendMediaTool, createSessionSearchTool, createSessionStatusTool, createShellTool, createSkillManageTool, createSkillViewTool, createSkillsListTool, createTodoTool, createToolManualTool, createWebExtractTool, createWebFetchTool, createWebSearchTool, createWorkflowTool, createWriteFileTool, editFileTool, findTool, formatSize, fuzzyFindText, generateDiffString, grepTool, isShareToolAvailable, listDirTool, normalizeForFuzzyMatch, normalizeToLF, resolveImageGenerationModelConfigForTool, resolveImageModelConfigForTool, restoreLineEndings, stripBom, stripHtmlBoilerplate, truncateHead, truncateLine, truncateTail, writeFileTool };
39
+ export { BrowserManager, DEFAULT_DELEGATE_TOOLS, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_WEB_EXTRACT_MAX_LENGTH, DELEGATE_BLOCKED_TOOLS, GREP_MAX_LINE_LENGTH, MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT, SANDBOX_ALLOWED_TOOLS, TodoStore, assertBrowserUrlAllowed, buildSandboxToolMap, createApplyPatchTool, createAutomationTool, createClarifyTool, createComposioExecuteTool, createCreateShareTool, createCuratedMemoryTool, createDelegateTool, createDreamingTool, createExecCommandTool, createExecuteCodeTool, createFindTool, createGoalTool, createGrepTool, createImageGenerateTool, createImageTool, createListDirTool, createMemoryGetTool, createMemorySearchTool, createMessageTool, createReadFileTool, createReadMediaTool, createSendMediaTool, createSessionSearchTool, createSessionStatusTool, createSkillManageTool, createSkillViewTool, createSkillsListTool, createTodoTool, createToolManualTool, createUpdatePlanTool, createWebExtractTool, createWebFetchTool, createWebSearchTool, createWorkflowTool, createWriteFileTool, findTool, formatSize, fuzzyFindText, generateDiffString, grepTool, isShareToolAvailable, listDirTool, normalizeForFuzzyMatch, normalizeToLF, resolveImageGenerationModelConfigForTool, resolveImageModelConfigForTool, restoreLineEndings, stripBom, stripHtmlBoilerplate, truncateHead, truncateLine, truncateTail, writeFileTool };
@@ -6,7 +6,7 @@ export interface SkillsToolsDeps {
6
6
  registeredToolNames: string[];
7
7
  skillAllowlist?: string[];
8
8
  } | undefined;
9
- /** Register declared env var names for shell / tool passthrough (values never exposed). */
9
+ /** Register declared env var names for command/tool passthrough (values never exposed). */
10
10
  registerSkillEnvPassthrough?: (names: string[]) => void;
11
11
  }
12
12
  export declare function createSkillsListTool(deps: SkillsToolsDeps): AgentTool;
@@ -1 +1 @@
1
- {"version":3,"file":"skills-tools.js","names":[],"sources":["../../../../src/agent/tools/skills-tools.ts"],"sourcesContent":["import { readFileSync, statSync } from 'fs';\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\n\nimport { resolveStateDir } from '../../config/paths.js';\nimport { createSkillConfigManager, isSkillEnabled, resolveSkillConfig } from '../skills/config.js';\nimport { resolveSkillReadablePath } from '../skills/skill-view-path.js';\nimport type { SkillManager } from '../skills/skill-manager.js';\nimport { truncateHead, formatSize, DEFAULT_MAX_BYTES } from './truncate.js';\n\nconst DEFAULT_MAX_LINES = 500;\nconst DEFAULT_MAX_SKILL_FILE_BYTES = 1_048_576;\n\nconst SkillsListSchema = Type.Object({\n query: Type.Optional(\n Type.String({\n description: 'Optional case-insensitive substring filter on skill name and description',\n }),\n ),\n});\n\nconst SkillViewSchema = Type.Object({\n name: Type.String({ description: 'Skill name (as in <available_skills> / skills_list)' }),\n path: Type.Optional(\n Type.String({\n description:\n 'Relative path inside the skill dir: omit for SKILL.md, or e.g. references/doc.md (only references/, templates/, scripts/, assets/)',\n }),\n ),\n limit: Type.Optional(\n Type.Number({ description: 'Max lines to return (default 500, like read_file)' }),\n ),\n});\n\nexport interface SkillsToolsDeps {\n getSkillManager: () => SkillManager | undefined;\n getSkillIndexingContext?: () =>\n | { registeredToolNames: string[]; skillAllowlist?: string[] }\n | undefined;\n /** Register declared env var names for shell / tool passthrough (values never exposed). */\n registerSkillEnvPassthrough?: (names: string[]) => void;\n}\n\nfunction maxSkillBytes(): number {\n const lim = createSkillConfigManager(resolveStateDir()).load().limits?.maxSkillFileBytes;\n return typeof lim === 'number' && lim > 0 ? lim : DEFAULT_MAX_SKILL_FILE_BYTES;\n}\n\nexport function createSkillsListTool(deps: SkillsToolsDeps): AgentTool {\n return {\n name: 'skills_list',\n label: '📚 Skills',\n description:\n 'List available skills (name and description only). Use skill_view(name) to load SKILL.md or a file under references/, templates/, scripts/, or assets/.',\n parameters: SkillsListSchema,\n async execute(\n _toolCallId: string,\n params: any,\n ): Promise<AgentToolResult<{}>> {\n const mgr = deps.getSkillManager();\n if (!mgr) {\n return {\n content: [{ type: 'text', text: 'Skills are not available in this runtime context.' }],\n details: {},\n };\n }\n\n const idx = deps.getSkillIndexingContext?.();\n let skills = mgr.getEnabledSkillsForAgentSession({\n skillAllowlist: idx?.skillAllowlist,\n registeredToolNames: idx?.registeredToolNames,\n });\n const q = (params as { query?: string }).query?.trim().toLowerCase();\n if (q) {\n skills = skills.filter(\n (s) =>\n s.name.toLowerCase().includes(q) || s.description.toLowerCase().includes(q),\n );\n }\n\n const payload = {\n skills: skills.map((s) => ({\n name: s.name,\n description: s.description,\n source: s.source,\n })),\n };\n\n return {\n content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }],\n details: {},\n };\n },\n } as any;\n}\n\nexport function createSkillViewTool(deps: SkillsToolsDeps): AgentTool {\n return {\n name: 'skill_view',\n label: '📖 Skill',\n description:\n 'Load a skill\\'s SKILL.md (default) or a supporting file under references/, templates/, scripts/, or assets/.',\n parameters: SkillViewSchema,\n async execute(\n _toolCallId: string,\n params: any,\n ): Promise<AgentToolResult<{}>> {\n const p = params as { name: string; path?: string; limit?: number };\n const mgr = deps.getSkillManager();\n if (!mgr) {\n return {\n content: [{ type: 'text', text: 'Skills are not available in this runtime context.' }],\n details: {},\n };\n }\n\n const skill = mgr.findSkill(p.name.trim());\n if (!skill) {\n return {\n content: [\n {\n type: 'text',\n text: `Skill \"${p.name}\" was not found. It may not be installed. Open the Skills library to install it, or use skills_list to see available names.`,\n },\n ],\n details: { errorCode: 'skill_not_found', skillName: p.name },\n };\n }\n\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const skillConfig = resolveSkillConfig(skill, skillsConfig);\n if (skillConfig.enabled === false) {\n return {\n content: [\n {\n type: 'text',\n text: `Skill \"${skill.name}\" is installed but disabled. Enable it in Skills settings before using it.`,\n },\n ],\n details: { errorCode: 'skill_disabled', skillName: skill.name },\n };\n }\n if (skill.disableModelInvocation) {\n return {\n content: [{ type: 'text', text: `Skill \"${skill.name}\" is installed, but it is not available for model invocation.` }],\n details: { errorCode: 'skill_model_invocation_disabled', skillName: skill.name },\n };\n }\n if (!isSkillEnabled(skill, skillsConfig)) {\n return {\n content: [{ type: 'text', text: `Skill \"${skill.name}\" is installed, but its requirements are not met.` }],\n details: { errorCode: 'skill_requirements_unmet', skillName: skill.name },\n };\n }\n\n const idx = deps.getSkillIndexingContext?.();\n const visible = mgr.getEnabledSkillsForAgentSession({\n skillAllowlist: idx?.skillAllowlist,\n registeredToolNames: idx?.registeredToolNames,\n });\n if (!visible.some((s) => s.name === skill.name)) {\n return {\n content: [\n {\n type: 'text',\n text: `The current agent cannot use skill \"${skill.name}\". It is installed, but it is not in this agent's skill allowlist or is hidden by tool gating. Enable it in Agent settings → Skills before using it.`,\n },\n ],\n details: { errorCode: 'skill_agent_denied', skillName: skill.name },\n };\n }\n\n const resolved = resolveSkillReadablePath(skill, p.path);\n if (resolved.ok === false) {\n return { content: [{ type: 'text', text: resolved.error }], details: {} };\n }\n\n const maxBytes = maxSkillBytes();\n try {\n const st = statSync(resolved.absolutePath);\n if (st.size > maxBytes) {\n return {\n content: [\n {\n type: 'text',\n text: `File too large: ${formatSize(st.size)} (limit ${formatSize(maxBytes)})`,\n },\n ],\n details: {},\n };\n }\n\n const raw = readFileSync(resolved.absolutePath, 'utf-8');\n const truncation = truncateHead(raw, {\n maxLines: p.limit ?? DEFAULT_MAX_LINES,\n maxBytes: DEFAULT_MAX_BYTES,\n });\n\n let outputText = truncation.content;\n if (truncation.truncated) {\n if (truncation.firstLineExceedsLimit) {\n outputText = `(Line exceeds ${formatSize(DEFAULT_MAX_BYTES)})`;\n } else {\n outputText += `\\n\\n[${truncation.outputLines}/${truncation.totalLines} lines]`;\n }\n }\n\n const envNames = skill.requiredEnvVarNames;\n if (envNames?.length && deps.registerSkillEnvPassthrough) {\n deps.registerSkillEnvPassthrough(envNames);\n const setNow = envNames.filter((k) => process.env[k] !== undefined).length;\n outputText += `\\n\\n[skill env passthrough] Registered ${envNames.length} declared variable name(s) for this session; ${setNow} are currently defined in the process (values are never shown).`;\n }\n\n return { content: [{ type: 'text', text: outputText }], details: {} };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error: ${e instanceof Error ? e.message : String(e)}` }],\n details: {},\n };\n }\n },\n } as any;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"skills-tools.js","names":[],"sources":["../../../../src/agent/tools/skills-tools.ts"],"sourcesContent":["import { readFileSync, statSync } from 'fs';\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\n\nimport { resolveStateDir } from '../../config/paths.js';\nimport { createSkillConfigManager, isSkillEnabled, resolveSkillConfig } from '../skills/config.js';\nimport { resolveSkillReadablePath } from '../skills/skill-view-path.js';\nimport type { SkillManager } from '../skills/skill-manager.js';\nimport { truncateHead, formatSize, DEFAULT_MAX_BYTES } from './truncate.js';\n\nconst DEFAULT_MAX_LINES = 500;\nconst DEFAULT_MAX_SKILL_FILE_BYTES = 1_048_576;\n\nconst SkillsListSchema = Type.Object({\n query: Type.Optional(\n Type.String({\n description: 'Optional case-insensitive substring filter on skill name and description',\n }),\n ),\n});\n\nconst SkillViewSchema = Type.Object({\n name: Type.String({ description: 'Skill name (as in <available_skills> / skills_list)' }),\n path: Type.Optional(\n Type.String({\n description:\n 'Relative path inside the skill dir: omit for SKILL.md, or e.g. references/doc.md (only references/, templates/, scripts/, assets/)',\n }),\n ),\n limit: Type.Optional(\n Type.Number({ description: 'Max lines to return (default 500, like read_file)' }),\n ),\n});\n\nexport interface SkillsToolsDeps {\n getSkillManager: () => SkillManager | undefined;\n getSkillIndexingContext?: () =>\n | { registeredToolNames: string[]; skillAllowlist?: string[] }\n | undefined;\n /** Register declared env var names for command/tool passthrough (values never exposed). */\n registerSkillEnvPassthrough?: (names: string[]) => void;\n}\n\nfunction maxSkillBytes(): number {\n const lim = createSkillConfigManager(resolveStateDir()).load().limits?.maxSkillFileBytes;\n return typeof lim === 'number' && lim > 0 ? lim : DEFAULT_MAX_SKILL_FILE_BYTES;\n}\n\nexport function createSkillsListTool(deps: SkillsToolsDeps): AgentTool {\n return {\n name: 'skills_list',\n label: '📚 Skills',\n description:\n 'List available skills (name and description only). Use skill_view(name) to load SKILL.md or a file under references/, templates/, scripts/, or assets/.',\n parameters: SkillsListSchema,\n async execute(\n _toolCallId: string,\n params: any,\n ): Promise<AgentToolResult<{}>> {\n const mgr = deps.getSkillManager();\n if (!mgr) {\n return {\n content: [{ type: 'text', text: 'Skills are not available in this runtime context.' }],\n details: {},\n };\n }\n\n const idx = deps.getSkillIndexingContext?.();\n let skills = mgr.getEnabledSkillsForAgentSession({\n skillAllowlist: idx?.skillAllowlist,\n registeredToolNames: idx?.registeredToolNames,\n });\n const q = (params as { query?: string }).query?.trim().toLowerCase();\n if (q) {\n skills = skills.filter(\n (s) =>\n s.name.toLowerCase().includes(q) || s.description.toLowerCase().includes(q),\n );\n }\n\n const payload = {\n skills: skills.map((s) => ({\n name: s.name,\n description: s.description,\n source: s.source,\n })),\n };\n\n return {\n content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }],\n details: {},\n };\n },\n } as any;\n}\n\nexport function createSkillViewTool(deps: SkillsToolsDeps): AgentTool {\n return {\n name: 'skill_view',\n label: '📖 Skill',\n description:\n 'Load a skill\\'s SKILL.md (default) or a supporting file under references/, templates/, scripts/, or assets/.',\n parameters: SkillViewSchema,\n async execute(\n _toolCallId: string,\n params: any,\n ): Promise<AgentToolResult<{}>> {\n const p = params as { name: string; path?: string; limit?: number };\n const mgr = deps.getSkillManager();\n if (!mgr) {\n return {\n content: [{ type: 'text', text: 'Skills are not available in this runtime context.' }],\n details: {},\n };\n }\n\n const skill = mgr.findSkill(p.name.trim());\n if (!skill) {\n return {\n content: [\n {\n type: 'text',\n text: `Skill \"${p.name}\" was not found. It may not be installed. Open the Skills library to install it, or use skills_list to see available names.`,\n },\n ],\n details: { errorCode: 'skill_not_found', skillName: p.name },\n };\n }\n\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const skillConfig = resolveSkillConfig(skill, skillsConfig);\n if (skillConfig.enabled === false) {\n return {\n content: [\n {\n type: 'text',\n text: `Skill \"${skill.name}\" is installed but disabled. Enable it in Skills settings before using it.`,\n },\n ],\n details: { errorCode: 'skill_disabled', skillName: skill.name },\n };\n }\n if (skill.disableModelInvocation) {\n return {\n content: [{ type: 'text', text: `Skill \"${skill.name}\" is installed, but it is not available for model invocation.` }],\n details: { errorCode: 'skill_model_invocation_disabled', skillName: skill.name },\n };\n }\n if (!isSkillEnabled(skill, skillsConfig)) {\n return {\n content: [{ type: 'text', text: `Skill \"${skill.name}\" is installed, but its requirements are not met.` }],\n details: { errorCode: 'skill_requirements_unmet', skillName: skill.name },\n };\n }\n\n const idx = deps.getSkillIndexingContext?.();\n const visible = mgr.getEnabledSkillsForAgentSession({\n skillAllowlist: idx?.skillAllowlist,\n registeredToolNames: idx?.registeredToolNames,\n });\n if (!visible.some((s) => s.name === skill.name)) {\n return {\n content: [\n {\n type: 'text',\n text: `The current agent cannot use skill \"${skill.name}\". It is installed, but it is not in this agent's skill allowlist or is hidden by tool gating. Enable it in Agent settings → Skills before using it.`,\n },\n ],\n details: { errorCode: 'skill_agent_denied', skillName: skill.name },\n };\n }\n\n const resolved = resolveSkillReadablePath(skill, p.path);\n if (resolved.ok === false) {\n return { content: [{ type: 'text', text: resolved.error }], details: {} };\n }\n\n const maxBytes = maxSkillBytes();\n try {\n const st = statSync(resolved.absolutePath);\n if (st.size > maxBytes) {\n return {\n content: [\n {\n type: 'text',\n text: `File too large: ${formatSize(st.size)} (limit ${formatSize(maxBytes)})`,\n },\n ],\n details: {},\n };\n }\n\n const raw = readFileSync(resolved.absolutePath, 'utf-8');\n const truncation = truncateHead(raw, {\n maxLines: p.limit ?? DEFAULT_MAX_LINES,\n maxBytes: DEFAULT_MAX_BYTES,\n });\n\n let outputText = truncation.content;\n if (truncation.truncated) {\n if (truncation.firstLineExceedsLimit) {\n outputText = `(Line exceeds ${formatSize(DEFAULT_MAX_BYTES)})`;\n } else {\n outputText += `\\n\\n[${truncation.outputLines}/${truncation.totalLines} lines]`;\n }\n }\n\n const envNames = skill.requiredEnvVarNames;\n if (envNames?.length && deps.registerSkillEnvPassthrough) {\n deps.registerSkillEnvPassthrough(envNames);\n const setNow = envNames.filter((k) => process.env[k] !== undefined).length;\n outputText += `\\n\\n[skill env passthrough] Registered ${envNames.length} declared variable name(s) for this session; ${setNow} are currently defined in the process (values are never shown).`;\n }\n\n return { content: [{ type: 'text', text: outputText }], details: {} };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error: ${e instanceof Error ? e.message : String(e)}` }],\n details: {},\n };\n }\n },\n } as any;\n}\n"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { AgentTool } from '@earendil-works/pi-agent-core';
2
+ export type TurnPlanStatus = 'pending' | 'in_progress' | 'completed';
3
+ export interface TurnPlanStep {
4
+ step: string;
5
+ status: TurnPlanStatus;
6
+ }
7
+ export interface TurnPlanDetails {
8
+ explanation?: string;
9
+ plan: TurnPlanStep[];
10
+ }
11
+ export declare function createUpdatePlanTool(): AgentTool;
@@ -0,0 +1,72 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ //#region src/agent/tools/update-plan-tool.ts
3
+ const VALID_STATUSES = new Set([
4
+ "pending",
5
+ "in_progress",
6
+ "completed"
7
+ ]);
8
+ const PlanStepSchema = Type.Object({
9
+ step: Type.String({
10
+ minLength: 1,
11
+ description: "Short task step"
12
+ }),
13
+ status: Type.Union([
14
+ Type.Literal("pending"),
15
+ Type.Literal("in_progress"),
16
+ Type.Literal("completed")
17
+ ])
18
+ });
19
+ const UpdatePlanSchema = Type.Object({
20
+ explanation: Type.Optional(Type.String({ description: "Short reason for this plan update" })),
21
+ plan: Type.Array(PlanStepSchema, {
22
+ minItems: 1,
23
+ maxItems: 8,
24
+ description: "Full current plan. Exactly zero or one step may be in_progress."
25
+ })
26
+ });
27
+ function normalizePlan(raw) {
28
+ if (!Array.isArray(raw)) throw new Error("plan must be an array");
29
+ const plan = raw.map((item) => {
30
+ const rec = item && typeof item === "object" ? item : {};
31
+ const step = String(rec.step ?? "").trim();
32
+ const statusRaw = String(rec.status ?? "").trim();
33
+ if (!step) throw new Error("each plan item must include a non-empty step");
34
+ if (!VALID_STATUSES.has(statusRaw)) throw new Error(`invalid plan status: ${statusRaw || "(empty)"}`);
35
+ return {
36
+ step,
37
+ status: statusRaw
38
+ };
39
+ });
40
+ if (plan.filter((item) => item.status === "in_progress").length > 1) throw new Error("at most one plan item may be in_progress");
41
+ return plan;
42
+ }
43
+ function formatPlan(details) {
44
+ const lines = details.plan.map((item) => `- [${item.status}] ${item.step}`);
45
+ return [details.explanation?.trim(), ...lines].filter(Boolean).join("\n");
46
+ }
47
+ function createUpdatePlanTool() {
48
+ return {
49
+ name: "update_plan",
50
+ label: "Update Plan",
51
+ description: "Update the current coding-task plan. Use for multi-step implementation, review, or debugging work. Keep the full plan current, with at most one step marked in_progress.",
52
+ parameters: UpdatePlanSchema,
53
+ async execute(_toolCallId, params) {
54
+ const rec = params;
55
+ const details = {
56
+ explanation: typeof rec.explanation === "string" && rec.explanation.trim() ? rec.explanation.trim() : void 0,
57
+ plan: normalizePlan(rec.plan)
58
+ };
59
+ return {
60
+ content: [{
61
+ type: "text",
62
+ text: formatPlan(details)
63
+ }],
64
+ details
65
+ };
66
+ }
67
+ };
68
+ }
69
+ //#endregion
70
+ export { createUpdatePlanTool };
71
+
72
+ //# sourceMappingURL=update-plan-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-plan-tool.js","names":[],"sources":["../../../../src/agent/tools/update-plan-tool.ts"],"sourcesContent":["import { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\n\nexport type TurnPlanStatus = 'pending' | 'in_progress' | 'completed';\n\nexport interface TurnPlanStep {\n step: string;\n status: TurnPlanStatus;\n}\n\nexport interface TurnPlanDetails {\n explanation?: string;\n plan: TurnPlanStep[];\n}\n\nconst VALID_STATUSES = new Set<TurnPlanStatus>(['pending', 'in_progress', 'completed']);\n\nconst PlanStepSchema = Type.Object({\n step: Type.String({ minLength: 1, description: 'Short task step' }),\n status: Type.Union([\n Type.Literal('pending'),\n Type.Literal('in_progress'),\n Type.Literal('completed'),\n ]),\n});\n\nconst UpdatePlanSchema = Type.Object({\n explanation: Type.Optional(Type.String({ description: 'Short reason for this plan update' })),\n plan: Type.Array(PlanStepSchema, {\n minItems: 1,\n maxItems: 8,\n description: 'Full current plan. Exactly zero or one step may be in_progress.',\n }),\n});\n\nfunction normalizePlan(raw: unknown): TurnPlanStep[] {\n if (!Array.isArray(raw)) {\n throw new Error('plan must be an array');\n }\n const plan = raw.map((item) => {\n const rec = item && typeof item === 'object' ? item as Record<string, unknown> : {};\n const step = String(rec.step ?? '').trim();\n const statusRaw = String(rec.status ?? '').trim();\n if (!step) {\n throw new Error('each plan item must include a non-empty step');\n }\n if (!VALID_STATUSES.has(statusRaw as TurnPlanStatus)) {\n throw new Error(`invalid plan status: ${statusRaw || '(empty)'}`);\n }\n return { step, status: statusRaw as TurnPlanStatus };\n });\n\n const active = plan.filter((item) => item.status === 'in_progress');\n if (active.length > 1) {\n throw new Error('at most one plan item may be in_progress');\n }\n return plan;\n}\n\nfunction formatPlan(details: TurnPlanDetails): string {\n const lines = details.plan.map((item) => `- [${item.status}] ${item.step}`);\n return [details.explanation?.trim(), ...lines].filter(Boolean).join('\\n');\n}\n\nexport function createUpdatePlanTool(): AgentTool {\n return {\n name: 'update_plan',\n label: 'Update Plan',\n description:\n 'Update the current coding-task plan. Use for multi-step implementation, review, or debugging work. ' +\n 'Keep the full plan current, with at most one step marked in_progress.',\n parameters: UpdatePlanSchema,\n async execute(_toolCallId, params): Promise<AgentToolResult<TurnPlanDetails>> {\n const rec = params as Record<string, unknown>;\n const details: TurnPlanDetails = {\n explanation: typeof rec.explanation === 'string' && rec.explanation.trim()\n ? rec.explanation.trim()\n : undefined,\n plan: normalizePlan(rec.plan),\n };\n return {\n content: [{ type: 'text', text: formatPlan(details) }],\n details,\n };\n },\n };\n}\n"],"mappings":";;AAeA,MAAM,iBAAiB,IAAI,IAAoB;CAAC;CAAW;CAAe;CAAY,CAAC;AAEvF,MAAM,iBAAiB,KAAK,OAAO;CACjC,MAAM,KAAK,OAAO;EAAE,WAAW;EAAG,aAAa;EAAmB,CAAC;CACnE,QAAQ,KAAK,MAAM;EACjB,KAAK,QAAQ,UAAU;EACvB,KAAK,QAAQ,cAAc;EAC3B,KAAK,QAAQ,YAAY;EAC1B,CAAC;CACH,CAAC;AAEF,MAAM,mBAAmB,KAAK,OAAO;CACnC,aAAa,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,qCAAqC,CAAC,CAAC;CAC7F,MAAM,KAAK,MAAM,gBAAgB;EAC/B,UAAU;EACV,UAAU;EACV,aAAa;EACd,CAAC;CACH,CAAC;AAEF,SAAS,cAAc,KAA8B;AACnD,KAAI,CAAC,MAAM,QAAQ,IAAI,CACrB,OAAM,IAAI,MAAM,wBAAwB;CAE1C,MAAM,OAAO,IAAI,KAAK,SAAS;EAC7B,MAAM,MAAM,QAAQ,OAAO,SAAS,WAAW,OAAkC,EAAE;EACnF,MAAM,OAAO,OAAO,IAAI,QAAQ,GAAG,CAAC,MAAM;EAC1C,MAAM,YAAY,OAAO,IAAI,UAAU,GAAG,CAAC,MAAM;AACjD,MAAI,CAAC,KACH,OAAM,IAAI,MAAM,+CAA+C;AAEjE,MAAI,CAAC,eAAe,IAAI,UAA4B,CAClD,OAAM,IAAI,MAAM,wBAAwB,aAAa,YAAY;AAEnE,SAAO;GAAE;GAAM,QAAQ;GAA6B;GACpD;AAGF,KADe,KAAK,QAAQ,SAAS,KAAK,WAAW,cAC3C,CAAC,SAAS,EAClB,OAAM,IAAI,MAAM,2CAA2C;AAE7D,QAAO;;AAGT,SAAS,WAAW,SAAkC;CACpD,MAAM,QAAQ,QAAQ,KAAK,KAAK,SAAS,MAAM,KAAK,OAAO,IAAI,KAAK,OAAO;AAC3E,QAAO,CAAC,QAAQ,aAAa,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK;;AAG3E,SAAgB,uBAAkC;AAChD,QAAO;EACL,MAAM;EACN,OAAO;EACP,aACE;EAEF,YAAY;EACZ,MAAM,QAAQ,aAAa,QAAmD;GAC5E,MAAM,MAAM;GACZ,MAAM,UAA2B;IAC/B,aAAa,OAAO,IAAI,gBAAgB,YAAY,IAAI,YAAY,MAAM,GACtE,IAAI,YAAY,MAAM,GACtB,KAAA;IACJ,MAAM,cAAc,IAAI,KAAK;IAC9B;AACD,UAAO;IACL,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM,WAAW,QAAQ;KAAE,CAAC;IACtD;IACD;;EAEJ"}
@@ -10,4 +10,4 @@
10
10
  * - logs: optional log excerpt
11
11
  * - context: optional extra context (what changed, when it started)
12
12
  */
13
- export declare const DEBUG_INCIDENT_SCRIPT = "export const meta = {\n name: 'debug_incident',\n description: 'Triage an error or log snippet with parallel hypotheses and ranked root-cause analysis.',\n whenToUse: 'User reports a bug, crash, error message, or unexpected behavior and wants systematic triage.',\n examplePrompts: [\n { field: 'error', text: 'Triage this stack trace from production' },\n { field: 'error', text: 'Why does the gateway return 502 after deploy?' },\n ],\n i18n: {\n zh: {\n description: '\u5BF9\u9519\u8BEF\u6216\u65E5\u5FD7\u7247\u6BB5\u505A\u5E76\u884C\u5047\u8BBE\u63A8\u6F14\uFF0C\u5E76\u6392\u5E8F\u6839\u56E0\u4E0E\u9A8C\u8BC1\u6B65\u9AA4\u3002',\n whenToUse: '\u7528\u6237\u62A5\u544A bug\u3001\u5D29\u6E83\u3001\u62A5\u9519\u6216\u5F02\u5E38\u884C\u4E3A\uFF0C\u9700\u8981\u7CFB\u7EDF\u5316\u6392\u67E5\u65F6\u3002',\n examplePrompts: [\n { field: 'error', text: '\u6392\u67E5\u751F\u4EA7\u73AF\u5883\u8FD9\u6761\u5806\u6808' },\n { field: 'error', text: '\u90E8\u7F72\u540E\u7F51\u5173\u8FD4\u56DE 502\uFF0C\u53EF\u80FD\u662F\u4EC0\u4E48\u539F\u56E0\uFF1F' },\n ],\n },\n },\n tags: ['debug', 'incident', 'troubleshooting'],\n estimatedAgents: { min: 7, max: 7 },\n phases: [\n { title: 'Triage' },\n { title: 'Hypotheses' },\n { title: 'Rank' },\n ],\n}\n\nconst READ_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'shell']\n\nconst error = args && typeof args === 'object' && args.error\n ? String(args.error)\n : 'Infer the primary error from the most recent user message or conversation context.'\n\nconst logs = args && typeof args === 'object' && args.logs\n ? String(args.logs)\n : ''\n\nconst context = args && typeof args === 'object' && args.context\n ? String(args.context)\n : ''\n\nphase('Triage')\nconst triage = await agent(\n 'Parse this incident signal. Extract: error type, likely subsystem, affected files/modules if identifiable, and 2\u20133 key facts from logs.\\n\\n' +\n 'ERROR:\\n' + error + '\\n\\n' +\n (logs ? 'LOGS:\\n' + logs + '\\n\\n' : '') +\n (context ? 'CONTEXT:\\n' + context + '\\n\\n' : '') +\n 'Use read/grep tools to locate relevant code if the workspace may contain the failing path.',\n {\n label: 'incident triage',\n toolset: READ_TOOLS,\n schema: {\n type: 'object',\n properties: {\n errorType: { type: 'string' },\n subsystem: { type: 'string' },\n affectedPaths: { type: 'array', items: { type: 'string' } },\n keyFacts: { type: 'array', items: { type: 'string' } },\n },\n required: ['errorType', 'keyFacts'],\n },\n },\n)\n\nconst HYPOTHESES = [\n { key: 'config', angle: 'Misconfiguration, missing env vars, wrong defaults, feature flags, stale config cache.' },\n { key: 'race', angle: 'Concurrency, timing, ordering, partial failure under load, missing locks or awaits.' },\n { key: 'dependency', angle: 'Version mismatch, breaking upstream change, network/API failure, timeout, auth expiry.' },\n { key: 'data', angle: 'Bad input, schema drift, null/empty edge case, corrupt state, migration gap.' },\n { key: 'environment', angle: 'OS, permissions, disk, memory, container/network isolation, platform-specific behavior.' },\n]\n\nphase('Hypotheses')\nconst hypothesisReports = await parallel(\n HYPOTHESES.map((h) => () =>\n agent(\n 'Evaluate whether this hypothesis explains the incident. Search the codebase for supporting or refuting evidence.\\n\\n' +\n 'HYPOTHESIS: ' + h.key + ' \u2014 ' + h.angle + '\\n\\n' +\n 'TRIAGE:\\n' + JSON.stringify(triage, null, 2) + '\\n\\n' +\n 'ERROR:\\n' + error + '\\n\\n' +\n (logs ? 'LOGS:\\n' + logs + '\\n\\n' : '') +\n 'Return: likelihood (low/med/high), evidence (file paths + brief notes), and one verification step.',\n {\n label: h.key + ' hypothesis',\n toolset: READ_TOOLS,\n schema: {\n type: 'object',\n properties: {\n likelihood: { type: 'string', enum: ['low', 'med', 'high'] },\n evidence: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n path: { type: 'string' },\n note: { type: 'string' },\n },\n required: ['path', 'note'],\n },\n },\n verificationStep: { type: 'string' },\n },\n required: ['likelihood', 'evidence', 'verificationStep'],\n },\n },\n ),\n ),\n)\n\nphase('Rank')\nconst live = hypothesisReports.filter(Boolean)\nconst byHypothesis = {}\nfor (let i = 0; i < HYPOTHESES.length; i++) {\n byHypothesis[HYPOTHESES[i].key] = live[i] ?? null\n}\n\nconst ranking = await agent(\n 'Rank root causes by likelihood. Pick the top 3 with confidence and concrete next steps to confirm or fix.\\n\\n' +\n JSON.stringify({ triage, byHypothesis }, null, 2),\n {\n label: 'root cause ranking',\n schema: {\n type: 'object',\n properties: {\n topCauses: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n hypothesis: { type: 'string' },\n likelihood: { type: 'string', enum: ['low', 'med', 'high'] },\n summary: { type: 'string' },\n nextStep: { type: 'string' },\n },\n required: ['hypothesis', 'likelihood', 'summary', 'nextStep'],\n },\n },\n immediateActions: { type: 'array', items: { type: 'string' } },\n summary: { type: 'string' },\n },\n required: ['topCauses', 'summary'],\n },\n },\n)\n\nconst output = {\n ok: true,\n triage,\n ...(ranking ?? { topCauses: [], summary: 'ranking failed', immediateActions: [] }),\n byHypothesis,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'risks', title: 'Top causes', items: output.topCauses.map((item) => ({ title: item.hypothesis, severity: item.likelihood, detail: item.summary, mitigation: item.nextStep })) },\n { kind: 'questions', title: 'Immediate actions', items: output.immediateActions ?? [] },\n ],\n structuredOutput: output,\n}\n";
13
+ export declare const DEBUG_INCIDENT_SCRIPT = "export const meta = {\n name: 'debug_incident',\n description: 'Triage an error or log snippet with parallel hypotheses and ranked root-cause analysis.',\n whenToUse: 'User reports a bug, crash, error message, or unexpected behavior and wants systematic triage.',\n examplePrompts: [\n { field: 'error', text: 'Triage this stack trace from production' },\n { field: 'error', text: 'Why does the gateway return 502 after deploy?' },\n ],\n i18n: {\n zh: {\n description: '\u5BF9\u9519\u8BEF\u6216\u65E5\u5FD7\u7247\u6BB5\u505A\u5E76\u884C\u5047\u8BBE\u63A8\u6F14\uFF0C\u5E76\u6392\u5E8F\u6839\u56E0\u4E0E\u9A8C\u8BC1\u6B65\u9AA4\u3002',\n whenToUse: '\u7528\u6237\u62A5\u544A bug\u3001\u5D29\u6E83\u3001\u62A5\u9519\u6216\u5F02\u5E38\u884C\u4E3A\uFF0C\u9700\u8981\u7CFB\u7EDF\u5316\u6392\u67E5\u65F6\u3002',\n examplePrompts: [\n { field: 'error', text: '\u6392\u67E5\u751F\u4EA7\u73AF\u5883\u8FD9\u6761\u5806\u6808' },\n { field: 'error', text: '\u90E8\u7F72\u540E\u7F51\u5173\u8FD4\u56DE 502\uFF0C\u53EF\u80FD\u662F\u4EC0\u4E48\u539F\u56E0\uFF1F' },\n ],\n },\n },\n tags: ['debug', 'incident', 'troubleshooting'],\n estimatedAgents: { min: 7, max: 7 },\n phases: [\n { title: 'Triage' },\n { title: 'Hypotheses' },\n { title: 'Rank' },\n ],\n}\n\nconst READ_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'exec_command']\n\nconst error = args && typeof args === 'object' && args.error\n ? String(args.error)\n : 'Infer the primary error from the most recent user message or conversation context.'\n\nconst logs = args && typeof args === 'object' && args.logs\n ? String(args.logs)\n : ''\n\nconst context = args && typeof args === 'object' && args.context\n ? String(args.context)\n : ''\n\nphase('Triage')\nconst triage = await agent(\n 'Parse this incident signal. Extract: error type, likely subsystem, affected files/modules if identifiable, and 2\u20133 key facts from logs.\\n\\n' +\n 'ERROR:\\n' + error + '\\n\\n' +\n (logs ? 'LOGS:\\n' + logs + '\\n\\n' : '') +\n (context ? 'CONTEXT:\\n' + context + '\\n\\n' : '') +\n 'Use read/grep tools to locate relevant code if the workspace may contain the failing path.',\n {\n label: 'incident triage',\n toolset: READ_TOOLS,\n schema: {\n type: 'object',\n properties: {\n errorType: { type: 'string' },\n subsystem: { type: 'string' },\n affectedPaths: { type: 'array', items: { type: 'string' } },\n keyFacts: { type: 'array', items: { type: 'string' } },\n },\n required: ['errorType', 'keyFacts'],\n },\n },\n)\n\nconst HYPOTHESES = [\n { key: 'config', angle: 'Misconfiguration, missing env vars, wrong defaults, feature flags, stale config cache.' },\n { key: 'race', angle: 'Concurrency, timing, ordering, partial failure under load, missing locks or awaits.' },\n { key: 'dependency', angle: 'Version mismatch, breaking upstream change, network/API failure, timeout, auth expiry.' },\n { key: 'data', angle: 'Bad input, schema drift, null/empty edge case, corrupt state, migration gap.' },\n { key: 'environment', angle: 'OS, permissions, disk, memory, container/network isolation, platform-specific behavior.' },\n]\n\nphase('Hypotheses')\nconst hypothesisReports = await parallel(\n HYPOTHESES.map((h) => () =>\n agent(\n 'Evaluate whether this hypothesis explains the incident. Search the codebase for supporting or refuting evidence.\\n\\n' +\n 'HYPOTHESIS: ' + h.key + ' \u2014 ' + h.angle + '\\n\\n' +\n 'TRIAGE:\\n' + JSON.stringify(triage, null, 2) + '\\n\\n' +\n 'ERROR:\\n' + error + '\\n\\n' +\n (logs ? 'LOGS:\\n' + logs + '\\n\\n' : '') +\n 'Return: likelihood (low/med/high), evidence (file paths + brief notes), and one verification step.',\n {\n label: h.key + ' hypothesis',\n toolset: READ_TOOLS,\n schema: {\n type: 'object',\n properties: {\n likelihood: { type: 'string', enum: ['low', 'med', 'high'] },\n evidence: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n path: { type: 'string' },\n note: { type: 'string' },\n },\n required: ['path', 'note'],\n },\n },\n verificationStep: { type: 'string' },\n },\n required: ['likelihood', 'evidence', 'verificationStep'],\n },\n },\n ),\n ),\n)\n\nphase('Rank')\nconst live = hypothesisReports.filter(Boolean)\nconst byHypothesis = {}\nfor (let i = 0; i < HYPOTHESES.length; i++) {\n byHypothesis[HYPOTHESES[i].key] = live[i] ?? null\n}\n\nconst ranking = await agent(\n 'Rank root causes by likelihood. Pick the top 3 with confidence and concrete next steps to confirm or fix.\\n\\n' +\n JSON.stringify({ triage, byHypothesis }, null, 2),\n {\n label: 'root cause ranking',\n schema: {\n type: 'object',\n properties: {\n topCauses: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n hypothesis: { type: 'string' },\n likelihood: { type: 'string', enum: ['low', 'med', 'high'] },\n summary: { type: 'string' },\n nextStep: { type: 'string' },\n },\n required: ['hypothesis', 'likelihood', 'summary', 'nextStep'],\n },\n },\n immediateActions: { type: 'array', items: { type: 'string' } },\n summary: { type: 'string' },\n },\n required: ['topCauses', 'summary'],\n },\n },\n)\n\nconst output = {\n ok: true,\n triage,\n ...(ranking ?? { topCauses: [], summary: 'ranking failed', immediateActions: [] }),\n byHypothesis,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'risks', title: 'Top causes', items: output.topCauses.map((item) => ({ title: item.hypothesis, severity: item.likelihood, detail: item.summary, mitigation: item.nextStep })) },\n { kind: 'questions', title: 'Immediate actions', items: output.immediateActions ?? [] },\n ],\n structuredOutput: output,\n}\n";
@@ -38,7 +38,7 @@ const DEBUG_INCIDENT_SCRIPT = `export const meta = {
38
38
  ],
39
39
  }
40
40
 
41
- const READ_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'shell']
41
+ const READ_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'exec_command']
42
42
 
43
43
  const error = args && typeof args === 'object' && args.error
44
44
  ? String(args.error)
@@ -1 +1 @@
1
- {"version":3,"file":"debug-incident.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/debug-incident.ts"],"sourcesContent":["/**\n * Built-in workflow: `debug_incident`\n *\n * Triage an error, stack trace, or log snippet. Parses the signal, fans out\n * parallel hypotheses (config, race, dependency, data, environment), then\n * ranks likely root causes with verification steps.\n *\n * Args:\n * - error: error message or stack trace\n * - logs: optional log excerpt\n * - context: optional extra context (what changed, when it started)\n */\n\nexport const DEBUG_INCIDENT_SCRIPT = `export const meta = {\n name: 'debug_incident',\n description: 'Triage an error or log snippet with parallel hypotheses and ranked root-cause analysis.',\n whenToUse: 'User reports a bug, crash, error message, or unexpected behavior and wants systematic triage.',\n examplePrompts: [\n { field: 'error', text: 'Triage this stack trace from production' },\n { field: 'error', text: 'Why does the gateway return 502 after deploy?' },\n ],\n i18n: {\n zh: {\n description: '对错误或日志片段做并行假设推演,并排序根因与验证步骤。',\n whenToUse: '用户报告 bug、崩溃、报错或异常行为,需要系统化排查时。',\n examplePrompts: [\n { field: 'error', text: '排查生产环境这条堆栈' },\n { field: 'error', text: '部署后网关返回 502,可能是什么原因?' },\n ],\n },\n },\n tags: ['debug', 'incident', 'troubleshooting'],\n estimatedAgents: { min: 7, max: 7 },\n phases: [\n { title: 'Triage' },\n { title: 'Hypotheses' },\n { title: 'Rank' },\n ],\n}\n\nconst READ_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'shell']\n\nconst error = args && typeof args === 'object' && args.error\n ? String(args.error)\n : 'Infer the primary error from the most recent user message or conversation context.'\n\nconst logs = args && typeof args === 'object' && args.logs\n ? String(args.logs)\n : ''\n\nconst context = args && typeof args === 'object' && args.context\n ? String(args.context)\n : ''\n\nphase('Triage')\nconst triage = await agent(\n 'Parse this incident signal. Extract: error type, likely subsystem, affected files/modules if identifiable, and 2–3 key facts from logs.\\\\n\\\\n' +\n 'ERROR:\\\\n' + error + '\\\\n\\\\n' +\n (logs ? 'LOGS:\\\\n' + logs + '\\\\n\\\\n' : '') +\n (context ? 'CONTEXT:\\\\n' + context + '\\\\n\\\\n' : '') +\n 'Use read/grep tools to locate relevant code if the workspace may contain the failing path.',\n {\n label: 'incident triage',\n toolset: READ_TOOLS,\n schema: {\n type: 'object',\n properties: {\n errorType: { type: 'string' },\n subsystem: { type: 'string' },\n affectedPaths: { type: 'array', items: { type: 'string' } },\n keyFacts: { type: 'array', items: { type: 'string' } },\n },\n required: ['errorType', 'keyFacts'],\n },\n },\n)\n\nconst HYPOTHESES = [\n { key: 'config', angle: 'Misconfiguration, missing env vars, wrong defaults, feature flags, stale config cache.' },\n { key: 'race', angle: 'Concurrency, timing, ordering, partial failure under load, missing locks or awaits.' },\n { key: 'dependency', angle: 'Version mismatch, breaking upstream change, network/API failure, timeout, auth expiry.' },\n { key: 'data', angle: 'Bad input, schema drift, null/empty edge case, corrupt state, migration gap.' },\n { key: 'environment', angle: 'OS, permissions, disk, memory, container/network isolation, platform-specific behavior.' },\n]\n\nphase('Hypotheses')\nconst hypothesisReports = await parallel(\n HYPOTHESES.map((h) => () =>\n agent(\n 'Evaluate whether this hypothesis explains the incident. Search the codebase for supporting or refuting evidence.\\\\n\\\\n' +\n 'HYPOTHESIS: ' + h.key + ' — ' + h.angle + '\\\\n\\\\n' +\n 'TRIAGE:\\\\n' + JSON.stringify(triage, null, 2) + '\\\\n\\\\n' +\n 'ERROR:\\\\n' + error + '\\\\n\\\\n' +\n (logs ? 'LOGS:\\\\n' + logs + '\\\\n\\\\n' : '') +\n 'Return: likelihood (low/med/high), evidence (file paths + brief notes), and one verification step.',\n {\n label: h.key + ' hypothesis',\n toolset: READ_TOOLS,\n schema: {\n type: 'object',\n properties: {\n likelihood: { type: 'string', enum: ['low', 'med', 'high'] },\n evidence: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n path: { type: 'string' },\n note: { type: 'string' },\n },\n required: ['path', 'note'],\n },\n },\n verificationStep: { type: 'string' },\n },\n required: ['likelihood', 'evidence', 'verificationStep'],\n },\n },\n ),\n ),\n)\n\nphase('Rank')\nconst live = hypothesisReports.filter(Boolean)\nconst byHypothesis = {}\nfor (let i = 0; i < HYPOTHESES.length; i++) {\n byHypothesis[HYPOTHESES[i].key] = live[i] ?? null\n}\n\nconst ranking = await agent(\n 'Rank root causes by likelihood. Pick the top 3 with confidence and concrete next steps to confirm or fix.\\\\n\\\\n' +\n JSON.stringify({ triage, byHypothesis }, null, 2),\n {\n label: 'root cause ranking',\n schema: {\n type: 'object',\n properties: {\n topCauses: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n hypothesis: { type: 'string' },\n likelihood: { type: 'string', enum: ['low', 'med', 'high'] },\n summary: { type: 'string' },\n nextStep: { type: 'string' },\n },\n required: ['hypothesis', 'likelihood', 'summary', 'nextStep'],\n },\n },\n immediateActions: { type: 'array', items: { type: 'string' } },\n summary: { type: 'string' },\n },\n required: ['topCauses', 'summary'],\n },\n },\n)\n\nconst output = {\n ok: true,\n triage,\n ...(ranking ?? { topCauses: [], summary: 'ranking failed', immediateActions: [] }),\n byHypothesis,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'risks', title: 'Top causes', items: output.topCauses.map((item) => ({ title: item.hypothesis, severity: item.likelihood, detail: item.summary, mitigation: item.nextStep })) },\n { kind: 'questions', title: 'Immediate actions', items: output.immediateActions ?? [] },\n ],\n structuredOutput: output,\n}\n`\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAa,wBAAwB"}
1
+ {"version":3,"file":"debug-incident.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/debug-incident.ts"],"sourcesContent":["/**\n * Built-in workflow: `debug_incident`\n *\n * Triage an error, stack trace, or log snippet. Parses the signal, fans out\n * parallel hypotheses (config, race, dependency, data, environment), then\n * ranks likely root causes with verification steps.\n *\n * Args:\n * - error: error message or stack trace\n * - logs: optional log excerpt\n * - context: optional extra context (what changed, when it started)\n */\n\nexport const DEBUG_INCIDENT_SCRIPT = `export const meta = {\n name: 'debug_incident',\n description: 'Triage an error or log snippet with parallel hypotheses and ranked root-cause analysis.',\n whenToUse: 'User reports a bug, crash, error message, or unexpected behavior and wants systematic triage.',\n examplePrompts: [\n { field: 'error', text: 'Triage this stack trace from production' },\n { field: 'error', text: 'Why does the gateway return 502 after deploy?' },\n ],\n i18n: {\n zh: {\n description: '对错误或日志片段做并行假设推演,并排序根因与验证步骤。',\n whenToUse: '用户报告 bug、崩溃、报错或异常行为,需要系统化排查时。',\n examplePrompts: [\n { field: 'error', text: '排查生产环境这条堆栈' },\n { field: 'error', text: '部署后网关返回 502,可能是什么原因?' },\n ],\n },\n },\n tags: ['debug', 'incident', 'troubleshooting'],\n estimatedAgents: { min: 7, max: 7 },\n phases: [\n { title: 'Triage' },\n { title: 'Hypotheses' },\n { title: 'Rank' },\n ],\n}\n\nconst READ_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'exec_command']\n\nconst error = args && typeof args === 'object' && args.error\n ? String(args.error)\n : 'Infer the primary error from the most recent user message or conversation context.'\n\nconst logs = args && typeof args === 'object' && args.logs\n ? String(args.logs)\n : ''\n\nconst context = args && typeof args === 'object' && args.context\n ? String(args.context)\n : ''\n\nphase('Triage')\nconst triage = await agent(\n 'Parse this incident signal. Extract: error type, likely subsystem, affected files/modules if identifiable, and 2–3 key facts from logs.\\\\n\\\\n' +\n 'ERROR:\\\\n' + error + '\\\\n\\\\n' +\n (logs ? 'LOGS:\\\\n' + logs + '\\\\n\\\\n' : '') +\n (context ? 'CONTEXT:\\\\n' + context + '\\\\n\\\\n' : '') +\n 'Use read/grep tools to locate relevant code if the workspace may contain the failing path.',\n {\n label: 'incident triage',\n toolset: READ_TOOLS,\n schema: {\n type: 'object',\n properties: {\n errorType: { type: 'string' },\n subsystem: { type: 'string' },\n affectedPaths: { type: 'array', items: { type: 'string' } },\n keyFacts: { type: 'array', items: { type: 'string' } },\n },\n required: ['errorType', 'keyFacts'],\n },\n },\n)\n\nconst HYPOTHESES = [\n { key: 'config', angle: 'Misconfiguration, missing env vars, wrong defaults, feature flags, stale config cache.' },\n { key: 'race', angle: 'Concurrency, timing, ordering, partial failure under load, missing locks or awaits.' },\n { key: 'dependency', angle: 'Version mismatch, breaking upstream change, network/API failure, timeout, auth expiry.' },\n { key: 'data', angle: 'Bad input, schema drift, null/empty edge case, corrupt state, migration gap.' },\n { key: 'environment', angle: 'OS, permissions, disk, memory, container/network isolation, platform-specific behavior.' },\n]\n\nphase('Hypotheses')\nconst hypothesisReports = await parallel(\n HYPOTHESES.map((h) => () =>\n agent(\n 'Evaluate whether this hypothesis explains the incident. Search the codebase for supporting or refuting evidence.\\\\n\\\\n' +\n 'HYPOTHESIS: ' + h.key + ' — ' + h.angle + '\\\\n\\\\n' +\n 'TRIAGE:\\\\n' + JSON.stringify(triage, null, 2) + '\\\\n\\\\n' +\n 'ERROR:\\\\n' + error + '\\\\n\\\\n' +\n (logs ? 'LOGS:\\\\n' + logs + '\\\\n\\\\n' : '') +\n 'Return: likelihood (low/med/high), evidence (file paths + brief notes), and one verification step.',\n {\n label: h.key + ' hypothesis',\n toolset: READ_TOOLS,\n schema: {\n type: 'object',\n properties: {\n likelihood: { type: 'string', enum: ['low', 'med', 'high'] },\n evidence: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n path: { type: 'string' },\n note: { type: 'string' },\n },\n required: ['path', 'note'],\n },\n },\n verificationStep: { type: 'string' },\n },\n required: ['likelihood', 'evidence', 'verificationStep'],\n },\n },\n ),\n ),\n)\n\nphase('Rank')\nconst live = hypothesisReports.filter(Boolean)\nconst byHypothesis = {}\nfor (let i = 0; i < HYPOTHESES.length; i++) {\n byHypothesis[HYPOTHESES[i].key] = live[i] ?? null\n}\n\nconst ranking = await agent(\n 'Rank root causes by likelihood. Pick the top 3 with confidence and concrete next steps to confirm or fix.\\\\n\\\\n' +\n JSON.stringify({ triage, byHypothesis }, null, 2),\n {\n label: 'root cause ranking',\n schema: {\n type: 'object',\n properties: {\n topCauses: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n hypothesis: { type: 'string' },\n likelihood: { type: 'string', enum: ['low', 'med', 'high'] },\n summary: { type: 'string' },\n nextStep: { type: 'string' },\n },\n required: ['hypothesis', 'likelihood', 'summary', 'nextStep'],\n },\n },\n immediateActions: { type: 'array', items: { type: 'string' } },\n summary: { type: 'string' },\n },\n required: ['topCauses', 'summary'],\n },\n },\n)\n\nconst output = {\n ok: true,\n triage,\n ...(ranking ?? { topCauses: [], summary: 'ranking failed', immediateActions: [] }),\n byHypothesis,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'risks', title: 'Top causes', items: output.topCauses.map((item) => ({ title: item.hypothesis, severity: item.likelihood, detail: item.summary, mitigation: item.nextStep })) },\n { kind: 'questions', title: 'Immediate actions', items: output.immediateActions ?? [] },\n ],\n structuredOutput: output,\n}\n`\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAa,wBAAwB"}
@@ -9,4 +9,4 @@
9
9
  * - target: PR description, diff, commit range, or file list
10
10
  * - diff: alias for target
11
11
  */
12
- export declare const PR_REVIEW_SCRIPT = "export const meta = {\n name: 'pr_review',\n description: 'Review a PR/diff/commit range with parallel focused reviewers and a ship/block verdict.',\n whenToUse: 'User asks to review a PR, diff, specific changes, or commit range (not the whole repo).',\n examplePrompts: [\n { field: 'target', text: 'Review the changes on this branch' },\n { field: 'target', text: 'Review PR #42 for ship/block verdict' },\n ],\n i18n: {\n zh: {\n description: '\u5E76\u884C\u805A\u7126\u5BA1\u67E5 PR\u3001diff \u6216\u63D0\u4EA4\u8303\u56F4\uFF0C\u5E76\u7ED9\u51FA\u53EF\u5408\u5E76/\u5E94\u62E6\u622A\u7684\u7ED3\u8BBA\u3002',\n whenToUse: '\u7528\u6237\u8981\u5BA1\u67E5 PR\u3001diff\u3001\u7279\u5B9A\u6539\u52A8\u6216\u63D0\u4EA4\u8303\u56F4\uFF08\u800C\u975E\u6574\u5E93\uFF09\u65F6\u3002',\n examplePrompts: [\n { field: 'target', text: '\u5BA1\u67E5\u5F53\u524D\u5206\u652F\u4E0A\u7684\u6539\u52A8' },\n { field: 'target', text: '\u5BA1\u67E5 PR #42\uFF0C\u7ED9\u51FA\u662F\u5426\u53EF\u5408\u5E76\u7684\u7ED3\u8BBA' },\n ],\n },\n },\n tags: ['code-review', 'pr'],\n estimatedAgents: { min: 7, max: 7 },\n phases: [\n { title: 'Scope' },\n { title: 'Review' },\n { title: 'Verdict' },\n ],\n}\n\nconst READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'shell']\n\nconst target = args && typeof args === 'object'\n ? String(args.target ?? args.diff ?? '')\n : ''\nconst reviewTarget = target.trim()\n ? target\n : 'Recent changes in the working tree or the diff/context from the current conversation.'\n\nconst REVIEWERS = [\n { key: 'correctness', focus: 'Logic bugs, edge cases, error handling, null safety, race conditions in changed code.' },\n { key: 'security', focus: 'Auth/authz regressions, input validation, secret exposure, injection, unsafe deserialization in the diff.' },\n { key: 'tests', focus: 'Missing tests for changed behavior, brittle assertions, untested edge cases introduced by this change.' },\n { key: 'api_compat', focus: 'Breaking public API changes, schema migrations, backward compatibility, deprecation handling.' },\n { key: 'perf', focus: 'Regressions in hot paths, accidental N+1, sync I/O, unbounded loops or allocations in changed code.' },\n]\n\nphase('Scope')\nconst scope = await agent(\n 'Identify what changed for this review target. List changed files, blast radius (what depends on them), and the apparent intent of the change. Be concise.\\n\\nTARGET:\\n' +\n reviewTarget,\n {\n label: 'change scope',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n changedFiles: { type: 'array', items: { type: 'string' } },\n intent: { type: 'string' },\n blastRadius: { type: 'string' },\n },\n required: ['changedFiles', 'intent'],\n },\n },\n)\n\nphase('Review')\nconst reviews = await parallel(\n REVIEWERS.map((r) => () =>\n agent(\n 'Review these changes through the ' + r.key + ' lens.\\n' +\n 'Focus: ' + r.focus + '\\n\\n' +\n 'TARGET:\\n' + reviewTarget + '\\n\\n' +\n 'SCOPE:\\n' + JSON.stringify(scope, null, 2) + '\\n\\n' +\n 'Return findings: file, severity (low/med/high/blocker), title, fix suggestion. Blocker = must fix before merge.',\n {\n label: r.key,\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n findings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n severity: { type: 'string', enum: ['low', 'med', 'high', 'blocker'] },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'severity', 'title', 'fix'],\n },\n },\n },\n required: ['findings'],\n },\n },\n ),\n ),\n)\n\nphase('Verdict')\nconst live = reviews.filter(Boolean)\nconst byReviewer = {}\nfor (let i = 0; i < REVIEWERS.length; i++) {\n byReviewer[REVIEWERS[i].key] = live[i]?.findings ?? []\n}\n\nconst verdict = await agent(\n 'Synthesize a PR review verdict. Separate blockers from suggestions. Deduplicate. Recommend ship | fix_first | block.\\n\\n' +\n JSON.stringify(byReviewer, null, 2),\n {\n label: 'verdict',\n schema: {\n type: 'object',\n properties: {\n recommendation: { type: 'string', enum: ['ship', 'fix_first', 'block'] },\n summary: { type: 'string' },\n blockers: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'title'],\n },\n },\n suggestions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n },\n required: ['file', 'title'],\n },\n },\n },\n required: ['recommendation', 'summary', 'blockers'],\n },\n },\n)\n\nconst output = {\n ok: true,\n target: reviewTarget,\n scope,\n ...(verdict ?? { recommendation: 'fix_first', summary: 'verdict failed', blockers: [], suggestions: [] }),\n byReviewer,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'findings', title: 'Blockers', items: output.blockers.map((item) => ({ title: item.title, severity: 'high', file: item.file, detail: item.fix })) },\n { kind: 'findings', title: 'Suggestions', items: output.suggestions.map((item) => ({ title: item.title, severity: item.severity, file: item.file })) },\n ],\n structuredOutput: output,\n}\n";
12
+ export declare const PR_REVIEW_SCRIPT = "export const meta = {\n name: 'pr_review',\n description: 'Review a PR/diff/commit range with parallel focused reviewers and a ship/block verdict.',\n whenToUse: 'User asks to review a PR, diff, specific changes, or commit range (not the whole repo).',\n examplePrompts: [\n { field: 'target', text: 'Review the changes on this branch' },\n { field: 'target', text: 'Review PR #42 for ship/block verdict' },\n ],\n i18n: {\n zh: {\n description: '\u5E76\u884C\u805A\u7126\u5BA1\u67E5 PR\u3001diff \u6216\u63D0\u4EA4\u8303\u56F4\uFF0C\u5E76\u7ED9\u51FA\u53EF\u5408\u5E76/\u5E94\u62E6\u622A\u7684\u7ED3\u8BBA\u3002',\n whenToUse: '\u7528\u6237\u8981\u5BA1\u67E5 PR\u3001diff\u3001\u7279\u5B9A\u6539\u52A8\u6216\u63D0\u4EA4\u8303\u56F4\uFF08\u800C\u975E\u6574\u5E93\uFF09\u65F6\u3002',\n examplePrompts: [\n { field: 'target', text: '\u5BA1\u67E5\u5F53\u524D\u5206\u652F\u4E0A\u7684\u6539\u52A8' },\n { field: 'target', text: '\u5BA1\u67E5 PR #42\uFF0C\u7ED9\u51FA\u662F\u5426\u53EF\u5408\u5E76\u7684\u7ED3\u8BBA' },\n ],\n },\n },\n tags: ['code-review', 'pr'],\n estimatedAgents: { min: 7, max: 7 },\n phases: [\n { title: 'Scope' },\n { title: 'Review' },\n { title: 'Verdict' },\n ],\n}\n\nconst READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'exec_command']\n\nconst target = args && typeof args === 'object'\n ? String(args.target ?? args.diff ?? '')\n : ''\nconst reviewTarget = target.trim()\n ? target\n : 'Recent changes in the working tree or the diff/context from the current conversation.'\n\nconst REVIEWERS = [\n { key: 'correctness', focus: 'Logic bugs, edge cases, error handling, null safety, race conditions in changed code.' },\n { key: 'security', focus: 'Auth/authz regressions, input validation, secret exposure, injection, unsafe deserialization in the diff.' },\n { key: 'tests', focus: 'Missing tests for changed behavior, brittle assertions, untested edge cases introduced by this change.' },\n { key: 'api_compat', focus: 'Breaking public API changes, schema migrations, backward compatibility, deprecation handling.' },\n { key: 'perf', focus: 'Regressions in hot paths, accidental N+1, sync I/O, unbounded loops or allocations in changed code.' },\n]\n\nphase('Scope')\nconst scope = await agent(\n 'Identify what changed for this review target. List changed files, blast radius (what depends on them), and the apparent intent of the change. Be concise.\\n\\nTARGET:\\n' +\n reviewTarget,\n {\n label: 'change scope',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n changedFiles: { type: 'array', items: { type: 'string' } },\n intent: { type: 'string' },\n blastRadius: { type: 'string' },\n },\n required: ['changedFiles', 'intent'],\n },\n },\n)\n\nphase('Review')\nconst reviews = await parallel(\n REVIEWERS.map((r) => () =>\n agent(\n 'Review these changes through the ' + r.key + ' lens.\\n' +\n 'Focus: ' + r.focus + '\\n\\n' +\n 'TARGET:\\n' + reviewTarget + '\\n\\n' +\n 'SCOPE:\\n' + JSON.stringify(scope, null, 2) + '\\n\\n' +\n 'Return findings: file, severity (low/med/high/blocker), title, fix suggestion. Blocker = must fix before merge.',\n {\n label: r.key,\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n findings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n severity: { type: 'string', enum: ['low', 'med', 'high', 'blocker'] },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'severity', 'title', 'fix'],\n },\n },\n },\n required: ['findings'],\n },\n },\n ),\n ),\n)\n\nphase('Verdict')\nconst live = reviews.filter(Boolean)\nconst byReviewer = {}\nfor (let i = 0; i < REVIEWERS.length; i++) {\n byReviewer[REVIEWERS[i].key] = live[i]?.findings ?? []\n}\n\nconst verdict = await agent(\n 'Synthesize a PR review verdict. Separate blockers from suggestions. Deduplicate. Recommend ship | fix_first | block.\\n\\n' +\n JSON.stringify(byReviewer, null, 2),\n {\n label: 'verdict',\n schema: {\n type: 'object',\n properties: {\n recommendation: { type: 'string', enum: ['ship', 'fix_first', 'block'] },\n summary: { type: 'string' },\n blockers: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'title'],\n },\n },\n suggestions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n },\n required: ['file', 'title'],\n },\n },\n },\n required: ['recommendation', 'summary', 'blockers'],\n },\n },\n)\n\nconst output = {\n ok: true,\n target: reviewTarget,\n scope,\n ...(verdict ?? { recommendation: 'fix_first', summary: 'verdict failed', blockers: [], suggestions: [] }),\n byReviewer,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'findings', title: 'Blockers', items: output.blockers.map((item) => ({ title: item.title, severity: 'high', file: item.file, detail: item.fix })) },\n { kind: 'findings', title: 'Suggestions', items: output.suggestions.map((item) => ({ title: item.title, severity: item.severity, file: item.file })) },\n ],\n structuredOutput: output,\n}\n";
@@ -37,7 +37,7 @@ const PR_REVIEW_SCRIPT = `export const meta = {
37
37
  ],
38
38
  }
39
39
 
40
- const READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'shell']
40
+ const READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'exec_command']
41
41
 
42
42
  const target = args && typeof args === 'object'
43
43
  ? String(args.target ?? args.diff ?? '')
@@ -1 +1 @@
1
- {"version":3,"file":"pr-review.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/pr-review.ts"],"sourcesContent":["/**\n * Built-in workflow: `pr_review`\n *\n * Focused review of a PR, diff, or commit range — lighter than full repo audit.\n * Parallel reviewers cover correctness, security, tests, API compat, and perf;\n * final phase produces a ship/block verdict with blockers vs suggestions.\n *\n * Args:\n * - target: PR description, diff, commit range, or file list\n * - diff: alias for target\n */\n\nexport const PR_REVIEW_SCRIPT = `export const meta = {\n name: 'pr_review',\n description: 'Review a PR/diff/commit range with parallel focused reviewers and a ship/block verdict.',\n whenToUse: 'User asks to review a PR, diff, specific changes, or commit range (not the whole repo).',\n examplePrompts: [\n { field: 'target', text: 'Review the changes on this branch' },\n { field: 'target', text: 'Review PR #42 for ship/block verdict' },\n ],\n i18n: {\n zh: {\n description: '并行聚焦审查 PR、diff 或提交范围,并给出可合并/应拦截的结论。',\n whenToUse: '用户要审查 PR、diff、特定改动或提交范围(而非整库)时。',\n examplePrompts: [\n { field: 'target', text: '审查当前分支上的改动' },\n { field: 'target', text: '审查 PR #42,给出是否可合并的结论' },\n ],\n },\n },\n tags: ['code-review', 'pr'],\n estimatedAgents: { min: 7, max: 7 },\n phases: [\n { title: 'Scope' },\n { title: 'Review' },\n { title: 'Verdict' },\n ],\n}\n\nconst READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'shell']\n\nconst target = args && typeof args === 'object'\n ? String(args.target ?? args.diff ?? '')\n : ''\nconst reviewTarget = target.trim()\n ? target\n : 'Recent changes in the working tree or the diff/context from the current conversation.'\n\nconst REVIEWERS = [\n { key: 'correctness', focus: 'Logic bugs, edge cases, error handling, null safety, race conditions in changed code.' },\n { key: 'security', focus: 'Auth/authz regressions, input validation, secret exposure, injection, unsafe deserialization in the diff.' },\n { key: 'tests', focus: 'Missing tests for changed behavior, brittle assertions, untested edge cases introduced by this change.' },\n { key: 'api_compat', focus: 'Breaking public API changes, schema migrations, backward compatibility, deprecation handling.' },\n { key: 'perf', focus: 'Regressions in hot paths, accidental N+1, sync I/O, unbounded loops or allocations in changed code.' },\n]\n\nphase('Scope')\nconst scope = await agent(\n 'Identify what changed for this review target. List changed files, blast radius (what depends on them), and the apparent intent of the change. Be concise.\\\\n\\\\nTARGET:\\\\n' +\n reviewTarget,\n {\n label: 'change scope',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n changedFiles: { type: 'array', items: { type: 'string' } },\n intent: { type: 'string' },\n blastRadius: { type: 'string' },\n },\n required: ['changedFiles', 'intent'],\n },\n },\n)\n\nphase('Review')\nconst reviews = await parallel(\n REVIEWERS.map((r) => () =>\n agent(\n 'Review these changes through the ' + r.key + ' lens.\\\\n' +\n 'Focus: ' + r.focus + '\\\\n\\\\n' +\n 'TARGET:\\\\n' + reviewTarget + '\\\\n\\\\n' +\n 'SCOPE:\\\\n' + JSON.stringify(scope, null, 2) + '\\\\n\\\\n' +\n 'Return findings: file, severity (low/med/high/blocker), title, fix suggestion. Blocker = must fix before merge.',\n {\n label: r.key,\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n findings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n severity: { type: 'string', enum: ['low', 'med', 'high', 'blocker'] },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'severity', 'title', 'fix'],\n },\n },\n },\n required: ['findings'],\n },\n },\n ),\n ),\n)\n\nphase('Verdict')\nconst live = reviews.filter(Boolean)\nconst byReviewer = {}\nfor (let i = 0; i < REVIEWERS.length; i++) {\n byReviewer[REVIEWERS[i].key] = live[i]?.findings ?? []\n}\n\nconst verdict = await agent(\n 'Synthesize a PR review verdict. Separate blockers from suggestions. Deduplicate. Recommend ship | fix_first | block.\\\\n\\\\n' +\n JSON.stringify(byReviewer, null, 2),\n {\n label: 'verdict',\n schema: {\n type: 'object',\n properties: {\n recommendation: { type: 'string', enum: ['ship', 'fix_first', 'block'] },\n summary: { type: 'string' },\n blockers: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'title'],\n },\n },\n suggestions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n },\n required: ['file', 'title'],\n },\n },\n },\n required: ['recommendation', 'summary', 'blockers'],\n },\n },\n)\n\nconst output = {\n ok: true,\n target: reviewTarget,\n scope,\n ...(verdict ?? { recommendation: 'fix_first', summary: 'verdict failed', blockers: [], suggestions: [] }),\n byReviewer,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'findings', title: 'Blockers', items: output.blockers.map((item) => ({ title: item.title, severity: 'high', file: item.file, detail: item.fix })) },\n { kind: 'findings', title: 'Suggestions', items: output.suggestions.map((item) => ({ title: item.title, severity: item.severity, file: item.file })) },\n ],\n structuredOutput: output,\n}\n`\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,mBAAmB"}
1
+ {"version":3,"file":"pr-review.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/pr-review.ts"],"sourcesContent":["/**\n * Built-in workflow: `pr_review`\n *\n * Focused review of a PR, diff, or commit range — lighter than full repo audit.\n * Parallel reviewers cover correctness, security, tests, API compat, and perf;\n * final phase produces a ship/block verdict with blockers vs suggestions.\n *\n * Args:\n * - target: PR description, diff, commit range, or file list\n * - diff: alias for target\n */\n\nexport const PR_REVIEW_SCRIPT = `export const meta = {\n name: 'pr_review',\n description: 'Review a PR/diff/commit range with parallel focused reviewers and a ship/block verdict.',\n whenToUse: 'User asks to review a PR, diff, specific changes, or commit range (not the whole repo).',\n examplePrompts: [\n { field: 'target', text: 'Review the changes on this branch' },\n { field: 'target', text: 'Review PR #42 for ship/block verdict' },\n ],\n i18n: {\n zh: {\n description: '并行聚焦审查 PR、diff 或提交范围,并给出可合并/应拦截的结论。',\n whenToUse: '用户要审查 PR、diff、特定改动或提交范围(而非整库)时。',\n examplePrompts: [\n { field: 'target', text: '审查当前分支上的改动' },\n { field: 'target', text: '审查 PR #42,给出是否可合并的结论' },\n ],\n },\n },\n tags: ['code-review', 'pr'],\n estimatedAgents: { min: 7, max: 7 },\n phases: [\n { title: 'Scope' },\n { title: 'Review' },\n { title: 'Verdict' },\n ],\n}\n\nconst READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'exec_command']\n\nconst target = args && typeof args === 'object'\n ? String(args.target ?? args.diff ?? '')\n : ''\nconst reviewTarget = target.trim()\n ? target\n : 'Recent changes in the working tree or the diff/context from the current conversation.'\n\nconst REVIEWERS = [\n { key: 'correctness', focus: 'Logic bugs, edge cases, error handling, null safety, race conditions in changed code.' },\n { key: 'security', focus: 'Auth/authz regressions, input validation, secret exposure, injection, unsafe deserialization in the diff.' },\n { key: 'tests', focus: 'Missing tests for changed behavior, brittle assertions, untested edge cases introduced by this change.' },\n { key: 'api_compat', focus: 'Breaking public API changes, schema migrations, backward compatibility, deprecation handling.' },\n { key: 'perf', focus: 'Regressions in hot paths, accidental N+1, sync I/O, unbounded loops or allocations in changed code.' },\n]\n\nphase('Scope')\nconst scope = await agent(\n 'Identify what changed for this review target. List changed files, blast radius (what depends on them), and the apparent intent of the change. Be concise.\\\\n\\\\nTARGET:\\\\n' +\n reviewTarget,\n {\n label: 'change scope',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n changedFiles: { type: 'array', items: { type: 'string' } },\n intent: { type: 'string' },\n blastRadius: { type: 'string' },\n },\n required: ['changedFiles', 'intent'],\n },\n },\n)\n\nphase('Review')\nconst reviews = await parallel(\n REVIEWERS.map((r) => () =>\n agent(\n 'Review these changes through the ' + r.key + ' lens.\\\\n' +\n 'Focus: ' + r.focus + '\\\\n\\\\n' +\n 'TARGET:\\\\n' + reviewTarget + '\\\\n\\\\n' +\n 'SCOPE:\\\\n' + JSON.stringify(scope, null, 2) + '\\\\n\\\\n' +\n 'Return findings: file, severity (low/med/high/blocker), title, fix suggestion. Blocker = must fix before merge.',\n {\n label: r.key,\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n findings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n severity: { type: 'string', enum: ['low', 'med', 'high', 'blocker'] },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'severity', 'title', 'fix'],\n },\n },\n },\n required: ['findings'],\n },\n },\n ),\n ),\n)\n\nphase('Verdict')\nconst live = reviews.filter(Boolean)\nconst byReviewer = {}\nfor (let i = 0; i < REVIEWERS.length; i++) {\n byReviewer[REVIEWERS[i].key] = live[i]?.findings ?? []\n}\n\nconst verdict = await agent(\n 'Synthesize a PR review verdict. Separate blockers from suggestions. Deduplicate. Recommend ship | fix_first | block.\\\\n\\\\n' +\n JSON.stringify(byReviewer, null, 2),\n {\n label: 'verdict',\n schema: {\n type: 'object',\n properties: {\n recommendation: { type: 'string', enum: ['ship', 'fix_first', 'block'] },\n summary: { type: 'string' },\n blockers: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'title'],\n },\n },\n suggestions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n },\n required: ['file', 'title'],\n },\n },\n },\n required: ['recommendation', 'summary', 'blockers'],\n },\n },\n)\n\nconst output = {\n ok: true,\n target: reviewTarget,\n scope,\n ...(verdict ?? { recommendation: 'fix_first', summary: 'verdict failed', blockers: [], suggestions: [] }),\n byReviewer,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'findings', title: 'Blockers', items: output.blockers.map((item) => ({ title: item.title, severity: 'high', file: item.file, detail: item.fix })) },\n { kind: 'findings', title: 'Suggestions', items: output.suggestions.map((item) => ({ title: item.title, severity: item.severity, file: item.file })) },\n ],\n structuredOutput: output,\n}\n`\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,mBAAmB"}
@@ -8,4 +8,4 @@
8
8
  * - target: release candidate, branch, commit range, or feature summary
9
9
  * - checks: optional subset of check keys
10
10
  */
11
- export declare const RELEASE_CHECK_SCRIPT = "export const meta = {\n name: 'release_check',\n description: 'Assess whether a change is ready to release with parallel risk checks and a go/no-go verdict.',\n whenToUse: 'User is near the end of implementation and wants a release-quality readiness check before shipping.',\n examplePrompts: [\n { field: 'target', text: 'Is this repo ready to release v1.2?' },\n { field: 'target', text: 'Pre-release readiness check for the current branch' },\n ],\n i18n: {\n zh: {\n description: '\u5E76\u884C\u68C0\u67E5\u53D1\u5E03\u98CE\u9669\uFF0C\u5224\u65AD\u53D8\u66F4\u662F\u5426\u8FBE\u5230\u53EF\u53D1\u5E03\u6807\u51C6\u3002',\n whenToUse: '\u7528\u6237\u63A5\u8FD1\u5F00\u53D1\u5C3E\u58F0\uFF0C\u60F3\u5728\u53D1\u5E03\u524D\u505A\u53D1\u5E03\u8D28\u91CF/\u5C31\u7EEA\u68C0\u67E5\u65F6\u3002',\n examplePrompts: [\n { field: 'target', text: '\u8FD9\u4E2A\u4ED3\u5E93\u662F\u5426\u51C6\u5907\u597D\u53D1\u5E03 v1.2\uFF1F' },\n { field: 'target', text: '\u5BF9\u5F53\u524D\u5206\u652F\u505A\u53D1\u5E03\u524D\u5C31\u7EEA\u68C0\u67E5' },\n ],\n },\n },\n tags: ['release', 'quality', 'validation'],\n estimatedAgents: { min: 6, max: 7 },\n phases: [\n { title: 'Scope' },\n { title: 'Checks' },\n { title: 'Verdict' },\n ],\n}\n\nconst READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'shell']\n\nconst target = args && typeof args === 'object' && args.target\n ? String(args.target)\n : 'Current working tree or release candidate from the conversation context.'\n\nconst ALL_CHECKS = [\n { key: 'regression', focus: 'Behavior changes, compatibility breaks, edge cases, and accidental scope creep.' },\n { key: 'tests', focus: 'Relevant automated tests, missing regression cases, flaky or weak assertions, and manual coverage gaps.' },\n { key: 'build', focus: 'Typecheck, lint, build, packaging, lazy imports, generated assets, and dependency correctness.' },\n { key: 'security', focus: 'Secrets, auth/authz, input validation, unsafe shell/file/network access, and data exposure.' },\n { key: 'ops', focus: 'Logging, observability, migrations, persistence, rollback, failure modes, and supportability.' },\n]\n\nlet checks = ALL_CHECKS\nif (args && typeof args === 'object' && Array.isArray(args.checks) && args.checks.length) {\n const selected = new Set(args.checks.map((check) => String(check)))\n checks = ALL_CHECKS.filter((check) => selected.has(check.key))\n if (!checks.length) checks = ALL_CHECKS\n}\n\nphase('Scope')\nconst scope = await agent(\n 'Identify the release candidate scope. Inspect the working tree or target if useful. Return changed areas, user-visible behavior, and likely blast radius.\\n\\n' +\n 'TARGET:\\n' + target,\n {\n label: 'release scope',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n changedAreas: { type: 'array', items: { type: 'string' } },\n userVisibleChanges: { type: 'array', items: { type: 'string' } },\n blastRadius: { type: 'string' },\n },\n required: ['changedAreas', 'blastRadius'],\n },\n },\n)\n\nphase('Checks')\nconst reports = await parallel(\n checks.map((check) => () =>\n agent(\n 'Run a release-readiness check through the ' + check.key + ' lens.\\n' +\n 'Focus: ' + check.focus + '\\n\\n' +\n 'TARGET:\\n' + target + '\\n\\n' +\n 'SCOPE:\\n' + JSON.stringify(scope, null, 2) + '\\n\\n' +\n 'Return blockers, warnings, evidence, and concrete fixes. Prefer specific files/commands over generic statements.',\n {\n label: check.key + ' check',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n blockers: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n evidence: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['title', 'evidence', 'fix'],\n },\n },\n warnings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n evidence: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['title', 'evidence'],\n },\n },\n recommendedCommands: { type: 'array', items: { type: 'string' } },\n },\n required: ['blockers', 'warnings'],\n },\n },\n ),\n ),\n)\n\nphase('Verdict')\nconst byCheck = {}\nfor (let i = 0; i < checks.length; i++) {\n byCheck[checks[i].key] = reports[i] ?? { blockers: [], warnings: [], recommendedCommands: [] }\n}\n\nconst verdict = await agent(\n 'Synthesize a release go/no-go verdict. Block if any credible blocker remains. If not blocked, distinguish ship_now from ship_after_checks. ' +\n 'Deduplicate issues and produce the shortest checklist that would make this release safe.\\n\\n' +\n JSON.stringify({ target, scope, byCheck }, null, 2),\n {\n label: 'release verdict',\n schema: {\n type: 'object',\n properties: {\n recommendation: { type: 'string', enum: ['ship_now', 'ship_after_checks', 'block'] },\n summary: { type: 'string' },\n blockers: { type: 'array', items: { type: 'string' } },\n finalChecklist: { type: 'array', items: { type: 'string' } },\n commandsToRun: { type: 'array', items: { type: 'string' } },\n },\n required: ['recommendation', 'summary', 'blockers', 'finalChecklist'],\n },\n },\n)\n\nconst output = {\n ok: true,\n target,\n checks: checks.map((check) => check.key),\n scope,\n ...(verdict ?? { recommendation: 'ship_after_checks', summary: 'verdict failed', blockers: [], finalChecklist: [] }),\n byCheck,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'risks', title: 'Blockers', items: output.blockers.map((title) => ({ title, severity: 'high' })) },\n { kind: 'questions', title: 'Final checklist', items: output.finalChecklist },\n { kind: 'questions', title: 'Commands to run', items: output.commandsToRun ?? [] },\n ],\n structuredOutput: output,\n}\n";
11
+ export declare const RELEASE_CHECK_SCRIPT = "export const meta = {\n name: 'release_check',\n description: 'Assess whether a change is ready to release with parallel risk checks and a go/no-go verdict.',\n whenToUse: 'User is near the end of implementation and wants a release-quality readiness check before shipping.',\n examplePrompts: [\n { field: 'target', text: 'Is this repo ready to release v1.2?' },\n { field: 'target', text: 'Pre-release readiness check for the current branch' },\n ],\n i18n: {\n zh: {\n description: '\u5E76\u884C\u68C0\u67E5\u53D1\u5E03\u98CE\u9669\uFF0C\u5224\u65AD\u53D8\u66F4\u662F\u5426\u8FBE\u5230\u53EF\u53D1\u5E03\u6807\u51C6\u3002',\n whenToUse: '\u7528\u6237\u63A5\u8FD1\u5F00\u53D1\u5C3E\u58F0\uFF0C\u60F3\u5728\u53D1\u5E03\u524D\u505A\u53D1\u5E03\u8D28\u91CF/\u5C31\u7EEA\u68C0\u67E5\u65F6\u3002',\n examplePrompts: [\n { field: 'target', text: '\u8FD9\u4E2A\u4ED3\u5E93\u662F\u5426\u51C6\u5907\u597D\u53D1\u5E03 v1.2\uFF1F' },\n { field: 'target', text: '\u5BF9\u5F53\u524D\u5206\u652F\u505A\u53D1\u5E03\u524D\u5C31\u7EEA\u68C0\u67E5' },\n ],\n },\n },\n tags: ['release', 'quality', 'validation'],\n estimatedAgents: { min: 6, max: 7 },\n phases: [\n { title: 'Scope' },\n { title: 'Checks' },\n { title: 'Verdict' },\n ],\n}\n\nconst READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'exec_command']\n\nconst target = args && typeof args === 'object' && args.target\n ? String(args.target)\n : 'Current working tree or release candidate from the conversation context.'\n\nconst ALL_CHECKS = [\n { key: 'regression', focus: 'Behavior changes, compatibility breaks, edge cases, and accidental scope creep.' },\n { key: 'tests', focus: 'Relevant automated tests, missing regression cases, flaky or weak assertions, and manual coverage gaps.' },\n { key: 'build', focus: 'Typecheck, lint, build, packaging, lazy imports, generated assets, and dependency correctness.' },\n { key: 'security', focus: 'Secrets, auth/authz, input validation, unsafe shell/file/network access, and data exposure.' },\n { key: 'ops', focus: 'Logging, observability, migrations, persistence, rollback, failure modes, and supportability.' },\n]\n\nlet checks = ALL_CHECKS\nif (args && typeof args === 'object' && Array.isArray(args.checks) && args.checks.length) {\n const selected = new Set(args.checks.map((check) => String(check)))\n checks = ALL_CHECKS.filter((check) => selected.has(check.key))\n if (!checks.length) checks = ALL_CHECKS\n}\n\nphase('Scope')\nconst scope = await agent(\n 'Identify the release candidate scope. Inspect the working tree or target if useful. Return changed areas, user-visible behavior, and likely blast radius.\\n\\n' +\n 'TARGET:\\n' + target,\n {\n label: 'release scope',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n changedAreas: { type: 'array', items: { type: 'string' } },\n userVisibleChanges: { type: 'array', items: { type: 'string' } },\n blastRadius: { type: 'string' },\n },\n required: ['changedAreas', 'blastRadius'],\n },\n },\n)\n\nphase('Checks')\nconst reports = await parallel(\n checks.map((check) => () =>\n agent(\n 'Run a release-readiness check through the ' + check.key + ' lens.\\n' +\n 'Focus: ' + check.focus + '\\n\\n' +\n 'TARGET:\\n' + target + '\\n\\n' +\n 'SCOPE:\\n' + JSON.stringify(scope, null, 2) + '\\n\\n' +\n 'Return blockers, warnings, evidence, and concrete fixes. Prefer specific files/commands over generic statements.',\n {\n label: check.key + ' check',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n blockers: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n evidence: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['title', 'evidence', 'fix'],\n },\n },\n warnings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n evidence: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['title', 'evidence'],\n },\n },\n recommendedCommands: { type: 'array', items: { type: 'string' } },\n },\n required: ['blockers', 'warnings'],\n },\n },\n ),\n ),\n)\n\nphase('Verdict')\nconst byCheck = {}\nfor (let i = 0; i < checks.length; i++) {\n byCheck[checks[i].key] = reports[i] ?? { blockers: [], warnings: [], recommendedCommands: [] }\n}\n\nconst verdict = await agent(\n 'Synthesize a release go/no-go verdict. Block if any credible blocker remains. If not blocked, distinguish ship_now from ship_after_checks. ' +\n 'Deduplicate issues and produce the shortest checklist that would make this release safe.\\n\\n' +\n JSON.stringify({ target, scope, byCheck }, null, 2),\n {\n label: 'release verdict',\n schema: {\n type: 'object',\n properties: {\n recommendation: { type: 'string', enum: ['ship_now', 'ship_after_checks', 'block'] },\n summary: { type: 'string' },\n blockers: { type: 'array', items: { type: 'string' } },\n finalChecklist: { type: 'array', items: { type: 'string' } },\n commandsToRun: { type: 'array', items: { type: 'string' } },\n },\n required: ['recommendation', 'summary', 'blockers', 'finalChecklist'],\n },\n },\n)\n\nconst output = {\n ok: true,\n target,\n checks: checks.map((check) => check.key),\n scope,\n ...(verdict ?? { recommendation: 'ship_after_checks', summary: 'verdict failed', blockers: [], finalChecklist: [] }),\n byCheck,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'risks', title: 'Blockers', items: output.blockers.map((title) => ({ title, severity: 'high' })) },\n { kind: 'questions', title: 'Final checklist', items: output.finalChecklist },\n { kind: 'questions', title: 'Commands to run', items: output.commandsToRun ?? [] },\n ],\n structuredOutput: output,\n}\n";
@@ -36,7 +36,7 @@ const RELEASE_CHECK_SCRIPT = `export const meta = {
36
36
  ],
37
37
  }
38
38
 
39
- const READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'shell']
39
+ const READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'exec_command']
40
40
 
41
41
  const target = args && typeof args === 'object' && args.target
42
42
  ? String(args.target)
@@ -1 +1 @@
1
- {"version":3,"file":"release-check.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/release-check.ts"],"sourcesContent":["/**\n * Built-in workflow: `release_check`\n *\n * Runs a release-readiness review for a finished change. It inspects the diff,\n * validates risk areas in parallel, and produces a go/no-go checklist.\n *\n * Args:\n * - target: release candidate, branch, commit range, or feature summary\n * - checks: optional subset of check keys\n */\n\nexport const RELEASE_CHECK_SCRIPT = `export const meta = {\n name: 'release_check',\n description: 'Assess whether a change is ready to release with parallel risk checks and a go/no-go verdict.',\n whenToUse: 'User is near the end of implementation and wants a release-quality readiness check before shipping.',\n examplePrompts: [\n { field: 'target', text: 'Is this repo ready to release v1.2?' },\n { field: 'target', text: 'Pre-release readiness check for the current branch' },\n ],\n i18n: {\n zh: {\n description: '并行检查发布风险,判断变更是否达到可发布标准。',\n whenToUse: '用户接近开发尾声,想在发布前做发布质量/就绪检查时。',\n examplePrompts: [\n { field: 'target', text: '这个仓库是否准备好发布 v1.2?' },\n { field: 'target', text: '对当前分支做发布前就绪检查' },\n ],\n },\n },\n tags: ['release', 'quality', 'validation'],\n estimatedAgents: { min: 6, max: 7 },\n phases: [\n { title: 'Scope' },\n { title: 'Checks' },\n { title: 'Verdict' },\n ],\n}\n\nconst READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'shell']\n\nconst target = args && typeof args === 'object' && args.target\n ? String(args.target)\n : 'Current working tree or release candidate from the conversation context.'\n\nconst ALL_CHECKS = [\n { key: 'regression', focus: 'Behavior changes, compatibility breaks, edge cases, and accidental scope creep.' },\n { key: 'tests', focus: 'Relevant automated tests, missing regression cases, flaky or weak assertions, and manual coverage gaps.' },\n { key: 'build', focus: 'Typecheck, lint, build, packaging, lazy imports, generated assets, and dependency correctness.' },\n { key: 'security', focus: 'Secrets, auth/authz, input validation, unsafe shell/file/network access, and data exposure.' },\n { key: 'ops', focus: 'Logging, observability, migrations, persistence, rollback, failure modes, and supportability.' },\n]\n\nlet checks = ALL_CHECKS\nif (args && typeof args === 'object' && Array.isArray(args.checks) && args.checks.length) {\n const selected = new Set(args.checks.map((check) => String(check)))\n checks = ALL_CHECKS.filter((check) => selected.has(check.key))\n if (!checks.length) checks = ALL_CHECKS\n}\n\nphase('Scope')\nconst scope = await agent(\n 'Identify the release candidate scope. Inspect the working tree or target if useful. Return changed areas, user-visible behavior, and likely blast radius.\\\\n\\\\n' +\n 'TARGET:\\\\n' + target,\n {\n label: 'release scope',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n changedAreas: { type: 'array', items: { type: 'string' } },\n userVisibleChanges: { type: 'array', items: { type: 'string' } },\n blastRadius: { type: 'string' },\n },\n required: ['changedAreas', 'blastRadius'],\n },\n },\n)\n\nphase('Checks')\nconst reports = await parallel(\n checks.map((check) => () =>\n agent(\n 'Run a release-readiness check through the ' + check.key + ' lens.\\\\n' +\n 'Focus: ' + check.focus + '\\\\n\\\\n' +\n 'TARGET:\\\\n' + target + '\\\\n\\\\n' +\n 'SCOPE:\\\\n' + JSON.stringify(scope, null, 2) + '\\\\n\\\\n' +\n 'Return blockers, warnings, evidence, and concrete fixes. Prefer specific files/commands over generic statements.',\n {\n label: check.key + ' check',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n blockers: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n evidence: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['title', 'evidence', 'fix'],\n },\n },\n warnings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n evidence: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['title', 'evidence'],\n },\n },\n recommendedCommands: { type: 'array', items: { type: 'string' } },\n },\n required: ['blockers', 'warnings'],\n },\n },\n ),\n ),\n)\n\nphase('Verdict')\nconst byCheck = {}\nfor (let i = 0; i < checks.length; i++) {\n byCheck[checks[i].key] = reports[i] ?? { blockers: [], warnings: [], recommendedCommands: [] }\n}\n\nconst verdict = await agent(\n 'Synthesize a release go/no-go verdict. Block if any credible blocker remains. If not blocked, distinguish ship_now from ship_after_checks. ' +\n 'Deduplicate issues and produce the shortest checklist that would make this release safe.\\\\n\\\\n' +\n JSON.stringify({ target, scope, byCheck }, null, 2),\n {\n label: 'release verdict',\n schema: {\n type: 'object',\n properties: {\n recommendation: { type: 'string', enum: ['ship_now', 'ship_after_checks', 'block'] },\n summary: { type: 'string' },\n blockers: { type: 'array', items: { type: 'string' } },\n finalChecklist: { type: 'array', items: { type: 'string' } },\n commandsToRun: { type: 'array', items: { type: 'string' } },\n },\n required: ['recommendation', 'summary', 'blockers', 'finalChecklist'],\n },\n },\n)\n\nconst output = {\n ok: true,\n target,\n checks: checks.map((check) => check.key),\n scope,\n ...(verdict ?? { recommendation: 'ship_after_checks', summary: 'verdict failed', blockers: [], finalChecklist: [] }),\n byCheck,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'risks', title: 'Blockers', items: output.blockers.map((title) => ({ title, severity: 'high' })) },\n { kind: 'questions', title: 'Final checklist', items: output.finalChecklist },\n { kind: 'questions', title: 'Commands to run', items: output.commandsToRun ?? [] },\n ],\n structuredOutput: output,\n}\n`\n"],"mappings":";;;;;;;;;;;AAWA,MAAa,uBAAuB"}
1
+ {"version":3,"file":"release-check.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/release-check.ts"],"sourcesContent":["/**\n * Built-in workflow: `release_check`\n *\n * Runs a release-readiness review for a finished change. It inspects the diff,\n * validates risk areas in parallel, and produces a go/no-go checklist.\n *\n * Args:\n * - target: release candidate, branch, commit range, or feature summary\n * - checks: optional subset of check keys\n */\n\nexport const RELEASE_CHECK_SCRIPT = `export const meta = {\n name: 'release_check',\n description: 'Assess whether a change is ready to release with parallel risk checks and a go/no-go verdict.',\n whenToUse: 'User is near the end of implementation and wants a release-quality readiness check before shipping.',\n examplePrompts: [\n { field: 'target', text: 'Is this repo ready to release v1.2?' },\n { field: 'target', text: 'Pre-release readiness check for the current branch' },\n ],\n i18n: {\n zh: {\n description: '并行检查发布风险,判断变更是否达到可发布标准。',\n whenToUse: '用户接近开发尾声,想在发布前做发布质量/就绪检查时。',\n examplePrompts: [\n { field: 'target', text: '这个仓库是否准备好发布 v1.2?' },\n { field: 'target', text: '对当前分支做发布前就绪检查' },\n ],\n },\n },\n tags: ['release', 'quality', 'validation'],\n estimatedAgents: { min: 6, max: 7 },\n phases: [\n { title: 'Scope' },\n { title: 'Checks' },\n { title: 'Verdict' },\n ],\n}\n\nconst READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir', 'exec_command']\n\nconst target = args && typeof args === 'object' && args.target\n ? String(args.target)\n : 'Current working tree or release candidate from the conversation context.'\n\nconst ALL_CHECKS = [\n { key: 'regression', focus: 'Behavior changes, compatibility breaks, edge cases, and accidental scope creep.' },\n { key: 'tests', focus: 'Relevant automated tests, missing regression cases, flaky or weak assertions, and manual coverage gaps.' },\n { key: 'build', focus: 'Typecheck, lint, build, packaging, lazy imports, generated assets, and dependency correctness.' },\n { key: 'security', focus: 'Secrets, auth/authz, input validation, unsafe shell/file/network access, and data exposure.' },\n { key: 'ops', focus: 'Logging, observability, migrations, persistence, rollback, failure modes, and supportability.' },\n]\n\nlet checks = ALL_CHECKS\nif (args && typeof args === 'object' && Array.isArray(args.checks) && args.checks.length) {\n const selected = new Set(args.checks.map((check) => String(check)))\n checks = ALL_CHECKS.filter((check) => selected.has(check.key))\n if (!checks.length) checks = ALL_CHECKS\n}\n\nphase('Scope')\nconst scope = await agent(\n 'Identify the release candidate scope. Inspect the working tree or target if useful. Return changed areas, user-visible behavior, and likely blast radius.\\\\n\\\\n' +\n 'TARGET:\\\\n' + target,\n {\n label: 'release scope',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n changedAreas: { type: 'array', items: { type: 'string' } },\n userVisibleChanges: { type: 'array', items: { type: 'string' } },\n blastRadius: { type: 'string' },\n },\n required: ['changedAreas', 'blastRadius'],\n },\n },\n)\n\nphase('Checks')\nconst reports = await parallel(\n checks.map((check) => () =>\n agent(\n 'Run a release-readiness check through the ' + check.key + ' lens.\\\\n' +\n 'Focus: ' + check.focus + '\\\\n\\\\n' +\n 'TARGET:\\\\n' + target + '\\\\n\\\\n' +\n 'SCOPE:\\\\n' + JSON.stringify(scope, null, 2) + '\\\\n\\\\n' +\n 'Return blockers, warnings, evidence, and concrete fixes. Prefer specific files/commands over generic statements.',\n {\n label: check.key + ' check',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n blockers: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n evidence: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['title', 'evidence', 'fix'],\n },\n },\n warnings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n evidence: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['title', 'evidence'],\n },\n },\n recommendedCommands: { type: 'array', items: { type: 'string' } },\n },\n required: ['blockers', 'warnings'],\n },\n },\n ),\n ),\n)\n\nphase('Verdict')\nconst byCheck = {}\nfor (let i = 0; i < checks.length; i++) {\n byCheck[checks[i].key] = reports[i] ?? { blockers: [], warnings: [], recommendedCommands: [] }\n}\n\nconst verdict = await agent(\n 'Synthesize a release go/no-go verdict. Block if any credible blocker remains. If not blocked, distinguish ship_now from ship_after_checks. ' +\n 'Deduplicate issues and produce the shortest checklist that would make this release safe.\\\\n\\\\n' +\n JSON.stringify({ target, scope, byCheck }, null, 2),\n {\n label: 'release verdict',\n schema: {\n type: 'object',\n properties: {\n recommendation: { type: 'string', enum: ['ship_now', 'ship_after_checks', 'block'] },\n summary: { type: 'string' },\n blockers: { type: 'array', items: { type: 'string' } },\n finalChecklist: { type: 'array', items: { type: 'string' } },\n commandsToRun: { type: 'array', items: { type: 'string' } },\n },\n required: ['recommendation', 'summary', 'blockers', 'finalChecklist'],\n },\n },\n)\n\nconst output = {\n ok: true,\n target,\n checks: checks.map((check) => check.key),\n scope,\n ...(verdict ?? { recommendation: 'ship_after_checks', summary: 'verdict failed', blockers: [], finalChecklist: [] }),\n byCheck,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'risks', title: 'Blockers', items: output.blockers.map((title) => ({ title, severity: 'high' })) },\n { kind: 'questions', title: 'Final checklist', items: output.finalChecklist },\n { kind: 'questions', title: 'Commands to run', items: output.commandsToRun ?? [] },\n ],\n structuredOutput: output,\n}\n`\n"],"mappings":";;;;;;;;;;;AAWA,MAAa,uBAAuB"}
@@ -7,10 +7,11 @@ const MAX_DETAIL_LEN = 120;
7
7
  function workflowStepLabel(toolName, args) {
8
8
  const n = toolName.toLowerCase().replace(/-/g, "_").trim();
9
9
  let label = toolName.trim() || "tool";
10
- if (n === "shell") label = "Run command";
10
+ if (n === "exec_command") label = "Run command";
11
+ else if (n === "update_plan") label = "Update plan";
11
12
  else if (n === "list_dir" || n === "ls") label = "List directory";
12
13
  else if (n === "write_file") label = "Write file";
13
- else if (n === "edit_file") label = "Edit file";
14
+ else if (n === "apply_patch") label = "Edit file";
14
15
  else if (n === "web_fetch") label = "Fetch URL";
15
16
  else if (n === "open_url") label = "Open URL";
16
17
  else if (n === "grep" || n === "rg" || n === "file_grep") label = "Search files";
@@ -34,7 +35,10 @@ function extractStepDetail(toolKey, args) {
34
35
  const v = args[key];
35
36
  if (typeof v === "string" && v.trim()) return truncate(v.trim());
36
37
  }
37
- if (toolKey === "shell" && typeof args.command === "string" && args.command.trim()) return truncate(args.command.trim());
38
+ if (toolKey === "exec_command") {
39
+ const command = typeof args.cmd === "string" ? args.cmd : typeof args.command === "string" ? args.command : "";
40
+ if (command.trim()) return truncate(command.trim());
41
+ }
38
42
  if ((toolKey.includes("search") || toolKey === "grep" || toolKey === "rg" || toolKey === "file_grep") && typeof args.query === "string" && args.query.trim()) return truncate(args.query.trim());
39
43
  if (typeof args.url === "string" && args.url.trim()) return truncate(args.url.trim());
40
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"step-labels.js","names":[],"sources":["../../../../src/agent/workflow/step-labels.ts"],"sourcesContent":["/**\n * Human-readable labels for workflow subagent tool steps (server-side snapshot).\n * Mirrors the web `tool-friendly-title` rules so IM/TUI and gateway stay aligned.\n */\n\nconst MAX_DETAIL_LEN = 120;\n\nexport function workflowStepLabel(\n toolName: string,\n args: Record<string, unknown>,\n): { label: string; detail?: string } {\n const n = toolName.toLowerCase().replace(/-/g, '_').trim();\n let label = toolName.trim() || 'tool';\n if (n === 'shell') label = 'Run command';\n else if (n === 'list_dir' || n === 'ls') label = 'List directory';\n else if (n === 'write_file') label = 'Write file';\n else if (n === 'edit_file') label = 'Edit file';\n else if (n === 'web_fetch') label = 'Fetch URL';\n else if (n === 'open_url') label = 'Open URL';\n else if (n === 'grep' || n === 'rg' || n === 'file_grep') label = 'Search files';\n else if (n === 'web_search' || n === 'brave_search' || n.includes('search')) label = 'Search web';\n else if (n === 'read_file' || n.includes('read_file') || n.includes('file_read')) label = 'Read file';\n else if (n === 'delegate_task' || n === 'workflow') label = toolName;\n\n const detail = extractStepDetail(n, args);\n return detail ? { label, detail } : { label };\n}\n\nfunction extractStepDetail(toolKey: string, args: Record<string, unknown>): string | undefined {\n const pathKeys = ['path', 'file_path', 'filePath', 'target_file', 'targetFile'];\n for (const key of pathKeys) {\n const v = args[key];\n if (typeof v === 'string' && v.trim()) return truncate(v.trim());\n }\n if (toolKey === 'shell' && typeof args.command === 'string' && args.command.trim()) {\n return truncate(args.command.trim());\n }\n if (\n (toolKey.includes('search') || toolKey === 'grep' || toolKey === 'rg' || toolKey === 'file_grep') &&\n typeof args.query === 'string' &&\n args.query.trim()\n ) {\n return truncate(args.query.trim());\n }\n if (typeof args.url === 'string' && args.url.trim()) return truncate(args.url.trim());\n return undefined;\n}\n\nfunction truncate(text: string): string {\n if (text.length <= MAX_DETAIL_LEN) return text;\n return `${text.slice(0, MAX_DETAIL_LEN - 1)}…`;\n}\n"],"mappings":";;;;;AAKA,MAAM,iBAAiB;AAEvB,SAAgB,kBACd,UACA,MACoC;CACpC,MAAM,IAAI,SAAS,aAAa,CAAC,QAAQ,MAAM,IAAI,CAAC,MAAM;CAC1D,IAAI,QAAQ,SAAS,MAAM,IAAI;AAC/B,KAAI,MAAM,QAAS,SAAQ;UAClB,MAAM,cAAc,MAAM,KAAM,SAAQ;UACxC,MAAM,aAAc,SAAQ;UAC5B,MAAM,YAAa,SAAQ;UAC3B,MAAM,YAAa,SAAQ;UAC3B,MAAM,WAAY,SAAQ;UAC1B,MAAM,UAAU,MAAM,QAAQ,MAAM,YAAa,SAAQ;UACzD,MAAM,gBAAgB,MAAM,kBAAkB,EAAE,SAAS,SAAS,CAAE,SAAQ;UAC5E,MAAM,eAAe,EAAE,SAAS,YAAY,IAAI,EAAE,SAAS,YAAY,CAAE,SAAQ;UACjF,MAAM,mBAAmB,MAAM,WAAY,SAAQ;CAE5D,MAAM,SAAS,kBAAkB,GAAG,KAAK;AACzC,QAAO,SAAS;EAAE;EAAO;EAAQ,GAAG,EAAE,OAAO;;AAG/C,SAAS,kBAAkB,SAAiB,MAAmD;AAE7F,MAAK,MAAM,OAAO;EADA;EAAQ;EAAa;EAAY;EAAe;EACxC,EAAE;EAC1B,MAAM,IAAI,KAAK;AACf,MAAI,OAAO,MAAM,YAAY,EAAE,MAAM,CAAE,QAAO,SAAS,EAAE,MAAM,CAAC;;AAElE,KAAI,YAAY,WAAW,OAAO,KAAK,YAAY,YAAY,KAAK,QAAQ,MAAM,CAChF,QAAO,SAAS,KAAK,QAAQ,MAAM,CAAC;AAEtC,MACG,QAAQ,SAAS,SAAS,IAAI,YAAY,UAAU,YAAY,QAAQ,YAAY,gBACrF,OAAO,KAAK,UAAU,YACtB,KAAK,MAAM,MAAM,CAEjB,QAAO,SAAS,KAAK,MAAM,MAAM,CAAC;AAEpC,KAAI,OAAO,KAAK,QAAQ,YAAY,KAAK,IAAI,MAAM,CAAE,QAAO,SAAS,KAAK,IAAI,MAAM,CAAC;;AAIvF,SAAS,SAAS,MAAsB;AACtC,KAAI,KAAK,UAAU,eAAgB,QAAO;AAC1C,QAAO,GAAG,KAAK,MAAM,GAAG,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"step-labels.js","names":[],"sources":["../../../../src/agent/workflow/step-labels.ts"],"sourcesContent":["/**\n * Human-readable labels for workflow subagent tool steps (server-side snapshot).\n * Mirrors the web `tool-friendly-title` rules so IM/TUI and gateway stay aligned.\n */\n\nconst MAX_DETAIL_LEN = 120;\n\nexport function workflowStepLabel(\n toolName: string,\n args: Record<string, unknown>,\n): { label: string; detail?: string } {\n const n = toolName.toLowerCase().replace(/-/g, '_').trim();\n let label = toolName.trim() || 'tool';\n if (n === 'exec_command') label = 'Run command';\n else if (n === 'update_plan') label = 'Update plan';\n else if (n === 'list_dir' || n === 'ls') label = 'List directory';\n else if (n === 'write_file') label = 'Write file';\n else if (n === 'apply_patch') label = 'Edit file';\n else if (n === 'web_fetch') label = 'Fetch URL';\n else if (n === 'open_url') label = 'Open URL';\n else if (n === 'grep' || n === 'rg' || n === 'file_grep') label = 'Search files';\n else if (n === 'web_search' || n === 'brave_search' || n.includes('search')) label = 'Search web';\n else if (n === 'read_file' || n.includes('read_file') || n.includes('file_read')) label = 'Read file';\n else if (n === 'delegate_task' || n === 'workflow') label = toolName;\n\n const detail = extractStepDetail(n, args);\n return detail ? { label, detail } : { label };\n}\n\nfunction extractStepDetail(toolKey: string, args: Record<string, unknown>): string | undefined {\n const pathKeys = ['path', 'file_path', 'filePath', 'target_file', 'targetFile'];\n for (const key of pathKeys) {\n const v = args[key];\n if (typeof v === 'string' && v.trim()) return truncate(v.trim());\n }\n if (toolKey === 'exec_command') {\n const command = typeof args.cmd === 'string' ? args.cmd : typeof args.command === 'string' ? args.command : '';\n if (command.trim()) return truncate(command.trim());\n }\n if (\n (toolKey.includes('search') || toolKey === 'grep' || toolKey === 'rg' || toolKey === 'file_grep') &&\n typeof args.query === 'string' &&\n args.query.trim()\n ) {\n return truncate(args.query.trim());\n }\n if (typeof args.url === 'string' && args.url.trim()) return truncate(args.url.trim());\n return undefined;\n}\n\nfunction truncate(text: string): string {\n if (text.length <= MAX_DETAIL_LEN) return text;\n return `${text.slice(0, MAX_DETAIL_LEN - 1)}…`;\n}\n"],"mappings":";;;;;AAKA,MAAM,iBAAiB;AAEvB,SAAgB,kBACd,UACA,MACoC;CACpC,MAAM,IAAI,SAAS,aAAa,CAAC,QAAQ,MAAM,IAAI,CAAC,MAAM;CAC1D,IAAI,QAAQ,SAAS,MAAM,IAAI;AAC/B,KAAI,MAAM,eAAgB,SAAQ;UACzB,MAAM,cAAe,SAAQ;UAC7B,MAAM,cAAc,MAAM,KAAM,SAAQ;UACxC,MAAM,aAAc,SAAQ;UAC5B,MAAM,cAAe,SAAQ;UAC7B,MAAM,YAAa,SAAQ;UAC3B,MAAM,WAAY,SAAQ;UAC1B,MAAM,UAAU,MAAM,QAAQ,MAAM,YAAa,SAAQ;UACzD,MAAM,gBAAgB,MAAM,kBAAkB,EAAE,SAAS,SAAS,CAAE,SAAQ;UAC5E,MAAM,eAAe,EAAE,SAAS,YAAY,IAAI,EAAE,SAAS,YAAY,CAAE,SAAQ;UACjF,MAAM,mBAAmB,MAAM,WAAY,SAAQ;CAE5D,MAAM,SAAS,kBAAkB,GAAG,KAAK;AACzC,QAAO,SAAS;EAAE;EAAO;EAAQ,GAAG,EAAE,OAAO;;AAG/C,SAAS,kBAAkB,SAAiB,MAAmD;AAE7F,MAAK,MAAM,OAAO;EADA;EAAQ;EAAa;EAAY;EAAe;EACxC,EAAE;EAC1B,MAAM,IAAI,KAAK;AACf,MAAI,OAAO,MAAM,YAAY,EAAE,MAAM,CAAE,QAAO,SAAS,EAAE,MAAM,CAAC;;AAElE,KAAI,YAAY,gBAAgB;EAC9B,MAAM,UAAU,OAAO,KAAK,QAAQ,WAAW,KAAK,MAAM,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;AAC5G,MAAI,QAAQ,MAAM,CAAE,QAAO,SAAS,QAAQ,MAAM,CAAC;;AAErD,MACG,QAAQ,SAAS,SAAS,IAAI,YAAY,UAAU,YAAY,QAAQ,YAAY,gBACrF,OAAO,KAAK,UAAU,YACtB,KAAK,MAAM,MAAM,CAEjB,QAAO,SAAS,KAAK,MAAM,MAAM,CAAC;AAEpC,KAAI,OAAO,KAAK,QAAQ,YAAY,KAAK,IAAI,MAAM,CAAE,QAAO,SAAS,KAAK,IAAI,MAAM,CAAC;;AAIvF,SAAS,SAAS,MAAsB;AACtC,KAAI,KAAK,UAAU,eAAgB,QAAO;AAC1C,QAAO,GAAG,KAAK,MAAM,GAAG,iBAAiB,EAAE,CAAC"}
@@ -74,7 +74,7 @@ function buildEditInstructions(agentId, fileNames) {
74
74
  "- “Read `SOUL.md` first, propose changes, then write them back.”",
75
75
  "",
76
76
  `Editable profile files: ${files}.`,
77
- "I can read and update these by bare filename with `read_file`, `edit_file`, and `write_file`."
77
+ "I can read and update these by bare filename with `read_file`, `apply_patch`, and `write_file`."
78
78
  ].join("\n");
79
79
  }
80
80
  const agentEditCommand = {
@@ -1 +1 @@
1
- {"version":3,"file":"agent-edit.js","names":[],"sources":["../../../src/chat-commands/agent-edit.ts"],"sourcesContent":["/**\n * /agent-edit — open the current chat as an agent profile editing session.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport type { CommandContext, CommandDefinition } from './types.js';\nimport { commandRegistry } from './registry.js';\nimport { resolveAgentIdFromSessionKey } from '../routing/agent-session-key.js';\nimport { normalizeAgentId, resolveAgentProfileDir } from '../agent/agent-scope.js';\nimport { WORKSPACE_FILES } from '../config/paths.js';\n\nconst PROFILE_FILE_NAMES = [\n WORKSPACE_FILES.SOUL,\n WORKSPACE_FILES.IDENTITY,\n WORKSPACE_FILES.TOOLS,\n WORKSPACE_FILES.AGENTS,\n WORKSPACE_FILES.HEARTBEAT,\n WORKSPACE_FILES.MEMORY,\n] as const;\n\nconst DEFAULT_PREVIEW_CHARS = 900;\nconst MAX_PREVIEW_CHARS = 4_000;\n\nfunction parseArgs(args: string): { fileName?: string; previewChars: number } {\n const trimmed = args.trim();\n if (!trimmed) {\n return { previewChars: DEFAULT_PREVIEW_CHARS };\n }\n\n const parts = trimmed.split(/\\s+/);\n let fileName: string | undefined;\n let previewChars = DEFAULT_PREVIEW_CHARS;\n\n for (const part of parts) {\n const limitMatch = /^--limit=(\\d+)$/.exec(part);\n if (limitMatch) {\n previewChars = Math.min(Number(limitMatch[1]), MAX_PREVIEW_CHARS);\n continue;\n }\n if (!fileName) {\n fileName = part;\n }\n }\n\n return { fileName, previewChars };\n}\n\nfunction normalizeProfileFileName(input: string | undefined): string | undefined {\n if (!input) {\n return undefined;\n }\n const basename = input.trim().replace(/\\\\/g, '/').split('/').pop();\n const matched = PROFILE_FILE_NAMES.find((name) => name.toLowerCase() === basename?.toLowerCase());\n return matched;\n}\n\nasync function readPreview(path: string, limit: number): Promise<{ content: string; missing: boolean }> {\n try {\n const content = await readFile(path, 'utf-8');\n const trimmed = content.trimEnd();\n if (trimmed.length <= limit) {\n return { content: trimmed, missing: false };\n }\n return {\n content: `${trimmed.slice(0, limit)}\\n\\n… truncated, ask me to read the full file before editing …`,\n missing: false,\n };\n } catch {\n return { content: '', missing: true };\n }\n}\n\nfunction buildEditInstructions(agentId: string, fileNames: readonly string[]): string {\n const files = fileNames.map((name) => `\\`${name}\\``).join(', ');\n return [\n `You are editing agent \\`${agentId}\\`.`,\n '',\n 'Tell me what to change, or say things like:',\n '- “Refine `SOUL.md` to sound warmer and more concise.”',\n '- “Update `IDENTITY.md` so this agent is focused on data analysis.”',\n '- “Read `SOUL.md` first, propose changes, then write them back.”',\n '',\n `Editable profile files: ${files}.`,\n 'I can read and update these by bare filename with `read_file`, `edit_file`, and `write_file`.',\n ].join('\\n');\n}\n\nconst agentEditCommand: CommandDefinition = {\n id: 'agent.edit',\n name: 'agent-edit',\n aliases: ['agentedit'],\n description: 'Show editable profile files for the current agent and prepare this chat for profile edits.',\n category: 'system',\n scope: ['global', 'private', 'group'],\n acceptsArgs: true,\n examples: ['/agent-edit', '/agent-edit SOUL.md', '/agent-edit IDENTITY.md --limit=2000'],\n handler: async (ctx: CommandContext, args: string) => {\n await ctx.setTyping(true);\n\n const { fileName: rawFileName, previewChars } = parseArgs(args);\n const fileName = normalizeProfileFileName(rawFileName);\n if (rawFileName && !fileName) {\n return {\n content: `⚠️ Unsupported profile file: \\`${rawFileName}\\`. Use one of: ${PROFILE_FILE_NAMES.map((name) => `\\`${name}\\``).join(', ')}.`,\n success: false,\n };\n }\n\n const agentId = normalizeAgentId(resolveAgentIdFromSessionKey(ctx.sessionKey));\n const profileDir = resolveAgentProfileDir(ctx.config, agentId);\n const namesToShow = fileName ? [fileName] : [WORKSPACE_FILES.SOUL, WORKSPACE_FILES.IDENTITY];\n\n const sections: string[] = [];\n for (const name of namesToShow) {\n const preview = await readPreview(join(profileDir, name), previewChars);\n if (preview.missing) {\n sections.push(`## ${name}\\n_missing_`);\n } else {\n sections.push(`## ${name}\\n\\`\\`\\`markdown\\n${preview.content}\\n\\`\\`\\``);\n }\n }\n\n return {\n content: [\n '🛠️ Agent editor mode',\n '',\n buildEditInstructions(agentId, PROFILE_FILE_NAMES),\n '',\n `Profile directory: \\`${profileDir}\\``,\n '',\n ...sections,\n ].join('\\n'),\n success: true,\n };\n },\n};\n\nexport function registerAgentEditCommand(): void {\n commandRegistry.register(agentEditCommand);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent-edit.js","names":[],"sources":["../../../src/chat-commands/agent-edit.ts"],"sourcesContent":["/**\n * /agent-edit — open the current chat as an agent profile editing session.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport type { CommandContext, CommandDefinition } from './types.js';\nimport { commandRegistry } from './registry.js';\nimport { resolveAgentIdFromSessionKey } from '../routing/agent-session-key.js';\nimport { normalizeAgentId, resolveAgentProfileDir } from '../agent/agent-scope.js';\nimport { WORKSPACE_FILES } from '../config/paths.js';\n\nconst PROFILE_FILE_NAMES = [\n WORKSPACE_FILES.SOUL,\n WORKSPACE_FILES.IDENTITY,\n WORKSPACE_FILES.TOOLS,\n WORKSPACE_FILES.AGENTS,\n WORKSPACE_FILES.HEARTBEAT,\n WORKSPACE_FILES.MEMORY,\n] as const;\n\nconst DEFAULT_PREVIEW_CHARS = 900;\nconst MAX_PREVIEW_CHARS = 4_000;\n\nfunction parseArgs(args: string): { fileName?: string; previewChars: number } {\n const trimmed = args.trim();\n if (!trimmed) {\n return { previewChars: DEFAULT_PREVIEW_CHARS };\n }\n\n const parts = trimmed.split(/\\s+/);\n let fileName: string | undefined;\n let previewChars = DEFAULT_PREVIEW_CHARS;\n\n for (const part of parts) {\n const limitMatch = /^--limit=(\\d+)$/.exec(part);\n if (limitMatch) {\n previewChars = Math.min(Number(limitMatch[1]), MAX_PREVIEW_CHARS);\n continue;\n }\n if (!fileName) {\n fileName = part;\n }\n }\n\n return { fileName, previewChars };\n}\n\nfunction normalizeProfileFileName(input: string | undefined): string | undefined {\n if (!input) {\n return undefined;\n }\n const basename = input.trim().replace(/\\\\/g, '/').split('/').pop();\n const matched = PROFILE_FILE_NAMES.find((name) => name.toLowerCase() === basename?.toLowerCase());\n return matched;\n}\n\nasync function readPreview(path: string, limit: number): Promise<{ content: string; missing: boolean }> {\n try {\n const content = await readFile(path, 'utf-8');\n const trimmed = content.trimEnd();\n if (trimmed.length <= limit) {\n return { content: trimmed, missing: false };\n }\n return {\n content: `${trimmed.slice(0, limit)}\\n\\n… truncated, ask me to read the full file before editing …`,\n missing: false,\n };\n } catch {\n return { content: '', missing: true };\n }\n}\n\nfunction buildEditInstructions(agentId: string, fileNames: readonly string[]): string {\n const files = fileNames.map((name) => `\\`${name}\\``).join(', ');\n return [\n `You are editing agent \\`${agentId}\\`.`,\n '',\n 'Tell me what to change, or say things like:',\n '- “Refine `SOUL.md` to sound warmer and more concise.”',\n '- “Update `IDENTITY.md` so this agent is focused on data analysis.”',\n '- “Read `SOUL.md` first, propose changes, then write them back.”',\n '',\n `Editable profile files: ${files}.`,\n 'I can read and update these by bare filename with `read_file`, `apply_patch`, and `write_file`.',\n ].join('\\n');\n}\n\nconst agentEditCommand: CommandDefinition = {\n id: 'agent.edit',\n name: 'agent-edit',\n aliases: ['agentedit'],\n description: 'Show editable profile files for the current agent and prepare this chat for profile edits.',\n category: 'system',\n scope: ['global', 'private', 'group'],\n acceptsArgs: true,\n examples: ['/agent-edit', '/agent-edit SOUL.md', '/agent-edit IDENTITY.md --limit=2000'],\n handler: async (ctx: CommandContext, args: string) => {\n await ctx.setTyping(true);\n\n const { fileName: rawFileName, previewChars } = parseArgs(args);\n const fileName = normalizeProfileFileName(rawFileName);\n if (rawFileName && !fileName) {\n return {\n content: `⚠️ Unsupported profile file: \\`${rawFileName}\\`. Use one of: ${PROFILE_FILE_NAMES.map((name) => `\\`${name}\\``).join(', ')}.`,\n success: false,\n };\n }\n\n const agentId = normalizeAgentId(resolveAgentIdFromSessionKey(ctx.sessionKey));\n const profileDir = resolveAgentProfileDir(ctx.config, agentId);\n const namesToShow = fileName ? [fileName] : [WORKSPACE_FILES.SOUL, WORKSPACE_FILES.IDENTITY];\n\n const sections: string[] = [];\n for (const name of namesToShow) {\n const preview = await readPreview(join(profileDir, name), previewChars);\n if (preview.missing) {\n sections.push(`## ${name}\\n_missing_`);\n } else {\n sections.push(`## ${name}\\n\\`\\`\\`markdown\\n${preview.content}\\n\\`\\`\\``);\n }\n }\n\n return {\n content: [\n '🛠️ Agent editor mode',\n '',\n buildEditInstructions(agentId, PROFILE_FILE_NAMES),\n '',\n `Profile directory: \\`${profileDir}\\``,\n '',\n ...sections,\n ].join('\\n'),\n success: true,\n };\n },\n};\n\nexport function registerAgentEditCommand(): void {\n commandRegistry.register(agentEditCommand);\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function registerReviewCommand(): void;