@hotmeshio/long-tail 0.13.1 → 0.14.0

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 (235) hide show
  1. package/build/api/announcements.d.ts +22 -0
  2. package/build/api/announcements.js +96 -0
  3. package/build/api/escalations/list.d.ts +8 -0
  4. package/build/api/escalations/list.js +14 -4
  5. package/build/api/index.d.ts +1 -0
  6. package/build/api/index.js +2 -1
  7. package/build/api/workflows/config.d.ts +1 -0
  8. package/build/api/workflows/config.js +1 -0
  9. package/build/api/workflows/discovery.js +1 -0
  10. package/build/lib/db/schemas/031_announcements.sql +30 -0
  11. package/build/lib/db/schemas/032_workflow_read_safe.sql +9 -0
  12. package/build/lib/events/publish.d.ts +15 -0
  13. package/build/lib/events/publish.js +22 -0
  14. package/build/routes/announcements.d.ts +2 -0
  15. package/build/routes/announcements.js +64 -0
  16. package/build/routes/escalations/list.js +2 -0
  17. package/build/routes/index.js +2 -0
  18. package/build/services/announcement/index.d.ts +30 -0
  19. package/build/services/announcement/index.js +29 -0
  20. package/build/services/announcement/sql.d.ts +8 -0
  21. package/build/services/announcement/sql.js +24 -0
  22. package/build/services/config/cache.js +1 -0
  23. package/build/services/config/read.js +2 -0
  24. package/build/services/config/sql.d.ts +2 -2
  25. package/build/services/config/sql.js +6 -5
  26. package/build/services/config/write.js +5 -0
  27. package/build/services/topics/system-topics.js +20 -0
  28. package/build/shared/form-validation/index.d.ts +1 -0
  29. package/build/shared/form-validation/index.js +1 -0
  30. package/build/shared/form-validation/validate-resolver-payload.d.ts +3 -0
  31. package/build/shared/form-validation/validate-resolver-payload.js +19 -0
  32. package/build/shared/form-validation/x-lt-labels.d.ts +17 -6
  33. package/build/shared/form-validation/x-lt-labels.js +12 -4
  34. package/build/shared/form-validation/x-lt-require-any.d.ts +22 -0
  35. package/build/shared/form-validation/x-lt-require-any.js +41 -0
  36. package/build/start/workers.js +3 -5
  37. package/build/system/mcp-servers/admin/announcements.d.ts +7 -0
  38. package/build/system/mcp-servers/admin/announcements.js +69 -0
  39. package/build/system/mcp-servers/admin/index.js +5 -3
  40. package/build/system/mcp-servers/admin/workflows.js +45 -0
  41. package/build/system/seed/tool-manifests-admin.d.ts +357 -0
  42. package/build/system/seed/tool-manifests-admin.js +3 -0
  43. package/build/tsconfig.tsbuildinfo +1 -1
  44. package/build/types/config.d.ts +8 -0
  45. package/build/types/startup.d.ts +5 -0
  46. package/dashboard/dist/assets/{AdminDashboard-D2unnS2b.js → AdminDashboard-DeZsR4pA.js} +2 -2
  47. package/dashboard/dist/assets/{AdminDashboard-D2unnS2b.js.map → AdminDashboard-DeZsR4pA.js.map} +1 -1
  48. package/dashboard/dist/assets/{AgentConfigPage-CBkf403g.js → AgentConfigPage-Bi5ZAsjf.js} +2 -2
  49. package/dashboard/dist/assets/{AgentConfigPage-CBkf403g.js.map → AgentConfigPage-Bi5ZAsjf.js.map} +1 -1
  50. package/dashboard/dist/assets/{AgentDetailPage-CAIU3yzo.js → AgentDetailPage-CIbKor5E.js} +2 -2
  51. package/dashboard/dist/assets/{AgentDetailPage-CAIU3yzo.js.map → AgentDetailPage-CIbKor5E.js.map} +1 -1
  52. package/dashboard/dist/assets/{AgentsPage-qP9fWMyT.js → AgentsPage-CRFZ6KDu.js} +2 -2
  53. package/dashboard/dist/assets/{AgentsPage-qP9fWMyT.js.map → AgentsPage-CRFZ6KDu.js.map} +1 -1
  54. package/dashboard/dist/assets/AvailableEscalationsPage-DDsmXjpi.js +2 -0
  55. package/dashboard/dist/assets/AvailableEscalationsPage-DDsmXjpi.js.map +1 -0
  56. package/dashboard/dist/assets/{BotPicker-BN-MKITV.js → BotPicker-dUpw1wW6.js} +2 -2
  57. package/dashboard/dist/assets/{BotPicker-BN-MKITV.js.map → BotPicker-dUpw1wW6.js.map} +1 -1
  58. package/dashboard/dist/assets/{CapabilitiesPage-CJfmWokN.js → CapabilitiesPage-Ca2jEln-.js} +2 -2
  59. package/dashboard/dist/assets/{CapabilitiesPage-CJfmWokN.js.map → CapabilitiesPage-Ca2jEln-.js.map} +1 -1
  60. package/dashboard/dist/assets/{CollapsibleSection-BvMHlHyt.js → CollapsibleSection-BXlR5QmW.js} +2 -2
  61. package/dashboard/dist/assets/{CollapsibleSection-BvMHlHyt.js.map → CollapsibleSection-BXlR5QmW.js.map} +1 -1
  62. package/dashboard/dist/assets/CountdownTimer-rnoWmFqx.js +2 -0
  63. package/dashboard/dist/assets/CountdownTimer-rnoWmFqx.js.map +1 -0
  64. package/dashboard/dist/assets/{CredentialsPage-2TvvRwGJ.js → CredentialsPage-CGyCCzGh.js} +2 -2
  65. package/dashboard/dist/assets/{CredentialsPage-2TvvRwGJ.js.map → CredentialsPage-CGyCCzGh.js.map} +1 -1
  66. package/dashboard/dist/assets/{CronLabel-HxmsDSnV.js → CronLabel-CAu2hmQf.js} +2 -2
  67. package/dashboard/dist/assets/{CronLabel-HxmsDSnV.js.map → CronLabel-CAu2hmQf.js.map} +1 -1
  68. package/dashboard/dist/assets/CustomDurationPicker-hlnadaFt.js +2 -0
  69. package/dashboard/dist/assets/CustomDurationPicker-hlnadaFt.js.map +1 -0
  70. package/dashboard/dist/assets/{ElapsedCell-BkRu9Xpd.js → ElapsedCell-B1eoCzEw.js} +2 -2
  71. package/dashboard/dist/assets/{ElapsedCell-BkRu9Xpd.js.map → ElapsedCell-B1eoCzEw.js.map} +1 -1
  72. package/dashboard/dist/assets/{EntityTimelinePanel--E6hLMCM.js → EntityTimelinePanel-CIOyjwjM.js} +2 -2
  73. package/dashboard/dist/assets/{EntityTimelinePanel--E6hLMCM.js.map → EntityTimelinePanel-CIOyjwjM.js.map} +1 -1
  74. package/dashboard/dist/assets/{EscalationListSchemaPage-CdFtqEEX.js → EscalationListSchemaPage-DQNQ7o_4.js} +2 -2
  75. package/dashboard/dist/assets/{EscalationListSchemaPage-CdFtqEEX.js.map → EscalationListSchemaPage-DQNQ7o_4.js.map} +1 -1
  76. package/dashboard/dist/assets/{EscalationSchemaPage-BsjS2axz.js → EscalationSchemaPage-DFgDn4R3.js} +2 -2
  77. package/dashboard/dist/assets/{EscalationSchemaPage-BsjS2axz.js.map → EscalationSchemaPage-DFgDn4R3.js.map} +1 -1
  78. package/dashboard/dist/assets/{EscalationsOverview-FL-xteVc.js → EscalationsOverview-DfbKtXVZ.js} +2 -2
  79. package/dashboard/dist/assets/{EscalationsOverview-FL-xteVc.js.map → EscalationsOverview-DfbKtXVZ.js.map} +1 -1
  80. package/dashboard/dist/assets/{EventTable-BOcgZ78i.js → EventTable-CZPkvhao.js} +2 -2
  81. package/dashboard/dist/assets/{EventTable-BOcgZ78i.js.map → EventTable-CZPkvhao.js.map} +1 -1
  82. package/dashboard/dist/assets/{FilterBar-DfCiCmm-.js → FilterBar-CYjKK9Cp.js} +2 -2
  83. package/dashboard/dist/assets/{FilterBar-DfCiCmm-.js.map → FilterBar-CYjKK9Cp.js.map} +1 -1
  84. package/dashboard/dist/assets/{GraphInvokePage-DfVeiN-8.js → GraphInvokePage-DY9u42vt.js} +2 -2
  85. package/dashboard/dist/assets/{GraphInvokePage-DfVeiN-8.js.map → GraphInvokePage-DY9u42vt.js.map} +1 -1
  86. package/dashboard/dist/assets/{HomePage-C2IhF9WB.js → HomePage-p_CYlGnh.js} +2 -2
  87. package/dashboard/dist/assets/{HomePage-C2IhF9WB.js.map → HomePage-p_CYlGnh.js.map} +1 -1
  88. package/dashboard/dist/assets/{ListToolbar-DA0PTOl5.js → ListToolbar-Dz-1RXSH.js} +2 -2
  89. package/dashboard/dist/assets/{ListToolbar-DA0PTOl5.js.map → ListToolbar-Dz-1RXSH.js.map} +1 -1
  90. package/dashboard/dist/assets/{McpOverview-DstPch5M.js → McpOverview-BUI9sVTk.js} +2 -2
  91. package/dashboard/dist/assets/{McpOverview-DstPch5M.js.map → McpOverview-BUI9sVTk.js.map} +1 -1
  92. package/dashboard/dist/assets/{McpQueryDetailPage-Csv0PKE0.js → McpQueryDetailPage-CVN_UAB3.js} +2 -2
  93. package/dashboard/dist/assets/{McpQueryDetailPage-Csv0PKE0.js.map → McpQueryDetailPage-CVN_UAB3.js.map} +1 -1
  94. package/dashboard/dist/assets/{McpQueryPage-DxmqCkly.js → McpQueryPage-DRTKSPDR.js} +2 -2
  95. package/dashboard/dist/assets/{McpQueryPage-DxmqCkly.js.map → McpQueryPage-DRTKSPDR.js.map} +1 -1
  96. package/dashboard/dist/assets/{McpRunDetailPage-CcJOlp_B.js → McpRunDetailPage-CTb1AxR3.js} +2 -2
  97. package/dashboard/dist/assets/{McpRunDetailPage-CcJOlp_B.js.map → McpRunDetailPage-CTb1AxR3.js.map} +1 -1
  98. package/dashboard/dist/assets/{McpRunsPage-BZCR043j.js → McpRunsPage-BWLwjVd0.js} +2 -2
  99. package/dashboard/dist/assets/{McpRunsPage-BZCR043j.js.map → McpRunsPage-BWLwjVd0.js.map} +1 -1
  100. package/dashboard/dist/assets/{OperationsPage-DMsPXITh.js → OperationsPage-BSl_oUAJ.js} +2 -2
  101. package/dashboard/dist/assets/{OperationsPage-DMsPXITh.js.map → OperationsPage-BSl_oUAJ.js.map} +1 -1
  102. package/dashboard/dist/assets/{OperatorDashboard-DSloftQ5.js → OperatorDashboard-DGs9kPOZ.js} +2 -2
  103. package/dashboard/dist/assets/{OperatorDashboard-DSloftQ5.js.map → OperatorDashboard-DGs9kPOZ.js.map} +1 -1
  104. package/dashboard/dist/assets/{PersonaDetailPage-jDVRCLbU.js → PersonaDetailPage-C33MgXUY.js} +2 -2
  105. package/dashboard/dist/assets/{PersonaDetailPage-jDVRCLbU.js.map → PersonaDetailPage-C33MgXUY.js.map} +1 -1
  106. package/dashboard/dist/assets/{PersonasPage-DnDDwXoy.js → PersonasPage-BbLOHq5X.js} +2 -2
  107. package/dashboard/dist/assets/{PersonasPage-DnDDwXoy.js.map → PersonasPage-BbLOHq5X.js.map} +1 -1
  108. package/dashboard/dist/assets/{ProcessDetailPage-CfAUU6q2.js → ProcessDetailPage-zwd0HCJl.js} +2 -2
  109. package/dashboard/dist/assets/{ProcessDetailPage-CfAUU6q2.js.map → ProcessDetailPage-zwd0HCJl.js.map} +1 -1
  110. package/dashboard/dist/assets/{ProcessesListPage-CnAXzaVv.js → ProcessesListPage-DnfmK6jf.js} +2 -2
  111. package/dashboard/dist/assets/{ProcessesListPage-CnAXzaVv.js.map → ProcessesListPage-DnfmK6jf.js.map} +1 -1
  112. package/dashboard/dist/assets/{RoleDetailPage-Dg1p6Qz_.js → RoleDetailPage-axZtFPC_.js} +2 -2
  113. package/dashboard/dist/assets/{RoleDetailPage-Dg1p6Qz_.js.map → RoleDetailPage-axZtFPC_.js.map} +1 -1
  114. package/dashboard/dist/assets/{RolesPage-DeRVQux8.js → RolesPage-DN6yqH7-.js} +2 -2
  115. package/dashboard/dist/assets/{RolesPage-DeRVQux8.js.map → RolesPage-DN6yqH7-.js.map} +1 -1
  116. package/dashboard/dist/assets/{RunAsSelector-BFNqQGuG.js → RunAsSelector-DrGsUhL8.js} +2 -2
  117. package/dashboard/dist/assets/{RunAsSelector-BFNqQGuG.js.map → RunAsSelector-DrGsUhL8.js.map} +1 -1
  118. package/dashboard/dist/assets/{ScanCodesPage-D0GOdk5m.js → ScanCodesPage-BmQjEyWZ.js} +2 -2
  119. package/dashboard/dist/assets/{ScanCodesPage-D0GOdk5m.js.map → ScanCodesPage-BmQjEyWZ.js.map} +1 -1
  120. package/dashboard/dist/assets/ScanSchemeDetailPage-VODehqGs.js +2 -0
  121. package/dashboard/dist/assets/ScanSchemeDetailPage-VODehqGs.js.map +1 -0
  122. package/dashboard/dist/assets/{ScanStationPage-DH1ynTX9.js → ScanStationPage-Y-9Gs7t5.js} +2 -2
  123. package/dashboard/dist/assets/{ScanStationPage-DH1ynTX9.js.map → ScanStationPage-Y-9Gs7t5.js.map} +1 -1
  124. package/dashboard/dist/assets/{StickyPagination-B99hVu95.js → StickyPagination-9VkHiOsT.js} +2 -2
  125. package/dashboard/dist/assets/{StickyPagination-B99hVu95.js.map → StickyPagination-9VkHiOsT.js.map} +1 -1
  126. package/dashboard/dist/assets/{StreamMessageDetail-DcDGISrv.js → StreamMessageDetail-C37J6Qyz.js} +2 -2
  127. package/dashboard/dist/assets/{StreamMessageDetail-DcDGISrv.js.map → StreamMessageDetail-C37J6Qyz.js.map} +1 -1
  128. package/dashboard/dist/assets/{SwimlaneTimeline-BP3mSQAg.js → SwimlaneTimeline-NVGsBIX-.js} +2 -2
  129. package/dashboard/dist/assets/{SwimlaneTimeline-BP3mSQAg.js.map → SwimlaneTimeline-NVGsBIX-.js.map} +1 -1
  130. package/dashboard/dist/assets/{TaskDetailPage-_XWLJzt-.js → TaskDetailPage-5sbMHi5U.js} +2 -2
  131. package/dashboard/dist/assets/{TaskDetailPage-_XWLJzt-.js.map → TaskDetailPage-5sbMHi5U.js.map} +1 -1
  132. package/dashboard/dist/assets/{TasksListPage-iGriKiO2.js → TasksListPage-C9AN7IBb.js} +2 -2
  133. package/dashboard/dist/assets/{TasksListPage-iGriKiO2.js.map → TasksListPage-C9AN7IBb.js.map} +1 -1
  134. package/dashboard/dist/assets/{TimeAgo-BO33VeFl.js → TimeAgo-CsbQGlSd.js} +2 -2
  135. package/dashboard/dist/assets/{TimeAgo-BO33VeFl.js.map → TimeAgo-CsbQGlSd.js.map} +1 -1
  136. package/dashboard/dist/assets/{TimestampCell-KAjX7w35.js → TimestampCell-DlbIkV-G.js} +2 -2
  137. package/dashboard/dist/assets/{TimestampCell-KAjX7w35.js.map → TimestampCell-DlbIkV-G.js.map} +1 -1
  138. package/dashboard/dist/assets/{ToolTestPanel-BchG2yC6.js → ToolTestPanel-BKbLocvr.js} +2 -2
  139. package/dashboard/dist/assets/{ToolTestPanel-BchG2yC6.js.map → ToolTestPanel-BKbLocvr.js.map} +1 -1
  140. package/dashboard/dist/assets/{TopicDetailPage-BaK8H0o1.js → TopicDetailPage-fOnTfDso.js} +2 -2
  141. package/dashboard/dist/assets/{TopicDetailPage-BaK8H0o1.js.map → TopicDetailPage-fOnTfDso.js.map} +1 -1
  142. package/dashboard/dist/assets/{TopicsPage-DEyvm669.js → TopicsPage-BoVkp7DM.js} +2 -2
  143. package/dashboard/dist/assets/{TopicsPage-DEyvm669.js.map → TopicsPage-BoVkp7DM.js.map} +1 -1
  144. package/dashboard/dist/assets/{UserName-BV6SKI9P.js → UserName-0gjVPU_U.js} +2 -2
  145. package/dashboard/dist/assets/{UserName-BV6SKI9P.js.map → UserName-0gjVPU_U.js.map} +1 -1
  146. package/dashboard/dist/assets/{WorkflowExecutionPage-1sKoEFNC.js → WorkflowExecutionPage-B28OxTS_.js} +2 -2
  147. package/dashboard/dist/assets/{WorkflowExecutionPage-1sKoEFNC.js.map → WorkflowExecutionPage-B28OxTS_.js.map} +1 -1
  148. package/dashboard/dist/assets/{WorkflowsDashboard-YTHDZZOD.js → WorkflowsDashboard-Bzvz6tTY.js} +2 -2
  149. package/dashboard/dist/assets/{WorkflowsDashboard-YTHDZZOD.js.map → WorkflowsDashboard-Bzvz6tTY.js.map} +1 -1
  150. package/dashboard/dist/assets/{WorkflowsOverview-ucXPLTtm.js → WorkflowsOverview-BkcRU4Ej.js} +2 -2
  151. package/dashboard/dist/assets/{WorkflowsOverview-ucXPLTtm.js.map → WorkflowsOverview-BkcRU4Ej.js.map} +1 -1
  152. package/dashboard/dist/assets/{YamlWorkflowDetailPage-C_RTZKqZ.js → YamlWorkflowDetailPage-CmM78sYi.js} +2 -2
  153. package/dashboard/dist/assets/{YamlWorkflowDetailPage-C_RTZKqZ.js.map → YamlWorkflowDetailPage-CmM78sYi.js.map} +1 -1
  154. package/dashboard/dist/assets/{YamlWorkflowsPage-Usid3w2W.js → YamlWorkflowsPage-Dp6vG1au.js} +2 -2
  155. package/dashboard/dist/assets/{YamlWorkflowsPage-Usid3w2W.js.map → YamlWorkflowsPage-Dp6vG1au.js.map} +1 -1
  156. package/dashboard/dist/assets/{agents-BTDsRK8e.js → agents-MeqzOPD6.js} +2 -2
  157. package/dashboard/dist/assets/{agents-BTDsRK8e.js.map → agents-MeqzOPD6.js.map} +1 -1
  158. package/dashboard/dist/assets/{bots-DxLrfdfr.js → bots-DTGXnvX_.js} +2 -2
  159. package/dashboard/dist/assets/{bots-DxLrfdfr.js.map → bots-DTGXnvX_.js.map} +1 -1
  160. package/dashboard/dist/assets/{capabilities-DbTmeW-S.js → capabilities-BjlARR7F.js} +2 -2
  161. package/dashboard/dist/assets/{capabilities-DbTmeW-S.js.map → capabilities-BjlARR7F.js.map} +1 -1
  162. package/dashboard/dist/assets/{controlplane-CEBntAL4.js → controlplane-DMYI0OaL.js} +2 -2
  163. package/dashboard/dist/assets/{controlplane-CEBntAL4.js.map → controlplane-DMYI0OaL.js.map} +1 -1
  164. package/dashboard/dist/assets/{escalation-columns-Carqdwoh.js → escalation-columns-BMO_H3cb.js} +2 -2
  165. package/dashboard/dist/assets/{escalation-columns-Carqdwoh.js.map → escalation-columns-BMO_H3cb.js.map} +1 -1
  166. package/dashboard/dist/assets/{index-De8iV1y2.js → index-3QEnMBNG.js} +2 -2
  167. package/dashboard/dist/assets/{index-De8iV1y2.js.map → index-3QEnMBNG.js.map} +1 -1
  168. package/dashboard/dist/assets/{index-Bqm4zu46.js → index-B3FzpDEG.js} +2 -2
  169. package/dashboard/dist/assets/{index-Bqm4zu46.js.map → index-B3FzpDEG.js.map} +1 -1
  170. package/dashboard/dist/assets/{index-cFHoANSG.css → index-B5jxf81r.css} +1 -1
  171. package/dashboard/dist/assets/{index-DBXm49S6.js → index-BU4oujVO.js} +30 -29
  172. package/dashboard/dist/assets/index-BU4oujVO.js.map +1 -0
  173. package/dashboard/dist/assets/{index-kes8V4Xw.js → index-CGCD5hTX.js} +2 -2
  174. package/dashboard/dist/assets/{index-kes8V4Xw.js.map → index-CGCD5hTX.js.map} +1 -1
  175. package/dashboard/dist/assets/{index-BhapT-Vl.js → index-Ch-OS1pk.js} +2 -2
  176. package/dashboard/dist/assets/{index-BhapT-Vl.js.map → index-Ch-OS1pk.js.map} +1 -1
  177. package/dashboard/dist/assets/{index-B9m7fA3M.js → index-CkkOh8y9.js} +2 -2
  178. package/dashboard/dist/assets/{index-B9m7fA3M.js.map → index-CkkOh8y9.js.map} +1 -1
  179. package/dashboard/dist/assets/{index-B2hz0pUh.js → index-D3iDAWK2.js} +2 -2
  180. package/dashboard/dist/assets/{index-B2hz0pUh.js.map → index-D3iDAWK2.js.map} +1 -1
  181. package/dashboard/dist/assets/{index-C0hSttF5.js → index-D6kXz3H8.js} +2 -2
  182. package/dashboard/dist/assets/{index-C0hSttF5.js.map → index-D6kXz3H8.js.map} +1 -1
  183. package/dashboard/dist/assets/{index-CVBBkW8V.js → index-Dsgqxdyh.js} +2 -2
  184. package/dashboard/dist/assets/{index-CVBBkW8V.js.map → index-Dsgqxdyh.js.map} +1 -1
  185. package/dashboard/dist/assets/{index-nwLh3CK2.js → index-DuhqzYwC.js} +2 -2
  186. package/dashboard/dist/assets/{index-nwLh3CK2.js.map → index-DuhqzYwC.js.map} +1 -1
  187. package/dashboard/dist/assets/{index-CDkg6iOE.js → index-DuyzcDuV.js} +2 -2
  188. package/dashboard/dist/assets/{index-CDkg6iOE.js.map → index-DuyzcDuV.js.map} +1 -1
  189. package/dashboard/dist/assets/index-LF1gEc6w.js +3 -0
  190. package/dashboard/dist/assets/index-LF1gEc6w.js.map +1 -0
  191. package/dashboard/dist/assets/{index-CgIBjZta.js → index-k5vcLICm.js} +2 -2
  192. package/dashboard/dist/assets/{index-CgIBjZta.js.map → index-k5vcLICm.js.map} +1 -1
  193. package/dashboard/dist/assets/{knowledge-oFYAanUp.js → knowledge-DAV1Jy7b.js} +2 -2
  194. package/dashboard/dist/assets/{knowledge-oFYAanUp.js.map → knowledge-DAV1Jy7b.js.map} +1 -1
  195. package/dashboard/dist/assets/{mcp-C9Kw4Ow8.js → mcp-CivbxL1P.js} +2 -2
  196. package/dashboard/dist/assets/{mcp-C9Kw4Ow8.js.map → mcp-CivbxL1P.js.map} +1 -1
  197. package/dashboard/dist/assets/{mcp-query-BwzpZ91Z.js → mcp-query-CGvWNrgo.js} +2 -2
  198. package/dashboard/dist/assets/{mcp-query-BwzpZ91Z.js.map → mcp-query-CGvWNrgo.js.map} +1 -1
  199. package/dashboard/dist/assets/{personas-D5ehmtRb.js → personas-lI3aUr6t.js} +2 -2
  200. package/dashboard/dist/assets/{personas-D5ehmtRb.js.map → personas-lI3aUr6t.js.map} +1 -1
  201. package/dashboard/dist/assets/{pipelines-xgPKGEdD.js → pipelines-DjPfnTmx.js} +2 -2
  202. package/dashboard/dist/assets/{pipelines-xgPKGEdD.js.map → pipelines-DjPfnTmx.js.map} +1 -1
  203. package/dashboard/dist/assets/{tasks-CLyrl-MU.js → tasks-Co_S55BO.js} +2 -2
  204. package/dashboard/dist/assets/{tasks-CLyrl-MU.js.map → tasks-Co_S55BO.js.map} +1 -1
  205. package/dashboard/dist/assets/{topics-B_gO7CQ0.js → topics-2IGhZXBi.js} +2 -2
  206. package/dashboard/dist/assets/{topics-B_gO7CQ0.js.map → topics-2IGhZXBi.js.map} +1 -1
  207. package/dashboard/dist/assets/{useEventHooks-BdWYm63U.js → useEventHooks-D0C5yke4.js} +2 -2
  208. package/dashboard/dist/assets/{useEventHooks-BdWYm63U.js.map → useEventHooks-D0C5yke4.js.map} +1 -1
  209. package/dashboard/dist/assets/{useNamespace-C238M4Qn.js → useNamespace-LG52DTT-.js} +2 -2
  210. package/dashboard/dist/assets/{useNamespace-C238M4Qn.js.map → useNamespace-LG52DTT-.js.map} +1 -1
  211. package/dashboard/dist/assets/{useYamlActivityEvents-B2ryEK4S.js → useYamlActivityEvents-1IZGVpWC.js} +2 -2
  212. package/dashboard/dist/assets/{useYamlActivityEvents-B2ryEK4S.js.map → useYamlActivityEvents-1IZGVpWC.js.map} +1 -1
  213. package/dashboard/dist/assets/{users-BFaTe6Mt.js → users-C-eHT1i6.js} +2 -2
  214. package/dashboard/dist/assets/{users-BFaTe6Mt.js.map → users-C-eHT1i6.js.map} +1 -1
  215. package/dashboard/dist/assets/{workflows-DXz7tZxp.js → workflows-C16CeY4e.js} +2 -2
  216. package/dashboard/dist/assets/{workflows-DXz7tZxp.js.map → workflows-C16CeY4e.js.map} +1 -1
  217. package/dashboard/dist/assets/{yaml-workflows-u3xuRAnS.js → yaml-workflows-BBenayT9.js} +2 -2
  218. package/dashboard/dist/assets/{yaml-workflows-u3xuRAnS.js.map → yaml-workflows-BBenayT9.js.map} +1 -1
  219. package/dashboard/dist/index.html +2 -2
  220. package/docs/dashboard.md +15 -0
  221. package/docs/hitl/x-lt-footer.md +16 -4
  222. package/docs/hitl/x-lt-validation.md +23 -0
  223. package/docs/mcp.md +2 -0
  224. package/package.json +1 -1
  225. package/dashboard/dist/assets/AvailableEscalationsPage-DvWaiafI.js +0 -2
  226. package/dashboard/dist/assets/AvailableEscalationsPage-DvWaiafI.js.map +0 -1
  227. package/dashboard/dist/assets/CountdownTimer-By4rbMDN.js +0 -2
  228. package/dashboard/dist/assets/CountdownTimer-By4rbMDN.js.map +0 -1
  229. package/dashboard/dist/assets/CustomDurationPicker-8Ao-1pKA.js +0 -2
  230. package/dashboard/dist/assets/CustomDurationPicker-8Ao-1pKA.js.map +0 -1
  231. package/dashboard/dist/assets/ScanSchemeDetailPage-vFqoe_P4.js +0 -2
  232. package/dashboard/dist/assets/ScanSchemeDetailPage-vFqoe_P4.js.map +0 -1
  233. package/dashboard/dist/assets/index-DBXm49S6.js.map +0 -1
  234. package/dashboard/dist/assets/index-DsgjFRvA.js +0 -3
  235. package/dashboard/dist/assets/index-DsgjFRvA.js.map +0 -1
