@hotmeshio/long-tail 0.10.7 → 0.10.9

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 (224) hide show
  1. package/build/api/escalations/bulk.js +7 -1
  2. package/build/api/escalations/helpers.d.ts +10 -1
  3. package/build/api/escalations/helpers.js +52 -12
  4. package/build/lib/events/matching.d.ts +10 -0
  5. package/build/lib/events/matching.js +14 -0
  6. package/build/lib/events/publish.d.ts +8 -2
  7. package/build/lib/events/publish.js +9 -2
  8. package/build/lib/events/socketio.d.ts +8 -2
  9. package/build/lib/events/socketio.js +36 -3
  10. package/build/lib/events/system-events.js +9 -1
  11. package/build/services/escalation/crud.js +40 -2
  12. package/build/services/orchestrator/condition.d.ts +1 -1
  13. package/build/services/orchestrator/condition.js +1 -1
  14. package/build/services/topics/system-topics.d.ts +0 -4
  15. package/build/services/topics/system-topics.js +57 -14
  16. package/build/types/events.d.ts +11 -3
  17. package/build/types/index.d.ts +1 -1
  18. package/dashboard/dist/assets/{AdminDashboard-CYlm0_J0.js → AdminDashboard-DWSYdAeW.js} +2 -2
  19. package/dashboard/dist/assets/{AdminDashboard-CYlm0_J0.js.map → AdminDashboard-DWSYdAeW.js.map} +1 -1
  20. package/dashboard/dist/assets/{AgentConfigPage-BttOMcj_.js → AgentConfigPage-Dm6gL76m.js} +2 -2
  21. package/dashboard/dist/assets/{AgentConfigPage-BttOMcj_.js.map → AgentConfigPage-Dm6gL76m.js.map} +1 -1
  22. package/dashboard/dist/assets/{AgentDetailPage-D9JdkWV8.js → AgentDetailPage-D-Xbyrb6.js} +3 -3
  23. package/dashboard/dist/assets/AgentDetailPage-D-Xbyrb6.js.map +1 -0
  24. package/dashboard/dist/assets/{AgentsPage-AqGtEOL1.js → AgentsPage-DKaDRk-Y.js} +2 -2
  25. package/dashboard/dist/assets/{AgentsPage-AqGtEOL1.js.map → AgentsPage-DKaDRk-Y.js.map} +1 -1
  26. package/dashboard/dist/assets/{AvailableEscalationsPage-rKbrcY8Y.js → AvailableEscalationsPage-B-aHvGKD.js} +2 -2
  27. package/dashboard/dist/assets/AvailableEscalationsPage-B-aHvGKD.js.map +1 -0
  28. package/dashboard/dist/assets/{BotPicker-Bj4MB_so.js → BotPicker-DRv_orzI.js} +2 -2
  29. package/dashboard/dist/assets/{BotPicker-Bj4MB_so.js.map → BotPicker-DRv_orzI.js.map} +1 -1
  30. package/dashboard/dist/assets/{CapabilitiesPage-DzLP5-ad.js → CapabilitiesPage-DqRVzMol.js} +2 -2
  31. package/dashboard/dist/assets/{CapabilitiesPage-DzLP5-ad.js.map → CapabilitiesPage-DqRVzMol.js.map} +1 -1
  32. package/dashboard/dist/assets/{CollapsibleSection-CReMhtzK.js → CollapsibleSection-D0psvw8i.js} +2 -2
  33. package/dashboard/dist/assets/{CollapsibleSection-CReMhtzK.js.map → CollapsibleSection-D0psvw8i.js.map} +1 -1
  34. package/dashboard/dist/assets/CountdownTimer-BhF3oqS8.js +2 -0
  35. package/dashboard/dist/assets/CountdownTimer-BhF3oqS8.js.map +1 -0
  36. package/dashboard/dist/assets/{CredentialsPage-D_2T6vSb.js → CredentialsPage-Axdci1z-.js} +2 -2
  37. package/dashboard/dist/assets/{CredentialsPage-D_2T6vSb.js.map → CredentialsPage-Axdci1z-.js.map} +1 -1
  38. package/dashboard/dist/assets/{CronLabel-DBmKrLvL.js → CronLabel-BjZ_wZA8.js} +2 -2
  39. package/dashboard/dist/assets/{CronLabel-DBmKrLvL.js.map → CronLabel-BjZ_wZA8.js.map} +1 -1
  40. package/dashboard/dist/assets/CustomDurationPicker-CkUCMUfk.js +2 -0
  41. package/dashboard/dist/assets/CustomDurationPicker-CkUCMUfk.js.map +1 -0
  42. package/dashboard/dist/assets/{DropZone-BrnAkQxF.js → DropZone-_tmC3jEe.js} +2 -2
  43. package/dashboard/dist/assets/{DropZone-BrnAkQxF.js.map → DropZone-_tmC3jEe.js.map} +1 -1
  44. package/dashboard/dist/assets/{ElapsedCell-C0LbM8o2.js → ElapsedCell-BE_CN5sP.js} +2 -2
  45. package/dashboard/dist/assets/{ElapsedCell-C0LbM8o2.js.map → ElapsedCell-BE_CN5sP.js.map} +1 -1
  46. package/dashboard/dist/assets/{EscalationListSchemaPage-CkEJnFKd.js → EscalationListSchemaPage-CgcVIiYR.js} +3 -3
  47. package/dashboard/dist/assets/{EscalationListSchemaPage-CkEJnFKd.js.map → EscalationListSchemaPage-CgcVIiYR.js.map} +1 -1
  48. package/dashboard/dist/assets/{EscalationSchemaPage-CnlwGAIE.js → EscalationSchemaPage-BaAn1Hcr.js} +3 -3
  49. package/dashboard/dist/assets/{EscalationSchemaPage-CnlwGAIE.js.map → EscalationSchemaPage-BaAn1Hcr.js.map} +1 -1
  50. package/dashboard/dist/assets/{EscalationsOverview-DFM-f7do.js → EscalationsOverview-Dbq7tKzr.js} +2 -2
  51. package/dashboard/dist/assets/{EscalationsOverview-DFM-f7do.js.map → EscalationsOverview-Dbq7tKzr.js.map} +1 -1
  52. package/dashboard/dist/assets/{EventTable-Q3iICRf_.js → EventTable-0RUK9jqt.js} +2 -2
  53. package/dashboard/dist/assets/{EventTable-Q3iICRf_.js.map → EventTable-0RUK9jqt.js.map} +1 -1
  54. package/dashboard/dist/assets/{FilterBar-B0taDH7I.js → FilterBar-B_dy2Jhj.js} +2 -2
  55. package/dashboard/dist/assets/{FilterBar-B0taDH7I.js.map → FilterBar-B_dy2Jhj.js.map} +1 -1
  56. package/dashboard/dist/assets/{GraphInvokePage-B_P3pJeA.js → GraphInvokePage-CvLYp1nL.js} +2 -2
  57. package/dashboard/dist/assets/{GraphInvokePage-B_P3pJeA.js.map → GraphInvokePage-CvLYp1nL.js.map} +1 -1
  58. package/dashboard/dist/assets/HomePage-B6s1ZeyA.js +2 -0
  59. package/dashboard/dist/assets/HomePage-B6s1ZeyA.js.map +1 -0
  60. package/dashboard/dist/assets/{ListToolbar-ueCQtu5C.js → ListToolbar-DVhlAKZ3.js} +2 -2
  61. package/dashboard/dist/assets/{ListToolbar-ueCQtu5C.js.map → ListToolbar-DVhlAKZ3.js.map} +1 -1
  62. package/dashboard/dist/assets/{McpOverview-DMaRUXnA.js → McpOverview-Ca8cpc8g.js} +2 -2
  63. package/dashboard/dist/assets/{McpOverview-DMaRUXnA.js.map → McpOverview-Ca8cpc8g.js.map} +1 -1
  64. package/dashboard/dist/assets/{McpQueryDetailPage-D6YSD94n.js → McpQueryDetailPage-D0r2lyZg.js} +2 -2
  65. package/dashboard/dist/assets/{McpQueryDetailPage-D6YSD94n.js.map → McpQueryDetailPage-D0r2lyZg.js.map} +1 -1
  66. package/dashboard/dist/assets/{McpQueryPage-CNGNB59o.js → McpQueryPage-DPP6BB3d.js} +2 -2
  67. package/dashboard/dist/assets/{McpQueryPage-CNGNB59o.js.map → McpQueryPage-DPP6BB3d.js.map} +1 -1
  68. package/dashboard/dist/assets/{McpRunDetailPage-CJ9hDTNs.js → McpRunDetailPage-C76mfUtG.js} +2 -2
  69. package/dashboard/dist/assets/{McpRunDetailPage-CJ9hDTNs.js.map → McpRunDetailPage-C76mfUtG.js.map} +1 -1
  70. package/dashboard/dist/assets/{McpRunsPage-_UaoIwzX.js → McpRunsPage-B43BqEyw.js} +2 -2
  71. package/dashboard/dist/assets/{McpRunsPage-_UaoIwzX.js.map → McpRunsPage-B43BqEyw.js.map} +1 -1
  72. package/dashboard/dist/assets/{NamespacePill-DQGzN0Ph.js → NamespacePill-B5gHotsd.js} +2 -2
  73. package/dashboard/dist/assets/{NamespacePill-DQGzN0Ph.js.map → NamespacePill-B5gHotsd.js.map} +1 -1
  74. package/dashboard/dist/assets/OperationsPage-DbHzQCuE.js +2 -0
  75. package/dashboard/dist/assets/OperationsPage-DbHzQCuE.js.map +1 -0
  76. package/dashboard/dist/assets/OperatorDashboard-B70nS_Ah.js +2 -0
  77. package/dashboard/dist/assets/OperatorDashboard-B70nS_Ah.js.map +1 -0
  78. package/dashboard/dist/assets/{PageHeader-DlcE3U5L.js → PageHeader-DrbNMGxm.js} +2 -2
  79. package/dashboard/dist/assets/{PageHeader-DlcE3U5L.js.map → PageHeader-DrbNMGxm.js.map} +1 -1
  80. package/dashboard/dist/assets/{PageHeaderWithStats-BMhnR3-9.js → PageHeaderWithStats-SbQkaQLG.js} +2 -2
  81. package/dashboard/dist/assets/{PageHeaderWithStats-BMhnR3-9.js.map → PageHeaderWithStats-SbQkaQLG.js.map} +1 -1
  82. package/dashboard/dist/assets/{ProcessDetailPage-CxJ5BSDk.js → ProcessDetailPage-eLLUCWFf.js} +2 -2
  83. package/dashboard/dist/assets/{ProcessDetailPage-CxJ5BSDk.js.map → ProcessDetailPage-eLLUCWFf.js.map} +1 -1
  84. package/dashboard/dist/assets/{ProcessesListPage-GQMOo5Wo.js → ProcessesListPage-Di0n8TR4.js} +2 -2
  85. package/dashboard/dist/assets/{ProcessesListPage-GQMOo5Wo.js.map → ProcessesListPage-Di0n8TR4.js.map} +1 -1
  86. package/dashboard/dist/assets/{RoleDetailPage-Bh5qdI0w.js → RoleDetailPage-Dhn9zU5l.js} +3 -3
  87. package/dashboard/dist/assets/{RoleDetailPage-Bh5qdI0w.js.map → RoleDetailPage-Dhn9zU5l.js.map} +1 -1
  88. package/dashboard/dist/assets/{RolePill-dzo14hB_.js → RolePill-Cz-AAWqA.js} +2 -2
  89. package/dashboard/dist/assets/{RolePill-dzo14hB_.js.map → RolePill-Cz-AAWqA.js.map} +1 -1
  90. package/dashboard/dist/assets/{RolesPage-BIg3_Em6.js → RolesPage-BnAwjUiG.js} +2 -2
  91. package/dashboard/dist/assets/{RolesPage-BIg3_Em6.js.map → RolesPage-BnAwjUiG.js.map} +1 -1
  92. package/dashboard/dist/assets/{RunAsSelector-DQp_keSD.js → RunAsSelector-DFv0VNVZ.js} +2 -2
  93. package/dashboard/dist/assets/{RunAsSelector-DQp_keSD.js.map → RunAsSelector-DFv0VNVZ.js.map} +1 -1
  94. package/dashboard/dist/assets/{StickyPagination-qLaLa33X.js → StickyPagination-D5zxe_l9.js} +2 -2
  95. package/dashboard/dist/assets/{StickyPagination-qLaLa33X.js.map → StickyPagination-D5zxe_l9.js.map} +1 -1
  96. package/dashboard/dist/assets/{StreamMessageDetail-Bi37x95H.js → StreamMessageDetail-BmBfNSEr.js} +2 -2
  97. package/dashboard/dist/assets/{StreamMessageDetail-Bi37x95H.js.map → StreamMessageDetail-BmBfNSEr.js.map} +1 -1
  98. package/dashboard/dist/assets/{SwimlaneTimeline-BdNhoiW8.js → SwimlaneTimeline-CA0TKDIi.js} +2 -2
  99. package/dashboard/dist/assets/{SwimlaneTimeline-BdNhoiW8.js.map → SwimlaneTimeline-CA0TKDIi.js.map} +1 -1
  100. package/dashboard/dist/assets/{TagInput-cyhTZTwe.js → TagInput-Bf9dZSG6.js} +2 -2
  101. package/dashboard/dist/assets/{TagInput-cyhTZTwe.js.map → TagInput-Bf9dZSG6.js.map} +1 -1
  102. package/dashboard/dist/assets/{TaskDetailPage-ngdXRgQp.js → TaskDetailPage-C15nADUW.js} +2 -2
  103. package/dashboard/dist/assets/{TaskDetailPage-ngdXRgQp.js.map → TaskDetailPage-C15nADUW.js.map} +1 -1
  104. package/dashboard/dist/assets/{TaskQueuePill-_zIpG4bG.js → TaskQueuePill-DfiBYQy2.js} +2 -2
  105. package/dashboard/dist/assets/{TaskQueuePill-_zIpG4bG.js.map → TaskQueuePill-DfiBYQy2.js.map} +1 -1
  106. package/dashboard/dist/assets/{TasksListPage-BIE7nrdE.js → TasksListPage-DQdAayqc.js} +2 -2
  107. package/dashboard/dist/assets/{TasksListPage-BIE7nrdE.js.map → TasksListPage-DQdAayqc.js.map} +1 -1
  108. package/dashboard/dist/assets/{TimeAgo-C6FZSNZp.js → TimeAgo-CvslqTB7.js} +2 -2
  109. package/dashboard/dist/assets/{TimeAgo-C6FZSNZp.js.map → TimeAgo-CvslqTB7.js.map} +1 -1
  110. package/dashboard/dist/assets/{TimestampCell-DI5zPUgV.js → TimestampCell-BZCQQONl.js} +2 -2
  111. package/dashboard/dist/assets/{TimestampCell-DI5zPUgV.js.map → TimestampCell-BZCQQONl.js.map} +1 -1
  112. package/dashboard/dist/assets/{ToolPill-CKHYG6eV.js → ToolPill-gA4sXukc.js} +2 -2
  113. package/dashboard/dist/assets/{ToolPill-CKHYG6eV.js.map → ToolPill-gA4sXukc.js.map} +1 -1
  114. package/dashboard/dist/assets/{ToolTestPanel-Dli94RPI.js → ToolTestPanel-BgLVc6R5.js} +2 -2
  115. package/dashboard/dist/assets/{ToolTestPanel-Dli94RPI.js.map → ToolTestPanel-BgLVc6R5.js.map} +1 -1
  116. package/dashboard/dist/assets/{TopicDetailPage-vPtXb7gD.js → TopicDetailPage-9A0aPb4t.js} +2 -2
  117. package/dashboard/dist/assets/{TopicDetailPage-vPtXb7gD.js.map → TopicDetailPage-9A0aPb4t.js.map} +1 -1
  118. package/dashboard/dist/assets/{TopicsPage-BwiEX0pU.js → TopicsPage-o0EZxKbR.js} +2 -2
  119. package/dashboard/dist/assets/{TopicsPage-BwiEX0pU.js.map → TopicsPage-o0EZxKbR.js.map} +1 -1
  120. package/dashboard/dist/assets/{UserName-YozoXJA1.js → UserName-DKMLxBJ5.js} +2 -2
  121. package/dashboard/dist/assets/{UserName-YozoXJA1.js.map → UserName-DKMLxBJ5.js.map} +1 -1
  122. package/dashboard/dist/assets/{WorkflowExecutionPage-Bce8g08l.js → WorkflowExecutionPage-C-snB_dD.js} +2 -2
  123. package/dashboard/dist/assets/{WorkflowExecutionPage-Bce8g08l.js.map → WorkflowExecutionPage-C-snB_dD.js.map} +1 -1
  124. package/dashboard/dist/assets/{WorkflowPill-DlSVXnnj.js → WorkflowPill-Djt2AtZk.js} +2 -2
  125. package/dashboard/dist/assets/{WorkflowPill-DlSVXnnj.js.map → WorkflowPill-Djt2AtZk.js.map} +1 -1
  126. package/dashboard/dist/assets/{WorkflowsDashboard-DpVAH35I.js → WorkflowsDashboard-BRQmgsLR.js} +2 -2
  127. package/dashboard/dist/assets/{WorkflowsDashboard-DpVAH35I.js.map → WorkflowsDashboard-BRQmgsLR.js.map} +1 -1
  128. package/dashboard/dist/assets/{WorkflowsOverview-Bp2pxXJO.js → WorkflowsOverview-DmMdIRHQ.js} +2 -2
  129. package/dashboard/dist/assets/{WorkflowsOverview-Bp2pxXJO.js.map → WorkflowsOverview-DmMdIRHQ.js.map} +1 -1
  130. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CL_kD0mX.js → YamlWorkflowDetailPage-Bj7QkCry.js} +2 -2
  131. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CL_kD0mX.js.map → YamlWorkflowDetailPage-Bj7QkCry.js.map} +1 -1
  132. package/dashboard/dist/assets/{YamlWorkflowsPage-Dtt3x3_T.js → YamlWorkflowsPage-BIi77mE0.js} +2 -2
  133. package/dashboard/dist/assets/{YamlWorkflowsPage-Dtt3x3_T.js.map → YamlWorkflowsPage-BIi77mE0.js.map} +1 -1
  134. package/dashboard/dist/assets/{agents-xhtLVBwq.js → agents-EBIsjLCr.js} +2 -2
  135. package/dashboard/dist/assets/{agents-xhtLVBwq.js.map → agents-EBIsjLCr.js.map} +1 -1
  136. package/dashboard/dist/assets/{bots-DZ1MQUms.js → bots-BXzxybS6.js} +2 -2
  137. package/dashboard/dist/assets/{bots-DZ1MQUms.js.map → bots-BXzxybS6.js.map} +1 -1
  138. package/dashboard/dist/assets/{capabilities-B8j2h7Jn.js → capabilities-CnprG6q_.js} +2 -2
  139. package/dashboard/dist/assets/{capabilities-B8j2h7Jn.js.map → capabilities-CnprG6q_.js.map} +1 -1
  140. package/dashboard/dist/assets/{controlplane-DKijNA6h.js → controlplane-DiC0xtNq.js} +2 -2
  141. package/dashboard/dist/assets/{controlplane-DKijNA6h.js.map → controlplane-DiC0xtNq.js.map} +1 -1
  142. package/dashboard/dist/assets/{escalation-columns-DjoZ4dDb.js → escalation-columns-D0aYpJkF.js} +2 -2
  143. package/dashboard/dist/assets/{escalation-columns-DjoZ4dDb.js.map → escalation-columns-D0aYpJkF.js.map} +1 -1
  144. package/dashboard/dist/assets/index-B2iZG_HP.css +1 -0
  145. package/dashboard/dist/assets/{index-BCIJE--_.js → index-B6ldRx_s.js} +2 -2
  146. package/dashboard/dist/assets/{index-BCIJE--_.js.map → index-B6ldRx_s.js.map} +1 -1
  147. package/dashboard/dist/assets/{index-DrPWIFSv.js → index-BHAjQoOy.js} +2 -2
  148. package/dashboard/dist/assets/{index-DrPWIFSv.js.map → index-BHAjQoOy.js.map} +1 -1
  149. package/dashboard/dist/assets/{index-DcDEJ6b_.js → index-BzRXMicE.js} +2 -2
  150. package/dashboard/dist/assets/{index-DcDEJ6b_.js.map → index-BzRXMicE.js.map} +1 -1
  151. package/dashboard/dist/assets/{index-CMv6YMJY.js → index-C7KY8GTF.js} +2 -2
  152. package/dashboard/dist/assets/{index-CMv6YMJY.js.map → index-C7KY8GTF.js.map} +1 -1
  153. package/dashboard/dist/assets/index-CSTwyrwu.js +63 -0
  154. package/dashboard/dist/assets/index-CSTwyrwu.js.map +1 -0
  155. package/dashboard/dist/assets/{index-DYCCUmSM.js → index-CcMIca5t.js} +2 -2
  156. package/dashboard/dist/assets/{index-DYCCUmSM.js.map → index-CcMIca5t.js.map} +1 -1
  157. package/dashboard/dist/assets/{index-BqeQGQ4K.js → index-CjBdB8Ht.js} +2 -2
  158. package/dashboard/dist/assets/{index-BqeQGQ4K.js.map → index-CjBdB8Ht.js.map} +1 -1
  159. package/dashboard/dist/assets/{index-B0ktIiOY.js → index-D-7mT0ew.js} +2 -2
  160. package/dashboard/dist/assets/{index-B0ktIiOY.js.map → index-D-7mT0ew.js.map} +1 -1
  161. package/dashboard/dist/assets/{index-Cp1jJHm1.js → index-DDA7FvqT.js} +2 -2
  162. package/dashboard/dist/assets/{index-Cp1jJHm1.js.map → index-DDA7FvqT.js.map} +1 -1
  163. package/dashboard/dist/assets/index-DVmC_UfQ.js +5 -0
  164. package/dashboard/dist/assets/index-DVmC_UfQ.js.map +1 -0
  165. package/dashboard/dist/assets/{index-ChHD9p_I.js → index-Dht0ihGT.js} +2 -2
  166. package/dashboard/dist/assets/{index-ChHD9p_I.js.map → index-Dht0ihGT.js.map} +1 -1
  167. package/dashboard/dist/assets/{index-DWDEa8jS.js → index-gBnGEubX.js} +2 -2
  168. package/dashboard/dist/assets/{index-DWDEa8jS.js.map → index-gBnGEubX.js.map} +1 -1
  169. package/dashboard/dist/assets/{index-0SzWFShg.js → index-ovFEZ9SV.js} +2 -2
  170. package/dashboard/dist/assets/{index-0SzWFShg.js.map → index-ovFEZ9SV.js.map} +1 -1
  171. package/dashboard/dist/assets/{knowledge-Dl3cOfFR.js → knowledge-W5QSKkYQ.js} +2 -2
  172. package/dashboard/dist/assets/{knowledge-Dl3cOfFR.js.map → knowledge-W5QSKkYQ.js.map} +1 -1
  173. package/dashboard/dist/assets/{mcp-BwjeqkHn.js → mcp-n877HyOj.js} +2 -2
  174. package/dashboard/dist/assets/{mcp-BwjeqkHn.js.map → mcp-n877HyOj.js.map} +1 -1
  175. package/dashboard/dist/assets/{mcp-query-C1Rlt4az.js → mcp-query-C9kV4sUm.js} +2 -2
  176. package/dashboard/dist/assets/{mcp-query-C1Rlt4az.js.map → mcp-query-C9kV4sUm.js.map} +1 -1
  177. package/dashboard/dist/assets/{pipelines-BGIUgIH_.js → pipelines-CBR68T8R.js} +2 -2
  178. package/dashboard/dist/assets/{pipelines-BGIUgIH_.js.map → pipelines-CBR68T8R.js.map} +1 -1
  179. package/dashboard/dist/assets/{tasks-CnC1xEaD.js → tasks-DHpWqKMk.js} +2 -2
  180. package/dashboard/dist/assets/{tasks-CnC1xEaD.js.map → tasks-DHpWqKMk.js.map} +1 -1
  181. package/dashboard/dist/assets/{topics-C6EcHi07.js → topics-CaLtyqSh.js} +2 -2
  182. package/dashboard/dist/assets/{topics-C6EcHi07.js.map → topics-CaLtyqSh.js.map} +1 -1
  183. package/dashboard/dist/assets/useEventHooks-B8p56JlB.js +2 -0
  184. package/dashboard/dist/assets/useEventHooks-B8p56JlB.js.map +1 -0
  185. package/dashboard/dist/assets/{useNamespace-Ci_oA5Tq.js → useNamespace-ej71FCvu.js} +2 -2
  186. package/dashboard/dist/assets/{useNamespace-Ci_oA5Tq.js.map → useNamespace-ej71FCvu.js.map} +1 -1
  187. package/dashboard/dist/assets/{useYamlActivityEvents-u8RUiMma.js → useYamlActivityEvents-DgpiFXib.js} +2 -2
  188. package/dashboard/dist/assets/{useYamlActivityEvents-u8RUiMma.js.map → useYamlActivityEvents-DgpiFXib.js.map} +1 -1
  189. package/dashboard/dist/assets/{users-DtiYvg8z.js → users-CHnjI_Ca.js} +2 -2
  190. package/dashboard/dist/assets/{users-DtiYvg8z.js.map → users-CHnjI_Ca.js.map} +1 -1
  191. package/dashboard/dist/assets/{vendor-icons-BE_WrH2z.js → vendor-icons-Bg6eJX4Z.js} +136 -141
  192. package/dashboard/dist/assets/vendor-icons-Bg6eJX4Z.js.map +1 -0
  193. package/dashboard/dist/assets/{workflows-BysPDsh9.js → workflows-DtnXUL0U.js} +2 -2
  194. package/dashboard/dist/assets/{workflows-BysPDsh9.js.map → workflows-DtnXUL0U.js.map} +1 -1
  195. package/dashboard/dist/assets/{yaml-workflows-31qtxg5W.js → yaml-workflows-DDclYAID.js} +2 -2
  196. package/dashboard/dist/assets/{yaml-workflows-31qtxg5W.js.map → yaml-workflows-DDclYAID.js.map} +1 -1
  197. package/dashboard/dist/index.html +3 -3
  198. package/docs/api/http/escalations.md +2 -2
  199. package/docs/api/sdk/escalations.md +2 -2
  200. package/docs/events.md +4 -2
  201. package/docs/hitl/escalation.md +2 -2
  202. package/docs/hitl/x-lt-embed.md +41 -12
  203. package/docs/hitl/x-lt-list-schema.md +26 -3
  204. package/package.json +1 -1
  205. package/dashboard/dist/assets/AgentDetailPage-D9JdkWV8.js.map +0 -1
  206. package/dashboard/dist/assets/AvailableEscalationsPage-rKbrcY8Y.js.map +0 -1
  207. package/dashboard/dist/assets/CountdownTimer-Z8N8ccJ1.js +0 -2
  208. package/dashboard/dist/assets/CountdownTimer-Z8N8ccJ1.js.map +0 -1
  209. package/dashboard/dist/assets/CustomDurationPicker-BTmpAQOL.js +0 -2
  210. package/dashboard/dist/assets/CustomDurationPicker-BTmpAQOL.js.map +0 -1
  211. package/dashboard/dist/assets/HomePage-lu88PzQH.js +0 -2
  212. package/dashboard/dist/assets/HomePage-lu88PzQH.js.map +0 -1
  213. package/dashboard/dist/assets/OperationsPage-CTfwuWXR.js +0 -2
  214. package/dashboard/dist/assets/OperationsPage-CTfwuWXR.js.map +0 -1
  215. package/dashboard/dist/assets/OperatorDashboard-DMPJmgP_.js +0 -2
  216. package/dashboard/dist/assets/OperatorDashboard-DMPJmgP_.js.map +0 -1
  217. package/dashboard/dist/assets/index-C6UuVkz7.js +0 -63
  218. package/dashboard/dist/assets/index-C6UuVkz7.js.map +0 -1
  219. package/dashboard/dist/assets/index-Dh5Y3hq7.js +0 -5
  220. package/dashboard/dist/assets/index-Dh5Y3hq7.js.map +0 -1
  221. package/dashboard/dist/assets/index-WSGppNeK.css +0 -1
  222. package/dashboard/dist/assets/useEventHooks-Cyq4DiQA.js +0 -2
  223. package/dashboard/dist/assets/useEventHooks-Cyq4DiQA.js.map +0 -1
  224. package/dashboard/dist/assets/vendor-icons-BE_WrH2z.js.map +0 -1
