@hotmeshio/long-tail 0.1.6 → 0.1.8
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 +47 -5
- package/build/api/auth.d.ts +16 -0
- package/build/api/auth.js +53 -0
- package/build/api/bot-accounts.d.ts +137 -0
- package/build/api/bot-accounts.js +302 -0
- package/build/api/controlplane.d.ts +68 -0
- package/build/api/controlplane.js +158 -0
- package/build/api/dba.d.ts +42 -0
- package/build/api/dba.js +95 -0
- package/build/api/escalations.d.ts +271 -0
- package/build/api/escalations.js +892 -0
- package/build/api/exports.d.ts +90 -0
- package/build/api/exports.js +204 -0
- package/build/api/index.d.ts +18 -0
- package/build/api/index.js +54 -0
- package/build/api/insight.d.ts +86 -0
- package/build/api/insight.js +147 -0
- package/build/api/maintenance.d.ts +22 -0
- package/build/api/maintenance.js +43 -0
- package/build/api/mcp-runs.d.ts +43 -0
- package/build/api/mcp-runs.js +89 -0
- package/build/api/mcp.d.ts +160 -0
- package/build/api/mcp.js +320 -0
- package/build/api/namespaces.d.ts +20 -0
- package/build/{routes/escalations/helpers.js → api/namespaces.js} +35 -10
- package/build/api/roles.d.ts +88 -0
- package/build/api/roles.js +217 -0
- package/build/api/settings.d.ts +10 -0
- package/build/api/settings.js +43 -0
- package/build/api/tasks.d.ts +70 -0
- package/build/api/tasks.js +139 -0
- package/build/api/users.d.ts +115 -0
- package/build/api/users.js +228 -0
- package/build/api/workflow-sets.d.ts +77 -0
- package/build/api/workflow-sets.js +170 -0
- package/build/api/workflows.d.ts +158 -0
- package/build/api/workflows.js +407 -0
- package/build/api/yaml-workflows.d.ts +282 -0
- package/build/api/yaml-workflows.js +751 -0
- package/build/examples/types/envelopes.d.ts +27 -0
- package/build/examples/types/index.d.ts +1 -1
- package/build/examples/workers.js +8 -0
- package/build/examples/workflows/assembly-line/activities.d.ts +28 -0
- package/build/examples/workflows/assembly-line/activities.js +53 -0
- package/build/examples/workflows/assembly-line/index.d.ts +17 -0
- package/build/examples/workflows/assembly-line/index.js +60 -0
- package/build/examples/workflows/assembly-line/iterator.d.ts +12 -0
- package/build/examples/workflows/assembly-line/iterator.js +54 -0
- package/build/examples/workflows/assembly-line/reverter.d.ts +18 -0
- package/build/examples/workflows/assembly-line/reverter.js +89 -0
- package/build/examples/workflows/assembly-line/types.d.ts +25 -0
- package/build/examples/workflows/assembly-line/types.js +8 -0
- package/build/examples/workflows/assembly-line/worker.d.ts +13 -0
- package/build/examples/workflows/assembly-line/worker.js +81 -0
- package/build/index.d.ts +4 -0
- package/build/index.js +6 -1
- package/build/lib/db/schemas/004_workflow_sets.sql +29 -0
- package/build/lib/db/schemas/005_unique_graph_topic.sql +7 -0
- package/build/lib/db/schemas/011_system_workflow_configs.sql +7 -0
- package/build/lib/events/callback.d.ts +41 -0
- package/build/lib/events/callback.js +98 -0
- package/build/modules/config.js +1 -1
- package/build/routes/auth.js +37 -36
- package/build/routes/bot-accounts.js +34 -164
- package/build/routes/controlplane.js +20 -60
- package/build/routes/dba.js +18 -28
- package/build/routes/escalations/bulk.js +17 -192
- package/build/routes/escalations/list.js +51 -75
- package/build/routes/escalations/resolve.js +3 -193
- package/build/routes/escalations/single.js +13 -122
- package/build/routes/exports.js +44 -95
- package/build/routes/index.js +2 -0
- package/build/routes/insight.js +46 -88
- package/build/routes/maintenance.js +41 -17
- package/build/routes/mcp-runs.js +52 -60
- package/build/routes/mcp.js +49 -177
- package/build/routes/namespaces.js +9 -20
- package/build/routes/roles.js +23 -97
- package/build/routes/settings.js +37 -25
- package/build/routes/tasks.js +28 -64
- package/build/routes/users.js +24 -113
- package/build/routes/workflow-sets.d.ts +2 -0
- package/build/routes/workflow-sets.js +98 -0
- package/build/routes/workflows/config.js +23 -57
- package/build/routes/workflows/discovery.js +11 -85
- package/build/routes/workflows/invocation.js +28 -90
- package/build/routes/yaml-workflows/cron.js +12 -61
- package/build/routes/yaml-workflows/crud.js +30 -223
- package/build/routes/yaml-workflows/deployment.js +15 -115
- package/build/routes/yaml-workflows/versions.js +20 -58
- package/build/sdk/index.d.ts +338 -0
- package/build/sdk/index.js +299 -0
- package/build/services/controlplane/index.d.ts +1 -2
- package/build/services/controlplane/index.js +3 -3
- package/build/services/controlplane/sql.d.ts +2 -2
- package/build/services/controlplane/sql.js +4 -5
- package/build/services/controlplane/types.d.ts +1 -0
- package/build/services/export/index.js +6 -1
- package/build/services/hotmesh-utils.js +2 -4
- package/build/services/insight/index.d.ts +7 -0
- package/build/services/insight/index.js +30 -0
- package/build/services/mcp/client/tools.js +13 -1
- package/build/services/mcp-runs/sql.js +1 -1
- package/build/services/workflow-invocation.d.ts +15 -2
- package/build/services/workflow-invocation.js +11 -6
- package/build/services/workflow-sets/db.d.ts +16 -0
- package/build/services/workflow-sets/db.js +78 -0
- package/build/services/workflow-sets/index.d.ts +1 -0
- package/build/services/workflow-sets/index.js +11 -0
- package/build/services/workflow-sets/sql.d.ts +6 -0
- package/build/services/workflow-sets/sql.js +24 -0
- package/build/services/yaml-workflow/db-utils.d.ts +1 -0
- package/build/services/yaml-workflow/db-utils.js +4 -0
- package/build/services/yaml-workflow/db.d.ts +5 -0
- package/build/services/yaml-workflow/db.js +17 -0
- package/build/services/yaml-workflow/pipeline/build/wiring.js +14 -1
- package/build/services/yaml-workflow/pipeline/prompts.d.ts +1 -1
- package/build/services/yaml-workflow/pipeline/prompts.js +1 -1
- package/build/services/yaml-workflow/sql.d.ts +2 -1
- package/build/services/yaml-workflow/sql.js +8 -3
- package/build/services/yaml-workflow/types.d.ts +3 -0
- package/build/services/yaml-workflow/workers/callbacks.js +7 -1
- package/build/services/yaml-workflow/workers/register.js +7 -0
- package/build/start/adapters.js +4 -0
- package/build/system/index.js +6 -0
- package/build/system/mcp-servers/knowledge.js +1 -1
- package/build/system/seed/server-definitions.js +2 -1
- package/build/system/workflows/mcp-workflow-builder/activities/index.d.ts +1 -1
- package/build/system/workflows/mcp-workflow-builder/activities/index.js +2 -1
- package/build/system/workflows/mcp-workflow-builder/activities/tool-loader.d.ts +6 -0
- package/build/system/workflows/mcp-workflow-builder/activities/tool-loader.js +26 -0
- package/build/system/workflows/mcp-workflow-builder/index.js +26 -2
- package/build/system/workflows/mcp-workflow-builder/prompts.js +104 -35
- package/build/system/workflows/mcp-workflow-planner/activities/analyze.d.ts +11 -0
- package/build/system/workflows/mcp-workflow-planner/activities/analyze.js +36 -0
- package/build/system/workflows/mcp-workflow-planner/activities/index.d.ts +3 -0
- package/build/system/workflows/mcp-workflow-planner/activities/index.js +12 -0
- package/build/system/workflows/mcp-workflow-planner/activities/persist.d.ts +19 -0
- package/build/system/workflows/mcp-workflow-planner/activities/persist.js +55 -0
- package/build/system/workflows/mcp-workflow-planner/activities/plan.d.ts +10 -0
- package/build/system/workflows/mcp-workflow-planner/activities/plan.js +43 -0
- package/build/system/workflows/mcp-workflow-planner/index.d.ts +7 -0
- package/build/system/workflows/mcp-workflow-planner/index.js +152 -0
- package/build/system/workflows/mcp-workflow-planner/prompts.d.ts +7 -0
- package/build/system/workflows/mcp-workflow-planner/prompts.js +77 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/sdk.d.ts +27 -0
- package/build/types/sdk.js +2 -0
- package/build/types/workflow-set.d.ts +44 -0
- package/build/types/workflow-set.js +5 -0
- package/dashboard/dist/assets/{AdminDashboard-BXkKGkb5.js → AdminDashboard-B15jSEV2.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-BXkKGkb5.js.map → AdminDashboard-B15jSEV2.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-DcH592mc.js → AvailableEscalationsPage-0V2yvKak.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-DcH592mc.js.map → AvailableEscalationsPage-0V2yvKak.js.map} +1 -1
- package/dashboard/dist/assets/BotPicker-B4UxHcek.js +2 -0
- package/dashboard/dist/assets/{BotPicker-A6LtzyuO.js.map → BotPicker-B4UxHcek.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-C7nL2_mv.js → CollapsibleSection-BBexNWVd.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-C7nL2_mv.js.map → CollapsibleSection-BBexNWVd.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-CWFwJrSl.js → ConfirmDeleteModal-DlPDJSq_.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-CWFwJrSl.js.map → ConfirmDeleteModal-DlPDJSq_.js.map} +1 -1
- package/dashboard/dist/assets/{CopyableId-DbZ5c3jh.js → CopyableId-BxHW1ahb.js} +2 -2
- package/dashboard/dist/assets/{CopyableId-DbZ5c3jh.js.map → CopyableId-BxHW1ahb.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-ClWkmLPu.js → CredentialsPage-Bp_Y1Szk.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-ClWkmLPu.js.map → CredentialsPage-Bp_Y1Szk.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-CtH2hReF.js → CustomDurationPicker-ByBFqXSO.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-CtH2hReF.js.map → CustomDurationPicker-ByBFqXSO.js.map} +1 -1
- package/dashboard/dist/assets/{DataTable-CM5ZcpPi.js → DataTable-DyIXg-tQ.js} +2 -2
- package/dashboard/dist/assets/{DataTable-CM5ZcpPi.js.map → DataTable-DyIXg-tQ.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-CwqavyeC.js → ElapsedCell-BgnA0qpS.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-CwqavyeC.js.map → ElapsedCell-BgnA0qpS.js.map} +1 -1
- package/dashboard/dist/assets/{EmptyState-BBn78pmm.js → EmptyState-DlMImvgm.js} +2 -2
- package/dashboard/dist/assets/{EmptyState-BBn78pmm.js.map → EmptyState-DlMImvgm.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-BcJ2E3X7.js → EscalationsOverview-D90kdfw1.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-BcJ2E3X7.js.map → EscalationsOverview-D90kdfw1.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-C1en_KZ0.js → EventTable-BNxtlgNz.js} +2 -2
- package/dashboard/dist/assets/{EventTable-C1en_KZ0.js.map → EventTable-BNxtlgNz.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-CZTlrLQT.js → FilterBar-BTiaAhCx.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-CZTlrLQT.js.map → FilterBar-BTiaAhCx.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-Cdbsapig.js → ListToolbar-BUcagSCn.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-Cdbsapig.js.map → ListToolbar-BUcagSCn.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-CSpEJxKa.js → McpOverview-B-tCvz8C.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-CSpEJxKa.js.map → McpOverview-B-tCvz8C.js.map} +1 -1
- package/dashboard/dist/assets/McpQueryDetailPage-DPlF1wYb.js +5 -0
- package/dashboard/dist/assets/McpQueryDetailPage-DPlF1wYb.js.map +1 -0
- package/dashboard/dist/assets/McpQueryPage-Bz7AdcfR.js +2 -0
- package/dashboard/dist/assets/McpQueryPage-Bz7AdcfR.js.map +1 -0
- package/dashboard/dist/assets/{McpRunDetailPage-9xdxgG4d.js → McpRunDetailPage-Di_qpL2V.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-9xdxgG4d.js.map → McpRunDetailPage-Di_qpL2V.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-wWLqHsd4.js → McpRunsPage-BBgybBEa.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-wWLqHsd4.js.map → McpRunsPage-BBgybBEa.js.map} +1 -1
- package/dashboard/dist/assets/{Modal-kB_P7ZOr.js → Modal-CaJ0gTEa.js} +2 -2
- package/dashboard/dist/assets/{Modal-kB_P7ZOr.js.map → Modal-CaJ0gTEa.js.map} +1 -1
- package/dashboard/dist/assets/OperatorDashboard-DDfMmrmR.js +2 -0
- package/dashboard/dist/assets/{OperatorDashboard-jc0vrgDI.js.map → OperatorDashboard-DDfMmrmR.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-NkOeBR05.js → PageHeader-C5D-G5rp.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-NkOeBR05.js.map → PageHeader-C5D-G5rp.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-ywNhrmFK.js → PageHeaderWithStats-DCa2eZh2.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-ywNhrmFK.js.map → PageHeaderWithStats-DCa2eZh2.js.map} +1 -1
- package/dashboard/dist/assets/{PriorityBadge-B2MQbSxy.js → PriorityBadge-DTHq6OUZ.js} +2 -2
- package/dashboard/dist/assets/{PriorityBadge-B2MQbSxy.js.map → PriorityBadge-DTHq6OUZ.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-B7z7IdqE.js → ProcessDetailPage-fC4dhrd0.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-B7z7IdqE.js.map → ProcessDetailPage-fC4dhrd0.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-C-uHadO6.js → ProcessesListPage-CL2MY8uD.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-C-uHadO6.js.map → ProcessesListPage-CL2MY8uD.js.map} +1 -1
- package/dashboard/dist/assets/{RolePill-C1dgC-fK.js → RolePill-kgKPANly.js} +2 -2
- package/dashboard/dist/assets/{RolePill-C1dgC-fK.js.map → RolePill-kgKPANly.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-BSxrD1vm.js → RolesPage-Be2lXTHD.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-BSxrD1vm.js.map → RolesPage-Be2lXTHD.js.map} +1 -1
- package/dashboard/dist/assets/{RowActions-lYaHGI-v.js → RowActions-DIzJCwqR.js} +2 -2
- package/dashboard/dist/assets/{RowActions-lYaHGI-v.js.map → RowActions-DIzJCwqR.js.map} +1 -1
- package/dashboard/dist/assets/{StatCard-v2TiITVr.js → StatCard-CRi2Jy6t.js} +2 -2
- package/dashboard/dist/assets/{StatCard-v2TiITVr.js.map → StatCard-CRi2Jy6t.js.map} +1 -1
- package/dashboard/dist/assets/{StatusBadge-DWlxevgG.js → StatusBadge-BETI_8Mr.js} +2 -2
- package/dashboard/dist/assets/{StatusBadge-DWlxevgG.js.map → StatusBadge-BETI_8Mr.js.map} +1 -1
- package/dashboard/dist/assets/{StepIndicator-CRM4ft28.js → StepIndicator-DjpMqCjz.js} +2 -2
- package/dashboard/dist/assets/{StepIndicator-CRM4ft28.js.map → StepIndicator-DjpMqCjz.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-CF0EToEU.js → StickyPagination-BZbExQ9t.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-CF0EToEU.js.map → StickyPagination-BZbExQ9t.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-CNlj7fgg.js → SwimlaneTimeline-DZthQyhR.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-CNlj7fgg.js.map → SwimlaneTimeline-DZthQyhR.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-CH8qMGhC.js → TagInput-CukbOfYn.js} +2 -2
- package/dashboard/dist/assets/{TagInput-CH8qMGhC.js.map → TagInput-CukbOfYn.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-CdWo-6mu.js → TaskDetailPage-CIZHIKo9.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-CdWo-6mu.js.map → TaskDetailPage-CIZHIKo9.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-BPj4ogVG.js → TaskQueuePill-Q7DGoysj.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-BPj4ogVG.js.map → TaskQueuePill-Q7DGoysj.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CtRkMpKU.js → TasksListPage-CsC9wjb0.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CtRkMpKU.js.map → TasksListPage-CsC9wjb0.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-Di1a3X5P.js → TimeAgo-BcOOnJeH.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-Di1a3X5P.js.map → TimeAgo-BcOOnJeH.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-CqrXql-S.js → TimestampCell-CEMapYDQ.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-CqrXql-S.js.map → TimestampCell-CEMapYDQ.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-BUFYCnRa.js → UserName-BHoN7iRL.js} +2 -2
- package/dashboard/dist/assets/{UserName-BUFYCnRa.js.map → UserName-BHoN7iRL.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-25iusMml.js → WorkflowExecutionPage-DawKl1LT.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-25iusMml.js.map → WorkflowExecutionPage-DawKl1LT.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowPill-CP84Vqeg.js +2 -0
- package/dashboard/dist/assets/{WorkflowPill-DPKOcbf4.js.map → WorkflowPill-CP84Vqeg.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-BgxslssH.js → WorkflowsDashboard-QrvVFxtQ.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-BgxslssH.js.map → WorkflowsDashboard-QrvVFxtQ.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-Doe5L-Re.js → WorkflowsOverview-DuhAi_OY.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-Doe5L-Re.js.map → WorkflowsOverview-DuhAi_OY.js.map} +1 -1
- package/dashboard/dist/assets/YamlWorkflowsPage-Dc9xw82a.js +2 -0
- package/dashboard/dist/assets/YamlWorkflowsPage-Dc9xw82a.js.map +1 -0
- package/dashboard/dist/assets/{bots-Bi2_O1Ts.js → bots-Dny-rmmI.js} +2 -2
- package/dashboard/dist/assets/{bots-Bi2_O1Ts.js.map → bots-Dny-rmmI.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-Ck1KlLkT.js → escalation-CV0sKNH5.js} +2 -2
- package/dashboard/dist/assets/{escalation-Ck1KlLkT.js.map → escalation-CV0sKNH5.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-ohDsj2eJ.js → escalation-columns-30CKyoWI.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-ohDsj2eJ.js.map → escalation-columns-30CKyoWI.js.map} +1 -1
- package/dashboard/dist/assets/{helpers-BoD2SgUY.js → helpers-C1-30CzH.js} +2 -2
- package/dashboard/dist/assets/{helpers-BoD2SgUY.js.map → helpers-C1-30CzH.js.map} +1 -1
- package/dashboard/dist/assets/helpers-C1jaRD-d.js +2 -0
- package/dashboard/dist/assets/helpers-C1jaRD-d.js.map +1 -0
- package/dashboard/dist/assets/{index-FuohTtaM.js → index-BUVQ6wmy.js} +3 -3
- package/dashboard/dist/assets/{index-FuohTtaM.js.map → index-BUVQ6wmy.js.map} +1 -1
- package/dashboard/dist/assets/index-CxVB7F4X.js +2 -0
- package/dashboard/dist/assets/{index-Dk2Q51o0.js.map → index-CxVB7F4X.js.map} +1 -1
- package/dashboard/dist/assets/{index-BEtLIsML.js → index-D-oCWCAS.js} +2 -2
- package/dashboard/dist/assets/{index-BEtLIsML.js.map → index-D-oCWCAS.js.map} +1 -1
- package/dashboard/dist/assets/index-D0wPM3Ck.js +2 -0
- package/dashboard/dist/assets/{index-BpT-6WgJ.js.map → index-D0wPM3Ck.js.map} +1 -1
- package/dashboard/dist/assets/{index-Bn2xHDr8.js → index-DHgnkykj.js} +3 -3
- package/dashboard/dist/assets/{index-Bn2xHDr8.js.map → index-DHgnkykj.js.map} +1 -1
- package/dashboard/dist/assets/{index-D3NyVADW.js → index-D_aJBEAG.js} +2 -2
- package/dashboard/dist/assets/index-D_aJBEAG.js.map +1 -0
- package/dashboard/dist/assets/{index-PyCTS05D.css → index-DcIKW-cZ.css} +1 -1
- package/dashboard/dist/assets/{index-CZrJ09p-.js → index-Dd_U4mLm.js} +2 -2
- package/dashboard/dist/assets/{index-CZrJ09p-.js.map → index-Dd_U4mLm.js.map} +1 -1
- package/dashboard/dist/assets/{index-DYyLF-Qb.js → index-DnmZbNxk.js} +8 -8
- package/dashboard/dist/assets/index-DnmZbNxk.js.map +1 -0
- package/dashboard/dist/assets/index-_RBvi7s6.js +2 -0
- package/dashboard/dist/assets/{index-D7zYZOnH.js.map → index-_RBvi7s6.js.map} +1 -1
- package/dashboard/dist/assets/index-n7td8zgX.js +17 -0
- package/dashboard/dist/assets/{index-DOkHXmyf.js.map → index-n7td8zgX.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-CJtYjA7A.js → mcp-CRFr4L9W.js} +2 -2
- package/dashboard/dist/assets/{mcp-CJtYjA7A.js.map → mcp-CRFr4L9W.js.map} +1 -1
- package/dashboard/dist/assets/mcp-query-DHY2mZBQ.js +2 -0
- package/dashboard/dist/assets/mcp-query-DHY2mZBQ.js.map +1 -0
- package/dashboard/dist/assets/{mcp-runs-DUWm9Z4V.js → mcp-runs-BqPHqwAO.js} +2 -2
- package/dashboard/dist/assets/{mcp-runs-DUWm9Z4V.js.map → mcp-runs-BqPHqwAO.js.map} +1 -1
- package/dashboard/dist/assets/{namespaces-BM5P2qmL.js → namespaces-TG1aIpo_.js} +2 -2
- package/dashboard/dist/assets/{namespaces-BM5P2qmL.js.map → namespaces-TG1aIpo_.js.map} +1 -1
- package/dashboard/dist/assets/{roles-lv0shpjJ.js → roles-DhhLTvXg.js} +2 -2
- package/dashboard/dist/assets/{roles-lv0shpjJ.js.map → roles-DhhLTvXg.js.map} +1 -1
- package/dashboard/dist/assets/{settings-Wlq92mRo.js → settings-D9MBzEeB.js} +2 -2
- package/dashboard/dist/assets/{settings-Wlq92mRo.js.map → settings-D9MBzEeB.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-BFGm4PuE.js → tasks-BxmcZoev.js} +2 -2
- package/dashboard/dist/assets/{tasks-BFGm4PuE.js.map → tasks-BxmcZoev.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-DIE6ue4x.js → useEventHooks-BylecvvI.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-DIE6ue4x.js.map → useEventHooks-BylecvvI.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-DCwSO73t.js → useYamlActivityEvents-ocmj11e_.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-DCwSO73t.js.map → useYamlActivityEvents-ocmj11e_.js.map} +1 -1
- package/dashboard/dist/assets/{users-tA5-K0wA.js → users-Ce5r-JAv.js} +2 -2
- package/dashboard/dist/assets/{users-tA5-K0wA.js.map → users-Ce5r-JAv.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-BiIug1SK.js → vendor-icons-D1DdudfH.js} +93 -73
- package/dashboard/dist/assets/vendor-icons-D1DdudfH.js.map +1 -0
- package/dashboard/dist/assets/{workflows-CfLc15Wr.js → workflows-ykIeVbRJ.js} +2 -2
- package/dashboard/dist/assets/{workflows-CfLc15Wr.js.map → workflows-ykIeVbRJ.js.map} +1 -1
- package/dashboard/dist/assets/yaml-workflows-WypmKYht.js +2 -0
- package/dashboard/dist/assets/yaml-workflows-WypmKYht.js.map +1 -0
- package/dashboard/dist/index.html +3 -3
- package/docs/api/sdk/auth.md +27 -0
- package/docs/api/sdk/bot-accounts.md +243 -0
- package/docs/api/sdk/controlplane.md +103 -0
- package/docs/api/sdk/dba.md +52 -0
- package/docs/api/sdk/escalations.md +374 -0
- package/docs/api/sdk/events.md +68 -0
- package/docs/api/sdk/exports.md +124 -0
- package/docs/api/sdk/insight.md +112 -0
- package/docs/api/sdk/maintenance.md +54 -0
- package/docs/api/sdk/mcp-runs.md +71 -0
- package/docs/api/sdk/mcp.md +250 -0
- package/docs/api/sdk/namespaces.md +43 -0
- package/docs/api/sdk/roles.md +183 -0
- package/docs/api/sdk/settings.md +24 -0
- package/docs/api/sdk/tasks.md +120 -0
- package/docs/api/sdk/users.md +196 -0
- package/docs/api/sdk/workflow-sets.md +135 -0
- package/docs/api/sdk/workflows.md +271 -0
- package/docs/api/sdk/yaml-workflows.md +408 -0
- package/docs/events.md +28 -0
- package/docs/sdk.md +177 -0
- package/docs/story.md +157 -0
- package/package.json +3 -2
- package/build/routes/escalations/helpers.d.ts +0 -5
- package/build/routes/resolve.d.ts +0 -9
- package/build/routes/resolve.js +0 -19
- package/build/routes/yaml-workflows/helpers.d.ts +0 -2
- package/build/routes/yaml-workflows/helpers.js +0 -8
- package/dashboard/dist/assets/BotPicker-A6LtzyuO.js +0 -2
- package/dashboard/dist/assets/McpQueryDetailPage-DhqEI180.js +0 -5
- package/dashboard/dist/assets/McpQueryDetailPage-DhqEI180.js.map +0 -1
- package/dashboard/dist/assets/McpQueryPage-CIiVMlqo.js +0 -2
- package/dashboard/dist/assets/McpQueryPage-CIiVMlqo.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-jc0vrgDI.js +0 -2
- package/dashboard/dist/assets/RunAsSelector-CJDnyp93.js +0 -2
- package/dashboard/dist/assets/RunAsSelector-CJDnyp93.js.map +0 -1
- package/dashboard/dist/assets/WorkflowPill-DPKOcbf4.js +0 -2
- package/dashboard/dist/assets/YamlWorkflowsPage-BliAckJ6.js +0 -2
- package/dashboard/dist/assets/YamlWorkflowsPage-BliAckJ6.js.map +0 -1
- package/dashboard/dist/assets/index-BpT-6WgJ.js +0 -2
- package/dashboard/dist/assets/index-D3NyVADW.js.map +0 -1
- package/dashboard/dist/assets/index-D7zYZOnH.js +0 -2
- package/dashboard/dist/assets/index-DOkHXmyf.js +0 -17
- package/dashboard/dist/assets/index-DYyLF-Qb.js.map +0 -1
- package/dashboard/dist/assets/index-Dk2Q51o0.js +0 -2
- package/dashboard/dist/assets/mcp-query-jQJQrs_7.js +0 -2
- package/dashboard/dist/assets/mcp-query-jQJQrs_7.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-BiIug1SK.js.map +0 -1
- package/dashboard/dist/assets/yaml-workflows-D7JXNqbM.js +0 -2
- package/dashboard/dist/assets/yaml-workflows-D7JXNqbM.js.map +0 -1
- package/docs/img/01-login.png +0 -0
- package/docs/img/02-dashboard-home.png +0 -0
- package/docs/img/03-processes-list.png +0 -0
- package/docs/img/04-escalations-list.png +0 -0
- package/docs/img/05-mcp-servers.png +0 -0
- package/docs/img/06-mcp-pipelines.png +0 -0
- package/docs/img/07-workflows-list.png +0 -0
- package/docs/img/compilation/01-query-submit.png +0 -0
- package/docs/img/compilation/02-mcp-servers.png +0 -0
- package/docs/img/compilation/03-query-completed.png +0 -0
- package/docs/img/compilation/04-wizard-original.png +0 -0
- package/docs/img/compilation/05-wizard-timeline.png +0 -0
- package/docs/img/compilation/06-wizard-profile.png +0 -0
- package/docs/img/compilation/07-wizard-deploy.png +0 -0
- package/docs/img/compilation/08-wizard-test-modal.png +0 -0
- package/docs/img/compilation/09-wizard-test-compare.png +0 -0
- package/docs/img/compilation/10-wizard-verify.png +0 -0
- /package/docs/api/{dba.md → http/dba.md} +0 -0
- /package/docs/api/{escalations.md → http/escalations.md} +0 -0
- /package/docs/api/{exports.md → http/exports.md} +0 -0
- /package/docs/api/{maintenance.md → http/maintenance.md} +0 -0
- /package/docs/api/{mcp-runs.md → http/mcp-runs.md} +0 -0
- /package/docs/api/{mcp-servers.md → http/mcp-servers.md} +0 -0
- /package/docs/api/{namespaces.md → http/namespaces.md} +0 -0
- /package/docs/api/{roles.md → http/roles.md} +0 -0
- /package/docs/api/{service-accounts.md → http/service-accounts.md} +0 -0
- /package/docs/api/{settings.md → http/settings.md} +0 -0
- /package/docs/api/{tasks.md → http/tasks.md} +0 -0
- /package/docs/api/{users.md → http/users.md} +0 -0
- /package/docs/api/{workflows.md → http/workflows.md} +0 -0
- /package/docs/api/{yaml-workflows.md → http/yaml-workflows.md} +0 -0
|
@@ -0,0 +1,892 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.createEscalation = createEscalation;
|
|
37
|
+
exports.listEscalations = listEscalations;
|
|
38
|
+
exports.listAvailableEscalations = listAvailableEscalations;
|
|
39
|
+
exports.listDistinctTypes = listDistinctTypes;
|
|
40
|
+
exports.getEscalationStats = getEscalationStats;
|
|
41
|
+
exports.getEscalation = getEscalation;
|
|
42
|
+
exports.getEscalationsByWorkflowId = getEscalationsByWorkflowId;
|
|
43
|
+
exports.escalateToRole = escalateToRole;
|
|
44
|
+
exports.claimEscalation = claimEscalation;
|
|
45
|
+
exports.releaseEscalation = releaseEscalation;
|
|
46
|
+
exports.releaseExpiredClaims = releaseExpiredClaims;
|
|
47
|
+
exports.updatePriority = updatePriority;
|
|
48
|
+
exports.bulkClaim = bulkClaim;
|
|
49
|
+
exports.bulkAssign = bulkAssign;
|
|
50
|
+
exports.bulkEscalate = bulkEscalate;
|
|
51
|
+
exports.bulkTriage = bulkTriage;
|
|
52
|
+
exports.resolveEscalation = resolveEscalation;
|
|
53
|
+
const escalationService = __importStar(require("../services/escalation"));
|
|
54
|
+
const userService = __importStar(require("../services/user"));
|
|
55
|
+
const roleService = __importStar(require("../services/role"));
|
|
56
|
+
const taskService = __importStar(require("../services/task"));
|
|
57
|
+
const publish_1 = require("../lib/events/publish");
|
|
58
|
+
const escalation_strategy_1 = require("../services/escalation-strategy");
|
|
59
|
+
const ephemeral_1 = require("../services/iam/ephemeral");
|
|
60
|
+
const deployer_1 = require("../services/yaml-workflow/deployer");
|
|
61
|
+
const workers_1 = require("../workers");
|
|
62
|
+
const defaults_1 = require("../modules/defaults");
|
|
63
|
+
// ── Private helpers ────────────────────────────────────────────────────────
|
|
64
|
+
async function getVisibleRoles(userId) {
|
|
65
|
+
const isSuperAdminUser = await userService.isSuperAdmin(userId);
|
|
66
|
+
if (isSuperAdminUser)
|
|
67
|
+
return undefined;
|
|
68
|
+
const userRoles = await userService.getUserRoles(userId);
|
|
69
|
+
return userRoles.map((r) => r.role);
|
|
70
|
+
}
|
|
71
|
+
function validateIds(ids) {
|
|
72
|
+
return Array.isArray(ids) && ids.length > 0;
|
|
73
|
+
}
|
|
74
|
+
async function checkBulkPermission(userId, ids) {
|
|
75
|
+
const isSuperAdminUser = await userService.isSuperAdmin(userId);
|
|
76
|
+
if (isSuperAdminUser)
|
|
77
|
+
return { allowed: true };
|
|
78
|
+
const roles = await escalationService.getEscalationRoles(ids);
|
|
79
|
+
for (const role of roles) {
|
|
80
|
+
const canManage = await userService.isGroupAdmin(userId, role);
|
|
81
|
+
if (!canManage) {
|
|
82
|
+
return { allowed: false, status: 403, error: `Insufficient permissions for role "${role}"` };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return { allowed: true };
|
|
86
|
+
}
|
|
87
|
+
function publishBulkClaimEvents(ids, assignedTo) {
|
|
88
|
+
for (const id of ids) {
|
|
89
|
+
(0, publish_1.publishEscalationEvent)({
|
|
90
|
+
type: 'escalation.claimed',
|
|
91
|
+
source: 'api',
|
|
92
|
+
workflowId: '',
|
|
93
|
+
workflowName: '',
|
|
94
|
+
taskQueue: '',
|
|
95
|
+
escalationId: id,
|
|
96
|
+
status: 'claimed',
|
|
97
|
+
data: { assigned_to: assignedTo, bulk: true },
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// ── Create ────────────────────────────────────────────────────────────────
|
|
102
|
+
/**
|
|
103
|
+
* Create a standalone escalation (not tied to a workflow).
|
|
104
|
+
*
|
|
105
|
+
* Useful for manual work items, support tickets, or approval requests
|
|
106
|
+
* that originate outside the durable workflow engine. The caller must
|
|
107
|
+
* hold the target role or be a superadmin.
|
|
108
|
+
*
|
|
109
|
+
* @param input.type — escalation category (e.g. `"support"`, `"approval"`)
|
|
110
|
+
* @param input.subtype — subcategory for finer routing
|
|
111
|
+
* @param input.role — role responsible for resolving this escalation
|
|
112
|
+
* @param input.description — human-readable summary
|
|
113
|
+
* @param input.priority — 1 (critical) through 4 (low), default 2
|
|
114
|
+
* @param input.envelope — serialized context for the resolver
|
|
115
|
+
* @param input.metadata — arbitrary key-value data (e.g. signal_routing)
|
|
116
|
+
* @param input.escalation_payload — serialized payload for the resolver UI
|
|
117
|
+
* @param auth — authenticated user context (must hold target role or be superadmin)
|
|
118
|
+
* @returns `{ status: 201, data: <escalation record> }`
|
|
119
|
+
*/
|
|
120
|
+
async function createEscalation(input, auth) {
|
|
121
|
+
try {
|
|
122
|
+
const { type, role } = input;
|
|
123
|
+
if (!type || typeof type !== 'string') {
|
|
124
|
+
return { status: 400, error: 'type is required' };
|
|
125
|
+
}
|
|
126
|
+
if (!role || typeof role !== 'string') {
|
|
127
|
+
return { status: 400, error: 'role is required' };
|
|
128
|
+
}
|
|
129
|
+
// RBAC: caller must hold the target role or be superadmin
|
|
130
|
+
const isSuperAdminUser = await userService.isSuperAdmin(auth.userId);
|
|
131
|
+
if (!isSuperAdminUser) {
|
|
132
|
+
const userHasRole = await userService.hasRole(auth.userId, role);
|
|
133
|
+
if (!userHasRole) {
|
|
134
|
+
return { status: 403, error: `You must hold the "${role}" role or be a superadmin to create escalations for it` };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const escalation = await escalationService.createEscalation({
|
|
138
|
+
type,
|
|
139
|
+
subtype: input.subtype ?? type,
|
|
140
|
+
description: input.description,
|
|
141
|
+
priority: input.priority,
|
|
142
|
+
role,
|
|
143
|
+
envelope: input.envelope ?? '{}',
|
|
144
|
+
metadata: input.metadata,
|
|
145
|
+
escalation_payload: input.escalation_payload,
|
|
146
|
+
});
|
|
147
|
+
(0, publish_1.publishEscalationEvent)({
|
|
148
|
+
type: 'escalation.created',
|
|
149
|
+
source: 'api',
|
|
150
|
+
workflowId: '',
|
|
151
|
+
workflowName: '',
|
|
152
|
+
taskQueue: '',
|
|
153
|
+
escalationId: escalation.id,
|
|
154
|
+
status: 'pending',
|
|
155
|
+
data: { type: input.type, role },
|
|
156
|
+
});
|
|
157
|
+
return { status: 201, data: escalation };
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
return { status: 500, error: err.message };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// ── List routes ────────────────────────────────────────────────────────────
|
|
164
|
+
/**
|
|
165
|
+
* List escalations with optional filters.
|
|
166
|
+
*
|
|
167
|
+
* Results are scoped to the authenticated user's roles unless the user
|
|
168
|
+
* is a superadmin (who sees all roles).
|
|
169
|
+
*
|
|
170
|
+
* @param input.status — filter by `pending`, `resolved`, or `cancelled`
|
|
171
|
+
* @param input.role — filter by assigned role
|
|
172
|
+
* @param input.type — filter by workflow type
|
|
173
|
+
* @param input.subtype — filter by subtype
|
|
174
|
+
* @param input.assigned_to — filter by assigned user ID
|
|
175
|
+
* @param input.priority — filter by priority (1–4)
|
|
176
|
+
* @param input.limit — max results (default: 50)
|
|
177
|
+
* @param input.offset — pagination offset
|
|
178
|
+
* @param input.sort_by — column to sort by (e.g. `created_at`, `priority`)
|
|
179
|
+
* @param input.order — `asc` or `desc`
|
|
180
|
+
* @param auth — authenticated user context (required for role scoping)
|
|
181
|
+
* @returns `{ status: 200, data: { escalations, total } }`
|
|
182
|
+
*/
|
|
183
|
+
async function listEscalations(input, auth) {
|
|
184
|
+
try {
|
|
185
|
+
const visibleRoles = await getVisibleRoles(auth.userId);
|
|
186
|
+
if (visibleRoles && visibleRoles.length === 0) {
|
|
187
|
+
return { status: 200, data: { escalations: [], total: 0 } };
|
|
188
|
+
}
|
|
189
|
+
const result = await escalationService.listEscalations({
|
|
190
|
+
status: input.status,
|
|
191
|
+
role: input.role,
|
|
192
|
+
type: input.type,
|
|
193
|
+
subtype: input.subtype,
|
|
194
|
+
assigned_to: input.assigned_to,
|
|
195
|
+
priority: input.priority,
|
|
196
|
+
limit: input.limit,
|
|
197
|
+
offset: input.offset,
|
|
198
|
+
sort_by: input.sort_by,
|
|
199
|
+
order: input.order,
|
|
200
|
+
visibleRoles,
|
|
201
|
+
});
|
|
202
|
+
return { status: 200, data: result };
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
return { status: 500, error: err.message };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* List escalations available for claim (pending and not actively claimed).
|
|
210
|
+
*
|
|
211
|
+
* Similar to `listEscalations` but excludes escalations with active claims.
|
|
212
|
+
* Scoped to the authenticated user's roles.
|
|
213
|
+
*
|
|
214
|
+
* @param input.role — filter by role
|
|
215
|
+
* @param input.type — filter by workflow type
|
|
216
|
+
* @param input.subtype — filter by subtype
|
|
217
|
+
* @param input.priority — filter by priority (1–4)
|
|
218
|
+
* @param input.limit — max results (default: 50)
|
|
219
|
+
* @param input.offset — pagination offset
|
|
220
|
+
* @param input.sort_by — column to sort by
|
|
221
|
+
* @param input.order — `asc` or `desc`
|
|
222
|
+
* @param auth — authenticated user context
|
|
223
|
+
* @returns `{ status: 200, data: { escalations, total } }`
|
|
224
|
+
*/
|
|
225
|
+
async function listAvailableEscalations(input, auth) {
|
|
226
|
+
try {
|
|
227
|
+
const visibleRoles = await getVisibleRoles(auth.userId);
|
|
228
|
+
if (visibleRoles && visibleRoles.length === 0) {
|
|
229
|
+
return { status: 200, data: { escalations: [], total: 0 } };
|
|
230
|
+
}
|
|
231
|
+
const result = await escalationService.listAvailableEscalations({
|
|
232
|
+
role: input.role,
|
|
233
|
+
type: input.type,
|
|
234
|
+
subtype: input.subtype,
|
|
235
|
+
priority: input.priority,
|
|
236
|
+
limit: input.limit,
|
|
237
|
+
offset: input.offset,
|
|
238
|
+
sort_by: input.sort_by,
|
|
239
|
+
order: input.order,
|
|
240
|
+
visibleRoles,
|
|
241
|
+
});
|
|
242
|
+
return { status: 200, data: result };
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
return { status: 500, error: err.message };
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* List all distinct escalation type values.
|
|
250
|
+
*
|
|
251
|
+
* @returns `{ status: 200, data: { types: string[] } }`
|
|
252
|
+
*/
|
|
253
|
+
async function listDistinctTypes() {
|
|
254
|
+
try {
|
|
255
|
+
const types = await escalationService.listDistinctTypes();
|
|
256
|
+
return { status: 200, data: { types } };
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
return { status: 500, error: err.message };
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Get aggregate escalation statistics scoped to the user's roles.
|
|
264
|
+
*
|
|
265
|
+
* @param input.period — time window (`1h`, `24h`, `7d`, `30d`)
|
|
266
|
+
* @param auth — authenticated user context
|
|
267
|
+
* @returns `{ status: 200, data: { pending, claimed, created, resolved, by_role, by_type } }`
|
|
268
|
+
*/
|
|
269
|
+
async function getEscalationStats(input, auth) {
|
|
270
|
+
try {
|
|
271
|
+
const visibleRoles = await getVisibleRoles(auth.userId);
|
|
272
|
+
if (visibleRoles && visibleRoles.length === 0) {
|
|
273
|
+
return {
|
|
274
|
+
status: 200,
|
|
275
|
+
data: {
|
|
276
|
+
pending: 0,
|
|
277
|
+
claimed: 0,
|
|
278
|
+
created: 0,
|
|
279
|
+
resolved: 0,
|
|
280
|
+
by_role: [],
|
|
281
|
+
by_type: [],
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
const stats = await escalationService.getEscalationStats(visibleRoles, input.period);
|
|
286
|
+
return { status: 200, data: stats };
|
|
287
|
+
}
|
|
288
|
+
catch (err) {
|
|
289
|
+
return { status: 500, error: err.message };
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// ── Single-escalation routes ───────────────────────────────────────────────
|
|
293
|
+
/**
|
|
294
|
+
* Get a single escalation by ID.
|
|
295
|
+
*
|
|
296
|
+
* Non-superadmin users must hold the escalation's assigned role.
|
|
297
|
+
*
|
|
298
|
+
* @param input.id — escalation UUID
|
|
299
|
+
* @param auth — authenticated user context
|
|
300
|
+
* @returns `{ status: 200, data: <escalation record> }` or 403/404
|
|
301
|
+
*/
|
|
302
|
+
async function getEscalation(input, auth) {
|
|
303
|
+
try {
|
|
304
|
+
const escalation = await escalationService.getEscalation(input.id);
|
|
305
|
+
if (!escalation) {
|
|
306
|
+
return { status: 404, error: 'Escalation not found' };
|
|
307
|
+
}
|
|
308
|
+
const isSuperAdminUser = await userService.isSuperAdmin(auth.userId);
|
|
309
|
+
if (!isSuperAdminUser) {
|
|
310
|
+
const userHasRole = await userService.hasRole(auth.userId, escalation.role);
|
|
311
|
+
if (!userHasRole) {
|
|
312
|
+
return { status: 403, error: 'Not authorized to view this escalation' };
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return { status: 200, data: escalation };
|
|
316
|
+
}
|
|
317
|
+
catch (err) {
|
|
318
|
+
return { status: 500, error: err.message };
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* List all escalations for a given workflow ID.
|
|
323
|
+
*
|
|
324
|
+
* @param input.workflowId — HotMesh workflow ID
|
|
325
|
+
* @returns `{ status: 200, data: { escalations } }`
|
|
326
|
+
*/
|
|
327
|
+
async function getEscalationsByWorkflowId(input) {
|
|
328
|
+
try {
|
|
329
|
+
const escalations = await escalationService.getEscalationsByWorkflowId(input.workflowId);
|
|
330
|
+
return { status: 200, data: { escalations } };
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
return { status: 500, error: err.message };
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Route a pending escalation to a different role.
|
|
338
|
+
*
|
|
339
|
+
* The user must be authorized to escalate from the current role to the
|
|
340
|
+
* target role (checked via escalation chain configuration).
|
|
341
|
+
*
|
|
342
|
+
* @param input.id — escalation UUID
|
|
343
|
+
* @param input.targetRole — destination role
|
|
344
|
+
* @param auth — authenticated user context
|
|
345
|
+
* @returns `{ status: 200, data: <updated escalation> }` or 403/404/409
|
|
346
|
+
*/
|
|
347
|
+
async function escalateToRole(input, auth) {
|
|
348
|
+
try {
|
|
349
|
+
const { id, targetRole } = input;
|
|
350
|
+
if (!targetRole || typeof targetRole !== 'string') {
|
|
351
|
+
return { status: 400, error: 'targetRole is required' };
|
|
352
|
+
}
|
|
353
|
+
const escalation = await escalationService.getEscalation(id);
|
|
354
|
+
if (!escalation) {
|
|
355
|
+
return { status: 404, error: 'Escalation not found' };
|
|
356
|
+
}
|
|
357
|
+
if (escalation.status !== 'pending') {
|
|
358
|
+
return { status: 409, error: 'Escalation is not pending' };
|
|
359
|
+
}
|
|
360
|
+
const canEscalate = await roleService.canEscalateTo(auth.userId, escalation.role, targetRole);
|
|
361
|
+
if (!canEscalate) {
|
|
362
|
+
return { status: 403, error: 'Not authorized to escalate to this role' };
|
|
363
|
+
}
|
|
364
|
+
const updated = await escalationService.escalateToRole(id, targetRole);
|
|
365
|
+
if (!updated) {
|
|
366
|
+
return { status: 409, error: 'Escalation could not be updated' };
|
|
367
|
+
}
|
|
368
|
+
return { status: 200, data: updated };
|
|
369
|
+
}
|
|
370
|
+
catch (err) {
|
|
371
|
+
return { status: 500, error: err.message };
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Claim a pending escalation for the authenticated user.
|
|
376
|
+
*
|
|
377
|
+
* Sets `assigned_to` and `assigned_until` on the escalation (soft lock).
|
|
378
|
+
* Non-superadmin users must hold the escalation's role. Publishes a
|
|
379
|
+
* `escalation.claimed` event.
|
|
380
|
+
*
|
|
381
|
+
* @param input.id — escalation UUID
|
|
382
|
+
* @param input.durationMinutes — claim duration (default: 30)
|
|
383
|
+
* @param auth — authenticated user context
|
|
384
|
+
* @returns `{ status: 200, data: { escalation, isExtension } }` or 403/404/409
|
|
385
|
+
*/
|
|
386
|
+
async function claimEscalation(input, auth) {
|
|
387
|
+
try {
|
|
388
|
+
const { id, durationMinutes } = input;
|
|
389
|
+
const escalation = await escalationService.getEscalation(id);
|
|
390
|
+
if (!escalation) {
|
|
391
|
+
return { status: 404, error: 'Escalation not found' };
|
|
392
|
+
}
|
|
393
|
+
const isSuperAdminUser = await userService.isSuperAdmin(auth.userId);
|
|
394
|
+
if (!isSuperAdminUser) {
|
|
395
|
+
const userHasRole = await userService.hasRole(auth.userId, escalation.role);
|
|
396
|
+
if (!userHasRole) {
|
|
397
|
+
return {
|
|
398
|
+
status: 403,
|
|
399
|
+
error: `You must have the "${escalation.role}" role to claim this escalation`,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const result = await escalationService.claimEscalation(id, auth.userId, durationMinutes);
|
|
404
|
+
if (!result) {
|
|
405
|
+
return { status: 409, error: 'Escalation not available for claim' };
|
|
406
|
+
}
|
|
407
|
+
(0, publish_1.publishEscalationEvent)({
|
|
408
|
+
type: 'escalation.claimed',
|
|
409
|
+
source: 'api',
|
|
410
|
+
workflowId: escalation.workflow_id || '',
|
|
411
|
+
workflowName: escalation.workflow_type || '',
|
|
412
|
+
taskQueue: escalation.task_queue || '',
|
|
413
|
+
escalationId: id,
|
|
414
|
+
status: 'claimed',
|
|
415
|
+
data: { assigned_to: auth.userId },
|
|
416
|
+
});
|
|
417
|
+
return { status: 200, data: result };
|
|
418
|
+
}
|
|
419
|
+
catch (err) {
|
|
420
|
+
return { status: 500, error: err.message };
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Release a claimed escalation back to the pool.
|
|
425
|
+
*
|
|
426
|
+
* Only the user who holds the claim can release it. Publishes a
|
|
427
|
+
* `escalation.released` event.
|
|
428
|
+
*
|
|
429
|
+
* @param input.id — escalation UUID
|
|
430
|
+
* @param auth — authenticated user context
|
|
431
|
+
* @returns `{ status: 200, data: { escalation } }` or 409
|
|
432
|
+
*/
|
|
433
|
+
async function releaseEscalation(input, auth) {
|
|
434
|
+
try {
|
|
435
|
+
const result = await escalationService.releaseEscalation(input.id, auth.userId);
|
|
436
|
+
if (!result) {
|
|
437
|
+
return { status: 409, error: 'Escalation not found or not claimed by you' };
|
|
438
|
+
}
|
|
439
|
+
(0, publish_1.publishEscalationEvent)({
|
|
440
|
+
type: 'escalation.released',
|
|
441
|
+
source: 'api',
|
|
442
|
+
workflowId: result.workflow_id || '',
|
|
443
|
+
workflowName: result.workflow_type || '',
|
|
444
|
+
taskQueue: result.task_queue || '',
|
|
445
|
+
escalationId: input.id,
|
|
446
|
+
status: 'released',
|
|
447
|
+
data: { released_by: auth.userId },
|
|
448
|
+
});
|
|
449
|
+
return { status: 200, data: { escalation: result } };
|
|
450
|
+
}
|
|
451
|
+
catch (err) {
|
|
452
|
+
return { status: 500, error: err.message };
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
// ── Bulk routes ────────────────────────────────────────────────────────────
|
|
456
|
+
/**
|
|
457
|
+
* Release all escalation claims past their `assigned_until` deadline.
|
|
458
|
+
*
|
|
459
|
+
* Typically called on a maintenance schedule. Returns the count of
|
|
460
|
+
* released claims.
|
|
461
|
+
*
|
|
462
|
+
* @returns `{ status: 200, data: { released: number } }`
|
|
463
|
+
*/
|
|
464
|
+
async function releaseExpiredClaims() {
|
|
465
|
+
try {
|
|
466
|
+
const released = await escalationService.releaseExpiredClaims();
|
|
467
|
+
return { status: 200, data: { released } };
|
|
468
|
+
}
|
|
469
|
+
catch (err) {
|
|
470
|
+
return { status: 500, error: err.message };
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Update priority for one or more escalations.
|
|
475
|
+
*
|
|
476
|
+
* @param input.ids — array of escalation UUIDs
|
|
477
|
+
* @param input.priority — new priority (1=critical, 2=high, 3=medium, 4=low)
|
|
478
|
+
* @param auth — authenticated user context (admin or role-holder required)
|
|
479
|
+
* @returns `{ status: 200, data: { updated: number } }`
|
|
480
|
+
*/
|
|
481
|
+
async function updatePriority(input, auth) {
|
|
482
|
+
try {
|
|
483
|
+
const { ids, priority } = input;
|
|
484
|
+
if (!validateIds(ids)) {
|
|
485
|
+
return { status: 400, error: 'ids must be a non-empty array' };
|
|
486
|
+
}
|
|
487
|
+
if (![1, 2, 3, 4].includes(priority)) {
|
|
488
|
+
return { status: 400, error: 'priority must be 1, 2, 3, or 4' };
|
|
489
|
+
}
|
|
490
|
+
const perm = await checkBulkPermission(auth.userId, ids);
|
|
491
|
+
if (!perm.allowed)
|
|
492
|
+
return perm;
|
|
493
|
+
const updated = await escalationService.updateEscalationsPriority(ids, priority);
|
|
494
|
+
return { status: 200, data: { updated } };
|
|
495
|
+
}
|
|
496
|
+
catch (err) {
|
|
497
|
+
return { status: 500, error: err.message };
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Claim multiple escalations at once for the authenticated user.
|
|
502
|
+
*
|
|
503
|
+
* @param input.ids — array of escalation UUIDs
|
|
504
|
+
* @param input.durationMinutes — claim duration (default: 30)
|
|
505
|
+
* @param auth — authenticated user context
|
|
506
|
+
* @returns `{ status: 200, data: { claimed, skipped } }`
|
|
507
|
+
*/
|
|
508
|
+
async function bulkClaim(input, auth) {
|
|
509
|
+
try {
|
|
510
|
+
const { ids, durationMinutes } = input;
|
|
511
|
+
if (!validateIds(ids)) {
|
|
512
|
+
return { status: 400, error: 'ids must be a non-empty array' };
|
|
513
|
+
}
|
|
514
|
+
const perm = await checkBulkPermission(auth.userId, ids);
|
|
515
|
+
if (!perm.allowed)
|
|
516
|
+
return perm;
|
|
517
|
+
const result = await escalationService.bulkClaimEscalations(ids, auth.userId, durationMinutes ?? 30);
|
|
518
|
+
if (result.claimed > 0)
|
|
519
|
+
publishBulkClaimEvents(ids, auth.userId);
|
|
520
|
+
return { status: 200, data: result };
|
|
521
|
+
}
|
|
522
|
+
catch (err) {
|
|
523
|
+
return { status: 500, error: err.message };
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Assign multiple escalations to a specific user.
|
|
528
|
+
*
|
|
529
|
+
* Non-superadmin callers must verify the target user holds each
|
|
530
|
+
* escalation's role. Publishes claim events for assigned items.
|
|
531
|
+
*
|
|
532
|
+
* @param input.ids — array of escalation UUIDs
|
|
533
|
+
* @param input.targetUserId — user to assign to
|
|
534
|
+
* @param input.durationMinutes — assignment duration (default: 30)
|
|
535
|
+
* @param auth — authenticated user context
|
|
536
|
+
* @returns `{ status: 200, data: { assigned, skipped } }`
|
|
537
|
+
*/
|
|
538
|
+
async function bulkAssign(input, auth) {
|
|
539
|
+
try {
|
|
540
|
+
const { ids, targetUserId, durationMinutes } = input;
|
|
541
|
+
if (!validateIds(ids)) {
|
|
542
|
+
return { status: 400, error: 'ids must be a non-empty array' };
|
|
543
|
+
}
|
|
544
|
+
if (!targetUserId || typeof targetUserId !== 'string') {
|
|
545
|
+
return { status: 400, error: 'targetUserId is required' };
|
|
546
|
+
}
|
|
547
|
+
const perm = await checkBulkPermission(auth.userId, ids);
|
|
548
|
+
if (!perm.allowed)
|
|
549
|
+
return perm;
|
|
550
|
+
// Non-superadmin: target user must hold each escalation's role
|
|
551
|
+
const isSuperAdminUser = await userService.isSuperAdmin(auth.userId);
|
|
552
|
+
if (!isSuperAdminUser) {
|
|
553
|
+
const roles = await escalationService.getEscalationRoles(ids);
|
|
554
|
+
for (const role of roles) {
|
|
555
|
+
const targetHasRole = await userService.hasRole(targetUserId, role);
|
|
556
|
+
if (!targetHasRole) {
|
|
557
|
+
return { status: 400, error: `Target user does not hold the "${role}" role` };
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
const result = await escalationService.bulkAssignEscalations(ids, targetUserId, durationMinutes ?? 30);
|
|
562
|
+
if (result.assigned > 0)
|
|
563
|
+
publishBulkClaimEvents(ids, targetUserId);
|
|
564
|
+
return { status: 200, data: result };
|
|
565
|
+
}
|
|
566
|
+
catch (err) {
|
|
567
|
+
return { status: 500, error: err.message };
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Route multiple escalations to a different role.
|
|
572
|
+
*
|
|
573
|
+
* @param input.ids — array of escalation UUIDs
|
|
574
|
+
* @param input.targetRole — destination role
|
|
575
|
+
* @param auth — authenticated user context
|
|
576
|
+
* @returns `{ status: 200, data: { updated: number } }`
|
|
577
|
+
*/
|
|
578
|
+
async function bulkEscalate(input, auth) {
|
|
579
|
+
try {
|
|
580
|
+
const { ids, targetRole } = input;
|
|
581
|
+
if (!validateIds(ids)) {
|
|
582
|
+
return { status: 400, error: 'ids must be a non-empty array' };
|
|
583
|
+
}
|
|
584
|
+
if (!targetRole || typeof targetRole !== 'string') {
|
|
585
|
+
return { status: 400, error: 'targetRole is required' };
|
|
586
|
+
}
|
|
587
|
+
const perm = await checkBulkPermission(auth.userId, ids);
|
|
588
|
+
if (!perm.allowed)
|
|
589
|
+
return perm;
|
|
590
|
+
const updated = await escalationService.bulkEscalateToRole(ids, targetRole);
|
|
591
|
+
return { status: 200, data: { updated } };
|
|
592
|
+
}
|
|
593
|
+
catch (err) {
|
|
594
|
+
return { status: 500, error: err.message };
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Trigger AI triage for multiple escalations.
|
|
599
|
+
*
|
|
600
|
+
* Resolves each escalation and starts a triage workflow that uses MCP
|
|
601
|
+
* tools to analyze and potentially auto-resolve the issue.
|
|
602
|
+
*
|
|
603
|
+
* @param input.ids — array of escalation UUIDs
|
|
604
|
+
* @param input.hint — optional natural-language guidance for the triage AI
|
|
605
|
+
* @param auth — authenticated user context
|
|
606
|
+
* @returns `{ status: 200, data: { triaged, workflows } }`
|
|
607
|
+
*/
|
|
608
|
+
async function bulkTriage(input, auth) {
|
|
609
|
+
try {
|
|
610
|
+
const { ids, hint } = input;
|
|
611
|
+
if (!validateIds(ids)) {
|
|
612
|
+
return { status: 400, error: 'ids must be a non-empty array' };
|
|
613
|
+
}
|
|
614
|
+
const perm = await checkBulkPermission(auth.userId, ids);
|
|
615
|
+
if (!perm.allowed)
|
|
616
|
+
return perm;
|
|
617
|
+
const resolved = await escalationService.bulkResolveForTriage(ids, hint);
|
|
618
|
+
const client = (0, workers_1.createClient)();
|
|
619
|
+
const workflowIds = [];
|
|
620
|
+
for (const escalation of resolved) {
|
|
621
|
+
const triageWorkflowId = await startTriageWorkflow(escalation, hint, auth.userId, client);
|
|
622
|
+
workflowIds.push(triageWorkflowId);
|
|
623
|
+
}
|
|
624
|
+
return { status: 200, data: { triaged: resolved.length, workflows: workflowIds } };
|
|
625
|
+
}
|
|
626
|
+
catch (err) {
|
|
627
|
+
return { status: 500, error: err.message };
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
// ── Resolve route ──────────────────────────────────────────────────────────
|
|
631
|
+
/**
|
|
632
|
+
* Resolve a pending escalation with a human-provided payload.
|
|
633
|
+
*
|
|
634
|
+
* Handles two resolution paths:
|
|
635
|
+
* 1. **Signal-routed** — if the escalation has `signal_routing` metadata,
|
|
636
|
+
* the resolver payload is sent directly to the paused workflow via
|
|
637
|
+
* `handle.signal()`. Supports both Durable and YAML engines.
|
|
638
|
+
* 2. **Re-run** — the original workflow is re-started with the resolver
|
|
639
|
+
* payload injected into `envelope.resolver`. The interceptor detects
|
|
640
|
+
* the re-run and skips to the resolution branch.
|
|
641
|
+
*
|
|
642
|
+
* Password fields in the resolver payload are replaced with ephemeral
|
|
643
|
+
* tokens (15-minute TTL) so plaintext never enters the signal store.
|
|
644
|
+
*
|
|
645
|
+
* Supports optional escalation strategy execution after resolution.
|
|
646
|
+
*
|
|
647
|
+
* @param input.id — escalation UUID
|
|
648
|
+
* @param input.resolverPayload — human decision data
|
|
649
|
+
* @param auth — authenticated user context
|
|
650
|
+
* @returns `{ status: 200, data: { signaled, escalationId, workflowId } }` (signal path)
|
|
651
|
+
* or `{ status: 200, data: { workflowId, resumed, escalationId } }` (re-run path)
|
|
652
|
+
*/
|
|
653
|
+
async function resolveEscalation(input, auth) {
|
|
654
|
+
try {
|
|
655
|
+
const { id, resolverPayload } = input;
|
|
656
|
+
if (!resolverPayload) {
|
|
657
|
+
return { status: 400, error: 'resolverPayload is required' };
|
|
658
|
+
}
|
|
659
|
+
// 1. Read escalation (verify pending)
|
|
660
|
+
const escalation = await escalationService.getEscalation(id);
|
|
661
|
+
if (!escalation) {
|
|
662
|
+
return { status: 404, error: 'Escalation not found' };
|
|
663
|
+
}
|
|
664
|
+
if (escalation.status !== 'pending') {
|
|
665
|
+
return { status: 409, error: 'Escalation not available for resolution' };
|
|
666
|
+
}
|
|
667
|
+
// 2. waitFor signal escalation -- signal the paused workflow directly
|
|
668
|
+
const signalRouting = escalation.metadata?.signal_routing;
|
|
669
|
+
if (signalRouting?.signalId) {
|
|
670
|
+
// Replace password fields with ephemeral tokens so plaintext never enters the signal store
|
|
671
|
+
let signalPayload = resolverPayload;
|
|
672
|
+
const formSchema = escalation.metadata?.form_schema;
|
|
673
|
+
if (formSchema?.properties) {
|
|
674
|
+
signalPayload = { ...resolverPayload };
|
|
675
|
+
for (const [key, def] of Object.entries(formSchema.properties)) {
|
|
676
|
+
if (def?.format === 'password' && typeof signalPayload[key] === 'string') {
|
|
677
|
+
const uuid = await (0, ephemeral_1.storeEphemeral)(signalPayload[key], {
|
|
678
|
+
ttlSeconds: 900,
|
|
679
|
+
label: key,
|
|
680
|
+
});
|
|
681
|
+
signalPayload[key] = (0, ephemeral_1.formatEphemeralToken)(uuid, key);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (signalRouting.engine === 'yaml' && signalRouting.hookTopic && signalRouting.appId) {
|
|
686
|
+
const engine = await (0, deployer_1.getEngine)(signalRouting.appId);
|
|
687
|
+
await engine.signal(signalRouting.hookTopic, {
|
|
688
|
+
...signalPayload,
|
|
689
|
+
escalationId: escalation.id,
|
|
690
|
+
job_id: signalRouting.jobId,
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
else if (signalRouting.workflowId) {
|
|
694
|
+
const client = (0, workers_1.createClient)();
|
|
695
|
+
const handle = await client.workflow.getHandle(signalRouting.taskQueue, signalRouting.workflowType, signalRouting.workflowId);
|
|
696
|
+
await handle.signal(signalRouting.signalId, signalPayload);
|
|
697
|
+
}
|
|
698
|
+
await escalationService.resolveEscalation(escalation.id, resolverPayload);
|
|
699
|
+
(0, publish_1.publishEscalationEvent)({
|
|
700
|
+
type: 'escalation.resolved',
|
|
701
|
+
source: 'api',
|
|
702
|
+
workflowId: escalation.workflow_id || signalRouting.workflowId,
|
|
703
|
+
workflowName: escalation.workflow_type || signalRouting.workflowType,
|
|
704
|
+
taskQueue: escalation.task_queue || signalRouting.taskQueue || signalRouting.appId,
|
|
705
|
+
taskId: escalation.task_id,
|
|
706
|
+
escalationId: escalation.id,
|
|
707
|
+
originId: escalation.origin_id ?? undefined,
|
|
708
|
+
status: 'resolved',
|
|
709
|
+
});
|
|
710
|
+
return {
|
|
711
|
+
status: 200,
|
|
712
|
+
data: {
|
|
713
|
+
signaled: true,
|
|
714
|
+
escalationId: escalation.id,
|
|
715
|
+
workflowId: signalRouting.workflowId || signalRouting.appId,
|
|
716
|
+
},
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
// 3. Reconstruct the original envelope from the escalation or task
|
|
720
|
+
let envelope = {};
|
|
721
|
+
if (escalation.envelope) {
|
|
722
|
+
try {
|
|
723
|
+
envelope = JSON.parse(escalation.envelope);
|
|
724
|
+
}
|
|
725
|
+
catch { /* use empty */ }
|
|
726
|
+
}
|
|
727
|
+
else if (escalation.task_id) {
|
|
728
|
+
const task = await taskService.getTask(escalation.task_id);
|
|
729
|
+
if (task?.envelope) {
|
|
730
|
+
try {
|
|
731
|
+
envelope = JSON.parse(task.envelope);
|
|
732
|
+
}
|
|
733
|
+
catch { /* use empty */ }
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
// 4. Check escalation strategy for triage routing
|
|
737
|
+
const strategy = escalation_strategy_1.escalationStrategyRegistry.current;
|
|
738
|
+
if (strategy) {
|
|
739
|
+
const directive = await strategy.onResolution({
|
|
740
|
+
escalation,
|
|
741
|
+
resolverPayload,
|
|
742
|
+
envelope,
|
|
743
|
+
});
|
|
744
|
+
if (directive.action === 'triage') {
|
|
745
|
+
const originalTask = escalation.task_id
|
|
746
|
+
? await taskService.getTask(escalation.task_id)
|
|
747
|
+
: null;
|
|
748
|
+
const routing = originalTask?.metadata;
|
|
749
|
+
const triageWorkflowId = `triage-${escalation.id}-${Date.now()}`;
|
|
750
|
+
const client = (0, workers_1.createClient)();
|
|
751
|
+
await taskService.createTask({
|
|
752
|
+
workflow_id: triageWorkflowId,
|
|
753
|
+
workflow_type: 'mcpTriageRouter',
|
|
754
|
+
lt_type: 'mcpTriage',
|
|
755
|
+
task_queue: 'long-tail-system',
|
|
756
|
+
signal_id: `lt-triage-${triageWorkflowId}`,
|
|
757
|
+
parent_workflow_id: triageWorkflowId,
|
|
758
|
+
origin_id: escalation.origin_id || triageWorkflowId,
|
|
759
|
+
parent_id: escalation.parent_id ?? undefined,
|
|
760
|
+
envelope: JSON.stringify(directive.triageEnvelope),
|
|
761
|
+
});
|
|
762
|
+
await client.workflow.start({
|
|
763
|
+
workflowName: 'mcpTriageRouter',
|
|
764
|
+
args: [directive.triageEnvelope],
|
|
765
|
+
taskQueue: 'long-tail-system',
|
|
766
|
+
workflowId: triageWorkflowId,
|
|
767
|
+
expire: defaults_1.JOB_EXPIRE_SECS,
|
|
768
|
+
entity: 'mcpTriageRouter',
|
|
769
|
+
});
|
|
770
|
+
await escalationService.resolveEscalation(escalation.id, {
|
|
771
|
+
...resolverPayload,
|
|
772
|
+
_lt: { ...resolverPayload._lt, triaged: true, triageWorkflowId },
|
|
773
|
+
});
|
|
774
|
+
(0, publish_1.publishEscalationEvent)({
|
|
775
|
+
type: 'escalation.resolved',
|
|
776
|
+
source: 'api',
|
|
777
|
+
workflowId: escalation.workflow_id,
|
|
778
|
+
workflowName: escalation.workflow_type,
|
|
779
|
+
taskQueue: escalation.task_queue,
|
|
780
|
+
taskId: escalation.task_id,
|
|
781
|
+
escalationId: escalation.id,
|
|
782
|
+
originId: escalation.origin_id ?? undefined,
|
|
783
|
+
status: 'resolved',
|
|
784
|
+
});
|
|
785
|
+
return {
|
|
786
|
+
status: 200,
|
|
787
|
+
data: {
|
|
788
|
+
started: true,
|
|
789
|
+
escalationId: escalation.id,
|
|
790
|
+
workflowId: triageWorkflowId,
|
|
791
|
+
triage: true,
|
|
792
|
+
},
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
// 5. If no workflow_type, this is a notification-only escalation -- acknowledge and close
|
|
797
|
+
if (!escalation.workflow_type || !escalation.task_queue) {
|
|
798
|
+
await escalationService.resolveEscalation(escalation.id, resolverPayload);
|
|
799
|
+
return { status: 200, data: { acknowledged: true, escalationId: escalation.id } };
|
|
800
|
+
}
|
|
801
|
+
// 6. Standard re-run: inject resolver data and start original workflow
|
|
802
|
+
envelope.resolver = resolverPayload;
|
|
803
|
+
envelope.lt = {
|
|
804
|
+
...envelope.lt,
|
|
805
|
+
escalationId: escalation.id,
|
|
806
|
+
};
|
|
807
|
+
const newWorkflowId = `rerun-${escalation.id}-${Date.now()}`;
|
|
808
|
+
const client = (0, workers_1.createClient)();
|
|
809
|
+
await client.workflow.start({
|
|
810
|
+
workflowName: escalation.workflow_type,
|
|
811
|
+
args: [envelope],
|
|
812
|
+
taskQueue: escalation.task_queue,
|
|
813
|
+
workflowId: newWorkflowId,
|
|
814
|
+
expire: 180,
|
|
815
|
+
});
|
|
816
|
+
(0, publish_1.publishEscalationEvent)({
|
|
817
|
+
type: 'escalation.resolved',
|
|
818
|
+
source: 'api',
|
|
819
|
+
workflowId: escalation.workflow_id,
|
|
820
|
+
workflowName: escalation.workflow_type,
|
|
821
|
+
taskQueue: escalation.task_queue,
|
|
822
|
+
taskId: escalation.task_id,
|
|
823
|
+
escalationId: escalation.id,
|
|
824
|
+
originId: escalation.origin_id ?? undefined,
|
|
825
|
+
status: 'resolved',
|
|
826
|
+
});
|
|
827
|
+
return {
|
|
828
|
+
status: 200,
|
|
829
|
+
data: { started: true, escalationId: escalation.id, workflowId: newWorkflowId },
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
catch (err) {
|
|
833
|
+
return { status: 500, error: err.message };
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
// ── Triage workflow launcher (shared by bulkTriage) ────────────────────────
|
|
837
|
+
async function startTriageWorkflow(escalation, hint, userId, client) {
|
|
838
|
+
let escalationPayload = {};
|
|
839
|
+
if (escalation.escalation_payload) {
|
|
840
|
+
try {
|
|
841
|
+
escalationPayload = JSON.parse(escalation.escalation_payload);
|
|
842
|
+
}
|
|
843
|
+
catch { }
|
|
844
|
+
}
|
|
845
|
+
let envelope = {};
|
|
846
|
+
if (escalation.envelope) {
|
|
847
|
+
try {
|
|
848
|
+
envelope = JSON.parse(escalation.envelope);
|
|
849
|
+
}
|
|
850
|
+
catch { }
|
|
851
|
+
}
|
|
852
|
+
const triageWorkflowId = `triage-${escalation.id}-${Date.now()}`;
|
|
853
|
+
const triageEnvelope = {
|
|
854
|
+
data: {
|
|
855
|
+
escalationId: escalation.id,
|
|
856
|
+
originId: escalation.origin_id ?? undefined,
|
|
857
|
+
originalWorkflowType: escalation.workflow_type,
|
|
858
|
+
originalTaskQueue: escalation.task_queue,
|
|
859
|
+
originalTaskId: escalation.task_id,
|
|
860
|
+
escalationPayload,
|
|
861
|
+
resolverPayload: {
|
|
862
|
+
_lt: { needsTriage: true, ...(hint ? { hint } : {}) },
|
|
863
|
+
},
|
|
864
|
+
},
|
|
865
|
+
metadata: envelope.metadata || {},
|
|
866
|
+
lt: { ...(envelope.lt || {}), userId },
|
|
867
|
+
};
|
|
868
|
+
const routing = escalation.task_id
|
|
869
|
+
? (await taskService.getTask(escalation.task_id))?.metadata
|
|
870
|
+
: null;
|
|
871
|
+
await taskService.createTask({
|
|
872
|
+
workflow_id: triageWorkflowId,
|
|
873
|
+
workflow_type: 'mcpTriage',
|
|
874
|
+
lt_type: 'mcpTriage',
|
|
875
|
+
task_queue: 'long-tail-system',
|
|
876
|
+
signal_id: `lt-triage-${triageWorkflowId}`,
|
|
877
|
+
parent_workflow_id: routing?.parentWorkflowId || triageWorkflowId,
|
|
878
|
+
origin_id: escalation.origin_id || triageWorkflowId,
|
|
879
|
+
parent_id: escalation.parent_id ?? undefined,
|
|
880
|
+
envelope: JSON.stringify(triageEnvelope),
|
|
881
|
+
metadata: routing || undefined,
|
|
882
|
+
});
|
|
883
|
+
await client.workflow.start({
|
|
884
|
+
workflowName: 'mcpTriage',
|
|
885
|
+
args: [triageEnvelope],
|
|
886
|
+
taskQueue: 'long-tail-system',
|
|
887
|
+
workflowId: triageWorkflowId,
|
|
888
|
+
expire: defaults_1.JOB_EXPIRE_SECS,
|
|
889
|
+
entity: 'mcpTriage',
|
|
890
|
+
});
|
|
891
|
+
return triageWorkflowId;
|
|
892
|
+
}
|