@@ -0,0 +1,22 @@
1
+ import type { LTApiResult, LTApiAuth } from '../types/sdk';
2
+ /**
3
+ * Dashboard announcements — broadcast notices on the dashboard surface.
4
+ * Publishing is a role-manager act (superadmin/admin/engineer via the route
5
+ * guard); reading is any authenticated user, server-filtered to their roles.
6
+ * Role targeting is display scoping only: the live event reaches every
7
+ * authenticated subscriber, so bodies must never carry secrets.
8
+ */
9
+ /** Create an announcement. Only `body` is required — everything else defaults. */
10
+ export declare function createAnnouncement(input: {
11
+ body?: string;
12
+ title?: string;
13
+ layout?: string;
14
+ roles?: string[];
15
+ expiresAt?: string;
16
+ }, auth: LTApiAuth): Promise<LTApiResult>;
17
+ /** Active announcements for the caller — admins see all, others their roles' slice. */
18
+ export declare function listAnnouncements(auth: LTApiAuth): Promise<LTApiResult>;
19
+ /** Remove an announcement; subscribers see it drop live. */
20
+ export declare function deleteAnnouncement(input: {
21
+ id: string;
22
+ }, _auth: LTApiAuth): Promise<LTApiResult>;
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.createAnnouncement = createAnnouncement;
37
+ exports.listAnnouncements = listAnnouncements;
38
+ exports.deleteAnnouncement = deleteAnnouncement;
39
+ const announcementService = __importStar(require("../services/announcement"));
40
+ const publish_1 = require("../lib/events/publish");
41
+ const user_1 = require("../services/user");
42
+ /**
43
+ * Dashboard announcements — broadcast notices on the dashboard surface.
44
+ * Publishing is a role-manager act (superadmin/admin/engineer via the route
45
+ * guard); reading is any authenticated user, server-filtered to their roles.
46
+ * Role targeting is display scoping only: the live event reaches every
47
+ * authenticated subscriber, so bodies must never carry secrets.
48
+ */
49
+ /** Create an announcement. Only `body` is required — everything else defaults. */
50
+ async function createAnnouncement(input, auth) {
51
+ try {
52
+ if (!input.body?.trim()) {
53
+ return { status: 400, error: 'body is required' };
54
+ }
55
+ const announcement = await announcementService.createAnnouncement({
56
+ body: input.body,
57
+ title: input.title,
58
+ layout: input.layout,
59
+ roles: input.roles,
60
+ expiresAt: input.expiresAt,
61
+ createdBy: auth.userId,
62
+ });
63
+ await (0, publish_1.publishAnnouncementEvent)({ type: 'announcement.created', announcement });
64
+ return { status: 200, data: announcement };
65
+ }
66
+ catch (err) {
67
+ return { status: 500, error: err.message };
68
+ }
69
+ }
70
+ /** Active announcements for the caller — admins see all, others their roles' slice. */
71
+ async function listAnnouncements(auth) {
72
+ try {
73
+ const unscoped = auth.role === 'superadmin' || auth.role === 'admin';
74
+ const roles = unscoped
75
+ ? null
76
+ : (await (0, user_1.getUserRoles)(auth.userId)).map((r) => r.role);
77
+ const announcements = await announcementService.listActiveAnnouncements(roles);
78
+ return { status: 200, data: { announcements } };
79
+ }
80
+ catch (err) {
81
+ return { status: 500, error: err.message };
82
+ }
83
+ }
84
+ /** Remove an announcement; subscribers see it drop live. */
85
+ async function deleteAnnouncement(input, _auth) {
86
+ try {
87
+ const deleted = await announcementService.deleteAnnouncement(input.id);
88
+ if (!deleted)
89
+ return { status: 404, error: 'announcement not found' };
90
+ await (0, publish_1.publishAnnouncementEvent)({ type: 'announcement.deleted', announcement: deleted });
91
+ return { status: 200, data: { deleted: true, id: input.id } };
92
+ }
93
+ catch (err) {
94
+ return { status: 500, error: err.message };
95
+ }
96
+ }
@@ -11,6 +11,14 @@ export interface FacetInput {
11
11
  /** Only rows past their role's priority threshold — see FacetQuery.jeopardy. */
12
12
  jeopardy?: boolean;
13
13
  orderBy?: FacetOrder[];
14
+ /**
15
+ * List rows omit the two heavyweight JSON columns (`envelope`,
16
+ * `escalation_payload`) by default — at scale they dominate the payload.
17
+ * Pass `'envelope'` to restore both (list schemas interpolating
18
+ * `{{envelope.*}}`/`{{payload.*}}` need them). The single-item GET always
19
+ * carries the full record.
20
+ */
21
+ include?: string;
14
22
  }
