@xopcai/xopc 0.0.111 → 0.0.113

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 (443) hide show
  1. package/dist/browser-ext/icons/icon-128.png +0 -0
  2. package/dist/browser-ext/icons/icon-16.png +0 -0
  3. package/dist/browser-ext/icons/icon-32.png +0 -0
  4. package/dist/browser-ext/icons/icon-48.png +0 -0
  5. package/dist/browser-ext/manifest.json +1 -1
  6. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  7. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  8. package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
  9. package/dist/extensions/telegram/src/inbound-processor.js +1 -1
  10. package/dist/extensions/telegram/src/plugin.js +1 -1
  11. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  12. package/dist/extensions/telegram/src/update-offset-store.js +1 -1
  13. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  14. package/dist/extensions/telegram/xopc.extension.json +1 -1
  15. package/dist/extensions/weixin/src/api/api.js +2 -2
  16. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  17. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  18. package/dist/extensions/weixin/src/delivery-to.d.ts +3 -3
  19. package/dist/extensions/weixin/src/delivery-to.js.map +1 -1
  20. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  21. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  22. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  23. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  24. package/dist/extensions/weixin/src/plugin.js +1 -1
  25. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  26. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  27. package/dist/gateway/static/root/apple-touch-icon.png +0 -0
  28. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-zlx9l5Yp.js → agent-avatar-dicebear-CBlklyNr.js} +1 -1
  29. package/dist/gateway/static/root/assets/agent-browser-settings-page-rGbKc2Hh.js +6 -0
  30. package/dist/gateway/static/root/assets/{agent-defaults-tabbed-page-Bz7JWjRM.js → agent-defaults-tabbed-page-CtwVbjOA.js} +1 -1
  31. package/dist/gateway/static/root/assets/agents-CCBmGcwc.js +71 -0
  32. package/dist/gateway/static/root/assets/{app-management-settings-panel-DaQwdeCq.js → app-management-settings-panel-28E_WfMe.js} +1 -1
  33. package/dist/gateway/static/root/assets/{appearance-settings-D2zv6r3P.js → appearance-settings-Do1z0XgJ.js} +1 -1
  34. package/dist/gateway/static/root/assets/{apps-page-BIppe_jj.js → apps-page-xwCsJS15.js} +1 -1
  35. package/dist/gateway/static/root/assets/{archive-plugin-DEmu8eH7.js → archive-plugin-BAFlsov_.js} +1 -1
  36. package/dist/gateway/static/root/assets/{attachment-load-B98lJoN5.js → attachment-load-V3qGPC3x.js} +1 -1
  37. package/dist/gateway/static/root/assets/{binary-plugins-CL9QKmyo.js → binary-plugins-DT8NvA6W.js} +1 -1
  38. package/dist/gateway/static/root/assets/{block-editor-BOAhMAhT.js → block-editor-CdLMEcHd.js} +1 -1
  39. package/dist/gateway/static/root/assets/{channels-settings-Br8iRnXp.js → channels-settings-C044DcYk.js} +1 -1
  40. package/dist/gateway/static/root/assets/{config-api-0o1WYdz2.js → config-api-Bf5mjpu7.js} +1 -1
  41. package/dist/gateway/static/root/assets/config-reload-event-Bjh2zoKp.js +1 -0
  42. package/dist/gateway/static/root/assets/connectors-settings-8VEWUOTj.js +2 -0
  43. package/dist/gateway/static/root/assets/cron-api--pAB_rps.js +1 -0
  44. package/dist/gateway/static/root/assets/cron-page-DqmNGNOy.js +3 -0
  45. package/dist/gateway/static/root/assets/dreaming-settings-6UZE1FSK.js +1 -0
  46. package/dist/gateway/static/root/assets/{extension-debug-page-Cjx6pZVz.js → extension-debug-page-BGhE7msg.js} +1 -1
  47. package/dist/gateway/static/root/assets/{extension-page-BSPNL90V.js → extension-page-CvpI45WG.js} +1 -1
  48. package/dist/gateway/static/root/assets/extension-settings-page-DAmR5FUe.js +1 -0
  49. package/dist/gateway/static/root/assets/{fetch-Bs7in_4F.js → fetch-NZmjSXLl.js} +1 -1
  50. package/dist/gateway/static/root/assets/format-cron-label-BsotZDO5.js +2 -0
  51. package/dist/gateway/static/root/assets/{format-interval-label-CftJ5uXu.js → format-interval-label-qhth3BMV.js} +1 -1
  52. package/dist/gateway/static/root/assets/{gateway-config-api-Clfck-hW.js → gateway-config-api-CaXBt-9R.js} +1 -1
  53. package/dist/gateway/static/root/assets/gateway-settings-DphpbLBc.js +1 -0
  54. package/dist/gateway/static/root/assets/{gateway-startup-retry-BkjVJc38.js → gateway-startup-retry-Be1omjh3.js} +1 -1
  55. package/dist/gateway/static/root/assets/{goal-detail-page-kqJue0sE.js → goal-detail-page-bv0VRDaf.js} +1 -1
  56. package/dist/gateway/static/root/assets/goals-page-1Ywnt4Cb.js +2 -0
  57. package/dist/gateway/static/root/assets/{goals-settings-CJnzNSDo.js → goals-settings-ceEBjnfc.js} +1 -1
  58. package/dist/gateway/static/root/assets/{heartbeat-config-api-Cp7CPuIn.js → heartbeat-config-api-BzO6G4fD.js} +1 -1
  59. package/dist/gateway/static/root/assets/{heartbeat-settings-ifSI1Wbh.js → heartbeat-settings-DCST9-du.js} +1 -1
  60. package/dist/gateway/static/root/assets/index-Cxm6xsps.js +122 -0
  61. package/dist/gateway/static/root/assets/index-b_R4tKqt.css +1 -0
  62. package/dist/gateway/static/root/assets/interval-presets-DJmshV8n.js +1 -0
  63. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings--MI1rYl7.js → keyboard-shortcuts-settings-9AUUlQ5Q.js} +1 -1
  64. package/dist/gateway/static/root/assets/{logs-page-BwrVNlyW.js → logs-page-B_wrxhee.js} +1 -1
  65. package/dist/gateway/static/root/assets/{markdown-split-B_oc9lJe.js → markdown-split-CYYELqAr.js} +1 -1
  66. package/dist/gateway/static/root/assets/{media-plugins-DLPvB5H3.js → media-plugins-BEcMR2M8.js} +1 -1
  67. package/dist/gateway/static/root/assets/messages-CkT-lcgP.js +3 -0
  68. package/dist/gateway/static/root/assets/models-hub-panel-D0JDSbNu.js +2 -0
  69. package/dist/gateway/static/root/assets/note-detail-page-DpFV-EO6.js +2 -0
  70. package/dist/gateway/static/root/assets/{note-image-lightbox-rSqAgOi9.js → note-image-lightbox-DNAoPcmm.js} +1 -1
  71. package/dist/gateway/static/root/assets/{notes-page-C9ACGEty.js → notes-page-CdkjTch8.js} +1 -1
  72. package/dist/gateway/static/root/assets/{preview-open-alternatives-Bw_N2oZi.js → preview-open-alternatives-BPLz0AIv.js} +1 -1
  73. package/dist/gateway/static/root/assets/{remote-access-hub-BhcWIKuM.js → remote-access-hub-DSYVAi96.js} +1 -1
  74. package/dist/gateway/static/root/assets/{save-bar-controls-CNP2jmw0.js → save-bar-controls-CrWwWRVK.js} +1 -1
  75. package/dist/gateway/static/root/assets/schedule-field-CF2sadvN.js +1 -0
  76. package/dist/gateway/static/root/assets/{schema-form-CDPzua9q.js → schema-form-Di5cKjYE.js} +1 -1
  77. package/dist/gateway/static/root/assets/{sessions-page-DzkpSDZr.js → sessions-page-CenkcVjF.js} +1 -1
  78. package/dist/gateway/static/root/assets/settings-advanced-gate-D9sva86V.js +1 -0
  79. package/dist/gateway/static/root/assets/{settings-collapsible-section-C9bff85B.js → settings-collapsible-section-Chh282jW.js} +1 -1
  80. package/dist/gateway/static/root/assets/settings-form-section-Dq-83cQd.js +1 -0
  81. package/dist/gateway/static/root/assets/{settings-page-DWK4Zo7s.js → settings-page-DL35U0x0.js} +1 -1
  82. package/dist/gateway/static/root/assets/setup-status-panel-Ctwbp9Er.js +1 -0
  83. package/dist/gateway/static/root/assets/{share-preview-page-DnutoY_S.js → share-preview-page-0FXYnSUA.js} +1 -1
  84. package/dist/gateway/static/root/assets/{shares-settings-6oRgJMpn.js → shares-settings-DIM3JNsr.js} +1 -1
  85. package/dist/gateway/static/root/assets/skill-reload-api-DAlNaNzL.js +1 -0
  86. package/dist/gateway/static/root/assets/skills-page-CLrHVzAt.js +2 -0
  87. package/dist/gateway/static/root/assets/{system-settings-panel-qP1JDtDd.js → system-settings-panel-W1pTcojB.js} +1 -1
  88. package/dist/gateway/static/root/assets/use-agent-defaults-form-BVRvkK7m.js +1 -0
  89. package/dist/gateway/static/root/assets/{use-channel-catalog-C4mg1hjD.js → use-channel-catalog-CgJibfMM.js} +1 -1
  90. package/dist/gateway/static/root/assets/{use-settings-tab-guard-F6C0mpJt.js → use-settings-tab-guard-Bw_qkRQE.js} +1 -1
  91. package/dist/gateway/static/root/assets/{voice-api-key-field-BnDDb6qO.js → voice-api-key-field-vYAO71Gn.js} +1 -1
  92. package/dist/gateway/static/root/assets/{voice-player-store-B2EwIhtY.js → voice-player-store-C7lziaAx.js} +1 -1
  93. package/dist/gateway/static/root/assets/{workflow-page.utils-CRB7WX9l.js → workflow-page.utils-sgHjOXOm.js} +1 -1
  94. package/dist/gateway/static/root/assets/{workflows-page-2Fptr0je.js → workflows-page-DYyOTmFx.js} +1 -1
  95. package/dist/gateway/static/root/favicon-16x16.png +0 -0
  96. package/dist/gateway/static/root/favicon-32x32.png +0 -0
  97. package/dist/gateway/static/root/favicon-icon.svg +1 -0
  98. package/dist/gateway/static/root/favicon.ico +0 -0
  99. package/dist/gateway/static/root/favicon.png +0 -0
  100. package/dist/gateway/static/root/favicon.svg +24 -15
  101. package/dist/gateway/static/root/index.html +11 -10
  102. package/dist/gateway/static/root/logo-dark.svg +23 -15
  103. package/dist/gateway/static/root/logo.svg +23 -16
  104. package/dist/package.js +1 -1
  105. package/dist/src/agent/agent-manager.d.ts +28 -2
  106. package/dist/src/agent/agent-manager.js +82 -11
  107. package/dist/src/agent/agent-manager.js.map +1 -1
  108. package/dist/src/agent/agent-scope.js +1 -1
  109. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  110. package/dist/src/agent/context/workspace-seed.js +2 -2
  111. package/dist/src/agent/context/workspace-state.js +1 -1
  112. package/dist/src/agent/context/workspace.js +1 -1
  113. package/dist/src/agent/goals/goal-locale.js +2 -2
  114. package/dist/src/agent/goals/persistent-goal-service.js +1 -1
  115. package/dist/src/agent/goals/post-turn.js +3 -3
  116. package/dist/src/agent/image/load-image-media.js +2 -2
  117. package/dist/src/agent/ipc/inbox.js +3 -3
  118. package/dist/src/agent/ipc/socket.js +1 -1
  119. package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
  120. package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
  121. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  122. package/dist/src/agent/mcp/mcp-transport.js +1 -1
  123. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  124. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  125. package/dist/src/agent/memory/dreaming/events.js +1 -1
  126. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  127. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  128. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  129. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  130. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  131. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  132. package/dist/src/agent/memory/memory-flush.js +1 -1
  133. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  134. package/dist/src/agent/messaging/command-handler.d.ts +3 -0
  135. package/dist/src/agent/messaging/command-handler.js +5 -0
  136. package/dist/src/agent/messaging/command-handler.js.map +1 -1
  137. package/dist/src/agent/models/manager.js +1 -1
  138. package/dist/src/agent/prompt/memory/index.js +1 -1
  139. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  140. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  141. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  142. package/dist/src/agent/sandbox/path-policy.js +2 -2
  143. package/dist/src/agent/service/process-direct-streaming.js +9 -4
  144. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  145. package/dist/src/agent/service/reconcile-dreaming-cron.js +8 -5
  146. package/dist/src/agent/service/reconcile-dreaming-cron.js.map +1 -1
  147. package/dist/src/agent/service.d.ts +2 -1
  148. package/dist/src/agent/service.js +10 -5
  149. package/dist/src/agent/service.js.map +1 -1
  150. package/dist/src/agent/service.types.d.ts +4 -0
  151. package/dist/src/agent/session/session-config-service.d.ts +8 -0
  152. package/dist/src/agent/session/session-config-service.js +20 -0
  153. package/dist/src/agent/session/session-config-service.js.map +1 -1
  154. package/dist/src/agent/session/session-inspector.js +1 -1
  155. package/dist/src/agent/skills/config.js +2 -2
  156. package/dist/src/agent/skills/filesystem-watcher.d.ts +19 -0
  157. package/dist/src/agent/skills/filesystem-watcher.js +182 -0
  158. package/dist/src/agent/skills/filesystem-watcher.js.map +1 -0
  159. package/dist/src/agent/skills/hub-hash.js +2 -2
  160. package/dist/src/agent/skills/hub-lock.js +1 -1
  161. package/dist/src/agent/skills/hub-pull.js +30 -36
  162. package/dist/src/agent/skills/hub-pull.js.map +1 -1
  163. package/dist/src/agent/skills/index.js +82 -38
  164. package/dist/src/agent/skills/index.js.map +1 -1
  165. package/dist/src/agent/skills/installer.js +2 -2
  166. package/dist/src/agent/skills/managed-store.d.ts +19 -0
  167. package/dist/src/agent/skills/managed-store.js +97 -38
  168. package/dist/src/agent/skills/managed-store.js.map +1 -1
  169. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  170. package/dist/src/agent/skills/skill-manager.d.ts +16 -6
  171. package/dist/src/agent/skills/skill-manager.js +79 -24
  172. package/dist/src/agent/skills/skill-manager.js.map +1 -1
  173. package/dist/src/agent/skills/skill-view-path.js +1 -1
  174. package/dist/src/agent/skills/test-framework.js +1 -1
  175. package/dist/src/agent/skills/types.d.ts +11 -0
  176. package/dist/src/agent/skills/watcher.js +1 -1
  177. package/dist/src/agent/starter-agents.js +1 -1
  178. package/dist/src/agent/tools/cronjob-tool.d.ts +6 -3
  179. package/dist/src/agent/tools/cronjob-tool.js +58 -23
  180. package/dist/src/agent/tools/cronjob-tool.js.map +1 -1
  181. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  182. package/dist/src/agent/tools/factory.js +1 -1
  183. package/dist/src/agent/tools/find.js +1 -1
  184. package/dist/src/agent/tools/grep.js +1 -1
  185. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  186. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  187. package/dist/src/agent/tools/workflow-tool.js +1 -1
  188. package/dist/src/agent/workflow/catalog.js +1 -1
  189. package/dist/src/agent/workspace-runtime/registry.d.ts +5 -0
  190. package/dist/src/agent/workspace-runtime/registry.js +7 -0
  191. package/dist/src/agent/workspace-runtime/registry.js.map +1 -1
  192. package/dist/src/ai-assist/text-assist.d.ts +42 -0
  193. package/dist/src/ai-assist/text-assist.js +252 -0
  194. package/dist/src/ai-assist/text-assist.js.map +1 -0
  195. package/dist/src/auth/credentials.js +2 -2
  196. package/dist/src/auth/profiles/store.js +2 -2
  197. package/dist/src/auth/sync-provider-auth.js +1 -1
  198. package/dist/src/browser/cache-dir-policy.js +1 -1
  199. package/dist/src/browser/cdp-local-launcher.js +2 -2
  200. package/dist/src/browser/providers/browser-ext-install.js +4 -4
  201. package/dist/src/browser/providers/cloakbrowser.js +5 -5
  202. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  203. package/dist/src/browser/stealth.js +1 -1
  204. package/dist/src/channels/outbound/persist-store.js +1 -1
  205. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  206. package/dist/src/channels/pairing/pairing-store.js +2 -2
  207. package/dist/src/channels/plugins/types.adapters.d.ts +2 -2
  208. package/dist/src/chat-commands/agent-edit.js +2 -2
  209. package/dist/src/chat-commands/builtins/config.js +3 -3
  210. package/dist/src/chat-commands/builtins/system.js +11 -4
  211. package/dist/src/chat-commands/builtins/system.js.map +1 -1
  212. package/dist/src/chat-commands/context.d.ts +3 -0
  213. package/dist/src/chat-commands/context.js +7 -0
  214. package/dist/src/chat-commands/context.js.map +1 -1
  215. package/dist/src/chat-commands/types.d.ts +2 -0
  216. package/dist/src/cli/commands/config.js +1 -1
  217. package/dist/src/cli/commands/cron.js +55 -16
  218. package/dist/src/cli/commands/cron.js.map +1 -1
  219. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  220. package/dist/src/cli/commands/doctor/checks/cron-health.js +2 -83
  221. package/dist/src/cli/commands/doctor/checks/cron-health.js.map +1 -1
  222. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  223. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  224. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  225. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  226. package/dist/src/cli/commands/extension-create.js +1 -1
  227. package/dist/src/cli/commands/extension-dev.js +2 -2
  228. package/dist/src/cli/commands/extension-marketplace.js +2 -2
  229. package/dist/src/cli/commands/extension-pack.js +2 -2
  230. package/dist/src/cli/commands/extension.js +3 -3
  231. package/dist/src/cli/commands/gateway/logs.js +1 -1
  232. package/dist/src/cli/commands/image.js +1 -1
  233. package/dist/src/cli/commands/init.js +2 -2
  234. package/dist/src/cli/commands/models.js +1 -1
  235. package/dist/src/cli/commands/skills-test.js +1 -1
  236. package/dist/src/cli/templates.js +1 -1
  237. package/dist/src/cli/utils/gateway-client.js +1 -1
  238. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  239. package/dist/src/config/agent-profile.js +1 -1
  240. package/dist/src/config/agent-typed-models.js +1 -1
  241. package/dist/src/config/gateway-bind.js +1 -1
  242. package/dist/src/config/index.js +7 -7
  243. package/dist/src/config/loader.js +4 -4
  244. package/dist/src/config/models-json.js +2 -2
  245. package/dist/src/config/paths-state.js +1 -1
  246. package/dist/src/config/paths.js +1 -1
  247. package/dist/src/config/profile.js +1 -1
  248. package/dist/src/config/reload.js +1 -1
  249. package/dist/src/config/schema.d.ts +0 -2
  250. package/dist/src/config/schema.js +0 -3
  251. package/dist/src/config/schema.js.map +1 -1
  252. package/dist/src/config/web-patch.d.ts +0 -1
  253. package/dist/src/config/web-patch.js +0 -2
  254. package/dist/src/config/web-patch.js.map +1 -1
  255. package/dist/src/config/workspace-path.js +1 -1
  256. package/dist/src/cron/executor.js +102 -71
  257. package/dist/src/cron/executor.js.map +1 -1
  258. package/dist/src/cron/index.d.ts +1 -1
  259. package/dist/src/cron/index.js +3 -3
  260. package/dist/src/cron/run-log-store.d.ts +1 -0
  261. package/dist/src/cron/run-log-store.js +4 -2
  262. package/dist/src/cron/run-log-store.js.map +1 -1
  263. package/dist/src/cron/schedule.d.ts +10 -0
  264. package/dist/src/cron/schedule.js +85 -0
  265. package/dist/src/cron/schedule.js.map +1 -0
  266. package/dist/src/cron/service.d.ts +34 -77
  267. package/dist/src/cron/service.js +327 -264
  268. package/dist/src/cron/service.js.map +1 -1
  269. package/dist/src/cron/types.d.ts +80 -50
  270. package/dist/src/cron/validation.d.ts +358 -90
  271. package/dist/src/cron/validation.js +152 -132
  272. package/dist/src/cron/validation.js.map +1 -1
  273. package/dist/src/cron/workflow-run-completion.js +1 -1
  274. package/dist/src/daemon/constants.js +1 -1
  275. package/dist/src/daemon/install-plan.js +2 -2
  276. package/dist/src/daemon/launchd.js +2 -2
  277. package/dist/src/daemon/schtasks.js +2 -2
  278. package/dist/src/daemon/systemd.js +2 -2
  279. package/dist/src/extensions/bundle-mcp.js +1 -1
  280. package/dist/src/extensions/discover-extensions.js +2 -2
  281. package/dist/src/extensions/health.js +1 -1
  282. package/dist/src/extensions/install.js +2 -2
  283. package/dist/src/extensions/loader.js +2 -2
  284. package/dist/src/extensions/lockfile.js +3 -3
  285. package/dist/src/extensions/security.js +1 -1
  286. package/dist/src/extensions/update.js +2 -2
  287. package/dist/src/gateway/agents-admin.js +2 -2
  288. package/dist/src/gateway/chat-stream/mapper.d.ts +1 -0
  289. package/dist/src/gateway/chat-stream/mapper.js +6 -2
  290. package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
  291. package/dist/src/gateway/chat-stream/protocol.d.ts +2 -0
  292. package/dist/src/gateway/file-path-classifier.js +2 -2
  293. package/dist/src/gateway/hono/lib/config-payload.d.ts +0 -1
  294. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  295. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  296. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  297. package/dist/src/gateway/hono/oauth-async.js +1 -1
  298. package/dist/src/gateway/hono/routes/agents.js +1 -1
  299. package/dist/src/gateway/hono/routes/ai-assist.d.ts +3 -0
  300. package/dist/src/gateway/hono/routes/ai-assist.js +66 -0
  301. package/dist/src/gateway/hono/routes/ai-assist.js.map +1 -0
  302. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  303. package/dist/src/gateway/hono/routes/commands-skills.js +7 -0
  304. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  305. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  306. package/dist/src/gateway/hono/routes/cron.js +24 -5
  307. package/dist/src/gateway/hono/routes/cron.js.map +1 -1
  308. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  309. package/dist/src/gateway/hono/routes/home.js +5 -3
  310. package/dist/src/gateway/hono/routes/home.js.map +1 -1
  311. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  312. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  313. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  314. package/dist/src/gateway/hono/routes/models.js +1 -1
  315. package/dist/src/gateway/hono/routes/shares.js +1 -1
  316. package/dist/src/gateway/hono/routes/workflows.js +2 -2
  317. package/dist/src/gateway/hono/routes/workspace.js +2 -2
  318. package/dist/src/gateway/lock.js +3 -3
  319. package/dist/src/gateway/ports.js +1 -1
  320. package/dist/src/gateway/service/agent-runner.js +2 -2
  321. package/dist/src/gateway/service/config-coordinator.js +1 -1
  322. package/dist/src/gateway/service/marketplace-service.d.ts +22 -10
  323. package/dist/src/gateway/service/marketplace-service.js +46 -5
  324. package/dist/src/gateway/service/marketplace-service.js.map +1 -1
  325. package/dist/src/gateway/service.js +11 -5
  326. package/dist/src/gateway/service.js.map +1 -1
  327. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  328. package/dist/src/goals/goal-notifications.js +1 -1
  329. package/dist/src/goals/goal-workflow-judge.js +3 -3
  330. package/dist/src/i18n/goals-bundle.js +1 -1
  331. package/dist/src/i18n/index.js +1 -1
  332. package/dist/src/i18n/share-tool-bundle.js +2 -2
  333. package/dist/src/infra/brew.js +1 -1
  334. package/dist/src/infra/package-json.js +1 -1
  335. package/dist/src/infra/package-update-steps.js +1 -1
  336. package/dist/src/infra/path-env.js +2 -2
  337. package/dist/src/infra/restart.js +1 -1
  338. package/dist/src/infra/stable-node-path.js +1 -1
  339. package/dist/src/infra/update-check.js +1 -1
  340. package/dist/src/infra/update-global.js +1 -1
  341. package/dist/src/infra/update-lock.js +2 -2
  342. package/dist/src/infra/update-restart.js +1 -1
  343. package/dist/src/infra/update-runner.js +1 -1
  344. package/dist/src/infra/update-startup.js +1 -1
  345. package/dist/src/infra/write-file-atomic.js +2 -2
  346. package/dist/src/media/store.js +1 -1
  347. package/dist/src/notes/agent-context.js +1 -1
  348. package/dist/src/notes/service.js +1 -1
  349. package/dist/src/notes/store.js +2 -2
  350. package/dist/src/project-trust/trust-store.js +2 -2
  351. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  352. package/dist/src/providers/index.js +1 -1
  353. package/dist/src/providers/model-registry.js +4 -4
  354. package/dist/src/session/init-session-turn.js +2 -2
  355. package/dist/src/session/resolve-session.js +3 -3
  356. package/dist/src/session/session-title.js +2 -2
  357. package/dist/src/session/store-reader.d.ts +5 -0
  358. package/dist/src/session/store-reader.js +1 -0
  359. package/dist/src/session/store.js +1 -1
  360. package/dist/src/share/share-auto.js +2 -2
  361. package/dist/src/share/share-store.js +3 -3
  362. package/dist/src/share/share-thumbnail.js +2 -2
  363. package/dist/src/share/share-zip.js +1 -1
  364. package/dist/src/share/site-share-store.js +3 -3
  365. package/dist/src/share/site-static-serve.js +1 -1
  366. package/dist/src/storage/sqlite/connection.js +1 -1
  367. package/dist/src/storage/sqlite/cron-job-repository.d.ts +6 -0
  368. package/dist/src/storage/sqlite/cron-job-repository.js +70 -0
  369. package/dist/src/storage/sqlite/cron-job-repository.js.map +1 -0
  370. package/dist/src/storage/sqlite/cron-run-repository.js +0 -1
  371. package/dist/src/storage/sqlite/cron-run-repository.js.map +1 -1
  372. package/dist/src/storage/sqlite/index.d.ts +1 -0
  373. package/dist/src/storage/sqlite/index.js +2 -1
  374. package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
  375. package/dist/src/storage/sqlite/migrations/009_cron_jobs.sql +24 -0
  376. package/dist/src/storage/sqlite/migrations/discover.js +1 -1
  377. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  378. package/dist/src/storage/sqlite/migrations/runner.js +4 -4
  379. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  380. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  381. package/dist/src/storage/sqlite/schema.js +2 -2
  382. package/dist/src/storage/sqlite/schema.sql +25 -0
  383. package/dist/src/tui/clipboard-image.js +3 -3
  384. package/dist/src/tui/extension-host/load-extensions.js +1 -1
  385. package/dist/src/tui/theme-manager.js +1 -1
  386. package/dist/src/tui/tui-command-formatters.js +4 -4
  387. package/dist/src/tui/tui-commands.js +2 -2
  388. package/dist/src/tui/tui-keybindings-file.js +1 -1
  389. package/dist/src/tui/tui-scoped-models.js +2 -2
  390. package/dist/src/tui/tui-settings.js +1 -1
  391. package/dist/src/tui/tui-startup-resources.js +1 -1
  392. package/dist/src/tui/tui.js +6 -6
  393. package/dist/src/tunnel/frpc-binary.js +4 -4
  394. package/dist/src/tunnel/frpc-config.js +1 -1
  395. package/dist/src/tunnel/frpc-extract.js +1 -1
  396. package/dist/src/tunnel/tunnel-state.js +1 -1
  397. package/dist/src/utils/logger/audit.js +1 -1
  398. package/dist/src/utils/logger/log-store.js +1 -1
  399. package/dist/src/utils/logger/rotation.js +1 -1
  400. package/dist/src/utils/logger/streams.js +1 -1
  401. package/dist/src/voice/tts/audio.js +1 -1
  402. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  403. package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
  404. package/dist/src/workflows/engine/projector.js +23 -14
  405. package/dist/src/workflows/engine/projector.js.map +1 -1
  406. package/dist/src/workflows/engine/workflow-engine.d.ts +1 -0
  407. package/dist/src/workflows/engine/workflow-engine.js +36 -0
  408. package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
  409. package/dist/src/workflows/index.js +1 -1
  410. package/dist/src/workflows/service/workflow-run-service.js +2 -2
  411. package/dist/src/workflows/service/workflow-session-bridge.js +2 -2
  412. package/dist/src/workflows/store/event-store.js +1 -1
  413. package/dist/src/workflows/store/run-store.js +1 -1
  414. package/package.json +2 -3
  415. package/dist/gateway/static/root/assets/agent-browser-settings-page-B-0zGjt8.js +0 -6
  416. package/dist/gateway/static/root/assets/agents-DwDnJlXT.js +0 -71
  417. package/dist/gateway/static/root/assets/connectors-settings-DDvHo9in.js +0 -2
  418. package/dist/gateway/static/root/assets/cron-api-Dj_UZKST.js +0 -1
  419. package/dist/gateway/static/root/assets/cron-page-Dv7GII9G.js +0 -1
  420. package/dist/gateway/static/root/assets/cron-schedule-picker-DH10KgD6.js +0 -1
  421. package/dist/gateway/static/root/assets/dreaming-settings-L2rgZDQl.js +0 -1
  422. package/dist/gateway/static/root/assets/extension-settings-page-m_UQYkVc.js +0 -1
  423. package/dist/gateway/static/root/assets/gateway-settings-CS177xni.js +0 -1
  424. package/dist/gateway/static/root/assets/goals-page-C0FujUB5.js +0 -2
  425. package/dist/gateway/static/root/assets/index-COkF54xv.js +0 -121
  426. package/dist/gateway/static/root/assets/index-DIaSNGEO.css +0 -1
  427. package/dist/gateway/static/root/assets/interval-presets-B29Ss_2y.js +0 -2
  428. package/dist/gateway/static/root/assets/messages-Csef1aW7.js +0 -3
  429. package/dist/gateway/static/root/assets/models-hub-panel-DHGiTIvf.js +0 -2
  430. package/dist/gateway/static/root/assets/note-detail-page-BM7zlDiT.js +0 -2
  431. package/dist/gateway/static/root/assets/schedule-field-BPAWui3P.js +0 -1
  432. package/dist/gateway/static/root/assets/schedule-summary-B-hdSRdR.js +0 -1
  433. package/dist/gateway/static/root/assets/settings-advanced-gate-BYS-rpzn.js +0 -1
  434. package/dist/gateway/static/root/assets/settings-form-section-BsrK7TBF.js +0 -1
  435. package/dist/gateway/static/root/assets/setup-status-panel-DJiksNu4.js +0 -1
  436. package/dist/gateway/static/root/assets/skill-reload-api-CU9i0nJV.js +0 -1
  437. package/dist/gateway/static/root/assets/skills-page-ERbdWENm.js +0 -2
  438. package/dist/gateway/static/root/assets/use-agent-defaults-form-D3FGVLZb.js +0 -1
  439. package/dist/gateway/static/root/favicon-16.png +0 -0
  440. package/dist/gateway/static/root/favicon-32.png +0 -0
  441. package/dist/src/cron/persistence.d.ts +0 -62
  442. package/dist/src/cron/persistence.js +0 -188
  443. package/dist/src/cron/persistence.js.map +0 -1
