@hotmeshio/long-tail 0.10.6 → 0.10.7

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 (179) hide show
  1. package/build/api/escalations/bulk.d.ts +16 -4
  2. package/build/api/escalations/bulk.js +42 -7
  3. package/build/api/escalations/resolve.js +57 -15
  4. package/build/routes/escalations/bulk.js +1 -0
  5. package/build/sdk/index.d.ts +5 -1
  6. package/build/services/escalation/bulk.d.ts +14 -0
  7. package/build/services/escalation/bulk.js +17 -0
  8. package/build/services/escalation/crud.d.ts +13 -2
  9. package/build/services/escalation/crud.js +9 -4
  10. package/build/services/orchestrator/condition.d.ts +20 -0
  11. package/build/services/orchestrator/condition.js +30 -6
  12. package/build/types/escalation.d.ts +8 -0
  13. package/dashboard/dist/assets/{AdminDashboard-B5B8cf1A.js → AdminDashboard-CYlm0_J0.js} +2 -2
  14. package/dashboard/dist/assets/{AdminDashboard-B5B8cf1A.js.map → AdminDashboard-CYlm0_J0.js.map} +1 -1
  15. package/dashboard/dist/assets/{AgentConfigPage-BxuHbkDF.js → AgentConfigPage-BttOMcj_.js} +2 -2
  16. package/dashboard/dist/assets/{AgentConfigPage-BxuHbkDF.js.map → AgentConfigPage-BttOMcj_.js.map} +1 -1
  17. package/dashboard/dist/assets/{AgentDetailPage-Bv89ria_.js → AgentDetailPage-D9JdkWV8.js} +2 -2
  18. package/dashboard/dist/assets/{AgentDetailPage-Bv89ria_.js.map → AgentDetailPage-D9JdkWV8.js.map} +1 -1
  19. package/dashboard/dist/assets/{AgentsPage-BPgki44D.js → AgentsPage-AqGtEOL1.js} +2 -2
  20. package/dashboard/dist/assets/{AgentsPage-BPgki44D.js.map → AgentsPage-AqGtEOL1.js.map} +1 -1
  21. package/dashboard/dist/assets/{AvailableEscalationsPage-Dq_FyUcB.js → AvailableEscalationsPage-rKbrcY8Y.js} +2 -2
  22. package/dashboard/dist/assets/{AvailableEscalationsPage-Dq_FyUcB.js.map → AvailableEscalationsPage-rKbrcY8Y.js.map} +1 -1
  23. package/dashboard/dist/assets/{BotPicker-D-WegFKH.js → BotPicker-Bj4MB_so.js} +2 -2
  24. package/dashboard/dist/assets/{BotPicker-D-WegFKH.js.map → BotPicker-Bj4MB_so.js.map} +1 -1
  25. package/dashboard/dist/assets/{CapabilitiesPage-C8Zxzh1x.js → CapabilitiesPage-DzLP5-ad.js} +2 -2
  26. package/dashboard/dist/assets/{CapabilitiesPage-C8Zxzh1x.js.map → CapabilitiesPage-DzLP5-ad.js.map} +1 -1
  27. package/dashboard/dist/assets/{CollapsibleSection-Ca2iifr4.js → CollapsibleSection-CReMhtzK.js} +2 -2
  28. package/dashboard/dist/assets/{CollapsibleSection-Ca2iifr4.js.map → CollapsibleSection-CReMhtzK.js.map} +1 -1
  29. package/dashboard/dist/assets/{CountdownTimer-CQSukTT4.js → CountdownTimer-Z8N8ccJ1.js} +2 -2
  30. package/dashboard/dist/assets/{CountdownTimer-CQSukTT4.js.map → CountdownTimer-Z8N8ccJ1.js.map} +1 -1
  31. package/dashboard/dist/assets/{CredentialsPage-BFf0p9CE.js → CredentialsPage-D_2T6vSb.js} +2 -2
  32. package/dashboard/dist/assets/{CredentialsPage-BFf0p9CE.js.map → CredentialsPage-D_2T6vSb.js.map} +1 -1
  33. package/dashboard/dist/assets/{CronLabel-CvjUA6jF.js → CronLabel-DBmKrLvL.js} +2 -2
  34. package/dashboard/dist/assets/{CronLabel-CvjUA6jF.js.map → CronLabel-DBmKrLvL.js.map} +1 -1
  35. package/dashboard/dist/assets/{CustomDurationPicker-znQCEiPe.js → CustomDurationPicker-BTmpAQOL.js} +2 -2
  36. package/dashboard/dist/assets/{CustomDurationPicker-znQCEiPe.js.map → CustomDurationPicker-BTmpAQOL.js.map} +1 -1
  37. package/dashboard/dist/assets/{ElapsedCell-C0pd3pO8.js → ElapsedCell-C0LbM8o2.js} +2 -2
  38. package/dashboard/dist/assets/{ElapsedCell-C0pd3pO8.js.map → ElapsedCell-C0LbM8o2.js.map} +1 -1
  39. package/dashboard/dist/assets/{EscalationListSchemaPage-BRrrftTq.js → EscalationListSchemaPage-CkEJnFKd.js} +2 -2
  40. package/dashboard/dist/assets/{EscalationListSchemaPage-BRrrftTq.js.map → EscalationListSchemaPage-CkEJnFKd.js.map} +1 -1
  41. package/dashboard/dist/assets/{EscalationSchemaPage-ChawQh5H.js → EscalationSchemaPage-CnlwGAIE.js} +2 -2
  42. package/dashboard/dist/assets/{EscalationSchemaPage-ChawQh5H.js.map → EscalationSchemaPage-CnlwGAIE.js.map} +1 -1
  43. package/dashboard/dist/assets/{EscalationsOverview-D3dFDffZ.js → EscalationsOverview-DFM-f7do.js} +2 -2
  44. package/dashboard/dist/assets/{EscalationsOverview-D3dFDffZ.js.map → EscalationsOverview-DFM-f7do.js.map} +1 -1
  45. package/dashboard/dist/assets/{EventTable-C6vkJJcQ.js → EventTable-Q3iICRf_.js} +2 -2
  46. package/dashboard/dist/assets/{EventTable-C6vkJJcQ.js.map → EventTable-Q3iICRf_.js.map} +1 -1
  47. package/dashboard/dist/assets/{FilterBar-OqpCEYW2.js → FilterBar-B0taDH7I.js} +2 -2
  48. package/dashboard/dist/assets/{FilterBar-OqpCEYW2.js.map → FilterBar-B0taDH7I.js.map} +1 -1
  49. package/dashboard/dist/assets/{GraphInvokePage-CJOyaU4g.js → GraphInvokePage-B_P3pJeA.js} +2 -2
  50. package/dashboard/dist/assets/{GraphInvokePage-CJOyaU4g.js.map → GraphInvokePage-B_P3pJeA.js.map} +1 -1
  51. package/dashboard/dist/assets/{HomePage-DxJz7AQ7.js → HomePage-lu88PzQH.js} +2 -2
  52. package/dashboard/dist/assets/{HomePage-DxJz7AQ7.js.map → HomePage-lu88PzQH.js.map} +1 -1
  53. package/dashboard/dist/assets/{ListToolbar-B6ZoJ4Rd.js → ListToolbar-ueCQtu5C.js} +2 -2
  54. package/dashboard/dist/assets/{ListToolbar-B6ZoJ4Rd.js.map → ListToolbar-ueCQtu5C.js.map} +1 -1
  55. package/dashboard/dist/assets/{McpOverview-YPY-lX3M.js → McpOverview-DMaRUXnA.js} +2 -2
  56. package/dashboard/dist/assets/{McpOverview-YPY-lX3M.js.map → McpOverview-DMaRUXnA.js.map} +1 -1
  57. package/dashboard/dist/assets/{McpQueryDetailPage-Ct3Mb1R2.js → McpQueryDetailPage-D6YSD94n.js} +2 -2
  58. package/dashboard/dist/assets/{McpQueryDetailPage-Ct3Mb1R2.js.map → McpQueryDetailPage-D6YSD94n.js.map} +1 -1
  59. package/dashboard/dist/assets/{McpQueryPage-C5-AQvnp.js → McpQueryPage-CNGNB59o.js} +2 -2
  60. package/dashboard/dist/assets/{McpQueryPage-C5-AQvnp.js.map → McpQueryPage-CNGNB59o.js.map} +1 -1
  61. package/dashboard/dist/assets/{McpRunDetailPage-Bl12usuN.js → McpRunDetailPage-CJ9hDTNs.js} +2 -2
  62. package/dashboard/dist/assets/{McpRunDetailPage-Bl12usuN.js.map → McpRunDetailPage-CJ9hDTNs.js.map} +1 -1
  63. package/dashboard/dist/assets/{McpRunsPage-PRAQPR-H.js → McpRunsPage-_UaoIwzX.js} +2 -2
  64. package/dashboard/dist/assets/{McpRunsPage-PRAQPR-H.js.map → McpRunsPage-_UaoIwzX.js.map} +1 -1
  65. package/dashboard/dist/assets/{OperationsPage-DLGNcE-b.js → OperationsPage-CTfwuWXR.js} +2 -2
  66. package/dashboard/dist/assets/{OperationsPage-DLGNcE-b.js.map → OperationsPage-CTfwuWXR.js.map} +1 -1
  67. package/dashboard/dist/assets/{OperatorDashboard-353PWYOD.js → OperatorDashboard-DMPJmgP_.js} +2 -2
  68. package/dashboard/dist/assets/{OperatorDashboard-353PWYOD.js.map → OperatorDashboard-DMPJmgP_.js.map} +1 -1
  69. package/dashboard/dist/assets/{ProcessDetailPage-DyB979ge.js → ProcessDetailPage-CxJ5BSDk.js} +2 -2
  70. package/dashboard/dist/assets/{ProcessDetailPage-DyB979ge.js.map → ProcessDetailPage-CxJ5BSDk.js.map} +1 -1
  71. package/dashboard/dist/assets/{ProcessesListPage-BPi9CNxQ.js → ProcessesListPage-GQMOo5Wo.js} +2 -2
  72. package/dashboard/dist/assets/{ProcessesListPage-BPi9CNxQ.js.map → ProcessesListPage-GQMOo5Wo.js.map} +1 -1
  73. package/dashboard/dist/assets/{RoleDetailPage-D6K3tdNO.js → RoleDetailPage-Bh5qdI0w.js} +2 -2
  74. package/dashboard/dist/assets/{RoleDetailPage-D6K3tdNO.js.map → RoleDetailPage-Bh5qdI0w.js.map} +1 -1
  75. package/dashboard/dist/assets/{RolesPage-C_i2RLwv.js → RolesPage-BIg3_Em6.js} +2 -2
  76. package/dashboard/dist/assets/{RolesPage-C_i2RLwv.js.map → RolesPage-BIg3_Em6.js.map} +1 -1
  77. package/dashboard/dist/assets/{RunAsSelector-CWBQWKM0.js → RunAsSelector-DQp_keSD.js} +2 -2
  78. package/dashboard/dist/assets/{RunAsSelector-CWBQWKM0.js.map → RunAsSelector-DQp_keSD.js.map} +1 -1
  79. package/dashboard/dist/assets/{StickyPagination-4cY0OXWj.js → StickyPagination-qLaLa33X.js} +2 -2
  80. package/dashboard/dist/assets/{StickyPagination-4cY0OXWj.js.map → StickyPagination-qLaLa33X.js.map} +1 -1
  81. package/dashboard/dist/assets/{StreamMessageDetail-DxA7AzOR.js → StreamMessageDetail-Bi37x95H.js} +2 -2
  82. package/dashboard/dist/assets/{StreamMessageDetail-DxA7AzOR.js.map → StreamMessageDetail-Bi37x95H.js.map} +1 -1
  83. package/dashboard/dist/assets/{SwimlaneTimeline-BlinxMjc.js → SwimlaneTimeline-BdNhoiW8.js} +2 -2
  84. package/dashboard/dist/assets/{SwimlaneTimeline-BlinxMjc.js.map → SwimlaneTimeline-BdNhoiW8.js.map} +1 -1
  85. package/dashboard/dist/assets/{TaskDetailPage-Cbr6Bzx3.js → TaskDetailPage-ngdXRgQp.js} +2 -2
  86. package/dashboard/dist/assets/{TaskDetailPage-Cbr6Bzx3.js.map → TaskDetailPage-ngdXRgQp.js.map} +1 -1
  87. package/dashboard/dist/assets/{TasksListPage-DNjZbo42.js → TasksListPage-BIE7nrdE.js} +2 -2
  88. package/dashboard/dist/assets/{TasksListPage-DNjZbo42.js.map → TasksListPage-BIE7nrdE.js.map} +1 -1
  89. package/dashboard/dist/assets/{TimeAgo-BEOuisPG.js → TimeAgo-C6FZSNZp.js} +2 -2
  90. package/dashboard/dist/assets/{TimeAgo-BEOuisPG.js.map → TimeAgo-C6FZSNZp.js.map} +1 -1
  91. package/dashboard/dist/assets/{TimestampCell--CLqQOJa.js → TimestampCell-DI5zPUgV.js} +2 -2
  92. package/dashboard/dist/assets/{TimestampCell--CLqQOJa.js.map → TimestampCell-DI5zPUgV.js.map} +1 -1
  93. package/dashboard/dist/assets/{ToolTestPanel-x7po38Fn.js → ToolTestPanel-Dli94RPI.js} +2 -2
  94. package/dashboard/dist/assets/{ToolTestPanel-x7po38Fn.js.map → ToolTestPanel-Dli94RPI.js.map} +1 -1
  95. package/dashboard/dist/assets/{TopicDetailPage-Bay2lUOW.js → TopicDetailPage-vPtXb7gD.js} +2 -2
  96. package/dashboard/dist/assets/{TopicDetailPage-Bay2lUOW.js.map → TopicDetailPage-vPtXb7gD.js.map} +1 -1
  97. package/dashboard/dist/assets/{TopicsPage-Ckh6ln0h.js → TopicsPage-BwiEX0pU.js} +2 -2
  98. package/dashboard/dist/assets/{TopicsPage-Ckh6ln0h.js.map → TopicsPage-BwiEX0pU.js.map} +1 -1
  99. package/dashboard/dist/assets/{UserName-Doe8DDXc.js → UserName-YozoXJA1.js} +2 -2
  100. package/dashboard/dist/assets/{UserName-Doe8DDXc.js.map → UserName-YozoXJA1.js.map} +1 -1
  101. package/dashboard/dist/assets/{WorkflowExecutionPage-DPymyMAM.js → WorkflowExecutionPage-Bce8g08l.js} +2 -2
  102. package/dashboard/dist/assets/{WorkflowExecutionPage-DPymyMAM.js.map → WorkflowExecutionPage-Bce8g08l.js.map} +1 -1
  103. package/dashboard/dist/assets/{WorkflowsDashboard-CrwdULL7.js → WorkflowsDashboard-DpVAH35I.js} +2 -2
  104. package/dashboard/dist/assets/{WorkflowsDashboard-CrwdULL7.js.map → WorkflowsDashboard-DpVAH35I.js.map} +1 -1
  105. package/dashboard/dist/assets/{WorkflowsOverview-YoPFHjOb.js → WorkflowsOverview-Bp2pxXJO.js} +2 -2
  106. package/dashboard/dist/assets/{WorkflowsOverview-YoPFHjOb.js.map → WorkflowsOverview-Bp2pxXJO.js.map} +1 -1
  107. package/dashboard/dist/assets/{YamlWorkflowDetailPage-B4H8WvSt.js → YamlWorkflowDetailPage-CL_kD0mX.js} +2 -2
  108. package/dashboard/dist/assets/{YamlWorkflowDetailPage-B4H8WvSt.js.map → YamlWorkflowDetailPage-CL_kD0mX.js.map} +1 -1
  109. package/dashboard/dist/assets/{YamlWorkflowsPage-gburzX11.js → YamlWorkflowsPage-Dtt3x3_T.js} +2 -2
  110. package/dashboard/dist/assets/{YamlWorkflowsPage-gburzX11.js.map → YamlWorkflowsPage-Dtt3x3_T.js.map} +1 -1
  111. package/dashboard/dist/assets/{agents-BwrYw_S8.js → agents-xhtLVBwq.js} +2 -2
  112. package/dashboard/dist/assets/{agents-BwrYw_S8.js.map → agents-xhtLVBwq.js.map} +1 -1
  113. package/dashboard/dist/assets/{bots-C0vU7IG9.js → bots-DZ1MQUms.js} +2 -2
  114. package/dashboard/dist/assets/{bots-C0vU7IG9.js.map → bots-DZ1MQUms.js.map} +1 -1
  115. package/dashboard/dist/assets/{capabilities-DOE8jqWc.js → capabilities-B8j2h7Jn.js} +2 -2
  116. package/dashboard/dist/assets/{capabilities-DOE8jqWc.js.map → capabilities-B8j2h7Jn.js.map} +1 -1
  117. package/dashboard/dist/assets/{controlplane-TtPp8V9E.js → controlplane-DKijNA6h.js} +2 -2
  118. package/dashboard/dist/assets/{controlplane-TtPp8V9E.js.map → controlplane-DKijNA6h.js.map} +1 -1
  119. package/dashboard/dist/assets/{escalation-columns-Cyp-K89u.js → escalation-columns-DjoZ4dDb.js} +2 -2
  120. package/dashboard/dist/assets/{escalation-columns-Cyp-K89u.js.map → escalation-columns-DjoZ4dDb.js.map} +1 -1
  121. package/dashboard/dist/assets/{index-zuK6pSyZ.js → index-0SzWFShg.js} +2 -2
  122. package/dashboard/dist/assets/{index-zuK6pSyZ.js.map → index-0SzWFShg.js.map} +1 -1
  123. package/dashboard/dist/assets/{index-j-X71wT4.js → index-B0ktIiOY.js} +2 -2
  124. package/dashboard/dist/assets/{index-j-X71wT4.js.map → index-B0ktIiOY.js.map} +1 -1
  125. package/dashboard/dist/assets/{index-CkwNuQzx.js → index-BCIJE--_.js} +2 -2
  126. package/dashboard/dist/assets/{index-CkwNuQzx.js.map → index-BCIJE--_.js.map} +1 -1
  127. package/dashboard/dist/assets/{index-DFJm742Y.js → index-BqeQGQ4K.js} +2 -2
  128. package/dashboard/dist/assets/{index-DFJm742Y.js.map → index-BqeQGQ4K.js.map} +1 -1
  129. package/dashboard/dist/assets/{index-BmsZnbW1.js → index-C6UuVkz7.js} +3 -3
  130. package/dashboard/dist/assets/{index-BmsZnbW1.js.map → index-C6UuVkz7.js.map} +1 -1
  131. package/dashboard/dist/assets/{index-Dh6F3Wbx.js → index-CMv6YMJY.js} +2 -2
  132. package/dashboard/dist/assets/{index-Dh6F3Wbx.js.map → index-CMv6YMJY.js.map} +1 -1
  133. package/dashboard/dist/assets/{index-CVZOAQVo.js → index-ChHD9p_I.js} +2 -2
  134. package/dashboard/dist/assets/{index-CVZOAQVo.js.map → index-ChHD9p_I.js.map} +1 -1
  135. package/dashboard/dist/assets/{index-CR1_qhQf.js → index-Cp1jJHm1.js} +2 -2
  136. package/dashboard/dist/assets/{index-CR1_qhQf.js.map → index-Cp1jJHm1.js.map} +1 -1
  137. package/dashboard/dist/assets/{index-Bl-09ECD.js → index-DWDEa8jS.js} +2 -2
  138. package/dashboard/dist/assets/{index-Bl-09ECD.js.map → index-DWDEa8jS.js.map} +1 -1
  139. package/dashboard/dist/assets/{index-stu9QXmW.js → index-DYCCUmSM.js} +2 -2
  140. package/dashboard/dist/assets/{index-stu9QXmW.js.map → index-DYCCUmSM.js.map} +1 -1
  141. package/dashboard/dist/assets/{index-b7P6Hjd3.js → index-DcDEJ6b_.js} +2 -2
  142. package/dashboard/dist/assets/{index-b7P6Hjd3.js.map → index-DcDEJ6b_.js.map} +1 -1
  143. package/dashboard/dist/assets/index-Dh5Y3hq7.js +5 -0
  144. package/dashboard/dist/assets/index-Dh5Y3hq7.js.map +1 -0
  145. package/dashboard/dist/assets/{index-BTsTdaRt.js → index-DrPWIFSv.js} +2 -2
  146. package/dashboard/dist/assets/{index-BTsTdaRt.js.map → index-DrPWIFSv.js.map} +1 -1
  147. package/dashboard/dist/assets/index-WSGppNeK.css +1 -0
  148. package/dashboard/dist/assets/{knowledge-DD9NIG9d.js → knowledge-Dl3cOfFR.js} +2 -2
  149. package/dashboard/dist/assets/{knowledge-DD9NIG9d.js.map → knowledge-Dl3cOfFR.js.map} +1 -1
  150. package/dashboard/dist/assets/{mcp-C4upVuuP.js → mcp-BwjeqkHn.js} +2 -2
  151. package/dashboard/dist/assets/{mcp-C4upVuuP.js.map → mcp-BwjeqkHn.js.map} +1 -1
  152. package/dashboard/dist/assets/{mcp-query-JEk3cZyH.js → mcp-query-C1Rlt4az.js} +2 -2
  153. package/dashboard/dist/assets/{mcp-query-JEk3cZyH.js.map → mcp-query-C1Rlt4az.js.map} +1 -1
  154. package/dashboard/dist/assets/{pipelines-BkBpa2Y7.js → pipelines-BGIUgIH_.js} +2 -2
  155. package/dashboard/dist/assets/{pipelines-BkBpa2Y7.js.map → pipelines-BGIUgIH_.js.map} +1 -1
  156. package/dashboard/dist/assets/{tasks-B7QVagGw.js → tasks-CnC1xEaD.js} +2 -2
  157. package/dashboard/dist/assets/{tasks-B7QVagGw.js.map → tasks-CnC1xEaD.js.map} +1 -1
  158. package/dashboard/dist/assets/{topics-C55xydgR.js → topics-C6EcHi07.js} +2 -2
  159. package/dashboard/dist/assets/{topics-C55xydgR.js.map → topics-C6EcHi07.js.map} +1 -1
  160. package/dashboard/dist/assets/{useEventHooks-CKpFrpjc.js → useEventHooks-Cyq4DiQA.js} +2 -2
  161. package/dashboard/dist/assets/{useEventHooks-CKpFrpjc.js.map → useEventHooks-Cyq4DiQA.js.map} +1 -1
  162. package/dashboard/dist/assets/{useNamespace-BJbjZubz.js → useNamespace-Ci_oA5Tq.js} +2 -2
  163. package/dashboard/dist/assets/{useNamespace-BJbjZubz.js.map → useNamespace-Ci_oA5Tq.js.map} +1 -1
  164. package/dashboard/dist/assets/{useYamlActivityEvents-C80oooy6.js → useYamlActivityEvents-u8RUiMma.js} +2 -2
  165. package/dashboard/dist/assets/{useYamlActivityEvents-C80oooy6.js.map → useYamlActivityEvents-u8RUiMma.js.map} +1 -1
  166. package/dashboard/dist/assets/{users-BdvakxB1.js → users-DtiYvg8z.js} +2 -2
  167. package/dashboard/dist/assets/{users-BdvakxB1.js.map → users-DtiYvg8z.js.map} +1 -1
  168. package/dashboard/dist/assets/{workflows-DYTqfgom.js → workflows-BysPDsh9.js} +2 -2
  169. package/dashboard/dist/assets/{workflows-DYTqfgom.js.map → workflows-BysPDsh9.js.map} +1 -1
  170. package/dashboard/dist/assets/{yaml-workflows-D3o7rHzN.js → yaml-workflows-31qtxg5W.js} +2 -2
  171. package/dashboard/dist/assets/{yaml-workflows-D3o7rHzN.js.map → yaml-workflows-31qtxg5W.js.map} +1 -1
  172. package/dashboard/dist/index.html +2 -2
  173. package/docs/api/http/escalations.md +12 -3
  174. package/docs/hitl/escalation.md +21 -0
  175. package/docs/hitl/x-lt-embed.md +60 -0
  176. package/package.json +2 -2
  177. package/dashboard/dist/assets/index-Cm42dgjx.css +0 -1
  178. package/dashboard/dist/assets/index-Wu6GCvUq.js +0 -5
  179. package/dashboard/dist/assets/index-Wu6GCvUq.js.map +0 -1
