@hotmeshio/long-tail 0.4.18 → 0.4.20
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 +0 -2
- package/build/api/auth-sso.d.ts +12 -0
- package/build/api/auth-sso.js +54 -0
- package/build/api/escalations/bulk.js +2 -2
- package/build/api/escalations/claim.js +3 -13
- package/build/api/escalations/create.js +3 -2
- package/build/api/escalations/helpers.d.ts +1 -0
- package/build/api/escalations/helpers.js +12 -9
- package/build/api/escalations/list.d.ts +1 -0
- package/build/api/escalations/list.js +1 -0
- package/build/api/escalations/metadata.d.ts +7 -24
- package/build/api/escalations/metadata.js +31 -65
- package/build/api/escalations/single.js +3 -2
- package/build/api/settings.js +5 -0
- package/build/api/topics.d.ts +9 -0
- package/build/api/topics.js +31 -2
- package/build/lib/events/index.d.ts +1 -0
- package/build/lib/events/index.js +4 -0
- package/build/lib/events/publish.d.ts +12 -9
- package/build/lib/events/publish.js +27 -17
- package/build/modules/auth.d.ts +7 -0
- package/build/modules/auth.js +104 -2
- package/build/modules/sso.d.ts +6 -0
- package/build/modules/sso.js +20 -0
- package/build/routes/auth-sso.d.ts +2 -0
- package/build/routes/auth-sso.js +51 -0
- package/build/routes/bot-accounts.js +1 -1
- package/build/routes/controlplane.js +6 -6
- package/build/routes/escalations/list.js +1 -0
- package/build/routes/index.js +2 -0
- package/build/routes/mcp-endpoint.d.ts +17 -0
- package/build/routes/mcp-endpoint.js +70 -0
- package/build/routes/roles.js +5 -5
- package/build/routes/topics.js +2 -0
- package/build/routes/users.js +31 -5
- package/build/sdk/index.d.ts +1 -0
- package/build/services/agent/input-mapper.js +17 -1
- package/build/services/escalation/crud.d.ts +17 -1
- package/build/services/escalation/crud.js +62 -13
- package/build/services/escalation/queries.d.ts +1 -0
- package/build/services/escalation/queries.js +7 -0
- package/build/services/escalation/sql.d.ts +14 -5
- package/build/services/escalation/sql.js +53 -16
- package/build/services/mcp/exposure.d.ts +15 -0
- package/build/services/mcp/exposure.js +18 -0
- package/build/services/mcp/external-server.d.ts +15 -0
- package/build/services/mcp/external-server.js +125 -0
- package/build/services/mcp/seed-service-account.d.ts +11 -0
- package/build/services/mcp/seed-service-account.js +77 -0
- package/build/services/role/index.d.ts +1 -1
- package/build/services/role/index.js +2 -2
- package/build/services/topics/system-topics.js +29 -25
- package/build/services/user/index.d.ts +1 -1
- package/build/services/user/index.js +3 -1
- package/build/services/user/rbac.d.ts +16 -0
- package/build/services/user/rbac.js +31 -0
- package/build/services/user/sso-provision.d.ts +19 -0
- package/build/services/user/sso-provision.js +62 -0
- package/build/services/workflow-invocation.js +5 -3
- package/build/start/config.js +6 -0
- package/build/start/server.js +2 -0
- package/build/start/workers.js +15 -0
- package/build/system/index.js +53 -35
- package/build/system/mcp-servers/admin/agent-subscriptions.d.ts +5 -0
- package/build/system/mcp-servers/admin/agent-subscriptions.js +78 -0
- package/build/system/mcp-servers/admin/agents.d.ts +5 -0
- package/build/system/mcp-servers/admin/agents.js +103 -0
- package/build/system/mcp-servers/admin/bot-accounts.d.ts +5 -0
- package/build/system/mcp-servers/admin/bot-accounts.js +126 -0
- package/build/system/mcp-servers/admin/controlplane.d.ts +5 -0
- package/build/system/mcp-servers/admin/controlplane.js +107 -0
- package/build/system/mcp-servers/admin/escalations.js +88 -0
- package/build/system/mcp-servers/admin/exports.d.ts +5 -0
- package/build/system/mcp-servers/admin/exports.js +101 -0
- package/build/system/mcp-servers/admin/index.d.ts +16 -8
- package/build/system/mcp-servers/admin/index.js +36 -21
- package/build/system/mcp-servers/admin/pipelines.d.ts +5 -0
- package/build/system/mcp-servers/admin/pipelines.js +96 -0
- package/build/system/mcp-servers/admin/schemas.d.ts +614 -6
- package/build/system/mcp-servers/admin/schemas.js +239 -1
- package/build/system/mcp-servers/admin/settings.d.ts +5 -0
- package/build/system/mcp-servers/admin/settings.js +53 -0
- package/build/system/mcp-servers/admin/topics.d.ts +5 -0
- package/build/system/mcp-servers/admin/topics.js +101 -0
- package/build/system/seed/tool-manifests-admin.d.ts +5077 -188
- package/build/system/seed/tool-manifests-admin.js +79 -30
- package/build/system/seed/tool-manifests-data.d.ts +20 -0
- package/build/system/seed/tool-manifests-data.js +24 -6
- package/build/system/seed/tool-manifests-escalation.d.ts +5 -0
- package/build/system/seed/tool-manifests-escalation.js +5 -0
- package/build/system/seed/tool-manifests-events.d.ts +4 -0
- package/build/system/seed/tool-manifests-events.js +4 -0
- package/build/system/seed/tool-manifests-knowledge.d.ts +6 -0
- package/build/system/seed/tool-manifests-knowledge.js +7 -0
- package/build/system/seed/tool-manifests-workflows.d.ts +8 -0
- package/build/system/seed/tool-manifests-workflows.js +8 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/auth.d.ts +71 -0
- package/build/types/events.d.ts +17 -6
- package/build/types/index.d.ts +1 -1
- package/build/types/startup.d.ts +22 -1
- package/dashboard/dist/assets/{AdminDashboard-Cfo0mwL2.js → AdminDashboard-BwUGcCxQ.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-Cfo0mwL2.js.map → AdminDashboard-BwUGcCxQ.js.map} +1 -1
- package/dashboard/dist/assets/AgentConfigPage-DgrYzLwq.js +16 -0
- package/dashboard/dist/assets/AgentConfigPage-DgrYzLwq.js.map +1 -0
- package/dashboard/dist/assets/{AgentDetailPage-3mZA7SOb.js → AgentDetailPage-XJpl7wfJ.js} +4 -4
- package/dashboard/dist/assets/AgentDetailPage-XJpl7wfJ.js.map +1 -0
- package/dashboard/dist/assets/{AgentsPage-CTVocfBb.js → AgentsPage-CGpVG6r8.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-CTVocfBb.js.map → AgentsPage-CGpVG6r8.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-DR1e0TQZ.js +2 -0
- package/dashboard/dist/assets/{AvailableEscalationsPage-CA9x9o5s.js.map → AvailableEscalationsPage-DR1e0TQZ.js.map} +1 -1
- package/dashboard/dist/assets/BotPicker-BKtjl6IL.js +2 -0
- package/dashboard/dist/assets/{BotPicker-BQp_Vs73.js.map → BotPicker-BKtjl6IL.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-wpVtkGeU.js → CapabilitiesPage-kCB8fyOj.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-wpVtkGeU.js.map → CapabilitiesPage-kCB8fyOj.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-2eZMMZiG.js → CollapsibleSection-C3tU61hB.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-2eZMMZiG.js.map → CollapsibleSection-C3tU61hB.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-DJGLssm0.js → CredentialsPage-Dt4nJs_B.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-DJGLssm0.js.map → CredentialsPage-Dt4nJs_B.js.map} +1 -1
- package/dashboard/dist/assets/CronLabel-BdE6mHyA.js +2 -0
- package/dashboard/dist/assets/CronLabel-BdE6mHyA.js.map +1 -0
- package/dashboard/dist/assets/{CustomDurationPicker-DbyqfK35.js → CustomDurationPicker-B_Yxfb-u.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-DbyqfK35.js.map → CustomDurationPicker-B_Yxfb-u.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-BkfRoUcm.js → DropZone-CptiQ0wc.js} +2 -2
- package/dashboard/dist/assets/{DropZone-BkfRoUcm.js.map → DropZone-CptiQ0wc.js.map} +1 -1
- package/dashboard/dist/assets/ElapsedCell-tcGx5PFI.js +2 -0
- package/dashboard/dist/assets/{ElapsedCell-BPYm8RA7.js.map → ElapsedCell-tcGx5PFI.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-kYGHfnLf.js → EscalationsOverview-1KO5dXzk.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-kYGHfnLf.js.map → EscalationsOverview-1KO5dXzk.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-DSDzJMer.js → EventTable-DnpsQ6Ew.js} +2 -2
- package/dashboard/dist/assets/{EventTable-DSDzJMer.js.map → EventTable-DnpsQ6Ew.js.map} +1 -1
- package/dashboard/dist/assets/HomePage-B2Jgo1J1.js +2 -0
- package/dashboard/dist/assets/HomePage-B2Jgo1J1.js.map +1 -0
- package/dashboard/dist/assets/ListToolbar-jrVba7QN.js +2 -0
- package/dashboard/dist/assets/{ListToolbar-DEef1_-T.js.map → ListToolbar-jrVba7QN.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-CZFW5qMb.js → McpOverview-BzyxJyc9.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-CZFW5qMb.js.map → McpOverview-BzyxJyc9.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-q9xH-QRo.js → McpQueryDetailPage-DXNseeKl.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-q9xH-QRo.js.map → McpQueryDetailPage-DXNseeKl.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-D14466yi.js → McpQueryPage-WZfTY43_.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-D14466yi.js.map → McpQueryPage-WZfTY43_.js.map} +1 -1
- package/dashboard/dist/assets/McpRunDetailPage-DKZp-p7S.js +2 -0
- package/dashboard/dist/assets/McpRunDetailPage-DKZp-p7S.js.map +1 -0
- package/dashboard/dist/assets/McpRunsPage-SXyiwc0d.js +2 -0
- package/dashboard/dist/assets/{McpRunsPage-aZg057y3.js.map → McpRunsPage-SXyiwc0d.js.map} +1 -1
- package/dashboard/dist/assets/OperatorDashboard-Cy7ySMXj.js +2 -0
- package/dashboard/dist/assets/OperatorDashboard-Cy7ySMXj.js.map +1 -0
- package/dashboard/dist/assets/{PageHeader-CR6TpJG_.js → PageHeader-BuJpMxyu.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-CR6TpJG_.js.map → PageHeader-BuJpMxyu.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-CRcQEAO1.js → PageHeaderWithStats-yD_PTbOl.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-CRcQEAO1.js.map → PageHeaderWithStats-yD_PTbOl.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-DyzNjwu8.js → ProcessDetailPage-DYIfvWyc.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-DyzNjwu8.js.map → ProcessDetailPage-DYIfvWyc.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-CT_3b5Wt.js → ProcessesListPage-DR1RGaMl.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-CT_3b5Wt.js.map → ProcessesListPage-DR1RGaMl.js.map} +1 -1
- package/dashboard/dist/assets/{RolePill-BC54Vn-U.js → RolePill-SasQKc_B.js} +2 -2
- package/dashboard/dist/assets/{RolePill-BC54Vn-U.js.map → RolePill-SasQKc_B.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-CpRJq-sg.js → RolesPage-pMERxj15.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-CpRJq-sg.js.map → RolesPage-pMERxj15.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-C20rdNsC.js → RunAsSelector-B-ksMoEj.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-C20rdNsC.js.map → RunAsSelector-B-ksMoEj.js.map} +1 -1
- package/dashboard/dist/assets/ServerName-CHspudaC.js +2 -0
- package/dashboard/dist/assets/{ServerName-Q6okiv4f.js.map → ServerName-CHspudaC.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-CbFaU4bq.js → SwimlaneTimeline-Cr_K5qpu.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-CbFaU4bq.js.map → SwimlaneTimeline-Cr_K5qpu.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-D6l1SPWd.js → TagInput-DvF3j8MA.js} +2 -2
- package/dashboard/dist/assets/{TagInput-D6l1SPWd.js.map → TagInput-DvF3j8MA.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-22cJsFmM.js → TaskDetailPage-BO5p7AEe.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-22cJsFmM.js.map → TaskDetailPage-BO5p7AEe.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-iDBVCEQQ.js → TaskQueuePill-BCQrS2oK.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-iDBVCEQQ.js.map → TaskQueuePill-BCQrS2oK.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-BDmaUIKu.js → TasksListPage-BRg-uFtF.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-BDmaUIKu.js.map → TasksListPage-BRg-uFtF.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-7wqEp87-.js → TimeAgo-BSzN6rAH.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-7wqEp87-.js.map → TimeAgo-BSzN6rAH.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-BBCf8zsN.js → TimestampCell-DL6zMNEQ.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-BBCf8zsN.js.map → TimestampCell-DL6zMNEQ.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-HcRTggHo.js → ToolPill-1aTqYtzp.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-HcRTggHo.js.map → ToolPill-1aTqYtzp.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-Dosq1cqG.js → ToolTestPanel-fLzNp79U.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-Dosq1cqG.js.map → ToolTestPanel-fLzNp79U.js.map} +1 -1
- package/dashboard/dist/assets/TopicDetailPage-D7gCsPKB.js +9 -0
- package/dashboard/dist/assets/TopicDetailPage-D7gCsPKB.js.map +1 -0
- package/dashboard/dist/assets/{TopicsPage-tVPdz-k0.js → TopicsPage-B3Aa8Haz.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-tVPdz-k0.js.map → TopicsPage-B3Aa8Haz.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-DX7IBjFn.js → UserName-BjHIJWgh.js} +2 -2
- package/dashboard/dist/assets/{UserName-DX7IBjFn.js.map → UserName-BjHIJWgh.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-BjC0j9_L.js → WorkflowExecutionPage-BQ7AYlQA.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-BjC0j9_L.js.map → WorkflowExecutionPage-BQ7AYlQA.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-54px0YiY.js → WorkflowPill-Z-zHRKOK.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-54px0YiY.js.map → WorkflowPill-Z-zHRKOK.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowsDashboard-D-G8Xudz.js +2 -0
- package/dashboard/dist/assets/WorkflowsDashboard-D-G8Xudz.js.map +1 -0
- package/dashboard/dist/assets/{WorkflowsOverview-DaJRDkNy.js → WorkflowsOverview-B4DUcVxs.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-DaJRDkNy.js.map → WorkflowsOverview-B4DUcVxs.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-CkpQaUmz.js → YamlWorkflowsPage-CnTNOku0.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-CkpQaUmz.js.map → YamlWorkflowsPage-CnTNOku0.js.map} +1 -1
- package/dashboard/dist/assets/{agents-B-P5MlEx.js → agents-CkvQDr9b.js} +2 -2
- package/dashboard/dist/assets/{agents-B-P5MlEx.js.map → agents-CkvQDr9b.js.map} +1 -1
- package/dashboard/dist/assets/{bots-CZz9iVys.js → bots-CzuMCVgU.js} +2 -2
- package/dashboard/dist/assets/{bots-CZz9iVys.js.map → bots-CzuMCVgU.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-DrZ8Vw_v.js → capabilities-CbGmS0ty.js} +2 -2
- package/dashboard/dist/assets/{capabilities-DrZ8Vw_v.js.map → capabilities-CbGmS0ty.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-cj-1c-1C.js → controlplane-DGvwkuYx.js} +2 -2
- package/dashboard/dist/assets/{controlplane-cj-1c-1C.js.map → controlplane-DGvwkuYx.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-BEVFyQnE.js → escalation-B7ysVToF.js} +2 -2
- package/dashboard/dist/assets/{escalation-BEVFyQnE.js.map → escalation-B7ysVToF.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-Beox3TXH.js → escalation-columns-CHQEJU1j.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-Beox3TXH.js.map → escalation-columns-CHQEJU1j.js.map} +1 -1
- package/dashboard/dist/assets/{helpers-B4gzNq9h.js → helpers-BFOjXa4r.js} +2 -2
- package/dashboard/dist/assets/{helpers-B4gzNq9h.js.map → helpers-BFOjXa4r.js.map} +1 -1
- package/dashboard/dist/assets/index-B9_1AZaG.js +2 -0
- package/dashboard/dist/assets/{index-3n5VREXN.js.map → index-B9_1AZaG.js.map} +1 -1
- package/dashboard/dist/assets/{index-BCQ65lNu.js → index-BFaDxPxA.js} +2 -2
- package/dashboard/dist/assets/{index-BCQ65lNu.js.map → index-BFaDxPxA.js.map} +1 -1
- package/dashboard/dist/assets/index-BduDiGcw.js +15 -0
- package/dashboard/dist/assets/{index-UtAfnStw.js.map → index-BduDiGcw.js.map} +1 -1
- package/dashboard/dist/assets/{index-Bh-PnP17.js → index-BeLphL59.js} +2 -2
- package/dashboard/dist/assets/{index-Bh-PnP17.js.map → index-BeLphL59.js.map} +1 -1
- package/dashboard/dist/assets/index-C--SEsU7.css +1 -0
- package/dashboard/dist/assets/{index-_DfbFHXk.js → index-CRiBkHPb.js} +2 -2
- package/dashboard/dist/assets/{index-_DfbFHXk.js.map → index-CRiBkHPb.js.map} +1 -1
- package/dashboard/dist/assets/{index-DdKbIZNE.js → index-CbrMW-gM.js} +2 -2
- package/dashboard/dist/assets/{index-DdKbIZNE.js.map → index-CbrMW-gM.js.map} +1 -1
- package/dashboard/dist/assets/{index-aJRDh4zW.js → index-CvOGgvzP.js} +2 -2
- package/dashboard/dist/assets/{index-aJRDh4zW.js.map → index-CvOGgvzP.js.map} +1 -1
- package/dashboard/dist/assets/{index-D1MywQ2z.js → index-DDlrQeTj.js} +2 -2
- package/dashboard/dist/assets/{index-D1MywQ2z.js.map → index-DDlrQeTj.js.map} +1 -1
- package/dashboard/dist/assets/{index-BYXiz05a.js → index-DQHmfTPo.js} +2 -2
- package/dashboard/dist/assets/{index-BYXiz05a.js.map → index-DQHmfTPo.js.map} +1 -1
- package/dashboard/dist/assets/{index-BpN31nuC.js → index-_BRA9uFL.js} +25 -25
- package/dashboard/dist/assets/index-_BRA9uFL.js.map +1 -0
- package/dashboard/dist/assets/index-a98qWLB-.js +2 -0
- package/dashboard/dist/assets/index-a98qWLB-.js.map +1 -0
- package/dashboard/dist/assets/index-l_8R6U4r.js +6 -0
- package/dashboard/dist/assets/index-l_8R6U4r.js.map +1 -0
- package/dashboard/dist/assets/{index-D4KGadbW.js → index-v0OQpgXS.js} +2 -2
- package/dashboard/dist/assets/{index-D4KGadbW.js.map → index-v0OQpgXS.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-DhtKWMON.js → knowledge-BlF8UMrk.js} +2 -2
- package/dashboard/dist/assets/{knowledge-DhtKWMON.js.map → knowledge-BlF8UMrk.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-BXN7-wGF.js → mcp-MtXuky8q.js} +2 -2
- package/dashboard/dist/assets/{mcp-BXN7-wGF.js.map → mcp-MtXuky8q.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-BIJP4mQJ.js → mcp-query-DQ-J1Q0K.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-BIJP4mQJ.js.map → mcp-query-DQ-J1Q0K.js.map} +1 -1
- package/dashboard/dist/assets/{namespaces-ne_yDQZX.js → namespaces-DtsT_GoV.js} +2 -2
- package/dashboard/dist/assets/{namespaces-ne_yDQZX.js.map → namespaces-DtsT_GoV.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-Bcz62DoS.js → pipelines-BjlCm9VH.js} +2 -2
- package/dashboard/dist/assets/{pipelines-Bcz62DoS.js.map → pipelines-BjlCm9VH.js.map} +1 -1
- package/dashboard/dist/assets/{roles-De2CzGCy.js → roles-D-LhJ82d.js} +2 -2
- package/dashboard/dist/assets/{roles-De2CzGCy.js.map → roles-D-LhJ82d.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-4yL5EfxI.js → tasks-BrP_8uEN.js} +2 -2
- package/dashboard/dist/assets/{tasks-4yL5EfxI.js.map → tasks-BrP_8uEN.js.map} +1 -1
- package/dashboard/dist/assets/topics-DUk-zX5D.js +2 -0
- package/dashboard/dist/assets/{topics-DDKHpRwP.js.map → topics-DUk-zX5D.js.map} +1 -1
- package/dashboard/dist/assets/useEventHooks-XNNzwADV.js +2 -0
- package/dashboard/dist/assets/useEventHooks-XNNzwADV.js.map +1 -0
- package/dashboard/dist/assets/{useYamlActivityEvents-Dv6GhDkh.js → useYamlActivityEvents-DANQ5jIY.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-Dv6GhDkh.js.map → useYamlActivityEvents-DANQ5jIY.js.map} +1 -1
- package/dashboard/dist/assets/{users-pSMWP58G.js → users-vj0JgOkA.js} +2 -2
- package/dashboard/dist/assets/{users-pSMWP58G.js.map → users-vj0JgOkA.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-CrrAvF2g.js → vendor-icons-Doy0g69_.js} +116 -111
- package/dashboard/dist/assets/vendor-icons-Doy0g69_.js.map +1 -0
- package/dashboard/dist/assets/{workflows-COYPOe2I.js → workflows-CmqgGPzI.js} +2 -2
- package/dashboard/dist/assets/{workflows-COYPOe2I.js.map → workflows-CmqgGPzI.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-1dF3ig6u.js → yaml-workflows-DNFyjBXH.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-1dF3ig6u.js.map → yaml-workflows-DNFyjBXH.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/controlplane.md +1 -1
- package/docs/api/http/mcp-endpoint.md +133 -0
- package/docs/api/http/roles.md +46 -0
- package/docs/api/http/service-accounts.md +15 -0
- package/docs/api/http/settings.md +6 -0
- package/docs/api/mcp/admin.md +1187 -0
- package/docs/api/mcp/claude-code.md +47 -0
- package/docs/api/mcp/docs.md +54 -0
- package/docs/api/mcp/events.md +80 -0
- package/docs/api/mcp/file-storage.md +76 -0
- package/docs/api/mcp/http-fetch.md +64 -0
- package/docs/api/mcp/human-queue.md +101 -0
- package/docs/api/mcp/index.md +52 -0
- package/docs/api/mcp/knowledge.md +125 -0
- package/docs/api/mcp/oauth.md +62 -0
- package/docs/api/mcp/schema-exchange.md +56 -0
- package/docs/api/mcp/translation.md +28 -0
- package/docs/api/mcp/vision.md +46 -0
- package/docs/api/sdk/settings.md +3 -1
- package/docs/auth.md +109 -0
- package/docs/dashboard.md +1 -1
- package/package.json +1 -1
- package/build/system/mcp-servers/playwright/browser-lifecycle.d.ts +0 -26
- package/build/system/mcp-servers/playwright/browser-lifecycle.js +0 -125
- package/build/system/mcp-servers/playwright/index.d.ts +0 -25
- package/build/system/mcp-servers/playwright/index.js +0 -42
- package/build/system/mcp-servers/playwright/schemas.d.ts +0 -394
- package/build/system/mcp-servers/playwright/schemas.js +0 -90
- package/build/system/mcp-servers/playwright/tools-atomic.d.ts +0 -2
- package/build/system/mcp-servers/playwright/tools-atomic.js +0 -9
- package/build/system/mcp-servers/playwright/tools-navigation.d.ts +0 -2
- package/build/system/mcp-servers/playwright/tools-navigation.js +0 -153
- package/build/system/mcp-servers/playwright/tools-page-interaction.d.ts +0 -2
- package/build/system/mcp-servers/playwright/tools-page-interaction.js +0 -162
- package/build/system/mcp-servers/playwright/tools-run-script.d.ts +0 -2
- package/build/system/mcp-servers/playwright/tools-run-script.js +0 -207
- package/build/system/mcp-servers/playwright/types.d.ts +0 -8
- package/build/system/mcp-servers/playwright/types.js +0 -30
- package/build/system/mcp-servers/playwright/vision-helper.d.ts +0 -12
- package/build/system/mcp-servers/playwright/vision-helper.js +0 -81
- package/build/system/mcp-servers/playwright-cli/helpers.d.ts +0 -11
- package/build/system/mcp-servers/playwright-cli/helpers.js +0 -20
- package/build/system/mcp-servers/playwright-cli/index.d.ts +0 -4
- package/build/system/mcp-servers/playwright-cli/index.js +0 -15
- package/build/system/mcp-servers/playwright-cli/schemas.d.ts +0 -219
- package/build/system/mcp-servers/playwright-cli/schemas.js +0 -75
- package/build/system/mcp-servers/playwright-cli/tools-auth.d.ts +0 -2
- package/build/system/mcp-servers/playwright-cli/tools-auth.js +0 -183
- package/build/system/mcp-servers/playwright-cli/tools-capture.d.ts +0 -2
- package/build/system/mcp-servers/playwright-cli/tools-capture.js +0 -273
- package/build/system/seed/tool-manifests-browser.d.ts +0 -577
- package/build/system/seed/tool-manifests-browser.js +0 -158
- package/dashboard/dist/assets/AgentConfigPage-DBtvb2x5.js +0 -16
- package/dashboard/dist/assets/AgentConfigPage-DBtvb2x5.js.map +0 -1
- package/dashboard/dist/assets/AgentDetailPage-3mZA7SOb.js.map +0 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-CA9x9o5s.js +0 -2
- package/dashboard/dist/assets/BotPicker-BQp_Vs73.js +0 -2
- package/dashboard/dist/assets/CronLabel-DY8VdTS9.js +0 -2
- package/dashboard/dist/assets/CronLabel-DY8VdTS9.js.map +0 -1
- package/dashboard/dist/assets/ElapsedCell-BPYm8RA7.js +0 -2
- package/dashboard/dist/assets/EventTopicPill-CCWCs07y.js +0 -2
- package/dashboard/dist/assets/EventTopicPill-CCWCs07y.js.map +0 -1
- package/dashboard/dist/assets/HomePage-CwRebzmO.js +0 -2
- package/dashboard/dist/assets/HomePage-CwRebzmO.js.map +0 -1
- package/dashboard/dist/assets/ListToolbar-DEef1_-T.js +0 -2
- package/dashboard/dist/assets/McpRunDetailPage-X0sfRFTk.js +0 -2
- package/dashboard/dist/assets/McpRunDetailPage-X0sfRFTk.js.map +0 -1
- package/dashboard/dist/assets/McpRunsPage-aZg057y3.js +0 -2
- package/dashboard/dist/assets/OperatorDashboard-iZEHnndU.js +0 -2
- package/dashboard/dist/assets/OperatorDashboard-iZEHnndU.js.map +0 -1
- package/dashboard/dist/assets/ServerName-Q6okiv4f.js +0 -2
- package/dashboard/dist/assets/TopicDetailPage-DW97-YHQ.js +0 -9
- package/dashboard/dist/assets/TopicDetailPage-DW97-YHQ.js.map +0 -1
- package/dashboard/dist/assets/WorkflowsDashboard-eCH4gpAk.js +0 -2
- package/dashboard/dist/assets/WorkflowsDashboard-eCH4gpAk.js.map +0 -1
- package/dashboard/dist/assets/index-3n5VREXN.js +0 -2
- package/dashboard/dist/assets/index-BAXzN-QB.js +0 -6
- package/dashboard/dist/assets/index-BAXzN-QB.js.map +0 -1
- package/dashboard/dist/assets/index-BpN31nuC.js.map +0 -1
- package/dashboard/dist/assets/index-C37LMzJa.css +0 -1
- package/dashboard/dist/assets/index-C5dHozmW.js +0 -2
- package/dashboard/dist/assets/index-C5dHozmW.js.map +0 -1
- package/dashboard/dist/assets/index-UtAfnStw.js +0 -15
- package/dashboard/dist/assets/topics-DDKHpRwP.js +0 -2
- package/dashboard/dist/assets/useEventHooks-NzIyvoGY.js +0 -2
- package/dashboard/dist/assets/useEventHooks-NzIyvoGY.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-CrrAvF2g.js.map +0 -1
|
@@ -40,7 +40,23 @@ function applyInputMapping(mapping, event) {
|
|
|
40
40
|
if (typeof value === 'string') {
|
|
41
41
|
result[key] = resolveTemplate(value, event);
|
|
42
42
|
}
|
|
43
|
-
else if (
|
|
43
|
+
else if (Array.isArray(value)) {
|
|
44
|
+
result[key] = value.map((item) => {
|
|
45
|
+
if (typeof item === 'string') {
|
|
46
|
+
const resolved = resolveTemplate(item, event);
|
|
47
|
+
// Coerce scalars to strings when the template was a string in an array context.
|
|
48
|
+
// Objects/arrays pass through (e.g., "{event.data}" resolves to the full object).
|
|
49
|
+
if (resolved !== null && resolved !== undefined && typeof resolved !== 'object') {
|
|
50
|
+
return String(resolved);
|
|
51
|
+
}
|
|
52
|
+
return resolved;
|
|
53
|
+
}
|
|
54
|
+
if (item && typeof item === 'object')
|
|
55
|
+
return applyInputMapping(item, event);
|
|
56
|
+
return item;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
else if (value && typeof value === 'object') {
|
|
44
60
|
result[key] = applyInputMapping(value, event);
|
|
45
61
|
}
|
|
46
62
|
else {
|
|
@@ -49,4 +49,20 @@ export declare function findByMetadata(key: string, value: string, status?: stri
|
|
|
49
49
|
escalations: LTEscalationRecord[];
|
|
50
50
|
total: number;
|
|
51
51
|
}>;
|
|
52
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Atomic claim by metadata with inline RBAC.
|
|
54
|
+
* The SQL WHERE clause enforces role membership — if the caller
|
|
55
|
+
* doesn't have an allowed role, zero rows match and the claim
|
|
56
|
+
* never happens. No pre-flight find, no TOCTOU.
|
|
57
|
+
*
|
|
58
|
+
* @param allowedRoles — roles the caller can claim (null = no filter / global access)
|
|
59
|
+
* @returns `{ escalation, isExtension, candidatesExist }` or null
|
|
60
|
+
*/
|
|
61
|
+
export declare function claimByMetadata(key: string, value: string, userId: string, durationMinutes?: number, metadata?: Record<string, any>, allowedRoles?: string[] | null): Promise<(ClaimResult & {
|
|
62
|
+
candidatesExist: number;
|
|
63
|
+
}) | null>;
|
|
64
|
+
/**
|
|
65
|
+
* Atomic resolve by metadata: find + claim + resolve in one CTE.
|
|
66
|
+
* RBAC is enforced in the SQL WHERE clause via allowedRoles.
|
|
67
|
+
*/
|
|
68
|
+
export declare function resolveByMetadataAtomic(key: string, value: string, userId: string, resolverPayload: Record<string, any>, metadata?: Record<string, any>, allowedRoles?: string[] | null): Promise<LTEscalationRecord | null>;
|
|
@@ -16,6 +16,7 @@ exports.enrichEscalationRouting = enrichEscalationRouting;
|
|
|
16
16
|
exports.getEscalationsByOriginId = getEscalationsByOriginId;
|
|
17
17
|
exports.findByMetadata = findByMetadata;
|
|
18
18
|
exports.claimByMetadata = claimByMetadata;
|
|
19
|
+
exports.resolveByMetadataAtomic = resolveByMetadataAtomic;
|
|
19
20
|
const db_1 = require("../../lib/db");
|
|
20
21
|
const publish_1 = require("../../lib/events/publish");
|
|
21
22
|
const logger_1 = require("../../lib/logger");
|
|
@@ -135,7 +136,20 @@ async function getEscalationRoles(ids) {
|
|
|
135
136
|
async function releaseEscalation(id, userId) {
|
|
136
137
|
const pool = (0, db_1.getPool)();
|
|
137
138
|
const { rows } = await pool.query(sql_1.RELEASE_ESCALATION, [id, userId]);
|
|
138
|
-
|
|
139
|
+
const released = rows[0];
|
|
140
|
+
if (released) {
|
|
141
|
+
(0, publish_1.publishEscalationEvent)({
|
|
142
|
+
type: 'escalation.released',
|
|
143
|
+
source: 'service',
|
|
144
|
+
workflowId: released.workflow_id || '',
|
|
145
|
+
workflowName: released.workflow_type || '',
|
|
146
|
+
taskQueue: released.task_queue || '',
|
|
147
|
+
escalationId: released.id,
|
|
148
|
+
status: 'released',
|
|
149
|
+
data: { released_by: userId },
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return released || null;
|
|
139
153
|
}
|
|
140
154
|
async function releaseExpiredClaims() {
|
|
141
155
|
const pool = (0, db_1.getPool)();
|
|
@@ -192,24 +206,32 @@ async function getEscalationsByOriginId(originId) {
|
|
|
192
206
|
async function findByMetadata(key, value, status, limit = 50, offset = 0) {
|
|
193
207
|
const pool = (0, db_1.getPool)();
|
|
194
208
|
const filter = JSON.stringify({ [key]: value });
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
return {
|
|
200
|
-
escalations: dataResult.rows,
|
|
201
|
-
total: parseInt(countResult.rows[0].count, 10),
|
|
202
|
-
};
|
|
209
|
+
const { rows } = await pool.query(sql_1.FIND_BY_METADATA, [filter, status || null, limit, offset]);
|
|
210
|
+
const total = rows.length > 0 ? parseInt(rows[0]._total, 10) : 0;
|
|
211
|
+
// Strip the window function column from results
|
|
212
|
+
const escalations = rows.map(({ _total, ...rest }) => rest);
|
|
213
|
+
return { escalations, total };
|
|
203
214
|
}
|
|
204
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Atomic claim by metadata with inline RBAC.
|
|
217
|
+
* The SQL WHERE clause enforces role membership — if the caller
|
|
218
|
+
* doesn't have an allowed role, zero rows match and the claim
|
|
219
|
+
* never happens. No pre-flight find, no TOCTOU.
|
|
220
|
+
*
|
|
221
|
+
* @param allowedRoles — roles the caller can claim (null = no filter / global access)
|
|
222
|
+
* @returns `{ escalation, isExtension, candidatesExist }` or null
|
|
223
|
+
*/
|
|
224
|
+
async function claimByMetadata(key, value, userId, durationMinutes = 30, metadata, allowedRoles) {
|
|
205
225
|
const pool = (0, db_1.getPool)();
|
|
206
226
|
const filter = JSON.stringify({ [key]: value });
|
|
207
227
|
const metaPatch = metadata ? JSON.stringify(metadata) : null;
|
|
208
|
-
const
|
|
228
|
+
const roles = allowedRoles ?? null;
|
|
229
|
+
const { rows } = await pool.query(sql_1.CLAIM_BY_METADATA_GUARDED, [filter, userId, durationMinutes, metaPatch, roles]);
|
|
209
230
|
if (rows.length === 0)
|
|
210
231
|
return null;
|
|
211
232
|
const row = rows[0];
|
|
212
|
-
const
|
|
233
|
+
const { candidates_exist, prev_assigned_to, _total, ...rest } = row;
|
|
234
|
+
const escalation = rest;
|
|
213
235
|
(0, publish_1.publishEscalationEvent)({
|
|
214
236
|
type: 'escalation.claimed',
|
|
215
237
|
source: 'service',
|
|
@@ -222,6 +244,33 @@ async function claimByMetadata(key, value, userId, durationMinutes = 30, metadat
|
|
|
222
244
|
});
|
|
223
245
|
return {
|
|
224
246
|
escalation,
|
|
225
|
-
isExtension:
|
|
247
|
+
isExtension: prev_assigned_to === userId,
|
|
248
|
+
candidatesExist: parseInt(candidates_exist, 10),
|
|
226
249
|
};
|
|
227
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* Atomic resolve by metadata: find + claim + resolve in one CTE.
|
|
253
|
+
* RBAC is enforced in the SQL WHERE clause via allowedRoles.
|
|
254
|
+
*/
|
|
255
|
+
async function resolveByMetadataAtomic(key, value, userId, resolverPayload, metadata, allowedRoles) {
|
|
256
|
+
const pool = (0, db_1.getPool)();
|
|
257
|
+
const filter = JSON.stringify({ [key]: value });
|
|
258
|
+
const payloadJson = JSON.stringify(resolverPayload);
|
|
259
|
+
const metaPatch = metadata ? JSON.stringify(metadata) : null;
|
|
260
|
+
const roles = allowedRoles ?? null;
|
|
261
|
+
const { rows } = await pool.query(sql_1.RESOLVE_BY_METADATA_ATOMIC, [filter, userId, payloadJson, metaPatch, roles]);
|
|
262
|
+
if (rows.length === 0)
|
|
263
|
+
return null;
|
|
264
|
+
const escalation = rows[0];
|
|
265
|
+
(0, publish_1.publishEscalationEvent)({
|
|
266
|
+
type: 'escalation.resolved',
|
|
267
|
+
source: 'service',
|
|
268
|
+
workflowId: escalation.workflow_id || '',
|
|
269
|
+
workflowName: escalation.workflow_type || '',
|
|
270
|
+
taskQueue: escalation.task_queue || '',
|
|
271
|
+
escalationId: escalation.id,
|
|
272
|
+
status: 'resolved',
|
|
273
|
+
data: { resolved_by: userId },
|
|
274
|
+
});
|
|
275
|
+
return escalation;
|
|
276
|
+
}
|
|
@@ -96,6 +96,13 @@ async function listEscalations(filters) {
|
|
|
96
96
|
if (filters.assigned_to) {
|
|
97
97
|
conditions.push(`assigned_to = $${idx++}`);
|
|
98
98
|
values.push(filters.assigned_to);
|
|
99
|
+
// Only return active claims — expired claims are back in the available pool
|
|
100
|
+
conditions.push('assigned_until > NOW()');
|
|
101
|
+
}
|
|
102
|
+
if (filters.claimed) {
|
|
103
|
+
// All actively claimed escalations (by anyone)
|
|
104
|
+
conditions.push('assigned_to IS NOT NULL');
|
|
105
|
+
conditions.push('assigned_until > NOW()');
|
|
99
106
|
}
|
|
100
107
|
if (filters.priority) {
|
|
101
108
|
conditions.push(`priority = $${idx++}`);
|
|
@@ -19,8 +19,17 @@ export declare const BULK_RESOLVE_FOR_TRIAGE = "UPDATE lt_escalations\nSET statu
|
|
|
19
19
|
export declare const UPDATE_ESCALATION_METADATA = "UPDATE lt_escalations\nSET metadata = COALESCE(metadata, '{}'::jsonb) || $2::jsonb,\n updated_at = NOW()\nWHERE id = $1\nRETURNING *";
|
|
20
20
|
export declare const ENRICH_ESCALATION_ROUTING = "UPDATE lt_escalations\nSET metadata = COALESCE(metadata, '{}'::jsonb) || $2::jsonb,\n workflow_type = COALESCE(workflow_type, $3),\n workflow_id = COALESCE(workflow_id, $4),\n task_queue = COALESCE(task_queue, $5),\n task_id = COALESCE(task_id, $6),\n updated_at = NOW()\nWHERE id = $1\nRETURNING *";
|
|
21
21
|
export declare const LIST_DISTINCT_TYPES = "SELECT DISTINCT type FROM lt_escalations ORDER BY type";
|
|
22
|
-
/** Find escalations by a single metadata key-value pair. */
|
|
23
|
-
export declare const FIND_BY_METADATA = "SELECT *
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
/** Find escalations by a single metadata key-value pair. Window function for total count. */
|
|
23
|
+
export declare const FIND_BY_METADATA = "SELECT *, COUNT(*) OVER() AS _total\nFROM lt_escalations\nWHERE metadata @> $1::jsonb\n AND ($2::text IS NULL OR status = $2)\nORDER BY priority ASC, created_at ASC\nLIMIT $3 OFFSET $4";
|
|
24
|
+
/**
|
|
25
|
+
* Atomic claim by metadata with inline RBAC.
|
|
26
|
+
* $1 = metadata filter (jsonb), $2 = userId, $3 = durationMinutes,
|
|
27
|
+
* $4 = metadata patch (jsonb, nullable), $5 = allowed roles (text[], null = no filter)
|
|
28
|
+
*/
|
|
29
|
+
export declare const CLAIM_BY_METADATA_GUARDED = "WITH target AS (\n SELECT id, assigned_to\n FROM lt_escalations\n WHERE metadata @> $1::jsonb\n AND status = 'pending'\n AND (assigned_to IS NULL OR assigned_until <= NOW() OR assigned_to = $2)\n AND ($5::text[] IS NULL OR role = ANY($5))\n ORDER BY priority ASC, created_at ASC\n LIMIT 1\n FOR UPDATE SKIP LOCKED\n),\nupdated AS (\n UPDATE lt_escalations e\n SET assigned_to = $2,\n claimed_at = NOW(),\n assigned_until = NOW() + INTERVAL '1 minute' * $3,\n metadata = CASE WHEN $4::jsonb IS NOT NULL\n THEN COALESCE(e.metadata, '{}'::jsonb) || $4::jsonb\n ELSE e.metadata END,\n updated_at = NOW()\n FROM target t\n WHERE e.id = t.id\n RETURNING e.*, t.assigned_to AS prev_assigned_to\n)\nSELECT *,\n (SELECT COUNT(*) FROM lt_escalations WHERE metadata @> $1::jsonb AND status = 'pending') AS candidates_exist\nFROM updated";
|
|
30
|
+
/**
|
|
31
|
+
* Atomic resolve by metadata: find + claim + resolve in one CTE.
|
|
32
|
+
* $1 = metadata filter (jsonb), $2 = userId, $3 = resolver_payload (jsonb),
|
|
33
|
+
* $4 = metadata patch (jsonb, nullable), $5 = allowed roles (text[], null = no filter)
|
|
34
|
+
*/
|
|
35
|
+
export declare const RESOLVE_BY_METADATA_ATOMIC = "WITH target AS (\n SELECT id\n FROM lt_escalations\n WHERE metadata @> $1::jsonb\n AND status = 'pending'\n AND ($5::text[] IS NULL OR role = ANY($5))\n ORDER BY priority ASC, created_at ASC\n LIMIT 1\n FOR UPDATE SKIP LOCKED\n),\nclaimed AS (\n UPDATE lt_escalations e\n SET assigned_to = $2,\n claimed_at = NOW(),\n assigned_until = NOW() + INTERVAL '5 minutes',\n metadata = CASE WHEN $4::jsonb IS NOT NULL\n THEN COALESCE(e.metadata, '{}'::jsonb) || $4::jsonb\n ELSE e.metadata END\n FROM target\n WHERE e.id = target.id\n RETURNING e.*\n)\nUPDATE lt_escalations e\nSET status = 'resolved',\n resolved_at = NOW(),\n resolver_payload = $3,\n updated_at = NOW()\nFROM claimed\nWHERE e.id = claimed.id\nRETURNING e.*";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Escalation SQL – externalized from crud.ts, bulk.ts, queries.ts
|
|
4
4
|
// ---------------------------------------------------------------------------
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.RESOLVE_BY_METADATA_ATOMIC = exports.CLAIM_BY_METADATA_GUARDED = exports.FIND_BY_METADATA = exports.LIST_DISTINCT_TYPES = exports.ENRICH_ESCALATION_ROUTING = exports.UPDATE_ESCALATION_METADATA = exports.BULK_RESOLVE_FOR_TRIAGE = exports.BULK_ESCALATE_TO_ROLE = exports.BULK_ASSIGN = exports.BULK_CLAIM = exports.GET_ESCALATIONS_BY_ORIGIN_ID = exports.GET_ESCALATIONS_BY_WORKFLOW_ID = exports.GET_ESCALATIONS_BY_TASK_ID = exports.GET_ESCALATION = exports.ESCALATE_TO_ROLE = exports.RELEASE_EXPIRED_CLAIMS = exports.RELEASE_ESCALATION = exports.GET_ESCALATION_ROLES = exports.UPDATE_ESCALATIONS_PRIORITY = exports.RESOLVE_ESCALATION = exports.CLAIM_ESCALATION = exports.CREATE_ESCALATION = exports.ENSURE_ROLE_EXISTS = void 0;
|
|
7
7
|
// --- Role management -------------------------------------------------------
|
|
8
8
|
exports.ENSURE_ROLE_EXISTS = 'INSERT INTO lt_roles (role) VALUES ($1) ON CONFLICT DO NOTHING';
|
|
9
9
|
// --- Single-record CRUD ---------------------------------------------------
|
|
@@ -134,29 +134,27 @@ WHERE id = $1
|
|
|
134
134
|
RETURNING *`;
|
|
135
135
|
exports.LIST_DISTINCT_TYPES = 'SELECT DISTINCT type FROM lt_escalations ORDER BY type';
|
|
136
136
|
// --- Metadata candidate key lookups -----------------------------------------
|
|
137
|
-
/** Find escalations by a single metadata key-value pair. */
|
|
137
|
+
/** Find escalations by a single metadata key-value pair. Window function for total count. */
|
|
138
138
|
exports.FIND_BY_METADATA = `\
|
|
139
|
-
SELECT *
|
|
139
|
+
SELECT *, COUNT(*) OVER() AS _total
|
|
140
|
+
FROM lt_escalations
|
|
140
141
|
WHERE metadata @> $1::jsonb
|
|
141
142
|
AND ($2::text IS NULL OR status = $2)
|
|
142
143
|
ORDER BY priority ASC, created_at ASC
|
|
143
144
|
LIMIT $3 OFFSET $4`;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
exports.
|
|
145
|
+
/**
|
|
146
|
+
* Atomic claim by metadata with inline RBAC.
|
|
147
|
+
* $1 = metadata filter (jsonb), $2 = userId, $3 = durationMinutes,
|
|
148
|
+
* $4 = metadata patch (jsonb, nullable), $5 = allowed roles (text[], null = no filter)
|
|
149
|
+
*/
|
|
150
|
+
exports.CLAIM_BY_METADATA_GUARDED = `\
|
|
150
151
|
WITH target AS (
|
|
151
152
|
SELECT id, assigned_to
|
|
152
153
|
FROM lt_escalations
|
|
153
154
|
WHERE metadata @> $1::jsonb
|
|
154
155
|
AND status = 'pending'
|
|
155
|
-
AND (
|
|
156
|
-
|
|
157
|
-
OR assigned_until <= NOW()
|
|
158
|
-
OR assigned_to = $2
|
|
159
|
-
)
|
|
156
|
+
AND (assigned_to IS NULL OR assigned_until <= NOW() OR assigned_to = $2)
|
|
157
|
+
AND ($5::text[] IS NULL OR role = ANY($5))
|
|
160
158
|
ORDER BY priority ASC, created_at ASC
|
|
161
159
|
LIMIT 1
|
|
162
160
|
FOR UPDATE SKIP LOCKED
|
|
@@ -168,9 +166,48 @@ updated AS (
|
|
|
168
166
|
assigned_until = NOW() + INTERVAL '1 minute' * $3,
|
|
169
167
|
metadata = CASE WHEN $4::jsonb IS NOT NULL
|
|
170
168
|
THEN COALESCE(e.metadata, '{}'::jsonb) || $4::jsonb
|
|
171
|
-
ELSE e.metadata END
|
|
169
|
+
ELSE e.metadata END,
|
|
170
|
+
updated_at = NOW()
|
|
172
171
|
FROM target t
|
|
173
172
|
WHERE e.id = t.id
|
|
174
173
|
RETURNING e.*, t.assigned_to AS prev_assigned_to
|
|
175
174
|
)
|
|
176
|
-
SELECT
|
|
175
|
+
SELECT *,
|
|
176
|
+
(SELECT COUNT(*) FROM lt_escalations WHERE metadata @> $1::jsonb AND status = 'pending') AS candidates_exist
|
|
177
|
+
FROM updated`;
|
|
178
|
+
/**
|
|
179
|
+
* Atomic resolve by metadata: find + claim + resolve in one CTE.
|
|
180
|
+
* $1 = metadata filter (jsonb), $2 = userId, $3 = resolver_payload (jsonb),
|
|
181
|
+
* $4 = metadata patch (jsonb, nullable), $5 = allowed roles (text[], null = no filter)
|
|
182
|
+
*/
|
|
183
|
+
exports.RESOLVE_BY_METADATA_ATOMIC = `\
|
|
184
|
+
WITH target AS (
|
|
185
|
+
SELECT id
|
|
186
|
+
FROM lt_escalations
|
|
187
|
+
WHERE metadata @> $1::jsonb
|
|
188
|
+
AND status = 'pending'
|
|
189
|
+
AND ($5::text[] IS NULL OR role = ANY($5))
|
|
190
|
+
ORDER BY priority ASC, created_at ASC
|
|
191
|
+
LIMIT 1
|
|
192
|
+
FOR UPDATE SKIP LOCKED
|
|
193
|
+
),
|
|
194
|
+
claimed AS (
|
|
195
|
+
UPDATE lt_escalations e
|
|
196
|
+
SET assigned_to = $2,
|
|
197
|
+
claimed_at = NOW(),
|
|
198
|
+
assigned_until = NOW() + INTERVAL '5 minutes',
|
|
199
|
+
metadata = CASE WHEN $4::jsonb IS NOT NULL
|
|
200
|
+
THEN COALESCE(e.metadata, '{}'::jsonb) || $4::jsonb
|
|
201
|
+
ELSE e.metadata END
|
|
202
|
+
FROM target
|
|
203
|
+
WHERE e.id = target.id
|
|
204
|
+
RETURNING e.*
|
|
205
|
+
)
|
|
206
|
+
UPDATE lt_escalations e
|
|
207
|
+
SET status = 'resolved',
|
|
208
|
+
resolved_at = NOW(),
|
|
209
|
+
resolver_payload = $3,
|
|
210
|
+
updated_at = NOW()
|
|
211
|
+
FROM claimed
|
|
212
|
+
WHERE e.id = claimed.id
|
|
213
|
+
RETURNING e.*`;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP exposure configuration — controls which tools are visible
|
|
3
|
+
* when long-tail acts as an MCP server for external clients.
|
|
4
|
+
*
|
|
5
|
+
* Set once at startup from startConfig.mcp.exposure.
|
|
6
|
+
* Read by the /mcp endpoint handler on each request.
|
|
7
|
+
*/
|
|
8
|
+
export interface ExposureConfig {
|
|
9
|
+
readOnly?: boolean;
|
|
10
|
+
hideAiWhenUnavailable?: boolean;
|
|
11
|
+
allowServers?: string[];
|
|
12
|
+
denyServers?: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare function setExposureConfig(config?: ExposureConfig): void;
|
|
15
|
+
export declare function getExposureConfig(): ExposureConfig | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MCP exposure configuration — controls which tools are visible
|
|
4
|
+
* when long-tail acts as an MCP server for external clients.
|
|
5
|
+
*
|
|
6
|
+
* Set once at startup from startConfig.mcp.exposure.
|
|
7
|
+
* Read by the /mcp endpoint handler on each request.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.setExposureConfig = setExposureConfig;
|
|
11
|
+
exports.getExposureConfig = getExposureConfig;
|
|
12
|
+
let _exposure;
|
|
13
|
+
function setExposureConfig(config) {
|
|
14
|
+
_exposure = config;
|
|
15
|
+
}
|
|
16
|
+
function getExposureConfig() {
|
|
17
|
+
return _exposure;
|
|
18
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified MCP server for external clients.
|
|
3
|
+
*
|
|
4
|
+
* Aggregates tools from all shipped built-in servers into a single
|
|
5
|
+
* McpServer instance that can be connected to a StreamableHTTPServerTransport.
|
|
6
|
+
* Created per-request in stateless mode (pure in-memory, no IO).
|
|
7
|
+
*/
|
|
8
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
|
+
import type { ExposureConfig } from './exposure';
|
|
10
|
+
/**
|
|
11
|
+
* Create a unified McpServer with tools from all qualifying shipped servers.
|
|
12
|
+
* Called per-request in stateless mode. Server instances are cached; only
|
|
13
|
+
* the McpServer wrapper and tool registrations are fresh (pure in-memory).
|
|
14
|
+
*/
|
|
15
|
+
export declare function createUnifiedMcpServer(exposure?: ExposureConfig, callerScopes?: string[]): Promise<McpServer>;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Unified MCP server for external clients.
|
|
4
|
+
*
|
|
5
|
+
* Aggregates tools from all shipped built-in servers into a single
|
|
6
|
+
* McpServer instance that can be connected to a StreamableHTTPServerTransport.
|
|
7
|
+
* Created per-request in stateless mode (pure in-memory, no IO).
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.createUnifiedMcpServer = createUnifiedMcpServer;
|
|
11
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
12
|
+
const logger_1 = require("../../lib/logger");
|
|
13
|
+
const system_1 = require("../../system");
|
|
14
|
+
// ── Shipped server allowlist ─────────────────────────────────────────────────
|
|
15
|
+
// Only these servers are exposed via the /mcp endpoint.
|
|
16
|
+
// Example servers (playwright, gmail, image-tools) are excluded.
|
|
17
|
+
const SHIPPED_SERVERS = new Set([
|
|
18
|
+
'long-tail-admin',
|
|
19
|
+
'long-tail-human-queue',
|
|
20
|
+
'long-tail-file-storage',
|
|
21
|
+
'long-tail-http-fetch',
|
|
22
|
+
'long-tail-schema-exchange',
|
|
23
|
+
'long-tail-oauth',
|
|
24
|
+
'long-tail-knowledge',
|
|
25
|
+
'long-tail-docs',
|
|
26
|
+
'long-tail-events',
|
|
27
|
+
'long-tail-vision',
|
|
28
|
+
'long-tail-translation',
|
|
29
|
+
'long-tail-claude-code',
|
|
30
|
+
]);
|
|
31
|
+
// ── Server instance cache ────────────────────────────────────────────────────
|
|
32
|
+
// Built-in servers are lazily created once and reused across requests.
|
|
33
|
+
// Tool handlers are stateless — safe to share.
|
|
34
|
+
const serverCache = new Map();
|
|
35
|
+
async function getOrCreateServer(name) {
|
|
36
|
+
if (serverCache.has(name))
|
|
37
|
+
return serverCache.get(name);
|
|
38
|
+
const entry = system_1.builtinMcpServerFactories[name];
|
|
39
|
+
if (!entry)
|
|
40
|
+
return null;
|
|
41
|
+
const server = await entry.factory();
|
|
42
|
+
serverCache.set(name, server);
|
|
43
|
+
return server;
|
|
44
|
+
}
|
|
45
|
+
// ── Exposure filtering ───────────────────────────────────────────────────────
|
|
46
|
+
function isServerAllowed(name, exposure) {
|
|
47
|
+
if (!SHIPPED_SERVERS.has(name))
|
|
48
|
+
return false;
|
|
49
|
+
if (exposure?.allowServers?.length) {
|
|
50
|
+
if (!exposure.allowServers.includes(name))
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (exposure?.denyServers?.length) {
|
|
54
|
+
if (exposure.denyServers.includes(name))
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
if (exposure?.hideAiWhenUnavailable !== false) {
|
|
58
|
+
const config = system_1.builtinMcpServerFactories[name]?.config;
|
|
59
|
+
if (config?.aiRequired) {
|
|
60
|
+
const hasKey = !!(process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY);
|
|
61
|
+
if (!hasKey)
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
function isToolAllowed(toolName, serverName, exposure, callerScopes) {
|
|
68
|
+
// Per-caller scope filtering: mcp:read callers only see read_safe tools
|
|
69
|
+
const isReadOnly = exposure?.readOnly
|
|
70
|
+
|| (callerScopes?.length && callerScopes.includes('mcp:read') && !callerScopes.includes('mcp:full'));
|
|
71
|
+
if (!isReadOnly)
|
|
72
|
+
return true;
|
|
73
|
+
// Check read_safe in the tool manifest
|
|
74
|
+
const config = system_1.builtinMcpServerFactories[serverName]?.config;
|
|
75
|
+
const manifest = config?.toolManifest;
|
|
76
|
+
if (!manifest)
|
|
77
|
+
return true; // no manifest = allow (conservative)
|
|
78
|
+
const entry = manifest.find((t) => t.name === toolName);
|
|
79
|
+
return entry?.read_safe !== false; // allow if read_safe is true or absent
|
|
80
|
+
}
|
|
81
|
+
// ── Unified server creation ──────────────────────────────────────────────────
|
|
82
|
+
/**
|
|
83
|
+
* Create a unified McpServer with tools from all qualifying shipped servers.
|
|
84
|
+
* Called per-request in stateless mode. Server instances are cached; only
|
|
85
|
+
* the McpServer wrapper and tool registrations are fresh (pure in-memory).
|
|
86
|
+
*/
|
|
87
|
+
async function createUnifiedMcpServer(exposure, callerScopes) {
|
|
88
|
+
const unified = new mcp_js_1.McpServer({ name: 'long-tail', version: '1.0.0' });
|
|
89
|
+
const registered = new Set();
|
|
90
|
+
for (const [name, entry] of Object.entries(system_1.builtinMcpServerFactories)) {
|
|
91
|
+
if (!isServerAllowed(name, exposure))
|
|
92
|
+
continue;
|
|
93
|
+
const server = await getOrCreateServer(name);
|
|
94
|
+
if (!server)
|
|
95
|
+
continue;
|
|
96
|
+
const tools = server._registeredTools;
|
|
97
|
+
if (!tools)
|
|
98
|
+
continue;
|
|
99
|
+
for (const [toolName, tool] of Object.entries(tools)) {
|
|
100
|
+
if (!tool?.handler || !tool.enabled)
|
|
101
|
+
continue;
|
|
102
|
+
if (!isToolAllowed(toolName, name, exposure, callerScopes))
|
|
103
|
+
continue;
|
|
104
|
+
// Deduplicate: prefix with server short name on collision
|
|
105
|
+
let finalName = toolName;
|
|
106
|
+
if (registered.has(toolName)) {
|
|
107
|
+
const prefix = name.replace('long-tail-', '').replace(/-/g, '_');
|
|
108
|
+
finalName = `${prefix}_${toolName}`;
|
|
109
|
+
if (registered.has(finalName))
|
|
110
|
+
continue; // still a collision — skip
|
|
111
|
+
}
|
|
112
|
+
registered.add(finalName);
|
|
113
|
+
// Re-register the tool handler on the unified server.
|
|
114
|
+
// Use the low-level `tool()` API since we already have the parsed handler.
|
|
115
|
+
unified.registerTool(finalName, {
|
|
116
|
+
title: tool.title,
|
|
117
|
+
description: tool.description,
|
|
118
|
+
inputSchema: tool.inputSchema,
|
|
119
|
+
annotations: tool.annotations,
|
|
120
|
+
}, tool.handler);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
logger_1.loggerRegistry.info(`[lt-mcp:endpoint] unified server ready (${registered.size} tools)`);
|
|
124
|
+
return unified;
|
|
125
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seed the MCP service account at startup.
|
|
3
|
+
*
|
|
4
|
+
* Creates a single `mcp-service` bot account with two API keys:
|
|
5
|
+
* - `mcp:read` — read-safe tools only (discovery, monitoring)
|
|
6
|
+
* - `mcp:full` — all tools (automation, orchestration)
|
|
7
|
+
*
|
|
8
|
+
* Idempotent — skips creation if the account already exists.
|
|
9
|
+
* Keys are generated once and logged; they cannot be retrieved again.
|
|
10
|
+
*/
|
|
11
|
+
export declare function seedMcpServiceAccount(): Promise<void>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Seed the MCP service account at startup.
|
|
4
|
+
*
|
|
5
|
+
* Creates a single `mcp-service` bot account with two API keys:
|
|
6
|
+
* - `mcp:read` — read-safe tools only (discovery, monitoring)
|
|
7
|
+
* - `mcp:full` — all tools (automation, orchestration)
|
|
8
|
+
*
|
|
9
|
+
* Idempotent — skips creation if the account already exists.
|
|
10
|
+
* Keys are generated once and logged; they cannot be retrieved again.
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.seedMcpServiceAccount = seedMcpServiceAccount;
|
|
47
|
+
const logger_1 = require("../../lib/logger");
|
|
48
|
+
const crud_1 = require("../user/crud");
|
|
49
|
+
const iam = __importStar(require("../iam"));
|
|
50
|
+
const SERVICE_ACCOUNT_NAME = 'mcp-service';
|
|
51
|
+
async function seedMcpServiceAccount() {
|
|
52
|
+
try {
|
|
53
|
+
// Check if account already exists (bot external_id = name)
|
|
54
|
+
const existing = await (0, crud_1.getUserByExternalId)(SERVICE_ACCOUNT_NAME);
|
|
55
|
+
if (existing) {
|
|
56
|
+
logger_1.loggerRegistry.info(`[seed-mcp] ${SERVICE_ACCOUNT_NAME} already exists, skipping`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Create the service account
|
|
60
|
+
const bot = await iam.createBot({
|
|
61
|
+
name: SERVICE_ACCOUNT_NAME,
|
|
62
|
+
description: 'MCP service account for external tool access. Use the read key to explore, full key to automate.',
|
|
63
|
+
display_name: 'MCP Service',
|
|
64
|
+
roles: [{ role: 'system', type: 'member' }],
|
|
65
|
+
});
|
|
66
|
+
// Generate read key (scoped to mcp:read)
|
|
67
|
+
const readKey = await iam.createBotKey(bot.id, 'read', ['mcp:read']);
|
|
68
|
+
logger_1.loggerRegistry.info(`[seed-mcp] read key: ${readKey.rawKey}`);
|
|
69
|
+
// Generate full key (scoped to mcp:full)
|
|
70
|
+
const fullKey = await iam.createBotKey(bot.id, 'full', ['mcp:read', 'mcp:full']);
|
|
71
|
+
logger_1.loggerRegistry.info(`[seed-mcp] full key: ${fullKey.rawKey}`);
|
|
72
|
+
logger_1.loggerRegistry.info(`[seed-mcp] ${SERVICE_ACCOUNT_NAME} created with read + full API keys`);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
logger_1.loggerRegistry.warn(`[seed-mcp] failed to seed: ${err.message}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -21,7 +21,7 @@ export declare function removeEscalationChain(sourceRole: string, targetRole: st
|
|
|
21
21
|
export declare function replaceEscalationTargets(sourceRole: string, targets: string[]): Promise<void>;
|
|
22
22
|
/**
|
|
23
23
|
* Check whether a user can escalate from sourceRole to targetRole.
|
|
24
|
-
* Superadmins can escalate to any role.
|
|
24
|
+
* Superadmins and admin/admin can escalate to any role.
|
|
25
25
|
* Others must hold the sourceRole AND the chain must exist.
|
|
26
26
|
*/
|
|
27
27
|
export declare function canEscalateTo(userId: string, sourceRole: string, targetRole: string): Promise<boolean>;
|
|
@@ -74,11 +74,11 @@ async function replaceEscalationTargets(sourceRole, targets) {
|
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
76
|
* Check whether a user can escalate from sourceRole to targetRole.
|
|
77
|
-
* Superadmins can escalate to any role.
|
|
77
|
+
* Superadmins and admin/admin can escalate to any role.
|
|
78
78
|
* Others must hold the sourceRole AND the chain must exist.
|
|
79
79
|
*/
|
|
80
80
|
async function canEscalateTo(userId, sourceRole, targetRole) {
|
|
81
|
-
if (await (0, user_1.
|
|
81
|
+
if (await (0, user_1.hasGlobalEscalationAccess)(userId))
|
|
82
82
|
return true;
|
|
83
83
|
if (!(await (0, user_1.hasRole)(userId, sourceRole)))
|
|
84
84
|
return false;
|