15
23
  /**
16
24
  * List escalations with optional filters.
@@ -42,6 +42,16 @@ exports.getStationMetrics = getStationMetrics;
42
42
  const escalationService = __importStar(require("../../services/escalation"));
43
43
  const features_1 = require("../../modules/features");
44
44
  const helpers_1 = require("./helpers");
45
+ /** Strip the heavyweight JSON columns from list rows unless asked back. */
46
+ function projectListRows(rows, include) {
47
+ if (include === 'envelope')
48
+ return rows;
49
+ return rows.map(({ envelope: _e, escalation_payload: _p, ...rest }) => rest);
50
+ }
51
+ /** Apply the list projection to a { escalations, ... } service result. */
52
+ function projectListResult(result, include) {
53
+ return { ...result, escalations: projectListRows(result.escalations, include) };
54
+ }
45
55
  /** True when the caller asked for anything the plain list path can't express. */
46
56
  function hasFacetQuery(i) {
47
57
  return !!(i.facets ||
@@ -107,7 +117,7 @@ async function listEscalations(input, auth) {
107
117
  limit: input.limit ?? 50,
108
118
  offset: input.offset ?? 0,
109
119
  });
110
- return { status: 200, data: result };
120
+ return { status: 200, data: projectListResult(result, input.include) };
111
121
  }
