@hotmeshio/long-tail 0.12.1 → 0.13.1
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 +1 -0
- package/build/api/auth-sso.d.ts +6 -3
- package/build/api/auth-sso.js +6 -3
- package/build/api/escalations/helpers.js +4 -2
- package/build/api/settings.js +3 -0
- package/build/modules/auth.js +9 -3
- package/build/routes/auth-sso.js +6 -1
- package/build/services/agent/index.d.ts +11 -0
- package/build/services/agent/index.js +32 -0
- package/build/services/agent/sql.d.ts +7 -0
- package/build/services/agent/sql.js +32 -1
- package/build/services/agent/subscription-sql.d.ts +6 -0
- package/build/services/agent/subscription-sql.js +32 -1
- package/build/services/agent/subscriptions.d.ts +6 -0
- package/build/services/agent/subscriptions.js +23 -0
- package/build/services/config/index.d.ts +1 -1
- package/build/services/config/index.js +2 -1
- package/build/services/config/write.d.ts +10 -0
- package/build/services/config/write.js +49 -2
- package/build/services/domain/seed.d.ts +12 -5
- package/build/services/domain/seed.js +25 -6
- package/build/services/mcp/db.d.ts +16 -0
- package/build/services/mcp/db.js +24 -0
- package/build/services/mcp/sql.d.ts +8 -0
- package/build/services/mcp/sql.js +24 -1
- package/build/services/role/seed.d.ts +21 -0
- package/build/services/role/seed.js +113 -0
- package/build/services/role/sql.d.ts +8 -0
- package/build/services/role/sql.js +24 -1
- package/build/services/scan-code/index.d.ts +1 -1
- package/build/services/scan-code/index.js +3 -1
- package/build/services/scan-code/sql.d.ts +7 -0
- package/build/services/scan-code/sql.js +55 -1
- package/build/services/scan-code/write.d.ts +8 -0
- package/build/services/scan-code/write.js +23 -1
- package/build/services/topics/index.d.ts +2 -0
- package/build/services/topics/index.js +7 -0
- package/build/services/topics/sql.d.ts +2 -0
- package/build/services/topics/sql.js +5 -1
- package/build/services/topics/system-topics.d.ts +3 -2
- package/build/services/topics/system-topics.js +4 -3
- package/build/services/user/index.d.ts +1 -1
- package/build/services/user/index.js +2 -1
- package/build/services/user/roles.d.ts +8 -0
- package/build/services/user/roles.js +29 -0
- package/build/services/user/sql.d.ts +6 -0
- package/build/services/user/sql.js +9 -1
- package/build/services/user/sso-provision.js +14 -3
- package/build/start/apply-report.d.ts +26 -0
- package/build/start/apply-report.js +65 -0
- package/build/start/config.js +8 -1
- package/build/start/workers.js +222 -33
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/auth.d.ts +44 -4
- package/build/types/index.d.ts +1 -1
- package/build/types/startup.d.ts +160 -4
- package/dashboard/dist/assets/{AdminDashboard-DpTZG5EL.js → AdminDashboard-D2unnS2b.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-DpTZG5EL.js.map → AdminDashboard-D2unnS2b.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-DVTL0NvC.js → AgentConfigPage-CBkf403g.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-DVTL0NvC.js.map → AgentConfigPage-CBkf403g.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-DOLKNPJl.js → AgentDetailPage-CAIU3yzo.js} +2 -2
- package/dashboard/dist/assets/{AgentDetailPage-DOLKNPJl.js.map → AgentDetailPage-CAIU3yzo.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-DiOZu6Xb.js → AgentsPage-qP9fWMyT.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-DiOZu6Xb.js.map → AgentsPage-qP9fWMyT.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-CY5lfx27.js → AvailableEscalationsPage-DvWaiafI.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-CY5lfx27.js.map → AvailableEscalationsPage-DvWaiafI.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-ButjLJr2.js → BotPicker-BN-MKITV.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-ButjLJr2.js.map → BotPicker-BN-MKITV.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-CW_r2OlX.js → CapabilitiesPage-CJfmWokN.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-CW_r2OlX.js.map → CapabilitiesPage-CJfmWokN.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-BOGRyCfm.js → CollapsibleSection-BvMHlHyt.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-BOGRyCfm.js.map → CollapsibleSection-BvMHlHyt.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-UcHYZSg1.js → CountdownTimer-By4rbMDN.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-UcHYZSg1.js.map → CountdownTimer-By4rbMDN.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-A7OFYVsX.js → CredentialsPage-2TvvRwGJ.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-A7OFYVsX.js.map → CredentialsPage-2TvvRwGJ.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-Dve2Udsm.js → CronLabel-HxmsDSnV.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-Dve2Udsm.js.map → CronLabel-HxmsDSnV.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-BoPrA-Em.js → CustomDurationPicker-8Ao-1pKA.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-BoPrA-Em.js.map → CustomDurationPicker-8Ao-1pKA.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-B114P5mb.js → ElapsedCell-BkRu9Xpd.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-B114P5mb.js.map → ElapsedCell-BkRu9Xpd.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-BqDWyOa9.js → EntityTimelinePanel--E6hLMCM.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-BqDWyOa9.js.map → EntityTimelinePanel--E6hLMCM.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-DyyTyghx.js → EscalationListSchemaPage-CdFtqEEX.js} +2 -2
- package/dashboard/dist/assets/{EscalationListSchemaPage-DyyTyghx.js.map → EscalationListSchemaPage-CdFtqEEX.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-DLQG6EXQ.js → EscalationSchemaPage-BsjS2axz.js} +2 -2
- package/dashboard/dist/assets/{EscalationSchemaPage-DLQG6EXQ.js.map → EscalationSchemaPage-BsjS2axz.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-RrbkkEU0.js → EscalationsOverview-FL-xteVc.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-RrbkkEU0.js.map → EscalationsOverview-FL-xteVc.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-DOxubt7O.js → EventTable-BOcgZ78i.js} +2 -2
- package/dashboard/dist/assets/{EventTable-DOxubt7O.js.map → EventTable-BOcgZ78i.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-y659Gc3X.js → FilterBar-DfCiCmm-.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-y659Gc3X.js.map → FilterBar-DfCiCmm-.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-oHLgSAl6.js → GraphInvokePage-DfVeiN-8.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-oHLgSAl6.js.map → GraphInvokePage-DfVeiN-8.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-C9FUpD7x.js → HomePage-C2IhF9WB.js} +2 -2
- package/dashboard/dist/assets/{HomePage-C9FUpD7x.js.map → HomePage-C2IhF9WB.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-DfpSgWYU.js → ListToolbar-DA0PTOl5.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-DfpSgWYU.js.map → ListToolbar-DA0PTOl5.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-6Ubpr9QS.js → McpOverview-DstPch5M.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-6Ubpr9QS.js.map → McpOverview-DstPch5M.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-DFt-vQEp.js → McpQueryDetailPage-Csv0PKE0.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-DFt-vQEp.js.map → McpQueryDetailPage-Csv0PKE0.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-DQiG0AE3.js → McpQueryPage-DxmqCkly.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-DQiG0AE3.js.map → McpQueryPage-DxmqCkly.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-BgsSegyP.js → McpRunDetailPage-CcJOlp_B.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-BgsSegyP.js.map → McpRunDetailPage-CcJOlp_B.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-tCMxspqS.js → McpRunsPage-BZCR043j.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-tCMxspqS.js.map → McpRunsPage-BZCR043j.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-DUaRmEPa.js → OperationsPage-DMsPXITh.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-DUaRmEPa.js.map → OperationsPage-DMsPXITh.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-CayyjMcf.js → OperatorDashboard-DSloftQ5.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-CayyjMcf.js.map → OperatorDashboard-DSloftQ5.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-DBcxfdbN.js → PersonaDetailPage-jDVRCLbU.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-DBcxfdbN.js.map → PersonaDetailPage-jDVRCLbU.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-DPq0HQAB.js → PersonasPage-DnDDwXoy.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-DPq0HQAB.js.map → PersonasPage-DnDDwXoy.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-QQZNNNMw.js → ProcessDetailPage-CfAUU6q2.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-QQZNNNMw.js.map → ProcessDetailPage-CfAUU6q2.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-UKQMJ4Te.js → ProcessesListPage-CnAXzaVv.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-UKQMJ4Te.js.map → ProcessesListPage-CnAXzaVv.js.map} +1 -1
- package/dashboard/dist/assets/{RoleDetailPage-DT-3sSRD.js → RoleDetailPage-Dg1p6Qz_.js} +2 -2
- package/dashboard/dist/assets/{RoleDetailPage-DT-3sSRD.js.map → RoleDetailPage-Dg1p6Qz_.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-DZg4niqL.js → RolesPage-DeRVQux8.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-DZg4niqL.js.map → RolesPage-DeRVQux8.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-DkcNR7L6.js → RunAsSelector-BFNqQGuG.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-DkcNR7L6.js.map → RunAsSelector-BFNqQGuG.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-U-alpwWF.js → ScanCodesPage-D0GOdk5m.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-U-alpwWF.js.map → ScanCodesPage-D0GOdk5m.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-lXwlcraS.js → ScanSchemeDetailPage-vFqoe_P4.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-lXwlcraS.js.map → ScanSchemeDetailPage-vFqoe_P4.js.map} +1 -1
- package/dashboard/dist/assets/{ScanStationPage-DYMiTp-v.js → ScanStationPage-DH1ynTX9.js} +2 -2
- package/dashboard/dist/assets/{ScanStationPage-DYMiTp-v.js.map → ScanStationPage-DH1ynTX9.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-D896Wquq.js → StickyPagination-B99hVu95.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-D896Wquq.js.map → StickyPagination-B99hVu95.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-DIh5qEGJ.js → StreamMessageDetail-DcDGISrv.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-DIh5qEGJ.js.map → StreamMessageDetail-DcDGISrv.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-B8SucVj5.js → SwimlaneTimeline-BP3mSQAg.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-B8SucVj5.js.map → SwimlaneTimeline-BP3mSQAg.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-Di-z_ZE2.js → TaskDetailPage-_XWLJzt-.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-Di-z_ZE2.js.map → TaskDetailPage-_XWLJzt-.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-ClHGEdin.js → TasksListPage-iGriKiO2.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-ClHGEdin.js.map → TasksListPage-iGriKiO2.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-BSDHd9Xo.js → TimeAgo-BO33VeFl.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-BSDHd9Xo.js.map → TimeAgo-BO33VeFl.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-WQL3FxWl.js → TimestampCell-KAjX7w35.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-WQL3FxWl.js.map → TimestampCell-KAjX7w35.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-IVIkqZTi.js → ToolTestPanel-BchG2yC6.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-IVIkqZTi.js.map → ToolTestPanel-BchG2yC6.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-BOasQo68.js → TopicDetailPage-BaK8H0o1.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-BOasQo68.js.map → TopicDetailPage-BaK8H0o1.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-DV_orf_V.js → TopicsPage-DEyvm669.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-DV_orf_V.js.map → TopicsPage-DEyvm669.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-rshjKBtm.js → UserName-BV6SKI9P.js} +2 -2
- package/dashboard/dist/assets/{UserName-rshjKBtm.js.map → UserName-BV6SKI9P.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-BpNGLwbK.js → WorkflowExecutionPage-1sKoEFNC.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-BpNGLwbK.js.map → WorkflowExecutionPage-1sKoEFNC.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-BAXt8gv_.js → WorkflowsDashboard-YTHDZZOD.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-BAXt8gv_.js.map → WorkflowsDashboard-YTHDZZOD.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-DvOyzL6y.js → WorkflowsOverview-ucXPLTtm.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-DvOyzL6y.js.map → WorkflowsOverview-ucXPLTtm.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CraijGy6.js → YamlWorkflowDetailPage-C_RTZKqZ.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CraijGy6.js.map → YamlWorkflowDetailPage-C_RTZKqZ.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-CNz3ptmj.js → YamlWorkflowsPage-Usid3w2W.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-CNz3ptmj.js.map → YamlWorkflowsPage-Usid3w2W.js.map} +1 -1
- package/dashboard/dist/assets/{agents-BswSJR-t.js → agents-BTDsRK8e.js} +2 -2
- package/dashboard/dist/assets/{agents-BswSJR-t.js.map → agents-BTDsRK8e.js.map} +1 -1
- package/dashboard/dist/assets/{bots-VzlLx_GQ.js → bots-DxLrfdfr.js} +2 -2
- package/dashboard/dist/assets/{bots-VzlLx_GQ.js.map → bots-DxLrfdfr.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-B0bNlTTA.js → capabilities-DbTmeW-S.js} +2 -2
- package/dashboard/dist/assets/{capabilities-B0bNlTTA.js.map → capabilities-DbTmeW-S.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DBESTVZS.js → controlplane-CEBntAL4.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DBESTVZS.js.map → controlplane-CEBntAL4.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-CoqsCdbP.js → escalation-columns-Carqdwoh.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-CoqsCdbP.js.map → escalation-columns-Carqdwoh.js.map} +1 -1
- package/dashboard/dist/assets/{index-DUfdCp8e.js → index-B2hz0pUh.js} +2 -2
- package/dashboard/dist/assets/{index-DUfdCp8e.js.map → index-B2hz0pUh.js.map} +1 -1
- package/dashboard/dist/assets/{index-DJS-hvDt.js → index-B9m7fA3M.js} +2 -2
- package/dashboard/dist/assets/{index-DJS-hvDt.js.map → index-B9m7fA3M.js.map} +1 -1
- package/dashboard/dist/assets/{index-C_lA7ghl.js → index-BhapT-Vl.js} +2 -2
- package/dashboard/dist/assets/{index-C_lA7ghl.js.map → index-BhapT-Vl.js.map} +1 -1
- package/dashboard/dist/assets/{index-DsDFZzqr.js → index-Bqm4zu46.js} +2 -2
- package/dashboard/dist/assets/{index-DsDFZzqr.js.map → index-Bqm4zu46.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cd7jZylO.js → index-C0hSttF5.js} +2 -2
- package/dashboard/dist/assets/{index-Cd7jZylO.js.map → index-C0hSttF5.js.map} +1 -1
- package/dashboard/dist/assets/{index-ByUjwu37.js → index-CDkg6iOE.js} +2 -2
- package/dashboard/dist/assets/{index-ByUjwu37.js.map → index-CDkg6iOE.js.map} +1 -1
- package/dashboard/dist/assets/{index-Ci4lxPwS.js → index-CVBBkW8V.js} +2 -2
- package/dashboard/dist/assets/{index-Ci4lxPwS.js.map → index-CVBBkW8V.js.map} +1 -1
- package/dashboard/dist/assets/{index-DYDcjn-b.js → index-CgIBjZta.js} +2 -2
- package/dashboard/dist/assets/{index-DYDcjn-b.js.map → index-CgIBjZta.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cqrp5B5S.js → index-DBXm49S6.js} +25 -25
- package/dashboard/dist/assets/index-DBXm49S6.js.map +1 -0
- package/dashboard/dist/assets/{index-BBXmIWKx.js → index-De8iV1y2.js} +2 -2
- package/dashboard/dist/assets/{index-BBXmIWKx.js.map → index-De8iV1y2.js.map} +1 -1
- package/dashboard/dist/assets/{index-D8ljRGIb.js → index-DsgjFRvA.js} +2 -2
- package/dashboard/dist/assets/{index-D8ljRGIb.js.map → index-DsgjFRvA.js.map} +1 -1
- package/dashboard/dist/assets/{index-BLzwfbZV.js → index-kes8V4Xw.js} +2 -2
- package/dashboard/dist/assets/{index-BLzwfbZV.js.map → index-kes8V4Xw.js.map} +1 -1
- package/dashboard/dist/assets/{index-CALocCAr.js → index-nwLh3CK2.js} +2 -2
- package/dashboard/dist/assets/{index-CALocCAr.js.map → index-nwLh3CK2.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-DB2DgDa_.js → knowledge-oFYAanUp.js} +2 -2
- package/dashboard/dist/assets/{knowledge-DB2DgDa_.js.map → knowledge-oFYAanUp.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-D72yCeuf.js → mcp-C9Kw4Ow8.js} +2 -2
- package/dashboard/dist/assets/{mcp-D72yCeuf.js.map → mcp-C9Kw4Ow8.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-Cyyc_0E8.js → mcp-query-BwzpZ91Z.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-Cyyc_0E8.js.map → mcp-query-BwzpZ91Z.js.map} +1 -1
- package/dashboard/dist/assets/{personas-xMDV7yXb.js → personas-D5ehmtRb.js} +2 -2
- package/dashboard/dist/assets/{personas-xMDV7yXb.js.map → personas-D5ehmtRb.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-mlxfmi6m.js → pipelines-xgPKGEdD.js} +2 -2
- package/dashboard/dist/assets/{pipelines-mlxfmi6m.js.map → pipelines-xgPKGEdD.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-CxgOp_9H.js → tasks-CLyrl-MU.js} +2 -2
- package/dashboard/dist/assets/{tasks-CxgOp_9H.js.map → tasks-CLyrl-MU.js.map} +1 -1
- package/dashboard/dist/assets/{topics-CFb_L0Vs.js → topics-B_gO7CQ0.js} +2 -2
- package/dashboard/dist/assets/{topics-CFb_L0Vs.js.map → topics-B_gO7CQ0.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-nC5kH-QW.js → useEventHooks-BdWYm63U.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-nC5kH-QW.js.map → useEventHooks-BdWYm63U.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-DQeDgRFR.js → useNamespace-C238M4Qn.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-DQeDgRFR.js.map → useNamespace-C238M4Qn.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-BuGC3oBE.js → useYamlActivityEvents-B2ryEK4S.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-BuGC3oBE.js.map → useYamlActivityEvents-B2ryEK4S.js.map} +1 -1
- package/dashboard/dist/assets/{users-BZUTtM_6.js → users-BFaTe6Mt.js} +2 -2
- package/dashboard/dist/assets/{users-BZUTtM_6.js.map → users-BFaTe6Mt.js.map} +1 -1
- package/dashboard/dist/assets/{workflows-DWhaZWVK.js → workflows-DXz7tZxp.js} +2 -2
- package/dashboard/dist/assets/{workflows-DWhaZWVK.js.map → workflows-DXz7tZxp.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-C1TeDIIk.js → yaml-workflows-u3xuRAnS.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-C1TeDIIk.js.map → yaml-workflows-u3xuRAnS.js.map} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/docs/auth.md +26 -1
- package/docs/code-owned-configuration.md +158 -0
- package/docs/scan-codes.md +24 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/index-Cqrp5B5S.js.map +0 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isValidRoleType = isValidRoleType;
|
|
4
4
|
exports.addUserRole = addUserRole;
|
|
5
|
+
exports.grantRoleIfAbsent = grantRoleIfAbsent;
|
|
5
6
|
exports.removeUserRole = removeUserRole;
|
|
6
7
|
exports.getUserRoles = getUserRoles;
|
|
7
8
|
exports.hasRole = hasRole;
|
|
@@ -36,6 +37,34 @@ async function addUserRole(userId, role, type, scope) {
|
|
|
36
37
|
client.release();
|
|
37
38
|
}
|
|
38
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Grant a role ONLY when the user does not already hold it — the scope-safe
|
|
42
|
+
* add for sync paths (SSO provisioning, claim-time provisioning). An existing
|
|
43
|
+
* grant is never touched: identity sync adds missing memberships, it never
|
|
44
|
+
* mutates the type/scope/provenance an admin set. Returns the inserted row, or
|
|
45
|
+
* null when the membership already existed.
|
|
46
|
+
*/
|
|
47
|
+
async function grantRoleIfAbsent(userId, role, type, scope) {
|
|
48
|
+
const eff = (0, scope_1.effectiveScope)(type, scope?.read_scope ?? scope_1.DEFAULT_READ_SCOPE, scope?.write_scope ?? scope_1.DEFAULT_WRITE_SCOPE);
|
|
49
|
+
const pool = (0, db_1.getPool)();
|
|
50
|
+
// Same ensure-role + insert transaction as addUserRole: the FK target and the
|
|
51
|
+
// assignment commit together.
|
|
52
|
+
const client = await pool.connect();
|
|
53
|
+
try {
|
|
54
|
+
await client.query('BEGIN');
|
|
55
|
+
await client.query(sql_1.ENSURE_ROLE_EXISTS, [role]);
|
|
56
|
+
const { rows } = await client.query(sql_1.INSERT_USER_ROLE_IF_ABSENT, [userId, role, type, eff.read, eff.write]);
|
|
57
|
+
await client.query('COMMIT');
|
|
58
|
+
return rows[0] ?? null;
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
await client.query('ROLLBACK');
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
client.release();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
39
68
|
async function removeUserRole(userId, role) {
|
|
40
69
|
const pool = (0, db_1.getPool)();
|
|
41
70
|
const { rowCount } = await pool.query(sql_1.DELETE_USER_ROLE, [userId, role]);
|
|
@@ -37,6 +37,12 @@ export declare const GET_ROLES_BY_USER_IDS = "SELECT r.user_id, r.role, r.type,
|
|
|
37
37
|
* A direct grant takes the row over: granted_by_persona resets to NULL, so a
|
|
38
38
|
* later persona unassign can never remove a membership an admin set by hand. */
|
|
39
39
|
export declare const UPSERT_USER_ROLE = "INSERT INTO lt_user_roles (user_id, role, type, read_scope, write_scope) VALUES ($1, $2, $3, $4, $5)\n ON CONFLICT (user_id, role) DO UPDATE SET\n type = EXCLUDED.type,\n read_scope = EXCLUDED.read_scope,\n write_scope = EXCLUDED.write_scope,\n granted_by_persona = NULL\n RETURNING role, type, read_scope, write_scope, created_at";
|
|
40
|
+
/** Insert a user–role assignment ONLY when absent. The scope-safe grant for
|
|
41
|
+
* sync paths (SSO, claim-time provisioning): an existing row — whatever its
|
|
42
|
+
* type/scope/provenance — is left untouched; zero rows return on conflict.
|
|
43
|
+
* Identity sync may add a missing membership but never mutates authorization
|
|
44
|
+
* an admin already set. */
|
|
45
|
+
export declare const INSERT_USER_ROLE_IF_ABSENT = "INSERT INTO lt_user_roles (user_id, role, type, read_scope, write_scope) VALUES ($1, $2, $3, $4, $5)\n ON CONFLICT (user_id, role) DO NOTHING\n RETURNING role, type, read_scope, write_scope, created_at";
|
|
40
46
|
export declare const DELETE_USER_ROLE = "DELETE FROM lt_user_roles WHERE user_id = $1 AND role = $2";
|
|
41
47
|
export declare const HAS_ROLE = "SELECT 1 FROM lt_user_roles WHERE user_id = $1 AND role = $2 LIMIT 1";
|
|
42
48
|
export declare const HAS_ROLE_TYPE = "SELECT 1 FROM lt_user_roles WHERE user_id = $1 AND type = $2 LIMIT 1";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// ─── Shared queries (used by multiple modules) ──────────────────────────────
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.IS_GROUP_ADMIN = exports.GET_ROLE_SCOPE = exports.HAS_ROLE_TYPE = exports.HAS_ROLE = exports.DELETE_USER_ROLE = exports.UPSERT_USER_ROLE = exports.GET_ROLES_BY_USER_IDS = exports.DELETE_USER_BY_ID = exports.GET_USER_WITH_ROLES = exports.VERIFY_USER_BY_ID = exports.GET_USERS_BY_METADATA_VALUE = exports.GET_USER_BY_ID = exports.GET_USER_BY_EMAIL = exports.CREATE_USER_WITH_ROLES = exports.GET_USER_BY_EXTERNAL_ID = exports.GET_ROLES_BY_USER_ID = exports.ENSURE_ROLE_EXISTS = void 0;
|
|
4
|
+
exports.IS_GROUP_ADMIN = exports.GET_ROLE_SCOPE = exports.HAS_ROLE_TYPE = exports.HAS_ROLE = exports.DELETE_USER_ROLE = exports.INSERT_USER_ROLE_IF_ABSENT = exports.UPSERT_USER_ROLE = exports.GET_ROLES_BY_USER_IDS = exports.DELETE_USER_BY_ID = exports.GET_USER_WITH_ROLES = exports.VERIFY_USER_BY_ID = exports.GET_USERS_BY_METADATA_VALUE = exports.GET_USER_BY_ID = exports.GET_USER_BY_EMAIL = exports.CREATE_USER_WITH_ROLES = exports.GET_USER_BY_EXTERNAL_ID = exports.GET_ROLES_BY_USER_ID = exports.ENSURE_ROLE_EXISTS = void 0;
|
|
5
5
|
/** Ensure a role name exists in the lt_roles lookup table (FK target). */
|
|
6
6
|
exports.ENSURE_ROLE_EXISTS = 'INSERT INTO lt_roles (role) VALUES ($1) ON CONFLICT DO NOTHING';
|
|
7
7
|
/** Fetch roles for a single user, ordered by creation time. granted_by_persona
|
|
@@ -74,6 +74,14 @@ exports.UPSERT_USER_ROLE = `INSERT INTO lt_user_roles (user_id, role, type, read
|
|
|
74
74
|
write_scope = EXCLUDED.write_scope,
|
|
75
75
|
granted_by_persona = NULL
|
|
76
76
|
RETURNING role, type, read_scope, write_scope, created_at`;
|
|
77
|
+
/** Insert a user–role assignment ONLY when absent. The scope-safe grant for
|
|
78
|
+
* sync paths (SSO, claim-time provisioning): an existing row — whatever its
|
|
79
|
+
* type/scope/provenance — is left untouched; zero rows return on conflict.
|
|
80
|
+
* Identity sync may add a missing membership but never mutates authorization
|
|
81
|
+
* an admin already set. */
|
|
82
|
+
exports.INSERT_USER_ROLE_IF_ABSENT = `INSERT INTO lt_user_roles (user_id, role, type, read_scope, write_scope) VALUES ($1, $2, $3, $4, $5)
|
|
83
|
+
ON CONFLICT (user_id, role) DO NOTHING
|
|
84
|
+
RETURNING role, type, read_scope, write_scope, created_at`;
|
|
77
85
|
exports.DELETE_USER_ROLE = 'DELETE FROM lt_user_roles WHERE user_id = $1 AND role = $2';
|
|
78
86
|
exports.HAS_ROLE = 'SELECT 1 FROM lt_user_roles WHERE user_id = $1 AND role = $2 LIMIT 1';
|
|
79
87
|
exports.HAS_ROLE_TYPE = 'SELECT 1 FROM lt_user_roles WHERE user_id = $1 AND type = $2 LIMIT 1';
|
|
@@ -49,13 +49,21 @@ async function ssoProvision(identity, ssoConfig) {
|
|
|
49
49
|
throw err;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Ensure all resolved roles exist on an already-provisioned user.
|
|
54
|
+
*
|
|
55
|
+
* SSO synchronizes IDENTITY, never authorization scope: a missing membership
|
|
56
|
+
* is added, an existing one is left exactly as the admin set it (type, scope,
|
|
57
|
+
* persona provenance). The has-check keeps the steady-state login read-only;
|
|
58
|
+
* `grantRoleIfAbsent` (INSERT … DO NOTHING) is the database-level guarantee
|
|
59
|
+
* for anything that races past it.
|
|
60
|
+
*/
|
|
53
61
|
async function syncExistingUser(userId, ltRoles) {
|
|
54
62
|
const currentRoles = await (0, roles_1.getUserRoles)(userId);
|
|
55
63
|
for (const lr of ltRoles) {
|
|
56
64
|
const has = currentRoles.some((r) => r.role === lr.role);
|
|
57
65
|
if (!has) {
|
|
58
|
-
await (0, roles_1.
|
|
66
|
+
await (0, roles_1.grantRoleIfAbsent)(userId, lr.role, lr.type);
|
|
59
67
|
}
|
|
60
68
|
}
|
|
61
69
|
const updatedRoles = await (0, roles_1.getUserRoles)(userId);
|
|
@@ -69,8 +77,11 @@ function resolveRoles(hostRoles, defaultRoleType, roleMap) {
|
|
|
69
77
|
const mapped = roleMap
|
|
70
78
|
? hostRoles.filter((r) => roleMap[r]).map((r) => roleMap[r])
|
|
71
79
|
: hostRoles;
|
|
80
|
+
// A configured roleMap is the complete contract: an unmapped host role means
|
|
81
|
+
// "no LT role" — never an injected default. The default membership applies
|
|
82
|
+
// only when no roleMap exists (raw host roles pass through, empty = default).
|
|
72
83
|
if (mapped.length === 0) {
|
|
73
|
-
return [{ role: defaultRoleType, type: defaultRoleType }];
|
|
84
|
+
return roleMap ? [] : [{ role: defaultRoleType, type: defaultRoleType }];
|
|
74
85
|
}
|
|
75
86
|
return mapped.map((role) => ({
|
|
76
87
|
role,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Who owns declared configuration after first boot. */
|
|
2
|
+
export type ConfigSource = 'code' | 'db';
|
|
3
|
+
/**
|
|
4
|
+
* Effective ownership for one declared entry: the per-entry `reset` flag wins
|
|
5
|
+
* in either direction; otherwise the global `configSource` decides.
|
|
6
|
+
*/
|
|
7
|
+
export declare function ownedByCode(reset: boolean | undefined, source: ConfigSource): boolean;
|
|
8
|
+
/** Outcome of one entry's startup pass. */
|
|
9
|
+
export type ApplyOutcome = 'applied' | 'unchanged' | 'db-owned';
|
|
10
|
+
/** Per-surface tally of a boot's config pass. */
|
|
11
|
+
export interface SurfaceReport {
|
|
12
|
+
applied: string[];
|
|
13
|
+
unchanged: string[];
|
|
14
|
+
dbOwned: string[];
|
|
15
|
+
/** DB rows of this surface not declared in code (reported, never deleted). */
|
|
16
|
+
orphans: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare function newSurfaceReport(): SurfaceReport;
|
|
19
|
+
/** Record one entry's outcome on the surface report. */
|
|
20
|
+
export declare function recordOutcome(report: SurfaceReport, name: string, outcome: ApplyOutcome): void;
|
|
21
|
+
export declare function withConfigLock<T>(fn: () => Promise<T>): Promise<T>;
|
|
22
|
+
/**
|
|
23
|
+
* One boot line per surface. Warn level when orphans exist so operators see
|
|
24
|
+
* "declared set no longer matches the DB" without grepping.
|
|
25
|
+
*/
|
|
26
|
+
export declare function logSurfaceReport(surface: string, report: SurfaceReport): void;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ownedByCode = ownedByCode;
|
|
4
|
+
exports.newSurfaceReport = newSurfaceReport;
|
|
5
|
+
exports.recordOutcome = recordOutcome;
|
|
6
|
+
exports.withConfigLock = withConfigLock;
|
|
7
|
+
exports.logSurfaceReport = logSurfaceReport;
|
|
8
|
+
const db_1 = require("../lib/db");
|
|
9
|
+
const logger_1 = require("../lib/logger");
|
|
10
|
+
/**
|
|
11
|
+
* Effective ownership for one declared entry: the per-entry `reset` flag wins
|
|
12
|
+
* in either direction; otherwise the global `configSource` decides.
|
|
13
|
+
*/
|
|
14
|
+
function ownedByCode(reset, source) {
|
|
15
|
+
return reset ?? source === 'code';
|
|
16
|
+
}
|
|
17
|
+
function newSurfaceReport() {
|
|
18
|
+
return { applied: [], unchanged: [], dbOwned: [], orphans: [] };
|
|
19
|
+
}
|
|
20
|
+
/** Record one entry's outcome on the surface report. */
|
|
21
|
+
function recordOutcome(report, name, outcome) {
|
|
22
|
+
if (outcome === 'applied')
|
|
23
|
+
report.applied.push(name);
|
|
24
|
+
else if (outcome === 'unchanged')
|
|
25
|
+
report.unchanged.push(name);
|
|
26
|
+
else
|
|
27
|
+
report.dbOwned.push(name);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Serializes multi-statement config writes (role-list replaces, escalation
|
|
31
|
+
* target replaces) across concurrently booting containers. Single-statement
|
|
32
|
+
* upserts are individually race-safe; the lock exists for the replace
|
|
33
|
+
* transactions and keeps boot reports coherent. Distinct from the migration
|
|
34
|
+
* lock so a slow migration on one container never blocks another's config
|
|
35
|
+
* pass behind two locks at once.
|
|
36
|
+
*/
|
|
37
|
+
const CONFIG_APPLY_LOCK_ID = 8675310;
|
|
38
|
+
async function withConfigLock(fn) {
|
|
39
|
+
const pool = (0, db_1.getPool)();
|
|
40
|
+
const client = await pool.connect();
|
|
41
|
+
try {
|
|
42
|
+
await client.query(`SELECT pg_advisory_lock(${CONFIG_APPLY_LOCK_ID})`);
|
|
43
|
+
return await fn();
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
await client
|
|
47
|
+
.query(`SELECT pg_advisory_unlock(${CONFIG_APPLY_LOCK_ID})`)
|
|
48
|
+
.catch(() => { });
|
|
49
|
+
client.release();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* One boot line per surface. Warn level when orphans exist so operators see
|
|
54
|
+
* "declared set no longer matches the DB" without grepping.
|
|
55
|
+
*/
|
|
56
|
+
function logSurfaceReport(surface, report) {
|
|
57
|
+
const counts = `applied ${report.applied.length}, unchanged ${report.unchanged.length}, ` +
|
|
58
|
+
`db-owned ${report.dbOwned.length}`;
|
|
59
|
+
if (report.orphans.length > 0) {
|
|
60
|
+
logger_1.loggerRegistry.warn(`[long-tail] config apply (${surface}): ${counts}, orphans: [${report.orphans.join(', ')}]`);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
logger_1.loggerRegistry.info(`[long-tail] config apply (${surface}): ${counts}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
package/build/start/config.js
CHANGED
|
@@ -103,7 +103,14 @@ async function applyServerAuthConfig(startConfig) {
|
|
|
103
103
|
// SSO — store config for requireAuth fallback and /api/auth/sso exchange
|
|
104
104
|
if (startConfig.auth?.sso) {
|
|
105
105
|
const { setSSOConfig } = await Promise.resolve().then(() => __importStar(require('../modules/sso')));
|
|
106
|
-
|
|
106
|
+
const sso = { ...startConfig.auth.sso };
|
|
107
|
+
// A keepalive beat re-runs resolve + provisioning per tab; clamp runaway
|
|
108
|
+
// intervals (a 1s misconfiguration = one exchange per second per tab).
|
|
109
|
+
if (sso.keepaliveSeconds != null && sso.keepaliveSeconds > 0 && sso.keepaliveSeconds < 15) {
|
|
110
|
+
logger_1.loggerRegistry.warn(`[long-tail] sso.keepaliveSeconds ${sso.keepaliveSeconds}s clamped to 15s`);
|
|
111
|
+
sso.keepaliveSeconds = 15;
|
|
112
|
+
}
|
|
113
|
+
setSSOConfig(sso);
|
|
107
114
|
logger_1.loggerRegistry.info('[long-tail] SSO enabled — host auth will be trusted');
|
|
108
115
|
}
|
|
109
116
|
}
|
package/build/start/workers.js
CHANGED
|
@@ -50,6 +50,7 @@ const cron_1 = require("../services/cron");
|
|
|
50
50
|
const mcp_1 = require("../services/mcp");
|
|
51
51
|
const yamlWorkflowWorkers = __importStar(require("../services/yaml-workflow/workers"));
|
|
52
52
|
const migrate_1 = require("../lib/db/migrate");
|
|
53
|
+
const apply_report_1 = require("./apply-report");
|
|
53
54
|
/**
|
|
54
55
|
* Create a named no-op workflow function for readonly/observer workers.
|
|
55
56
|
* The function name is used by `registerWorker` for discovery.
|
|
@@ -116,6 +117,54 @@ async function startWorkers(startConfig, workers, builtinMcpServerFactories) {
|
|
|
116
117
|
// Seed MCP service account (idempotent)
|
|
117
118
|
const { seedMcpServiceAccount } = await Promise.resolve().then(() => __importStar(require('../services/mcp/seed-service-account')));
|
|
118
119
|
await seedMcpServiceAccount();
|
|
120
|
+
// Who owns declared configuration after first boot ('db' = insert-if-absent).
|
|
121
|
+
const configSource = startConfig.configSource ?? 'db';
|
|
122
|
+
const codeOwnedBoot = configSource === 'code';
|
|
123
|
+
// Register declared roles (every container — roles are independent of workers).
|
|
124
|
+
if (startConfig.roles?.length) {
|
|
125
|
+
const { applyRoleConfig, listConfiguredRoles } = await Promise.resolve().then(() => __importStar(require('../services/role/seed')));
|
|
126
|
+
const roleReport = (0, apply_report_1.newSurfaceReport)();
|
|
127
|
+
await (0, apply_report_1.withConfigLock)(async () => {
|
|
128
|
+
for (const roleCfg of startConfig.roles) {
|
|
129
|
+
try {
|
|
130
|
+
const outcome = await applyRoleConfig(roleCfg, (0, apply_report_1.ownedByCode)(roleCfg.reset, configSource));
|
|
131
|
+
(0, apply_report_1.recordOutcome)(roleReport, roleCfg.role, outcome);
|
|
132
|
+
if (outcome === 'applied')
|
|
133
|
+
logger_1.loggerRegistry.info(`[long-tail] role applied: ${roleCfg.role}`);
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
logger_1.loggerRegistry.warn(`[long-tail] role apply failed for ${roleCfg.role}: ${err.message}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
if (codeOwnedBoot && !startConfig.examples) {
|
|
141
|
+
// Orphans = configured roles (title or form schema set) neither declared
|
|
142
|
+
// here nor referenced by a declared workflow profile. Bare FK rows and
|
|
143
|
+
// membership-only roles never count. Skipped under examples — the demo
|
|
144
|
+
// seeders own their roles.
|
|
145
|
+
const declared = new Set(['reviewer', 'superadmin', 'system']);
|
|
146
|
+
for (const r of startConfig.roles) {
|
|
147
|
+
declared.add(r.role);
|
|
148
|
+
if (r.parent_role)
|
|
149
|
+
declared.add(r.parent_role);
|
|
150
|
+
for (const t of r.escalation_targets ?? [])
|
|
151
|
+
declared.add(t);
|
|
152
|
+
for (const u of r.upstream_roles ?? [])
|
|
153
|
+
declared.add(u);
|
|
154
|
+
}
|
|
155
|
+
for (const w of workers) {
|
|
156
|
+
if (!w.config)
|
|
157
|
+
continue;
|
|
158
|
+
declared.add(w.config.defaultRole ?? 'reviewer');
|
|
159
|
+
for (const role of [...(w.config.roles ?? []), ...(w.config.invocationRoles ?? [])]) {
|
|
160
|
+
declared.add(role);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
roleReport.orphans = (await listConfiguredRoles()).filter((r) => !declared.has(r));
|
|
164
|
+
}
|
|
165
|
+
if (codeOwnedBoot)
|
|
166
|
+
(0, apply_report_1.logSurfaceReport)('roles', roleReport);
|
|
167
|
+
}
|
|
119
168
|
const connection = buildConnection();
|
|
120
169
|
// Readonly mode: all user-provided workers are observers — skip crons, triggers, and agent seeding.
|
|
121
170
|
// System workers (mcpQuery, etc.) are always added by collectWorkers, so check the original config.
|
|
@@ -160,16 +209,19 @@ async function startWorkers(startConfig, workers, builtinMcpServerFactories) {
|
|
|
160
209
|
(0, registry_1.registerWorker)(w.workflow.name, w.taskQueue);
|
|
161
210
|
}
|
|
162
211
|
logger_1.loggerRegistry.info(`[long-tail] workers started on queues: ${workers.map((w) => w.taskQueue).join(', ')}`);
|
|
163
|
-
//
|
|
212
|
+
// Register workflow configs — ownership per configSource / per-entry reset.
|
|
213
|
+
// Code-owned profiles are diffed and applied; db-owned profiles keep the
|
|
214
|
+
// insert-if-absent contract (DB is source of truth after first boot).
|
|
164
215
|
const workersWithConfig = workers.filter((w) => w.config);
|
|
165
216
|
if (workersWithConfig.length) {
|
|
166
|
-
const { seedWorkflowConfig } = await Promise.resolve().then(() => __importStar(require('../services/config/write')));
|
|
217
|
+
const { seedWorkflowConfig, applyWorkflowConfig } = await Promise.resolve().then(() => __importStar(require('../services/config/write')));
|
|
167
218
|
const { ltConfig } = await Promise.resolve().then(() => __importStar(require('../modules/ltconfig')));
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
const
|
|
219
|
+
const wfReport = (0, apply_report_1.newSurfaceReport)();
|
|
220
|
+
await (0, apply_report_1.withConfigLock)(async () => {
|
|
221
|
+
for (const w of workersWithConfig) {
|
|
222
|
+
const workflowType = w.workflow.name;
|
|
223
|
+
const c = w.config;
|
|
224
|
+
const declaration = {
|
|
173
225
|
workflow_type: workflowType,
|
|
174
226
|
task_queue: w.taskQueue,
|
|
175
227
|
invocable: c.invocable ?? false,
|
|
@@ -184,13 +236,33 @@ async function startWorkers(startConfig, workers, builtinMcpServerFactories) {
|
|
|
184
236
|
resolver_schema: c.resolverSchema ?? null,
|
|
185
237
|
cron_schedule: c.cronSchedule ?? null,
|
|
186
238
|
execute_as: c.executeAs ?? null,
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
239
|
+
};
|
|
240
|
+
try {
|
|
241
|
+
if ((0, apply_report_1.ownedByCode)(c.reset, configSource)) {
|
|
242
|
+
const outcome = await applyWorkflowConfig(declaration);
|
|
243
|
+
(0, apply_report_1.recordOutcome)(wfReport, workflowType, outcome);
|
|
244
|
+
if (outcome === 'applied')
|
|
245
|
+
logger_1.loggerRegistry.info(`[long-tail] config applied: ${workflowType}`);
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
const inserted = await seedWorkflowConfig(declaration);
|
|
249
|
+
(0, apply_report_1.recordOutcome)(wfReport, workflowType, 'db-owned');
|
|
250
|
+
if (inserted)
|
|
251
|
+
logger_1.loggerRegistry.info(`[long-tail] config seeded: ${workflowType}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
logger_1.loggerRegistry.warn(`[long-tail] config seed failed for ${workflowType}: ${err.message}`);
|
|
256
|
+
}
|
|
193
257
|
}
|
|
258
|
+
});
|
|
259
|
+
if (codeOwnedBoot) {
|
|
260
|
+
const { listWorkflowConfigs } = await Promise.resolve().then(() => __importStar(require('../services/config/read')));
|
|
261
|
+
const registered = new Set(workers.map((w) => w.workflow.name));
|
|
262
|
+
wfReport.orphans = (await listWorkflowConfigs())
|
|
263
|
+
.map((cfg) => cfg.workflow_type)
|
|
264
|
+
.filter((t) => !registered.has(t));
|
|
265
|
+
(0, apply_report_1.logSurfaceReport)('workflows', wfReport);
|
|
194
266
|
}
|
|
195
267
|
ltConfig.invalidate();
|
|
196
268
|
}
|
|
@@ -211,7 +283,7 @@ async function startWorkers(startConfig, workers, builtinMcpServerFactories) {
|
|
|
211
283
|
// Register MCP server factories: built-in (from system/) + user-provided
|
|
212
284
|
// Both system and user factories can carry inline config for DB seeding.
|
|
213
285
|
const { registerBuiltinServer } = await Promise.resolve().then(() => __importStar(require('../services/mcp/client')));
|
|
214
|
-
const { seedMcpServer, cleanStaleBuiltinServers } = await Promise.resolve().then(() => __importStar(require('../services/mcp/db')));
|
|
286
|
+
const { seedMcpServer, applyMcpServer, cleanStaleBuiltinServers } = await Promise.resolve().then(() => __importStar(require('../services/mcp/db')));
|
|
215
287
|
const userFactories = startConfig.mcp?.serverFactories ?? {};
|
|
216
288
|
// Resolve user factories — plain function or { factory, config }
|
|
217
289
|
const resolvedUserFactories = {};
|
|
@@ -236,19 +308,33 @@ async function startWorkers(startConfig, workers, builtinMcpServerFactories) {
|
|
|
236
308
|
// Set exposure config for the /mcp endpoint
|
|
237
309
|
const { setExposureConfig } = await Promise.resolve().then(() => __importStar(require('../services/mcp/exposure')));
|
|
238
310
|
setExposureConfig(startConfig.mcp?.exposure);
|
|
239
|
-
// 2.
|
|
311
|
+
// 2. Register MCP server configs — ownership per configSource / per-entry
|
|
312
|
+
// reset. Code-owned entries apply the config fields (runtime state stays
|
|
313
|
+
// untouched); db-owned entries keep insert-if-absent + drift log.
|
|
314
|
+
const mcpReport = (0, apply_report_1.newSurfaceReport)();
|
|
240
315
|
for (const [name, entry] of Object.entries(allFactories)) {
|
|
241
316
|
if (entry.config) {
|
|
242
317
|
try {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
318
|
+
if ((0, apply_report_1.ownedByCode)(entry.config.reset, configSource)) {
|
|
319
|
+
const outcome = await applyMcpServer({ name, ...entry.config });
|
|
320
|
+
(0, apply_report_1.recordOutcome)(mcpReport, name, outcome);
|
|
321
|
+
if (outcome === 'applied')
|
|
322
|
+
logger_1.loggerRegistry.info(`[long-tail] MCP server applied: ${name}`);
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
const inserted = await seedMcpServer({ name, ...entry.config });
|
|
326
|
+
(0, apply_report_1.recordOutcome)(mcpReport, name, 'db-owned');
|
|
327
|
+
if (inserted)
|
|
328
|
+
logger_1.loggerRegistry.info(`[long-tail] MCP server seeded: ${name}`);
|
|
329
|
+
}
|
|
246
330
|
}
|
|
247
331
|
catch (err) {
|
|
248
332
|
logger_1.loggerRegistry.warn(`[long-tail] MCP server seed failed for ${name}: ${err.message}`);
|
|
249
333
|
}
|
|
250
334
|
}
|
|
251
335
|
}
|
|
336
|
+
if (codeOwnedBoot)
|
|
337
|
+
(0, apply_report_1.logSurfaceReport)('mcp-servers', mcpReport);
|
|
252
338
|
// 3. Clean stale builtin servers no longer in factory list
|
|
253
339
|
await cleanStaleBuiltinServers(Object.keys(allFactories));
|
|
254
340
|
// Seed static graph (YAML/DAG) workflows — the graph-form peer of `workers`.
|
|
@@ -268,16 +354,34 @@ async function startWorkers(startConfig, workers, builtinMcpServerFactories) {
|
|
|
268
354
|
// Register workers for active YAML (deterministic) workflows
|
|
269
355
|
await yamlWorkflowWorkers.registerAllActiveWorkers();
|
|
270
356
|
}
|
|
271
|
-
// Seed topic catalog (system topics + user-declared topics)
|
|
357
|
+
// Seed topic catalog (system topics + user-declared topics). Declared
|
|
358
|
+
// topics follow configSource; per-entry `reset` overrides in either direction.
|
|
272
359
|
const { seedSystemTopics, seedConfigTopics } = await Promise.resolve().then(() => __importStar(require('../services/topics/system-topics')));
|
|
273
360
|
await seedSystemTopics();
|
|
274
361
|
if (startConfig.topics?.length)
|
|
275
|
-
await seedConfigTopics(startConfig.topics);
|
|
276
|
-
|
|
277
|
-
|
|
362
|
+
await seedConfigTopics(startConfig.topics, codeOwnedBoot);
|
|
363
|
+
if (codeOwnedBoot) {
|
|
364
|
+
const { listConfigTopicNames } = await Promise.resolve().then(() => __importStar(require('../services/topics')));
|
|
365
|
+
const declaredTopics = new Set((startConfig.topics ?? []).map((t) => t.topic));
|
|
366
|
+
if (startConfig.examples) {
|
|
367
|
+
try {
|
|
368
|
+
const { EXAMPLE_TOPICS } = await Promise.resolve().then(() => __importStar(require('../examples')));
|
|
369
|
+
for (const t of EXAMPLE_TOPICS ?? [])
|
|
370
|
+
declaredTopics.add(t.topic);
|
|
371
|
+
}
|
|
372
|
+
catch { /* examples not available */ }
|
|
373
|
+
}
|
|
374
|
+
const orphanTopics = (await listConfigTopicNames()).filter((t) => !declaredTopics.has(t));
|
|
375
|
+
if (orphanTopics.length) {
|
|
376
|
+
logger_1.loggerRegistry.warn(`[long-tail] config apply (topics): orphans: [${orphanTopics.join(', ')}]`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// Seed the domain dictionary (every container, workers or not). Db-owned:
|
|
380
|
+
// insert-if-absent, the DB row is runtime truth. Code-owned: the file is
|
|
381
|
+
// compared and applied, bumping the version once per changed document.
|
|
278
382
|
if (startConfig.mcp?.domainDictionaryPath) {
|
|
279
383
|
const { seedDomainDictionary } = await Promise.resolve().then(() => __importStar(require('../services/domain')));
|
|
280
|
-
await seedDomainDictionary(startConfig.mcp.domainDictionaryPath);
|
|
384
|
+
await seedDomainDictionary(startConfig.mcp.domainDictionaryPath, startConfig.mcp.domainDictionaryReset ?? codeOwnedBoot);
|
|
281
385
|
}
|
|
282
386
|
// Seed example topics when examples are enabled
|
|
283
387
|
if (startConfig.examples) {
|
|
@@ -294,9 +398,11 @@ async function startWorkers(startConfig, workers, builtinMcpServerFactories) {
|
|
|
294
398
|
: [];
|
|
295
399
|
const allAgentConfigs = [...(startConfig.agents ?? []), ...systemAgents];
|
|
296
400
|
if (allAgentConfigs.length > 0) {
|
|
297
|
-
const { seedAgent } = await Promise.resolve().then(() => __importStar(require('../services/agent')));
|
|
298
|
-
const { seedSubscription } = await Promise.resolve().then(() => __importStar(require('../services/agent/subscriptions')));
|
|
401
|
+
const { seedAgent, applyAgent, listAgentIds } = await Promise.resolve().then(() => __importStar(require('../services/agent')));
|
|
402
|
+
const { seedSubscription, applySubscription, listSubscriptions } = await Promise.resolve().then(() => __importStar(require('../services/agent/subscriptions')));
|
|
403
|
+
const agentReport = (0, apply_report_1.newSurfaceReport)();
|
|
299
404
|
for (const agentConfig of allAgentConfigs) {
|
|
405
|
+
const codeOwned = (0, apply_report_1.ownedByCode)(agentConfig.reset, configSource);
|
|
300
406
|
try {
|
|
301
407
|
// Map flat schedules into behaviors.schedules for DB storage
|
|
302
408
|
const behaviors = {};
|
|
@@ -304,7 +410,7 @@ async function startWorkers(startConfig, workers, builtinMcpServerFactories) {
|
|
|
304
410
|
behaviors.schedules = agentConfig.schedules;
|
|
305
411
|
behaviors.cron = agentConfig.schedules[0].cron;
|
|
306
412
|
}
|
|
307
|
-
const
|
|
413
|
+
const declaration = {
|
|
308
414
|
id: agentConfig.name,
|
|
309
415
|
description: agentConfig.description,
|
|
310
416
|
goals: agentConfig.goals,
|
|
@@ -313,27 +419,110 @@ async function startWorkers(startConfig, workers, builtinMcpServerFactories) {
|
|
|
313
419
|
knowledge_domain: agentConfig.knowledge_domain,
|
|
314
420
|
behaviors,
|
|
315
421
|
workflow_type: agentConfig.schedules?.[0]?.workflow_type,
|
|
316
|
-
}
|
|
317
|
-
if (
|
|
318
|
-
|
|
319
|
-
|
|
422
|
+
};
|
|
423
|
+
if (codeOwned) {
|
|
424
|
+
const outcome = await applyAgent(declaration);
|
|
425
|
+
(0, apply_report_1.recordOutcome)(agentReport, agentConfig.name, outcome);
|
|
426
|
+
if (outcome === 'applied')
|
|
427
|
+
logger_1.loggerRegistry.info(`[long-tail] agent applied: ${agentConfig.name}`);
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
const inserted = await seedAgent(declaration);
|
|
431
|
+
(0, apply_report_1.recordOutcome)(agentReport, agentConfig.name, 'db-owned');
|
|
432
|
+
if (inserted)
|
|
433
|
+
logger_1.loggerRegistry.info(`[long-tail] agent seeded: ${agentConfig.name}`);
|
|
434
|
+
}
|
|
435
|
+
// Subscriptions for this agent — id IS the name
|
|
320
436
|
if (agentConfig.subscriptions?.length) {
|
|
321
437
|
for (const sub of agentConfig.subscriptions) {
|
|
322
438
|
try {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
439
|
+
if (codeOwned) {
|
|
440
|
+
const outcome = await applySubscription(agentConfig.name, sub);
|
|
441
|
+
if (outcome === 'applied')
|
|
442
|
+
logger_1.loggerRegistry.info(`[long-tail] subscription applied: ${agentConfig.name}/${sub.topic}`);
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
const subInserted = await seedSubscription(agentConfig.name, sub);
|
|
446
|
+
if (subInserted)
|
|
447
|
+
logger_1.loggerRegistry.info(`[long-tail] subscription seeded: ${agentConfig.name}/${sub.topic}`);
|
|
448
|
+
}
|
|
326
449
|
}
|
|
327
450
|
catch (subErr) {
|
|
328
451
|
logger_1.loggerRegistry.warn(`[long-tail] subscription seed failed: ${agentConfig.name}/${sub.topic}: ${subErr.message}`);
|
|
329
452
|
}
|
|
330
453
|
}
|
|
331
454
|
}
|
|
455
|
+
// Undeclared subscriptions on a code-owned agent are reported, never
|
|
456
|
+
// deleted — disabling or removing one stays a deliberate act.
|
|
457
|
+
if (codeOwned) {
|
|
458
|
+
const declaredSubs = new Set((agentConfig.subscriptions ?? []).map((s) => s.topic));
|
|
459
|
+
const existingSubs = await listSubscriptions(agentConfig.name);
|
|
460
|
+
agentReport.orphans.push(...existingSubs
|
|
461
|
+
.filter((s) => !declaredSubs.has(s.topic))
|
|
462
|
+
.map((s) => `${agentConfig.name}/${s.topic}`));
|
|
463
|
+
}
|
|
332
464
|
}
|
|
333
465
|
catch (err) {
|
|
334
466
|
logger_1.loggerRegistry.warn(`[long-tail] agent seed failed for ${agentConfig.name}: ${err.message}`);
|
|
335
467
|
}
|
|
336
468
|
}
|
|
469
|
+
if (codeOwnedBoot) {
|
|
470
|
+
const declaredAgents = new Set(allAgentConfigs.map((a) => a.name));
|
|
471
|
+
agentReport.orphans.push(...(await listAgentIds()).filter((id) => !declaredAgents.has(id)));
|
|
472
|
+
(0, apply_report_1.logSurfaceReport)('agents', agentReport);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
// Register declared scan schemes (with their rules) — ownership per
|
|
476
|
+
// configSource / per-entry reset. A scheme and its rules are one ownership
|
|
477
|
+
// unit; the scheme applies first so rule validation sees its kind.
|
|
478
|
+
if (startConfig.scanSchemes?.length) {
|
|
479
|
+
const { seedScanScheme, seedScanRule, applyScanScheme, applyScanRule, listScanSchemes, listScanRules, } = await Promise.resolve().then(() => __importStar(require('../services/scan-code')));
|
|
480
|
+
const scanReport = (0, apply_report_1.newSurfaceReport)();
|
|
481
|
+
for (const scheme of startConfig.scanSchemes) {
|
|
482
|
+
const codeOwned = (0, apply_report_1.ownedByCode)(scheme.reset, configSource);
|
|
483
|
+
const { rules, reset: _reset, ...schemeInput } = scheme;
|
|
484
|
+
try {
|
|
485
|
+
if (codeOwned) {
|
|
486
|
+
let outcome = await applyScanScheme(schemeInput);
|
|
487
|
+
for (const rule of rules ?? []) {
|
|
488
|
+
const ruleOutcome = await applyScanRule({ scheme_version: scheme.version, ...rule });
|
|
489
|
+
if (ruleOutcome === 'applied')
|
|
490
|
+
outcome = 'applied';
|
|
491
|
+
}
|
|
492
|
+
(0, apply_report_1.recordOutcome)(scanReport, `scheme ${scheme.version}`, outcome);
|
|
493
|
+
if (outcome === 'applied')
|
|
494
|
+
logger_1.loggerRegistry.info(`[long-tail] scan scheme applied: ${scheme.version}`);
|
|
495
|
+
// Undeclared rules on a code-owned scheme are reported, never deleted.
|
|
496
|
+
const declaredCategories = new Set((rules ?? []).map((r) => r.category));
|
|
497
|
+
const existingRules = await listScanRules(scheme.version);
|
|
498
|
+
scanReport.orphans.push(...existingRules
|
|
499
|
+
.filter((r) => !declaredCategories.has(r.category))
|
|
500
|
+
.map((r) => `${scheme.version}/${r.category}`));
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
const inserted = await seedScanScheme(schemeInput);
|
|
504
|
+
for (const rule of rules ?? []) {
|
|
505
|
+
await seedScanRule({ scheme_version: scheme.version, ...rule });
|
|
506
|
+
}
|
|
507
|
+
(0, apply_report_1.recordOutcome)(scanReport, `scheme ${scheme.version}`, 'db-owned');
|
|
508
|
+
if (inserted)
|
|
509
|
+
logger_1.loggerRegistry.info(`[long-tail] scan scheme seeded: ${scheme.version}`);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
catch (err) {
|
|
513
|
+
logger_1.loggerRegistry.warn(`[long-tail] scan scheme seed failed for ${scheme.version}: ${err.message}`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
if (codeOwnedBoot && !startConfig.examples) {
|
|
517
|
+
// Schemes in the DB not declared here (demo seeds own theirs under examples).
|
|
518
|
+
const declaredVersions = new Set(startConfig.scanSchemes.map((s) => s.version));
|
|
519
|
+
scanReport.orphans.push(...(await listScanSchemes())
|
|
520
|
+
.map((s) => s.version)
|
|
521
|
+
.filter((v) => !declaredVersions.has(v))
|
|
522
|
+
.map(String));
|
|
523
|
+
}
|
|
524
|
+
if (codeOwnedBoot)
|
|
525
|
+
(0, apply_report_1.logSurfaceReport)('scan-schemes', scanReport);
|
|
337
526
|
}
|
|
338
527
|
// Register the in-process callback adapter for agent event triggers.
|
|
339
528
|
// Reuse existing instance if already registered (e.g., from SDK createClient).
|