@@ -166,7 +166,7 @@ async function bulkAssign(input, auth) {
166
166
  }
167
167
  const result = await escalationService.bulkAssignEscalationsByQuery({ role: query.role, facets: query.facets }, targetUserId, durationMinutes ?? 30);
168
168
  if (result.assigned > 0)
169
- (0, helpers_1.publishBulkClaimEvents)(result.ids, targetUserId);
169
+ (0, helpers_1.publishBulkClaimEvents)(result.ids, targetUserId, query.role);
170
170
  return { status: 200, data: { assigned: result.assigned, skipped: 0 } };
171
171
  }
172
172
  if (!(0, helpers_1.validateIds)(ids)) {
@@ -215,7 +215,13 @@ async function bulkEscalate(input, auth) {
215
215
  const perm = await (0, helpers_1.checkBulkPermission)(auth.userId, ids);
216
216
  if (!perm.allowed)
217
217
  return perm;
218
+ // Departing roles are read before the move so each reassignment can
219
+ // publish under BOTH queues — the one the row leaves and the one it
220
+ // joins (same contract as the single escalate path).
221
+ const beforeRows = await escalationService.getEscalationScopeRows(ids);
218
222
  const updated = await escalationService.bulkEscalateToRole(ids, targetRole);
223
+ if (updated > 0)
224
+ (0, helpers_1.publishBulkReassignEvents)(beforeRows, targetRole);
219
225
  return { status: 200, data: { updated } };
220
226
  }
221
227
  catch (err) {
@@ -141,4 +141,13 @@ export declare function resolveAssignee(assignee: string | undefined, auth: {
141
141
  * Only adds the role if `provisionIfAbsent` declares it and caller has authority.
142
142
  */
143
143
  export declare function ensureRoleMembership(userId: string, requiredRole: string, callerUserId: string, provisionIfAbsent?: ProvisionIfAbsent): Promise<boolean>;
144
- export declare function publishBulkClaimEvents(ids: string[], assignedTo: string): void;
144
+ /**
145
+ * Publish `reassigned` for a bulk role move: every row publishes under its
146
+ * departing role AND the target role, so subscribers scoped to either queue
147
+ * observe the move. Rows already in the target role publish once.
148
+ */
149
+ export declare function publishBulkReassignEvents(beforeRows: Array<{
150
+ id: string;
151
+ role: string;
152
+ }>, targetRole: string): void;
153
+ export declare function publishBulkClaimEvents(ids: string[], assignedTo: string, knownRole?: string): void;
@@ -44,6 +44,7 @@ exports.assertQueueManageAccess = assertQueueManageAccess;
44
44
  exports.checkBulkPermission = checkBulkPermission;
45
45
  exports.resolveAssignee = resolveAssignee;
46
46
  exports.ensureRoleMembership = ensureRoleMembership;
47
+ exports.publishBulkReassignEvents = publishBulkReassignEvents;
47
48
  exports.publishBulkClaimEvents = publishBulkClaimEvents;
48
49
  const escalationService = __importStar(require("../../services/escalation"));
49
50
  const userService = __importStar(require("../../services/user"));
@@ -254,17 +255,56 @@ async function ensureRoleMembership(userId, requiredRole, callerUserId, provisio
254
255
  catch { /* already has it */ }
255
256
  return true;
256
257
  }
257
- function publishBulkClaimEvents(ids, assignedTo) {
258
- for (const id of ids) {
259
- (0, publish_1.publishEscalationEvent)({
260
- type: 'escalation.claimed',
261
- source: 'api',
262
- workflowId: '',
263
- workflowName: '',
264
- taskQueue: '',
265
- escalationId: id,
266
- status: 'claimed',
267
- data: { assigned_to: assignedTo, bulk: true },
268
- });
258
+ /**
259
+ * Publish `reassigned` for a bulk role move: every row publishes under its
260
+ * departing role AND the target role, so subscribers scoped to either queue
261
+ * observe the move. Rows already in the target role publish once.
262
+ */
263
+ function publishBulkReassignEvents(beforeRows, targetRole) {
264
+ for (const row of beforeRows) {
265
+ const roles = row.role && row.role !== targetRole ? [row.role, targetRole] : [targetRole];
266
+ for (const role of roles) {
267
+ (0, publish_1.publishEscalationEvent)({
268
+ type: 'escalation.reassigned',
269
+ source: 'api',
270
+ workflowId: '',
271
+ workflowName: '',
272
+ taskQueue: '',
273
+ escalationId: row.id,
274
+ role,
275
+ status: 'pending',
276
+ data: { from_role: row.role, to_role: targetRole, bulk: true },
277
+ });
278
+ }
269
279
  }
270
280
  }
281
+ function publishBulkClaimEvents(ids, assignedTo, knownRole) {
282
+ // The claimed subject carries each row's role token. Query-form callers
283
+ // already know the single role; id-form callers resolve roles with one
284
+ // indexed read. Fire-and-forget, like every event publish.
285
+ void (async () => {
286
+ const roleById = new Map();
287
+ if (knownRole) {
288
+ for (const id of ids)
289
+ roleById.set(id, knownRole);
290
+ }
291
+ else {
292
+ const rows = await escalationService.getEscalationScopeRows(ids);
293
+ for (const row of rows)
294
+ roleById.set(row.id, row.role);
295
+ }
296
+ for (const id of ids) {
297
+ (0, publish_1.publishEscalationEvent)({
298
+ type: 'escalation.claimed',
299
+ source: 'api',
300
+ workflowId: '',
301
+ workflowName: '',
302
+ taskQueue: '',
303
+ escalationId: id,
304
+ role: roleById.get(id) ?? '',
305
+ status: 'claimed',
306
+ data: { assigned_to: assignedTo, bulk: true },
307
+ });
308
+ }
309
+ })().catch(() => { });
310
+ }
@@ -10,4 +10,14 @@
10
10
  * - `app.epic.apis.createorder.error` matches `app.epic.>`
11
11
  * - `app.epic.apis.createorder.error` does NOT match `app.vendor.>`
12
12
  */
13
+ /**
14
+ * Make a value safe to embed as ONE token of a dot-delimited subject.
15
+ *
16
+ * Dots would splinter the token into extra subject levels; `*`, `>`, spaces,
17
+ * and other non-token characters would corrupt pattern matching (and are
18
+ * illegal in NATS subjects). Each run of unsafe characters collapses to a
19
+ * single `-`. An empty or missing value yields `none` so the subject always
20
+ * keeps its arity.
21
+ */
22
+ export declare function sanitizeSubjectToken(value: string | null | undefined): string;
13
23
  export declare function subjectMatchesPattern(subject: string, pattern: string): boolean;
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeSubjectToken = sanitizeSubjectToken;
3
4
  exports.subjectMatchesPattern = subjectMatchesPattern;
4
5
  /**
5
6
  * Match a dot-delimited subject against a pattern with NATS-style wildcards.
@@ -13,6 +14,19 @@ exports.subjectMatchesPattern = subjectMatchesPattern;
13
14
  * - `app.epic.apis.createorder.error` matches `app.epic.>`
14
15
  * - `app.epic.apis.createorder.error` does NOT match `app.vendor.>`
15
16
  */
17
+ /**
18
+ * Make a value safe to embed as ONE token of a dot-delimited subject.
19
+ *
20
+ * Dots would splinter the token into extra subject levels; `*`, `>`, spaces,
21
+ * and other non-token characters would corrupt pattern matching (and are
22
+ * illegal in NATS subjects). Each run of unsafe characters collapses to a
23
+ * single `-`. An empty or missing value yields `none` so the subject always
24
+ * keeps its arity.
25
+ */
26
+ function sanitizeSubjectToken(value) {
27
+ const cleaned = (value ?? '').replace(/[^A-Za-z0-9_-]+/g, '-').replace(/^-+|-+$/g, '');
28
+ return cleaned || 'none';
29
+ }
16
30
  function subjectMatchesPattern(subject, pattern) {
17
31
  if (pattern === '*')
18
32
  return true;
@@ -32,16 +32,22 @@ export declare function publishTaskEvent(params: {
32
32
  }): Promise<void>;
33
33
  /**
34
34
  * Publish an escalation lifecycle event.
35
- * Subject: system.escalation.{escalationId}.{action}
35
+ * Subject: system.escalation.{role}.{escalationId}.{action}
36
+ *
37
+ * The role token makes the queue the organizing level of the hierarchy:
38
+ * subscribers scope to one role (`system.escalation.{role}.>`), one verb
39
+ * across roles (`system.escalation.*.*.created`), or one item regardless of
40
+ * role hops (`system.escalation.*.{id}.>`).
36
41
  */
37
42
  export declare function publishEscalationEvent(params: {
38
- type: 'escalation.created' | 'escalation.resolved' | 'escalation.claimed' | 'escalation.released' | 'escalation.cancelled';
43
+ type: 'escalation.created' | 'escalation.resolved' | 'escalation.claimed' | 'escalation.released' | 'escalation.cancelled' | 'escalation.reassigned';
39
44
  source: string;
40
45
  workflowId: string;
41
46
  workflowName: string;
42
47
  taskQueue: string;
43
48
  taskId?: string;
44
49
  escalationId: string;
50
+ role: string;
45
51
  originId?: string;
46
52
  status: string;
47
53
  data?: Record<string, any>;
@@ -9,6 +9,7 @@ exports.publishFileEvent = publishFileEvent;
9
9
  exports.publishAgentEvent = publishAgentEvent;
10
10
  exports.publishWorkflowEvent = publishWorkflowEvent;
11
11
  const index_1 = require("./index");
12
+ const matching_1 = require("./matching");
12
13
  const logger_1 = require("../logger");
13
14
  /**
14
15
  * Fire-and-forget publish helper. Swallows errors (best-effort).
@@ -62,13 +63,19 @@ function publishTaskEvent(params) {
62
63
  }
63
64
  /**
64
65
  * Publish an escalation lifecycle event.
65
- * Subject: system.escalation.{escalationId}.{action}
66
+ * Subject: system.escalation.{role}.{escalationId}.{action}
67
+ *
68
+ * The role token makes the queue the organizing level of the hierarchy:
69
+ * subscribers scope to one role (`system.escalation.{role}.>`), one verb
70
+ * across roles (`system.escalation.*.*.created`), or one item regardless of
71
+ * role hops (`system.escalation.*.{id}.>`).
66
72
  */
67
73
  function publishEscalationEvent(params) {
68
74
  const action = params.type.split('.')[1];
69
75
  return fireAndForget({
70
- type: `system.escalation.${params.escalationId}.${action}`,
76
+ type: `system.escalation.${(0, matching_1.sanitizeSubjectToken)(params.role)}.${params.escalationId}.${action}`,
71
77
  source: params.source,
78
+ role: params.role,
72
79
  workflowId: params.workflowId,
73
80
  workflowName: params.workflowName,
74
81
  taskQueue: params.taskQueue,
@@ -8,8 +8,14 @@ export type SocketIOAuthenticator = (token: string) => boolean | Promise<boolean
8
8
  /**
9
9
  * Socket.IO event adapter for browser clients.
10
10
  *
11
- * Publishes LTEvent payloads to all connected Socket.IO clients
12
- * on channels following the pattern: `lt.events.{event.type}`
11
+ * Publishes LTEvent payloads to connected Socket.IO clients on channels
12
+ * following the pattern: `lt.events.{event.type}`.
13
+ *
14
+ * Delivery is scoped per socket: a client registers NATS-style subject
15
+ * patterns with `lt.subscribe` / `lt.unsubscribe` messages and receives only
16
+ * matching events — the server filters, the wire carries only what the page
17
+ * asked for. A socket that never registers a pattern receives every event
18
+ * (the broadcast contract external consumers may rely on).
13
19
  *
14
20
  * The HTTP server must be attached via `attachServer()` before
15
21
  * `connect()` is called. The startup flow handles this automatically
@@ -3,11 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SocketIOEventAdapter = void 0;
4
4
  const socket_io_1 = require("socket.io");
5
5
  const logger_1 = require("../logger");
6
+ const matching_1 = require("./matching");
6
7
  /**
7
8
  * Socket.IO event adapter for browser clients.
8
9
  *
9
- * Publishes LTEvent payloads to all connected Socket.IO clients
10
- * on channels following the pattern: `lt.events.{event.type}`
10
+ * Publishes LTEvent payloads to connected Socket.IO clients on channels
11
+ * following the pattern: `lt.events.{event.type}`.
12
+ *
13
+ * Delivery is scoped per socket: a client registers NATS-style subject
14
+ * patterns with `lt.subscribe` / `lt.unsubscribe` messages and receives only
15
+ * matching events — the server filters, the wire carries only what the page
16
+ * asked for. A socket that never registers a pattern receives every event
17
+ * (the broadcast contract external consumers may rely on).
11
18
  *
12
19
  * The HTTP server must be attached via `attachServer()` before
13
20
  * `connect()` is called. The startup flow handles this automatically
@@ -75,6 +82,19 @@ class SocketIOEventAdapter {
75
82
  }
76
83
  this.io.on('connection', (socket) => {
77
84
  logger_1.loggerRegistry.info(`[lt-events:socketio] client connected (${socket.id})`);
85
+ // Per-socket subject-pattern scope. Registering the first pattern
86
+ // switches the socket from broadcast to scoped delivery.
87
+ const patterns = new Set();
88
+ socket.data.ltPatterns = patterns;
89
+ socket.on('lt.subscribe', (pattern) => {
90
+ if (typeof pattern === 'string' && pattern.length > 0 && pattern.length <= 256) {
91
+ patterns.add(pattern);
92
+ }
93
+ });
94
+ socket.on('lt.unsubscribe', (pattern) => {
95
+ if (typeof pattern === 'string')
96
+ patterns.delete(pattern);
97
+ });
78
98
  socket.on('disconnect', () => {
79
99
  logger_1.loggerRegistry.debug(`[lt-events:socketio] client disconnected (${socket.id})`);
80
100
  });
@@ -85,7 +105,20 @@ class SocketIOEventAdapter {
85
105
  if (!this.io)
86
106
  return;
87
107
  const channel = `lt.events.${event.type}`;
88
- this.io.emit(channel, event);
108
+ for (const socket of this.io.of('/').sockets.values()) {
109
+ const patterns = socket.data.ltPatterns;
110
+ if (!patterns || patterns.size === 0) {
111
+ // Legacy scope: a socket with no registered patterns gets everything.
112
+ socket.emit(channel, event);
113
+ continue;
114
+ }
115
+ for (const pattern of patterns) {
116
+ if ((0, matching_1.subjectMatchesPattern)(channel, pattern)) {
117
+ socket.emit(channel, event);
118
+ break;
119
+ }
120
+ }
121
+ }
89
122
  }
90
123
  async disconnect() {
91
124
  if (this.io) {
@@ -4,6 +4,7 @@ exports.systemEventsConfig = void 0;
4
4
  exports.mapSystemEvent = mapSystemEvent;
5
5
  exports.onSystemEvent = onSystemEvent;
6
6
  const index_1 = require("./index");
7
+ const matching_1 = require("./matching");
7
8
  /** Verb → long-tail event status, matching the manual publishEscalationEvent convention. */
8
9
  const ESCALATION_STATUS_BY_VERB = {
9
10
  created: 'pending',
@@ -27,9 +28,16 @@ function mapSystemEvent(event) {
27
28
  if (domain === 'escalation') {
28
29
  const row = (event.data ?? {});
29
30
  const verb = segments[3] ?? '';
31
+ // The SDK forms `system.escalation.{id}.{verb}`; long-tail's canonical
32
+ // subject carries the role as the organizing token. The committed row
33
+ // rides in `data`, so the role is lifted from it and the subject is
34
+ // rewritten to `system.escalation.{role}.{id}.{verb}` — the same shape
35
+ // publishEscalationEvent produces for the service-mediated path.
36
+ const role = row.role || undefined;
30
37
  return {
31
- type: event.type,
38
+ type: `system.escalation.${(0, matching_1.sanitizeSubjectToken)(role)}.${segments[2]}.${verb}`,
32
39
  source: 'sdk',
40
+ role,
33
41
  workflowId: row.workflow_id || event.workflow_id || undefined,
34
42
  workflowName: row.workflow_type || undefined,
35
43
  taskQueue: row.task_queue || undefined,
@@ -74,6 +74,7 @@ async function createEscalation(input) {
74
74
  workflowName: escalation.workflow_type || '',
75
75
  taskQueue: escalation.task_queue || '',
76
76
  escalationId: escalation.id,
77
+ role: escalation.role,
77
78
  status: 'pending',
78
79
  data: { type: input.type, role: input.role },
79
80
  });
@@ -97,6 +98,7 @@ async function claimEscalation(id, userId, durationMinutes = 30) {
97
98
  workflowName: escalation.workflow_type || '',
98
99
  taskQueue: escalation.task_queue || '',
99
100
  escalationId: escalation.id,
101
+ role: escalation.role,
100
102
  status: 'claimed',
101
103
  data: { assigned_to: userId },
102
104
  });
@@ -137,6 +139,7 @@ async function resolveEscalation(id, resolverPayload, metadata, assertClaim, res
137
139
  workflowName: escalation.workflow_type || '',
138
140
  taskQueue: escalation.task_queue || '',
139
141
  escalationId: escalation.id,
142
+ role: escalation.role,
140
143
  status: 'resolved',
141
144
  data: {},
142
145
  });
@@ -170,6 +173,7 @@ async function resolveEscalationsByIds(ids, resolverPayload, metadata) {
170
173
  workflowName: escalation.workflow_type || '',
171
174
  taskQueue: escalation.task_queue || '',
172
175
  escalationId: escalation.id,
176
+ role: escalation.role,
173
177
  status: 'resolved',
174
178
  data: {},
175
179
  });
@@ -209,6 +213,7 @@ async function resolveEscalationsAllOrNone(items, metadata, assertAssignee, reso
209
213
  workflowName: escalation.workflow_type || '',
210
214
  taskQueue: escalation.task_queue || '',
211
215
  escalationId: escalation.id,
216
+ role: escalation.role,
212
217
  status: 'resolved',
213
218
  data: {},
214
219
  });
@@ -276,6 +281,7 @@ async function cancelEscalation(id) {
276
281
  workflowName: cancelled.workflow_type || '',
277
282
  taskQueue: cancelled.task_queue || '',
278
283
  escalationId: cancelled.id,
284
+ role: cancelled.role,
279
285
  status: 'cancelled',
280
286
  data: { reason: 'workflow_terminated' },
281
287
  });
@@ -335,6 +341,7 @@ async function releaseEscalation(id, userId) {
335
341
  workflowName: released.workflow_type || '',
336
342
  taskQueue: released.task_queue || '',
337
343
  escalationId: released.id,
344
+ role: released.role,
338
345
  status: 'released',
339
346
  data: { released_by: userId },
340
347
  });
@@ -358,8 +365,36 @@ async function releaseExpiredClaims() {
358
365
  */
359
366
  async function escalateToRole(id, targetRole) {
360
367
  const client = await (0, client_1.escalations)();
368
+ // The departing role is read before the move: the returned entry already
369
+ // carries the target role, and role-scoped subscribers of the OLD queue
370
+ // must see the item leave just as the new queue sees it arrive.
371
+ const before = await client.get(id);
372
+ const fromRole = before?.role ?? null;
361
373
  const entry = await client.escalateToRole({ id, targetRole });
362
- return entry ? (0, map_1.toEscalationRecord)(entry) : null;
374
+ if (!entry)
375
+ return null;
376
+ const escalation = (0, map_1.toEscalationRecord)(entry);
377
+ // One reassignment, two subjects: the same event publishes under the
378
+ // departing role and the arriving role, so a subscriber scoped to either
379
+ // queue observes the move. `data` names both ends for consumers that
380
+ // only see one side.
381
+ const rolesToNotify = fromRole && fromRole !== escalation.role
382
+ ? [fromRole, escalation.role]
383
+ : [escalation.role];
384
+ for (const role of rolesToNotify) {
385
+ publishEscalationChange({
386
+ type: 'escalation.reassigned',
387
+ source: 'service',
388
+ workflowId: escalation.workflow_id || '',
389
+ workflowName: escalation.workflow_type || '',
390
+ taskQueue: escalation.task_queue || '',
391
+ escalationId: escalation.id,
392
+ role,
393
+ status: 'pending',
394
+ data: { from_role: fromRole, to_role: escalation.role },
395
+ });
396
+ }
397
+ return escalation;
363
398
  }
364
399
  async function getEscalation(id) {
365
400
  const client = await (0, client_1.escalations)();
@@ -402,7 +437,7 @@ async function cancelEscalationsByWorkflowId(workflowId) {
402
437
  SET status = 'cancelled', updated_at = NOW()
403
438
  WHERE workflow_id = $1
404
439
  AND status = 'pending'
405
- RETURNING id, workflow_id, workflow_type, task_queue`, [workflowId]);
440
+ RETURNING id, workflow_id, workflow_type, task_queue, role`, [workflowId]);
406
441
  for (const row of rows) {
407
442
  publishEscalationChange({
408
443
  type: 'escalation.cancelled',
@@ -411,6 +446,7 @@ async function cancelEscalationsByWorkflowId(workflowId) {
411
446
  workflowName: row.workflow_type || '',
412
447
  taskQueue: row.task_queue || '',
413
448
  escalationId: row.id,
449
+ role: row.role || '',
414
450
  status: 'cancelled',
415
451
  data: { reason: 'workflow_terminated' },
416
452
  });
@@ -498,6 +534,7 @@ async function claimByMetadata(key, value, userId, durationMinutes = 30, metadat
498
534
  workflowName: escalation.workflow_type || '',
499
535
  taskQueue: escalation.task_queue || '',
500
536
  escalationId: escalation.id,
537
+ role: escalation.role,
501
538
  status: 'claimed',
502
539
  data: { assigned_to: userId },
503
540
  });
@@ -556,6 +593,7 @@ async function resolveByMetadataAtomic(key, value, userId, resolverPayload, meta
556
593
  workflowName: escalation.workflow_type || '',
557
594
  taskQueue: escalation.task_queue || '',
558
595
  escalationId: escalation.id,
596
+ role: escalation.role,
559
597
  status: 'resolved',
560
598
  data: { resolved_by: userId },
561
599
  });
@@ -21,7 +21,7 @@ export type ConditionEscalationConfig = Types.ConditionQueueConfig & {
21
21
  * written inside this workflow's Leg1 checkpoint (one commit, crash-safe — no
22
22
  * separate create activity, no enrich). `signal_key` is the signal id, so the
23
23
  * dashboard resolve endpoint (Path 0), `resolveEscalationBySignalKey`, and any
24
- * webhook resume the SAME job in place. `system.escalation.{id}.created` fires
24
+ * webhook resume the SAME job in place. `system.escalation.{role}.{id}.created` fires
25
25
  * from the engine automatically.
26
26
  *
27
27
  * ```typescript
@@ -60,7 +60,7 @@ function toEngineConfig(escalation) {
60
60
  * written inside this workflow's Leg1 checkpoint (one commit, crash-safe — no
61
61
  * separate create activity, no enrich). `signal_key` is the signal id, so the
62
62
  * dashboard resolve endpoint (Path 0), `resolveEscalationBySignalKey`, and any
63
- * webhook resume the SAME job in place. `system.escalation.{id}.created` fires
63
+ * webhook resume the SAME job in place. `system.escalation.{role}.{id}.created` fires
64
64
  * from the engine automatically.
65
65
  *
66
66
  * ```typescript
@@ -1,8 +1,4 @@
1
1
  import type { LTTopicConfig } from '../../types';
2
- /**
3
- * Seed all 22 built-in system topics into the catalog.
4
- * Called once at startup after migrations.
5
- */
6
2
  export declare function seedSystemTopics(): Promise<void>;
7
3
  /**
8
4
  * Seed user-declared topics from startConfig.topics[].
@@ -12,6 +12,7 @@ const WORKFLOW_CONTEXT_PROPS = {
12
12
  originId: { type: 'string', description: 'Root process lineage ID' },
13
13
  };
14
14
  const STATUS_FIELD = { type: 'string', description: 'Status after this event' };
15
+ const ROLE_FIELD = { type: 'string', description: 'Escalation role (the queue) — also the third subject token' };
15
16
  function objectSchema(properties) {
16
17
  return { type: 'object', properties };
17
18
  }
@@ -83,37 +84,64 @@ const SYSTEM_TOPICS = [
83
84
  example_payload: { workflowId: 'wf-abc', workflowName: 'processOrder', status: 'failed' },
84
85
  tags: ['lifecycle', 'error'],
85
86
  },
86
- // Escalation lifecycle
87
+ // Escalation lifecycle — subjects are `system.escalation.{role}.{id}.{verb}`.
88
+ // The role token is the organizing level: subscribe to one queue with
89
+ // `system.escalation.{role}.>`, one verb across queues with
90
+ // `system.escalation.*.*.{verb}`, or one item with `system.escalation.*.{id}.>`.
87
91
  {
88
- topic: 'system.escalation.*.created',
92
+ topic: 'system.escalation.*.*.created',
89
93
  description: 'An escalation has been created.',
90
94
  category: 'escalation',
91
- payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, status: STATUS_FIELD, data: { type: 'object' } }),
92
- example_payload: { escalationId: 'esc-001', status: 'pending', workflowName: 'processOrder' },
95
+ payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD, data: { type: 'object' } }),
96
+ example_payload: { escalationId: 'esc-001', role: 'order-review', status: 'pending', workflowName: 'processOrder' },
93
97
  tags: ['lifecycle', 'hitl'],
94
98
  },
95
99
  {
96
- topic: 'system.escalation.*.resolved',
100
+ topic: 'system.escalation.*.*.resolved',
97
101
  description: 'An escalation has been resolved.',
98
102
  category: 'escalation',
99
- payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, status: STATUS_FIELD, data: { type: 'object' } }),
100
- example_payload: { escalationId: 'esc-001', status: 'resolved', workflowName: 'processOrder' },
103
+ payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD, data: { type: 'object' } }),
104
+ example_payload: { escalationId: 'esc-001', role: 'order-review', status: 'resolved', workflowName: 'processOrder' },
101
105
  tags: ['lifecycle', 'hitl'],
102
106
  },
103
107
  {
104
- topic: 'system.escalation.*.claimed',
108
+ topic: 'system.escalation.*.*.claimed',
105
109
  description: 'An escalation has been claimed.',
106
110
  category: 'escalation',
107
- payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, status: STATUS_FIELD }),
108
- example_payload: { escalationId: 'esc-001', status: 'claimed' },
111
+ payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD }),
112
+ example_payload: { escalationId: 'esc-001', role: 'order-review', status: 'claimed' },
109
113
  tags: ['lifecycle', 'hitl'],
110
114
  },
111
115
  {
112
- topic: 'system.escalation.*.released',
116
+ topic: 'system.escalation.*.*.released',
113
117
  description: 'An escalation has been returned to the queue.',
114
118
  category: 'escalation',
115
- payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, status: STATUS_FIELD }),
116
- example_payload: { escalationId: 'esc-001', status: 'pending' },
119
+ payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD }),
120
+ example_payload: { escalationId: 'esc-001', role: 'order-review', status: 'pending' },
121
+ tags: ['lifecycle', 'hitl'],
122
+ },
123
+ {
124
+ topic: 'system.escalation.*.*.cancelled',
125
+ description: 'An escalation has been cancelled.',
126
+ category: 'escalation',
127
+ payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD, data: { type: 'object' } }),
128
+ example_payload: { escalationId: 'esc-001', role: 'order-review', status: 'cancelled' },
129
+ tags: ['lifecycle', 'hitl'],
130
+ },
131
+ {
132
+ topic: 'system.escalation.*.*.reassigned',
133
+ description: 'An escalation has moved to a different role. Publishes under both the departing and arriving role.',
134
+ category: 'escalation',
135
+ payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD, data: { type: 'object', description: 'from_role and to_role' } }),
136
+ example_payload: { escalationId: 'esc-001', role: 'order-manager', status: 'pending', data: { from_role: 'order-review', to_role: 'order-manager' } },
137
+ tags: ['lifecycle', 'hitl'],
138
+ },
139
+ {
140
+ topic: 'system.escalation.*.*.expired',
141
+ description: 'A waiting escalation hit its SLA timeout and the engine transitioned it.',
142
+ category: 'escalation',
143
+ payload_schema: objectSchema({ ...WORKFLOW_CONTEXT_PROPS, escalationId: { type: 'string' }, role: ROLE_FIELD, status: STATUS_FIELD, data: { type: 'object' } }),
144
+ example_payload: { escalationId: 'esc-001', role: 'order-review', status: 'expired' },
117
145
  tags: ['lifecycle', 'hitl'],
118
146
  },
119
147
  // Activity lifecycle
@@ -247,9 +275,18 @@ function inferCategory(topic) {
247
275
  return topic.split('.')[0];
248
276
  }
249
277
  /**
250
- * Seed all 22 built-in system topics into the catalog.
278
+ * Seed the built-in system topics into the catalog.
251
279
  * Called once at startup after migrations.
252
280
  */
281
+ // Catalog names no longer published. Escalation subjects carry the role token
282
+ // (`system.escalation.{role}.{id}.{verb}`), so the roleless names are retired
283
+ // from the catalog at seed time.
284
+ const RETIRED_TOPICS = [
285
+ 'system.escalation.*.created',
286
+ 'system.escalation.*.resolved',
287
+ 'system.escalation.*.claimed',
288
+ 'system.escalation.*.released',
289
+ ];
253
290
  async function seedSystemTopics() {
254
291
  for (const def of SYSTEM_TOPICS) {
255
292
  try {
@@ -268,6 +305,12 @@ async function seedSystemTopics() {
268
305
  logger_1.loggerRegistry.warn(`[long-tail] topic seed failed for ${def.topic}: ${err.message}`);
269
306
  }
270
307
  }
308
+ for (const retired of RETIRED_TOPICS) {
309
+ try {
310
+ await (0, index_1.deleteTopic)(retired);
311
+ }
312
+ catch { /* absent on a fresh catalog */ }
313
+ }
271
314
  }
272
315
  /**
273
316
  * Seed user-declared topics from startConfig.topics[].
@@ -4,16 +4,21 @@ import type { LTMilestone } from './task';
4
4
  *
5
5
  * System events use structured subjects with embedded resource IDs:
6
6
  * `system.workflow.{workflowId}.completed`
7
- * `system.escalation.{escalationId}.claimed`
7
+ * `system.escalation.{role}.{escalationId}.claimed`
8
8
  * `system.activity.{workflowId}.{activityName}.failed`
9
9
  *
10
+ * Escalation subjects carry the role as the organizing token — the queue is
11
+ * the unit of subscription. Scope to a role (`system.escalation.{role}.>`),
12
+ * a verb across roles (`system.escalation.*.*.created`), or one item across
13
+ * role hops (`system.escalation.*.{id}.>`).
14
+ *
10
15
  * On the wire (NATS): `lt.events.system.workflow.abc123.completed`
11
16
  * Dashboard subscribes: `lt.events.system.>` for all system events,
12
17
  * or `lt.events.system.workflow.abc123.>` for a specific workflow.
13
18
  *
14
19
  * The `*` segments in these patterns are replaced with actual IDs at publish time.
15
20
  */
16
- export type LTSystemEventPattern = `system.task.${string}.created` | `system.task.${string}.started` | `system.task.${string}.completed` | `system.task.${string}.escalated` | `system.task.${string}.failed` | `system.escalation.${string}.created` | `system.escalation.${string}.resolved` | `system.escalation.${string}.claimed` | `system.escalation.${string}.released` | `system.workflow.${string}.started` | `system.workflow.${string}.completed` | `system.workflow.${string}.failed` | `system.activity.${string}.${string}.started` | `system.activity.${string}.${string}.completed` | `system.activity.${string}.${string}.failed` | `system.knowledge.${string}.stored` | `system.knowledge.${string}.deleted` | 'system.file.stored' | 'system.file.deleted' | `system.agent.${string}.started` | `system.agent.${string}.completed` | `system.agent.${string}.failed` | `system.agent.${string}.status_changed` | `system.agent.${string}.triggers_changed` | `system.milestone.${string}`;
21
+ export type LTSystemEventPattern = `system.task.${string}.created` | `system.task.${string}.started` | `system.task.${string}.completed` | `system.task.${string}.escalated` | `system.task.${string}.failed` | `system.escalation.${string}.${string}.created` | `system.escalation.${string}.${string}.resolved` | `system.escalation.${string}.${string}.claimed` | `system.escalation.${string}.${string}.released` | `system.escalation.${string}.${string}.cancelled` | `system.escalation.${string}.${string}.reassigned` | `system.escalation.${string}.${string}.expired` | `system.workflow.${string}.started` | `system.workflow.${string}.completed` | `system.workflow.${string}.failed` | `system.activity.${string}.${string}.started` | `system.activity.${string}.${string}.completed` | `system.activity.${string}.${string}.failed` | `system.knowledge.${string}.stored` | `system.knowledge.${string}.deleted` | 'system.file.stored' | 'system.file.deleted' | `system.agent.${string}.started` | `system.agent.${string}.completed` | `system.agent.${string}.failed` | `system.agent.${string}.status_changed` | `system.agent.${string}.triggers_changed` | `system.milestone.${string}`;
17
22
  /** @deprecated Use LTSystemEventPattern for system events. Kept for backward compat. */
18
23
  export type LTEventType = LTSystemEventPattern;
19
24
  /**
@@ -63,6 +68,8 @@ export interface LTEvent extends LTEventBase {
63
68
  taskId?: string;
64
69
  /** Escalation ID — present on escalation events. */
65
70
  escalationId?: string;
71
+ /** Escalation role (the queue) — present on escalation events. */
72
+ role?: string;
66
73
  /** Root process lineage — present on workflow/task/escalation events. */
67
74
  originId?: string;
68
75
  /** Lifecycle status. Vocabulary is per-family (see the family interfaces). */
@@ -91,9 +98,10 @@ export interface LTTaskEvent extends LTEventBase, LTWorkflowContext {
91
98
  status: string;
92
99
  milestones?: LTMilestone[];
93
100
  }
94
- /** `system.escalation.{escalationId}.{created|resolved|claimed|released}`. status ∈ pending|claimed|released|resolved|cancelled. */
101
+ /** `system.escalation.{role}.{escalationId}.{created|resolved|claimed|released|cancelled|reassigned|expired}`. status ∈ pending|claimed|released|resolved|cancelled|expired. */
95
102
  export interface LTEscalationEvent extends LTEventBase, LTWorkflowContext {
96
103
  escalationId: string;
104
+ role: string;
97
105
  status: string;
98
106
  }
99
107
  /** `system.activity.{workflowId}.{activityName}.{started|completed|failed}`. */