@@ -33,19 +33,31 @@ export declare function bulkClaim(input: {
33
33
  durationMinutes?: number;
34
34
  }, auth: LTApiAuth): Promise<LTApiResult>;
35
35
  /**
36
- * Assign multiple escalations to a specific user.
36
+ * Assign multiple escalations to a specific user — by id-set OR by query
37
+ * (exactly one).
38
+ *
39
+ * The query form (`{ role, facets? }`) is one atomic statement: selection and
40
+ * claim happen in the same UPDATE, so a row that re-parks between a search and
41
+ * an ids-assign is still captured. Use it whenever the population is
42
+ * describable by filter (e.g. a walk's plates by `walkId` facet).
37
43
  *
38
44
  * Non-superadmin callers must verify the target user holds each
39
- * escalation's role. Publishes claim events for assigned items.
45
+ * escalation's role (the query form requires exactly the declared role).
46
+ * Publishes claim events for assigned items.
40
47
  *
41
- * @param input.ids — array of escalation UUIDs
48
+ * @param input.ids — array of escalation UUIDs (ids form)
49
+ * @param input.query — `{ role, facets? }` selector (query form)
42
50
  * @param input.targetUserId — user to assign to
43
51
  * @param input.durationMinutes — assignment duration (default: 30)
44
52
  * @param auth — authenticated user context
45
53
  * @returns `{ status: 200, data: { assigned, skipped } }`
46
54
  */