112
122
  const result = await escalationService.listEscalations({
113
123
  status: input.status,
@@ -127,7 +137,7 @@ async function listEscalations(input, auth) {
127
137
  selfRoles: scope.global ? undefined : scope.selfRoles,
128
138
  meUserId: auth.userId,
129
139
  });
130
- return { status: 200, data: result };
140
+ return { status: 200, data: projectListResult(result, input.include) };
131
141
  }
132
142
  catch (err) {
133
143
  return { status: 500, error: err.message };
@@ -182,7 +192,7 @@ async function listAvailableEscalations(input, auth) {
182
192
  limit: input.limit ?? 50,
183
193
  offset: input.offset ?? 0,
184
194
  });
185
- return { status: 200, data: result };
195
+ return { status: 200, data: projectListResult(result, input.include) };
186
196
  }
187
197
  const result = await escalationService.listAvailableEscalations({
188
198
  role: input.role,
@@ -198,7 +208,7 @@ async function listAvailableEscalations(input, auth) {
198
208
  selfRoles: scope.global ? undefined : scope.selfRoles,
199
209
  meUserId: auth.userId,
200
210
  });
201
- return { status: 200, data: result };
211
+ return { status: 200, data: projectListResult(result, input.include) };
202
212
  }
203
213
  catch (err) {
204
214
  return { status: 500, error: err.message };
@@ -18,3 +18,4 @@ export * as workflowSets from './workflow-sets';
18
18
  export * as dba from './dba';
19
19
  export * as namespaces from './namespaces';
20
20
  export * as maintenance from './maintenance';
21
+ export * as announcements from './announcements';
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.maintenance = exports.namespaces = exports.dba = exports.workflowSets = exports.botAccounts = exports.controlplane = exports.exports = exports.settings = exports.insight = exports.mcpRuns = exports.pipelines = exports.mcp = exports.auth = exports.personas = exports.roles = exports.users = exports.yamlWorkflows = exports.workflows = exports.escalations = exports.tasks = void 0;
36
+ exports.announcements = exports.maintenance = exports.namespaces = exports.dba = exports.workflowSets = exports.botAccounts = exports.controlplane = exports.exports = exports.settings = exports.insight = exports.mcpRuns = exports.pipelines = exports.mcp = exports.auth = exports.personas = exports.roles = exports.users = exports.yamlWorkflows = exports.workflows = exports.escalations = exports.tasks = void 0;
37
37
  exports.tasks = __importStar(require("./tasks"));
38
38
  exports.escalations = __importStar(require("./escalations"));
39
39
  exports.workflows = __importStar(require("./workflows"));
@@ -54,3 +54,4 @@ exports.workflowSets = __importStar(require("./workflow-sets"));
54
54
  exports.dba = __importStar(require("./dba"));
55
55
  exports.namespaces = __importStar(require("./namespaces"));
56
56
  exports.maintenance = __importStar(require("./maintenance"));
57
+ exports.announcements = __importStar(require("./announcements"));
@@ -55,6 +55,7 @@ export declare function upsertWorkflowConfig(input: {
55
55
  envelope_schema?: any;
56
56
  resolver_schema?: any;
57
57
  cron_schedule?: string | null;
58
+ read_safe?: boolean;
58
59
  }): Promise<LTApiResult>;
59
60
  /**
60
61
  * Delete a workflow configuration.
@@ -120,6 +120,7 @@ async function upsertWorkflowConfig(input) {
120
120
  envelope_schema: input.envelope_schema ?? null,
121
121
  resolver_schema: input.resolver_schema ?? null,
122
122
  cron_schedule: input.cron_schedule ?? null,
123
+ read_safe: input.read_safe ?? false,
123
124
  });
124
125
  ltconfig_1.ltConfig.invalidate();
125
126
  await cron_1.cronRegistry.restartCron(config);
@@ -113,6 +113,7 @@ async function listDiscoveredWorkflows(input) {
113
113
  registered: !!config,
114
114
  active: !!worker,
115
115
  invocable: config?.invocable ?? !!worker,
116
+ read_safe: config?.read_safe ?? false,
116
117
  system: registry_1.SYSTEM_WORKFLOWS.has(workflowType),
117
118
  description: config?.description ?? null,
118
119
  roles: config?.roles ?? [],
@@ -0,0 +1,30 @@
1
+ -- Migration 031: Dashboard announcements
2
+ --
3
+ -- Broadcast notices for the dashboard surface (system.surfaces.dashboard).
4
+ -- Role targeting is display scoping only — live events reach every
5
+ -- authenticated socket, so a body must never carry secrets. Rows expire by
6
+ -- timestamp; dismissal is per-browser on the client.
7
+
8
+ CREATE TABLE IF NOT EXISTS lt_announcements (
9
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
10
+ title TEXT,
11
+ body TEXT NOT NULL,
12
+ layout TEXT NOT NULL DEFAULT 'banner',
13
+ roles TEXT[] NOT NULL DEFAULT '{}',
14
+ created_by TEXT,
15
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
16
+ expires_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + INTERVAL '24 hours'
17
+ );
18
+
19
+ CREATE INDEX IF NOT EXISTS idx_lt_announcements_expires ON lt_announcements (expires_at);
20
+
21
+ -- The announcement topic (system.surfaces.dashboard) introduces the
22
+ -- 'surfaces' category to the topic catalog.
23
+ ALTER TABLE lt_topic_catalog
24
+ DROP CONSTRAINT IF EXISTS lt_topic_catalog_category_check;
25
+
26
+ ALTER TABLE lt_topic_catalog
27
+ ADD CONSTRAINT lt_topic_catalog_category_check
28
+ CHECK (category IN (
29
+ 'task','workflow','escalation','activity','knowledge','file','agent','app','milestone','surfaces'
30
+ ));
@@ -0,0 +1,9 @@
1
+ -- Migration 032: read-safe workflow flag
2
+ --
3
+ -- Marks a workflow as side-effect-free for external MCP callers: the
4
+ -- invoke_workflow_read_safe tool (manifest read_safe: true) starts only
5
+ -- workflows carrying this flag, extending the tool-manifest read-scope
6
+ -- contract to workflow invocation. Fail-closed: unset means not read-safe.
7
+
8
+ ALTER TABLE lt_config_workflows
9
+ ADD COLUMN IF NOT EXISTS read_safe BOOLEAN NOT NULL DEFAULT false;
@@ -64,6 +64,21 @@ export declare function publishActivityEvent(params: {
64
64
  activityName: string;
65
65
  data?: Record<string, any>;
66
66
  }): Promise<void>;
67
+ /**
68
+ * The dashboard-surface broadcast subject. Announcements publish here and the
69
+ * dashboard subscribes; the payload is the announcement row (small by
70
+ * nature). Delivery reaches every authenticated socket — role targeting is
71
+ * display scoping, never confidentiality.
72
+ */
73
+ export declare const ANNOUNCEMENT_TOPIC = "system.surfaces.dashboard";
74
+ /**
75
+ * Publish a dashboard announcement event.
76
+ * Subject: system.surfaces.dashboard (fixed — one surface, one channel)
77
+ */
78
+ export declare function publishAnnouncementEvent(params: {
79
+ type: 'announcement.created' | 'announcement.deleted';
80
+ announcement: Record<string, any>;
81
+ }): Promise<void>;
67
82
  /**
68
83
  * Publish a knowledge lifecycle event.
69
84
  * Subject: system.knowledge.{domain}.{action}
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ANNOUNCEMENT_TOPIC = void 0;
3
4
  exports.publishMilestoneEvent = publishMilestoneEvent;
4
5
  exports.publishTaskEvent = publishTaskEvent;
5
6
  exports.publishEscalationEvent = publishEscalationEvent;
6
7
  exports.publishActivityEvent = publishActivityEvent;
8
+ exports.publishAnnouncementEvent = publishAnnouncementEvent;
7
9
  exports.publishKnowledgeEvent = publishKnowledgeEvent;
8
10
  exports.publishFileEvent = publishFileEvent;
9
11
  exports.publishAgentEvent = publishAgentEvent;
@@ -104,6 +106,26 @@ function publishActivityEvent(params) {
104
106
  timestamp: new Date().toISOString(),
105
107
  });
106
108
  }
109
+ /**
110
+ * The dashboard-surface broadcast subject. Announcements publish here and the
111
+ * dashboard subscribes; the payload is the announcement row (small by
112
+ * nature). Delivery reaches every authenticated socket — role targeting is
113
+ * display scoping, never confidentiality.
114
+ */
115
+ exports.ANNOUNCEMENT_TOPIC = 'system.surfaces.dashboard';
116
+ /**
117
+ * Publish a dashboard announcement event.
118
+ * Subject: system.surfaces.dashboard (fixed — one surface, one channel)
119
+ */
120
+ function publishAnnouncementEvent(params) {
121
+ const action = params.type.split('.')[1];
122
+ return fireAndForget({
123
+ type: exports.ANNOUNCEMENT_TOPIC,
124
+ source: 'announcement',
125
+ data: { action, announcement: params.announcement },
126
+ timestamp: new Date().toISOString(),
127
+ });
128
+ }
107
129
  /**
108
130
  * Publish a knowledge lifecycle event.
109
131
  * Subject: system.knowledge.{domain}.{action}
@@ -0,0 +1,2 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const express_1 = require("express");
37
+ const api = __importStar(require("../api/announcements"));
38
+ const auth_1 = require("../modules/auth");
39
+ const router = (0, express_1.Router)();
40
+ /**
41
+ * Dashboard announcements. Publishing and removal are role-manager acts
42
+ * (superadmin, admin type, or engineer); any authenticated user reads their
43
+ * role-filtered slice. Targeting is display scoping — the live event
44
+ * broadcasts to every authenticated subscriber.
45
+ */
46
+ router.get('/', async (req, res) => {
47
+ const result = await api.listAnnouncements(req.auth);
48
+ res.status(result.status).json(result.data ?? { error: result.error });
49
+ });
50
+ router.post('/', auth_1.requireRoleManager, async (req, res) => {
51
+ const result = await api.createAnnouncement({
52
+ body: req.body?.body,
53
+ title: req.body?.title,
54
+ layout: req.body?.layout,
55
+ roles: req.body?.roles,
56
+ expiresAt: req.body?.expiresAt,
57
+ }, req.auth);
58
+ res.status(result.status).json(result.data ?? { error: result.error });
59
+ });
60
+ router.delete('/:id', auth_1.requireRoleManager, async (req, res) => {
61
+ const result = await api.deleteAnnouncement({ id: String(req.params.id) }, req.auth);
62
+ res.status(result.status).json(result.data ?? { error: result.error });
63
+ });
64
+ exports.default = router;
@@ -109,6 +109,7 @@ function registerListRoutes(router) {
109
109
  orderBy: jsonParam(req.query.orderBy),
110
110
  available: req.query.available != null ? req.query.available === 'true' : undefined,
111
111
  jeopardy: req.query.jeopardy === '1' || req.query.jeopardy === 'true' || undefined,
112
+ include: req.query.include,
112
113
  }, req.auth);
