@xopcai/xopc 0.0.110 → 0.0.112

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 (583) hide show
  1. package/README.md +46 -4
  2. package/README.zh-CN.md +46 -4
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  5. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  6. package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
  7. package/dist/extensions/telegram/src/inbound-processor.js +1 -1
  8. package/dist/extensions/telegram/src/plugin.js +1 -1
  9. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  10. package/dist/extensions/telegram/src/update-offset-store.js +1 -1
  11. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  12. package/dist/extensions/telegram/xopc.extension.json +1 -1
  13. package/dist/extensions/weixin/src/api/api.js +2 -2
  14. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  15. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  16. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  17. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  18. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  19. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  20. package/dist/extensions/weixin/src/plugin.js +1 -1
  21. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  22. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  23. package/dist/gateway/static/root/apple-touch-icon.png +0 -0
  24. package/dist/gateway/static/root/assets/Combination-BzaXOLd9.js +41 -0
  25. package/dist/gateway/static/root/assets/agent-avatar-dicebear-EhRp-ZMa.js +1 -0
  26. package/dist/gateway/static/root/assets/agent-browser-settings-page-H4foVCiS.js +6 -0
  27. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-DDNw2oNU.js +1 -0
  28. package/dist/gateway/static/root/assets/agents-E_X2kzS1.js +71 -0
  29. package/dist/gateway/static/root/assets/app-management-settings-panel-BIy7KEsM.js +1 -0
  30. package/dist/gateway/static/root/assets/appearance-settings-DGQG8NwA.js +1 -0
  31. package/dist/gateway/static/root/assets/apps-page-BZLvInLr.js +1 -0
  32. package/dist/gateway/static/root/assets/archive-plugin-uuQPupqx.js +1 -0
  33. package/dist/gateway/static/root/assets/attachment-load-DBkv0cAv.js +2 -0
  34. package/dist/gateway/static/root/assets/{attachment-preview-renderer-CybMSIoS.js → attachment-preview-renderer-DonnL2dL.js} +1 -1
  35. package/dist/gateway/static/root/assets/binary-plugins-DxxN_VAR.js +2 -0
  36. package/dist/gateway/static/root/assets/block-editor-CwnUlRmO.js +180 -0
  37. package/dist/gateway/static/root/assets/channels-settings-BHvUKlzw.js +1 -0
  38. package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +1 -0
  39. package/dist/gateway/static/root/assets/code-editor-dZTY2dRW.js +1 -0
  40. package/dist/gateway/static/root/assets/config-api-BD-NcD5d.js +3 -0
  41. package/dist/gateway/static/root/assets/config-reload-event-Bjh2zoKp.js +1 -0
  42. package/dist/gateway/static/root/assets/connectors-settings-VBzXcEXL.js +2 -0
  43. package/dist/gateway/static/root/assets/cron-api-C5DoipZA.js +1 -0
  44. package/dist/gateway/static/root/assets/cron-dreaming-jobs-nCMWCf0p.js +1 -0
  45. package/dist/gateway/static/root/assets/cron-page-BLTpdm34.js +3 -0
  46. package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +1 -0
  47. package/dist/gateway/static/root/assets/dist-CkobR7mk.js +1 -0
  48. package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +1 -0
  49. package/dist/gateway/static/root/assets/dreaming-scene-BHMRVEUS.js +4585 -0
  50. package/dist/gateway/static/root/assets/dreaming-settings-DSVhXTPq.js +1 -0
  51. package/dist/gateway/static/root/assets/extension-debug-page-BDHA9o_e.js +1 -0
  52. package/dist/gateway/static/root/assets/{extension-page-W1wiG38F.js → extension-page-DmDLVSPE.js} +1 -1
  53. package/dist/gateway/static/root/assets/extension-settings-page-1124aHw_.js +1 -0
  54. package/dist/gateway/static/root/assets/fetch-DOe56Wmy.js +1 -0
  55. package/dist/gateway/static/root/assets/format-cron-label-BsotZDO5.js +2 -0
  56. package/dist/gateway/static/root/assets/format-interval-label-tsMSvBSR.js +1 -0
  57. package/dist/gateway/static/root/assets/gateway-config-api-CsD4FC9D.js +1 -0
  58. package/dist/gateway/static/root/assets/gateway-settings-HQ8FBhY2.js +1 -0
  59. package/dist/gateway/static/root/assets/gateway-startup-retry-C1zg7pH3.js +1 -0
  60. package/dist/gateway/static/root/assets/goal-detail-page-BG3Onph0.js +1 -0
  61. package/dist/gateway/static/root/assets/goals-page-DgeKn8zL.js +2 -0
  62. package/dist/gateway/static/root/assets/goals-settings-B5nI6lgz.js +1 -0
  63. package/dist/gateway/static/root/assets/heartbeat-config-api-CIv42nJD.js +1 -0
  64. package/dist/gateway/static/root/assets/heartbeat-settings-DFcVuJ3M.js +1 -0
  65. package/dist/gateway/static/root/assets/html-workspace-editor-CQLWDiwE.js +1 -0
  66. package/dist/gateway/static/root/assets/index-5A_ZaABy.css +1 -0
  67. package/dist/gateway/static/root/assets/index-BTmbp2AU.js +121 -0
  68. package/dist/gateway/static/root/assets/interval-presets-DGP3S7OB.js +1 -0
  69. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-fETaDYQP.js +1 -0
  70. package/dist/gateway/static/root/assets/locale-store-DjbfSsfA.js +1 -0
  71. package/dist/gateway/static/root/assets/logs-page-B1-b27lK.js +2 -0
  72. package/dist/gateway/static/root/assets/markdown-editor-AssmZFx4.js +2 -0
  73. package/dist/gateway/static/root/assets/markdown-split-CgeBJMOD.js +1 -0
  74. package/dist/gateway/static/root/assets/media-plugins-C30GzlV2.js +1 -0
  75. package/dist/gateway/static/root/assets/mermaid-render-BbqDc_LQ.js +134 -0
  76. package/dist/gateway/static/root/assets/messages-BUUfPaZ9.js +3 -0
  77. package/dist/gateway/static/root/assets/middleware-Pd0e8Igk.js +1 -0
  78. package/dist/gateway/static/root/assets/models-hub-panel-DPcTS1-u.js +2 -0
  79. package/dist/gateway/static/root/assets/note-detail-page-xeGb4owe.js +2 -0
  80. package/dist/gateway/static/root/assets/note-image-lightbox-t1g0qZYh.js +1 -0
  81. package/dist/gateway/static/root/assets/note-time-hm6JO_Wi.js +1 -0
  82. package/dist/gateway/static/root/assets/notes-page-C_TdnKBe.js +1 -0
  83. package/dist/gateway/static/root/assets/preview-open-alternatives-DeWp9x5g.js +1 -0
  84. package/dist/gateway/static/root/assets/remote-access-hub-BtkPmJIN.js +1 -0
  85. package/dist/gateway/static/root/assets/save-bar-controls-BOaAOJI3.js +1 -0
  86. package/dist/gateway/static/root/assets/schedule-field-BLWLKqgw.js +1 -0
  87. package/dist/gateway/static/root/assets/schema-form-plqRFYT8.js +1 -0
  88. package/dist/gateway/static/root/assets/sessions-page-DOUjxzJm.js +1 -0
  89. package/dist/gateway/static/root/assets/settings-advanced-gate-qK_bnTrw.js +1 -0
  90. package/dist/gateway/static/root/assets/settings-collapsible-section-BP5zRrDI.js +1 -0
  91. package/dist/gateway/static/root/assets/settings-form-section-Bv8MZplG.js +1 -0
  92. package/dist/gateway/static/root/assets/settings-page-DmDfE1ww.js +1 -0
  93. package/dist/gateway/static/root/assets/setup-status-panel-BEFwNcIZ.js +1 -0
  94. package/dist/gateway/static/root/assets/share-preview-page-4OX1YCgp.js +2 -0
  95. package/dist/gateway/static/root/assets/shares-settings-CbKmJZot.js +1 -0
  96. package/dist/gateway/static/root/assets/skill-reload-api-YdtnUHtK.js +1 -0
  97. package/dist/gateway/static/root/assets/skills-page-DwW1IzQ0.js +2 -0
  98. package/dist/gateway/static/root/assets/system-settings-panel-CGy4f_s2.js +1 -0
  99. package/dist/gateway/static/root/assets/theme-store-CD2wtgZV.js +1 -0
  100. package/dist/gateway/static/root/assets/use-agent-defaults-form-BMuMvzl_.js +1 -0
  101. package/dist/gateway/static/root/assets/use-blob-object-url-D4BFuzZB.js +1 -0
  102. package/dist/gateway/static/root/assets/use-channel-catalog-CjGHnDvN.js +1 -0
  103. package/dist/gateway/static/root/assets/use-settings-tab-guard-BMMFa0oA.js +1 -0
  104. package/dist/gateway/static/root/assets/vendor-codemirror-CNP1wPe7.js +45 -0
  105. package/dist/gateway/static/root/assets/voice-api-key-field-DnRbhMNq.js +1 -0
  106. package/dist/gateway/static/root/assets/voice-player-store-D5vzWwls.js +1 -0
  107. package/dist/gateway/static/root/assets/{workflow-page.utils-EYg_xBQS.js → workflow-page.utils-tjGpRVnw.js} +1 -1
  108. package/dist/gateway/static/root/assets/workflows-page-DqqHKGj2.js +18 -0
  109. package/dist/gateway/static/root/favicon-16x16.png +0 -0
  110. package/dist/gateway/static/root/favicon-32x32.png +0 -0
  111. package/dist/gateway/static/root/favicon.ico +0 -0
  112. package/dist/gateway/static/root/favicon.svg +14 -12
  113. package/dist/gateway/static/root/index.html +18 -15
  114. package/dist/package.js +1 -1
  115. package/dist/src/agent/agent-manager.d.ts +28 -2
  116. package/dist/src/agent/agent-manager.js +82 -11
  117. package/dist/src/agent/agent-manager.js.map +1 -1
  118. package/dist/src/agent/agent-scope.js +1 -1
  119. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  120. package/dist/src/agent/context/workspace-seed.js +2 -2
  121. package/dist/src/agent/context/workspace-state.js +1 -1
  122. package/dist/src/agent/context/workspace.js +1 -1
  123. package/dist/src/agent/goals/checklist-judge.d.ts +5 -0
  124. package/dist/src/agent/goals/checklist-judge.js +26 -2
  125. package/dist/src/agent/goals/checklist-judge.js.map +1 -1
  126. package/dist/src/agent/goals/evaluate-turn.d.ts +5 -1
  127. package/dist/src/agent/goals/evaluate-turn.js +29 -3
  128. package/dist/src/agent/goals/evaluate-turn.js.map +1 -1
  129. package/dist/src/agent/goals/goal-locale.d.ts +0 -2
  130. package/dist/src/agent/goals/goal-locale.js +3 -16
  131. package/dist/src/agent/goals/goal-locale.js.map +1 -1
  132. package/dist/src/agent/goals/persistent-goal-service.d.ts +9 -0
  133. package/dist/src/agent/goals/persistent-goal-service.js +3 -2
  134. package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
  135. package/dist/src/agent/goals/post-turn.d.ts +7 -0
  136. package/dist/src/agent/goals/post-turn.js +70 -25
  137. package/dist/src/agent/goals/post-turn.js.map +1 -1
  138. package/dist/src/agent/goals/state.d.ts +0 -5
  139. package/dist/src/agent/goals/state.js +1 -96
  140. package/dist/src/agent/goals/state.js.map +1 -1
  141. package/dist/src/agent/image/load-image-media.js +2 -2
  142. package/dist/src/agent/ipc/inbox.js +3 -3
  143. package/dist/src/agent/ipc/socket.js +1 -1
  144. package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
  145. package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
  146. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  147. package/dist/src/agent/mcp/mcp-transport.js +1 -1
  148. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  149. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  150. package/dist/src/agent/memory/dreaming/events.js +1 -1
  151. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  152. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  153. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  154. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  155. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  156. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  157. package/dist/src/agent/memory/memory-flush.js +1 -1
  158. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  159. package/dist/src/agent/messaging/command-handler.d.ts +7 -0
  160. package/dist/src/agent/messaging/command-handler.js +11 -2
  161. package/dist/src/agent/messaging/command-handler.js.map +1 -1
  162. package/dist/src/agent/models/manager.js +1 -1
  163. package/dist/src/agent/prompt/memory/index.js +1 -1
  164. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  165. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  166. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  167. package/dist/src/agent/sandbox/path-policy.js +2 -2
  168. package/dist/src/agent/service/direct-turn-helpers.d.ts +2 -0
  169. package/dist/src/agent/service/direct-turn-helpers.js +3 -2
  170. package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
  171. package/dist/src/agent/service/process-direct-streaming.js +10 -1
  172. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  173. package/dist/src/agent/service/reconcile-dreaming-cron.js +8 -5
  174. package/dist/src/agent/service/reconcile-dreaming-cron.js.map +1 -1
  175. package/dist/src/agent/service.d.ts +2 -1
  176. package/dist/src/agent/service.js +30 -6
  177. package/dist/src/agent/service.js.map +1 -1
  178. package/dist/src/agent/service.types.d.ts +12 -0
  179. package/dist/src/agent/session/session-config-service.d.ts +8 -0
  180. package/dist/src/agent/session/session-config-service.js +20 -0
  181. package/dist/src/agent/session/session-config-service.js.map +1 -1
  182. package/dist/src/agent/session/session-inspector.js +1 -1
  183. package/dist/src/agent/skills/config.js +2 -2
  184. package/dist/src/agent/skills/filesystem-watcher.d.ts +19 -0
  185. package/dist/src/agent/skills/filesystem-watcher.js +182 -0
  186. package/dist/src/agent/skills/filesystem-watcher.js.map +1 -0
  187. package/dist/src/agent/skills/hub-hash.js +2 -2
  188. package/dist/src/agent/skills/hub-lock.js +1 -1
  189. package/dist/src/agent/skills/hub-pull.js +30 -36
  190. package/dist/src/agent/skills/hub-pull.js.map +1 -1
  191. package/dist/src/agent/skills/index.js +82 -38
  192. package/dist/src/agent/skills/index.js.map +1 -1
  193. package/dist/src/agent/skills/installer.js +2 -2
  194. package/dist/src/agent/skills/managed-store.d.ts +19 -0
  195. package/dist/src/agent/skills/managed-store.js +97 -38
  196. package/dist/src/agent/skills/managed-store.js.map +1 -1
  197. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  198. package/dist/src/agent/skills/skill-manager.d.ts +16 -6
  199. package/dist/src/agent/skills/skill-manager.js +79 -24
  200. package/dist/src/agent/skills/skill-manager.js.map +1 -1
  201. package/dist/src/agent/skills/skill-view-path.js +1 -1
  202. package/dist/src/agent/skills/test-framework.js +1 -1
  203. package/dist/src/agent/skills/types.d.ts +11 -0
  204. package/dist/src/agent/skills/watcher.js +1 -1
  205. package/dist/src/agent/starter-agents.js +1 -1
  206. package/dist/src/agent/tools/cronjob-tool.d.ts +8 -3
  207. package/dist/src/agent/tools/cronjob-tool.js +82 -24
  208. package/dist/src/agent/tools/cronjob-tool.js.map +1 -1
  209. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  210. package/dist/src/agent/tools/edit.d.ts +2 -0
  211. package/dist/src/agent/tools/edit.js +10 -0
  212. package/dist/src/agent/tools/edit.js.map +1 -1
  213. package/dist/src/agent/tools/factory.js +17 -4
  214. package/dist/src/agent/tools/factory.js.map +1 -1
  215. package/dist/src/agent/tools/find.js +1 -1
  216. package/dist/src/agent/tools/goal-evidence-recorder.d.ts +6 -0
  217. package/dist/src/agent/tools/goal-evidence-recorder.js +34 -0
  218. package/dist/src/agent/tools/goal-evidence-recorder.js.map +1 -0
  219. package/dist/src/agent/tools/goal-tool.d.ts +19 -0
  220. package/dist/src/agent/tools/goal-tool.js +101 -0
  221. package/dist/src/agent/tools/goal-tool.js.map +1 -0
  222. package/dist/src/agent/tools/grep.js +1 -1
  223. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  224. package/dist/src/agent/tools/index.d.ts +1 -0
  225. package/dist/src/agent/tools/index.js +2 -1
  226. package/dist/src/agent/tools/shell.d.ts +2 -0
  227. package/dist/src/agent/tools/shell.js +17 -2
  228. package/dist/src/agent/tools/shell.js.map +1 -1
  229. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  230. package/dist/src/agent/tools/workflow-tool.d.ts +1 -0
  231. package/dist/src/agent/tools/workflow-tool.js +11 -3
  232. package/dist/src/agent/tools/workflow-tool.js.map +1 -1
  233. package/dist/src/agent/tools/write.d.ts +2 -0
  234. package/dist/src/agent/tools/write.js +11 -0
  235. package/dist/src/agent/tools/write.js.map +1 -1
  236. package/dist/src/agent/workflow/catalog.js +1 -1
  237. package/dist/src/agent/workspace-runtime/registry.d.ts +5 -0
  238. package/dist/src/agent/workspace-runtime/registry.js +7 -0
  239. package/dist/src/agent/workspace-runtime/registry.js.map +1 -1
  240. package/dist/src/ai-assist/text-assist.d.ts +39 -0
  241. package/dist/src/ai-assist/text-assist.js +234 -0
  242. package/dist/src/ai-assist/text-assist.js.map +1 -0
  243. package/dist/src/auth/credentials.js +2 -2
  244. package/dist/src/auth/profiles/store.js +2 -2
  245. package/dist/src/auth/sync-provider-auth.js +1 -1
  246. package/dist/src/browser/cache-dir-policy.js +1 -1
  247. package/dist/src/browser/cdp-local-launcher.js +2 -2
  248. package/dist/src/browser/providers/browser-ext-install.js +4 -4
  249. package/dist/src/browser/providers/cloakbrowser.js +5 -5
  250. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  251. package/dist/src/browser/stealth.js +1 -1
  252. package/dist/src/channels/attachments/inbound-persist.d.ts +7 -0
  253. package/dist/src/channels/attachments/inbound-persist.js +20 -2
  254. package/dist/src/channels/attachments/inbound-persist.js.map +1 -1
  255. package/dist/src/channels/outbound/persist-store.js +1 -1
  256. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  257. package/dist/src/channels/pairing/pairing-store.js +2 -2
  258. package/dist/src/chat-commands/agent-edit.js +2 -2
  259. package/dist/src/chat-commands/builtins/config.js +3 -3
  260. package/dist/src/chat-commands/builtins/goal.d.ts +1 -1
  261. package/dist/src/chat-commands/builtins/goal.js +55 -97
  262. package/dist/src/chat-commands/builtins/goal.js.map +1 -1
  263. package/dist/src/chat-commands/builtins/subgoal.d.ts +1 -1
  264. package/dist/src/chat-commands/builtins/subgoal.js +49 -108
  265. package/dist/src/chat-commands/builtins/subgoal.js.map +1 -1
  266. package/dist/src/chat-commands/builtins/system.js +11 -4
  267. package/dist/src/chat-commands/builtins/system.js.map +1 -1
  268. package/dist/src/chat-commands/builtins/workflow.js +132 -8
  269. package/dist/src/chat-commands/builtins/workflow.js.map +1 -1
  270. package/dist/src/chat-commands/context.d.ts +6 -0
  271. package/dist/src/chat-commands/context.js +12 -0
  272. package/dist/src/chat-commands/context.js.map +1 -1
  273. package/dist/src/chat-commands/types.d.ts +7 -0
  274. package/dist/src/cli/command-catalog.js +43 -0
  275. package/dist/src/cli/command-catalog.js.map +1 -1
  276. package/dist/src/cli/command-loaders.js +1 -0
  277. package/dist/src/cli/command-loaders.js.map +1 -1
  278. package/dist/src/cli/command-manifest.js +4 -0
  279. package/dist/src/cli/command-manifest.js.map +1 -1
  280. package/dist/src/cli/commands/config.js +1 -1
  281. package/dist/src/cli/commands/cron.js +55 -16
  282. package/dist/src/cli/commands/cron.js.map +1 -1
  283. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  284. package/dist/src/cli/commands/doctor/checks/cron-health.js +2 -83
  285. package/dist/src/cli/commands/doctor/checks/cron-health.js.map +1 -1
  286. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  287. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  288. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  289. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  290. package/dist/src/cli/commands/extension-create.js +1 -1
  291. package/dist/src/cli/commands/extension-dev.js +2 -2
  292. package/dist/src/cli/commands/extension-marketplace.js +2 -2
  293. package/dist/src/cli/commands/extension-pack.js +2 -2
  294. package/dist/src/cli/commands/extension.js +3 -3
  295. package/dist/src/cli/commands/gateway/logs.js +1 -1
  296. package/dist/src/cli/commands/goal.d.ts +4 -0
  297. package/dist/src/cli/commands/goal.js +213 -0
  298. package/dist/src/cli/commands/goal.js.map +1 -0
  299. package/dist/src/cli/commands/image.js +1 -1
  300. package/dist/src/cli/commands/init.js +2 -2
  301. package/dist/src/cli/commands/models.js +1 -1
  302. package/dist/src/cli/commands/onboard.js +11 -5
  303. package/dist/src/cli/commands/onboard.js.map +1 -1
  304. package/dist/src/cli/commands/skills-test.js +1 -1
  305. package/dist/src/cli/templates.js +1 -1
  306. package/dist/src/cli/utils/gateway-client.js +1 -1
  307. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  308. package/dist/src/config/agent-profile.js +1 -1
  309. package/dist/src/config/agent-typed-models.js +1 -1
  310. package/dist/src/config/gateway-bind.js +1 -1
  311. package/dist/src/config/index.js +8 -8
  312. package/dist/src/config/loader.js +4 -4
  313. package/dist/src/config/models-json.js +2 -2
  314. package/dist/src/config/paths-state.js +1 -1
  315. package/dist/src/config/paths.js +1 -1
  316. package/dist/src/config/profile.js +1 -1
  317. package/dist/src/config/reload.js +1 -1
  318. package/dist/src/config/schema.d.ts +115 -2
  319. package/dist/src/config/schema.js +63 -7
  320. package/dist/src/config/schema.js.map +1 -1
  321. package/dist/src/config/web-patch.d.ts +14 -1
  322. package/dist/src/config/web-patch.js +45 -8
  323. package/dist/src/config/web-patch.js.map +1 -1
  324. package/dist/src/config/workspace-path.js +1 -1
  325. package/dist/src/cron/executor.d.ts +2 -0
  326. package/dist/src/cron/executor.js +126 -70
  327. package/dist/src/cron/executor.js.map +1 -1
  328. package/dist/src/cron/index.d.ts +1 -1
  329. package/dist/src/cron/index.js +3 -3
  330. package/dist/src/cron/job-content.js +1 -0
  331. package/dist/src/cron/job-content.js.map +1 -1
  332. package/dist/src/cron/run-log-store.d.ts +1 -0
  333. package/dist/src/cron/run-log-store.js +4 -2
  334. package/dist/src/cron/run-log-store.js.map +1 -1
  335. package/dist/src/cron/schedule.d.ts +10 -0
  336. package/dist/src/cron/schedule.js +85 -0
  337. package/dist/src/cron/schedule.js.map +1 -0
  338. package/dist/src/cron/service.d.ts +34 -77
  339. package/dist/src/cron/service.js +327 -264
  340. package/dist/src/cron/service.js.map +1 -1
  341. package/dist/src/cron/types.d.ts +97 -49
  342. package/dist/src/cron/validation.d.ts +374 -86
  343. package/dist/src/cron/validation.js +156 -129
  344. package/dist/src/cron/validation.js.map +1 -1
  345. package/dist/src/cron/workflow-run-completion.js +1 -1
  346. package/dist/src/daemon/constants.js +1 -1
  347. package/dist/src/daemon/install-plan.js +2 -2
  348. package/dist/src/daemon/launchd.js +2 -2
  349. package/dist/src/daemon/schtasks.js +2 -2
  350. package/dist/src/daemon/systemd.js +2 -2
  351. package/dist/src/extensions/bundle-mcp.js +1 -1
  352. package/dist/src/extensions/discover-extensions.js +2 -2
  353. package/dist/src/extensions/health.js +1 -1
  354. package/dist/src/extensions/install.js +2 -2
  355. package/dist/src/extensions/loader.js +2 -2
  356. package/dist/src/extensions/lockfile.js +3 -3
  357. package/dist/src/extensions/security.js +1 -1
  358. package/dist/src/extensions/update.js +2 -2
  359. package/dist/src/gateway/agents-admin.js +2 -2
  360. package/dist/src/gateway/chat-stream/mapper.d.ts +1 -0
  361. package/dist/src/gateway/chat-stream/mapper.js +6 -2
  362. package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
  363. package/dist/src/gateway/chat-stream/protocol.d.ts +2 -0
  364. package/dist/src/gateway/file-path-classifier.js +2 -2
  365. package/dist/src/gateway/hono/lib/config-payload.d.ts +14 -1
  366. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  367. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  368. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  369. package/dist/src/gateway/hono/oauth-async.js +1 -1
  370. package/dist/src/gateway/hono/routes/agents.js +1 -1
  371. package/dist/src/gateway/hono/routes/ai-assist.d.ts +3 -0
  372. package/dist/src/gateway/hono/routes/ai-assist.js +66 -0
  373. package/dist/src/gateway/hono/routes/ai-assist.js.map +1 -0
  374. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  375. package/dist/src/gateway/hono/routes/commands-skills.js +7 -0
  376. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  377. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  378. package/dist/src/gateway/hono/routes/cron.js +24 -5
  379. package/dist/src/gateway/hono/routes/cron.js.map +1 -1
  380. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  381. package/dist/src/gateway/hono/routes/goals.d.ts +1 -1
  382. package/dist/src/gateway/hono/routes/goals.js +670 -173
  383. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  384. package/dist/src/gateway/hono/routes/home.d.ts +5 -0
  385. package/dist/src/gateway/hono/routes/home.js +90 -3
  386. package/dist/src/gateway/hono/routes/home.js.map +1 -1
  387. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  388. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  389. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  390. package/dist/src/gateway/hono/routes/models.js +1 -1
  391. package/dist/src/gateway/hono/routes/notes.js +20 -14
  392. package/dist/src/gateway/hono/routes/notes.js.map +1 -1
  393. package/dist/src/gateway/hono/routes/shares.js +1 -1
  394. package/dist/src/gateway/hono/routes/workflows.js +8 -4
  395. package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
  396. package/dist/src/gateway/hono/routes/workspace.js +2 -2
  397. package/dist/src/gateway/hono/sse.js.map +1 -1
  398. package/dist/src/gateway/lock.js +3 -3
  399. package/dist/src/gateway/ports.js +1 -1
  400. package/dist/src/gateway/service/agent-runner.d.ts +2 -0
  401. package/dist/src/gateway/service/agent-runner.js +8 -4
  402. package/dist/src/gateway/service/agent-runner.js.map +1 -1
  403. package/dist/src/gateway/service/config-coordinator.js +1 -1
  404. package/dist/src/gateway/service/marketplace-service.d.ts +22 -10
  405. package/dist/src/gateway/service/marketplace-service.js +46 -5
  406. package/dist/src/gateway/service/marketplace-service.js.map +1 -1
  407. package/dist/src/gateway/service/run-gateway-agent.d.ts +3 -0
  408. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  409. package/dist/src/gateway/service.d.ts +8 -0
  410. package/dist/src/gateway/service.js +79 -6
  411. package/dist/src/gateway/service.js.map +1 -1
  412. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  413. package/dist/src/goals/goal-notifications.d.ts +29 -0
  414. package/dist/src/goals/goal-notifications.js +154 -0
  415. package/dist/src/goals/goal-notifications.js.map +1 -0
  416. package/dist/src/goals/goal-queue-store.d.ts +16 -0
  417. package/dist/src/goals/goal-queue-store.js +131 -0
  418. package/dist/src/goals/goal-queue-store.js.map +1 -0
  419. package/dist/src/goals/goal-queue-types.d.ts +31 -0
  420. package/dist/src/goals/goal-queue-types.js +1 -0
  421. package/dist/src/goals/goal-runner.d.ts +17 -0
  422. package/dist/src/goals/goal-runner.js +127 -0
  423. package/dist/src/goals/goal-runner.js.map +1 -0
  424. package/dist/src/goals/goal-service.d.ts +77 -0
  425. package/dist/src/goals/goal-service.js +261 -0
  426. package/dist/src/goals/goal-service.js.map +1 -0
  427. package/dist/src/goals/goal-store.d.ts +38 -0
  428. package/dist/src/goals/goal-store.js +404 -0
  429. package/dist/src/goals/goal-store.js.map +1 -0
  430. package/dist/src/goals/goal-workflow-judge.d.ts +13 -0
  431. package/dist/src/goals/goal-workflow-judge.js +147 -0
  432. package/dist/src/goals/goal-workflow-judge.js.map +1 -0
  433. package/dist/src/goals/index.d.ts +10 -0
  434. package/dist/src/goals/index.js +7 -0
  435. package/dist/src/goals/types.d.ts +119 -0
  436. package/dist/src/goals/types.js +1 -0
  437. package/dist/src/i18n/goals-bundle.js +1 -1
  438. package/dist/src/i18n/index.js +1 -1
  439. package/dist/src/i18n/share-tool-bundle.js +2 -2
  440. package/dist/src/infra/brew.js +1 -1
  441. package/dist/src/infra/package-json.js +1 -1
  442. package/dist/src/infra/package-update-steps.js +1 -1
  443. package/dist/src/infra/path-env.js +2 -2
  444. package/dist/src/infra/restart.js +1 -1
  445. package/dist/src/infra/stable-node-path.js +1 -1
  446. package/dist/src/infra/update-check.js +1 -1
  447. package/dist/src/infra/update-global.js +1 -1
  448. package/dist/src/infra/update-lock.js +2 -2
  449. package/dist/src/infra/update-restart.js +1 -1
  450. package/dist/src/infra/update-runner.js +1 -1
  451. package/dist/src/infra/update-startup.js +1 -1
  452. package/dist/src/infra/write-file-atomic.js +2 -2
  453. package/dist/src/media/store.js +1 -1
  454. package/dist/src/notes/agent-context.js +1 -1
  455. package/dist/src/notes/service.js +1 -1
  456. package/dist/src/notes/store.js +2 -2
  457. package/dist/src/project-trust/trust-store.js +2 -2
  458. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  459. package/dist/src/providers/index.js +1 -1
  460. package/dist/src/providers/model-registry.js +4 -4
  461. package/dist/src/session/init-session-turn.js +2 -2
  462. package/dist/src/session/resolve-session.js +3 -3
  463. package/dist/src/session/session-title.js +2 -2
  464. package/dist/src/session/store.js +1 -1
  465. package/dist/src/share/share-auto.js +2 -2
  466. package/dist/src/share/share-store.js +3 -3
  467. package/dist/src/share/share-thumbnail.js +2 -2
  468. package/dist/src/share/share-zip.js +1 -1
  469. package/dist/src/share/site-share-store.js +3 -3
  470. package/dist/src/share/site-static-serve.js +1 -1
  471. package/dist/src/storage/sqlite/connection.js +1 -1
  472. package/dist/src/storage/sqlite/cron-job-repository.d.ts +6 -0
  473. package/dist/src/storage/sqlite/cron-job-repository.js +70 -0
  474. package/dist/src/storage/sqlite/cron-job-repository.js.map +1 -0
  475. package/dist/src/storage/sqlite/cron-run-repository.js +0 -1
  476. package/dist/src/storage/sqlite/cron-run-repository.js.map +1 -1
  477. package/dist/src/storage/sqlite/index.d.ts +1 -0
  478. package/dist/src/storage/sqlite/index.js +2 -1
  479. package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
  480. package/dist/src/storage/sqlite/migrations/006_add_goals.sql +108 -0
  481. package/dist/src/storage/sqlite/migrations/007_goal_run_judge_schema.sql +4 -0
  482. package/dist/src/storage/sqlite/migrations/008_goal_queue_workflow_runs.sql +53 -0
  483. package/dist/src/storage/sqlite/migrations/009_cron_jobs.sql +24 -0
  484. package/dist/src/storage/sqlite/migrations/discover.js +1 -1
  485. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  486. package/dist/src/storage/sqlite/migrations/runner.js +4 -4
  487. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  488. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  489. package/dist/src/storage/sqlite/schema.js +2 -2
  490. package/dist/src/storage/sqlite/schema.sql +188 -0
  491. package/dist/src/tui/clipboard-image.js +3 -3
  492. package/dist/src/tui/extension-host/load-extensions.js +1 -1
  493. package/dist/src/tui/theme-manager.js +1 -1
  494. package/dist/src/tui/tui-command-formatters.js +4 -4
  495. package/dist/src/tui/tui-commands.js +2 -2
  496. package/dist/src/tui/tui-keybindings-file.js +1 -1
  497. package/dist/src/tui/tui-scoped-models.js +2 -2
  498. package/dist/src/tui/tui-settings.js +1 -1
  499. package/dist/src/tui/tui-startup-resources.js +1 -1
  500. package/dist/src/tui/tui.js +6 -6
  501. package/dist/src/tunnel/frpc-binary.js +4 -4
  502. package/dist/src/tunnel/frpc-config.js +1 -1
  503. package/dist/src/tunnel/frpc-extract.js +1 -1
  504. package/dist/src/tunnel/tunnel-state.js +1 -1
  505. package/dist/src/utils/logger/audit.js +1 -1
  506. package/dist/src/utils/logger/log-store.js +1 -1
  507. package/dist/src/utils/logger/rotation.js +1 -1
  508. package/dist/src/utils/logger/stats.d.ts +1 -1
  509. package/dist/src/utils/logger/streams.js +1 -1
  510. package/dist/src/voice/tts/audio.js +1 -1
  511. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  512. package/dist/src/workflows/domain/run.d.ts +1 -0
  513. package/dist/src/workflows/domain/run.js.map +1 -1
  514. package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
  515. package/dist/src/workflows/engine/projector.js +23 -14
  516. package/dist/src/workflows/engine/projector.js.map +1 -1
  517. package/dist/src/workflows/engine/workflow-engine.d.ts +1 -0
  518. package/dist/src/workflows/engine/workflow-engine.js +36 -0
  519. package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
  520. package/dist/src/workflows/index.js +1 -1
  521. package/dist/src/workflows/service/workflow-run-service.d.ts +1 -0
  522. package/dist/src/workflows/service/workflow-run-service.js +7 -3
  523. package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
  524. package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -0
  525. package/dist/src/workflows/service/workflow-session-bridge.js +8 -1
  526. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
  527. package/dist/src/workflows/store/event-store.js +1 -1
  528. package/dist/src/workflows/store/run-index-store.d.ts +8 -0
  529. package/dist/src/workflows/store/run-index-store.js +58 -0
  530. package/dist/src/workflows/store/run-index-store.js.map +1 -0
  531. package/dist/src/workflows/store/run-store.d.ts +2 -0
  532. package/dist/src/workflows/store/run-store.js +15 -22
  533. package/dist/src/workflows/store/run-store.js.map +1 -1
  534. package/package.json +10 -5
  535. package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +0 -41
  536. package/dist/gateway/static/root/assets/agents-CFFioJCI.js +0 -78
  537. package/dist/gateway/static/root/assets/apps-page-BYDmkbzG.js +0 -1
  538. package/dist/gateway/static/root/assets/channels-settings-CsbDaMvd.js +0 -1
  539. package/dist/gateway/static/root/assets/circle-check-C23XjkUj.js +0 -1
  540. package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +0 -1
  541. package/dist/gateway/static/root/assets/cron-page-Apk-7p4p.js +0 -1
  542. package/dist/gateway/static/root/assets/dist-DmGDgpy2.js +0 -1
  543. package/dist/gateway/static/root/assets/extension-debug-page-pxFC-tUa.js +0 -1
  544. package/dist/gateway/static/root/assets/extension-settings-page-COXSv6xP.js +0 -1
  545. package/dist/gateway/static/root/assets/fetch-CFdKBnE6.js +0 -1
  546. package/dist/gateway/static/root/assets/gateway-startup-retry-DdngdObI.js +0 -1
  547. package/dist/gateway/static/root/assets/heartbeat-config-api-DcmAMYmN.js +0 -1
  548. package/dist/gateway/static/root/assets/index-C_2yKRJX.js +0 -4845
  549. package/dist/gateway/static/root/assets/index-DI5_GsZt.css +0 -1
  550. package/dist/gateway/static/root/assets/logs-page-DvTWUOzd.js +0 -2
  551. package/dist/gateway/static/root/assets/note-detail-page-CZbdugWZ.js +0 -180
  552. package/dist/gateway/static/root/assets/note-time-RdyBZxj3.js +0 -1
  553. package/dist/gateway/static/root/assets/notes-page-mEAwy3e1.js +0 -1
  554. package/dist/gateway/static/root/assets/schema-form-DEvdni_r.js +0 -1
  555. package/dist/gateway/static/root/assets/sessions-page-BsgffzV4.js +0 -1
  556. package/dist/gateway/static/root/assets/settings-advanced-gate-t6v8Dwb8.js +0 -2
  557. package/dist/gateway/static/root/assets/settings-form-section-BoYYZmJG.js +0 -1
  558. package/dist/gateway/static/root/assets/settings-page-ClIthYF8.js +0 -3
  559. package/dist/gateway/static/root/assets/share-preview-page-Dd9et7KD.js +0 -2
  560. package/dist/gateway/static/root/assets/skills-page-DEXtxyfQ.js +0 -2
  561. package/dist/gateway/static/root/assets/theme-store-BZozwAeK.js +0 -1
  562. package/dist/gateway/static/root/assets/url-DQRqHuL-.js +0 -3
  563. package/dist/gateway/static/root/assets/vendor-codemirror-DYoKfS8f.js +0 -45
  564. package/dist/gateway/static/root/assets/voice-api-key-field-CNrKzQrf.js +0 -1
  565. package/dist/gateway/static/root/assets/workflows-page-EMZkzJNN.js +0 -18
  566. package/dist/gateway/static/root/favicon-16.png +0 -0
  567. package/dist/gateway/static/root/favicon-32.png +0 -0
  568. package/dist/src/agent/goals/checklist-user.d.ts +0 -24
  569. package/dist/src/agent/goals/checklist-user.js +0 -92
  570. package/dist/src/agent/goals/checklist-user.js.map +0 -1
  571. package/dist/src/agent/goals/goal-run-store.d.ts +0 -19
  572. package/dist/src/agent/goals/goal-run-store.js +0 -138
  573. package/dist/src/agent/goals/goal-run-store.js.map +0 -1
  574. package/dist/src/agent/goals/goal-run-types.d.ts +0 -28
  575. package/dist/src/agent/goals/goal-run-types.js +0 -6
  576. package/dist/src/agent/goals/goal-run-types.js.map +0 -1
  577. package/dist/src/agent/goals/patch-from-user-action.d.ts +0 -20
  578. package/dist/src/agent/goals/patch-from-user-action.js +0 -103
  579. package/dist/src/agent/goals/patch-from-user-action.js.map +0 -1
  580. package/dist/src/cron/persistence.d.ts +0 -62
  581. package/dist/src/cron/persistence.js +0 -188
  582. package/dist/src/cron/persistence.js.map +0 -1
  583. /package/dist/gateway/static/root/assets/{note-detail-page-D4ZIVQbk.css → block-editor-D4ZIVQbk.css} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"skill-manager.js","names":[],"sources":["../../../../src/agent/skills/skill-manager.ts"],"sourcesContent":["/**\n * Skill Manager - Manages skills loading and expansion\n *\n * Handles skill initialization, reloading, and command expansion.\n */\n\nimport { createSkillLoader, type Skill } from './index.js';\nimport { resolveBundledSkillsDir, resolveStateDir } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { createSkillConfigManager, isSkillEnabled } from './config.js';\nimport { formatSkillsForPrompt, selectSkillsVisibleInPrompt } from './format-skills-prompt.js';\n\nconst log = createLogger('SkillManager');\n\nexport interface SkillDiagnostic {\n type: 'collision' | 'warning' | 'error' | 'info';\n skillName: string;\n message: string;\n}\n\nexport interface SkillLoadResult {\n skills: Skill[];\n prompt: string;\n diagnostics: SkillDiagnostic[];\n}\n\nexport class SkillManager {\n private skillPrompt: string = '';\n private skills: Skill[] = [];\n private skillLoader = createSkillLoader();\n private workspace: string;\n private bundledSkillsDir: string;\n\n constructor(workspace: string, bundledSkillsDir?: string) {\n this.workspace = workspace;\n this.bundledSkillsDir = bundledSkillsDir || resolveBundledSkillsDir();\n this.initialize();\n }\n\n /**\n * Initialize skills from workspace and bundled directories\n */\n private initialize(): void {\n const result = this.skillLoader.init(this.workspace, this.bundledSkillsDir);\n this.skillPrompt = result.prompt;\n this.skills = result.skills;\n\n // Log diagnostics\n for (const diag of result.diagnostics) {\n if (diag.type === 'collision') {\n log.warn({ skill: diag.skillName, message: diag.message }, 'Skill collision');\n } else if (diag.type === 'warning') {\n log.warn({ skill: diag.skillName, message: diag.message }, 'Skill warning');\n } else if (diag.type === 'error') {\n log.error({ skill: diag.skillName, message: diag.message }, 'Skill error');\n } else {\n log.info({ skill: diag.skillName, message: diag.message }, 'Skill info');\n }\n }\n\n log.debug({ count: result.skills.length }, 'Skills loaded');\n }\n\n /**\n * Recompute skill XML prompt from current skills.json (no disk rescan).\n */\n refreshPromptFromConfig(): void {\n this.skillLoader.refreshPromptFromConfig();\n this.skillPrompt = this.skillLoader.getPrompt();\n }\n\n /**\n * Reload skills from disk\n */\n reload(): void {\n log.info('Reloading skills...');\n const result = this.skillLoader.reload();\n this.skillPrompt = result.prompt;\n this.skills = result.skills;\n\n for (const diag of result.diagnostics) {\n if (diag.type === 'collision') {\n log.warn({ skill: diag.skillName, message: diag.message }, 'Skill collision');\n } else if (diag.type === 'warning') {\n log.warn({ skill: diag.skillName, message: diag.message }, 'Skill warning');\n } else if (diag.type === 'error') {\n log.error({ skill: diag.skillName, message: diag.message }, 'Skill error');\n }\n }\n\n log.info({ count: result.skills.length }, 'Skills reloaded');\n }\n\n /**\n * Get the skill prompt to append to system prompt\n */\n getPrompt(): string {\n return this.skillPrompt;\n }\n\n /**\n * `<available_skills>` XML with optional per-agent allowlist and/or tool-based gating.\n * When both arguments are omitted, returns the cached prompt from disk load (no tool gating).\n */\n getPromptForSkillAllowlist(\n allowlist: string[] | undefined,\n registeredToolNames?: string[],\n ): string {\n if (allowlist === undefined && registeredToolNames === undefined) {\n return this.getPrompt();\n }\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return formatSkillsForPrompt(this.getSkills(), skillsConfig, {\n skillAllowlist: allowlist,\n registeredToolNames,\n });\n }\n\n /** Skills visible for prompts and skills_list given the same indexing options as {@link getPromptForSkillAllowlist}. */\n selectSkillsForAgentIndexing(options?: {\n skillAllowlist?: string[];\n registeredToolNames?: string[];\n }): Skill[] {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return selectSkillsVisibleInPrompt(this.getSkills(), skillsConfig, options);\n }\n\n /**\n * Get all loaded skills\n */\n getSkills(): Skill[] {\n return [...this.skills];\n }\n\n /**\n * Get skill names\n */\n getSkillNames(): string[] {\n return this.skills.map((s) => s.name);\n }\n\n /** Names of skills included in the agent system prompt (`<available_skills>`). */\n getSkillNamesForPrompt(): string[] {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return this.getSkills()\n .filter((s) => !s.disableModelInvocation && isSkillEnabled(s, skillsConfig))\n .map((s) => s.name);\n }\n\n /**\n * Skills that are enabled for model discovery (respects skills.json and requirement checks).\n */\n getEnabledSkills(): Skill[] {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return this.getSkills().filter(\n (s) => !s.disableModelInvocation && isSkillEnabled(s, skillsConfig),\n );\n }\n\n /**\n * Like {@link getEnabledSkills} plus optional allowlist and tool gating (matches `<available_skills>`).\n */\n getEnabledSkillsForAgentSession(options?: {\n skillAllowlist?: string[];\n registeredToolNames?: string[];\n }): Skill[] {\n return this.selectSkillsForAgentIndexing(options);\n }\n\n /**\n * Find a skill by name\n */\n findSkill(name: string): Skill | undefined {\n return this.skills.find(s => s.name === name);\n }\n\n /**\n * Check if a skill exists\n */\n hasSkill(name: string): boolean {\n return this.skills.some(s => s.name === name);\n }\n\n /**\n * Expand a skill command into a full skill block\n */\n expandCommand(text: string, options?: { skillAllowlist?: string[]; registeredToolNames?: string[] }): string {\n if (!text.startsWith('/skill:')) {\n return text;\n }\n\n const { skillName, args } = this.parseSkillCommand(text);\n const visible = this.selectSkillsForAgentIndexing(options);\n const skill = visible.find((s) => s.name === skillName);\n\n if (!skill) {\n log.warn({ skillName }, 'Skill not visible for expansion');\n return text;\n }\n\n return this.buildSkillBlock(skill, args);\n }\n\n /**\n * Parse a /skill: command\n */\n private parseSkillCommand(text: string): { skillName: string; args?: string } {\n // Format: /skill:name args...\n const withoutPrefix = text.slice(7); // Remove '/skill:'\n const spaceIndex = withoutPrefix.indexOf(' ');\n\n if (spaceIndex === -1) {\n return { skillName: withoutPrefix.trim() };\n }\n\n return {\n skillName: withoutPrefix.slice(0, spaceIndex).trim(),\n args: withoutPrefix.slice(spaceIndex + 1).trim(),\n };\n }\n\n /**\n * Build a skill block for inclusion in the prompt\n */\n private buildSkillBlock(skill: Skill, args?: string): string {\n let block = `\\n\\n## Skill: ${skill.name}\\n\\n`;\n \n if (skill.description) {\n block += `${skill.description}\\n\\n`;\n }\n\n // Include raw skill content (SKILL.md content)\n if (skill.content) {\n block += `${skill.content}\\n\\n`;\n }\n\n if (args) {\n block += `**Arguments**: ${args}\\n\\n`;\n }\n\n return block;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"skill-manager.js","names":[],"sources":["../../../../src/agent/skills/skill-manager.ts"],"sourcesContent":["/**\n * Skill Manager - Manages skills loading and expansion\n *\n * Handles skill initialization, reloading, and command expansion.\n */\n\nimport { createSkillLoader } from './index.js';\nimport { resolveBundledSkillsDir, resolveStateDir } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { createSkillConfigManager, isSkillEnabled } from './config.js';\nimport { formatSkillsForPrompt, selectSkillsVisibleInPrompt } from './format-skills-prompt.js';\nimport type {\n LoadSkillsResult,\n Skill,\n SkillDiagnostic,\n SkillRuntimeStatus,\n} from './types.js';\n\nconst log = createLogger('SkillManager');\n\nexport interface SkillLoadResult {\n skills: Skill[];\n prompt: string;\n diagnostics: SkillDiagnostic[];\n}\n\nexport class SkillManager {\n private skillPrompt: string = '';\n private skills: Skill[] = [];\n private skillLoader = createSkillLoader();\n private workspace: string;\n private bundledSkillsDir: string;\n private version = 0;\n private loadedAt = 0;\n private reloadInProgress = false;\n private reloadPending = false;\n private lastReloadStartedAt: number | undefined;\n private lastReloadFinishedAt: number | undefined;\n private lastReloadReason: SkillRuntimeStatus['lastReloadReason'];\n private lastReloadOk: boolean | undefined;\n private lastReloadError: string | undefined;\n\n constructor(workspace: string, bundledSkillsDir?: string) {\n this.workspace = workspace;\n this.bundledSkillsDir = bundledSkillsDir || resolveBundledSkillsDir();\n this.initialize();\n }\n\n /**\n * Initialize skills from workspace and bundled directories\n */\n private initialize(): void {\n this.runReload('initial', () => this.skillLoader.init(this.workspace, this.bundledSkillsDir));\n }\n\n /**\n * Recompute skill XML prompt from current skills.json (no disk rescan).\n */\n refreshPromptFromConfig(): void {\n this.skillLoader.refreshPromptFromConfig();\n this.skillPrompt = this.skillLoader.getPrompt();\n this.version += 1;\n this.loadedAt = Date.now();\n this.lastReloadReason = 'config';\n this.lastReloadOk = true;\n this.lastReloadError = undefined;\n }\n\n /**\n * Reload skills from disk\n */\n reload(): void {\n this.runReload('disk', () => this.skillLoader.reload());\n }\n\n private runReload(reason: NonNullable<SkillRuntimeStatus['lastReloadReason']>, load: () => LoadSkillsResult): void {\n if (this.reloadInProgress) {\n this.reloadPending = true;\n return;\n }\n\n do {\n this.reloadPending = false;\n this.reloadInProgress = true;\n this.lastReloadStartedAt = Date.now();\n this.lastReloadReason = reason;\n try {\n const result = load();\n this.applyLoadResult(result);\n this.lastReloadOk = true;\n this.lastReloadError = undefined;\n log.info({ count: result.skills.length, version: this.version }, 'Skills reloaded');\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n this.lastReloadOk = false;\n this.lastReloadError = errorMessage;\n log.error({ err, errorMessage }, `Skills reload failed: ${errorMessage}`);\n } finally {\n this.lastReloadFinishedAt = Date.now();\n this.reloadInProgress = false;\n }\n } while (this.reloadPending);\n }\n\n private applyLoadResult(result: LoadSkillsResult): void {\n this.skillPrompt = result.prompt;\n this.skills = result.skills;\n this.version += 1;\n this.loadedAt = Date.now();\n\n for (const diag of result.diagnostics) {\n if (diag.type === 'collision') {\n log.warn({ skill: diag.skillName, path: diag.path, message: diag.message }, 'Skill collision');\n } else if (diag.type === 'warning') {\n log.warn({ skill: diag.skillName, path: diag.path, message: diag.message }, 'Skill warning');\n } else if (diag.type === 'error') {\n log.error({ skill: diag.skillName, path: diag.path, message: diag.message }, 'Skill error');\n }\n }\n }\n\n /**\n * Get the skill prompt to append to system prompt\n */\n getPrompt(): string {\n return this.skillPrompt;\n }\n\n /**\n * `<available_skills>` XML with optional per-agent allowlist and/or tool-based gating.\n * When both arguments are omitted, returns the cached prompt from disk load (no tool gating).\n */\n getPromptForSkillAllowlist(\n allowlist: string[] | undefined,\n registeredToolNames?: string[],\n ): string {\n if (allowlist === undefined && registeredToolNames === undefined) {\n return this.getPrompt();\n }\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return formatSkillsForPrompt(this.getSkills(), skillsConfig, {\n skillAllowlist: allowlist,\n registeredToolNames,\n });\n }\n\n /** Skills visible for prompts and skills_list given the same indexing options as {@link getPromptForSkillAllowlist}. */\n selectSkillsForAgentIndexing(options?: {\n skillAllowlist?: string[];\n registeredToolNames?: string[];\n }): Skill[] {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return selectSkillsVisibleInPrompt(this.getSkills(), skillsConfig, options);\n }\n\n /**\n * Get all loaded skills\n */\n getSkills(): Skill[] {\n return [...this.skills];\n }\n\n getDiagnostics(): SkillDiagnostic[] {\n return this.skillLoader.getDiagnostics();\n }\n\n getVersion(): string {\n return String(this.version);\n }\n\n getLoadedAt(): number {\n return this.loadedAt;\n }\n\n getStatus(): SkillRuntimeStatus {\n return {\n version: this.getVersion(),\n loadedAt: this.loadedAt,\n reloadInProgress: this.reloadInProgress,\n reloadPending: this.reloadPending,\n ...(this.lastReloadStartedAt !== undefined ? { lastReloadStartedAt: this.lastReloadStartedAt } : {}),\n ...(this.lastReloadFinishedAt !== undefined ? { lastReloadFinishedAt: this.lastReloadFinishedAt } : {}),\n ...(this.lastReloadReason !== undefined ? { lastReloadReason: this.lastReloadReason } : {}),\n ...(this.lastReloadOk !== undefined ? { lastReloadOk: this.lastReloadOk } : {}),\n ...(this.lastReloadError !== undefined ? { lastReloadError: this.lastReloadError } : {}),\n };\n }\n\n /**\n * Get skill names\n */\n getSkillNames(): string[] {\n return this.skills.map((s) => s.name);\n }\n\n /** Names of skills included in the agent system prompt (`<available_skills>`). */\n getSkillNamesForPrompt(): string[] {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return this.getSkills()\n .filter((s) => !s.disableModelInvocation && isSkillEnabled(s, skillsConfig))\n .map((s) => s.name);\n }\n\n /**\n * Skills that are enabled for model discovery (respects skills.json and requirement checks).\n */\n getEnabledSkills(): Skill[] {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return this.getSkills().filter(\n (s) => !s.disableModelInvocation && isSkillEnabled(s, skillsConfig),\n );\n }\n\n /**\n * Like {@link getEnabledSkills} plus optional allowlist and tool gating (matches `<available_skills>`).\n */\n getEnabledSkillsForAgentSession(options?: {\n skillAllowlist?: string[];\n registeredToolNames?: string[];\n }): Skill[] {\n return this.selectSkillsForAgentIndexing(options);\n }\n\n /**\n * Find a skill by name\n */\n findSkill(name: string): Skill | undefined {\n return this.skills.find(s => s.name === name);\n }\n\n /**\n * Check if a skill exists\n */\n hasSkill(name: string): boolean {\n return this.skills.some(s => s.name === name);\n }\n\n /**\n * Expand a skill command into a full skill block\n */\n expandCommand(text: string, options?: { skillAllowlist?: string[]; registeredToolNames?: string[] }): string {\n if (!text.startsWith('/skill:')) {\n return text;\n }\n\n const { skillName, args } = this.parseSkillCommand(text);\n const visible = this.selectSkillsForAgentIndexing(options);\n const skill = visible.find((s) => s.name === skillName);\n\n if (!skill) {\n log.warn({ skillName }, 'Skill not visible for expansion');\n return text;\n }\n\n return this.buildSkillBlock(skill, args);\n }\n\n /**\n * Parse a /skill: command\n */\n private parseSkillCommand(text: string): { skillName: string; args?: string } {\n // Format: /skill:name args...\n const withoutPrefix = text.slice(7); // Remove '/skill:'\n const spaceIndex = withoutPrefix.indexOf(' ');\n\n if (spaceIndex === -1) {\n return { skillName: withoutPrefix.trim() };\n }\n\n return {\n skillName: withoutPrefix.slice(0, spaceIndex).trim(),\n args: withoutPrefix.slice(spaceIndex + 1).trim(),\n };\n }\n\n /**\n * Build a skill block for inclusion in the prompt\n */\n private buildSkillBlock(skill: Skill, args?: string): string {\n let block = `\\n\\n## Skill: ${skill.name}\\n\\n`;\n \n if (skill.description) {\n block += `${skill.description}\\n\\n`;\n }\n\n // Include raw skill content (SKILL.md content)\n if (skill.content) {\n block += `${skill.content}\\n\\n`;\n }\n\n if (args) {\n block += `**Arguments**: ${args}\\n\\n`;\n }\n\n return block;\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { resolve, sep } from "path";
2
1
  import { existsSync, realpathSync } from "fs";
2
+ import { resolve, sep } from "path";
3
3
  //#region src/agent/skills/skill-view-path.ts
4
4
  /**
5
5
  * Resolve safe paths for skill_view: only SKILL.md (default) or files under allowlisted subdirs.
@@ -4,8 +4,8 @@ import { parseFrontmatter } from "../../markdown/frontmatter.js";
4
4
  import { hasBinary } from "./installer.js";
5
5
  import { scanSkillDirectory } from "./scanner.js";
6
6
  import { parseSkillMetadata } from "./parse-skill-metadata.js";
7
- import { basename, join, relative } from "path";
8
7
  import { existsSync, readFileSync, readdirSync } from "fs";
8
+ import { basename, join, relative } from "path";
9
9
  //#region src/agent/skills/test-framework.ts
10
10
  /**
11
11
  * Skill Test Framework
@@ -207,6 +207,17 @@ export interface SkillDiagnostic {
207
207
  message: string;
208
208
  path?: string;
209
209
  }
210
+ export interface SkillRuntimeStatus {
211
+ version: string;
212
+ loadedAt: number;
213
+ reloadInProgress: boolean;
214
+ reloadPending: boolean;
215
+ lastReloadStartedAt?: number;
216
+ lastReloadFinishedAt?: number;
217
+ lastReloadReason?: 'initial' | 'disk' | 'config';
218
+ lastReloadOk?: boolean;
219
+ lastReloadError?: string;
220
+ }
210
221
  export interface SkillSnapshot {
211
222
  version: string;
212
223
  skills: SkillEntry[];
@@ -1,7 +1,7 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { join } from "path";
4
3
  import { watch } from "fs";
4
+ import { join } from "path";
5
5
  //#region src/agent/skills/watcher.ts
6
6
  /**
7
7
  * Skill Watcher
@@ -1,8 +1,8 @@
1
1
  import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentProfileDir, resolveAgentWorkspaceDir } from "./agent-scope.js";
2
2
  import { WORKSPACE_FILES, init_paths } from "../config/paths.js";
3
3
  import { applyAgentConfig } from "../commands/agents.config.js";
4
- import { join } from "node:path";
5
4
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
6
  //#region src/agent/starter-agents.ts
7
7
  init_paths();
8
8
  init_agent_scope();
@@ -4,16 +4,21 @@ export declare function scanCronPrompt(prompt: string): string | null;
4
4
  export type CronjobToolParams = {
5
5
  action: 'list' | 'create' | 'update' | 'remove' | 'enable' | 'disable' | 'history';
6
6
  name?: string;
7
- schedule?: string;
7
+ scheduleKind?: 'cron' | 'at' | 'every';
8
+ cronExpr?: string;
9
+ at?: string;
10
+ everyMs?: number;
11
+ tz?: string;
8
12
  message?: string;
9
13
  workflowDefinitionId?: string;
10
14
  workflowGoal?: string;
11
15
  workflowInputJson?: string;
16
+ goalId?: string;
17
+ goalMessage?: string;
12
18
  waitForCompletion?: boolean;
13
19
  deliveryChannel?: string;
14
20
  deliveryTo?: string;
15
- timezone?: string;
16
- sessionTarget?: 'main' | 'isolated';
21
+ sessionTarget?: 'main' | 'isolated' | 'current';
17
22
  agentId?: string;
18
23
  workingDirectory?: string;
19
24
  jobId?: string;
@@ -1,5 +1,5 @@
1
+ import { describeSchedule } from "../../cron/schedule.js";
1
2
  import { getCronPayloadText } from "../../cron/job-content.js";
2
- import { DEFAULT_WORKFLOW_CRON_WAIT_MS } from "../../cron/workflow-run-completion.js";
3
3
  import { Type } from "@sinclair/typebox";
4
4
  //#region src/agent/tools/cronjob-tool.ts
5
5
  const CRON_THREAT_PATTERNS = [
@@ -25,15 +25,24 @@ const CronjobSchema = Type.Object({
25
25
  Type.Literal("history")
26
26
  ], { description: "Action to perform on cron jobs" }),
27
27
  name: Type.Optional(Type.String({ description: "Human-readable job name" })),
28
- schedule: Type.Optional(Type.String({ description: "Cron schedule expression. Examples:\n \"0 9 * * *\" = every day at 9:00 AM\n \"*/30 * * * *\" = every 30 minutes\n \"0 9 * * 1-5\" = weekdays at 9:00 AM\n \"0 0 1 * *\" = first day of each month" })),
28
+ scheduleKind: Type.Optional(Type.Union([
29
+ Type.Literal("cron"),
30
+ Type.Literal("at"),
31
+ Type.Literal("every")
32
+ ], { description: "Schedule kind. Use cronExpr for cron, at for one-time ISO time, everyMs for interval." })),
33
+ cronExpr: Type.Optional(Type.String({ description: "Cron schedule expression. Examples:\n \"0 9 * * *\" = every day at 9:00 AM\n \"*/30 * * * *\" = every 30 minutes\n \"0 9 * * 1-5\" = weekdays at 9:00 AM\n \"0 0 1 * *\" = first day of each month" })),
34
+ at: Type.Optional(Type.String({ description: "One-time run timestamp as ISO 8601 string." })),
35
+ everyMs: Type.Optional(Type.Number({ description: "Fixed interval in milliseconds." })),
36
+ tz: Type.Optional(Type.String({ description: "IANA timezone for cronExpr, e.g. Asia/Shanghai." })),
29
37
  message: Type.Optional(Type.String({ description: "Instruction for the agent when the job runs (agentTurn payload; typically a fresh session)." })),