47
55
  export declare function bulkAssign(input: {
48
- ids: string[];
56
+ ids?: string[];
57
+ query?: {
58
+ role: string;
59
+ facets?: Record<string, unknown>;
60
+ };
49
61
  targetUserId: string;
50
62
  durationMinutes?: number;
51
63
  }, auth: LTApiAuth): Promise<LTApiResult>;
@@ -117,12 +117,20 @@ async function bulkClaim(input, auth) {
117
117
  }
118
118
  }
119
119
  /**
120
- * Assign multiple escalations to a specific user.
120
+ * Assign multiple escalations to a specific user — by id-set OR by query
121
+ * (exactly one).
122
+ *
123
+ * The query form (`{ role, facets? }`) is one atomic statement: selection and
124
+ * claim happen in the same UPDATE, so a row that re-parks between a search and
125
+ * an ids-assign is still captured. Use it whenever the population is
126
+ * describable by filter (e.g. a walk's plates by `walkId` facet).
121
127
  *
122
128
  * Non-superadmin callers must verify the target user holds each
123
- * escalation's role. Publishes claim events for assigned items.
129
+ * escalation's role (the query form requires exactly the declared role).
130
+ * Publishes claim events for assigned items.
124
131
  *
125
- * @param input.ids — array of escalation UUIDs
132
+ * @param input.ids — array of escalation UUIDs (ids form)
133
+ * @param input.query — `{ role, facets? }` selector (query form)
126
134
  * @param input.targetUserId — user to assign to
127
135
  * @param input.durationMinutes — assignment duration (default: 30)
128
136
  * @param auth — authenticated user context
@@ -130,13 +138,40 @@ async function bulkClaim(input, auth) {
130
138
  */
