@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.
- package/README.md +8 -1
- package/README.zh-CN.md +8 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/agents-cPvvYLXo.js +222 -0
- package/dist/gateway/static/root/assets/apps-page-Bk1_P5FJ.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-CZoeQwHz.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-DIsl75Y3.js → channels-status-swr-BrtH2VzC.js} +1 -1
- package/dist/gateway/static/root/assets/circle-check-C23XjkUj.js +1 -0
- package/dist/gateway/static/root/assets/cron-api-CyqbgfHM.js +1 -0
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-Ip703-qM.js +2 -0
- package/dist/gateway/static/root/assets/cron-page-BpLdiQN8.js +1 -0
- package/dist/gateway/static/root/assets/dist-BpAiK86n.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-BVJohZoZ.js → extension-debug-page-D6Ak0STa.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BT2tmElC.js → extension-page-Q0P3d6DW.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BSS47c2j.js → extension-settings-page-CL55LwU_.js} +1 -1
- package/dist/gateway/static/root/assets/eye-DAfL1U7M.js +1 -0
- package/dist/gateway/static/root/assets/{fetch-BaFNUtkE.js → fetch-Dqa9iTWl.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-QwYEq6Hz.js → field-primitives-HUR6JElP.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-BVSidEDJ.js → heartbeat-config-api-DusckjUX.js} +1 -1
- package/dist/gateway/static/root/assets/{index-qNrVJp-y.js → index-BYcGfwcE.js} +97 -97
- package/dist/gateway/static/root/assets/index-V7MQ7834.css +1 -0
- package/dist/gateway/static/root/assets/{logs-page-DDonPVLn.js → logs-page-_HcZ2fgK.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-iezSMjho.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-B8N3A3Zo.js → settings-form-section-a0qGVOlr.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-C9_nYQwM.js +3 -0
- package/dist/gateway/static/root/assets/{share-preview-page-Q7KqkO-u.js → share-preview-page-DExl7CJy.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page-BlgGD93t.js +2 -0
- package/dist/gateway/static/root/assets/{theme-store-BbRc5ugR.js → theme-store-C0Ehmdo5.js} +1 -1
- package/dist/gateway/static/root/assets/url-fxyYANfA.js +3 -0
- package/dist/gateway/static/root/assets/{utils-CxDGduqK.js → utils-DRQryzdn.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-D0viACE2.js +1 -0
- package/dist/gateway/static/root/assets/workflow-page.utils-DnG8JBhV.js +1 -0
- package/dist/gateway/static/root/assets/workflows-page-BvMobnJP.js +27 -0
- package/dist/gateway/static/root/index.html +7 -6
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +2 -0
- package/dist/src/agent/agent-manager.js +1 -0
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/service.js +2 -1
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +3 -1
- package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js +20 -18
- package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js.map +1 -1
- package/dist/src/agent/tools/cronjob-tool.d.ts +6 -0
- package/dist/src/agent/tools/cronjob-tool.js +76 -10
- package/dist/src/agent/tools/cronjob-tool.js.map +1 -1
- package/dist/src/agent/tools/edit.d.ts +5 -1
- package/dist/src/agent/tools/edit.js +7 -5
- package/dist/src/agent/tools/edit.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +3 -0
- package/dist/src/agent/tools/factory.js +4 -25
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/workflow-tool.d.ts +6 -28
- package/dist/src/agent/tools/workflow-tool.js +60 -260
- package/dist/src/agent/tools/workflow-tool.js.map +1 -1
- package/dist/src/agent/tools/write.d.ts +5 -1
- package/dist/src/agent/tools/write.js +7 -5
- package/dist/src/agent/tools/write.js.map +1 -1
- package/dist/src/agent/workflow/agent-progress.js +2 -0
- package/dist/src/agent/workflow/agent-progress.js.map +1 -1
- package/dist/src/agent/workflow/builtins/client-proposal.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/client-proposal.js +155 -0
- package/dist/src/agent/workflow/builtins/client-proposal.js.map +1 -0
- package/dist/src/agent/workflow/builtins/competitor-scan.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/competitor-scan.js +150 -0
- package/dist/src/agent/workflow/builtins/competitor-scan.js.map +1 -0
- package/dist/src/agent/workflow/builtins/content-draft.d.ts +13 -0
- package/dist/src/agent/workflow/builtins/content-draft.js +146 -0
- package/dist/src/agent/workflow/builtins/content-draft.js.map +1 -0
- package/dist/src/agent/workflow/builtins/content-repurpose.d.ts +11 -0
- package/dist/src/agent/workflow/builtins/content-repurpose.js +137 -0
- package/dist/src/agent/workflow/builtins/content-repurpose.js.map +1 -0
- package/dist/src/agent/workflow/builtins/decision-compare.d.ts +13 -0
- package/dist/src/agent/workflow/builtins/decision-compare.js +173 -0
- package/dist/src/agent/workflow/builtins/decision-compare.js.map +1 -0
- package/dist/src/agent/workflow/builtins/inbox-triage.d.ts +11 -0
- package/dist/src/agent/workflow/builtins/inbox-triage.js +148 -0
- package/dist/src/agent/workflow/builtins/inbox-triage.js.map +1 -0
- package/dist/src/agent/workflow/builtins/index.d.ts +10 -1
- package/dist/src/agent/workflow/builtins/index.js +46 -1
- package/dist/src/agent/workflow/builtins/index.js.map +1 -1
- package/dist/src/agent/workflow/builtins/meeting-prep.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/meeting-prep.js +144 -0
- package/dist/src/agent/workflow/builtins/meeting-prep.js.map +1 -0
- package/dist/src/agent/workflow/builtins/offer-design.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/offer-design.js +161 -0
- package/dist/src/agent/workflow/builtins/offer-design.js.map +1 -0
- package/dist/src/agent/workflow/builtins/weekly-review.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/weekly-review.js +131 -0
- package/dist/src/agent/workflow/builtins/weekly-review.js.map +1 -0
- package/dist/src/agent/workflow/step-labels.js +2 -2
- package/dist/src/agent/workflow/step-labels.js.map +1 -1
- package/dist/src/agent/workflow/subagent-runner.js +3 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/agent/workflow/types.d.ts +4 -0
- package/dist/src/agent/workflow/workflow-child-tools.d.ts +4 -0
- package/dist/src/agent/workflow/workflow-child-tools.js +21 -0
- package/dist/src/agent/workflow/workflow-child-tools.js.map +1 -0
- package/dist/src/auth/credentials.d.ts +14 -2
- package/dist/src/auth/credentials.js +38 -13
- package/dist/src/auth/credentials.js.map +1 -1
- package/dist/src/auth/oauth/types.d.ts +16 -0
- package/dist/src/chat-commands/agent-edit.d.ts +4 -0
- package/dist/src/chat-commands/agent-edit.js +136 -0
- package/dist/src/chat-commands/agent-edit.js.map +1 -0
- package/dist/src/chat-commands/index.d.ts +1 -0
- package/dist/src/chat-commands/index.js +3 -1
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/cli/bin.js +2 -0
- package/dist/src/cli/bin.js.map +1 -1
- package/dist/src/cli/commands/auth.js +6 -0
- package/dist/src/cli/commands/auth.js.map +1 -1
- package/dist/src/cli/commands/cron.js +42 -3
- package/dist/src/cli/commands/cron.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +79 -56
- package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
- package/dist/src/cli/commands/onboard/model.js +6 -0
- package/dist/src/cli/commands/onboard/model.js.map +1 -1
- package/dist/src/cli/commands/update.js +86 -79
- package/dist/src/cli/commands/update.js.map +1 -1
- package/dist/src/commands/agents.config.d.ts +3 -2
- package/dist/src/commands/agents.config.js +5 -2
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-typed-models.d.ts +2 -7
- package/dist/src/config/agent-typed-models.js +3 -14
- package/dist/src/config/agent-typed-models.js.map +1 -1
- package/dist/src/config/localized-text.d.ts +6 -0
- package/dist/src/config/localized-text.js +42 -0
- package/dist/src/config/localized-text.js.map +1 -0
- package/dist/src/config/models-json.d.ts +6 -6
- package/dist/src/config/schema.d.ts +6 -21
- package/dist/src/config/schema.js +4 -4
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/cron/executor.d.ts +4 -0
- package/dist/src/cron/executor.js +169 -5
- package/dist/src/cron/executor.js.map +1 -1
- package/dist/src/cron/job-content.js +2 -1
- package/dist/src/cron/job-content.js.map +1 -1
- package/dist/src/cron/types.d.ts +28 -1
- package/dist/src/cron/validation.d.ts +80 -0
- package/dist/src/cron/validation.js +30 -4
- package/dist/src/cron/validation.js.map +1 -1
- package/dist/src/cron/workflow-run-completion.d.ts +23 -0
- package/dist/src/cron/workflow-run-completion.js +72 -0
- package/dist/src/cron/workflow-run-completion.js.map +1 -0
- package/dist/src/extensions/update.d.ts +51 -0
- package/dist/src/extensions/update.js +260 -0
- package/dist/src/extensions/update.js.map +1 -0
- package/dist/src/gateway/agents-admin.d.ts +15 -8
- package/dist/src/gateway/agents-admin.js +77 -28
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/gateway-workflow-host.types.d.ts +17 -0
- package/dist/src/gateway/gateway-workflow-host.types.js +1 -0
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +5 -0
- package/dist/src/gateway/hono/lib/config-payload.js +2 -1
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/middleware/auth.d.ts +2 -0
- package/dist/src/gateway/hono/middleware/auth.js +12 -7
- package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
- package/dist/src/gateway/hono/oauth-async.js +40 -15
- package/dist/src/gateway/hono/oauth-async.js.map +1 -1
- package/dist/src/gateway/hono/oauth.js +31 -6
- package/dist/src/gateway/hono/oauth.js.map +1 -1
- package/dist/src/gateway/hono/routes/agents.js +55 -12
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/agents.js +1 -1
- package/dist/src/gateway/hono/routes/models.js +11 -5
- package/dist/src/gateway/hono/routes/models.js.map +1 -1
- package/dist/src/gateway/hono/routes/update.js +55 -107
- package/dist/src/gateway/hono/routes/update.js.map +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +72 -191
- package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
- package/dist/src/gateway/server.js +2 -0
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/service.d.ts +5 -0
- package/dist/src/gateway/service.js +24 -3
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/brew.d.ts +4 -0
- package/dist/src/infra/brew.js +20 -0
- package/dist/src/infra/brew.js.map +1 -0
- package/dist/src/infra/package-json.d.ts +2 -0
- package/dist/src/infra/package-json.js +23 -0
- package/dist/src/infra/package-json.js.map +1 -0
- package/dist/src/infra/package-update-steps.d.ts +35 -0
- package/dist/src/infra/package-update-steps.js +304 -0
- package/dist/src/infra/package-update-steps.js.map +1 -0
- package/dist/src/infra/path-env.d.ts +11 -0
- package/dist/src/infra/path-env.js +90 -0
- package/dist/src/infra/path-env.js.map +1 -0
- package/dist/src/infra/path-prepend.d.ts +7 -0
- package/dist/src/infra/path-prepend.js +44 -0
- package/dist/src/infra/path-prepend.js.map +1 -0
- package/dist/src/infra/stable-node-path.d.ts +2 -0
- package/dist/src/infra/stable-node-path.js +28 -0
- package/dist/src/infra/stable-node-path.js.map +1 -0
- package/dist/src/infra/update-global.d.ts +30 -23
- package/dist/src/infra/update-global.js +113 -64
- package/dist/src/infra/update-global.js.map +1 -1
- package/dist/src/infra/update-log.d.ts +1 -0
- package/dist/src/infra/update-log.js +12 -0
- package/dist/src/infra/update-log.js.map +1 -0
- package/dist/src/infra/update-restart.d.ts +20 -0
- package/dist/src/infra/update-restart.js +165 -0
- package/dist/src/infra/update-restart.js.map +1 -0
- package/dist/src/infra/update-runner.d.ts +89 -1
- package/dist/src/infra/update-runner.js +604 -173
- package/dist/src/infra/update-runner.js.map +1 -1
- package/dist/src/infra/update-startup.d.ts +3 -0
- package/dist/src/infra/update-startup.js +8 -4
- package/dist/src/infra/update-startup.js.map +1 -1
- package/dist/src/providers/index.d.ts +8 -0
- package/dist/src/providers/index.js +51 -12
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/routing/resolve-route.d.ts +3 -1
- package/dist/src/routing/resolve-route.js.map +1 -1
- package/dist/src/session/store.d.ts +5 -3
- package/dist/src/session/store.js +66 -20
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/share/site-share-config.d.ts +3 -2
- package/dist/src/share/site-share-config.js.map +1 -1
- package/dist/src/utils/logger/stats.d.ts +1 -1
- package/dist/src/workflows/domain/command.d.ts +2 -1
- package/dist/src/workflows/domain/definition-utils.d.ts +14 -0
- package/dist/src/workflows/domain/definition-utils.js +50 -0
- package/dist/src/workflows/domain/definition-utils.js.map +1 -0
- package/dist/src/workflows/domain/event.d.ts +3 -0
- package/dist/src/workflows/domain/index.d.ts +2 -0
- package/dist/src/workflows/domain/index.js +3 -1
- package/dist/src/workflows/domain/run.d.ts +60 -0
- package/dist/src/workflows/domain/run.js.map +1 -1
- package/dist/src/workflows/domain/validation.d.ts +19 -0
- package/dist/src/workflows/domain/validation.js +66 -0
- package/dist/src/workflows/domain/validation.js.map +1 -0
- package/dist/src/workflows/engine/projector.js +17 -0
- package/dist/src/workflows/engine/projector.js.map +1 -1
- package/dist/src/workflows/engine/workflow-engine.d.ts +2 -1
- package/dist/src/workflows/engine/workflow-engine.js +128 -0
- package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
- package/dist/src/workflows/index.d.ts +4 -0
- package/dist/src/workflows/index.js +9 -2
- package/dist/src/workflows/service/run-view-to-snapshot.d.ts +4 -0
- package/dist/src/workflows/service/run-view-to-snapshot.js +63 -0
- package/dist/src/workflows/service/run-view-to-snapshot.js.map +1 -0
- package/dist/src/workflows/service/workflow-run-service.d.ts +37 -0
- package/dist/src/workflows/service/workflow-run-service.js +282 -0
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -0
- package/dist/src/workflows/service/workflow-run-service.types.d.ts +47 -0
- package/dist/src/workflows/service/workflow-run-service.types.js +1 -0
- package/dist/src/workflows/service/workflow-session-bridge.d.ts +29 -0
- package/dist/src/workflows/service/workflow-session-bridge.js +177 -0
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -0
- package/dist/src/workflows/service/workflow-session-key.d.ts +3 -0
- package/dist/src/workflows/service/workflow-session-key.js +21 -0
- package/dist/src/workflows/service/workflow-session-key.js.map +1 -0
- package/dist/src/workflows/store/run-store.js +1 -0
- package/dist/src/workflows/store/run-store.js.map +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-CRxETUZx.js +0 -222
- package/dist/gateway/static/root/assets/apps-page-wKWf3l57.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-DDbqVNkx.js +0 -1
- package/dist/gateway/static/root/assets/copy-SxMW6Xpc.js +0 -1
- package/dist/gateway/static/root/assets/cron-api-N9hvuRrn.js +0 -1
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-DueM3rBz.js +0 -2
- package/dist/gateway/static/root/assets/cron-page-tlNGNxhP.js +0 -1
- package/dist/gateway/static/root/assets/dist-CJwfHYvT.js +0 -1
- package/dist/gateway/static/root/assets/index-CqZzHNEg.css +0 -1
- package/dist/gateway/static/root/assets/sessions-page-DKt-Wmib.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-DcJjvvw4.js +0 -3
- package/dist/gateway/static/root/assets/skills-page-DuJ4BTO3.js +0 -2
- package/dist/gateway/static/root/assets/url-D6jvVYIA.js +0 -7
- package/dist/gateway/static/root/assets/voice-api-key-field-CTyHz7L_.js +0 -1
- 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 {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
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
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
|
73
|
-
|
|
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
|
|
81
|
-
|
|
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
|
-
|
|
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 (
|
|
93
|
-
|
|
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(
|
|
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
|
|
106
|
-
|
|
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
|
-
|
|
121
|
-
payload: { reason: "Cancelled by user" }
|
|
120
|
+
reason: "Cancelled by user"
|
|
122
121
|
});
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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
|
-
|
|
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 (
|
|
163
|
-
|
|
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
|
-
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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":"
|
|
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":"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"}
|
|
@@ -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;
|