30
- workflowDefinitionId: Type.Optional(Type.String({ description: "Workflow definition id for a direct workflowRun job (mutually exclusive with message on create)." })),
38
+ workflowDefinitionId: Type.Optional(Type.String({ description: "Workflow definition id for a workflowRun job (mutually exclusive with message on create)." })),
31
39
  workflowGoal: Type.Optional(Type.String({ description: "Optional goal override when creating a workflowRun job." })),
32
40
  workflowInputJson: Type.Optional(Type.String({ description: "JSON object for workflow input payload (workflowRun create/update)." })),
41
+ goalId: Type.Optional(Type.String({ description: "Durable goal id for a goalContinue job (mutually exclusive with message and workflowDefinitionId)." })),
42
+ goalMessage: Type.Optional(Type.String({ description: "Optional custom continuation message for a goalContinue job." })),
33
43
  waitForCompletion: Type.Optional(Type.Boolean({ description: "For workflowRun jobs: when true (default), cron waits for terminal status before succeeding." })),
34
44
  deliveryChannel: Type.Optional(Type.String({ description: "Delivery channel when workflow completes (e.g. telegram)." })),
35
45
  deliveryTo: Type.Optional(Type.String({ description: "Delivery recipient chat id when workflow completes." })),
36
- timezone: Type.Optional(Type.String({ description: "IANA timezone (e.g. Asia/Shanghai, America/New_York). Must be one supported by the cron store." })),
37
46
  sessionTarget: Type.Optional(Type.Union([Type.Literal("main"), Type.Literal("isolated")], { description: "\"main\" uses the main session context; \"isolated\" (default on create) uses a separate session per run." })),