@@ -1,356 +1,419 @@
1
+ import { init_agent_scope, normalizeAgentId } from "../agent/agent-scope.js";
1
2
  import { createLogger } from "../utils/logger/index.js";
2
3
  import { init_logger } from "../utils/logger.js";
3
- import { init_paths, resolveCronJobsPath } from "../config/paths.js";
4
+ import { buildSessionKey, init_session_key } from "../routing/session-key.js";
5
+ import { AddJobRequestSchema, JobDataSchema, UpdateJobRequestSchema } from "./validation.js";
6
+ import { deleteCronJob, getCronJob, listCronJobs, saveCronJob, saveCronJobs } from "../storage/sqlite/cron-job-repository.js";
7
+ import "../storage/sqlite/index.js";
8
+ import { computeNextRunAtMs, describeSchedule, timerDelayUntil } from "./schedule.js";
4
9
  import { DefaultJobExecutor } from "./executor.js";
5
- import { AddJobRequestSchema, UpdateJobRequestSchema } from "./validation.js";
6
- import { CronPersistence } from "./persistence.js";
7
10
  import { CronRunLogStore } from "./run-log-store.js";
8
- import nodeCron from "node-cron";
9
- import { CronExpressionParser } from "cron-parser";
10
- import { v4 } from "uuid";
11
+ import { randomUUID } from "node:crypto";
11
12
  //#region src/cron/service.ts
