@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.
Files changed (234) hide show
  1. package/README.md +1 -0
  2. package/build/api/auth-sso.d.ts +6 -3
  3. package/build/api/auth-sso.js +6 -3
  4. package/build/api/escalations/helpers.js +4 -2
  5. package/build/api/settings.js +3 -0
  6. package/build/modules/auth.js +9 -3
  7. package/build/routes/auth-sso.js +6 -1
  8. package/build/services/agent/index.d.ts +11 -0
  9. package/build/services/agent/index.js +32 -0
  10. package/build/services/agent/sql.d.ts +7 -0
  11. package/build/services/agent/sql.js +32 -1
  12. package/build/services/agent/subscription-sql.d.ts +6 -0
  13. package/build/services/agent/subscription-sql.js +32 -1
  14. package/build/services/agent/subscriptions.d.ts +6 -0
  15. package/build/services/agent/subscriptions.js +23 -0
  16. package/build/services/config/index.d.ts +1 -1
  17. package/build/services/config/index.js +2 -1
  18. package/build/services/config/write.d.ts +10 -0
  19. package/build/services/config/write.js +49 -2
  20. package/build/services/domain/seed.d.ts +12 -5
  21. package/build/services/domain/seed.js +25 -6
  22. package/build/services/mcp/db.d.ts +16 -0
  23. package/build/services/mcp/db.js +24 -0
  24. package/build/services/mcp/sql.d.ts +8 -0
  25. package/build/services/mcp/sql.js +24 -1
  26. package/build/services/role/seed.d.ts +21 -0
  27. package/build/services/role/seed.js +113 -0
  28. package/build/services/role/sql.d.ts +8 -0
  29. package/build/services/role/sql.js +24 -1
  30. package/build/services/scan-code/index.d.ts +1 -1
  31. package/build/services/scan-code/index.js +3 -1
  32. package/build/services/scan-code/sql.d.ts +7 -0
  33. package/build/services/scan-code/sql.js +55 -1
  34. package/build/services/scan-code/write.d.ts +8 -0
  35. package/build/services/scan-code/write.js +23 -1
  36. package/build/services/topics/index.d.ts +2 -0
  37. package/build/services/topics/index.js +7 -0
  38. package/build/services/topics/sql.d.ts +2 -0
  39. package/build/services/topics/sql.js +5 -1
  40. package/build/services/topics/system-topics.d.ts +3 -2
  41. package/build/services/topics/system-topics.js +4 -3
  42. package/build/services/user/index.d.ts +1 -1
  43. package/build/services/user/index.js +2 -1
  44. package/build/services/user/roles.d.ts +8 -0
  45. package/build/services/user/roles.js +29 -0
  46. package/build/services/user/sql.d.ts +6 -0
  47. package/build/services/user/sql.js +9 -1
  48. package/build/services/user/sso-provision.js +14 -3
  49. package/build/start/apply-report.d.ts +26 -0
  50. package/build/start/apply-report.js +65 -0
  51. package/build/start/config.js +8 -1
  52. package/build/start/workers.js +222 -33
  53. package/build/tsconfig.tsbuildinfo +1 -1
  54. package/build/types/auth.d.ts +44 -4
  55. package/build/types/index.d.ts +1 -1
  56. package/build/types/startup.d.ts +160 -4
  57. package/dashboard/dist/assets/{AdminDashboard-DpTZG5EL.js → AdminDashboard-D2unnS2b.js} +2 -2
  58. package/dashboard/dist/assets/{AdminDashboard-DpTZG5EL.js.map → AdminDashboard-D2unnS2b.js.map} +1 -1
  59. package/dashboard/dist/assets/{AgentConfigPage-DVTL0NvC.js → AgentConfigPage-CBkf403g.js} +2 -2
  60. package/dashboard/dist/assets/{AgentConfigPage-DVTL0NvC.js.map → AgentConfigPage-CBkf403g.js.map} +1 -1
  61. package/dashboard/dist/assets/{AgentDetailPage-DOLKNPJl.js → AgentDetailPage-CAIU3yzo.js} +2 -2
  62. package/dashboard/dist/assets/{AgentDetailPage-DOLKNPJl.js.map → AgentDetailPage-CAIU3yzo.js.map} +1 -1
  63. package/dashboard/dist/assets/{AgentsPage-DiOZu6Xb.js → AgentsPage-qP9fWMyT.js} +2 -2
  64. package/dashboard/dist/assets/{AgentsPage-DiOZu6Xb.js.map → AgentsPage-qP9fWMyT.js.map} +1 -1
  65. package/dashboard/dist/assets/{AvailableEscalationsPage-CY5lfx27.js → AvailableEscalationsPage-DvWaiafI.js} +2 -2
  66. package/dashboard/dist/assets/{AvailableEscalationsPage-CY5lfx27.js.map → AvailableEscalationsPage-DvWaiafI.js.map} +1 -1
  67. package/dashboard/dist/assets/{BotPicker-ButjLJr2.js → BotPicker-BN-MKITV.js} +2 -2
  68. package/dashboard/dist/assets/{BotPicker-ButjLJr2.js.map → BotPicker-BN-MKITV.js.map} +1 -1
  69. package/dashboard/dist/assets/{CapabilitiesPage-CW_r2OlX.js → CapabilitiesPage-CJfmWokN.js} +2 -2
  70. package/dashboard/dist/assets/{CapabilitiesPage-CW_r2OlX.js.map → CapabilitiesPage-CJfmWokN.js.map} +1 -1
  71. package/dashboard/dist/assets/{CollapsibleSection-BOGRyCfm.js → CollapsibleSection-BvMHlHyt.js} +2 -2
  72. package/dashboard/dist/assets/{CollapsibleSection-BOGRyCfm.js.map → CollapsibleSection-BvMHlHyt.js.map} +1 -1
  73. package/dashboard/dist/assets/{CountdownTimer-UcHYZSg1.js → CountdownTimer-By4rbMDN.js} +2 -2
  74. package/dashboard/dist/assets/{CountdownTimer-UcHYZSg1.js.map → CountdownTimer-By4rbMDN.js.map} +1 -1
  75. package/dashboard/dist/assets/{CredentialsPage-A7OFYVsX.js → CredentialsPage-2TvvRwGJ.js} +2 -2
  76. package/dashboard/dist/assets/{CredentialsPage-A7OFYVsX.js.map → CredentialsPage-2TvvRwGJ.js.map} +1 -1
  77. package/dashboard/dist/assets/{CronLabel-Dve2Udsm.js → CronLabel-HxmsDSnV.js} +2 -2
  78. package/dashboard/dist/assets/{CronLabel-Dve2Udsm.js.map → CronLabel-HxmsDSnV.js.map} +1 -1
  79. package/dashboard/dist/assets/{CustomDurationPicker-BoPrA-Em.js → CustomDurationPicker-8Ao-1pKA.js} +2 -2
  80. package/dashboard/dist/assets/{CustomDurationPicker-BoPrA-Em.js.map → CustomDurationPicker-8Ao-1pKA.js.map} +1 -1
  81. package/dashboard/dist/assets/{ElapsedCell-B114P5mb.js → ElapsedCell-BkRu9Xpd.js} +2 -2
  82. package/dashboard/dist/assets/{ElapsedCell-B114P5mb.js.map → ElapsedCell-BkRu9Xpd.js.map} +1 -1
  83. package/dashboard/dist/assets/{EntityTimelinePanel-BqDWyOa9.js → EntityTimelinePanel--E6hLMCM.js} +2 -2
  84. package/dashboard/dist/assets/{EntityTimelinePanel-BqDWyOa9.js.map → EntityTimelinePanel--E6hLMCM.js.map} +1 -1
  85. package/dashboard/dist/assets/{EscalationListSchemaPage-DyyTyghx.js → EscalationListSchemaPage-CdFtqEEX.js} +2 -2
  86. package/dashboard/dist/assets/{EscalationListSchemaPage-DyyTyghx.js.map → EscalationListSchemaPage-CdFtqEEX.js.map} +1 -1
  87. package/dashboard/dist/assets/{EscalationSchemaPage-DLQG6EXQ.js → EscalationSchemaPage-BsjS2axz.js} +2 -2
  88. package/dashboard/dist/assets/{EscalationSchemaPage-DLQG6EXQ.js.map → EscalationSchemaPage-BsjS2axz.js.map} +1 -1
  89. package/dashboard/dist/assets/{EscalationsOverview-RrbkkEU0.js → EscalationsOverview-FL-xteVc.js} +2 -2
  90. package/dashboard/dist/assets/{EscalationsOverview-RrbkkEU0.js.map → EscalationsOverview-FL-xteVc.js.map} +1 -1
  91. package/dashboard/dist/assets/{EventTable-DOxubt7O.js → EventTable-BOcgZ78i.js} +2 -2
  92. package/dashboard/dist/assets/{EventTable-DOxubt7O.js.map → EventTable-BOcgZ78i.js.map} +1 -1
  93. package/dashboard/dist/assets/{FilterBar-y659Gc3X.js → FilterBar-DfCiCmm-.js} +2 -2
  94. package/dashboard/dist/assets/{FilterBar-y659Gc3X.js.map → FilterBar-DfCiCmm-.js.map} +1 -1
  95. package/dashboard/dist/assets/{GraphInvokePage-oHLgSAl6.js → GraphInvokePage-DfVeiN-8.js} +2 -2
  96. package/dashboard/dist/assets/{GraphInvokePage-oHLgSAl6.js.map → GraphInvokePage-DfVeiN-8.js.map} +1 -1
  97. package/dashboard/dist/assets/{HomePage-C9FUpD7x.js → HomePage-C2IhF9WB.js} +2 -2
  98. package/dashboard/dist/assets/{HomePage-C9FUpD7x.js.map → HomePage-C2IhF9WB.js.map} +1 -1
  99. package/dashboard/dist/assets/{ListToolbar-DfpSgWYU.js → ListToolbar-DA0PTOl5.js} +2 -2
  100. package/dashboard/dist/assets/{ListToolbar-DfpSgWYU.js.map → ListToolbar-DA0PTOl5.js.map} +1 -1
  101. package/dashboard/dist/assets/{McpOverview-6Ubpr9QS.js → McpOverview-DstPch5M.js} +2 -2
  102. package/dashboard/dist/assets/{McpOverview-6Ubpr9QS.js.map → McpOverview-DstPch5M.js.map} +1 -1
  103. package/dashboard/dist/assets/{McpQueryDetailPage-DFt-vQEp.js → McpQueryDetailPage-Csv0PKE0.js} +2 -2
  104. package/dashboard/dist/assets/{McpQueryDetailPage-DFt-vQEp.js.map → McpQueryDetailPage-Csv0PKE0.js.map} +1 -1
  105. package/dashboard/dist/assets/{McpQueryPage-DQiG0AE3.js → McpQueryPage-DxmqCkly.js} +2 -2
  106. package/dashboard/dist/assets/{McpQueryPage-DQiG0AE3.js.map → McpQueryPage-DxmqCkly.js.map} +1 -1
  107. package/dashboard/dist/assets/{McpRunDetailPage-BgsSegyP.js → McpRunDetailPage-CcJOlp_B.js} +2 -2
  108. package/dashboard/dist/assets/{McpRunDetailPage-BgsSegyP.js.map → McpRunDetailPage-CcJOlp_B.js.map} +1 -1
  109. package/dashboard/dist/assets/{McpRunsPage-tCMxspqS.js → McpRunsPage-BZCR043j.js} +2 -2
  110. package/dashboard/dist/assets/{McpRunsPage-tCMxspqS.js.map → McpRunsPage-BZCR043j.js.map} +1 -1
  111. package/dashboard/dist/assets/{OperationsPage-DUaRmEPa.js → OperationsPage-DMsPXITh.js} +2 -2
  112. package/dashboard/dist/assets/{OperationsPage-DUaRmEPa.js.map → OperationsPage-DMsPXITh.js.map} +1 -1
  113. package/dashboard/dist/assets/{OperatorDashboard-CayyjMcf.js → OperatorDashboard-DSloftQ5.js} +2 -2
  114. package/dashboard/dist/assets/{OperatorDashboard-CayyjMcf.js.map → OperatorDashboard-DSloftQ5.js.map} +1 -1
  115. package/dashboard/dist/assets/{PersonaDetailPage-DBcxfdbN.js → PersonaDetailPage-jDVRCLbU.js} +2 -2
  116. package/dashboard/dist/assets/{PersonaDetailPage-DBcxfdbN.js.map → PersonaDetailPage-jDVRCLbU.js.map} +1 -1
  117. package/dashboard/dist/assets/{PersonasPage-DPq0HQAB.js → PersonasPage-DnDDwXoy.js} +2 -2
  118. package/dashboard/dist/assets/{PersonasPage-DPq0HQAB.js.map → PersonasPage-DnDDwXoy.js.map} +1 -1
  119. package/dashboard/dist/assets/{ProcessDetailPage-QQZNNNMw.js → ProcessDetailPage-CfAUU6q2.js} +2 -2
  120. package/dashboard/dist/assets/{ProcessDetailPage-QQZNNNMw.js.map → ProcessDetailPage-CfAUU6q2.js.map} +1 -1
  121. package/dashboard/dist/assets/{ProcessesListPage-UKQMJ4Te.js → ProcessesListPage-CnAXzaVv.js} +2 -2
  122. package/dashboard/dist/assets/{ProcessesListPage-UKQMJ4Te.js.map → ProcessesListPage-CnAXzaVv.js.map} +1 -1
  123. package/dashboard/dist/assets/{RoleDetailPage-DT-3sSRD.js → RoleDetailPage-Dg1p6Qz_.js} +2 -2
  124. package/dashboard/dist/assets/{RoleDetailPage-DT-3sSRD.js.map → RoleDetailPage-Dg1p6Qz_.js.map} +1 -1
  125. package/dashboard/dist/assets/{RolesPage-DZg4niqL.js → RolesPage-DeRVQux8.js} +2 -2
  126. package/dashboard/dist/assets/{RolesPage-DZg4niqL.js.map → RolesPage-DeRVQux8.js.map} +1 -1
  127. package/dashboard/dist/assets/{RunAsSelector-DkcNR7L6.js → RunAsSelector-BFNqQGuG.js} +2 -2
  128. package/dashboard/dist/assets/{RunAsSelector-DkcNR7L6.js.map → RunAsSelector-BFNqQGuG.js.map} +1 -1
  129. package/dashboard/dist/assets/{ScanCodesPage-U-alpwWF.js → ScanCodesPage-D0GOdk5m.js} +2 -2
  130. package/dashboard/dist/assets/{ScanCodesPage-U-alpwWF.js.map → ScanCodesPage-D0GOdk5m.js.map} +1 -1
  131. package/dashboard/dist/assets/{ScanSchemeDetailPage-lXwlcraS.js → ScanSchemeDetailPage-vFqoe_P4.js} +2 -2
  132. package/dashboard/dist/assets/{ScanSchemeDetailPage-lXwlcraS.js.map → ScanSchemeDetailPage-vFqoe_P4.js.map} +1 -1
  133. package/dashboard/dist/assets/{ScanStationPage-DYMiTp-v.js → ScanStationPage-DH1ynTX9.js} +2 -2
  134. package/dashboard/dist/assets/{ScanStationPage-DYMiTp-v.js.map → ScanStationPage-DH1ynTX9.js.map} +1 -1
  135. package/dashboard/dist/assets/{StickyPagination-D896Wquq.js → StickyPagination-B99hVu95.js} +2 -2
  136. package/dashboard/dist/assets/{StickyPagination-D896Wquq.js.map → StickyPagination-B99hVu95.js.map} +1 -1
  137. package/dashboard/dist/assets/{StreamMessageDetail-DIh5qEGJ.js → StreamMessageDetail-DcDGISrv.js} +2 -2
  138. package/dashboard/dist/assets/{StreamMessageDetail-DIh5qEGJ.js.map → StreamMessageDetail-DcDGISrv.js.map} +1 -1
  139. package/dashboard/dist/assets/{SwimlaneTimeline-B8SucVj5.js → SwimlaneTimeline-BP3mSQAg.js} +2 -2
  140. package/dashboard/dist/assets/{SwimlaneTimeline-B8SucVj5.js.map → SwimlaneTimeline-BP3mSQAg.js.map} +1 -1
  141. package/dashboard/dist/assets/{TaskDetailPage-Di-z_ZE2.js → TaskDetailPage-_XWLJzt-.js} +2 -2
  142. package/dashboard/dist/assets/{TaskDetailPage-Di-z_ZE2.js.map → TaskDetailPage-_XWLJzt-.js.map} +1 -1
  143. package/dashboard/dist/assets/{TasksListPage-ClHGEdin.js → TasksListPage-iGriKiO2.js} +2 -2
  144. package/dashboard/dist/assets/{TasksListPage-ClHGEdin.js.map → TasksListPage-iGriKiO2.js.map} +1 -1
  145. package/dashboard/dist/assets/{TimeAgo-BSDHd9Xo.js → TimeAgo-BO33VeFl.js} +2 -2
  146. package/dashboard/dist/assets/{TimeAgo-BSDHd9Xo.js.map → TimeAgo-BO33VeFl.js.map} +1 -1
  147. package/dashboard/dist/assets/{TimestampCell-WQL3FxWl.js → TimestampCell-KAjX7w35.js} +2 -2
  148. package/dashboard/dist/assets/{TimestampCell-WQL3FxWl.js.map → TimestampCell-KAjX7w35.js.map} +1 -1
  149. package/dashboard/dist/assets/{ToolTestPanel-IVIkqZTi.js → ToolTestPanel-BchG2yC6.js} +2 -2
  150. package/dashboard/dist/assets/{ToolTestPanel-IVIkqZTi.js.map → ToolTestPanel-BchG2yC6.js.map} +1 -1
  151. package/dashboard/dist/assets/{TopicDetailPage-BOasQo68.js → TopicDetailPage-BaK8H0o1.js} +2 -2
  152. package/dashboard/dist/assets/{TopicDetailPage-BOasQo68.js.map → TopicDetailPage-BaK8H0o1.js.map} +1 -1
  153. package/dashboard/dist/assets/{TopicsPage-DV_orf_V.js → TopicsPage-DEyvm669.js} +2 -2
  154. package/dashboard/dist/assets/{TopicsPage-DV_orf_V.js.map → TopicsPage-DEyvm669.js.map} +1 -1
  155. package/dashboard/dist/assets/{UserName-rshjKBtm.js → UserName-BV6SKI9P.js} +2 -2
  156. package/dashboard/dist/assets/{UserName-rshjKBtm.js.map → UserName-BV6SKI9P.js.map} +1 -1
  157. package/dashboard/dist/assets/{WorkflowExecutionPage-BpNGLwbK.js → WorkflowExecutionPage-1sKoEFNC.js} +2 -2
  158. package/dashboard/dist/assets/{WorkflowExecutionPage-BpNGLwbK.js.map → WorkflowExecutionPage-1sKoEFNC.js.map} +1 -1
  159. package/dashboard/dist/assets/{WorkflowsDashboard-BAXt8gv_.js → WorkflowsDashboard-YTHDZZOD.js} +2 -2
  160. package/dashboard/dist/assets/{WorkflowsDashboard-BAXt8gv_.js.map → WorkflowsDashboard-YTHDZZOD.js.map} +1 -1
  161. package/dashboard/dist/assets/{WorkflowsOverview-DvOyzL6y.js → WorkflowsOverview-ucXPLTtm.js} +2 -2
  162. package/dashboard/dist/assets/{WorkflowsOverview-DvOyzL6y.js.map → WorkflowsOverview-ucXPLTtm.js.map} +1 -1
  163. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CraijGy6.js → YamlWorkflowDetailPage-C_RTZKqZ.js} +2 -2
  164. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CraijGy6.js.map → YamlWorkflowDetailPage-C_RTZKqZ.js.map} +1 -1
  165. package/dashboard/dist/assets/{YamlWorkflowsPage-CNz3ptmj.js → YamlWorkflowsPage-Usid3w2W.js} +2 -2
  166. package/dashboard/dist/assets/{YamlWorkflowsPage-CNz3ptmj.js.map → YamlWorkflowsPage-Usid3w2W.js.map} +1 -1
  167. package/dashboard/dist/assets/{agents-BswSJR-t.js → agents-BTDsRK8e.js} +2 -2
  168. package/dashboard/dist/assets/{agents-BswSJR-t.js.map → agents-BTDsRK8e.js.map} +1 -1
  169. package/dashboard/dist/assets/{bots-VzlLx_GQ.js → bots-DxLrfdfr.js} +2 -2
  170. package/dashboard/dist/assets/{bots-VzlLx_GQ.js.map → bots-DxLrfdfr.js.map} +1 -1
  171. package/dashboard/dist/assets/{capabilities-B0bNlTTA.js → capabilities-DbTmeW-S.js} +2 -2
  172. package/dashboard/dist/assets/{capabilities-B0bNlTTA.js.map → capabilities-DbTmeW-S.js.map} +1 -1
  173. package/dashboard/dist/assets/{controlplane-DBESTVZS.js → controlplane-CEBntAL4.js} +2 -2
  174. package/dashboard/dist/assets/{controlplane-DBESTVZS.js.map → controlplane-CEBntAL4.js.map} +1 -1
  175. package/dashboard/dist/assets/{escalation-columns-CoqsCdbP.js → escalation-columns-Carqdwoh.js} +2 -2
  176. package/dashboard/dist/assets/{escalation-columns-CoqsCdbP.js.map → escalation-columns-Carqdwoh.js.map} +1 -1
  177. package/dashboard/dist/assets/{index-DUfdCp8e.js → index-B2hz0pUh.js} +2 -2
  178. package/dashboard/dist/assets/{index-DUfdCp8e.js.map → index-B2hz0pUh.js.map} +1 -1
  179. package/dashboard/dist/assets/{index-DJS-hvDt.js → index-B9m7fA3M.js} +2 -2
  180. package/dashboard/dist/assets/{index-DJS-hvDt.js.map → index-B9m7fA3M.js.map} +1 -1
  181. package/dashboard/dist/assets/{index-C_lA7ghl.js → index-BhapT-Vl.js} +2 -2
  182. package/dashboard/dist/assets/{index-C_lA7ghl.js.map → index-BhapT-Vl.js.map} +1 -1
  183. package/dashboard/dist/assets/{index-DsDFZzqr.js → index-Bqm4zu46.js} +2 -2
  184. package/dashboard/dist/assets/{index-DsDFZzqr.js.map → index-Bqm4zu46.js.map} +1 -1
  185. package/dashboard/dist/assets/{index-Cd7jZylO.js → index-C0hSttF5.js} +2 -2
  186. package/dashboard/dist/assets/{index-Cd7jZylO.js.map → index-C0hSttF5.js.map} +1 -1
  187. package/dashboard/dist/assets/{index-ByUjwu37.js → index-CDkg6iOE.js} +2 -2
  188. package/dashboard/dist/assets/{index-ByUjwu37.js.map → index-CDkg6iOE.js.map} +1 -1
  189. package/dashboard/dist/assets/{index-Ci4lxPwS.js → index-CVBBkW8V.js} +2 -2
  190. package/dashboard/dist/assets/{index-Ci4lxPwS.js.map → index-CVBBkW8V.js.map} +1 -1
  191. package/dashboard/dist/assets/{index-DYDcjn-b.js → index-CgIBjZta.js} +2 -2
  192. package/dashboard/dist/assets/{index-DYDcjn-b.js.map → index-CgIBjZta.js.map} +1 -1
  193. package/dashboard/dist/assets/{index-Cqrp5B5S.js → index-DBXm49S6.js} +25 -25
  194. package/dashboard/dist/assets/index-DBXm49S6.js.map +1 -0
  195. package/dashboard/dist/assets/{index-BBXmIWKx.js → index-De8iV1y2.js} +2 -2
  196. package/dashboard/dist/assets/{index-BBXmIWKx.js.map → index-De8iV1y2.js.map} +1 -1
  197. package/dashboard/dist/assets/{index-D8ljRGIb.js → index-DsgjFRvA.js} +2 -2
  198. package/dashboard/dist/assets/{index-D8ljRGIb.js.map → index-DsgjFRvA.js.map} +1 -1
  199. package/dashboard/dist/assets/{index-BLzwfbZV.js → index-kes8V4Xw.js} +2 -2
  200. package/dashboard/dist/assets/{index-BLzwfbZV.js.map → index-kes8V4Xw.js.map} +1 -1
  201. package/dashboard/dist/assets/{index-CALocCAr.js → index-nwLh3CK2.js} +2 -2
  202. package/dashboard/dist/assets/{index-CALocCAr.js.map → index-nwLh3CK2.js.map} +1 -1
  203. package/dashboard/dist/assets/{knowledge-DB2DgDa_.js → knowledge-oFYAanUp.js} +2 -2
  204. package/dashboard/dist/assets/{knowledge-DB2DgDa_.js.map → knowledge-oFYAanUp.js.map} +1 -1
  205. package/dashboard/dist/assets/{mcp-D72yCeuf.js → mcp-C9Kw4Ow8.js} +2 -2
  206. package/dashboard/dist/assets/{mcp-D72yCeuf.js.map → mcp-C9Kw4Ow8.js.map} +1 -1
  207. package/dashboard/dist/assets/{mcp-query-Cyyc_0E8.js → mcp-query-BwzpZ91Z.js} +2 -2
  208. package/dashboard/dist/assets/{mcp-query-Cyyc_0E8.js.map → mcp-query-BwzpZ91Z.js.map} +1 -1
  209. package/dashboard/dist/assets/{personas-xMDV7yXb.js → personas-D5ehmtRb.js} +2 -2
  210. package/dashboard/dist/assets/{personas-xMDV7yXb.js.map → personas-D5ehmtRb.js.map} +1 -1
  211. package/dashboard/dist/assets/{pipelines-mlxfmi6m.js → pipelines-xgPKGEdD.js} +2 -2
  212. package/dashboard/dist/assets/{pipelines-mlxfmi6m.js.map → pipelines-xgPKGEdD.js.map} +1 -1
  213. package/dashboard/dist/assets/{tasks-CxgOp_9H.js → tasks-CLyrl-MU.js} +2 -2
  214. package/dashboard/dist/assets/{tasks-CxgOp_9H.js.map → tasks-CLyrl-MU.js.map} +1 -1
  215. package/dashboard/dist/assets/{topics-CFb_L0Vs.js → topics-B_gO7CQ0.js} +2 -2
  216. package/dashboard/dist/assets/{topics-CFb_L0Vs.js.map → topics-B_gO7CQ0.js.map} +1 -1
  217. package/dashboard/dist/assets/{useEventHooks-nC5kH-QW.js → useEventHooks-BdWYm63U.js} +2 -2
  218. package/dashboard/dist/assets/{useEventHooks-nC5kH-QW.js.map → useEventHooks-BdWYm63U.js.map} +1 -1
  219. package/dashboard/dist/assets/{useNamespace-DQeDgRFR.js → useNamespace-C238M4Qn.js} +2 -2
  220. package/dashboard/dist/assets/{useNamespace-DQeDgRFR.js.map → useNamespace-C238M4Qn.js.map} +1 -1
  221. package/dashboard/dist/assets/{useYamlActivityEvents-BuGC3oBE.js → useYamlActivityEvents-B2ryEK4S.js} +2 -2
  222. package/dashboard/dist/assets/{useYamlActivityEvents-BuGC3oBE.js.map → useYamlActivityEvents-B2ryEK4S.js.map} +1 -1
  223. package/dashboard/dist/assets/{users-BZUTtM_6.js → users-BFaTe6Mt.js} +2 -2
  224. package/dashboard/dist/assets/{users-BZUTtM_6.js.map → users-BFaTe6Mt.js.map} +1 -1
  225. package/dashboard/dist/assets/{workflows-DWhaZWVK.js → workflows-DXz7tZxp.js} +2 -2
  226. package/dashboard/dist/assets/{workflows-DWhaZWVK.js.map → workflows-DXz7tZxp.js.map} +1 -1
  227. package/dashboard/dist/assets/{yaml-workflows-C1TeDIIk.js → yaml-workflows-u3xuRAnS.js} +2 -2
  228. package/dashboard/dist/assets/{yaml-workflows-C1TeDIIk.js.map → yaml-workflows-u3xuRAnS.js.map} +1 -1
  229. package/dashboard/dist/index.html +1 -1
  230. package/docs/auth.md +26 -1
  231. package/docs/code-owned-configuration.md +158 -0
  232. package/docs/scan-codes.md +24 -0
  233. package/package.json +1 -1
  234. 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