113
114
  res.status(result.status).json(result.data ?? { error: result.error });
114
115
  });
@@ -136,6 +137,7 @@ function registerListRoutes(router) {
136
137
  exists: jsonParam(req.query.exists),
137
138
  orderBy: jsonParam(req.query.orderBy),
138
139
  jeopardy: req.query.jeopardy === '1' || req.query.jeopardy === 'true' || undefined,
140
+ include: req.query.include,
139
141
  }, req.auth);
140
142
  res.status(result.status).json(result.data ?? { error: result.error });
141
143
  });
@@ -38,6 +38,7 @@ const topics_1 = __importDefault(require("./topics"));
38
38
  const nats_credentials_1 = __importDefault(require("./nats-credentials"));
39
39
  const scan_codes_1 = __importDefault(require("./scan-codes"));
40
40
  const domain_1 = __importDefault(require("./domain"));
41
+ const announcements_1 = __importDefault(require("./announcements"));
41
42
  const router = (0, express_1.Router)();
42
43
  // Public routes (no auth required — they handle their own auth)
43
44
  router.use('/auth', auth_2.default);
@@ -76,6 +77,7 @@ router.use('/capabilities', capabilities_1.default);
76
77
  router.use('/topics', topics_1.default);
77
78
  router.use('/scan-codes', scan_codes_1.default);