12
- init_paths();
13
13
  init_logger();
14
+ init_agent_scope();
15
+ init_session_key();
14
16
  const log = createLogger("CronService");
17
+ const DEFAULT_MAX_CONCURRENT_JOBS = 5;
18
+ const DEFAULT_MISSED_JOB_STAGGER_MS = 5e3;
19
+ var CronJobAlreadyRunningError = class extends Error {
20
+ jobId;
21
+ runningSessionKey;
22
+ constructor(jobId, runningSessionKey) {
23
+ super(`Job is already running: ${jobId}`);
24
+ this.name = "CronJobAlreadyRunningError";
25
+ this.jobId = jobId;
26
+ this.runningSessionKey = runningSessionKey;
27
+ }
28
+ };
29
+ function nowMs() {
30
+ return Date.now();
31
+ }
32
+ function runStatusFromExecution(status) {
33
+ if (status === "success") return "ok";
34
+ if (status === "cancelled" || status === "skipped") return "skipped";
35
+ return "error";
36
+ }
37
+ async function postFailureWebhook(url, payload) {
38
+ const res = await fetch(url, {
39
+ method: "POST",
40
+ headers: { "content-type": "application/json" },
41
+ body: JSON.stringify(payload)
42
+ });
43
+ if (!res.ok) {
44
+ const text = await res.text().catch(() => "");
45
+ throw new Error(`Cron failure webhook failed: HTTP ${res.status}${text ? ` ${text.slice(0, 200)}` : ""}`);
46
+ }
47
+ }
48
+ function inferJobName(input) {
49
+ if (input.name?.trim()) return input.name.trim();
50
+ if (input.payload.kind === "agentTurn") return input.payload.message.slice(0, 60) || "Agent task";
51
+ if (input.payload.kind === "systemEvent") return input.payload.text.slice(0, 60) || "System event";
52
+ if (input.payload.kind === "workflowRun") return `Workflow ${input.payload.definitionId}`;
53
+ if (input.payload.kind === "goalContinue") return `Goal ${input.payload.goalId}`;
54
+ return describeSchedule(input.schedule);
55
+ }
56
+ function resolveRunningSessionKey(job, deps) {
57
+ if (job.payload.kind !== "agentTurn") return void 0;
58
+ if (job.sessionTarget.startsWith("session:")) return job.sessionTarget.slice(8).trim() || void 0;
59
+ if (job.sessionTarget === "current") return job.sessionKey?.trim() || void 0;
60
+ if (job.sessionTarget !== "isolated") return;
61
+ const aid = job.agentId?.trim();
62
+ const fallbackAgentId = deps.getDefaultCronAgentId?.() ?? "main";
63
+ return buildSessionKey({
64
+ agentId: normalizeAgentId(aid || fallbackAgentId),
65
+ source: "cron",
66
+ accountId: "default",
67
+ peerKind: "dm",
68
+ peerId: `${job.id}-${randomUUID().slice(0, 8)}`
69
+ });
70
+ }
15
71
  var CronService = class {
16
- persistence;
17
- executor;
72
+ executor = new DefaultJobExecutor();
18
73
  runLogStore;
19
- tasks = /* @__PURE__ */ new Map();
20
74
  initialized = false;
21
- agentService = null;
22
- messageBus = null;
75
+ stopped = false;
76
+ running = false;
77
+ timer = null;
78
+ deps = {};
79
+ maxConcurrentJobs;
80
+ missedJobStaggerMs;
23
81
  constructor(config) {
24
- const filePath = config?.filePath || resolveCronJobsPath();
25
- this.persistence = new CronPersistence(filePath);
26
- this.executor = new DefaultJobExecutor();
27
82
  this.runLogStore = new CronRunLogStore(config?.dbPath);
28
83
  this.executor.setRunLogStore(this.runLogStore);
84
+ this.maxConcurrentJobs = Math.max(1, Math.floor(config?.maxConcurrentJobs ?? DEFAULT_MAX_CONCURRENT_JOBS));
85
+ this.missedJobStaggerMs = Math.max(0, Math.floor(config?.missedJobStaggerMs ?? DEFAULT_MISSED_JOB_STAGGER_MS));
29
86
  if (config?.agentService || config?.messageBus) this.setDeps({
30
87
  agentService: config.agentService,
31
88
  messageBus: config.messageBus
32
89
  });
33
90
  }
34
- /**
35
- * Set dependencies for the executor
36
- */
37
91
  setDeps(deps) {
38
- this.agentService = deps.agentService;
39
- this.messageBus = deps.messageBus;
40
- this.executor.setDeps(deps);
92
+ this.deps = {
93
+ ...this.deps,
94
+ ...deps
95
+ };
96
+ this.executor.setDeps(this.deps);
41
97
  log.debug("CronService dependencies set");
42
98
  }
43
- /**
44
- * Initialize the service and load all jobs
45
- */
46
99
  async initialize() {
47
100
  if (this.initialized) return;
48
- await this.persistence.initialize();
49
- await this.loadAllJobs();
101
+ this.stopped = false;
102
+ await this.recomputeAllNextRuns({ catchUp: true });
50
103
  this.initialized = true;
51
- log.debug("CronService initialized");
104
+ this.armTimer();
105
+ log.info("CronService initialized");
52
106
  }
53
- /**
54
- * Add a new job
55
- */
56
- async addJob(schedule, options) {
57
- const validationResult = AddJobRequestSchema.safeParse({
58
- schedule,
59
- ...options
60
- });
61
- if (!validationResult.success) {
62
- const errorMsg = validationResult.error?.errors.map((e) => e.message).join(", ") || "Unknown validation error";
63
- throw new Error(`Validation failed: ${errorMsg}`);
64
- }
65
- const data = validationResult.data;
66
- const id = v4().slice(0, 8);
67
- const now = (/* @__PURE__ */ new Date()).toISOString();
68
- const sessionTarget = data.sessionTarget ?? "main";
69
- const job = {
107
+ async addJob(scheduleOrInput, options) {
108
+ const raw = options ? {
109
+ ...options,
110
+ schedule: scheduleOrInput
111
+ } : scheduleOrInput;
112
+ const parsed = AddJobRequestSchema.parse(raw);
113
+ const ts = nowMs();
114
+ const id = parsed.id?.trim() || randomUUID().slice(0, 12);
115
+ const job = JobDataSchema.parse({
116
+ ...parsed,
70
117
  id,
71
- name: data.name,
72
- schedule: data.schedule,
73
- enabled: true,
74
- timezone: data.timezone,
75
- maxRetries: data.maxRetries ?? 3,
76
- timeout: data.timeout ?? 6e4,
77
- created_at: now,
78
- updated_at: now,
79
- sessionTarget,
80
- ...data.agentId ? { agentId: data.agentId } : {},
81
- ...data.workingDirectory ? { workingDirectory: data.workingDirectory } : {},
82
- payload: data.payload,
83
- delivery: data.delivery,
84
- model: data.model
85
- };
86
- await this.persistence.addJob(job);
87
- this.scheduleJob(job);
118
+ name: inferJobName(parsed),
119
+ enabled: parsed.enabled ?? true,
120
+ deleteAfterRun: parsed.deleteAfterRun ?? parsed.schedule.kind === "at",
121
+ createdAtMs: ts,
122
+ updatedAtMs: ts,
123
+ sessionTarget: parsed.sessionTarget ?? (parsed.payload.kind === "systemEvent" ? "main" : "isolated"),
124
+ wakeMode: parsed.wakeMode ?? "now",
125
+ state: { ...parsed.state ?? {} }
126
+ });
127
+ job.state.nextRunAtMs = computeNextRunAtMs(job, ts);
128
+ saveCronJob(job);
129
+ this.armTimer();
88
130
  log.info({
89
- jobId: id,
90
- name: data.name,
91
- sessionTarget
92
- }, "Job added");
131
+ jobId: job.id,
132
+ name: job.name,
133
+ schedule: job.schedule
134
+ }, "Cron job added");
93
135
  return {
94
- id,
95
- schedule: data.schedule
136
+ id: job.id,
137
+ schedule: job.schedule
96
138
  };
97
139
  }