- /** Ensure all resolved roles exist on an already-provisioned user. */
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.addUserRole)(userId, lr.role, lr.type);
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
+ }
@@ -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
- setSSOConfig(startConfig.auth.sso);
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
  }
@@ -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
- // Seed workflow configs (insert-if-absent DB is source of truth)
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
- for (const w of workersWithConfig) {
169
- const workflowType = w.workflow.name;
170
- const c = w.config;
171
- try {
172
- const inserted = await seedWorkflowConfig({
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
- if (inserted)
189
- logger_1.loggerRegistry.info(`[long-tail] config seeded: ${workflowType}`);
190
- }
191
- catch (err) {
192
- logger_1.loggerRegistry.warn(`[long-tail] config seed failed for ${workflowType}: ${err.message}`);
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. Seed MCP server configs (insert-if-absent + drift log)
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
- const inserted = await seedMcpServer({ name, ...entry.config });
244
- if (inserted)
245
- logger_1.loggerRegistry.info(`[long-tail] MCP server seeded: ${name}`);
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
- // Seed the domain dictionary (every container, workers or not) — insert-if-
277
- // absent with warn-only reference validation; the DB row is runtime truth.
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 inserted = await seedAgent({
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 (inserted)
318
- logger_1.loggerRegistry.info(`[long-tail] agent seeded: ${agentConfig.name}`);
319
- // Seed subscriptions for this agent — id IS the name
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
- const subInserted = await seedSubscription(agentConfig.name, sub);
324
- if (subInserted)
325
- logger_1.loggerRegistry.info(`[long-tail] subscription seeded: ${agentConfig.name}/${sub.topic}`);
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).