@xopcai/xopc 0.0.88 → 0.0.90

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 (275) hide show
  1. package/README.md +8 -1
  2. package/README.zh-CN.md +8 -1
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/telegram/xopc.extension.json +1 -1
  5. package/dist/gateway/static/root/assets/agents-cPvvYLXo.js +222 -0
  6. package/dist/gateway/static/root/assets/apps-page-Bk1_P5FJ.js +1 -0
  7. package/dist/gateway/static/root/assets/channels-settings-CZoeQwHz.js +1 -0
  8. package/dist/gateway/static/root/assets/{channels-status-swr-DIsl75Y3.js → channels-status-swr-BrtH2VzC.js} +1 -1
  9. package/dist/gateway/static/root/assets/circle-check-C23XjkUj.js +1 -0
  10. package/dist/gateway/static/root/assets/cron-api-CyqbgfHM.js +1 -0
  11. package/dist/gateway/static/root/assets/cron-dreaming-jobs-Ip703-qM.js +2 -0
  12. package/dist/gateway/static/root/assets/cron-page-BpLdiQN8.js +1 -0
  13. package/dist/gateway/static/root/assets/dist-BpAiK86n.js +1 -0
  14. package/dist/gateway/static/root/assets/{extension-debug-page-BVJohZoZ.js → extension-debug-page-D6Ak0STa.js} +1 -1
  15. package/dist/gateway/static/root/assets/{extension-page-BT2tmElC.js → extension-page-Q0P3d6DW.js} +1 -1
  16. package/dist/gateway/static/root/assets/{extension-settings-page-BSS47c2j.js → extension-settings-page-CL55LwU_.js} +1 -1
  17. package/dist/gateway/static/root/assets/eye-DAfL1U7M.js +1 -0
  18. package/dist/gateway/static/root/assets/{fetch-BaFNUtkE.js → fetch-Dqa9iTWl.js} +1 -1
  19. package/dist/gateway/static/root/assets/{field-primitives-QwYEq6Hz.js → field-primitives-HUR6JElP.js} +1 -1
  20. package/dist/gateway/static/root/assets/{heartbeat-config-api-BVSidEDJ.js → heartbeat-config-api-DusckjUX.js} +1 -1
  21. package/dist/gateway/static/root/assets/{index-qNrVJp-y.js → index-BYcGfwcE.js} +97 -97
  22. package/dist/gateway/static/root/assets/index-V7MQ7834.css +1 -0
  23. package/dist/gateway/static/root/assets/{logs-page-DDonPVLn.js → logs-page-_HcZ2fgK.js} +1 -1
  24. package/dist/gateway/static/root/assets/sessions-page-iezSMjho.js +1 -0
  25. package/dist/gateway/static/root/assets/{settings-form-section-B8N3A3Zo.js → settings-form-section-a0qGVOlr.js} +1 -1
  26. package/dist/gateway/static/root/assets/settings-page-C9_nYQwM.js +3 -0
  27. package/dist/gateway/static/root/assets/{share-preview-page-Q7KqkO-u.js → share-preview-page-DExl7CJy.js} +1 -1
  28. package/dist/gateway/static/root/assets/skills-page-BlgGD93t.js +2 -0
  29. package/dist/gateway/static/root/assets/{theme-store-BbRc5ugR.js → theme-store-C0Ehmdo5.js} +1 -1
  30. package/dist/gateway/static/root/assets/url-fxyYANfA.js +3 -0
  31. package/dist/gateway/static/root/assets/{utils-CxDGduqK.js → utils-DRQryzdn.js} +1 -1
  32. package/dist/gateway/static/root/assets/voice-api-key-field-D0viACE2.js +1 -0
  33. package/dist/gateway/static/root/assets/workflow-page.utils-DnG8JBhV.js +1 -0
  34. package/dist/gateway/static/root/assets/workflows-page-BvMobnJP.js +27 -0
  35. package/dist/gateway/static/root/index.html +7 -6
  36. package/dist/package.js +1 -1
  37. package/dist/src/agent/agent-manager.d.ts +2 -0
  38. package/dist/src/agent/agent-manager.js +1 -0
  39. package/dist/src/agent/agent-manager.js.map +1 -1
  40. package/dist/src/agent/service.js +2 -1
  41. package/dist/src/agent/service.js.map +1 -1
  42. package/dist/src/agent/service.types.d.ts +3 -1
  43. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js +20 -18
  44. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js.map +1 -1
  45. package/dist/src/agent/tools/cronjob-tool.d.ts +6 -0
  46. package/dist/src/agent/tools/cronjob-tool.js +76 -10
  47. package/dist/src/agent/tools/cronjob-tool.js.map +1 -1
  48. package/dist/src/agent/tools/edit.d.ts +5 -1
  49. package/dist/src/agent/tools/edit.js +7 -5
  50. package/dist/src/agent/tools/edit.js.map +1 -1
  51. package/dist/src/agent/tools/factory.d.ts +3 -0
  52. package/dist/src/agent/tools/factory.js +4 -25
  53. package/dist/src/agent/tools/factory.js.map +1 -1
  54. package/dist/src/agent/tools/workflow-tool.d.ts +6 -28
  55. package/dist/src/agent/tools/workflow-tool.js +60 -260
  56. package/dist/src/agent/tools/workflow-tool.js.map +1 -1
  57. package/dist/src/agent/tools/write.d.ts +5 -1
  58. package/dist/src/agent/tools/write.js +7 -5
  59. package/dist/src/agent/tools/write.js.map +1 -1
  60. package/dist/src/agent/workflow/agent-progress.js +2 -0
  61. package/dist/src/agent/workflow/agent-progress.js.map +1 -1
  62. package/dist/src/agent/workflow/builtins/client-proposal.d.ts +12 -0
  63. package/dist/src/agent/workflow/builtins/client-proposal.js +155 -0
  64. package/dist/src/agent/workflow/builtins/client-proposal.js.map +1 -0
  65. package/dist/src/agent/workflow/builtins/competitor-scan.d.ts +12 -0
  66. package/dist/src/agent/workflow/builtins/competitor-scan.js +150 -0
  67. package/dist/src/agent/workflow/builtins/competitor-scan.js.map +1 -0
  68. package/dist/src/agent/workflow/builtins/content-draft.d.ts +13 -0
  69. package/dist/src/agent/workflow/builtins/content-draft.js +146 -0
  70. package/dist/src/agent/workflow/builtins/content-draft.js.map +1 -0
  71. package/dist/src/agent/workflow/builtins/content-repurpose.d.ts +11 -0
  72. package/dist/src/agent/workflow/builtins/content-repurpose.js +137 -0
  73. package/dist/src/agent/workflow/builtins/content-repurpose.js.map +1 -0
  74. package/dist/src/agent/workflow/builtins/decision-compare.d.ts +13 -0
  75. package/dist/src/agent/workflow/builtins/decision-compare.js +173 -0
  76. package/dist/src/agent/workflow/builtins/decision-compare.js.map +1 -0
  77. package/dist/src/agent/workflow/builtins/inbox-triage.d.ts +11 -0
  78. package/dist/src/agent/workflow/builtins/inbox-triage.js +148 -0
  79. package/dist/src/agent/workflow/builtins/inbox-triage.js.map +1 -0
  80. package/dist/src/agent/workflow/builtins/index.d.ts +10 -1
  81. package/dist/src/agent/workflow/builtins/index.js +46 -1
  82. package/dist/src/agent/workflow/builtins/index.js.map +1 -1
  83. package/dist/src/agent/workflow/builtins/meeting-prep.d.ts +12 -0
  84. package/dist/src/agent/workflow/builtins/meeting-prep.js +144 -0
  85. package/dist/src/agent/workflow/builtins/meeting-prep.js.map +1 -0
  86. package/dist/src/agent/workflow/builtins/offer-design.d.ts +12 -0
  87. package/dist/src/agent/workflow/builtins/offer-design.js +161 -0
  88. package/dist/src/agent/workflow/builtins/offer-design.js.map +1 -0
  89. package/dist/src/agent/workflow/builtins/weekly-review.d.ts +12 -0
  90. package/dist/src/agent/workflow/builtins/weekly-review.js +131 -0
  91. package/dist/src/agent/workflow/builtins/weekly-review.js.map +1 -0
  92. package/dist/src/agent/workflow/step-labels.js +2 -2
  93. package/dist/src/agent/workflow/step-labels.js.map +1 -1
  94. package/dist/src/agent/workflow/subagent-runner.js +3 -1
  95. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  96. package/dist/src/agent/workflow/types.d.ts +4 -0
  97. package/dist/src/agent/workflow/workflow-child-tools.d.ts +4 -0
  98. package/dist/src/agent/workflow/workflow-child-tools.js +21 -0
  99. package/dist/src/agent/workflow/workflow-child-tools.js.map +1 -0
  100. package/dist/src/auth/credentials.d.ts +14 -2
  101. package/dist/src/auth/credentials.js +38 -13
  102. package/dist/src/auth/credentials.js.map +1 -1
  103. package/dist/src/auth/oauth/types.d.ts +16 -0
  104. package/dist/src/chat-commands/agent-edit.d.ts +4 -0
  105. package/dist/src/chat-commands/agent-edit.js +136 -0
  106. package/dist/src/chat-commands/agent-edit.js.map +1 -0
  107. package/dist/src/chat-commands/index.d.ts +1 -0
  108. package/dist/src/chat-commands/index.js +3 -1
  109. package/dist/src/chat-commands/index.js.map +1 -1
  110. package/dist/src/cli/bin.js +2 -0
  111. package/dist/src/cli/bin.js.map +1 -1
  112. package/dist/src/cli/commands/auth.js +6 -0
  113. package/dist/src/cli/commands/auth.js.map +1 -1
  114. package/dist/src/cli/commands/cron.js +42 -3
  115. package/dist/src/cli/commands/cron.js.map +1 -1
  116. package/dist/src/cli/commands/doctor/checks/session-integrity.js +79 -56
  117. package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
  118. package/dist/src/cli/commands/onboard/model.js +6 -0
  119. package/dist/src/cli/commands/onboard/model.js.map +1 -1
  120. package/dist/src/cli/commands/update.js +86 -79
  121. package/dist/src/cli/commands/update.js.map +1 -1
  122. package/dist/src/commands/agents.config.d.ts +3 -2
  123. package/dist/src/commands/agents.config.js +5 -2
  124. package/dist/src/commands/agents.config.js.map +1 -1
  125. package/dist/src/config/agent-typed-models.d.ts +2 -7
  126. package/dist/src/config/agent-typed-models.js +3 -14
  127. package/dist/src/config/agent-typed-models.js.map +1 -1
  128. package/dist/src/config/localized-text.d.ts +6 -0
  129. package/dist/src/config/localized-text.js +42 -0
  130. package/dist/src/config/localized-text.js.map +1 -0
  131. package/dist/src/config/models-json.d.ts +6 -6
  132. package/dist/src/config/schema.d.ts +6 -21
  133. package/dist/src/config/schema.js +4 -4
  134. package/dist/src/config/schema.js.map +1 -1
  135. package/dist/src/cron/executor.d.ts +4 -0
  136. package/dist/src/cron/executor.js +169 -5
  137. package/dist/src/cron/executor.js.map +1 -1
  138. package/dist/src/cron/job-content.js +2 -1
  139. package/dist/src/cron/job-content.js.map +1 -1
  140. package/dist/src/cron/types.d.ts +28 -1
  141. package/dist/src/cron/validation.d.ts +80 -0
  142. package/dist/src/cron/validation.js +30 -4
  143. package/dist/src/cron/validation.js.map +1 -1
  144. package/dist/src/cron/workflow-run-completion.d.ts +23 -0
  145. package/dist/src/cron/workflow-run-completion.js +72 -0
  146. package/dist/src/cron/workflow-run-completion.js.map +1 -0
  147. package/dist/src/extensions/update.d.ts +51 -0
  148. package/dist/src/extensions/update.js +260 -0
  149. package/dist/src/extensions/update.js.map +1 -0
  150. package/dist/src/gateway/agents-admin.d.ts +15 -8
  151. package/dist/src/gateway/agents-admin.js +77 -28
  152. package/dist/src/gateway/agents-admin.js.map +1 -1
  153. package/dist/src/gateway/gateway-workflow-host.types.d.ts +17 -0
  154. package/dist/src/gateway/gateway-workflow-host.types.js +1 -0
  155. package/dist/src/gateway/heartbeat/service.js +1 -1
  156. package/dist/src/gateway/hono/lib/config-payload.d.ts +5 -0
  157. package/dist/src/gateway/hono/lib/config-payload.js +2 -1
  158. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  159. package/dist/src/gateway/hono/middleware/auth.d.ts +2 -0
  160. package/dist/src/gateway/hono/middleware/auth.js +12 -7
  161. package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
  162. package/dist/src/gateway/hono/oauth-async.js +40 -15
  163. package/dist/src/gateway/hono/oauth-async.js.map +1 -1
  164. package/dist/src/gateway/hono/oauth.js +31 -6
  165. package/dist/src/gateway/hono/oauth.js.map +1 -1
  166. package/dist/src/gateway/hono/routes/agents.js +55 -12
  167. package/dist/src/gateway/hono/routes/agents.js.map +1 -1
  168. package/dist/src/gateway/hono/routes/config-patch/agents.js +1 -1
  169. package/dist/src/gateway/hono/routes/models.js +11 -5
  170. package/dist/src/gateway/hono/routes/models.js.map +1 -1
  171. package/dist/src/gateway/hono/routes/update.js +55 -107
  172. package/dist/src/gateway/hono/routes/update.js.map +1 -1
  173. package/dist/src/gateway/hono/routes/workflows.js +72 -191
  174. package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
  175. package/dist/src/gateway/server.js +2 -0
  176. package/dist/src/gateway/server.js.map +1 -1
  177. package/dist/src/gateway/service.d.ts +5 -0
  178. package/dist/src/gateway/service.js +24 -3
  179. package/dist/src/gateway/service.js.map +1 -1
  180. package/dist/src/heartbeat/index.js +1 -1
  181. package/dist/src/infra/brew.d.ts +4 -0
  182. package/dist/src/infra/brew.js +20 -0
  183. package/dist/src/infra/brew.js.map +1 -0
  184. package/dist/src/infra/package-json.d.ts +2 -0
  185. package/dist/src/infra/package-json.js +23 -0
  186. package/dist/src/infra/package-json.js.map +1 -0
  187. package/dist/src/infra/package-update-steps.d.ts +35 -0
  188. package/dist/src/infra/package-update-steps.js +304 -0
  189. package/dist/src/infra/package-update-steps.js.map +1 -0
  190. package/dist/src/infra/path-env.d.ts +11 -0
  191. package/dist/src/infra/path-env.js +90 -0
  192. package/dist/src/infra/path-env.js.map +1 -0
  193. package/dist/src/infra/path-prepend.d.ts +7 -0
  194. package/dist/src/infra/path-prepend.js +44 -0
  195. package/dist/src/infra/path-prepend.js.map +1 -0
  196. package/dist/src/infra/stable-node-path.d.ts +2 -0
  197. package/dist/src/infra/stable-node-path.js +28 -0
  198. package/dist/src/infra/stable-node-path.js.map +1 -0
  199. package/dist/src/infra/update-global.d.ts +30 -23
  200. package/dist/src/infra/update-global.js +113 -64
  201. package/dist/src/infra/update-global.js.map +1 -1
  202. package/dist/src/infra/update-log.d.ts +1 -0
  203. package/dist/src/infra/update-log.js +12 -0
  204. package/dist/src/infra/update-log.js.map +1 -0
  205. package/dist/src/infra/update-restart.d.ts +20 -0
  206. package/dist/src/infra/update-restart.js +165 -0
  207. package/dist/src/infra/update-restart.js.map +1 -0
  208. package/dist/src/infra/update-runner.d.ts +89 -1
  209. package/dist/src/infra/update-runner.js +604 -173
  210. package/dist/src/infra/update-runner.js.map +1 -1
  211. package/dist/src/infra/update-startup.d.ts +3 -0
  212. package/dist/src/infra/update-startup.js +8 -4
  213. package/dist/src/infra/update-startup.js.map +1 -1
  214. package/dist/src/providers/index.d.ts +8 -0
  215. package/dist/src/providers/index.js +51 -12
  216. package/dist/src/providers/index.js.map +1 -1
  217. package/dist/src/routing/resolve-route.d.ts +3 -1
  218. package/dist/src/routing/resolve-route.js.map +1 -1
  219. package/dist/src/session/store.d.ts +5 -3
  220. package/dist/src/session/store.js +66 -20
  221. package/dist/src/session/store.js.map +1 -1
  222. package/dist/src/share/site-share-config.d.ts +3 -2
  223. package/dist/src/share/site-share-config.js.map +1 -1
  224. package/dist/src/utils/logger/stats.d.ts +1 -1
  225. package/dist/src/workflows/domain/command.d.ts +2 -1
  226. package/dist/src/workflows/domain/definition-utils.d.ts +14 -0
  227. package/dist/src/workflows/domain/definition-utils.js +50 -0
  228. package/dist/src/workflows/domain/definition-utils.js.map +1 -0
  229. package/dist/src/workflows/domain/event.d.ts +3 -0
  230. package/dist/src/workflows/domain/index.d.ts +2 -0
  231. package/dist/src/workflows/domain/index.js +3 -1
  232. package/dist/src/workflows/domain/run.d.ts +60 -0
  233. package/dist/src/workflows/domain/run.js.map +1 -1
  234. package/dist/src/workflows/domain/validation.d.ts +19 -0
  235. package/dist/src/workflows/domain/validation.js +66 -0
  236. package/dist/src/workflows/domain/validation.js.map +1 -0
  237. package/dist/src/workflows/engine/projector.js +17 -0
  238. package/dist/src/workflows/engine/projector.js.map +1 -1
  239. package/dist/src/workflows/engine/workflow-engine.d.ts +2 -1
  240. package/dist/src/workflows/engine/workflow-engine.js +128 -0
  241. package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
  242. package/dist/src/workflows/index.d.ts +4 -0
  243. package/dist/src/workflows/index.js +9 -2
  244. package/dist/src/workflows/service/run-view-to-snapshot.d.ts +4 -0
  245. package/dist/src/workflows/service/run-view-to-snapshot.js +63 -0
  246. package/dist/src/workflows/service/run-view-to-snapshot.js.map +1 -0
  247. package/dist/src/workflows/service/workflow-run-service.d.ts +37 -0
  248. package/dist/src/workflows/service/workflow-run-service.js +282 -0
  249. package/dist/src/workflows/service/workflow-run-service.js.map +1 -0
  250. package/dist/src/workflows/service/workflow-run-service.types.d.ts +47 -0
  251. package/dist/src/workflows/service/workflow-run-service.types.js +1 -0
  252. package/dist/src/workflows/service/workflow-session-bridge.d.ts +29 -0
  253. package/dist/src/workflows/service/workflow-session-bridge.js +177 -0
  254. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -0
  255. package/dist/src/workflows/service/workflow-session-key.d.ts +3 -0
  256. package/dist/src/workflows/service/workflow-session-key.js +21 -0
  257. package/dist/src/workflows/service/workflow-session-key.js.map +1 -0
  258. package/dist/src/workflows/store/run-store.js +1 -0
  259. package/dist/src/workflows/store/run-store.js.map +1 -1
  260. package/package.json +1 -1
  261. package/dist/gateway/static/root/assets/agents-CRxETUZx.js +0 -222
  262. package/dist/gateway/static/root/assets/apps-page-wKWf3l57.js +0 -1
  263. package/dist/gateway/static/root/assets/channels-settings-DDbqVNkx.js +0 -1
  264. package/dist/gateway/static/root/assets/copy-SxMW6Xpc.js +0 -1
  265. package/dist/gateway/static/root/assets/cron-api-N9hvuRrn.js +0 -1
  266. package/dist/gateway/static/root/assets/cron-dreaming-jobs-DueM3rBz.js +0 -2
  267. package/dist/gateway/static/root/assets/cron-page-tlNGNxhP.js +0 -1
  268. package/dist/gateway/static/root/assets/dist-CJwfHYvT.js +0 -1
  269. package/dist/gateway/static/root/assets/index-CqZzHNEg.css +0 -1
  270. package/dist/gateway/static/root/assets/sessions-page-DKt-Wmib.js +0 -1
  271. package/dist/gateway/static/root/assets/settings-page-DcJjvvw4.js +0 -3
  272. package/dist/gateway/static/root/assets/skills-page-DuJ4BTO3.js +0 -2
  273. package/dist/gateway/static/root/assets/url-D6jvVYIA.js +0 -7
  274. package/dist/gateway/static/root/assets/voice-api-key-field-CTyHz7L_.js +0 -1
  275. package/dist/gateway/static/root/assets/workflows-page-GacJ41Fv.js +0 -27