98
- /**
99
- * List all jobs with next run time
100
- */
101
140
  async listJobs() {
102
- return (await this.persistence.getJobs()).map((job) => {
103
- let nextRun;
104
- if (job.enabled) try {
105
- const options = job.timezone ? { tz: job.timezone } : void 0;
106
- nextRun = CronExpressionParser.parse(job.schedule, options).next().toISOString();
107
- } catch (err) {
108
- log.debug({
109
- jobId: job.id,
110
- err
111
- }, "Failed to parse cron for next run");
112
- }
113
- return {
114
- id: job.id,
115
- name: job.name,
116
- schedule: job.schedule,
117
- enabled: job.enabled,
118
- timezone: job.timezone,
119
- maxRetries: job.maxRetries,
120
- timeout: job.timeout,
121
- sessionTarget: job.sessionTarget,
122
- ...job.agentId ? { agentId: job.agentId } : {},
123
- ...job.workingDirectory ? { workingDirectory: job.workingDirectory } : {},
124
- payload: job.payload,
125
- delivery: job.delivery,
126
- model: job.model,
127
- next_run: nextRun
128
- };
129
- });
141
+ return listCronJobs();
130
142
  }
131
- /**
132
- * Get a single job
133
- */
134
143
  async getJob(id) {
135
- return this.persistence.getJob(id);
144
+ return getCronJob(id);
136
145
  }