131
139
  async function bulkAssign(input, auth) {
132
140
  try {
133
- const { ids, targetUserId, durationMinutes } = input;
134
- if (!(0, helpers_1.validateIds)(ids)) {
135
- return { status: 400, error: 'ids must be a non-empty array' };
136
- }
141
+ const { ids, query, targetUserId, durationMinutes } = input;
137
142
  if (!targetUserId || typeof targetUserId !== 'string') {
138
143
  return { status: 400, error: 'targetUserId is required' };
139
144
  }
145
+ const hasIds = Array.isArray(ids) && ids.length > 0;
146
+ const hasQuery = !!query && typeof query === 'object';
147
+ if (hasIds === hasQuery) {
148
+ return { status: 400, error: 'provide exactly one of ids or query' };
149
+ }
150
+ if (hasQuery) {
151
+ if (!query.role || typeof query.role !== 'string') {
152
+ return { status: 400, error: 'query.role is required' };
153
+ }
154
+ // RBAC, query form: the caller must hold the queried role (or global),
155
+ // and the target user must hold it — one role check instead of per-id.
156
+ const hasGlobal = await (0, helpers_1.hasGlobalEscalationAccess)(auth.userId);
157
+ if (!hasGlobal) {
158
+ const callerHasRole = await userService.hasRole(auth.userId, query.role);
159
+ if (!callerHasRole) {
160
+ return { status: 404, error: 'One or more escalations not found' };
161
+ }
162
+ const targetHasRole = await userService.hasRole(targetUserId, query.role);
163
+ if (!targetHasRole) {
164
+ return { status: 400, error: `Target user does not hold the "${query.role}" role` };
165
+ }
166
+ }
167
+ const result = await escalationService.bulkAssignEscalationsByQuery({ role: query.role, facets: query.facets }, targetUserId, durationMinutes ?? 30);
168
+ if (result.assigned > 0)
169
+ (0, helpers_1.publishBulkClaimEvents)(result.ids, targetUserId);
170
+ return { status: 200, data: { assigned: result.assigned, skipped: 0 } };
171
+ }
172
+ if (!(0, helpers_1.validateIds)(ids)) {
173
+ return { status: 400, error: 'ids must be a non-empty array' };
174
+ }
140
175
  const perm = await (0, helpers_1.checkBulkPermission)(auth.userId, ids);
141
176
  if (!perm.allowed)
142
177
  return perm;
@@ -39,6 +39,7 @@ exports.resolveByIds = resolveByIds;
39
39
  exports.resolveAllOrNone = resolveAllOrNone;
40
40
  exports.validationFailure = validationFailure;
41
41
  const escalationService = __importStar(require("../../services/escalation"));
42
+ const userService = __importStar(require("../../services/user"));
42
43
  const taskService = __importStar(require("../../services/task"));
43
44
  const escalation_strategy_1 = require("../../services/escalation-strategy");
44
45
  const ephemeral_1 = require("../../services/iam/ephemeral");
@@ -103,7 +104,14 @@ async function resolveEscalation(input, auth) {
103
104
  // The resolver payload is stored exactly as submitted — its shape is the
104
105
  // workflow's contract, formed by the caller (the React app maps the form to
105
106
  // the payload via x-lt-bind before submitting). No server-side transform.
106
- // `metadata` (the outcome patch) is never written separately — it rides WITH the
107
+ // Resolution provenance, both surfaces at once: `resolvedBy` rides the
108
+ // signal to the waiting workflow ($resolution — see conditionLT), and
109
+ // `resolved_by` merges into the row's GIN-indexed metadata inside the same
110
+ // atomic resolve, making "who resolved it" `@>`-queryable without a
111
+ // follow-up read.
112
+ const resolvedBy = await resolverIdentity(auth);
113
+ const outcome = { ...metadata, resolved_by: auth.userId };
114
+ // `outcome` (the outcome patch) is never written separately — it rides WITH the
107
115
  // resolverPayload to whichever path performs the resolve, so it merges inside the
108
116
  // single status='pending'-guarded UPDATE (HotMesh `resolve(metadata)`). Paths that
109
117
  // resolve here pass it as the 3rd arg; paths that resume a workflow carry it on the
@@ -111,19 +119,19 @@ async function resolveEscalation(input, auth) {
111
119
  // Path A: conditionLT signal
112
120
  const metadataSignalId = escalation.metadata?.signal_id;
113
121
  if (metadataSignalId && escalation.workflow_id && escalation.task_queue && escalation.workflow_type) {
114
- return resolveViaConditionSignal(escalation, resolverPayload, metadata);
122
+ return resolveViaConditionSignal(escalation, resolverPayload, outcome, resolvedBy);
115
123
  }
116
124
  // Path B: waitFor signal routing
117
125
  const signalRouting = escalation.metadata?.signal_routing;
118
126
  if (signalRouting?.signalId) {
119
- return resolveViaSignalRouting(escalation, resolverPayload, metadata);
127
+ return resolveViaSignalRouting(escalation, resolverPayload, outcome, resolvedBy);
120
128
  }
121
129
  // Path 0: efficient (atomic) escalation — signal_key resumes in place.
122
130
  // The row was written inside the workflow's Leg1 checkpoint via
123
131
  // `condition(signalId, config)`. The SDK's resolve marks it resolved AND
124
132
  // delivers the signal to `signal_key`, resuming THIS job — no re-run.
125
133
  if (escalation.signal_key) {
126
- return resolveViaSignalKey(escalation, resolverPayload, metadata, auth.userId);
134
+ return resolveViaSignalKey(escalation, resolverPayload, outcome, auth.userId, resolvedBy);
127
135
  }
128
136
  // Path C: escalation strategy may redirect to triage
129
137
  const envelope = await reconstructEnvelope(escalation);
@@ -131,19 +139,19 @@ async function resolveEscalation(input, auth) {
131
139
  if (strategy) {
132
140
  const directive = await strategy.onResolution({ escalation, resolverPayload, envelope });
133
141
  if (directive.action === 'triage') {
134
- return resolveViaTriage(escalation, resolverPayload, directive.triageEnvelope, metadata);
142
+ return resolveViaTriage(escalation, resolverPayload, directive.triageEnvelope, outcome);
135
143
  }
136
144
  }
137
145
  // Path D: notification-only — no workflow to restart. One atomic resolve.
138
146
  if (!escalation.workflow_type || !escalation.task_queue) {
139
- const resolved = await escalationService.resolveEscalation(escalation.id, resolverPayload, metadata, auth.userId);
147
+ const resolved = await escalationService.resolveEscalation(escalation.id, resolverPayload, outcome, auth.userId);
140
148
  if (!resolved) {
141
149
  return { status: 409, error: 'Escalation not available for resolution' };
142
150
  }
143
151
  return { status: 200, data: { acknowledged: true, escalationId: escalation.id } };
144
152
  }
145
153
  // Path E: standard re-run
146
- return resolveViaRerun(escalation, envelope, resolverPayload, metadata);
154
+ return resolveViaRerun(escalation, envelope, resolverPayload, outcome);
147
155
  }
148
156
  catch (err) {
149
157
  return { status: 500, error: err.message };
@@ -178,7 +186,11 @@ async function resolveBySignalKey(input, auth) {
178
186
  return validationFailure(violation);
179
187
  // The payload is delivered as the signal the parked workflow's condition()
180
188
  // receives — stored exactly as submitted (the caller formed its shape).
181
- return resolveViaSignalKey(escalation, resolverPayload, metadata);
189
+ // Same provenance contract as the interactive path: identity on the signal,
190
+ // resolved_by in the row metadata.
191
+ const resolvedBy = await resolverIdentity(auth);
192
+ const outcome = { ...metadata, resolved_by: auth.userId };
193
+ return resolveViaSignalKey(escalation, resolverPayload, outcome, undefined, resolvedBy);
182
194
  }
183
195
  catch (err) {
184
196
  return { status: 500, error: err.message };
@@ -243,7 +255,7 @@ async function resolveByIds(input, auth) {
243
255
  return bulkValidationFailure(failed);
244
256
  }
245
257
  }
246
- const resolved = await escalationService.resolveEscalationsByIds(ids, resolverPayload, metadata);
258
+ const resolved = await escalationService.resolveEscalationsByIds(ids, resolverPayload, { ...metadata, resolved_by: auth.userId });
247
259
  return { status: 200, data: { resolved: resolved.length, escalationIds: resolved.map((e) => e.id) } };
248
260
  }
249
261
  catch (err) {
@@ -347,7 +359,7 @@ async function resolveAllOrNone(input, auth) {
347
359
  id: item.id,
348
360
  resolverPayload: await redactPasswords(item.resolverPayload, rowById.get(item.id)?.metadata?.form_schema),
349
361
  })));
350
- const result = await escalationService.resolveEscalationsAllOrNone(serviceItems, metadata, requireClaimed ? auth.userId : undefined);
362
+ const result = await escalationService.resolveEscalationsAllOrNone(serviceItems, { ...metadata, resolved_by: auth.userId }, requireClaimed ? auth.userId : undefined, await resolverIdentity(auth));
351
363
  if (!result.ok) {
352
364
  const error = 'One or more escalations blocked the batch; nothing was resolved';
353
365
  return {
@@ -367,17 +379,20 @@ async function resolveAllOrNone(input, auth) {
367
379
  }
368
380
  // ── Resolution paths ─────────────────────────────────────────────────────
369
381
  /** Path A: lightweight conditionLT signal — inject $escalation_id and signal the running workflow. */
370
- async function resolveViaConditionSignal(escalation, resolverPayload, metadata) {
382
+ async function resolveViaConditionSignal(escalation, resolverPayload, metadata, resolvedBy) {
371
383
  const signalId = escalation.metadata.signal_id;
372
384
  const client = (0, workers_1.createClient)();
373
385
  const handle = await client.workflow.getHandle(escalation.task_queue, escalation.workflow_type, escalation.workflow_id);
374
386
  // The row is resolved downstream by the workflow's `conditionLT` → `ltResolveEscalation`.
375
387
  // Carry the outcome patch on the signal ($escalation_metadata, symmetric to $escalation_id)
376
388
  // so it merges inside that single atomic resolve — never a separate write here.
389
+ // $resolution (provenance) is surfaced to the workflow by conditionLT and stripped
390
+ // from the stored resolver_payload, same as the other $-control keys.
377
391
  await handle.signal(signalId, {
378
392
  ...resolverPayload,
379
393
  $escalation_id: escalation.id,
380
394
  ...(metadata ? { $escalation_metadata: metadata } : {}),
395
+ ...(resolvedBy ? { $resolution: resolutionOf(escalation.id, resolvedBy) } : {}),
381
396
  });
382
397
  // Event published by service layer (services/escalation/crud.ts)
383
398
  return signaledResult(escalation, escalation.workflow_id);
@@ -388,13 +403,14 @@ async function resolveViaConditionSignal(escalation, resolverPayload, metadata)
388
403
  * transaction, so the original job resumes in place (no re-run, no separate
389
404
  * resolve activity). Password fields are redacted before they enter the signal.
390
405
  */
391
- async function resolveViaSignalKey(escalation, resolverPayload, metadata, assertClaim) {
406
+ async function resolveViaSignalKey(escalation, resolverPayload, metadata, assertClaim, resolvedBy) {
392
407
  const signalPayload = await redactPasswords(resolverPayload, escalation.metadata?.form_schema);
393
408
  // One atomic call: status→resolved, signal delivered, and the outcome patch merged
394
409
  // into the GIN-indexed metadata — all inside the single WHERE-guarded UPDATE.
395
410
  // `assertClaim` (interactive path only) makes the claim-liveness gate part of
396
411
  // that same UPDATE; the webhook path (resolveBySignalKey) stays claim-agnostic.
397
- const resolved = await escalationService.resolveEscalation(escalation.id, signalPayload, metadata, assertClaim);
412
+ // `resolvedBy` rides the SDK signal as $resolution — never the stored payload.
413
+ const resolved = await escalationService.resolveEscalation(escalation.id, signalPayload, metadata, assertClaim, resolvedBy);
398
414
  if (!resolved) {
399
415
  return { status: 409, error: 'Escalation not available for resolution' };
400
416
  }
@@ -402,7 +418,7 @@ async function resolveViaSignalKey(escalation, resolverPayload, metadata, assert
402
418
  return signaledResult(escalation, escalation.workflow_id || '');
403
419
  }
404
420
  /** Path B: waitFor signal escalation — signal via YAML engine or Durable handle. */
405
- async function resolveViaSignalRouting(escalation, resolverPayload, metadata) {
421
+ async function resolveViaSignalRouting(escalation, resolverPayload, metadata, resolvedBy) {
406
422
  const signalRouting = escalation.metadata.signal_routing;
407
423
  const signalPayload = await redactPasswords(resolverPayload, escalation.metadata?.form_schema);
408
424
  if (signalRouting.engine === 'yaml' && signalRouting.hookTopic && signalRouting.appId) {
@@ -419,7 +435,11 @@ async function resolveViaSignalRouting(escalation, resolverPayload, metadata) {
419
435
  else if (signalRouting.workflowId) {
420
436
  const client = (0, workers_1.createClient)();
421
437
  const handle = await client.workflow.getHandle(signalRouting.taskQueue, signalRouting.workflowType, signalRouting.workflowId);
422
- await handle.signal(signalRouting.signalId, signalPayload);
438
+ // Provenance rides the SIGNAL only — the resolve below persists the clean payload.
439
+ await handle.signal(signalRouting.signalId, {
440
+ ...signalPayload,
441
+ ...(resolvedBy ? { $resolution: resolutionOf(escalation.id, resolvedBy) } : {}),
442
+ });
423
443
  }
424
444
  // Durable resolves here — one atomic call carries the outcome patch.
425
445
  // Persist the SAME redacted payload that was delivered to the signal: the raw
@@ -497,6 +517,28 @@ async function resolveViaRerun(escalation, envelope, resolverPayload, metadata)
497
517
  };
498
518
  }
499
519
  // ── Shared helpers ───────────────────────────────────────────────────────
520
+ /**
521
+ * The resolving principal's identity for `$resolution` delivery. The email is
522
+ * best-effort (one indexed read, tolerated failure) — the id alone satisfies
523
+ * the provenance contract.
524
+ */
525
+ async function resolverIdentity(auth) {
526
+ try {
527
+ const user = await userService.getUser(auth.userId);
528
+ return { id: auth.userId, ...(user?.email ? { email: user.email } : {}) };
529
+ }
530
+ catch {
531
+ return { id: auth.userId };
532
+ }
533
+ }
534
+ /** The `$resolution` provenance object injected into legacy-path signals. */
535
+ function resolutionOf(escalationId, resolvedBy) {
536
+ return {
537
+ escalationId,
538
+ resolvedBy: resolvedBy.id,
539
+ ...(resolvedBy.email ? { resolvedByEmail: resolvedBy.email } : {}),
540
+ };
541
+ }
500
542
  function signaledResult(escalation, workflowId) {
501
543
  return {
502
544
  status: 200,
@@ -51,6 +51,7 @@ function registerBulkRoutes(router) {
51
51
  router.post('/bulk-assign', async (req, res) => {
52
52
  const result = await api.bulkAssign({
53
53
  ids: req.body?.ids,
54
+ query: req.body?.query,
54
55
  targetUserId: req.body?.targetUserId,
55
56
  durationMinutes: req.body?.durationMinutes,
56
57
  }, req.auth);
@@ -171,7 +171,11 @@ export declare function createClient(options?: LTClientOptions): {
171
171
  durationMinutes?: number;
172
172
  }, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
173
173
  bulkAssign: (input: {
174
- ids: string[];
174
+ ids?: string[];
175
+ query?: {
176
+ role: string;
177
+ facets?: Record<string, unknown>;
178
+ };
175
179
  targetUserId: string;
176
180
  durationMinutes?: number;
177
181
  }, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
@@ -15,6 +15,20 @@ export declare function bulkAssignEscalations(ids: string[], targetUserId: strin
15
15
  assigned: number;
16
16
  skipped: number;
17
17
  }>;
18
+ /**
19
+ * Bulk assign by query: one atomic UPDATE selects and claims every pending,
20
+ * claimable row matching role + facet containment — no search-then-assign
21
+ * window. A row that re-parks between a search and an ids-assign is invisible
22
+ * to the ids form but claimed by this one. Returns the assigned row ids so
23
+ * callers can publish per-row events.
24
+ */
25
+ export declare function bulkAssignEscalationsByQuery(query: {
26
+ role: string;
27
+ facets?: Record<string, unknown>;
28
+ }, targetUserId: string, durationMinutes?: number): Promise<{
29
+ assigned: number;
30
+ ids: string[];
31
+ }>;
18
32
  /**
19
33
  * Bulk reassign escalations to a different role.
20
34
  * Clears assignment on all affected rows.
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.bulkClaimEscalations = bulkClaimEscalations;
4
4
  exports.bulkAssignEscalations = bulkAssignEscalations;
5
+ exports.bulkAssignEscalationsByQuery = bulkAssignEscalationsByQuery;
5
6
  exports.bulkEscalateToRole = bulkEscalateToRole;
6
7
  exports.bulkCancelEscalations = bulkCancelEscalations;
7
8
  exports.bulkResolveForTriage = bulkResolveForTriage;
@@ -32,6 +33,22 @@ async function bulkAssignEscalations(ids, targetUserId, durationMinutes = 30) {
32
33
  });
33
34
  return { assigned: claimed, skipped };
34
35
  }
36
+ /**
37
+ * Bulk assign by query: one atomic UPDATE selects and claims every pending,
38
+ * claimable row matching role + facet containment — no search-then-assign
39
+ * window. A row that re-parks between a search and an ids-assign is invisible
40
+ * to the ids form but claimed by this one. Returns the assigned row ids so
41
+ * callers can publish per-row events.
42
+ */
43
+ async function bulkAssignEscalationsByQuery(query, targetUserId, durationMinutes = 30) {
44
+ const client = await (0, client_1.escalations)();
45
+ const { claimed, entries } = await client.claimManyByQuery({
46
+ query: { role: query.role, metadata: query.facets },
47
+ assignee: targetUserId,
48
+ durationMinutes,
49
+ });
50
+ return { assigned: claimed, ids: entries.map((e) => e.id) };
51
+ }
35
52
  /**
36
53
  * Bulk reassign escalations to a different role.
37
54
  * Clears assignment on all affected rows.
@@ -19,8 +19,16 @@ export declare function claimEscalation(id: string, userId: string, durationMinu
19
19
  * results) into the `@>`-queryable surface alongside the creation metadata
20
20
  * ("what was intended"). Distinct from `resolverPayload`, which is delivered to
21
21
  * the waiting workflow as `condition()`'s return value and is not GIN-indexed.
22
+ *
23
+ * `resolvedBy` (optional) is delivered to the waiting workflow under the
24
+ * reserved `$resolution` signal key — resolution provenance for the workflow's
25
+ * next step (e.g. assign follow-on work to whoever resolved). Never written to
26
+ * the stored `resolver_payload`.
22
27
  */
23
- export declare function resolveEscalation(id: string, resolverPayload: Record<string, any>, metadata?: Record<string, any>, assertClaim?: string): Promise<LTEscalationRecord | null>;
28
+ export declare function resolveEscalation(id: string, resolverPayload: Record<string, any>, metadata?: Record<string, any>, assertClaim?: string, resolvedBy?: {
29
+ id: string;
30
+ email?: string;
31
+ }): Promise<LTEscalationRecord | null>;
24
32
  /**
25
33
  * Resolve a SET of escalations by id in ONE guarded statement
26
34
  * (`UPDATE … WHERE id = ANY($ids) AND status='pending'`). Returns the rows that
@@ -56,7 +64,10 @@ export declare function resolveEscalationsByIds(ids: string[], resolverPayload:
56
64
  export declare function resolveEscalationsAllOrNone(items: Array<{
57
65
  id: string;
58
66
  resolverPayload: Record<string, any>;
59
- }>, metadata?: Record<string, any>, assertAssignee?: string): Promise<{
67
+ }>, metadata?: Record<string, any>, assertAssignee?: string, resolvedBy?: {
68
+ id: string;
69
+ email?: string;
70
+ }): Promise<{
60
71
  ok: true;
61
72
  escalations: LTEscalationRecord[];
62
73
  } | {
@@ -114,14 +114,19 @@ async function claimEscalation(id, userId, durationMinutes = 30) {
114
114
  * results) into the `@>`-queryable surface alongside the creation metadata
115
115
  * ("what was intended"). Distinct from `resolverPayload`, which is delivered to
116
116
  * the waiting workflow as `condition()`'s return value and is not GIN-indexed.
117
+ *
118
+ * `resolvedBy` (optional) is delivered to the waiting workflow under the
119
+ * reserved `$resolution` signal key — resolution provenance for the workflow's
120
+ * next step (e.g. assign follow-on work to whoever resolved). Never written to
121
+ * the stored `resolver_payload`.
117
122
  */
118
- async function resolveEscalation(id, resolverPayload, metadata, assertClaim) {
123
+ async function resolveEscalation(id, resolverPayload, metadata, assertClaim, resolvedBy) {
119
124
  const client = await (0, client_1.escalations)();
120
125
  // `assertClaim` rides the SDK's guarded UPDATE: no active claim lock may
121
126
  // stand against this assignee, or the resolve blocks (claim-expired /
122
127
  // claimed-by-other). The API layer's advisory pre-check (assertLiveClaimant)
123
128
  // rejects early; this assertion is the atomic arbiter.
124
- const result = await client.resolve({ id, resolverPayload, metadata, assertClaim });
129
+ const result = await client.resolve({ id, resolverPayload, metadata, assertClaim, resolvedBy });
125
130
  if (!result.ok)
126
131
  return null;
127
132
  const escalation = (0, map_1.toEscalationRecord)(result.entry);
@@ -188,11 +193,11 @@ async function resolveEscalationsByIds(ids, resolverPayload, metadata) {
188
193
  * to that principal, asserted inside the same guarded statement — closing the
189
194
  * claim-race window for claim-then-resolve flows.
190
195
  */
191
- async function resolveEscalationsAllOrNone(items, metadata, assertAssignee) {
196
+ async function resolveEscalationsAllOrNone(items, metadata, assertAssignee, resolvedBy) {
192
197
  if (items.length === 0)
193
198
  return { ok: true, escalations: [] };
194
199
  const client = await (0, client_1.escalations)();
195
- const result = await client.resolveAllOrNone({ items, metadata, assertAssignee });
200
+ const result = await client.resolveAllOrNone({ items, metadata, assertAssignee, resolvedBy });
196
201
  if (!result.ok)
197
202
  return { ok: false, failed: result.failed };
198
203
  const records = (0, map_1.toEscalationRecords)(result.entries);
@@ -73,6 +73,26 @@ export type ConditionEscalationConfig = Types.ConditionQueueConfig & {
73
73
  * }
74
74
  * ```
75
75
  *
76
+ * **Resolution provenance — the reserved `$resolution` key.** When the resolve
77
+ * carries the resolver's identity (the API layer supplies it for interactive
78
+ * and webhook resolves), the payload delivered here includes
79
+ * `$resolution: { escalationId, resolvedBy, resolvedByEmail? }`. Declare it in
80
+ * the generic to consume it — e.g. assign follow-on work to whoever resolved:
81
+ *
82
+ * ```typescript
83
+ * import type { EscalationResolution } from '@hotmeshio/hotmesh/types';
84
+ *
85
+ * const decision = await conditionLT<{
86
+ * approved: boolean;
87
+ * $resolution?: EscalationResolution;
88
+ * }>(signalId, { role: 'print-operator' });
89
+ * const resolver = decision && decision.$resolution?.resolvedBy;
90
+ * ```
91
+ *
92
+ * `$resolution` never lands in the stored `resolver_payload` audit column —
93
+ * on the legacy path below it is stripped before the durable resolve and
94
+ * re-attached to the returned payload.
95
+ *
76
96
  * **Legacy (two-step) — no config.** Create the escalation first (e.g. via
77
97
  * `ltCreateEscalation`) with `signal_id`/`signal_routing` metadata, then wait.
78
98
  * On resume the signal payload carries an injected `$escalation_id`; this helper
@@ -112,6 +112,26 @@ function toEngineConfig(escalation) {
112
112
  * }
113
113
  * ```
114
114
  *
115
+ * **Resolution provenance — the reserved `$resolution` key.** When the resolve
116
+ * carries the resolver's identity (the API layer supplies it for interactive
117
+ * and webhook resolves), the payload delivered here includes
118
+ * `$resolution: { escalationId, resolvedBy, resolvedByEmail? }`. Declare it in
119
+ * the generic to consume it — e.g. assign follow-on work to whoever resolved:
120
+ *
121
+ * ```typescript
122
+ * import type { EscalationResolution } from '@hotmeshio/hotmesh/types';
123
+ *
124
+ * const decision = await conditionLT<{
125
+ * approved: boolean;
126
+ * $resolution?: EscalationResolution;
127
+ * }>(signalId, { role: 'print-operator' });
128
+ * const resolver = decision && decision.$resolution?.resolvedBy;
129
+ * ```
130
+ *
131
+ * `$resolution` never lands in the stored `resolver_payload` audit column —
132
+ * on the legacy path below it is stripped before the durable resolve and
133
+ * re-attached to the returned payload.
134
+ *
115
135
  * **Legacy (two-step) — no config.** Create the escalation first (e.g. via
116
136
  * `ltCreateEscalation`) with `signal_id`/`signal_routing` metadata, then wait.
117
137
  * On resume the signal payload carries an injected `$escalation_id`; this helper
@@ -138,17 +158,21 @@ async function conditionLT(signalId, escalation) {
138
158
  taskQueue: LT_ACTIVITY_QUEUE,
139
159
  retry: { maximumAttempts: 3 },
140
160
  });
141
- // Strip the injected control keys ($escalation_id, $escalation_metadata) before the
142
- // payload is returned to the caller. The outcome patch ($escalation_metadata, set by
143
- // the resolve orchestrator's signal paths) rides INTO the single atomic resolve below
144
- // so it merges in the same guarded UPDATE never a separate write.
145
- const { $escalation_id: _id, $escalation_metadata: metadata, ...resolverPayload } = raw;
161
+ // Strip the injected control keys ($escalation_id, $escalation_metadata,
162
+ // $resolution) before the payload is stored. The outcome patch
163
+ // ($escalation_metadata, set by the resolve orchestrator's signal paths)
164
+ // rides INTO the single atomic resolve below so it merges in the same
165
+ // guarded UPDATE never a separate write. $resolution is provenance for
166
+ // the CALLER, not the audit column: it re-attaches to the returned payload.
167
+ const { $escalation_id: _id, $escalation_metadata: metadata, $resolution: resolution, ...resolverPayload } = raw;
146
168
  await ltResolveEscalation({
147
169
  escalationId,
148
170
  resolverPayload: resolverPayload,
149
171
  metadata: metadata,
150
172
  });
151
- return resolverPayload;
173
+ return (resolution
174
+ ? { ...resolverPayload, $resolution: resolution }
175
+ : resolverPayload);
152
176
  }
153
177
  return raw;
154
178
  }
@@ -1,3 +1,11 @@
1
+ import type { Types } from '@hotmeshio/hotmesh';
2
+ /**
3
+ * Resolution provenance delivered to a waiting workflow under the reserved
4
+ * `$resolution` signal key — who resolved the escalation and which row
5
+ * delivered it. Declare it in the `conditionLT` payload generic to consume it.
6
+ * Re-exported from the HotMesh SDK so workflow authors import one package.
7
+ */
8
+ export type EscalationResolution = Types.EscalationResolution;
1
9
  /**
2
10
  * Reserved keys inside `lt_escalations.metadata`. Everything else in the bag
3
11
  * is caller-owned. These ride the GIN-indexed surface so they survive the
@@ -1,2 +1,2 @@
1
- import{j as o}from"./vendor-query-B2UbickB.js";import{c as n}from"./tasks-B7QVagGw.js";import{K as m}from"./index-BmsZnbW1.js";import{f as c}from"./useEventHooks-CKpFrpjc.js";import{u}from"./mcp-C4upVuuP.js";import{P as d}from"./PageHeaderWithStats-BMhnR3-9.js";import"./vendor-react-BpdAFEQc.js";import"./vendor-icons-BE_WrH2z.js";function j(){var a;c();const{data:s}=n({limit:1}),{data:e}=m({status:"pending",limit:1}),{data:t}=u(),r=((a=t==null?void 0:t.servers)==null?void 0:a.filter(i=>i.status==="connected").length)??0,l=t?`${r}/${t.total}`:"—";return o.jsx("div",{children:o.jsx(d,{title:"Admin",stats:[{label:"Tasks",value:(s==null?void 0:s.total)??"—"},{label:"Pending Escalations",value:(e==null?void 0:e.total)??"—",dotClass:"bg-status-pending"},{label:"MCP Servers",value:l},{label:"System",value:"Healthy",dotClass:"bg-status-success"}]})})}export{j as AdminDashboard};
2
- //# sourceMappingURL=AdminDashboard-B5B8cf1A.js.map
1
+ import{j as o}from"./vendor-query-B2UbickB.js";import{c as n}from"./tasks-CnC1xEaD.js";import{K as m}from"./index-C6UuVkz7.js";import{f as c}from"./useEventHooks-Cyq4DiQA.js";import{u}from"./mcp-BwjeqkHn.js";import{P as d}from"./PageHeaderWithStats-BMhnR3-9.js";import"./vendor-react-BpdAFEQc.js";import"./vendor-icons-BE_WrH2z.js";function j(){var a;c();const{data:s}=n({limit:1}),{data:e}=m({status:"pending",limit:1}),{data:t}=u(),r=((a=t==null?void 0:t.servers)==null?void 0:a.filter(i=>i.status==="connected").length)??0,l=t?`${r}/${t.total}`:"—";return o.jsx("div",{children:o.jsx(d,{title:"Admin",stats:[{label:"Tasks",value:(s==null?void 0:s.total)??"—"},{label:"Pending Escalations",value:(e==null?void 0:e.total)??"—",dotClass:"bg-status-pending"},{label:"MCP Servers",value:l},{label:"System",value:"Healthy",dotClass:"bg-status-success"}]})})}export{j as AdminDashboard};
2
+ //# sourceMappingURL=AdminDashboard-CYlm0_J0.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AdminDashboard-B5B8cf1A.js","sources":["../../src/pages/admin/AdminDashboard.tsx"],"sourcesContent":["import { useTasks } from '../../api/tasks';\nimport { useEscalations } from '../../api/escalations';\nimport { useEscalationListEvents } from '../../hooks/useEventHooks';\nimport { useMcpServers } from '../../api/mcp';\nimport { PageHeaderWithStats } from '../../components/common/layout/PageHeaderWithStats';\n\nexport function AdminDashboard() {\n useEscalationListEvents();\n const { data: taskData } = useTasks({ limit: 1 });\n const { data: pendingEsc } = useEscalations({ status: 'pending', limit: 1 });\n const { data: mcpData } = useMcpServers();\n\n const connectedServers =\n mcpData?.servers?.filter((s) => s.status === 'connected').length ?? 0;\n const mcpLabel = mcpData ? `${connectedServers}/${mcpData.total}` : '—';\n\n return (\n <div>\n <PageHeaderWithStats\n title=\"Admin\"\n stats={[\n { label: 'Tasks', value: taskData?.total ?? '—' },\n { label: 'Pending Escalations', value: pendingEsc?.total ?? '—', dotClass: 'bg-status-pending' },\n { label: 'MCP Servers', value: mcpLabel },\n { label: 'System', value: 'Healthy', dotClass: 'bg-status-success' },\n ]}\n />\n </div>\n );\n}\n"],"names":["AdminDashboard","useEscalationListEvents","taskData","useTasks","pendingEsc","useEscalations","mcpData","useMcpServers","connectedServers","_a","s","mcpLabel","jsx","PageHeaderWithStats"],"mappings":"4UAMO,SAASA,GAAiB,OAC/BC,EAAA,EACA,KAAM,CAAE,KAAMC,CAAA,EAAaC,EAAS,CAAE,MAAO,EAAG,EAC1C,CAAE,KAAMC,CAAA,EAAeC,EAAe,CAAE,OAAQ,UAAW,MAAO,EAAG,EACrE,CAAE,KAAMC,CAAA,EAAYC,EAAA,EAEpBC,IACJC,EAAAH,GAAA,YAAAA,EAAS,UAAT,YAAAG,EAAkB,OAAQC,GAAMA,EAAE,SAAW,aAAa,SAAU,EAChEC,EAAWL,EAAU,GAAGE,CAAgB,IAAIF,EAAQ,KAAK,GAAK,IAEpE,aACG,MAAA,CACC,SAAAM,EAAAA,IAACC,EAAA,CACC,MAAM,QACN,MAAO,CACL,CAAE,MAAO,QAAS,OAAOX,GAAA,YAAAA,EAAU,QAAS,GAAA,EAC5C,CAAE,MAAO,sBAAuB,OAAOE,GAAA,YAAAA,EAAY,QAAS,IAAK,SAAU,mBAAA,EAC3E,CAAE,MAAO,cAAe,MAAOO,CAAA,EAC/B,CAAE,MAAO,SAAU,MAAO,UAAW,SAAU,mBAAA,CAAoB,CACrE,CAAA,EAEJ,CAEJ"}
1
+ {"version":3,"file":"AdminDashboard-CYlm0_J0.js","sources":["../../src/pages/admin/AdminDashboard.tsx"],"sourcesContent":["import { useTasks } from '../../api/tasks';\nimport { useEscalations } from '../../api/escalations';\nimport { useEscalationListEvents } from '../../hooks/useEventHooks';\nimport { useMcpServers } from '../../api/mcp';\nimport { PageHeaderWithStats } from '../../components/common/layout/PageHeaderWithStats';\n\nexport function AdminDashboard() {\n useEscalationListEvents();\n const { data: taskData } = useTasks({ limit: 1 });\n const { data: pendingEsc } = useEscalations({ status: 'pending', limit: 1 });\n const { data: mcpData } = useMcpServers();\n\n const connectedServers =\n mcpData?.servers?.filter((s) => s.status === 'connected').length ?? 0;\n const mcpLabel = mcpData ? `${connectedServers}/${mcpData.total}` : '—';\n\n return (\n <div>\n <PageHeaderWithStats\n title=\"Admin\"\n stats={[\n { label: 'Tasks', value: taskData?.total ?? '—' },\n { label: 'Pending Escalations', value: pendingEsc?.total ?? '—', dotClass: 'bg-status-pending' },\n { label: 'MCP Servers', value: mcpLabel },\n { label: 'System', value: 'Healthy', dotClass: 'bg-status-success' },\n ]}\n />\n </div>\n );\n}\n"],"names":["AdminDashboard","useEscalationListEvents","taskData","useTasks","pendingEsc","useEscalations","mcpData","useMcpServers","connectedServers","_a","s","mcpLabel","jsx","PageHeaderWithStats"],"mappings":"4UAMO,SAASA,GAAiB,OAC/BC,EAAA,EACA,KAAM,CAAE,KAAMC,CAAA,EAAaC,EAAS,CAAE,MAAO,EAAG,EAC1C,CAAE,KAAMC,CAAA,EAAeC,EAAe,CAAE,OAAQ,UAAW,MAAO,EAAG,EACrE,CAAE,KAAMC,CAAA,EAAYC,EAAA,EAEpBC,IACJC,EAAAH,GAAA,YAAAA,EAAS,UAAT,YAAAG,EAAkB,OAAQC,GAAMA,EAAE,SAAW,aAAa,SAAU,EAChEC,EAAWL,EAAU,GAAGE,CAAgB,IAAIF,EAAQ,KAAK,GAAK,IAEpE,aACG,MAAA,CACC,SAAAM,EAAAA,IAACC,EAAA,CACC,MAAM,QACN,MAAO,CACL,CAAE,MAAO,QAAS,OAAOX,GAAA,YAAAA,EAAU,QAAS,GAAA,EAC5C,CAAE,MAAO,sBAAuB,OAAOE,GAAA,YAAAA,EAAY,QAAS,IAAK,SAAU,mBAAA,EAC3E,CAAE,MAAO,cAAe,MAAOO,CAAA,EAC/B,CAAE,MAAO,SAAU,MAAO,UAAW,SAAU,mBAAA,CAAoB,CACrE,CAAA,EAEJ,CAEJ"}