@@ -1 +1 @@
1
- {"version":3,"file":"update.js","names":[],"sources":["../../../../../src/gateway/hono/routes/update.ts"],"sourcesContent":["import type { Hono } from 'hono';\nimport { streamSSE } from 'hono/streaming';\n\nimport { loadConfig } from '../../../config/index.js';\nimport { acquireUpdateLock } from '../../../infra/update-lock.js';\nimport { detectInstallKind, resolvePackageRoot } from '../../../infra/update-check.js';\nimport {\n DEFAULT_PACKAGE_CHANNEL,\n normalizeUpdateChannel,\n type UpdateChannel,\n} from '../../../infra/update-channels.js';\nimport { runAutoUpdateCommand, runAutoUpdateCommandWithProgress } from '../../../infra/update-runner.js';\nimport { getUpdateAvailable, runGatewayUpdateCheck } from '../../../infra/update-startup.js';\nimport { PACKAGE_VERSION } from '../../../package-version.js';\nimport { createLogger } from '../../../utils/logger.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst log = createLogger('GatewayUpdate');\n\nfunction parseUpdateCliJson(stdout: string): Record<string, unknown> | null {\n const t = stdout.trim();\n if (!t) return null;\n try {\n const parsed = JSON.parse(t) as unknown;\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : null;\n } catch {\n const lines = t.split('\\n').filter(Boolean);\n for (let i = lines.length - 1; i >= 0; i--) {\n const line = lines[i]!.trim();\n if (!line.startsWith('{')) continue;\n try {\n const parsed = JSON.parse(line) as unknown;\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // try previous line\n }\n }\n }\n return null;\n}\n\ntype PreconditionOk = {\n ok: true;\n channel: UpdateChannel;\n root: string | null;\n};\n\nfunction isPreconditionFail(\n x: PreconditionOk | { ok: false; status: 400; body: Record<string, unknown> },\n): x is { ok: false; status: 400; body: Record<string, unknown> } {\n return !x.ok;\n}\n\nasync function npmUpdatePreconditions(\n service: AuthenticatedRouteDeps['service'],\n): Promise<PreconditionOk | { ok: false; status: 400; body: Record<string, unknown> }> {\n const config = loadConfig(service.getHealth().configPath);\n const channel = normalizeUpdateChannel(config.update?.channel) ?? DEFAULT_PACKAGE_CHANNEL;\n\n const root = await resolvePackageRoot();\n if (root) {\n const kind = await detectInstallKind(root);\n if (kind === 'git') {\n return {\n ok: false,\n status: 400,\n body: {\n ok: false,\n error: 'git-checkout',\n message:\n 'Running from a git checkout. Use `git pull` in the repo, or install from npm to use one-click update.',\n },\n };\n }\n }\n\n return { ok: true, channel, root };\n}\n\nexport function registerUpdateRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { strictRateLimitMiddleware, service } = deps;\n\n /**\n * GET /api/update/status\n */\n authenticated.get('/api/update/status', (c) => {\n const update = getUpdateAvailable();\n return c.json({\n ok: true,\n payload: {\n currentVersion: PACKAGE_VERSION,\n updateAvailable: update !== null,\n latestVersion: update?.latestVersion ?? null,\n channel: update?.channel ?? null,\n },\n });\n });\n\n /**\n * POST /api/update/check\n */\n authenticated.post('/api/update/check', strictRateLimitMiddleware, async (c) => {\n const config = loadConfig(service.getHealth().configPath);\n await runGatewayUpdateCheck({\n config,\n force: true,\n onUpdateAvailableChange: (update) => {\n service.emit('update.available', update);\n },\n });\n const result = getUpdateAvailable();\n return c.json({\n ok: true,\n payload: {\n currentVersion: PACKAGE_VERSION,\n updateAvailable: result !== null,\n latestVersion: result?.latestVersion ?? null,\n channel: result?.channel ?? null,\n },\n });\n });\n\n /**\n * POST /api/update/run — one-click npm install (OpenClaw-style). Rejects git checkouts.\n */\n authenticated.post('/api/update/run', strictRateLimitMiddleware, async (c) => {\n const pre = await npmUpdatePreconditions(service);\n if (isPreconditionFail(pre)) {\n return c.json(pre.body, pre.status);\n }\n\n const lock = await acquireUpdateLock('gateway');\n if (!lock) {\n return c.json(\n {\n ok: false,\n error: 'busy',\n message: 'Another update is already in progress.',\n },\n 409,\n );\n }\n\n const { channel, root } = pre;\n try {\n log.info({ channel }, 'Gateway: starting one-click npm update');\n const result = await runAutoUpdateCommand({ channel, root });\n const parsed = parseUpdateCliJson(result.stdout ?? '');\n\n if (result.ok && parsed?.status === 'skipped' && parsed?.reason === 'git-checkout') {\n return c.json(\n {\n ok: false,\n error: 'git-checkout',\n message: String(parsed.message ?? 'Git checkout — use git pull instead.'),\n },\n 400,\n );\n }\n\n if (!result.ok) {\n const installMessage =\n typeof parsed?.message === 'string'\n ? parsed.message\n : typeof parsed?.stderrTail === 'string'\n ? parsed.stderrTail\n : undefined;\n log.warn(\n { channel, exitCode: result.exitCode, reason: result.reason },\n 'Gateway: one-click npm update failed',\n );\n return c.json({\n ok: false,\n error: 'update-failed',\n message:\n installMessage ||\n result.stderr?.trim() ||\n result.reason ||\n `Update exited with code ${result.exitCode ?? 'unknown'}`,\n result: parsed,\n });\n }\n\n log.info({ channel }, 'Gateway: one-click npm update finished');\n return c.json({ ok: true, result: parsed });\n } catch (err) {\n log.error({ err, channel }, 'Gateway: one-click npm update threw');\n return c.json(\n {\n ok: false,\n error: 'internal',\n message: err instanceof Error ? err.message : String(err),\n },\n 500,\n );\n } finally {\n await lock.release();\n }\n });\n\n /**\n * POST /api/update/run/stream — SSE-streamed npm update with progress lines.\n */\n authenticated.post('/api/update/run/stream', strictRateLimitMiddleware, async (c) => {\n const pre = await npmUpdatePreconditions(service);\n if (isPreconditionFail(pre)) {\n return c.json(pre.body, pre.status);\n }\n\n const { channel, root } = pre;\n\n return streamSSE(c, async (stream) => {\n const lock = await acquireUpdateLock('gateway');\n if (!lock) {\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({\n ok: false,\n error: 'busy',\n message: 'Another update is already in progress.',\n }),\n });\n return;\n }\n\n try {\n log.info({ channel }, 'Gateway: starting streamed one-click npm update');\n const result = await runAutoUpdateCommandWithProgress({\n channel,\n root,\n onProgress: async (line, source) => {\n await stream.writeSSE({\n event: 'progress',\n data: JSON.stringify({ line, source }),\n });\n },\n });\n\n const parsed = parseUpdateCliJson(result.stdout ?? '');\n\n if (result.ok && parsed?.status === 'skipped' && parsed?.reason === 'git-checkout') {\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({\n ok: false,\n error: 'git-checkout',\n message: String(parsed.message ?? 'Git checkout — use git pull instead.'),\n }),\n });\n return;\n }\n\n if (!result.ok) {\n const installMessage =\n typeof parsed?.message === 'string'\n ? parsed.message\n : typeof parsed?.stderrTail === 'string'\n ? parsed.stderrTail\n : undefined;\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({\n ok: false,\n error: 'update-failed',\n message:\n installMessage ||\n result.stderr?.trim() ||\n result.reason ||\n `Update exited with code ${result.exitCode ?? 'unknown'}`,\n result: parsed,\n exitCode: result.exitCode,\n reason: result.reason,\n }),\n });\n return;\n }\n\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({ ok: true, result: parsed }),\n });\n } catch (err) {\n log.error({ err, channel }, 'Gateway: streamed npm update threw');\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({\n ok: false,\n error: 'internal',\n message: err instanceof Error ? err.message : String(err),\n }),\n });\n } finally {\n await lock.release();\n }\n });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"update.js","names":[],"sources":["../../../../../src/gateway/hono/routes/update.ts"],"sourcesContent":["import type { Hono } from 'hono';\nimport { streamSSE } from 'hono/streaming';\n\nimport { loadConfig } from '../../../config/index.js';\nimport { acquireUpdateLock } from '../../../infra/update-lock.js';\nimport {\n DEFAULT_PACKAGE_CHANNEL,\n normalizeUpdateChannel,\n type UpdateChannel,\n} from '../../../infra/update-channels.js';\nimport {\n formatUpdateApiResult,\n runGatewayUpdateWithPostSteps,\n type UpdateRunResult,\n} from '../../../infra/update-runner.js';\nimport { getUpdateAvailable, runGatewayUpdateCheck } from '../../../infra/update-startup.js';\nimport { PACKAGE_VERSION } from '../../../package-version.js';\nimport { createLogger } from '../../../utils/logger.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst log = createLogger('GatewayUpdate');\n\nfunction mapUpdateFailure(result: UpdateRunResult, channel: UpdateChannel) {\n const apiResult = formatUpdateApiResult(result, channel);\n const message =\n typeof apiResult.message === 'string'\n ? apiResult.message\n : result.reason ?? 'Update failed';\n return { apiResult, message };\n}\n\nexport function registerUpdateRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { strictRateLimitMiddleware, service } = deps;\n\n authenticated.get('/api/update/status', (c) => {\n const update = getUpdateAvailable();\n return c.json({\n ok: true,\n payload: {\n currentVersion: PACKAGE_VERSION,\n updateAvailable: update !== null,\n latestVersion: update?.latestVersion ?? null,\n channel: update?.channel ?? null,\n },\n });\n });\n\n authenticated.post('/api/update/check', strictRateLimitMiddleware, async (c) => {\n const config = loadConfig(service.getHealth().configPath);\n await runGatewayUpdateCheck({\n config,\n force: true,\n onUpdateAvailableChange: (update) => {\n service.emit('update.available', update);\n },\n });\n const result = getUpdateAvailable();\n return c.json({\n ok: true,\n payload: {\n currentVersion: PACKAGE_VERSION,\n updateAvailable: result !== null,\n latestVersion: result?.latestVersion ?? null,\n channel: result?.channel ?? null,\n },\n });\n });\n\n authenticated.post('/api/update/run', strictRateLimitMiddleware, async (c) => {\n const config = loadConfig(service.getHealth().configPath);\n const channel = normalizeUpdateChannel(config.update?.channel) ?? DEFAULT_PACKAGE_CHANNEL;\n\n const lock = await acquireUpdateLock('gateway');\n if (!lock) {\n return c.json(\n { ok: false, error: 'busy', message: 'Another update is already in progress.' },\n 409,\n );\n }\n\n try {\n log.info({ channel }, 'Gateway: starting in-process update');\n const result = await runGatewayUpdateWithPostSteps({\n channel,\n cwd: process.cwd(),\n argv1: process.argv[1],\n triggerInProcessRestart: () => service.triggerGatewayProcessRestart(),\n });\n const apiResult = formatUpdateApiResult(result, channel);\n if (result.status === 'error') {\n const { message } = mapUpdateFailure(result, channel);\n log.warn({ channel, reason: result.reason }, 'Gateway: update failed');\n return c.json({\n ok: false,\n error: 'update-failed',\n message,\n result: apiResult,\n });\n }\n log.info({ channel, mode: result.mode }, 'Gateway: update finished');\n return c.json({ ok: true, result: apiResult });\n } catch (err) {\n log.error({ err, channel }, 'Gateway: update threw');\n return c.json(\n {\n ok: false,\n error: 'internal',\n message: err instanceof Error ? err.message : String(err),\n },\n 500,\n );\n } finally {\n await lock.release();\n }\n });\n\n authenticated.post('/api/update/run/stream', strictRateLimitMiddleware, async (c) => {\n const config = loadConfig(service.getHealth().configPath);\n const channel = normalizeUpdateChannel(config.update?.channel) ?? DEFAULT_PACKAGE_CHANNEL;\n\n return streamSSE(c, async (stream) => {\n const lock = await acquireUpdateLock('gateway');\n if (!lock) {\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({\n ok: false,\n error: 'busy',\n message: 'Another update is already in progress.',\n }),\n });\n return;\n }\n\n try {\n log.info({ channel }, 'Gateway: starting streamed in-process update');\n const result = await runGatewayUpdateWithPostSteps({\n channel,\n cwd: process.cwd(),\n argv1: process.argv[1],\n triggerInProcessRestart: () => service.triggerGatewayProcessRestart(),\n progress: {\n onStepStart: async (step) => {\n await stream.writeSSE({\n event: 'progress',\n data: JSON.stringify({\n line: `[${step.index + 1}/${step.total}] ${step.name}: ${step.command}`,\n source: 'stdout',\n }),\n });\n },\n onStepComplete: async (step) => {\n if (step.stderrTail) {\n await stream.writeSSE({\n event: 'progress',\n data: JSON.stringify({ line: step.stderrTail, source: 'stderr' }),\n });\n }\n },\n },\n });\n\n const apiResult = formatUpdateApiResult(result, channel);\n if (result.status === 'error') {\n const { message } = mapUpdateFailure(result, channel);\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({\n ok: false,\n error: 'update-failed',\n message,\n result: apiResult,\n reason: result.reason,\n }),\n });\n return;\n }\n\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({ ok: true, result: apiResult }),\n });\n } catch (err) {\n log.error({ err, channel }, 'Gateway: streamed update threw');\n await stream.writeSSE({\n event: 'result',\n data: JSON.stringify({\n ok: false,\n error: 'internal',\n message: err instanceof Error ? err.message : String(err),\n }),\n });\n } finally {\n await lock.release();\n }\n });\n });\n}\n"],"mappings":"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"}
@@ -1,25 +1,13 @@
1
1
  import { init_agent_scope, resolveDefaultAgentId } from "../../../agent/agent-scope.js";
2
- import { extractProfileAgentId } from "../../../config/agent-profile.js";
3
- import { init_providers, resolveModel } from "../../../providers/index.js";
4
2
  import { createWorkflowCatalog } from "../../../agent/workflow/catalog.js";
5
- import { DelegateSubagentRunner } from "../../../agent/workflow/subagent-runner.js";
6
- import { resolveModelRef } from "../../../config/agent-typed-models.js";
7
- import { AgentToolsFactory } from "../../../agent/tools/factory.js";
8
- import { isTerminalWorkflowRunStatus } from "../../../workflows/domain/run.js";
9
- import { WorkflowEngine } from "../../../workflows/engine/workflow-engine.js";
10
- import { WorkflowEventStore } from "../../../workflows/store/event-store.js";
11
- import { WorkflowRunStore } from "../../../workflows/store/run-store.js";
12
- import "../../../workflows/index.js";
13
- import { randomUUID } from "node:crypto";
3
+ import { buildWorkflowDefinition } from "../../../workflows/domain/definition-utils.js";
4
+ import { validateWorkflowDefinitionInput } from "../../../workflows/domain/validation.js";
5
+ import "../../../workflows/domain/index.js";
14
6
  //#region src/gateway/hono/routes/workflows.ts
15
7
  init_agent_scope();
16
- init_providers();
17
- const DEFAULT_WORKFLOW_CONCURRENCY = 4;
18
- const DEFAULT_WORKFLOW_TIMEOUT_SEC = 1800;
19
- const DEFAULT_WORKFLOW_MAX_SUBAGENTS = 100;
20
- const activeWorkflowRuns = /* @__PURE__ */ new Map();
21
8
  function registerWorkflowRoutes(authenticated, deps) {
22
9
  const { service } = deps;
10
+ const workflowRunService = service.createWorkflowRunService();
23
11
  authenticated.get("/api/workflows/definitions", (c) => {
24
12
  const catalog = createWorkflowCatalog();
25
13
  const definitions = catalog.list().map((entry) => {
@@ -41,12 +29,26 @@ function registerWorkflowRoutes(authenticated, deps) {
41
29
  return c.json({ error: err instanceof Error ? err.message : "Workflow definition not found" }, 404);
42
30
  }
43
31
  });
32
+ authenticated.post("/api/workflows/definitions/validate", async (c) => {
33
+ const body = await readJsonBody(c.req.raw);
34
+ const result = validateWorkflowDefinitionInput({
35
+ name: body.name,
36
+ script: body.script
37
+ });
38
+ return c.json(result);
39
+ });
44
40
  authenticated.post("/api/workflows/definitions", async (c) => {
45
41
  const body = await readJsonBody(c.req.raw);
46
- const name = body.name?.trim();
47
- const script = body.script?.trim();
48
- if (!name) return c.json({ error: "name is required" }, 400);
49
- if (!script) return c.json({ error: "script is required" }, 400);
42
+ const validation = validateWorkflowDefinitionInput({
43
+ name: body.name,
44
+ script: body.script
45
+ });
46
+ if (!validation.valid) return c.json({
47
+ error: validation.errors[0]?.message ?? "Invalid workflow definition",
48
+ validation
49
+ }, 400);
50
+ const name = body.name?.trim() ?? "";
51
+ const script = body.script ?? "";
50
52
  const catalog = createWorkflowCatalog();
51
53
  try {
52
54
  catalog.save(name, script);
@@ -69,75 +71,74 @@ function registerWorkflowRoutes(authenticated, deps) {
69
71
  });
70
72
  authenticated.get("/api/workflows/stats", async (c) => {
71
73
  const agentId = getAgentId(c.req.query("agentId"), service.currentConfig);
72
- const runs = await createRunStore(service.currentConfig, agentId).listRunSummaries(500);
73
- return c.json({ stats: buildWorkflowStats(runs) });
74
+ const definitionId = c.req.query("definitionId")?.trim();
75
+ const runs = await workflowRunService.createRunStore(agentId).listRunSummaries(500);
76
+ const filteredRuns = definitionId ? runs.filter((run) => run.definitionId === definitionId) : runs;
77
+ return c.json({ stats: buildWorkflowStats(filteredRuns) });
74
78
  });
75
79
  authenticated.post("/api/workflows/runs", async (c) => {
76
80
  const body = await readJsonBody(c.req.raw);
77
81
  const definitionId = body.definitionId?.trim();
78
82
  if (!definitionId) return c.json({ error: "definitionId is required" }, 400);
79
83
  const agentId = getAgentId(body.agentId ?? c.req.query("agentId"), service.currentConfig);
80
- const runId = await queueWorkflowRun({
81
- deps,
84
+ const parentSessionKey = body.parentSessionKey?.trim() || void 0;
85
+ const result = await workflowRunService.startWorkflowRun({
82
86
  agentId,
83
- sessionKey: body.sessionKey?.trim() || `workflow:${agentId}`,
84
87
  definitionId,
85
88
  input: body.input,
89
+ inputEnvelope: body.inputEnvelope,
86
90
  goal: body.goal,
87
- source: body.source ?? { kind: "webui" },
91
+ parentSessionKey,
92
+ source: normalizeWorkflowRunSource(body.source),
88
93
  concurrency: normalizePositiveInteger(body.concurrency),
89
94
  maxSubagents: normalizePositiveInteger(body.maxSubagents),
90
- tokenBudget: body.tokenBudget
95
+ tokenBudget: body.tokenBudget,
96
+ idempotencyKey: body.idempotencyKey
91
97
  });
92
- if (!runId) return c.json({ error: "Workflow definition not found" }, 404);
93
- return c.json({ runId }, 202);
98
+ if (result.ok === false) return c.json({
99
+ error: result.message,
100
+ code: result.code
101
+ }, result.httpStatus);
102
+ return c.json({
103
+ runId: result.runId,
104
+ sessionKey: result.sessionKey
105
+ }, 202);
94
106
  });
95
107
  authenticated.get("/api/workflows/runs", async (c) => {
96
108
  const agentId = getAgentId(c.req.query("agentId"), service.currentConfig);
97
109
  const rawLimit = c.req.query("limit");
98
110
  const limit = rawLimit ? Number.parseInt(rawLimit, 10) : 50;
99
- const runs = await createRunStore(service.currentConfig, agentId).listRunSummaries(Number.isFinite(limit) ? limit : 50);
111
+ const runs = await workflowRunService.createRunStore(agentId).listRunSummaries(Number.isFinite(limit) ? limit : 50);
100
112
  return c.json({ runs });
101
113
  });
102
114
  authenticated.post("/api/workflows/runs/:runId/cancel", async (c) => {
103
115
  const runId = c.req.param("runId");
104
116
  const agentId = getAgentId(c.req.query("agentId"), service.currentConfig);
105
- const runStore = createRunStore(service.currentConfig, agentId);
106
- const controller = activeWorkflowRuns.get(runId);
107
- if (controller) {
108
- controller.abort();
109
- activeWorkflowRuns.delete(runId);
110
- return c.json({ cancelled: true });
111
- }
112
- const view = await runStore.readRunView(runId);
113
- if (!view) return c.json({ error: "Workflow run not found" }, 404);
114
- if (isTerminalWorkflowRunStatus(view.run.status)) return c.json({
115
- cancelled: true,
116
- alreadyFinished: true
117
- });
118
- await new WorkflowEventStore(service.currentConfig, agentId).append({
117
+ const result = await workflowRunService.cancelWorkflowRun({
118
+ agentId,
119
119
  runId,
120
- type: "run_cancelled",
121
- payload: { reason: "Cancelled by user" }
120
+ reason: "Cancelled by user"
122
121
  });
123
- const updated = await runStore.rebuildRunView(runId);
124
- if (updated) service.emit("workflow.run.updated", {
125
- runId,
126
- view: updated
122
+ if (result.ok === false) return c.json({
123
+ error: result.message,
124
+ code: result.code
125
+ }, result.httpStatus);
126
+ return c.json({
127
+ cancelled: result.cancelled,
128
+ alreadyFinished: result.alreadyFinished
127
129
  });
128
- return c.json({ cancelled: true });
129
130
  });
130
131
  authenticated.get("/api/workflows/runs/:runId", async (c) => {
131
132
  const agentId = getAgentId(c.req.query("agentId"), service.currentConfig);
132
133
  const runId = c.req.param("runId");
133
- const view = await createRunStore(service.currentConfig, agentId).readRunView(runId);
134
+ const view = await workflowRunService.createRunStore(agentId).readRunView(runId);
134
135
  if (!view) return c.json({ error: "Workflow run not found" }, 404);
135
136
  return c.json({ view });
136
137
  });
137
138
  authenticated.post("/api/workflows/runs/:runId/rebuild", async (c) => {
138
139
  const agentId = getAgentId(c.req.query("agentId"), service.currentConfig);
139
140
  const runId = c.req.param("runId");
140
- const view = await createRunStore(service.currentConfig, agentId).rebuildRunView(runId);
141
+ const view = await workflowRunService.createRunStore(agentId).rebuildRunView(runId);
141
142
  if (!view) return c.json({ error: "Workflow run not found" }, 404);
142
143
  service.emit("workflow.run.updated", {
143
144
  runId,
@@ -148,104 +149,32 @@ function registerWorkflowRoutes(authenticated, deps) {
148
149
  authenticated.post("/api/workflows/runs/:runId/retry", async (c) => {
149
150
  const agentId = getAgentId(c.req.query("agentId"), service.currentConfig);
150
151
  const runId = c.req.param("runId");
151
- const existing = await createRunStore(service.currentConfig, agentId).readRunView(runId);
152
- if (!existing) return c.json({ error: "Workflow run not found" }, 404);
153
- const newRunId = await queueWorkflowRun({
154
- deps,
152
+ const result = await workflowRunService.retryWorkflowRun({
155
153
  agentId,
156
- sessionKey: `workflow:${agentId}`,
157
- definitionId: existing.run.definitionId,
158
- input: existing.run.input,
159
- goal: existing.run.goal,
160
- source: { kind: "webui" }
154
+ runId
161
155
  });
162
- if (!newRunId) return c.json({ error: "Workflow definition not found" }, 404);
163
- return c.json({ runId: newRunId }, 202);
156
+ if (result.ok === false) return c.json({
157
+ error: result.message,
158
+ code: result.code
159
+ }, result.httpStatus);
160
+ return c.json({
161
+ runId: result.runId,
162
+ sessionKey: result.sessionKey
163
+ }, 202);
164
164
  });
165
165
  }
166
- function createRunStore(config, agentId) {
167
- return new WorkflowRunStore(config, agentId, new WorkflowEventStore(config, agentId));
168
- }
169
166
  function getAgentId(rawAgentId, config) {
170
167
  const trimmed = rawAgentId?.trim();
171
168
  if (trimmed) return trimmed;
172
169
  return resolveDefaultAgentId(config);
173
170
  }
174
171
  function toWorkflowDefinition(loaded) {
175
- const nowMs = Date.now();
176
- const phases = loaded.meta.phases?.map((phase, index) => ({
177
- id: normalizeId(phase.title) || `phase-${index + 1}`,
178
- title: phase.title,
179
- description: phase.detail
180
- })) ?? [];
181
- return {
182
- id: loaded.name,
172
+ return buildWorkflowDefinition({
183
173
  name: loaded.name,
184
- title: toTitle(loaded.name),
185
- description: loaded.meta.description,
186
- version: "1.0.0",
187
- phases,
188
- runtime: {
189
- kind: "script",
190
- source: loaded.script
191
- },
192
- defaults: {
193
- concurrency: DEFAULT_WORKFLOW_CONCURRENCY,
194
- timeoutSec: DEFAULT_WORKFLOW_TIMEOUT_SEC,
195
- maxSubagents: loaded.meta.estimatedAgents?.max ?? DEFAULT_WORKFLOW_MAX_SUBAGENTS
196
- },
197
- metadata: {
198
- tags: loaded.meta.tags ?? [],
199
- builtIn: loaded.source === "builtin",
200
- source: loaded.source,
201
- whenToUse: loaded.meta.whenToUse,
202
- estimatedAgents: loaded.meta.estimatedAgents,
203
- examplePrompts: loaded.meta.examplePrompts,
204
- i18n: loaded.meta.i18n,
205
- createdAtMs: nowMs,
206
- updatedAtMs: nowMs
207
- }
208
- };
209
- }
210
- async function queueWorkflowRun(params) {
211
- const { deps, agentId, sessionKey, definitionId } = params;
212
- const { service } = deps;
213
- const catalog = createWorkflowCatalog();
214
- let definition;
215
- try {
216
- definition = toWorkflowDefinition(catalog.load(definitionId));
217
- } catch {
218
- return null;
219
- }
220
- const eventStore = new WorkflowEventStore(service.currentConfig, agentId);
221
- const runStore = new WorkflowRunStore(service.currentConfig, agentId, eventStore);
222
- const runId = randomUUID();
223
- const abortController = new AbortController();
224
- const engine = createWorkflowEngine({
225
- deps,
226
- eventStore,
227
- runStore,
228
- sessionKey
229
- });
230
- activeWorkflowRuns.set(runId, abortController);
231
- engine.startRun(definition, {
232
- runId,
233
- input: params.input,
234
- goal: params.goal,
235
- source: params.source,
236
- signal: abortController.signal,
237
- concurrency: params.concurrency,
238
- maxSubagents: params.maxSubagents,
239
- tokenBudget: params.tokenBudget
240
- }).catch((err) => {
241
- service.emit("workflow.run.error", {
242
- runId,
243
- error: err instanceof Error ? err.message : String(err)
244
- });
245
- }).finally(() => {
246
- activeWorkflowRuns.delete(runId);
174
+ source: loaded.source,
175
+ script: loaded.script,
176
+ meta: loaded.meta
247
177
  });
248
- return runId;
249
178
  }
250
179
  function buildWorkflowStats(runs) {
251
180
  const activeStatuses = new Set(["queued", "running"]);
@@ -278,52 +207,6 @@ function buildWorkflowStats(runs) {
278
207
  topDefinitions
279
208
  };
280
209
  }
281
- function createWorkflowEngine(params) {
282
- const { service } = params.deps;
283
- const runner = new DelegateSubagentRunner({
284
- workspace: service.currentWorkspacePath,
285
- bus: service.messageBusInstance,
286
- getDefaultModel: () => resolveModel(service.agentService.getModelForSession(params.sessionKey)),
287
- getConfig: () => service.currentConfig,
288
- buildChildTools: (childOptions) => buildWorkflowChildTools(childOptions)
289
- });
290
- return new WorkflowEngine({
291
- cwd: service.currentWorkspacePath,
292
- eventStore: params.eventStore,
293
- runStore: params.runStore,
294
- runner,
295
- resolveModelId: (modelId) => {
296
- const agentId = extractProfileAgentId(params.sessionKey, service.currentConfig);
297
- return resolveModel(resolveModelRef(service.currentConfig, agentId, modelId));
298
- },
299
- onEventAppended: (event) => {
300
- service.emit("workflow.event.appended", {
301
- runId: event.runId,
302
- event
303
- });
304
- },
305
- onRunViewUpdated: (view) => {
306
- service.emit("workflow.run.updated", {
307
- runId: view.run.id,
308
- view
309
- });
310
- }
311
- });
312
- }
313
- function buildWorkflowChildTools(childOptions) {
314
- return new AgentToolsFactory({
315
- workspace: childOptions.workspace,
316
- bus: childOptions.bus,
317
- getCurrentContext: () => null,
318
- getConfig: childOptions.getConfig,
319
- getPrimaryModel: () => childOptions.model,
320
- toolExecutorConfig: childOptions.toolExecutorConfig
321
- }).createAllTools({
322
- workspace: childOptions.workspace,
323
- getPrimaryModel: () => childOptions.model,
324
- disabledTools: new Set(["extensions"])
325
- });
326
- }
327
210
  async function readJsonBody(request) {
328
211
  try {
329
212
  return await request.json();
@@ -331,16 +214,14 @@ async function readJsonBody(request) {
331
214
  return {};
332
215
  }
333
216
  }
217
+ function normalizeWorkflowRunSource(source) {
218
+ if (!source) return { kind: "webui" };
219
+ return source;
220
+ }
334
221
  function normalizePositiveInteger(value) {
335
222
  if (typeof value !== "number" || !Number.isFinite(value) || value < 1) return;
336
223
  return Math.floor(value);
337
224
  }
338
- function normalizeId(value) {
339
- return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
340
- }
341
- function toTitle(value) {
342
- return value.split(/[_-]+/g).filter(Boolean).map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
343
- }
344
225
  //#endregion
345
226
  export { registerWorkflowRoutes };
346
227
 
@@ -1 +1 @@
1
- {"version":3,"file":"workflows.js","names":["resolveModelById"],"sources":["../../../../../src/gateway/hono/routes/workflows.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { Hono } from 'hono';\n\nimport { resolveDefaultAgentId } from '../../../agent/agent-scope.js';\nimport type { BuildChildToolsOptions } from '../../../agent/child-agent-factory.js';\nimport { AgentToolsFactory } from '../../../agent/tools/factory.js';\nimport { createWorkflowCatalog } from '../../../agent/workflow/catalog.js';\nimport { DelegateSubagentRunner } from '../../../agent/workflow/subagent-runner.js';\nimport type { WorkflowDefinition, WorkflowRunSource, WorkflowRunSummary } from '../../../workflows/domain/index.js';\nimport { isTerminalWorkflowRunStatus } from '../../../workflows/domain/run.js';\nimport { WorkflowEngine, WorkflowEventStore, WorkflowRunStore } from '../../../workflows/index.js';\nimport { extractProfileAgentId } from '../../../config/agent-profile.js';\nimport { resolveModelRef } from '../../../config/agent-typed-models.js';\nimport { resolveModel as resolveModelById } from '../../../providers/index.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst DEFAULT_WORKFLOW_CONCURRENCY = 4;\nconst DEFAULT_WORKFLOW_TIMEOUT_SEC = 30 * 60;\nconst DEFAULT_WORKFLOW_MAX_SUBAGENTS = 100;\n\nconst activeWorkflowRuns = new Map<string, AbortController>();\n\ninterface StartWorkflowRunRequestBody {\n definitionId?: string;\n input?: unknown;\n goal?: string;\n agentId?: string;\n sessionKey?: string;\n source?: WorkflowRunSource;\n concurrency?: number;\n maxSubagents?: number;\n tokenBudget?: number | null;\n}\n\ninterface SaveWorkflowDefinitionRequestBody {\n name?: string;\n script?: string;\n}\n\nexport function registerWorkflowRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n authenticated.get('/api/workflows/definitions', (c) => {\n const catalog = createWorkflowCatalog();\n const definitions = catalog.list().map((entry) => {\n try {\n return toWorkflowDefinition(catalog.load(entry.name));\n } catch {\n return null;\n }\n }).filter((definition): definition is WorkflowDefinition => Boolean(definition));\n\n return c.json({ definitions });\n });\n\n authenticated.get('/api/workflows/definitions/:id', (c) => {\n const id = c.req.param('id');\n const catalog = createWorkflowCatalog();\n try {\n const definition = toWorkflowDefinition(catalog.load(id));\n return c.json({ definition });\n } catch (err) {\n return c.json({ error: err instanceof Error ? err.message : 'Workflow definition not found' }, 404);\n }\n });\n\n authenticated.post('/api/workflows/definitions', async (c) => {\n const body = await readJsonBody<SaveWorkflowDefinitionRequestBody>(c.req.raw);\n const name = body.name?.trim();\n const script = body.script?.trim();\n if (!name) {\n return c.json({ error: 'name is required' }, 400);\n }\n if (!script) {\n return c.json({ error: 'script is required' }, 400);\n }\n\n const catalog = createWorkflowCatalog();\n try {\n catalog.save(name, script);\n const definition = toWorkflowDefinition(catalog.load(name));\n return c.json({ definition }, 201);\n } catch (err) {\n return c.json({ error: err instanceof Error ? err.message : 'Failed to save workflow' }, 400);\n }\n });\n\n authenticated.delete('/api/workflows/definitions/:id', (c) => {\n const id = c.req.param('id').trim();\n if (!id) {\n return c.json({ error: 'id is required' }, 400);\n }\n\n const catalog = createWorkflowCatalog();\n try {\n const removed = catalog.remove(id);\n if (!removed) {\n return c.json({ error: 'User workflow not found or cannot delete built-in workflow' }, 404);\n }\n return c.json({ removed: true });\n } catch (err) {\n return c.json({ error: err instanceof Error ? err.message : 'Failed to delete workflow' }, 400);\n }\n });\n\n authenticated.get('/api/workflows/stats', async (c) => {\n const agentId = getAgentId(c.req.query('agentId'), service.currentConfig);\n const runStore = createRunStore(service.currentConfig, agentId);\n const runs = await runStore.listRunSummaries(500);\n return c.json({ stats: buildWorkflowStats(runs) });\n });\n\n authenticated.post('/api/workflows/runs', async (c) => {\n const body = await readJsonBody<StartWorkflowRunRequestBody>(c.req.raw);\n const definitionId = body.definitionId?.trim();\n if (!definitionId) {\n return c.json({ error: 'definitionId is required' }, 400);\n }\n\n const agentId = getAgentId(body.agentId ?? c.req.query('agentId'), service.currentConfig);\n const sessionKey = body.sessionKey?.trim() || `workflow:${agentId}`;\n const runId = await queueWorkflowRun({\n deps,\n agentId,\n sessionKey,\n definitionId,\n input: body.input,\n goal: body.goal,\n source: body.source ?? { kind: 'webui' },\n concurrency: normalizePositiveInteger(body.concurrency),\n maxSubagents: normalizePositiveInteger(body.maxSubagents),\n tokenBudget: body.tokenBudget,\n });\n\n if (!runId) {\n return c.json({ error: 'Workflow definition not found' }, 404);\n }\n\n return c.json({ runId }, 202);\n });\n\n authenticated.get('/api/workflows/runs', async (c) => {\n const agentId = getAgentId(c.req.query('agentId'), service.currentConfig);\n const rawLimit = c.req.query('limit');\n const limit = rawLimit ? Number.parseInt(rawLimit, 10) : 50;\n const runStore = createRunStore(service.currentConfig, agentId);\n const runs = await runStore.listRunSummaries(Number.isFinite(limit) ? limit : 50);\n return c.json({ runs });\n });\n\n authenticated.post('/api/workflows/runs/:runId/cancel', async (c) => {\n const runId = c.req.param('runId');\n const agentId = getAgentId(c.req.query('agentId'), service.currentConfig);\n const runStore = createRunStore(service.currentConfig, agentId);\n\n const controller = activeWorkflowRuns.get(runId);\n if (controller) {\n controller.abort();\n activeWorkflowRuns.delete(runId);\n return c.json({ cancelled: true });\n }\n\n const view = await runStore.readRunView(runId);\n if (!view) {\n return c.json({ error: 'Workflow run not found' }, 404);\n }\n\n if (isTerminalWorkflowRunStatus(view.run.status)) {\n return c.json({ cancelled: true, alreadyFinished: true });\n }\n\n const eventStore = new WorkflowEventStore(service.currentConfig, agentId);\n await eventStore.append({\n runId,\n type: 'run_cancelled',\n payload: { reason: 'Cancelled by user' },\n });\n const updated = await runStore.rebuildRunView(runId);\n if (updated) {\n service.emit('workflow.run.updated', { runId, view: updated });\n }\n return c.json({ cancelled: true });\n });\n\n authenticated.get('/api/workflows/runs/:runId', async (c) => {\n const agentId = getAgentId(c.req.query('agentId'), service.currentConfig);\n const runId = c.req.param('runId');\n const runStore = createRunStore(service.currentConfig, agentId);\n const view = await runStore.readRunView(runId);\n if (!view) {\n return c.json({ error: 'Workflow run not found' }, 404);\n }\n return c.json({ view });\n });\n\n authenticated.post('/api/workflows/runs/:runId/rebuild', async (c) => {\n const agentId = getAgentId(c.req.query('agentId'), service.currentConfig);\n const runId = c.req.param('runId');\n const runStore = createRunStore(service.currentConfig, agentId);\n const view = await runStore.rebuildRunView(runId);\n if (!view) {\n return c.json({ error: 'Workflow run not found' }, 404);\n }\n service.emit('workflow.run.updated', { runId, view });\n return c.json({ view });\n });\n\n authenticated.post('/api/workflows/runs/:runId/retry', async (c) => {\n const agentId = getAgentId(c.req.query('agentId'), service.currentConfig);\n const runId = c.req.param('runId');\n const runStore = createRunStore(service.currentConfig, agentId);\n const existing = await runStore.readRunView(runId);\n if (!existing) {\n return c.json({ error: 'Workflow run not found' }, 404);\n }\n\n const sessionKey = `workflow:${agentId}`;\n const newRunId = await queueWorkflowRun({\n deps,\n agentId,\n sessionKey,\n definitionId: existing.run.definitionId,\n input: existing.run.input,\n goal: existing.run.goal,\n source: { kind: 'webui' },\n });\n\n if (!newRunId) {\n return c.json({ error: 'Workflow definition not found' }, 404);\n }\n\n return c.json({ runId: newRunId }, 202);\n });\n}\n\nfunction createRunStore(config: AuthenticatedRouteDeps['service']['currentConfig'], agentId: string): WorkflowRunStore {\n const eventStore = new WorkflowEventStore(config, agentId);\n return new WorkflowRunStore(config, agentId, eventStore);\n}\n\nfunction getAgentId(rawAgentId: string | undefined, config: AuthenticatedRouteDeps['service']['currentConfig']): string {\n const trimmed = rawAgentId?.trim();\n if (trimmed) {\n return trimmed;\n }\n return resolveDefaultAgentId(config);\n}\n\nfunction toWorkflowDefinition(loaded: ReturnType<ReturnType<typeof createWorkflowCatalog>['load']>): WorkflowDefinition {\n const nowMs = Date.now();\n const phases = loaded.meta.phases?.map((phase, index) => ({\n id: normalizeId(phase.title) || `phase-${index + 1}`,\n title: phase.title,\n description: phase.detail,\n })) ?? [];\n\n return {\n id: loaded.name,\n name: loaded.name,\n title: toTitle(loaded.name),\n description: loaded.meta.description,\n version: '1.0.0',\n phases,\n runtime: {\n kind: 'script',\n source: loaded.script,\n },\n defaults: {\n concurrency: DEFAULT_WORKFLOW_CONCURRENCY,\n timeoutSec: DEFAULT_WORKFLOW_TIMEOUT_SEC,\n maxSubagents: loaded.meta.estimatedAgents?.max ?? DEFAULT_WORKFLOW_MAX_SUBAGENTS,\n },\n metadata: {\n tags: loaded.meta.tags ?? [],\n builtIn: loaded.source === 'builtin',\n source: loaded.source,\n whenToUse: loaded.meta.whenToUse,\n estimatedAgents: loaded.meta.estimatedAgents,\n examplePrompts: loaded.meta.examplePrompts,\n i18n: loaded.meta.i18n,\n createdAtMs: nowMs,\n updatedAtMs: nowMs,\n },\n };\n}\n\ninterface QueueWorkflowRunParams {\n deps: AuthenticatedRouteDeps;\n agentId: string;\n sessionKey: string;\n definitionId: string;\n input?: unknown;\n goal?: string;\n source: WorkflowRunSource;\n concurrency?: number;\n maxSubagents?: number;\n tokenBudget?: number | null;\n}\n\nasync function queueWorkflowRun(params: QueueWorkflowRunParams): Promise<string | null> {\n const { deps, agentId, sessionKey, definitionId } = params;\n const { service } = deps;\n const catalog = createWorkflowCatalog();\n let definition: WorkflowDefinition;\n try {\n definition = toWorkflowDefinition(catalog.load(definitionId));\n } catch {\n return null;\n }\n\n const eventStore = new WorkflowEventStore(service.currentConfig, agentId);\n const runStore = new WorkflowRunStore(service.currentConfig, agentId, eventStore);\n const runId = randomUUID();\n const abortController = new AbortController();\n const engine = createWorkflowEngine({\n deps,\n eventStore,\n runStore,\n sessionKey,\n });\n\n activeWorkflowRuns.set(runId, abortController);\n void engine.startRun(definition, {\n runId,\n input: params.input,\n goal: params.goal,\n source: params.source,\n signal: abortController.signal,\n concurrency: params.concurrency,\n maxSubagents: params.maxSubagents,\n tokenBudget: params.tokenBudget,\n }).catch((err) => {\n service.emit('workflow.run.error', {\n runId,\n error: err instanceof Error ? err.message : String(err),\n });\n }).finally(() => {\n activeWorkflowRuns.delete(runId);\n });\n\n return runId;\n}\n\nfunction buildWorkflowStats(runs: WorkflowRunSummary[]): {\n totalRuns: number;\n activeRuns: number;\n succeededRuns: number;\n failedRuns: number;\n averageDurationMs: number | null;\n topDefinitions: Array<{ definitionId: string; count: number }>;\n} {\n const activeStatuses = new Set(['queued', 'running']);\n const succeededStatuses = new Set(['succeeded']);\n const failedStatuses = new Set(['failed', 'timeout', 'cancelled']);\n\n let durationTotal = 0;\n let durationCount = 0;\n const definitionCounts = new Map<string, number>();\n\n for (const run of runs) {\n definitionCounts.set(run.definitionId, (definitionCounts.get(run.definitionId) ?? 0) + 1);\n if (run.metrics.durationMs != null && Number.isFinite(run.metrics.durationMs)) {\n durationTotal += run.metrics.durationMs;\n durationCount += 1;\n }\n }\n\n const topDefinitions = [...definitionCounts.entries()]\n .sort((left, right) => right[1] - left[1])\n .slice(0, 5)\n .map(([definitionId, count]) => ({ definitionId, count }));\n\n return {\n totalRuns: runs.length,\n activeRuns: runs.filter((run) => activeStatuses.has(run.status)).length,\n succeededRuns: runs.filter((run) => succeededStatuses.has(run.status)).length,\n failedRuns: runs.filter((run) => failedStatuses.has(run.status)).length,\n averageDurationMs: durationCount > 0 ? Math.round(durationTotal / durationCount) : null,\n topDefinitions,\n };\n}\n\nfunction createWorkflowEngine(params: {\n deps: AuthenticatedRouteDeps;\n eventStore: WorkflowEventStore;\n runStore: WorkflowRunStore;\n sessionKey: string;\n}): WorkflowEngine {\n const { service } = params.deps;\n const runner = new DelegateSubagentRunner({\n workspace: service.currentWorkspacePath,\n bus: service.messageBusInstance,\n getDefaultModel: () => resolveModelById(service.agentService.getModelForSession(params.sessionKey)),\n getConfig: () => service.currentConfig,\n buildChildTools: (childOptions) => buildWorkflowChildTools(childOptions),\n });\n\n return new WorkflowEngine({\n cwd: service.currentWorkspacePath,\n eventStore: params.eventStore,\n runStore: params.runStore,\n runner,\n resolveModelId: (modelId) => {\n const agentId = extractProfileAgentId(params.sessionKey, service.currentConfig);\n return resolveModelById(resolveModelRef(service.currentConfig, agentId, modelId));\n },\n onEventAppended: (event) => {\n service.emit('workflow.event.appended', { runId: event.runId, event });\n },\n onRunViewUpdated: (view) => {\n service.emit('workflow.run.updated', { runId: view.run.id, view });\n },\n });\n}\n\nfunction buildWorkflowChildTools(childOptions: BuildChildToolsOptions) {\n const childFactory = new AgentToolsFactory({\n workspace: childOptions.workspace,\n bus: childOptions.bus,\n getCurrentContext: () => null,\n getConfig: childOptions.getConfig,\n getPrimaryModel: () => childOptions.model,\n toolExecutorConfig: childOptions.toolExecutorConfig,\n });\n return childFactory.createAllTools({\n workspace: childOptions.workspace,\n getPrimaryModel: () => childOptions.model,\n disabledTools: new Set(['extensions']),\n });\n}\n\nasync function readJsonBody<T>(request: Request): Promise<T> {\n try {\n return await request.json() as T;\n } catch {\n return {} as T;\n }\n}\n\nfunction normalizePositiveInteger(value: number | undefined): number | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 1) {\n return undefined;\n }\n return Math.floor(value);\n}\n\nfunction normalizeId(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nfunction toTitle(value: string): string {\n return value\n .split(/[_-]+/g)\n .filter(Boolean)\n .map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)\n .join(' ');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"workflows.js","names":[],"sources":["../../../../../src/gateway/hono/routes/workflows.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { resolveDefaultAgentId } from '../../../agent/agent-scope.js';\nimport { createWorkflowCatalog } from '../../../agent/workflow/catalog.js';\nimport type {\n WorkflowDefinition,\n WorkflowRunInputEnvelope,\n WorkflowRunSource,\n WorkflowRunSummary,\n} from '../../../workflows/domain/index.js';\nimport { buildWorkflowDefinition, validateWorkflowDefinitionInput } from '../../../workflows/domain/index.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\ninterface StartWorkflowRunRequestBody {\n definitionId?: string;\n input?: unknown;\n inputEnvelope?: WorkflowRunInputEnvelope;\n goal?: string;\n agentId?: string;\n parentSessionKey?: string;\n source?: WorkflowRunSource;\n concurrency?: number;\n maxSubagents?: number;\n tokenBudget?: number | null;\n idempotencyKey?: string;\n}\n\ninterface SaveWorkflowDefinitionRequestBody {\n name?: string;\n script?: string;\n}\n\nexport function registerWorkflowRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n const workflowRunService = service.createWorkflowRunService();\n\n authenticated.get('/api/workflows/definitions', (c) => {\n const catalog = createWorkflowCatalog();\n const definitions = catalog.list().map((entry) => {\n try {\n return toWorkflowDefinition(catalog.load(entry.name));\n } catch {\n return null;\n }\n }).filter((definition): definition is WorkflowDefinition => Boolean(definition));\n\n return c.json({ definitions });\n });\n\n authenticated.get('/api/workflows/definitions/:id', (c) => {\n const id = c.req.param('id');\n const catalog = createWorkflowCatalog();\n try {\n const definition = toWorkflowDefinition(catalog.load(id));\n return c.json({ definition });\n } catch (err) {\n return c.json({ error: err instanceof Error ? err.message : 'Workflow definition not found' }, 404);\n }\n });\n\n authenticated.post('/api/workflows/definitions/validate', async (c) => {\n const body = await readJsonBody<SaveWorkflowDefinitionRequestBody>(c.req.raw);\n const result = validateWorkflowDefinitionInput({\n name: body.name,\n script: body.script,\n });\n return c.json(result);\n });\n\n authenticated.post('/api/workflows/definitions', async (c) => {\n const body = await readJsonBody<SaveWorkflowDefinitionRequestBody>(c.req.raw);\n const validation = validateWorkflowDefinitionInput({\n name: body.name,\n script: body.script,\n });\n if (!validation.valid) {\n return c.json({ error: validation.errors[0]?.message ?? 'Invalid workflow definition', validation }, 400);\n }\n\n const name = body.name?.trim() ?? '';\n const script = body.script ?? '';\n const catalog = createWorkflowCatalog();\n try {\n catalog.save(name, script);\n const definition = toWorkflowDefinition(catalog.load(name));\n return c.json({ definition }, 201);\n } catch (err) {\n return c.json({ error: err instanceof Error ? err.message : 'Failed to save workflow' }, 400);\n }\n });\n\n authenticated.delete('/api/workflows/definitions/:id', (c) => {\n const id = c.req.param('id').trim();\n if (!id) {\n return c.json({ error: 'id is required' }, 400);\n }\n\n const catalog = createWorkflowCatalog();\n try {\n const removed = catalog.remove(id);\n if (!removed) {\n return c.json({ error: 'User workflow not found or cannot delete built-in workflow' }, 404);\n }\n return c.json({ removed: true });\n } catch (err) {\n return c.json({ error: err instanceof Error ? err.message : 'Failed to delete workflow' }, 400);\n }\n });\n\n authenticated.get('/api/workflows/stats', async (c) => {\n const agentId = getAgentId(c.req.query('agentId'), service.currentConfig);\n const definitionId = c.req.query('definitionId')?.trim();\n const runStore = workflowRunService.createRunStore(agentId);\n const runs = await runStore.listRunSummaries(500);\n const filteredRuns = definitionId ? runs.filter((run) => run.definitionId === definitionId) : runs;\n return c.json({ stats: buildWorkflowStats(filteredRuns) });\n });\n\n authenticated.post('/api/workflows/runs', async (c) => {\n const body = await readJsonBody<StartWorkflowRunRequestBody>(c.req.raw);\n const definitionId = body.definitionId?.trim();\n if (!definitionId) {\n return c.json({ error: 'definitionId is required' }, 400);\n }\n\n const agentId = getAgentId(body.agentId ?? c.req.query('agentId'), service.currentConfig);\n const parentSessionKey = body.parentSessionKey?.trim() || undefined;\n const result = await workflowRunService.startWorkflowRun({\n agentId,\n definitionId,\n input: body.input,\n inputEnvelope: body.inputEnvelope,\n goal: body.goal,\n parentSessionKey,\n source: normalizeWorkflowRunSource(body.source),\n concurrency: normalizePositiveInteger(body.concurrency),\n maxSubagents: normalizePositiveInteger(body.maxSubagents),\n tokenBudget: body.tokenBudget,\n idempotencyKey: body.idempotencyKey,\n });\n\n if (result.ok === false) {\n return c.json({ error: result.message, code: result.code }, result.httpStatus);\n }\n\n return c.json({ runId: result.runId, sessionKey: result.sessionKey }, 202);\n });\n\n authenticated.get('/api/workflows/runs', async (c) => {\n const agentId = getAgentId(c.req.query('agentId'), service.currentConfig);\n const rawLimit = c.req.query('limit');\n const limit = rawLimit ? Number.parseInt(rawLimit, 10) : 50;\n const runStore = workflowRunService.createRunStore(agentId);\n const runs = await runStore.listRunSummaries(Number.isFinite(limit) ? limit : 50);\n return c.json({ runs });\n });\n\n authenticated.post('/api/workflows/runs/:runId/cancel', async (c) => {\n const runId = c.req.param('runId');\n const agentId = getAgentId(c.req.query('agentId'), service.currentConfig);\n const result = await workflowRunService.cancelWorkflowRun({\n agentId,\n runId,\n reason: 'Cancelled by user',\n });\n if (result.ok === false) {\n return c.json({ error: result.message, code: result.code }, result.httpStatus);\n }\n return c.json({\n cancelled: result.cancelled,\n alreadyFinished: result.alreadyFinished,\n });\n });\n\n authenticated.get('/api/workflows/runs/:runId', async (c) => {\n const agentId = getAgentId(c.req.query('agentId'), service.currentConfig);\n const runId = c.req.param('runId');\n const runStore = workflowRunService.createRunStore(agentId);\n const view = await runStore.readRunView(runId);\n if (!view) {\n return c.json({ error: 'Workflow run not found' }, 404);\n }\n return c.json({ view });\n });\n\n authenticated.post('/api/workflows/runs/:runId/rebuild', async (c) => {\n const agentId = getAgentId(c.req.query('agentId'), service.currentConfig);\n const runId = c.req.param('runId');\n const runStore = workflowRunService.createRunStore(agentId);\n const view = await runStore.rebuildRunView(runId);\n if (!view) {\n return c.json({ error: 'Workflow run not found' }, 404);\n }\n service.emit('workflow.run.updated', { runId, view });\n return c.json({ view });\n });\n\n authenticated.post('/api/workflows/runs/:runId/retry', async (c) => {\n const agentId = getAgentId(c.req.query('agentId'), service.currentConfig);\n const runId = c.req.param('runId');\n const result = await workflowRunService.retryWorkflowRun({ agentId, runId });\n if (result.ok === false) {\n return c.json({ error: result.message, code: result.code }, result.httpStatus);\n }\n\n return c.json({ runId: result.runId, sessionKey: result.sessionKey }, 202);\n });\n}\n\nfunction getAgentId(rawAgentId: string | undefined, config: AuthenticatedRouteDeps['service']['currentConfig']): string {\n const trimmed = rawAgentId?.trim();\n if (trimmed) {\n return trimmed;\n }\n return resolveDefaultAgentId(config);\n}\n\nfunction toWorkflowDefinition(loaded: ReturnType<ReturnType<typeof createWorkflowCatalog>['load']>): WorkflowDefinition {\n return buildWorkflowDefinition({\n name: loaded.name,\n source: loaded.source,\n script: loaded.script,\n meta: loaded.meta,\n });\n}\n\nfunction buildWorkflowStats(runs: WorkflowRunSummary[]): {\n totalRuns: number;\n activeRuns: number;\n succeededRuns: number;\n failedRuns: number;\n averageDurationMs: number | null;\n topDefinitions: Array<{ definitionId: string; count: number }>;\n} {\n const activeStatuses = new Set(['queued', 'running']);\n const succeededStatuses = new Set(['succeeded']);\n const failedStatuses = new Set(['failed', 'timeout', 'cancelled']);\n\n let durationTotal = 0;\n let durationCount = 0;\n const definitionCounts = new Map<string, number>();\n\n for (const run of runs) {\n definitionCounts.set(run.definitionId, (definitionCounts.get(run.definitionId) ?? 0) + 1);\n if (run.metrics.durationMs != null && Number.isFinite(run.metrics.durationMs)) {\n durationTotal += run.metrics.durationMs;\n durationCount += 1;\n }\n }\n\n const topDefinitions = [...definitionCounts.entries()]\n .sort((left, right) => right[1] - left[1])\n .slice(0, 5)\n .map(([definitionId, count]) => ({ definitionId, count }));\n\n return {\n totalRuns: runs.length,\n activeRuns: runs.filter((run) => activeStatuses.has(run.status)).length,\n succeededRuns: runs.filter((run) => succeededStatuses.has(run.status)).length,\n failedRuns: runs.filter((run) => failedStatuses.has(run.status)).length,\n averageDurationMs: durationCount > 0 ? Math.round(durationTotal / durationCount) : null,\n topDefinitions,\n };\n}\n\nasync function readJsonBody<T>(request: Request): Promise<T> {\n try {\n return await request.json() as T;\n } catch {\n return {} as T;\n }\n}\n\nfunction normalizeWorkflowRunSource(source: WorkflowRunSource | undefined): WorkflowRunSource {\n if (!source) {\n return { kind: 'webui' };\n }\n return source;\n}\n\nfunction normalizePositiveInteger(value: number | undefined): number | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 1) {\n return undefined;\n }\n return Math.floor(value);\n}\n\n"],"mappings":"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"}
@@ -1,10 +1,12 @@
1
1
  import { resolveGatewayBindHost, resolveGatewayListenHosts } from "../config/gateway-bind.js";
2
+ import { ensureXopcCliOnPath } from "../infra/path-env.js";
2
3
  import { resolveGatewayListenPlan } from "./listen.js";
3
4
  import { GatewayService } from "./service.js";
4
5
  import { handleSiteShareUpgrade } from "../share/site-share-router.js";
5
6
  import { createHonoApp } from "./hono/app.js";
6
7
  import { serve } from "@hono/node-server";
7
8
  //#region src/gateway/server.ts
9
+ ensureXopcCliOnPath();
8
10
  var GatewayServer = class {
9
11
  server;
10
12
  extraServers = [];
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","names":[],"sources":["../../../src/gateway/server.ts"],"sourcesContent":["import { serve, type ServerType } from '@hono/node-server';\nimport type { IncomingMessage } from 'node:http';\nimport type { Socket } from 'node:net';\n\nimport type { GatewayBindMode } from '../config/schema.js';\nimport { resolveGatewayBindHost, resolveGatewayListenHosts } from '../config/gateway-bind.js';\nimport { resolveGatewayListenPlan } from './listen.js';\nimport { GatewayService } from './service.js';\nimport { createHonoApp } from './hono/app.js';\nimport { handleSiteShareUpgrade } from '../share/site-share-router.js';\n\nexport interface GatewayServerConfig {\n port: number;\n /** Resolved listen address (sync plan); re-validated async at start when possible. */\n bindHost: string;\n bind?: GatewayBindMode;\n customBindHost?: string;\n token?: string;\n verbose?: boolean;\n configPath?: string;\n enableHotReload?: boolean;\n}\n\nexport class GatewayServer {\n private server?: ServerType;\n private extraServers: ServerType[] = [];\n private config: GatewayServerConfig;\n private service: GatewayService;\n\n constructor(config: GatewayServerConfig) {\n this.config = config;\n this.service = new GatewayService({\n configPath: config.configPath,\n enableHotReload: config.enableHotReload,\n deferChannelConnectUntilAfterHttp: true,\n listenBind: config.bind,\n listenCustomBindHost: config.customBindHost,\n listenPort: config.port,\n });\n }\n\n async start(): Promise<void> {\n const cfg = this.service.currentConfig;\n const plan = resolveGatewayListenPlan({\n cfg,\n bindOverride: this.config.bind,\n });\n\n let bindHost: string;\n try {\n bindHost = await resolveGatewayBindHost({\n bindMode: plan.bindMode,\n customBindHost: plan.customBindHost ?? this.config.customBindHost,\n });\n } catch (err) {\n bindHost = plan.bindHost;\n if (plan.bindMode === 'custom') {\n throw err;\n }\n }\n\n if (plan.bindMode === 'custom') {\n const expected = plan.customBindHost?.trim();\n if (!expected || bindHost !== expected) {\n throw new Error(\n `gateway bind=custom requested ${expected ?? '(missing)'} but resolved ${bindHost}`,\n );\n }\n }\n\n const listenHosts = await resolveGatewayListenHosts(bindHost);\n console.log(`[GatewayServer] Starting gateway server on ${bindHost}:${this.config.port}...`);\n\n await this.service.start();\n this.service.registerGatewayShutdownForRestart(async () => {\n await this.stop();\n });\n\n const { configureTunnelFromGatewayConfig } = await import('../tunnel/gateway-lifecycle.js');\n await configureTunnelFromGatewayConfig(this.service.currentConfig, { deferWellKnownFetch: true });\n\n const effectiveToken = this.config.token || this.service.getAuthToken();\n const app = createHonoApp({\n service: this.service,\n token: effectiveToken,\n });\n\n const primaryHost = listenHosts[0] ?? bindHost;\n const attachUpgrade = (server: ServerType): void => {\n // `@hono/node-server`'s `serve()` returns the underlying `http.Server`.\n const inner = server as unknown as {\n on(event: 'upgrade', listener: (req: IncomingMessage, socket: Socket, head: Buffer) => void): void;\n };\n inner.on('upgrade', (req, socket, head) => {\n try {\n handleSiteShareUpgrade(this.service, req, socket, head);\n } catch (err) {\n console.error('[GatewayServer] site-share upgrade error:', err);\n try {\n socket.destroy();\n } catch {\n /* ignore */\n }\n }\n });\n };\n\n this.server = serve(\n {\n fetch: app.fetch,\n port: this.config.port,\n hostname: primaryHost,\n },\n () => {\n console.log(`[GatewayServer] Gateway server running at http://${primaryHost}:${this.config.port}`);\n this.service.markHttpListening();\n void this.service.onHttpListening().catch((err) => {\n console.error('[GatewayServer] Deferred channel startup failed:', err);\n });\n },\n );\n attachUpgrade(this.server);\n\n for (const aliasHost of listenHosts.slice(1)) {\n const extra = serve({\n fetch: app.fetch,\n port: this.config.port,\n hostname: aliasHost,\n });\n attachUpgrade(extra);\n this.extraServers.push(extra);\n }\n }\n\n async close(opts?: { reason?: string; restartExpectedMs?: number | null }): Promise<void> {\n const reason = opts?.reason ?? 'gateway stopping';\n console.log(`[GatewayServer] Closing gateway server: ${reason}`);\n await this.stop();\n }\n\n async stop(): Promise<void> {\n console.log('[GatewayServer] Stopping gateway server...');\n\n const closeServer = async (server: ServerType | undefined) => {\n if (!server) {\n return;\n }\n const forceClose = setTimeout(() => {\n (server as { closeAllConnections?: () => void }).closeAllConnections?.();\n }, 2000);\n await new Promise<void>((resolve) => {\n server.close(() => {\n clearTimeout(forceClose);\n resolve();\n });\n });\n };\n\n await closeServer(this.server);\n this.server = undefined;\n\n for (const extra of this.extraServers) {\n await closeServer(extra);\n }\n this.extraServers = [];\n\n await this.service.stop();\n\n console.log('[GatewayServer] Gateway server stopped');\n }\n\n get isRunning(): boolean {\n return this.server !== undefined;\n }\n\n get serviceInstance(): GatewayService {\n return this.service;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.js","names":[],"sources":["../../../src/gateway/server.ts"],"sourcesContent":["import { serve, type ServerType } from '@hono/node-server';\nimport type { IncomingMessage } from 'node:http';\nimport type { Socket } from 'node:net';\n\nimport { ensureXopcCliOnPath } from '../infra/path-env.js';\n\nensureXopcCliOnPath();\n\nimport type { GatewayBindMode } from '../config/schema.js';\nimport { resolveGatewayBindHost, resolveGatewayListenHosts } from '../config/gateway-bind.js';\nimport { resolveGatewayListenPlan } from './listen.js';\nimport { GatewayService } from './service.js';\nimport { createHonoApp } from './hono/app.js';\nimport { handleSiteShareUpgrade } from '../share/site-share-router.js';\n\nexport interface GatewayServerConfig {\n port: number;\n /** Resolved listen address (sync plan); re-validated async at start when possible. */\n bindHost: string;\n bind?: GatewayBindMode;\n customBindHost?: string;\n token?: string;\n verbose?: boolean;\n configPath?: string;\n enableHotReload?: boolean;\n}\n\nexport class GatewayServer {\n private server?: ServerType;\n private extraServers: ServerType[] = [];\n private config: GatewayServerConfig;\n private service: GatewayService;\n\n constructor(config: GatewayServerConfig) {\n this.config = config;\n this.service = new GatewayService({\n configPath: config.configPath,\n enableHotReload: config.enableHotReload,\n deferChannelConnectUntilAfterHttp: true,\n listenBind: config.bind,\n listenCustomBindHost: config.customBindHost,\n listenPort: config.port,\n });\n }\n\n async start(): Promise<void> {\n const cfg = this.service.currentConfig;\n const plan = resolveGatewayListenPlan({\n cfg,\n bindOverride: this.config.bind,\n });\n\n let bindHost: string;\n try {\n bindHost = await resolveGatewayBindHost({\n bindMode: plan.bindMode,\n customBindHost: plan.customBindHost ?? this.config.customBindHost,\n });\n } catch (err) {\n bindHost = plan.bindHost;\n if (plan.bindMode === 'custom') {\n throw err;\n }\n }\n\n if (plan.bindMode === 'custom') {\n const expected = plan.customBindHost?.trim();\n if (!expected || bindHost !== expected) {\n throw new Error(\n `gateway bind=custom requested ${expected ?? '(missing)'} but resolved ${bindHost}`,\n );\n }\n }\n\n const listenHosts = await resolveGatewayListenHosts(bindHost);\n console.log(`[GatewayServer] Starting gateway server on ${bindHost}:${this.config.port}...`);\n\n await this.service.start();\n this.service.registerGatewayShutdownForRestart(async () => {\n await this.stop();\n });\n\n const { configureTunnelFromGatewayConfig } = await import('../tunnel/gateway-lifecycle.js');\n await configureTunnelFromGatewayConfig(this.service.currentConfig, { deferWellKnownFetch: true });\n\n const effectiveToken = this.config.token || this.service.getAuthToken();\n const app = createHonoApp({\n service: this.service,\n token: effectiveToken,\n });\n\n const primaryHost = listenHosts[0] ?? bindHost;\n const attachUpgrade = (server: ServerType): void => {\n // `@hono/node-server`'s `serve()` returns the underlying `http.Server`.\n const inner = server as unknown as {\n on(event: 'upgrade', listener: (req: IncomingMessage, socket: Socket, head: Buffer) => void): void;\n };\n inner.on('upgrade', (req, socket, head) => {\n try {\n handleSiteShareUpgrade(this.service, req, socket, head);\n } catch (err) {\n console.error('[GatewayServer] site-share upgrade error:', err);\n try {\n socket.destroy();\n } catch {\n /* ignore */\n }\n }\n });\n };\n\n this.server = serve(\n {\n fetch: app.fetch,\n port: this.config.port,\n hostname: primaryHost,\n },\n () => {\n console.log(`[GatewayServer] Gateway server running at http://${primaryHost}:${this.config.port}`);\n this.service.markHttpListening();\n void this.service.onHttpListening().catch((err) => {\n console.error('[GatewayServer] Deferred channel startup failed:', err);\n });\n },\n );\n attachUpgrade(this.server);\n\n for (const aliasHost of listenHosts.slice(1)) {\n const extra = serve({\n fetch: app.fetch,\n port: this.config.port,\n hostname: aliasHost,\n });\n attachUpgrade(extra);\n this.extraServers.push(extra);\n }\n }\n\n async close(opts?: { reason?: string; restartExpectedMs?: number | null }): Promise<void> {\n const reason = opts?.reason ?? 'gateway stopping';\n console.log(`[GatewayServer] Closing gateway server: ${reason}`);\n await this.stop();\n }\n\n async stop(): Promise<void> {\n console.log('[GatewayServer] Stopping gateway server...');\n\n const closeServer = async (server: ServerType | undefined) => {\n if (!server) {\n return;\n }\n const forceClose = setTimeout(() => {\n (server as { closeAllConnections?: () => void }).closeAllConnections?.();\n }, 2000);\n await new Promise<void>((resolve) => {\n server.close(() => {\n clearTimeout(forceClose);\n resolve();\n });\n });\n };\n\n await closeServer(this.server);\n this.server = undefined;\n\n for (const extra of this.extraServers) {\n await closeServer(extra);\n }\n this.extraServers = [];\n\n await this.service.stop();\n\n console.log('[GatewayServer] Gateway server stopped');\n }\n\n get isRunning(): boolean {\n return this.server !== undefined;\n }\n\n get serviceInstance(): GatewayService {\n return this.service;\n }\n}\n"],"mappings":";;;;;;;;AAMA,qBAAqB;AAqBrB,IAAa,gBAAb,MAA2B;CACzB;CACA,eAAqC,EAAE;CACvC;CACA;CAEA,YAAY,QAA6B;AACvC,OAAK,SAAS;AACd,OAAK,UAAU,IAAI,eAAe;GAChC,YAAY,OAAO;GACnB,iBAAiB,OAAO;GACxB,mCAAmC;GACnC,YAAY,OAAO;GACnB,sBAAsB,OAAO;GAC7B,YAAY,OAAO;GACpB,CAAC;;CAGJ,MAAM,QAAuB;EAC3B,MAAM,MAAM,KAAK,QAAQ;EACzB,MAAM,OAAO,yBAAyB;GACpC;GACA,cAAc,KAAK,OAAO;GAC3B,CAAC;EAEF,IAAI;AACJ,MAAI;AACF,cAAW,MAAM,uBAAuB;IACtC,UAAU,KAAK;IACf,gBAAgB,KAAK,kBAAkB,KAAK,OAAO;IACpD,CAAC;WACK,KAAK;AACZ,cAAW,KAAK;AAChB,OAAI,KAAK,aAAa,SACpB,OAAM;;AAIV,MAAI,KAAK,aAAa,UAAU;GAC9B,MAAM,WAAW,KAAK,gBAAgB,MAAM;AAC5C,OAAI,CAAC,YAAY,aAAa,SAC5B,OAAM,IAAI,MACR,iCAAiC,YAAY,YAAY,gBAAgB,WAC1E;;EAIL,MAAM,cAAc,MAAM,0BAA0B,SAAS;AAC7D,UAAQ,IAAI,8CAA8C,SAAS,GAAG,KAAK,OAAO,KAAK,KAAK;AAE5F,QAAM,KAAK,QAAQ,OAAO;AAC1B,OAAK,QAAQ,kCAAkC,YAAY;AACzD,SAAM,KAAK,MAAM;IACjB;EAEF,MAAM,EAAE,qCAAqC,MAAM,OAAO;AAC1D,QAAM,iCAAiC,KAAK,QAAQ,eAAe,EAAE,qBAAqB,MAAM,CAAC;EAEjG,MAAM,iBAAiB,KAAK,OAAO,SAAS,KAAK,QAAQ,cAAc;EACvE,MAAM,MAAM,cAAc;GACxB,SAAS,KAAK;GACd,OAAO;GACR,CAAC;EAEF,MAAM,cAAc,YAAY,MAAM;EACtC,MAAM,iBAAiB,WAA6B;AAKlD,UAAM,GAAG,YAAY,KAAK,QAAQ,SAAS;AACzC,QAAI;AACF,4BAAuB,KAAK,SAAS,KAAK,QAAQ,KAAK;aAChD,KAAK;AACZ,aAAQ,MAAM,6CAA6C,IAAI;AAC/D,SAAI;AACF,aAAO,SAAS;aACV;;KAIV;;AAGJ,OAAK,SAAS,MACZ;GACE,OAAO,IAAI;GACX,MAAM,KAAK,OAAO;GAClB,UAAU;GACX,QACK;AACJ,WAAQ,IAAI,oDAAoD,YAAY,GAAG,KAAK,OAAO,OAAO;AAClG,QAAK,QAAQ,mBAAmB;AAC3B,QAAK,QAAQ,iBAAiB,CAAC,OAAO,QAAQ;AACjD,YAAQ,MAAM,oDAAoD,IAAI;KACtE;IAEL;AACD,gBAAc,KAAK,OAAO;AAE1B,OAAK,MAAM,aAAa,YAAY,MAAM,EAAE,EAAE;GAC5C,MAAM,QAAQ,MAAM;IAClB,OAAO,IAAI;IACX,MAAM,KAAK,OAAO;IAClB,UAAU;IACX,CAAC;AACF,iBAAc,MAAM;AACpB,QAAK,aAAa,KAAK,MAAM;;;CAIjC,MAAM,MAAM,MAA8E;EACxF,MAAM,SAAS,MAAM,UAAU;AAC/B,UAAQ,IAAI,2CAA2C,SAAS;AAChE,QAAM,KAAK,MAAM;;CAGnB,MAAM,OAAsB;AAC1B,UAAQ,IAAI,6CAA6C;EAEzD,MAAM,cAAc,OAAO,WAAmC;AAC5D,OAAI,CAAC,OACH;GAEF,MAAM,aAAa,iBAAiB;AACjC,WAAgD,uBAAuB;MACvE,IAAK;AACR,SAAM,IAAI,SAAe,YAAY;AACnC,WAAO,YAAY;AACjB,kBAAa,WAAW;AACxB,cAAS;MACT;KACF;;AAGJ,QAAM,YAAY,KAAK,OAAO;AAC9B,OAAK,SAAS,KAAA;AAEd,OAAK,MAAM,SAAS,KAAK,aACvB,OAAM,YAAY,MAAM;AAE1B,OAAK,eAAe,EAAE;AAEtB,QAAM,KAAK,QAAQ,MAAM;AAEzB,UAAQ,IAAI,yCAAyC;;CAGvD,IAAI,YAAqB;AACvB,SAAO,KAAK,WAAW,KAAA;;CAGzB,IAAI,kBAAkC;AACpC,SAAO,KAAK"}
@@ -1,6 +1,7 @@
1
1
  import { AgentService } from '../agent/service.js';
2
2
  import { MessageBus } from '../infra/bus/index.js';
3
3
  import { CronService } from '../cron/index.js';
4
+ import { WorkflowRunService } from '../workflows/service/workflow-run-service.js';
4
5
  import { ExtensionLoader } from '../extensions/index.js';
5
6
  import { SessionIndex } from '../session/index.js';
6
7
  import type { Config } from '../config/schema.js';
@@ -43,6 +44,8 @@ export declare class GatewayService {
43
44
  private lastChannelConnectDeferSource;
44
45
  private readonly readiness;
45
46
  private startupTrace;
47
+ private workflowSessionBridge;
48
+ private workflowRunServiceInstance;
46
49
  /**
47
50
  * Webchat agent invocation surface (`runAgent`, `abortAgentRun`, `steer*`,
48
51
  * `submitClarifyResponse`, clarify-bridge dispatch). Owns the
@@ -216,6 +219,8 @@ export declare class GatewayService {
216
219
  getEffectiveListenPort(): number;
217
220
  get cronServiceInstance(): CronService;
218
221
  get sessionIndexInstance(): SessionIndex;
222
+ /** Shared workflow run orchestrator + session bridge (one instance per gateway). */
223
+ createWorkflowRunService(): WorkflowRunService;
219
224
  /** Process a message directly through the agent (for CLI mode). */
220
225
  processDirect(content: string, sessionKey?: string): Promise<string>;
221
226
  subscribe(sessionId: string, listener: (event: ServiceEvent) => Promise<void> | void): () => void;