137
- /**
138
- * Update a job
139
- */
140
146
  async updateJob(id, updates) {
141
- const validationResult = UpdateJobRequestSchema.safeParse(updates);
142
- if (!validationResult.success) {
143
- const errorMsg = validationResult.error?.errors.map((e) => e.message).join(", ") || "Unknown validation error";
144
- throw new Error(`Validation failed: ${errorMsg}`);
145
- }
146
- const job = await this.persistence.getJob(id);
147
- if (!job) return false;
148
- const { agentId: agentIdPatch, workingDirectory: workingDirectoryPatch, ...rest } = validationResult.data;
149
- const patch = { ...rest };
150
- let clearAgentId = false;
151
- if (agentIdPatch === null) clearAgentId = true;
152
- else if (agentIdPatch !== void 0) patch.agentId = agentIdPatch;
153
- let clearWorkingDirectory = false;
154
- if (workingDirectoryPatch === null) clearWorkingDirectory = true;
155
- else if (workingDirectoryPatch !== void 0) patch.workingDirectory = workingDirectoryPatch;
156
- if (patch.schedule && patch.schedule !== job.schedule) this.cancelTask(id);
157
- await this.persistence.updateJob(id, patch, {
158
- clearAgentId,
159
- clearWorkingDirectory
147
+ const parsed = UpdateJobRequestSchema.parse(updates);
148
+ const current = getCronJob(id);
149
+ if (!current) return false;
150
+ const ts = nowMs();
151
+ const next = JobDataSchema.parse({
152
+ ...current,
153
+ ...parsed,
154
+ id: current.id,
155
+ createdAtMs: current.createdAtMs,
156
+ updatedAtMs: ts,
157
+ state: {
158
+ ...current.state,
159
+ ...parsed.state ?? {}
160
+ }
160
161
  });
161
- const updated = await this.persistence.getJob(id);
162
- if (updated && updated.enabled) this.scheduleJob(updated);
163
- log.info({ jobId: id }, "Job updated");
162
+ if ("schedule" in parsed || "enabled" in parsed) {
163
+ next.state.nextRunAtMs = computeNextRunAtMs(next, ts);
164
+ delete next.state.runningAtMs;
165
+ }
166
+ if ("agentId" in updates && updates.agentId?.trim() === "") delete next.agentId;
167
+ if ("workingDirectory" in updates && updates.workingDirectory?.trim() === "") delete next.workingDirectory;
168
+ saveCronJob(next);
169
+ this.armTimer();
170
+ log.info({ jobId: id }, "Cron job updated");
164
171
  return true;
165
172
  }
166
- /**
167
- * Remove a job
168
- */
169
173
  async removeJob(id) {
170
- this.cancelTask(id);
171
- const removed = await this.persistence.removeJob(id);
174
+ const removed = deleteCronJob(id);
172
175
  if (removed) {
176
+ this.executor.cancelJob(id);
173
177
  await this.runLogStore.deleteJobRuns(id);
174
- log.info({ jobId: id }, "Job removed");
178
+ this.armTimer();
179
+ log.info({ jobId: id }, "Cron job removed");
175
180
  }
176
181
  return removed;
177
182
  }
178
- /**
179
- * Toggle job enabled state
180
- */
181
183
  async toggleJob(id, enabled) {
182
- if (!await this.persistence.getJob(id)) return false;
183
- await this.persistence.updateJob(id, { enabled });
184
- if (enabled) {
185
- const updated = await this.persistence.getJob(id);
186
- if (updated) this.scheduleJob(updated);
187
- } else this.cancelTask(id);
188
- log.info({
189
- jobId: id,
190
- enabled
191
- }, "Job toggled");
192
- return true;
184
+ return this.updateJob(id, { enabled });
193
185
  }
194
- /**
195
- * Execution history for one job: merged in-memory (incl. running) + persisted SQLite rows.
196
- */
197
186
  async getJobHistory(jobId, limit) {
198
- const cap = Math.min(Math.max(limit ?? 10, 1), 500);
199
- const [disk, memory] = await Promise.all([this.runLogStore.readJobHistory(jobId, cap * 2), Promise.resolve(this.executor.getHistory(jobId, cap * 2))]);
200
- const byId = /* @__PURE__ */ new Map();
201
- for (const e of memory) byId.set(e.id, e);
202
- for (const e of disk) if (!byId.has(e.id)) byId.set(e.id, e);
203
- return [...byId.values()].sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime()).slice(0, cap);
187
+ return this.runLogStore.readJobHistory(jobId, Math.min(Math.max(limit ?? 10, 1), 500));
204
188
  }
205
- /**
206
- * Latest runs across all jobs (persisted rows + optional job name).
207
- */
208
189
  async getAllRunsHistory(limit) {
209
190
  const cap = Math.min(Math.max(limit ?? 50, 1), 500);
210
- const jobs = await this.persistence.getJobs();
211
- const jobNames = new Map(jobs.map((j) => [j.id, j.name]));
212
- return this.runLogStore.readAllRuns(cap, jobNames);
191
+ const jobs = listCronJobs();
192
+ const names = new Map(jobs.map((job) => [job.id, job.name]));
193
+ return this.runLogStore.readAllRuns(cap, names);
213
194
  }
214
- /**
215
- * Get service metrics
216
- */
217
195
  async getMetrics() {
218
- const jobs = await this.persistence.getJobs();
219
- const enabled = jobs.filter((j) => j.enabled);
220
- let nextScheduledJob;
221
- for (const job of enabled) try {
222
- const options = job.timezone ? { tz: job.timezone } : void 0;
223
- const next = CronExpressionParser.parse(job.schedule, options).next();
224
- if (!nextScheduledJob || next.getTime() < nextScheduledJob.runAt.getTime()) nextScheduledJob = {
225
- id: job.id,
226
- name: job.name,
227
- runAt: next.toDate()
228
- };
229
- } catch {}
196
+ const jobs = listCronJobs();
197
+ const enabled = jobs.filter((job) => job.enabled);
198
+ const next = enabled.filter((job) => job.state.nextRunAtMs != null).toSorted((a, b) => (a.state.nextRunAtMs ?? 0) - (b.state.nextRunAtMs ?? 0))[0];
230
199
  return {
231
200
  totalJobs: jobs.length,
232
- runningJobs: this.tasks.size,
201
+ runningJobs: jobs.filter((job) => job.state.runningAtMs != null).length,
233
202
  enabledJobs: enabled.length,
234
- failedLastHour: 0,
203
+ failedLastHour: jobs.filter((job) => job.state.lastRunStatus === "error" && (job.state.lastRunAtMs ?? 0) >= nowMs() - 60 * 6e4).length,
235
204
  avgExecutionTime: 0,
236
- nextScheduledJob
205
+ nextScheduledJob: next?.state.nextRunAtMs ? {
206
+ id: next.id,
207
+ name: next.name,
208
+ runAt: new Date(next.state.nextRunAtMs)
209
+ } : void 0
237
210
  };
238
211
  }
239
- /**
240
- * Update config (hot reload)
241
- */
242
- updateConfig(_config) {
243
- log.debug("Cron config updated (jobs managed separately via addJob/removeJob)");
212
+ updateConfig(config) {
213
+ this.maxConcurrentJobs = Math.max(1, Math.floor(config.cron?.maxConcurrentJobs ?? DEFAULT_MAX_CONCURRENT_JOBS));
214
+ this.armTimer();
244
215
  }
245
- /**
246
- * Health check
247
- */
248
216
  async healthCheck() {
249
217
  const issues = [];
250
218
  if (!this.initialized) issues.push("Service not initialized");
251
- const jobs = await this.persistence.getJobs();
252
- for (const job of jobs) if (!nodeCron.validate(job.schedule)) issues.push(`Job ${job.id} has invalid schedule`);
253
- for (const job of jobs) if (job.enabled && job.sessionTarget === "isolated" && !this.agentService) {
254
- issues.push(`Job ${job.id} requires agent service but none configured`);
255
- break;
219
+ for (const job of listCronJobs()) {
220
+ if (!JobDataSchema.safeParse(job).success) issues.push(`Job ${job.id} is invalid`);
221
+ if (job.enabled && job.state.nextRunAtMs == null && job.schedule.kind !== "at") issues.push(`Job ${job.id} has no next run`);
256
222
  }
257
- let status = "healthy";
258
- if (issues.length > 0) status = issues.length > 5 ? "unhealthy" : "degraded";
259
223
  return {
260
- status,
224
+ status: issues.length === 0 ? "healthy" : issues.length > 5 ? "unhealthy" : "degraded",
261
225
  issues
262
226
  };
263
227
  }
264
- /**
265
- * Run a job immediately (manual trigger)
266
- */
267
228
  async runJobNow(id) {
268
- const job = await this.persistence.getJob(id);
229
+ const job = getCronJob(id);
269
230
  if (!job) throw new Error(`Job not found: ${id}`);
270
- if (!job.enabled) throw new Error(`Job is disabled: ${id}`);
271
- await this.executeJob(job);
231
+ if (job.state.runningAtMs != null) throw new CronJobAlreadyRunningError(id, job.state.runningSessionKey);
232
+ return {
233
+ job: this.startSingleJob(job, { manual: true }),
234
+ history: await this.getJobHistory(id, 20)
235
+ };
272
236
  }
273
- /**
274
- * Stop all jobs and cleanup
275
- */
276
237
  async stop(options) {
277
- const timeout = options?.timeout ?? 3e4;
278
- for (const [id, task] of this.tasks) {
279
- task.stop();
280
- this.executor.cancelJob(id);
238
+ this.stopped = true;
239
+ if (this.timer) {
240
+ clearTimeout(this.timer);
241
+ this.timer = null;
281
242
  }
282
- this.tasks.clear();
243
+ for (const job of listCronJobs()) this.executor.cancelJob(job.id);
283
244
  if (options?.waitForRunning) {
284
- const start = Date.now();
285
- while (Date.now() - start < timeout) {
286
- if (this.executor.getRunningExecutions().length === 0) break;
287
- await new Promise((r) => setTimeout(r, 100));
245
+ const started = nowMs();
246
+ const timeout = options.timeout ?? 3e4;
247
+ while (nowMs() - started < timeout) {
248
+ if (listCronJobs().every((job) => job.state.runningAtMs == null)) break;
249
+ await new Promise((resolve) => setTimeout(resolve, 100));
288
250
  }
289
251
  }
290
- await this.persistence.flush();
291
252
  log.info("CronService stopped");
292
253
  }
293
- /**
294
- * Load and schedule all enabled jobs
295
- */
296
- async loadAllJobs() {
297
- const jobs = await this.persistence.getJobs();
298
- for (const job of jobs) if (job.enabled) this.scheduleJob(job);
299
- log.debug({ count: this.tasks.size }, "Jobs loaded");
254
+ async recomputeAllNextRuns(opts) {
255
+ const ts = nowMs();
256
+ saveCronJobs(listCronJobs().map((job, index) => {
257
+ const next = {
258
+ ...job,
259
+ state: { ...job.state }
260
+ };
261
+ if (next.state.runningAtMs != null) {
262
+ next.state.lastRunStatus = "error";
263
+ next.state.lastError = "Interrupted by gateway restart";
264
+ next.state.consecutiveErrors = (next.state.consecutiveErrors ?? 0) + 1;
265
+ delete next.state.runningAtMs;
266
+ }
267
+ if (next.enabled) {
268
+ const existingNext = next.state.nextRunAtMs;
269
+ if (opts?.catchUp && existingNext != null && existingNext <= ts) next.state.nextRunAtMs = ts + index * this.missedJobStaggerMs;
270
+ else next.state.nextRunAtMs = computeNextRunAtMs(next, ts);
271
+ } else next.state.nextRunAtMs = void 0;
272
+ return next;
273
+ }));
300
274
  }
301
- /**
302
- * Schedule a job with node-cron
303
- */
304
- scheduleJob(job) {
305
- this.cancelTask(job.id);
306
- if (!nodeCron.validate(job.schedule)) {
307
- log.error({
308
- jobId: job.id,
309
- schedule: job.schedule
310
- }, "Invalid cron expression");
311
- return;
275
+ armTimer() {
276
+ if (this.stopped) return;
277
+ if (this.timer) {
278
+ clearTimeout(this.timer);
279
+ this.timer = null;
312
280
  }
313
- const options = job.timezone ? { timezone: job.timezone } : void 0;
314
- const task = nodeCron.schedule(job.schedule, async () => {
315
- await this.executeJob(job);
316
- }, options);
317
- this.tasks.set(job.id, task);
318
- log.debug({
319
- jobId: job.id,
320
- schedule: job.schedule
321
- }, "Job scheduled");
281
+ const next = listCronJobs().filter((job) => job.enabled && job.state.nextRunAtMs != null).toSorted((a, b) => (a.state.nextRunAtMs ?? 0) - (b.state.nextRunAtMs ?? 0))[0];
282
+ if (!next?.state.nextRunAtMs) return;
283
+ this.timer = setTimeout(() => {
284
+ this.onTimer();
285
+ }, timerDelayUntil(next.state.nextRunAtMs));
286
+ this.timer.unref?.();
322
287
  }
323
- /**
324
- * Execute a job with retry logic
325
- */
326
- async executeJob(job) {
327
- if (this.executor.isRunning(job.id)) {
328
- log.warn({ jobId: job.id }, "Job already running, skipping");
288
+ async onTimer() {
289
+ if (this.stopped) return;
290
+ if (this.running) {
291
+ this.armTimer();
329
292
  return;
330
293
  }
331
- const controller = new AbortController();
294
+ this.running = true;
332
295
  try {
333
- await this.executor.execute(job, controller.signal);
334
- } catch (error) {
296
+ const ts = nowMs();
297
+ const due = listCronJobs().filter((job) => job.enabled && job.state.nextRunAtMs != null && job.state.nextRunAtMs <= ts && job.state.runningAtMs == null).slice(0, this.maxConcurrentJobs);
298
+ if (due.length === 0) return;
299
+ const reserved = due.map((job) => ({
300
+ ...job,
301
+ state: {
302
+ ...job.state,
303
+ runningAtMs: ts
304
+ }
305
+ }));
306
+ saveCronJobs(reserved);
307
+ await Promise.all(reserved.map((job) => this.runSingleJob(job)));
308
+ } finally {
309
+ this.running = false;
310
+ this.armTimer();
311
+ }
312
+ }
313
+ startSingleJob(job, opts) {
314
+ const started = nowMs();
315
+ const runningSessionKey = resolveRunningSessionKey(job, this.deps);
316
+ const reserved = {
317
+ ...job,
318
+ state: {
319
+ ...job.state,
320
+ runningAtMs: started,
321
+ ...runningSessionKey ? { runningSessionKey } : {}
322
+ }
323
+ };
324
+ saveCronJob(reserved);
325
+ this.runReservedJob(reserved, started, runningSessionKey, opts).catch((err) => {
335
326
  log.error({
336
- jobId: job.id,
337
- err: error
338
- }, "Job execution failed");
327
+ err,
328
+ jobId: job.id
329
+ }, `Background cron job failed: ${err instanceof Error ? err.message : String(err)}`);
330
+ });
331
+ return reserved;
332
+ }
333
+ async runSingleJob(job, opts) {
334
+ const started = nowMs();
335
+ const runningSessionKey = resolveRunningSessionKey(job, this.deps);
336
+ const reserved = {
337
+ ...job,
338
+ state: {
339
+ ...job.state,
340
+ runningAtMs: started,
341
+ ...runningSessionKey ? { runningSessionKey } : {}
342
+ }
343
+ };
344
+ saveCronJob(reserved);
345
+ await this.runReservedJob(reserved, started, runningSessionKey, opts);
346
+ }
347
+ async runReservedJob(reserved, started, runningSessionKey, opts) {
348
+ const controller = new AbortController();
349
+ await this.executor.execute(runningSessionKey ? {
350
+ ...reserved,
351
+ sessionKey: runningSessionKey
352
+ } : reserved, controller.signal, this.deps);
353
+ const latestRun = (await this.getJobHistory(reserved.id, 1))[0];
354
+ const finished = nowMs();
355
+ const status = latestRun ? runStatusFromExecution(latestRun.status) : "error";
356
+ const latest = getCronJob(reserved.id);
357
+ if (!latest) return;
358
+ const next = {
359
+ ...latest,
360
+ state: {
361
+ ...latest.state,
362
+ lastRunAtMs: finished,
363
+ lastRunStatus: status,
364
+ lastError: latestRun?.error,
365
+ lastDurationMs: finished - started,
366
+ consecutiveErrors: status === "error" ? (latest.state.consecutiveErrors ?? 0) + 1 : 0,
367
+ consecutiveSkipped: status === "skipped" ? (latest.state.consecutiveSkipped ?? 0) + 1 : 0,
368
+ lastDeliveryStatus: latest.delivery?.mode && latest.delivery.mode !== "none" ? "unknown" : "not-requested"
369
+ }
370
+ };
371
+ delete next.state.runningAtMs;
372
+ delete next.state.runningSessionKey;
373
+ if (!opts?.manual && next.deleteAfterRun && status === "ok") {
374
+ await this.removeJob(next.id);
375
+ return;
339
376
  }
377
+ next.state.nextRunAtMs = computeNextRunAtMs(next, finished);
378
+ saveCronJob(next);
379
+ await this.maybeEmitFailureAlert(next);
340
380
  }
341
- /**
342
- * Cancel a scheduled task
343
- */
344
- cancelTask(id) {
345
- const task = this.tasks.get(id);
346
- if (task) {
347
- task.stop();
348
- this.tasks.delete(id);
349
- log.debug({ jobId: id }, "Task cancelled");
381
+ async maybeEmitFailureAlert(job) {
382
+ if (!job.failureAlert) return;
383
+ if (job.state.lastRunStatus !== "error") return;
384
+ const threshold = job.failureAlert.after ?? 1;
385
+ if ((job.state.consecutiveErrors ?? 0) < threshold) return;
386
+ const ts = nowMs();
387
+ const cooldownMs = job.failureAlert.cooldownMs ?? 60 * 6e4;
388
+ if (job.state.lastFailureAlertAtMs && ts - job.state.lastFailureAlertAtMs < cooldownMs) return;
389
+ const channel = job.failureAlert.channel || job.delivery?.channel;
390
+ const to = job.failureAlert.to || job.delivery?.to;
391
+ if (!to) return;
392
+ if (job.failureAlert.mode === "webhook") {
393
+ await postFailureWebhook(to, {
394
+ jobId: job.id,
395
+ jobName: job.name,
396
+ status: job.state.lastRunStatus,
397
+ error: job.state.lastError ?? "Unknown error",
398
+ consecutiveErrors: job.state.consecutiveErrors ?? 0,
399
+ lastRunAtMs: job.state.lastRunAtMs
400
+ });
401
+ job.state.lastFailureAlertAtMs = ts;
402
+ saveCronJob(job);
403
+ return;
350
404
  }
405
+ if (!this.deps.messageBus || !channel) return;
406
+ await this.deps.messageBus.publishOutbound({
407
+ channel,
408
+ chat_id: to,
409
+ type: "message",
410
+ content: `Cron job failed: ${job.name}\n${job.state.lastError ?? "Unknown error"}`
411
+ });
412
+ job.state.lastFailureAlertAtMs = ts;
413
+ saveCronJob(job);
351
414
  }
352
415
  };
353
416
  //#endregion
354
- export { CronService };
417
+ export { CronJobAlreadyRunningError, CronService };
355
418
 
356
419
  //# sourceMappingURL=service.js.map