38
47
  agentId: Type.Optional(Type.String({ description: "Agent profile id for isolated jobs (session key). Omit to use the configured default agent (usually `main`)." })),
39
48
  workingDirectory: Type.Optional(Type.String({ description: "Absolute workspace path on the gateway host for isolated jobs. Omit to use the agent default workspace." })),
@@ -49,21 +58,47 @@ function textResult(text) {
49
58
  };
50
59
  }
51
60
  function formatJob(job) {
52
- const status = job.enabled ? "▶️ active" : "⏸️ disabled";
61
+ const status = job.enabled ? "active" : "disabled";
53
62
  const payloadText = getCronPayloadText(job);
54
63
  const truncatedPayload = payloadText.length > 100 ? `${payloadText.slice(0, 100)}...` : payloadText;
55
64
  const payloadLine = job.payload.kind === "workflowRun" ? ` Workflow: ${job.payload.definitionId}${job.payload.goal ? ` — ${job.payload.goal}` : ""}` : ` Message: ${truncatedPayload}`;
56
65
  return [
57
66
  `${status} ${job.name ?? "(unnamed)"} (${job.id})`,
58
- ` Schedule: ${job.schedule}${job.timezone ? ` (${job.timezone})` : ""}`,
67
+ ` Schedule: ${describeSchedule(job.schedule)}`,
59
68
  ` Type: ${job.payload.kind}`,
60
69
  payloadLine,
61
- ` Next run: ${job.next_run ?? "N/A"}`,
70
+ ` Next run: ${job.state.nextRunAtMs ? new Date(job.state.nextRunAtMs).toISOString() : "N/A"}`,
62
71
  ` Session: ${job.sessionTarget ?? "main"}`,
63
72
  ` Agent: ${job.agentId?.trim() || "(default)"}`,
64
73
  ` Workspace: ${job.workingDirectory?.trim() || "(agent default)"}`
65
74
  ].join("\n");
66
75
  }