78
79
  router.use('/domain', domain_1.default);
80
+ router.use('/announcements', announcements_1.default);
79
81
  const overview_1 = __importDefault(require("./overview"));
80
82
  router.use('/overview', overview_1.default);
81
83
  const diagnostics_1 = __importDefault(require("./diagnostics"));
@@ -0,0 +1,30 @@
1
+ /**
2
+ * A dashboard announcement — a broadcast notice on the dashboard surface.
3
+ * Role targeting is display scoping only (live events reach every
4
+ * authenticated socket); bodies must never carry secrets.
5
+ */
6
+ export interface LTAnnouncement {
7
+ id: string;
8
+ title: string | null;
9
+ /** Markdown. */
10
+ body: string;
11
+ layout: string;
12
+ /** Empty = everyone; otherwise shown to holders of any named role. */
13
+ roles: string[];
14
+ created_by: string | null;
15
+ created_at: string;
16
+ expires_at: string;
17
+ }
18
+ /** Only the body is required; everything else has a liberal default (24h expiry). */
19
+ export declare function createAnnouncement(input: {
20
+ body: string;
21
+ title?: string;
22
+ layout?: string;
23
+ roles?: string[];
24
+ createdBy?: string;
25
+ expiresAt?: string;
26
+ }): Promise<LTAnnouncement>;
27
+ /** Active announcements visible to a viewer; null roles = the unscoped admin view. */
28
+ export declare function listActiveAnnouncements(userRoles: string[] | null): Promise<LTAnnouncement[]>;
29
+ /** Returns the deleted row so the caller can publish its removal, or null. */
30
+ export declare function deleteAnnouncement(id: string): Promise<LTAnnouncement | null>;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAnnouncement = createAnnouncement;
4
+ exports.listActiveAnnouncements = listActiveAnnouncements;
5
+ exports.deleteAnnouncement = deleteAnnouncement;
6
+ const db_1 = require("../../lib/db");
7
+ const sql_1 = require("./sql");
8
+ /** Only the body is required; everything else has a liberal default (24h expiry). */
9
+ async function createAnnouncement(input) {
10
+ const { rows } = await (0, db_1.getPool)().query(sql_1.INSERT_ANNOUNCEMENT, [
11
+ input.title ?? null,
12
+ input.body,
13
+ input.layout ?? null,
14
+ input.roles ?? null,
15
+ input.createdBy ?? null,
16
+ input.expiresAt ?? null,
17
+ ]);
18
+ return rows[0];
19
+ }
20
+ /** Active announcements visible to a viewer; null roles = the unscoped admin view. */
21
+ async function listActiveAnnouncements(userRoles) {
22
+ const { rows } = await (0, db_1.getPool)().query(sql_1.LIST_ACTIVE_ANNOUNCEMENTS, [userRoles]);
23
+ return rows;
24
+ }
25
+ /** Returns the deleted row so the caller can publish its removal, or null. */
26
+ async function deleteAnnouncement(id) {
27
+ const { rows } = await (0, db_1.getPool)().query(sql_1.DELETE_ANNOUNCEMENT, [id]);
28
+ return rows[0] ?? null;
29
+ }
@@ -0,0 +1,8 @@
1
+ export declare const INSERT_ANNOUNCEMENT = "\n INSERT INTO lt_announcements (title, body, layout, roles, created_by, expires_at)\n VALUES ($1, $2, COALESCE($3, 'banner'), COALESCE($4::text[], '{}'), $5,\n COALESCE($6::timestamptz, NOW() + INTERVAL '24 hours'))\n RETURNING *";
2
+ /**
3
+ * Active announcements for a viewer. $1 = the viewer's role names, or NULL
4
+ * for the unscoped admin view. Untargeted rows (roles = '{}') reach everyone;
5
+ * targeted rows reach holders of any named role.
6
+ */
7
+ export declare const LIST_ACTIVE_ANNOUNCEMENTS = "\n SELECT * FROM lt_announcements\n WHERE expires_at > NOW()\n AND ($1::text[] IS NULL OR roles = '{}' OR roles && $1::text[])\n ORDER BY created_at DESC";
8
+ export declare const DELETE_ANNOUNCEMENT = "\n DELETE FROM lt_announcements WHERE id = $1\n RETURNING *";
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ // ─── Announcement queries ────────────────────────────────────────────────────
3
+ // Liberal defaults live in the SQL so the service contract is self-describing:
4
+ // only the body is required; layout, targeting, and the 24-hour expiry fill in.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DELETE_ANNOUNCEMENT = exports.LIST_ACTIVE_ANNOUNCEMENTS = exports.INSERT_ANNOUNCEMENT = void 0;
7
+ exports.INSERT_ANNOUNCEMENT = `
8
+ INSERT INTO lt_announcements (title, body, layout, roles, created_by, expires_at)
9
+ VALUES ($1, $2, COALESCE($3, 'banner'), COALESCE($4::text[], '{}'), $5,
10
+ COALESCE($6::timestamptz, NOW() + INTERVAL '24 hours'))
11
+ RETURNING *`;
12
+ /**
13
+ * Active announcements for a viewer. $1 = the viewer's role names, or NULL
14
+ * for the unscoped admin view. Untargeted rows (roles = '{}') reach everyone;
15
+ * targeted rows reach holders of any named role.
16
+ */
17
+ exports.LIST_ACTIVE_ANNOUNCEMENTS = `
18
+ SELECT * FROM lt_announcements
19
+ WHERE expires_at > NOW()
20
+ AND ($1::text[] IS NULL OR roles = '{}' OR roles && $1::text[])
21
+ ORDER BY created_at DESC`;
22
+ exports.DELETE_ANNOUNCEMENT = `
23
+ DELETE FROM lt_announcements WHERE id = $1
24
+ RETURNING *`;
@@ -19,6 +19,7 @@ async function loadAllConfigs() {
19
19
  resolverSchema: c.resolver_schema ?? null,
20
20
  cronSchedule: c.cron_schedule ?? null,
21
21
  executeAs: c.execute_as ?? null,
22
+ readSafe: c.read_safe ?? false,
22
23
  });
23
24
  }
24
25
  return map;
@@ -29,6 +29,7 @@ async function getWorkflowConfig(workflowType) {
29
29
  resolver_schema: wf.resolver_schema ?? null,
30
30
  cron_schedule: wf.cron_schedule ?? null,
31
31
  execute_as: wf.execute_as ?? null,
32
+ read_safe: wf.read_safe ?? false,
32
33
  };
33
34
  }
34
35
  async function listWorkflowConfigs() {
@@ -66,5 +67,6 @@ async function listWorkflowConfigs() {
66
67
  resolver_schema: wf.resolver_schema ?? null,
67
68
  cron_schedule: wf.cron_schedule ?? null,
68
69
  execute_as: wf.execute_as ?? null,
70
+ read_safe: wf.read_safe ?? false,
69
71
  }));
70
72
  }
@@ -5,13 +5,13 @@ export declare const LIST_ALL_WORKFLOWS = "SELECT * FROM lt_config_workflows ORD
5
5
  export declare const LIST_ALL_ROLES = "SELECT * FROM lt_config_roles ORDER BY workflow_type, role";
6
6
  export declare const LIST_ALL_INVOCATION_ROLES = "SELECT * FROM lt_config_invocation_roles ORDER BY workflow_type, role";
7
7
  export declare const ENSURE_ROLE_EXISTS = "INSERT INTO lt_roles (role) VALUES ($1) ON CONFLICT DO NOTHING";