76
+ function scheduleFromParams(params) {
77
+ const kind = params.scheduleKind;
78
+ if (!kind) return void 0;
79
+ if (kind === "cron") {
80
+ const expr = params.cronExpr?.trim();
81
+ if (!expr) return void 0;
82
+ return {
83
+ kind,
84
+ expr,
85
+ ...params.tz?.trim() ? { tz: params.tz.trim() } : {}
86
+ };
87
+ }
88
+ if (kind === "at") {
89
+ const at = params.at?.trim();
90
+ if (!at) return void 0;
91
+ return {
92
+ kind,
93
+ at
94
+ };
95
+ }
96
+ if (!Number.isFinite(params.everyMs) || !params.everyMs || params.everyMs <= 0) return void 0;
97
+ return {
98
+ kind,
99
+ everyMs: Math.floor(params.everyMs)
100
+ };
101
+ }
67
102
  function formatExecution(exec) {
68
103
  const dur = exec.duration != null ? `${(exec.duration / 1e3).toFixed(1)}s` : "N/A";
69
104
  const lines = [`[${exec.status}] ${exec.startedAt} (${dur})`];
@@ -75,7 +110,7 @@ function createCronjobTool(deps) {
75
110
  return {
76
111
  name: "cronjob",
77
112
  label: "⏰ Cronjob",
78
- description: "Manage scheduled tasks (cron jobs) that run automatically.\n\nJobs can run an agent message (agentTurn) or a workflow directly (workflowRun).\n\nACTIONS:\n- list: Show all scheduled jobs with status and next run time\n- create: Create a job (schedule + message OR workflowDefinitionId; optional goal, workflowInputJson, deliveryChannel/deliveryTo, waitForCompletion)\n- update: Change schedule, message, workflow fields, name, timezone, sessionTarget, agentId, or workingDirectory (requires jobId)\n- remove: Delete a job (requires jobId)\n- enable / disable: Toggle a job (requires jobId)\n- history: Recent executions for a job (requires jobId)",
113
+ description: "Manage scheduled tasks (cron jobs) that run automatically.\n\nJobs can run an agent message (agentTurn), a workflow directly (workflowRun), or continue a durable goal (goalContinue).\n\nACTIONS:\n- list: Show all scheduled jobs with status and next run time\n- create: Create a job (scheduleKind plus exactly one of message, workflowDefinitionId, or goalId)\n- update: Change schedule, message, workflow fields, name, sessionTarget, agentId, or workingDirectory (requires jobId)\n- remove: Delete a job (requires jobId)\n- enable / disable: Toggle a job (requires jobId)\n- history: Recent executions for a job (requires jobId)",
79
114
  parameters: CronjobSchema,
80
115
  async execute(_toolCallId, params, _signal) {
81
116
  const cron = deps.getCronService();
@@ -95,17 +130,30 @@ function createCronjobTool(deps) {
95
130
  }
96
131
  case "create": {
97
132
  const workflowId = params.workflowDefinitionId?.trim();
133
+ const goalId = params.goalId?.trim();
98
134
  const hasMessage = Boolean(params.message?.trim());
99
- if (!params.schedule?.trim() || !workflowId && !hasMessage || workflowId && hasMessage) return textResult("Error: create requires schedule and exactly one of message or workflowDefinitionId.");
135
+ const targetCount = [
136
+ workflowId,
137
+ goalId,
138
+ hasMessage ? "message" : ""
139
+ ].filter(Boolean).length;
140
+ const schedule = scheduleFromParams(params);
141
+ if (!schedule || targetCount !== 1) return textResult("Error: create requires scheduleKind with matching cronExpr/at/everyMs and exactly one of message, workflowDefinitionId, or goalId.");
100
142
  if (hasMessage) {
101
143
  const scanResult = scanCronPrompt(params.message);
102
144
  if (scanResult) return textResult(`Error: ${scanResult}`);
103
145
  }
104
146
  let payload;
105
- let timeout;
106
147
  let sessionTarget = params.sessionTarget ?? "isolated";
107
148
  let delivery;
108
- if (workflowId) {
149
+ if (goalId) {
150
+ payload = {
151
+ kind: "goalContinue",
152
+ goalId,
153
+ ...params.goalMessage?.trim() ? { message: params.goalMessage.trim() } : {}
154
+ };
155
+ sessionTarget = "isolated";
156
+ } else if (workflowId) {
109
157
  let inputEnvelope;
110
158
  if (params.workflowInputJson?.trim()) try {
111
159
  inputEnvelope = { payload: JSON.parse(params.workflowInputJson) };
@@ -122,9 +170,8 @@ function createCronjobTool(deps) {
122
170
  ...params.waitForCompletion === false ? { waitForCompletion: false } : {}
123
171
  };
124
172
  sessionTarget = "isolated";
125
- timeout = DEFAULT_WORKFLOW_CRON_WAIT_MS;
126
173
  if (params.deliveryChannel?.trim() && params.deliveryTo?.trim()) delivery = {
127
- mode: "direct",
174
+ mode: "announce",
128
175
  channel: params.deliveryChannel.trim(),
129
176
  to: params.deliveryTo.trim()
130
177
  };
@@ -132,22 +179,21 @@ function createCronjobTool(deps) {
132
179
  kind: "agentTurn",
133
180
  message: params.message.trim()
134
181
  };
135
- const result = await cron.addJob(params.schedule.trim(), {
182
+ const result = await cron.addJob(schedule, {
136
183
  name: params.name?.trim() || void 0,
137
- timezone: params.timezone?.trim() || void 0,
138
184
  sessionTarget,
139
- ...timeout ? { timeout } : {},
140
185
  ...delivery ? { delivery } : {},
141
186
  ...params.agentId?.trim() ? { agentId: params.agentId.trim() } : {},
142
187
  ...params.workingDirectory?.trim() ? { workingDirectory: params.workingDirectory.trim() } : {},
143
188
  payload
144
189
  });
145
- return textResult(`Created ${workflowId ? `workflow job (${workflowId})` : "job"}${params.name ? ` "${params.name.trim()}"` : ""} (${result.id})\nSchedule: ${result.schedule}`);
190
+ return textResult(`Created ${goalId ? `goal job (${goalId})` : workflowId ? `workflow job (${workflowId})` : "job"}${params.name ? ` "${params.name.trim()}"` : ""} (${result.id})\nSchedule: ${describeSchedule(result.schedule)}`);
146
191
  }
147
192
  case "update": {
148
193
  if (!params.jobId?.trim()) return textResult("Error: update requires jobId.");
149
194
  const updates = {};
150
- if (params.schedule?.trim()) updates.schedule = params.schedule.trim();
195
+ const nextSchedule = scheduleFromParams(params);
196
+ if (nextSchedule) updates.schedule = nextSchedule;
151
197
  if (params.message != null && params.message.trim()) {
152
198
  const scanResult = scanCronPrompt(params.message);
153
199
  if (scanResult) return textResult(`Error: ${scanResult}`);
@@ -156,6 +202,14 @@ function createCronjobTool(deps) {
156
202
  message: params.message.trim()
157
203
  };
158
204
  }
205
+ if (params.goalId?.trim()) {
206
+ updates.payload = {
207
+ kind: "goalContinue",
208
+ goalId: params.goalId.trim(),
209
+ ...params.goalMessage?.trim() ? { message: params.goalMessage.trim() } : {}
210
+ };
211
+ updates.sessionTarget = "isolated";
212
+ }
159
213
  if (params.workflowDefinitionId?.trim()) {
160
214
  let inputEnvelope;
161
215
  if (params.workflowInputJson?.trim()) try {
@@ -173,19 +227,23 @@ function createCronjobTool(deps) {
173
227
  ...params.waitForCompletion === false ? { waitForCompletion: false } : {}
174
228
  };
175
229
  updates.sessionTarget = "isolated";
176
- updates.timeout = DEFAULT_WORKFLOW_CRON_WAIT_MS;
177
230
  }
178
231
  if (params.deliveryChannel?.trim() && params.deliveryTo?.trim()) updates.delivery = {
179
- mode: "direct",
232
+ mode: "announce",
180
233
  channel: params.deliveryChannel.trim(),
181
234
  to: params.deliveryTo.trim()
182
235
  };
183
- if (params.timezone?.trim()) updates.timezone = params.timezone.trim();
184
236
  if (params.name !== void 0) updates.name = params.name.trim() || void 0;
185
237
  if (params.sessionTarget !== void 0) updates.sessionTarget = params.sessionTarget;
186
- if (params.agentId !== void 0) updates.agentId = params.agentId.trim() || null;
187
- if (params.workingDirectory !== void 0) updates.workingDirectory = params.workingDirectory.trim() || null;
188
- if (Object.keys(updates).length === 0) return textResult("Error: update requires at least one of schedule, message, workflowDefinitionId, name, timezone, sessionTarget, agentId, workingDirectory, deliveryChannel/deliveryTo.");
238
+ if (params.agentId !== void 0) {
239
+ const t = params.agentId.trim();
240
+ if (t) updates.agentId = t;
241
+ }
242
+ if (params.workingDirectory !== void 0) {
243
+ const t = params.workingDirectory.trim();
244
+ if (t) updates.workingDirectory = t;
245
+ }
246
+ if (Object.keys(updates).length === 0) return textResult("Error: update requires at least one of scheduleKind, message, workflowDefinitionId, name, sessionTarget, agentId, workingDirectory, deliveryChannel/deliveryTo.");
189
247
  return textResult(await cron.updateJob(params.jobId.trim(), updates) ? `Updated job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`);
190
248
  }
191
249
  case "remove":
@@ -1 +1 @@
1
- {"version":3,"file":"cronjob-tool.js","names":[],"sources":["../../../../src/agent/tools/cronjob-tool.ts"],"sourcesContent":["// Agent tool for managing scheduled cron jobs (CronService-backed)\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\n\nimport type { CronService } from '../../cron/index.js';\nimport { getCronPayloadText } from '../../cron/job-content.js';\nimport { DEFAULT_WORKFLOW_CRON_WAIT_MS } from '../../cron/workflow-run-completion.js';\nimport type { CronPayload, JobData, JobExecution, JobWithNextRun } from '../../cron/types.js';\n\nconst CRON_THREAT_PATTERNS: Array<[RegExp, string]> = [\n [/ignore\\s+(previous|all|above)\\s+instructions/i, 'prompt_injection'],\n [/do\\s+not\\s+tell\\s+the\\s+user/i, 'deception'],\n [/system\\s+prompt\\s+override/i, 'sys_prompt_override'],\n [/curl\\s+[^\\n]*\\$\\{?\\w*(KEY|TOKEN|SECRET|PASSWORD)/i, 'exfil_curl'],\n [/cat\\s+[^\\n]*(\\.env|credentials|\\.netrc)/i, 'read_secrets'],\n [/rm\\s+-rf\\s+\\//i, 'destructive_rm'],\n];\n\nexport function scanCronPrompt(prompt: string): string | null {\n for (const [pattern, id] of CRON_THREAT_PATTERNS) {\n if (pattern.test(prompt)) {\n return (\n `Blocked: prompt matches threat pattern '${id}'. ` +\n 'Cron prompts must not contain injection or exfiltration payloads.'\n );\n }\n }\n return null;\n}\n\nconst CronjobSchema = Type.Object({\n action: Type.Union(\n [\n Type.Literal('list'),\n Type.Literal('create'),\n Type.Literal('update'),\n Type.Literal('remove'),\n Type.Literal('enable'),\n Type.Literal('disable'),\n Type.Literal('history'),\n ],\n { description: 'Action to perform on cron jobs' },\n ),\n\n name: Type.Optional(Type.String({ description: 'Human-readable job name' })),\n schedule: Type.Optional(\n Type.String({\n description:\n 'Cron schedule expression. Examples:\\n' +\n ' \"0 9 * * *\" = every day at 9:00 AM\\n' +\n ' \"*/30 * * * *\" = every 30 minutes\\n' +\n ' \"0 9 * * 1-5\" = weekdays at 9:00 AM\\n' +\n ' \"0 0 1 * *\" = first day of each month',\n }),\n ),\n message: Type.Optional(\n Type.String({\n description:\n 'Instruction for the agent when the job runs (agentTurn payload; typically a fresh session).',\n }),\n ),\n workflowDefinitionId: Type.Optional(\n Type.String({\n description:\n 'Workflow definition id for a direct workflowRun job (mutually exclusive with message on create).',\n }),\n ),\n workflowGoal: Type.Optional(\n Type.String({ description: 'Optional goal override when creating a workflowRun job.' }),\n ),\n workflowInputJson: Type.Optional(\n Type.String({\n description: 'JSON object for workflow input payload (workflowRun create/update).',\n }),\n ),\n waitForCompletion: Type.Optional(\n Type.Boolean({\n description:\n 'For workflowRun jobs: when true (default), cron waits for terminal status before succeeding.',\n }),\n ),\n deliveryChannel: Type.Optional(\n Type.String({ description: 'Delivery channel when workflow completes (e.g. telegram).' }),\n ),\n deliveryTo: Type.Optional(\n Type.String({ description: 'Delivery recipient chat id when workflow completes.' }),\n ),\n timezone: Type.Optional(\n Type.String({\n description:\n 'IANA timezone (e.g. Asia/Shanghai, America/New_York). Must be one supported by the cron store.',\n }),\n ),\n sessionTarget: Type.Optional(\n Type.Union([Type.Literal('main'), Type.Literal('isolated')], {\n description:\n '\"main\" uses the main session context; \"isolated\" (default on create) uses a separate session per run.',\n }),\n ),\n agentId: Type.Optional(\n Type.String({\n description:\n 'Agent profile id for isolated jobs (session key). Omit to use the configured default agent (usually `main`).',\n }),\n ),\n workingDirectory: Type.Optional(\n Type.String({\n description:\n 'Absolute workspace path on the gateway host for isolated jobs. Omit to use the agent default workspace.',\n }),\n ),\n\n jobId: Type.Optional(Type.String({ description: 'Job ID (from list output)' })),\n});\n\nexport type CronjobToolParams = {\n action: 'list' | 'create' | 'update' | 'remove' | 'enable' | 'disable' | 'history';\n name?: string;\n schedule?: string;\n message?: string;\n workflowDefinitionId?: string;\n workflowGoal?: string;\n workflowInputJson?: string;\n waitForCompletion?: boolean;\n deliveryChannel?: string;\n deliveryTo?: string;\n timezone?: string;\n sessionTarget?: 'main' | 'isolated';\n agentId?: string;\n workingDirectory?: string;\n jobId?: string;\n};\n\nexport interface CronjobToolDeps {\n getCronService: () => CronService | undefined;\n}\n\nfunction textResult(text: string): AgentToolResult<{}> {\n return { content: [{ type: 'text', text }], details: {} };\n}\n\nfunction formatJob(job: JobWithNextRun): string {\n const status = job.enabled ? '▶️ active' : '⏸️ disabled';\n const payloadText = getCronPayloadText(job);\n const truncatedPayload =\n payloadText.length > 100 ? `${payloadText.slice(0, 100)}...` : payloadText;\n const payloadLine =\n job.payload.kind === 'workflowRun'\n ? ` Workflow: ${job.payload.definitionId}${job.payload.goal ? ` — ${job.payload.goal}` : ''}`\n : ` Message: ${truncatedPayload}`;\n\n return [\n `${status} ${job.name ?? '(unnamed)'} (${job.id})`,\n ` Schedule: ${job.schedule}${job.timezone ? ` (${job.timezone})` : ''}`,\n ` Type: ${job.payload.kind}`,\n payloadLine,\n ` Next run: ${job.next_run ?? 'N/A'}`,\n ` Session: ${job.sessionTarget ?? 'main'}`,\n ` Agent: ${job.agentId?.trim() || '(default)'}`,\n ` Workspace: ${job.workingDirectory?.trim() || '(agent default)'}`,\n ].join('\\n');\n}\n\nfunction formatExecution(exec: JobExecution): string {\n const dur = exec.duration != null ? `${(exec.duration / 1000).toFixed(1)}s` : 'N/A';\n const lines = [`[${exec.status}] ${exec.startedAt} (${dur})`];\n if (exec.summary) {\n lines.push(` Summary: ${exec.summary.slice(0, 200)}`);\n }\n if (exec.error) {\n lines.push(` Error: ${exec.error.slice(0, 200)}`);\n }\n return lines.join('\\n');\n}\n\nexport function createCronjobTool(deps: CronjobToolDeps): AgentTool {\n return {\n name: 'cronjob',\n label: '⏰ Cronjob',\n description:\n 'Manage scheduled tasks (cron jobs) that run automatically.\\n\\n' +\n 'Jobs can run an agent message (agentTurn) or a workflow directly (workflowRun).\\n\\n' +\n 'ACTIONS:\\n' +\n '- list: Show all scheduled jobs with status and next run time\\n' +\n '- create: Create a job (schedule + message OR workflowDefinitionId; optional goal, workflowInputJson, deliveryChannel/deliveryTo, waitForCompletion)\\n' +\n '- update: Change schedule, message, workflow fields, name, timezone, sessionTarget, agentId, or workingDirectory (requires jobId)\\n' +\n '- remove: Delete a job (requires jobId)\\n' +\n '- enable / disable: Toggle a job (requires jobId)\\n' +\n '- history: Recent executions for a job (requires jobId)',\n parameters: CronjobSchema,\n\n async execute(_toolCallId, params: CronjobToolParams, _signal) {\n const cron = deps.getCronService();\n if (!cron) {\n return textResult('Cron service is not available in this environment.');\n }\n\n try {\n switch (params.action) {\n case 'list': {\n const jobs = await cron.listJobs();\n if (jobs.length === 0) {\n return textResult('No scheduled jobs.');\n }\n const formatted = jobs.map(formatJob).join('\\n\\n');\n return { content: [{ type: 'text', text: formatted }], details: {} };\n }\n\n case 'create': {\n const workflowId = params.workflowDefinitionId?.trim();\n const hasMessage = Boolean(params.message?.trim());\n if (!params.schedule?.trim() || (!workflowId && !hasMessage) || (workflowId && hasMessage)) {\n return textResult(\n 'Error: create requires schedule and exactly one of message or workflowDefinitionId.',\n );\n }\n\n if (hasMessage) {\n const scanResult = scanCronPrompt(params.message!);\n if (scanResult) {\n return textResult(`Error: ${scanResult}`);\n }\n }\n\n let payload: CronPayload;\n let timeout: number | undefined;\n let sessionTarget = params.sessionTarget ?? 'isolated';\n let delivery: JobData['delivery'];\n\n if (workflowId) {\n let inputEnvelope: { payload: unknown } | undefined;\n if (params.workflowInputJson?.trim()) {\n try {\n inputEnvelope = { payload: JSON.parse(params.workflowInputJson) as unknown };\n } catch {\n return textResult('Error: workflowInputJson must be valid JSON.');\n }\n }\n const agentId = params.agentId?.trim() || undefined;\n payload = {\n kind: 'workflowRun',\n definitionId: workflowId,\n ...(params.workflowGoal?.trim() ? { goal: params.workflowGoal.trim() } : {}),\n ...(inputEnvelope ? { inputEnvelope } : {}),\n ...(agentId ? { agentId } : {}),\n ...(params.waitForCompletion === false ? { waitForCompletion: false } : {}),\n };\n sessionTarget = 'isolated';\n timeout = DEFAULT_WORKFLOW_CRON_WAIT_MS;\n if (params.deliveryChannel?.trim() && params.deliveryTo?.trim()) {\n delivery = {\n mode: 'direct',\n channel: params.deliveryChannel.trim(),\n to: params.deliveryTo.trim(),\n };\n }\n } else {\n payload = {\n kind: 'agentTurn',\n message: params.message!.trim(),\n };\n }\n\n const result = await cron.addJob(params.schedule.trim(), {\n name: params.name?.trim() || undefined,\n timezone: params.timezone?.trim() || undefined,\n sessionTarget,\n ...(timeout ? { timeout } : {}),\n ...(delivery ? { delivery } : {}),\n ...(params.agentId?.trim() ? { agentId: params.agentId.trim() } : {}),\n ...(params.workingDirectory?.trim()\n ? { workingDirectory: params.workingDirectory.trim() }\n : {}),\n payload,\n });\n\n const kindLabel = workflowId ? `workflow job (${workflowId})` : 'job';\n return textResult(\n `Created ${kindLabel}${params.name ? ` \"${params.name.trim()}\"` : ''} (${result.id})\\n` +\n `Schedule: ${result.schedule}`,\n );\n }\n\n case 'update': {\n if (!params.jobId?.trim()) {\n return textResult('Error: update requires jobId.');\n }\n\n const updates: Partial<Omit<JobData, 'id' | 'created_at' | 'updated_at'>> = {};\n if (params.schedule?.trim()) {\n updates.schedule = params.schedule.trim();\n }\n if (params.message != null && params.message.trim()) {\n const scanResult = scanCronPrompt(params.message);\n if (scanResult) {\n return textResult(`Error: ${scanResult}`);\n }\n updates.payload = { kind: 'agentTurn', message: params.message.trim() };\n }\n if (params.workflowDefinitionId?.trim()) {\n let inputEnvelope: { payload: unknown } | undefined;\n if (params.workflowInputJson?.trim()) {\n try {\n inputEnvelope = { payload: JSON.parse(params.workflowInputJson) as unknown };\n } catch {\n return textResult('Error: workflowInputJson must be valid JSON.');\n }\n }\n const agentId = params.agentId?.trim() || undefined;\n updates.payload = {\n kind: 'workflowRun',\n definitionId: params.workflowDefinitionId.trim(),\n ...(params.workflowGoal?.trim() ? { goal: params.workflowGoal.trim() } : {}),\n ...(inputEnvelope ? { inputEnvelope } : {}),\n ...(agentId ? { agentId } : {}),\n ...(params.waitForCompletion === false ? { waitForCompletion: false } : {}),\n };\n updates.sessionTarget = 'isolated';\n updates.timeout = DEFAULT_WORKFLOW_CRON_WAIT_MS;\n }\n if (params.deliveryChannel?.trim() && params.deliveryTo?.trim()) {\n updates.delivery = {\n mode: 'direct',\n channel: params.deliveryChannel.trim(),\n to: params.deliveryTo.trim(),\n };\n }\n if (params.timezone?.trim()) {\n updates.timezone = params.timezone.trim();\n }\n if (params.name !== undefined) {\n updates.name = params.name.trim() || undefined;\n }\n if (params.sessionTarget !== undefined) {\n updates.sessionTarget = params.sessionTarget;\n }\n if (params.agentId !== undefined) {\n const t = params.agentId.trim();\n updates.agentId = t || null;\n }\n if (params.workingDirectory !== undefined) {\n const t = params.workingDirectory.trim();\n updates.workingDirectory = t || null;\n }\n\n if (Object.keys(updates).length === 0) {\n return textResult(\n 'Error: update requires at least one of schedule, message, workflowDefinitionId, name, timezone, sessionTarget, agentId, workingDirectory, deliveryChannel/deliveryTo.',\n );\n }\n\n const success = await cron.updateJob(params.jobId.trim(), updates);\n return textResult(\n success ? `Updated job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`,\n );\n }\n\n case 'remove': {\n if (!params.jobId?.trim()) {\n return textResult('Error: remove requires jobId.');\n }\n const removed = await cron.removeJob(params.jobId.trim());\n return textResult(\n removed ? `Removed job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`,\n );\n }\n\n case 'disable': {\n if (!params.jobId?.trim()) {\n return textResult('Error: disable requires jobId.');\n }\n const toggled = await cron.toggleJob(params.jobId.trim(), false);\n return textResult(\n toggled ? `Disabled job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`,\n );\n }\n\n case 'enable': {\n if (!params.jobId?.trim()) {\n return textResult('Error: enable requires jobId.');\n }\n const toggled = await cron.toggleJob(params.jobId.trim(), true);\n return textResult(\n toggled ? `Enabled job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`,\n );\n }\n\n case 'history': {\n if (!params.jobId?.trim()) {\n return textResult('Error: history requires jobId.');\n }\n const history = await cron.getJobHistory(params.jobId.trim(), 5);\n if (history.length === 0) {\n return textResult(`No execution history for job ${params.jobId.trim()}.`);\n }\n const formatted = history.map(formatExecution).join('\\n\\n');\n return textResult(formatted);\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return textResult(`Error: ${message}`);\n }\n },\n } as any;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cronjob-tool.js","names":[],"sources":["../../../../src/agent/tools/cronjob-tool.ts"],"sourcesContent":["// Agent tool for managing scheduled cron jobs (CronService-backed)\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\n\nimport type { CronService } from '../../cron/index.js';\nimport { describeSchedule } from '../../cron/schedule.js';\nimport { getCronPayloadText } from '../../cron/job-content.js';\nimport type { CronDelivery, CronPayload, CronSchedule, CronJobPatch, JobData, JobExecution } from '../../cron/types.js';\n\nconst CRON_THREAT_PATTERNS: Array<[RegExp, string]> = [\n [/ignore\\s+(previous|all|above)\\s+instructions/i, 'prompt_injection'],\n [/do\\s+not\\s+tell\\s+the\\s+user/i, 'deception'],\n [/system\\s+prompt\\s+override/i, 'sys_prompt_override'],\n [/curl\\s+[^\\n]*\\$\\{?\\w*(KEY|TOKEN|SECRET|PASSWORD)/i, 'exfil_curl'],\n [/cat\\s+[^\\n]*(\\.env|credentials|\\.netrc)/i, 'read_secrets'],\n [/rm\\s+-rf\\s+\\//i, 'destructive_rm'],\n];\n\nexport function scanCronPrompt(prompt: string): string | null {\n for (const [pattern, id] of CRON_THREAT_PATTERNS) {\n if (pattern.test(prompt)) {\n return (\n `Blocked: prompt matches threat pattern '${id}'. ` +\n 'Cron prompts must not contain injection or exfiltration payloads.'\n );\n }\n }\n return null;\n}\n\nconst CronjobSchema = Type.Object({\n action: Type.Union(\n [\n Type.Literal('list'),\n Type.Literal('create'),\n Type.Literal('update'),\n Type.Literal('remove'),\n Type.Literal('enable'),\n Type.Literal('disable'),\n Type.Literal('history'),\n ],\n { description: 'Action to perform on cron jobs' },\n ),\n\n name: Type.Optional(Type.String({ description: 'Human-readable job name' })),\n scheduleKind: Type.Optional(\n Type.Union([Type.Literal('cron'), Type.Literal('at'), Type.Literal('every')], {\n description: 'Schedule kind. Use cronExpr for cron, at for one-time ISO time, everyMs for interval.',\n }),\n ),\n cronExpr: Type.Optional(\n Type.String({\n description:\n 'Cron schedule expression. Examples:\\n' +\n ' \"0 9 * * *\" = every day at 9:00 AM\\n' +\n ' \"*/30 * * * *\" = every 30 minutes\\n' +\n ' \"0 9 * * 1-5\" = weekdays at 9:00 AM\\n' +\n ' \"0 0 1 * *\" = first day of each month',\n }),\n ),\n at: Type.Optional(Type.String({ description: 'One-time run timestamp as ISO 8601 string.' })),\n everyMs: Type.Optional(Type.Number({ description: 'Fixed interval in milliseconds.' })),\n tz: Type.Optional(Type.String({ description: 'IANA timezone for cronExpr, e.g. Asia/Shanghai.' })),\n message: Type.Optional(\n Type.String({\n description:\n 'Instruction for the agent when the job runs (agentTurn payload; typically a fresh session).',\n }),\n ),\n workflowDefinitionId: Type.Optional(\n Type.String({\n description:\n 'Workflow definition id for a workflowRun job (mutually exclusive with message on create).',\n }),\n ),\n workflowGoal: Type.Optional(\n Type.String({ description: 'Optional goal override when creating a workflowRun job.' }),\n ),\n workflowInputJson: Type.Optional(\n Type.String({\n description: 'JSON object for workflow input payload (workflowRun create/update).',\n }),\n ),\n goalId: Type.Optional(\n Type.String({\n description:\n 'Durable goal id for a goalContinue job (mutually exclusive with message and workflowDefinitionId).',\n }),\n ),\n goalMessage: Type.Optional(\n Type.String({\n description: 'Optional custom continuation message for a goalContinue job.',\n }),\n ),\n waitForCompletion: Type.Optional(\n Type.Boolean({\n description:\n 'For workflowRun jobs: when true (default), cron waits for terminal status before succeeding.',\n }),\n ),\n deliveryChannel: Type.Optional(\n Type.String({ description: 'Delivery channel when workflow completes (e.g. telegram).' }),\n ),\n deliveryTo: Type.Optional(\n Type.String({ description: 'Delivery recipient chat id when workflow completes.' }),\n ),\n sessionTarget: Type.Optional(\n Type.Union([Type.Literal('main'), Type.Literal('isolated')], {\n description:\n '\"main\" uses the main session context; \"isolated\" (default on create) uses a separate session per run.',\n }),\n ),\n agentId: Type.Optional(\n Type.String({\n description:\n 'Agent profile id for isolated jobs (session key). Omit to use the configured default agent (usually `main`).',\n }),\n ),\n workingDirectory: Type.Optional(\n Type.String({\n description:\n 'Absolute workspace path on the gateway host for isolated jobs. Omit to use the agent default workspace.',\n }),\n ),\n\n jobId: Type.Optional(Type.String({ description: 'Job ID (from list output)' })),\n});\n\nexport type CronjobToolParams = {\n action: 'list' | 'create' | 'update' | 'remove' | 'enable' | 'disable' | 'history';\n name?: string;\n scheduleKind?: 'cron' | 'at' | 'every';\n cronExpr?: string;\n at?: string;\n everyMs?: number;\n tz?: string;\n message?: string;\n workflowDefinitionId?: string;\n workflowGoal?: string;\n workflowInputJson?: string;\n goalId?: string;\n goalMessage?: string;\n waitForCompletion?: boolean;\n deliveryChannel?: string;\n deliveryTo?: string;\n sessionTarget?: 'main' | 'isolated' | 'current';\n agentId?: string;\n workingDirectory?: string;\n jobId?: string;\n};\n\nexport interface CronjobToolDeps {\n getCronService: () => CronService | undefined;\n}\n\nfunction textResult(text: string): AgentToolResult<{}> {\n return { content: [{ type: 'text', text }], details: {} };\n}\n\nfunction formatJob(job: JobData): string {\n const status = job.enabled ? 'active' : 'disabled';\n const payloadText = getCronPayloadText(job);\n const truncatedPayload =\n payloadText.length > 100 ? `${payloadText.slice(0, 100)}...` : payloadText;\n const payloadLine =\n job.payload.kind === 'workflowRun'\n ? ` Workflow: ${job.payload.definitionId}${job.payload.goal ? ` — ${job.payload.goal}` : ''}`\n : ` Message: ${truncatedPayload}`;\n\n return [\n `${status} ${job.name ?? '(unnamed)'} (${job.id})`,\n ` Schedule: ${describeSchedule(job.schedule)}`,\n ` Type: ${job.payload.kind}`,\n payloadLine,\n ` Next run: ${job.state.nextRunAtMs ? new Date(job.state.nextRunAtMs).toISOString() : 'N/A'}`,\n ` Session: ${job.sessionTarget ?? 'main'}`,\n ` Agent: ${job.agentId?.trim() || '(default)'}`,\n ` Workspace: ${job.workingDirectory?.trim() || '(agent default)'}`,\n ].join('\\n');\n}\n\nfunction scheduleFromParams(params: Pick<CronjobToolParams, 'scheduleKind' | 'cronExpr' | 'at' | 'everyMs' | 'tz'>): CronSchedule | undefined {\n const kind = params.scheduleKind;\n if (!kind) return undefined;\n if (kind === 'cron') {\n const expr = params.cronExpr?.trim();\n if (!expr) return undefined;\n return { kind, expr, ...(params.tz?.trim() ? { tz: params.tz.trim() } : {}) };\n }\n if (kind === 'at') {\n const at = params.at?.trim();\n if (!at) return undefined;\n return { kind, at };\n }\n if (!Number.isFinite(params.everyMs) || !params.everyMs || params.everyMs <= 0) return undefined;\n return { kind, everyMs: Math.floor(params.everyMs) };\n}\n\nfunction formatExecution(exec: JobExecution): string {\n const dur = exec.duration != null ? `${(exec.duration / 1000).toFixed(1)}s` : 'N/A';\n const lines = [`[${exec.status}] ${exec.startedAt} (${dur})`];\n if (exec.summary) {\n lines.push(` Summary: ${exec.summary.slice(0, 200)}`);\n }\n if (exec.error) {\n lines.push(` Error: ${exec.error.slice(0, 200)}`);\n }\n return lines.join('\\n');\n}\n\nexport function createCronjobTool(deps: CronjobToolDeps): AgentTool {\n return {\n name: 'cronjob',\n label: '⏰ Cronjob',\n description:\n 'Manage scheduled tasks (cron jobs) that run automatically.\\n\\n' +\n 'Jobs can run an agent message (agentTurn), a workflow directly (workflowRun), or continue a durable goal (goalContinue).\\n\\n' +\n 'ACTIONS:\\n' +\n '- list: Show all scheduled jobs with status and next run time\\n' +\n '- create: Create a job (scheduleKind plus exactly one of message, workflowDefinitionId, or goalId)\\n' +\n '- update: Change schedule, message, workflow fields, name, sessionTarget, agentId, or workingDirectory (requires jobId)\\n' +\n '- remove: Delete a job (requires jobId)\\n' +\n '- enable / disable: Toggle a job (requires jobId)\\n' +\n '- history: Recent executions for a job (requires jobId)',\n parameters: CronjobSchema,\n\n async execute(_toolCallId, params: CronjobToolParams, _signal) {\n const cron = deps.getCronService();\n if (!cron) {\n return textResult('Cron service is not available in this environment.');\n }\n\n try {\n switch (params.action) {\n case 'list': {\n const jobs = await cron.listJobs();\n if (jobs.length === 0) {\n return textResult('No scheduled jobs.');\n }\n const formatted = jobs.map(formatJob).join('\\n\\n');\n return { content: [{ type: 'text', text: formatted }], details: {} };\n }\n\n case 'create': {\n const workflowId = params.workflowDefinitionId?.trim();\n const goalId = params.goalId?.trim();\n const hasMessage = Boolean(params.message?.trim());\n const targetCount = [workflowId, goalId, hasMessage ? 'message' : ''].filter(Boolean).length;\n const schedule = scheduleFromParams(params);\n if (!schedule || targetCount !== 1) {\n return textResult(\n 'Error: create requires scheduleKind with matching cronExpr/at/everyMs and exactly one of message, workflowDefinitionId, or goalId.',\n );\n }\n\n if (hasMessage) {\n const scanResult = scanCronPrompt(params.message!);\n if (scanResult) {\n return textResult(`Error: ${scanResult}`);\n }\n }\n\n let payload: CronPayload;\n let sessionTarget = params.sessionTarget ?? 'isolated';\n let delivery: CronDelivery | undefined;\n\n if (goalId) {\n payload = {\n kind: 'goalContinue',\n goalId,\n ...(params.goalMessage?.trim() ? { message: params.goalMessage.trim() } : {}),\n };\n sessionTarget = 'isolated';\n } else if (workflowId) {\n let inputEnvelope: { payload: unknown } | undefined;\n if (params.workflowInputJson?.trim()) {\n try {\n inputEnvelope = { payload: JSON.parse(params.workflowInputJson) as unknown };\n } catch {\n return textResult('Error: workflowInputJson must be valid JSON.');\n }\n }\n const agentId = params.agentId?.trim() || undefined;\n payload = {\n kind: 'workflowRun',\n definitionId: workflowId,\n ...(params.workflowGoal?.trim() ? { goal: params.workflowGoal.trim() } : {}),\n ...(inputEnvelope ? { inputEnvelope } : {}),\n ...(agentId ? { agentId } : {}),\n ...(params.waitForCompletion === false ? { waitForCompletion: false } : {}),\n };\n sessionTarget = 'isolated';\n if (params.deliveryChannel?.trim() && params.deliveryTo?.trim()) {\n delivery = {\n mode: 'announce',\n channel: params.deliveryChannel.trim(),\n to: params.deliveryTo.trim(),\n };\n }\n } else {\n payload = {\n kind: 'agentTurn',\n message: params.message!.trim(),\n };\n }\n\n const result = await cron.addJob(schedule, {\n name: params.name?.trim() || undefined,\n sessionTarget,\n ...(delivery ? { delivery } : {}),\n ...(params.agentId?.trim() ? { agentId: params.agentId.trim() } : {}),\n ...(params.workingDirectory?.trim()\n ? { workingDirectory: params.workingDirectory.trim() }\n : {}),\n payload,\n });\n\n const kindLabel = goalId ? `goal job (${goalId})` : workflowId ? `workflow job (${workflowId})` : 'job';\n return textResult(\n `Created ${kindLabel}${params.name ? ` \"${params.name.trim()}\"` : ''} (${result.id})\\n` +\n `Schedule: ${describeSchedule(result.schedule)}`,\n );\n }\n\n case 'update': {\n if (!params.jobId?.trim()) {\n return textResult('Error: update requires jobId.');\n }\n\n const updates: CronJobPatch = {};\n const nextSchedule = scheduleFromParams(params);\n if (nextSchedule) {\n updates.schedule = nextSchedule;\n }\n if (params.message != null && params.message.trim()) {\n const scanResult = scanCronPrompt(params.message);\n if (scanResult) {\n return textResult(`Error: ${scanResult}`);\n }\n updates.payload = { kind: 'agentTurn', message: params.message.trim() };\n }\n if (params.goalId?.trim()) {\n updates.payload = {\n kind: 'goalContinue',\n goalId: params.goalId.trim(),\n ...(params.goalMessage?.trim() ? { message: params.goalMessage.trim() } : {}),\n };\n updates.sessionTarget = 'isolated';\n }\n if (params.workflowDefinitionId?.trim()) {\n let inputEnvelope: { payload: unknown } | undefined;\n if (params.workflowInputJson?.trim()) {\n try {\n inputEnvelope = { payload: JSON.parse(params.workflowInputJson) as unknown };\n } catch {\n return textResult('Error: workflowInputJson must be valid JSON.');\n }\n }\n const agentId = params.agentId?.trim() || undefined;\n updates.payload = {\n kind: 'workflowRun',\n definitionId: params.workflowDefinitionId.trim(),\n ...(params.workflowGoal?.trim() ? { goal: params.workflowGoal.trim() } : {}),\n ...(inputEnvelope ? { inputEnvelope } : {}),\n ...(agentId ? { agentId } : {}),\n ...(params.waitForCompletion === false ? { waitForCompletion: false } : {}),\n };\n updates.sessionTarget = 'isolated';\n }\n if (params.deliveryChannel?.trim() && params.deliveryTo?.trim()) {\n updates.delivery = {\n mode: 'announce',\n channel: params.deliveryChannel.trim(),\n to: params.deliveryTo.trim(),\n };\n }\n if (params.name !== undefined) {\n updates.name = params.name.trim() || undefined;\n }\n if (params.sessionTarget !== undefined) {\n updates.sessionTarget = params.sessionTarget;\n }\n if (params.agentId !== undefined) {\n const t = params.agentId.trim();\n if (t) updates.agentId = t;\n }\n if (params.workingDirectory !== undefined) {\n const t = params.workingDirectory.trim();\n if (t) updates.workingDirectory = t;\n }\n\n if (Object.keys(updates).length === 0) {\n return textResult(\n 'Error: update requires at least one of scheduleKind, message, workflowDefinitionId, name, sessionTarget, agentId, workingDirectory, deliveryChannel/deliveryTo.',\n );\n }\n\n const success = await cron.updateJob(params.jobId.trim(), updates);\n return textResult(\n success ? `Updated job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`,\n );\n }\n\n case 'remove': {\n if (!params.jobId?.trim()) {\n return textResult('Error: remove requires jobId.');\n }\n const removed = await cron.removeJob(params.jobId.trim());\n return textResult(\n removed ? `Removed job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`,\n );\n }\n\n case 'disable': {\n if (!params.jobId?.trim()) {\n return textResult('Error: disable requires jobId.');\n }\n const toggled = await cron.toggleJob(params.jobId.trim(), false);\n return textResult(\n toggled ? `Disabled job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`,\n );\n }\n\n case 'enable': {\n if (!params.jobId?.trim()) {\n return textResult('Error: enable requires jobId.');\n }\n const toggled = await cron.toggleJob(params.jobId.trim(), true);\n return textResult(\n toggled ? `Enabled job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`,\n );\n }\n\n case 'history': {\n if (!params.jobId?.trim()) {\n return textResult('Error: history requires jobId.');\n }\n const history = await cron.getJobHistory(params.jobId.trim(), 5);\n if (history.length === 0) {\n return textResult(`No execution history for job ${params.jobId.trim()}.`);\n }\n const formatted = history.map(formatExecution).join('\\n\\n');\n return textResult(formatted);\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return textResult(`Error: ${message}`);\n }\n },\n } as any;\n}\n"],"mappings":"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"}
@@ -3,8 +3,8 @@ import { init_logger } from "../../utils/logger.js";
3
3
  import { SHORT_TERM_PROMOTION_LOCK_RELATIVE, SHORT_TERM_RECALL_STORE_RELATIVE } from "../memory/dreaming/constants.js";
4
4
  import { loadDreamingStore, saveDreamingStore } from "../memory/dreaming/short-term-store.js";
5
5
  import { resolveDreamingConfig } from "../memory/dreaming/config.js";
6
- import path from "node:path";
7
6
  import fs from "node:fs/promises";
7
+ import path from "node:path";
8
8
  import { Type } from "@sinclair/typebox";
9
9
  //#region src/agent/tools/dreaming-tool.ts
10
10
  init_logger();
@@ -1,4 +1,5 @@
1
1
  import type { AgentTool } from '@earendil-works/pi-agent-core';
2
+ import type { GoalEvidenceRecordInput } from './goal-evidence-recorder.js';
2
3
  export interface EditToolDetails {
3
4
  diff?: string;
4
5
  firstChangedLine?: number;
@@ -7,6 +8,7 @@ export interface EditToolDetails {
7
8
  export interface CreateEditFileToolOptions {
8
9
  /** When set and the path is a bare profile filename (e.g. SOUL.md), edit under this root. */
9
10
  profileMarkdownRoot?: string;
11
+ recordGoalEvidence?: (input: GoalEvidenceRecordInput) => Promise<void> | void;
10
12
  }
11
13
  export declare function createEditFileTool(workspace: string, options?: CreateEditFileToolOptions): AgentTool;
12
14
  export declare const editFileTool: AgentTool;
@@ -86,6 +86,16 @@ function createEditFileTool(workspace, options) {
86
86
  };
87
87
  const diffResult = generateDiffString(originalWithReplacement, finalContent, normalized);
88
88
  await writeFile(normalized, finalContent, "utf-8");
89
+ await options?.recordGoalEvidence?.({
90
+ kind: "diff",
91
+ title: `File edited: ${normalized}`,
92
+ summary: diffResult.slice(0, 4e3),
93
+ uri: normalized,
94
+ data: {
95
+ path: normalized,
96
+ fuzzyMatchUsed: matchResult.usedFuzzyMatch
97
+ }
98
+ });
89
99
  return {
90
100
  content: [{
91
101
  type: "text",
@@ -1 +1 @@
1
- {"version":3,"file":"edit.js","names":[],"sources":["../../../../src/agent/tools/edit.ts"],"sourcesContent":["// Edit file tool\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { readFile, writeFile, stat } from 'fs/promises';\nimport { checkFileSafety } from '../prompt/safety.js';\nimport {\n isBareProfileMarkdownFileName,\n resolveProfileMarkdownPathIfBareName,\n resolvePathUnderWorkspace,\n} from './tool-paths.js';\nimport { evaluateFilePolicy } from '../sandbox/exec-policy.js';\nimport { normalizeToLF, restoreLineEndings, normalizeForFuzzyMatch, fuzzyFindText, stripBom, generateDiffString } from './edit-diff.js';\n\nconst MAX_FILE_SIZE = 10 * 1024 * 1024;\n\nconst EditFileSchema = Type.Object({\n path: Type.String({ description: 'File path to edit' }),\n oldText: Type.String({ description: 'Text to replace' }),\n newText: Type.String({ description: 'Replacement text' }),\n});\n\nexport interface EditToolDetails {\n diff?: string;\n firstChangedLine?: number;\n fuzzyMatchUsed?: boolean;\n}\n\ntype EditFileParams = { path: string; oldText: string; newText: string };\n\nexport interface CreateEditFileToolOptions {\n /** When set and the path is a bare profile filename (e.g. SOUL.md), edit under this root. */\n profileMarkdownRoot?: string;\n}\n\nexport function createEditFileTool(\n workspace: string,\n options?: CreateEditFileToolOptions,\n): AgentTool {\n return {\n name: 'edit_file',\n description:\n 'Edit file by replacing text. Relative paths are under the current agent workspace; profile Markdown (SOUL.md, etc.) is edited automatically when given by filename.',\n parameters: EditFileSchema,\n label: '✏️ Edit',\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<EditToolDetails>> {\n try {\n const p = params as EditFileParams;\n const safety = checkFileSafety('write', p.path);\n if (!safety.allowed) return { content: [{ type: 'text', text: `🚫 ${safety.message}` }], details: {} };\n\n const editsProfileFile = Boolean(\n options?.profileMarkdownRoot && isBareProfileMarkdownFileName(p.path),\n );\n const workspaceRoot = editsProfileFile ? options!.profileMarkdownRoot! : workspace;\n\n // Sandbox path-policy check (blocked dirs, symlink escape, config protection)\n const pathPolicy = evaluateFilePolicy({\n operation: 'edit',\n path: p.path,\n workspaceRoot,\n });\n if (!pathPolicy.allowed) {\n return { content: [{ type: 'text', text: `🚫 Sandbox: ${pathPolicy.reason}` }], details: {} };\n }\n\n const normalized = editsProfileFile\n ? resolveProfileMarkdownPathIfBareName(p.path, options!.profileMarkdownRoot!)\n : resolvePathUnderWorkspace(p.path, workspace);\n const stats = await stat(normalized);\n if (stats.size > MAX_FILE_SIZE) return { content: [{ type: 'text', text: `🚫 File too large` }], details: {} };\n\n const rawContent = await readFile(normalized, 'utf-8');\n const content = stripBom(rawContent);\n const lineEnding = detectLineEnding(rawContent);\n\n const normalizedContent = normalizeToLF(content);\n const normalizedOldText = normalizeToLF(p.oldText);\n const normalizedNewText = normalizeToLF(p.newText);\n\n const matchResult = fuzzyFindText(normalizedContent, normalizedOldText);\n if (!matchResult.found) return { content: [{ type: 'text', text: `Error: oldText not found` }], details: {} };\n\n const fuzzyContent = normalizeForFuzzyMatch(normalizedContent);\n const fuzzyOldText = normalizeForFuzzyMatch(normalizedOldText);\n const occurrences = fuzzyContent.split(fuzzyOldText).length - 1;\n if (occurrences > 1)\n return { content: [{ type: 'text', text: `Error: ${occurrences} occurrences found, text must be unique` }], details: {} };\n\n const baseContent = matchResult.contentForReplacement;\n const newContent =\n baseContent.substring(0, matchResult.index) +\n normalizedNewText +\n baseContent.substring(matchResult.index + matchResult.matchLength);\n const finalContent = restoreLineEndings(newContent, lineEnding);\n const originalWithReplacement = restoreLineEndings(baseContent, lineEnding);\n\n if (originalWithReplacement === finalContent)\n return { content: [{ type: 'text', text: `Error: No changes` }], details: {} };\n\n const diffResult = generateDiffString(originalWithReplacement, finalContent, normalized);\n await writeFile(normalized, finalContent, 'utf-8');\n\n return {\n content: [{ type: 'text', text: `File edited: ${normalized}` }],\n details: { diff: diffResult, fuzzyMatchUsed: matchResult.usedFuzzyMatch },\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],\n details: {},\n };\n }\n },\n } as any;\n}\n\nexport const editFileTool: AgentTool = createEditFileTool(process.cwd());\n\nfunction detectLineEnding(content: string): '\\r\\n' | '\\n' {\n const crlfIdx = content.indexOf('\\r\\n');\n const lfIdx = content.indexOf('\\n');\n if (lfIdx === -1) return '\\n';\n if (crlfIdx === -1) return '\\n';\n return crlfIdx < lfIdx ? '\\r\\n' : '\\n';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"edit.js","names":[],"sources":["../../../../src/agent/tools/edit.ts"],"sourcesContent":["// Edit file tool\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { readFile, writeFile, stat } from 'fs/promises';\nimport { checkFileSafety } from '../prompt/safety.js';\nimport {\n isBareProfileMarkdownFileName,\n resolveProfileMarkdownPathIfBareName,\n resolvePathUnderWorkspace,\n} from './tool-paths.js';\nimport { evaluateFilePolicy } from '../sandbox/exec-policy.js';\nimport { normalizeToLF, restoreLineEndings, normalizeForFuzzyMatch, fuzzyFindText, stripBom, generateDiffString } from './edit-diff.js';\nimport type { GoalEvidenceRecordInput } from './goal-evidence-recorder.js';\n\nconst MAX_FILE_SIZE = 10 * 1024 * 1024;\n\nconst EditFileSchema = Type.Object({\n path: Type.String({ description: 'File path to edit' }),\n oldText: Type.String({ description: 'Text to replace' }),\n newText: Type.String({ description: 'Replacement text' }),\n});\n\nexport interface EditToolDetails {\n diff?: string;\n firstChangedLine?: number;\n fuzzyMatchUsed?: boolean;\n}\n\ntype EditFileParams = { path: string; oldText: string; newText: string };\n\nexport interface CreateEditFileToolOptions {\n /** When set and the path is a bare profile filename (e.g. SOUL.md), edit under this root. */\n profileMarkdownRoot?: string;\n recordGoalEvidence?: (input: GoalEvidenceRecordInput) => Promise<void> | void;\n}\n\nexport function createEditFileTool(\n workspace: string,\n options?: CreateEditFileToolOptions,\n): AgentTool {\n return {\n name: 'edit_file',\n description:\n 'Edit file by replacing text. Relative paths are under the current agent workspace; profile Markdown (SOUL.md, etc.) is edited automatically when given by filename.',\n parameters: EditFileSchema,\n label: '✏️ Edit',\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<EditToolDetails>> {\n try {\n const p = params as EditFileParams;\n const safety = checkFileSafety('write', p.path);\n if (!safety.allowed) return { content: [{ type: 'text', text: `🚫 ${safety.message}` }], details: {} };\n\n const editsProfileFile = Boolean(\n options?.profileMarkdownRoot && isBareProfileMarkdownFileName(p.path),\n );\n const workspaceRoot = editsProfileFile ? options!.profileMarkdownRoot! : workspace;\n\n // Sandbox path-policy check (blocked dirs, symlink escape, config protection)\n const pathPolicy = evaluateFilePolicy({\n operation: 'edit',\n path: p.path,\n workspaceRoot,\n });\n if (!pathPolicy.allowed) {\n return { content: [{ type: 'text', text: `🚫 Sandbox: ${pathPolicy.reason}` }], details: {} };\n }\n\n const normalized = editsProfileFile\n ? resolveProfileMarkdownPathIfBareName(p.path, options!.profileMarkdownRoot!)\n : resolvePathUnderWorkspace(p.path, workspace);\n const stats = await stat(normalized);\n if (stats.size > MAX_FILE_SIZE) return { content: [{ type: 'text', text: `🚫 File too large` }], details: {} };\n\n const rawContent = await readFile(normalized, 'utf-8');\n const content = stripBom(rawContent);\n const lineEnding = detectLineEnding(rawContent);\n\n const normalizedContent = normalizeToLF(content);\n const normalizedOldText = normalizeToLF(p.oldText);\n const normalizedNewText = normalizeToLF(p.newText);\n\n const matchResult = fuzzyFindText(normalizedContent, normalizedOldText);\n if (!matchResult.found) return { content: [{ type: 'text', text: `Error: oldText not found` }], details: {} };\n\n const fuzzyContent = normalizeForFuzzyMatch(normalizedContent);\n const fuzzyOldText = normalizeForFuzzyMatch(normalizedOldText);\n const occurrences = fuzzyContent.split(fuzzyOldText).length - 1;\n if (occurrences > 1)\n return { content: [{ type: 'text', text: `Error: ${occurrences} occurrences found, text must be unique` }], details: {} };\n\n const baseContent = matchResult.contentForReplacement;\n const newContent =\n baseContent.substring(0, matchResult.index) +\n normalizedNewText +\n baseContent.substring(matchResult.index + matchResult.matchLength);\n const finalContent = restoreLineEndings(newContent, lineEnding);\n const originalWithReplacement = restoreLineEndings(baseContent, lineEnding);\n\n if (originalWithReplacement === finalContent)\n return { content: [{ type: 'text', text: `Error: No changes` }], details: {} };\n\n const diffResult = generateDiffString(originalWithReplacement, finalContent, normalized);\n await writeFile(normalized, finalContent, 'utf-8');\n await options?.recordGoalEvidence?.({\n kind: 'diff',\n title: `File edited: ${normalized}`,\n summary: diffResult.slice(0, 4000),\n uri: normalized,\n data: {\n path: normalized,\n fuzzyMatchUsed: matchResult.usedFuzzyMatch,\n },\n });\n\n return {\n content: [{ type: 'text', text: `File edited: ${normalized}` }],\n details: { diff: diffResult, fuzzyMatchUsed: matchResult.usedFuzzyMatch },\n };\n } catch (error) {\n return {\n content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],\n details: {},\n };\n }\n },\n } as any;\n}\n\nexport const editFileTool: AgentTool = createEditFileTool(process.cwd());\n\nfunction detectLineEnding(content: string): '\\r\\n' | '\\n' {\n const crlfIdx = content.indexOf('\\r\\n');\n const lfIdx = content.indexOf('\\n');\n if (lfIdx === -1) return '\\n';\n if (crlfIdx === -1) return '\\n';\n return crlfIdx < lfIdx ? '\\r\\n' : '\\n';\n}\n"],"mappings":"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"}