8
- export declare const UPSERT_WORKFLOW = "INSERT INTO lt_config_workflows\n (workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)\nON CONFLICT (workflow_type) DO UPDATE SET\n invocable = EXCLUDED.invocable,\n task_queue = EXCLUDED.task_queue,\n default_role = EXCLUDED.default_role,\n description = EXCLUDED.description,\n consumes = EXCLUDED.consumes,\n envelope_schema = EXCLUDED.envelope_schema,\n resolver_schema = EXCLUDED.resolver_schema,\n cron_schedule = EXCLUDED.cron_schedule,\n tool_tags = EXCLUDED.tool_tags,\n execute_as = EXCLUDED.execute_as,\n certified = EXCLUDED.certified";
8
+ export declare const UPSERT_WORKFLOW = "INSERT INTO lt_config_workflows\n (workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified, read_safe)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)\nON CONFLICT (workflow_type) DO UPDATE SET\n invocable = EXCLUDED.invocable,\n task_queue = EXCLUDED.task_queue,\n default_role = EXCLUDED.default_role,\n description = EXCLUDED.description,\n consumes = EXCLUDED.consumes,\n envelope_schema = EXCLUDED.envelope_schema,\n resolver_schema = EXCLUDED.resolver_schema,\n cron_schedule = EXCLUDED.cron_schedule,\n tool_tags = EXCLUDED.tool_tags,\n execute_as = EXCLUDED.execute_as,\n certified = EXCLUDED.certified,\n read_safe = EXCLUDED.read_safe";
9
9
  export declare const DELETE_CONFIG_ROLES = "DELETE FROM lt_config_roles WHERE workflow_type = $1";
10
10
  export declare const INSERT_CONFIG_ROLE = "INSERT INTO lt_config_roles (workflow_type, role) VALUES ($1, $2)";
11
11
  export declare const DELETE_INVOCATION_ROLES = "DELETE FROM lt_config_invocation_roles WHERE workflow_type = $1";
12
12
  export declare const INSERT_INVOCATION_ROLE = "INSERT INTO lt_config_invocation_roles (workflow_type, role) VALUES ($1, $2)";
13
13
  export declare const DELETE_WORKFLOW = "DELETE FROM lt_config_workflows WHERE workflow_type = $1";
14
- export declare const SEED_WORKFLOW_CONFIG = "INSERT INTO lt_config_workflows\n (workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)\nON CONFLICT (workflow_type) DO NOTHING";
14
+ export declare const SEED_WORKFLOW_CONFIG = "INSERT INTO lt_config_workflows\n (workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified, read_safe)\nVALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)\nON CONFLICT (workflow_type) DO NOTHING";
15
15
  export declare const SEED_CONFIG_ROLE = "INSERT INTO lt_config_roles (workflow_type, role) VALUES ($1, $2)\nON CONFLICT (workflow_type, role) DO NOTHING";
16
16
  export declare const SEED_INVOCATION_ROLE = "INSERT INTO lt_config_invocation_roles (workflow_type, role) VALUES ($1, $2)\nON CONFLICT (workflow_type, role) DO NOTHING";
17
17
  export declare const GET_PROVIDER_DATA = "SELECT workflow_type, data, completed_at\n FROM lt_tasks\n WHERE origin_id = $1\n AND workflow_type = ANY($2)\n AND status = 'completed'\n ORDER BY completed_at DESC";
@@ -23,8 +23,8 @@ exports.ENSURE_ROLE_EXISTS = `\
23
23
  INSERT INTO lt_roles (role) VALUES ($1) ON CONFLICT DO NOTHING`;
24
24
  exports.UPSERT_WORKFLOW = `\
25
25
  INSERT INTO lt_config_workflows
26
- (workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified)
27
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
26
+ (workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified, read_safe)
27
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
28
28
  ON CONFLICT (workflow_type) DO UPDATE SET
29
29
  invocable = EXCLUDED.invocable,
30
30
  task_queue = EXCLUDED.task_queue,
@@ -36,7 +36,8 @@ ON CONFLICT (workflow_type) DO UPDATE SET
36
36
  cron_schedule = EXCLUDED.cron_schedule,
37
37
  tool_tags = EXCLUDED.tool_tags,
38
38
  execute_as = EXCLUDED.execute_as,
39
- certified = EXCLUDED.certified`;
39
+ certified = EXCLUDED.certified,
40
+ read_safe = EXCLUDED.read_safe`;
40
41
  exports.DELETE_CONFIG_ROLES = `\
41
42
  DELETE FROM lt_config_roles WHERE workflow_type = $1`;
42
43
  exports.INSERT_CONFIG_ROLE = `\
@@ -52,8 +53,8 @@ DELETE FROM lt_config_workflows WHERE workflow_type = $1`;
52
53
  // ------------------------------------------------------------------ //
53
54
  exports.SEED_WORKFLOW_CONFIG = `\
54
55
  INSERT INTO lt_config_workflows
55
- (workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified)
56
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
56
+ (workflow_type, invocable, task_queue, default_role, description, consumes, envelope_schema, resolver_schema, cron_schedule, tool_tags, execute_as, certified, read_safe)
57
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
57
58
  ON CONFLICT (workflow_type) DO NOTHING`;
58
59
  exports.SEED_CONFIG_ROLE = `\
59
60
  INSERT INTO lt_config_roles (workflow_type, role) VALUES ($1, $2)
@@ -52,6 +52,7 @@ async function replaceWorkflowConfig(config, certified) {
52
52
  config.tool_tags || [],
53
53
  config.execute_as ?? null,
54
54
  certified,
55
+ config.read_safe ?? false,
55
56
  ]);
56
57
  // Replace roles
57
58
  await client.query(sql_1.DELETE_CONFIG_ROLES, [config.workflow_type]);
@@ -112,6 +113,7 @@ async function seedWorkflowConfig(config) {
112
113
  config.tool_tags || [],
113
114
  config.execute_as ?? null,
114
115
  resolveCertified(config),
116
+ config.read_safe ?? false,
115
117
  ]);
116
118
  const inserted = (rowCount ?? 0) > 0;
117
119
  if (inserted) {
@@ -134,6 +136,8 @@ async function seedWorkflowConfig(config) {
134
136
  drifts.push('invocable');
135
137
  if (resolveCertified(config) !== existing.certified)
136
138
  drifts.push('certified');
139
+ if ((config.read_safe ?? false) !== (existing.read_safe ?? false))
140
+ drifts.push('read_safe');
137
141
  if (config.default_role !== existing.default_role)
138
142
  drifts.push('default_role');
139
143
  if (JSON.stringify(config.envelope_schema) !== JSON.stringify(existing.envelope_schema))
@@ -169,6 +173,7 @@ async function applyWorkflowConfig(config) {
169
173
  existing.default_role === config.default_role &&
170
174
  (existing.description ?? null) === (config.description ?? null) &&
171
175
  existing.certified === certified &&
176
+ (existing.read_safe ?? false) === (config.read_safe ?? false) &&
172
177
  (existing.cron_schedule ?? null) === (config.cron_schedule ?? null) &&
173
178
  (existing.execute_as ?? null) === (config.execute_as ?? null) &&
174
179
  sortedEqual(existing.consumes ?? [], config.consumes ?? []) &&