@hotmeshio/long-tail 0.8.4 → 0.8.5

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 (190) hide show
  1. package/build/api/escalations/index.d.ts +1 -1
  2. package/build/api/escalations/index.js +2 -1
  3. package/build/api/escalations/resolve.d.ts +28 -0
  4. package/build/api/escalations/resolve.js +98 -0
  5. package/build/lib/db/index.js +12 -1
  6. package/build/lib/db/migrate.js +27 -0
  7. package/build/modules/defaults.d.ts +2 -0
  8. package/build/modules/defaults.js +3 -1
  9. package/build/routes/escalations/resolve.js +18 -0
  10. package/build/sdk/index.d.ts +8 -0
  11. package/build/sdk/index.js +1 -0
  12. package/build/services/escalation/crud.d.ts +36 -0
  13. package/build/services/escalation/crud.js +53 -0
  14. package/build/services/maintenance/index.js +22 -0
  15. package/build/types/maintenance.d.ts +6 -1
  16. package/dashboard/dist/assets/{AdminDashboard-B-JptT54.js → AdminDashboard-RrSvb8d-.js} +2 -2
  17. package/dashboard/dist/assets/{AdminDashboard-B-JptT54.js.map → AdminDashboard-RrSvb8d-.js.map} +1 -1
  18. package/dashboard/dist/assets/{AgentConfigPage-B1Jc6iJk.js → AgentConfigPage-5RMdI0ku.js} +2 -2
  19. package/dashboard/dist/assets/{AgentConfigPage-B1Jc6iJk.js.map → AgentConfigPage-5RMdI0ku.js.map} +1 -1
  20. package/dashboard/dist/assets/{AgentDetailPage-CWpclCOY.js → AgentDetailPage-C_-sIBcr.js} +2 -2
  21. package/dashboard/dist/assets/{AgentDetailPage-CWpclCOY.js.map → AgentDetailPage-C_-sIBcr.js.map} +1 -1
  22. package/dashboard/dist/assets/{AgentsPage-DyAf5GA2.js → AgentsPage-CxNNtSsf.js} +2 -2
  23. package/dashboard/dist/assets/{AgentsPage-DyAf5GA2.js.map → AgentsPage-CxNNtSsf.js.map} +1 -1
  24. package/dashboard/dist/assets/{AvailableEscalationsPage-DDwAgklw.js → AvailableEscalationsPage-BcbhA6NE.js} +2 -2
  25. package/dashboard/dist/assets/{AvailableEscalationsPage-DDwAgklw.js.map → AvailableEscalationsPage-BcbhA6NE.js.map} +1 -1
  26. package/dashboard/dist/assets/{BotPicker-B1RdaNuY.js → BotPicker-BQVz6bye.js} +2 -2
  27. package/dashboard/dist/assets/{BotPicker-B1RdaNuY.js.map → BotPicker-BQVz6bye.js.map} +1 -1
  28. package/dashboard/dist/assets/{CapabilitiesPage-CxHDnyjX.js → CapabilitiesPage-DlZ8SgO3.js} +2 -2
  29. package/dashboard/dist/assets/{CapabilitiesPage-CxHDnyjX.js.map → CapabilitiesPage-DlZ8SgO3.js.map} +1 -1
  30. package/dashboard/dist/assets/{CollapsibleSection-Ds0e8cCO.js → CollapsibleSection-lo8Qx4zb.js} +2 -2
  31. package/dashboard/dist/assets/{CollapsibleSection-Ds0e8cCO.js.map → CollapsibleSection-lo8Qx4zb.js.map} +1 -1
  32. package/dashboard/dist/assets/{CredentialsPage-D8UVO-3A.js → CredentialsPage-DJ9DyXsO.js} +2 -2
  33. package/dashboard/dist/assets/{CredentialsPage-D8UVO-3A.js.map → CredentialsPage-DJ9DyXsO.js.map} +1 -1
  34. package/dashboard/dist/assets/{CronLabel-ZesYXxCH.js → CronLabel-o0dbisw1.js} +2 -2
  35. package/dashboard/dist/assets/{CronLabel-ZesYXxCH.js.map → CronLabel-o0dbisw1.js.map} +1 -1
  36. package/dashboard/dist/assets/{CustomDurationPicker-OKlwH5a_.js → CustomDurationPicker-CGiwKSVJ.js} +2 -2
  37. package/dashboard/dist/assets/{CustomDurationPicker-OKlwH5a_.js.map → CustomDurationPicker-CGiwKSVJ.js.map} +1 -1
  38. package/dashboard/dist/assets/{ElapsedCell-CO8S6vdb.js → ElapsedCell-N22STQcg.js} +2 -2
  39. package/dashboard/dist/assets/{ElapsedCell-CO8S6vdb.js.map → ElapsedCell-N22STQcg.js.map} +1 -1
  40. package/dashboard/dist/assets/EscalationSchemaPage-Zsmewko2.js +9 -0
  41. package/dashboard/dist/assets/EscalationSchemaPage-Zsmewko2.js.map +1 -0
  42. package/dashboard/dist/assets/{EscalationsOverview-DMpRvVql.js → EscalationsOverview-CE2p70Ct.js} +2 -2
  43. package/dashboard/dist/assets/{EscalationsOverview-DMpRvVql.js.map → EscalationsOverview-CE2p70Ct.js.map} +1 -1
  44. package/dashboard/dist/assets/{EventTable-BARJeiS2.js → EventTable-B3Gj7Ayg.js} +2 -2
  45. package/dashboard/dist/assets/{EventTable-BARJeiS2.js.map → EventTable-B3Gj7Ayg.js.map} +1 -1
  46. package/dashboard/dist/assets/{GraphInvokePage-CTuul-av.js → GraphInvokePage-DywWVSdj.js} +2 -2
  47. package/dashboard/dist/assets/{GraphInvokePage-CTuul-av.js.map → GraphInvokePage-DywWVSdj.js.map} +1 -1
  48. package/dashboard/dist/assets/{HomePage-BKFpOaHX.js → HomePage-CxtBiULd.js} +2 -2
  49. package/dashboard/dist/assets/{HomePage-BKFpOaHX.js.map → HomePage-CxtBiULd.js.map} +1 -1
  50. package/dashboard/dist/assets/{ListToolbar-Dz2_neVF.js → ListToolbar-Ok2O0wmC.js} +2 -2
  51. package/dashboard/dist/assets/{ListToolbar-Dz2_neVF.js.map → ListToolbar-Ok2O0wmC.js.map} +1 -1
  52. package/dashboard/dist/assets/{McpOverview-Do-vaEqV.js → McpOverview-CTCYZXIp.js} +2 -2
  53. package/dashboard/dist/assets/{McpOverview-Do-vaEqV.js.map → McpOverview-CTCYZXIp.js.map} +1 -1
  54. package/dashboard/dist/assets/{McpQueryDetailPage-HwDGNSbN.js → McpQueryDetailPage-BOaXf0bZ.js} +2 -2
  55. package/dashboard/dist/assets/{McpQueryDetailPage-HwDGNSbN.js.map → McpQueryDetailPage-BOaXf0bZ.js.map} +1 -1
  56. package/dashboard/dist/assets/{McpQueryPage-DxMUpQ7R.js → McpQueryPage-BbYojoHu.js} +2 -2
  57. package/dashboard/dist/assets/{McpQueryPage-DxMUpQ7R.js.map → McpQueryPage-BbYojoHu.js.map} +1 -1
  58. package/dashboard/dist/assets/{McpRunDetailPage-BzzZIXIk.js → McpRunDetailPage-CXGCVmPq.js} +2 -2
  59. package/dashboard/dist/assets/{McpRunDetailPage-BzzZIXIk.js.map → McpRunDetailPage-CXGCVmPq.js.map} +1 -1
  60. package/dashboard/dist/assets/{McpRunsPage-D3J42d2i.js → McpRunsPage-Df1GqxUg.js} +2 -2
  61. package/dashboard/dist/assets/{McpRunsPage-D3J42d2i.js.map → McpRunsPage-Df1GqxUg.js.map} +1 -1
  62. package/dashboard/dist/assets/OperationsPage-DgZYi-BC.js +2 -0
  63. package/dashboard/dist/assets/OperationsPage-DgZYi-BC.js.map +1 -0
  64. package/dashboard/dist/assets/{OperatorDashboard-BqJn8wEZ.js → OperatorDashboard-DIR7XDeD.js} +2 -2
  65. package/dashboard/dist/assets/{OperatorDashboard-BqJn8wEZ.js.map → OperatorDashboard-DIR7XDeD.js.map} +1 -1
  66. package/dashboard/dist/assets/{ProcessDetailPage-C8sT2xuE.js → ProcessDetailPage-BuSi654J.js} +2 -2
  67. package/dashboard/dist/assets/{ProcessDetailPage-C8sT2xuE.js.map → ProcessDetailPage-BuSi654J.js.map} +1 -1
  68. package/dashboard/dist/assets/{ProcessesListPage-eA8buUgd.js → ProcessesListPage-Dhik7XpW.js} +2 -2
  69. package/dashboard/dist/assets/{ProcessesListPage-eA8buUgd.js.map → ProcessesListPage-Dhik7XpW.js.map} +1 -1
  70. package/dashboard/dist/assets/RoleDetailPage-BfzqQxMU.js +8 -0
  71. package/dashboard/dist/assets/RoleDetailPage-BfzqQxMU.js.map +1 -0
  72. package/dashboard/dist/assets/{RolesPage-BQNQxsMY.js → RolesPage-BRicD5mx.js} +2 -2
  73. package/dashboard/dist/assets/{RolesPage-BQNQxsMY.js.map → RolesPage-BRicD5mx.js.map} +1 -1
  74. package/dashboard/dist/assets/{RunAsSelector-mhusrlYE.js → RunAsSelector-DipyBf_T.js} +2 -2
  75. package/dashboard/dist/assets/{RunAsSelector-mhusrlYE.js.map → RunAsSelector-DipyBf_T.js.map} +1 -1
  76. package/dashboard/dist/assets/{StickyPagination-CqT9Q1I6.js → StickyPagination-CD4W450h.js} +2 -2
  77. package/dashboard/dist/assets/{StickyPagination-CqT9Q1I6.js.map → StickyPagination-CD4W450h.js.map} +1 -1
  78. package/dashboard/dist/assets/{StreamMessageDetail-jOJaoupp.js → StreamMessageDetail-BbDdWDUY.js} +2 -2
  79. package/dashboard/dist/assets/{StreamMessageDetail-jOJaoupp.js.map → StreamMessageDetail-BbDdWDUY.js.map} +1 -1
  80. package/dashboard/dist/assets/{SwimlaneTimeline-BrfmWgAj.js → SwimlaneTimeline-Bktv2vi5.js} +2 -2
  81. package/dashboard/dist/assets/{SwimlaneTimeline-BrfmWgAj.js.map → SwimlaneTimeline-Bktv2vi5.js.map} +1 -1
  82. package/dashboard/dist/assets/{TaskDetailPage-Cus_JHIC.js → TaskDetailPage-pSU3xuG9.js} +2 -2
  83. package/dashboard/dist/assets/{TaskDetailPage-Cus_JHIC.js.map → TaskDetailPage-pSU3xuG9.js.map} +1 -1
  84. package/dashboard/dist/assets/{TasksListPage-B7GK8AoX.js → TasksListPage-M6ok-Nfd.js} +2 -2
  85. package/dashboard/dist/assets/{TasksListPage-B7GK8AoX.js.map → TasksListPage-M6ok-Nfd.js.map} +1 -1
  86. package/dashboard/dist/assets/{TimeAgo-C606LzT3.js → TimeAgo-DVWhRNbi.js} +2 -2
  87. package/dashboard/dist/assets/{TimeAgo-C606LzT3.js.map → TimeAgo-DVWhRNbi.js.map} +1 -1
  88. package/dashboard/dist/assets/{TimestampCell-hfh6zvH-.js → TimestampCell-rG7pmIkW.js} +2 -2
  89. package/dashboard/dist/assets/{TimestampCell-hfh6zvH-.js.map → TimestampCell-rG7pmIkW.js.map} +1 -1
  90. package/dashboard/dist/assets/{ToolTestPanel-CsPsyvQq.js → ToolTestPanel-CLcMA8OE.js} +2 -2
  91. package/dashboard/dist/assets/{ToolTestPanel-CsPsyvQq.js.map → ToolTestPanel-CLcMA8OE.js.map} +1 -1
  92. package/dashboard/dist/assets/{TopicDetailPage-Diz6r7zr.js → TopicDetailPage-C9gvoWYu.js} +2 -2
  93. package/dashboard/dist/assets/{TopicDetailPage-Diz6r7zr.js.map → TopicDetailPage-C9gvoWYu.js.map} +1 -1
  94. package/dashboard/dist/assets/{TopicsPage-B6fn7fFh.js → TopicsPage-CIGi3TdT.js} +2 -2
  95. package/dashboard/dist/assets/{TopicsPage-B6fn7fFh.js.map → TopicsPage-CIGi3TdT.js.map} +1 -1
  96. package/dashboard/dist/assets/{UserName-Cc-5QH5q.js → UserName-CifbOahk.js} +2 -2
  97. package/dashboard/dist/assets/{UserName-Cc-5QH5q.js.map → UserName-CifbOahk.js.map} +1 -1
  98. package/dashboard/dist/assets/{WorkflowExecutionPage-BFq7UdhA.js → WorkflowExecutionPage-BR0oVx_p.js} +2 -2
  99. package/dashboard/dist/assets/{WorkflowExecutionPage-BFq7UdhA.js.map → WorkflowExecutionPage-BR0oVx_p.js.map} +1 -1
  100. package/dashboard/dist/assets/{WorkflowsDashboard-CHCM6hUa.js → WorkflowsDashboard-CSYrYQsO.js} +2 -2
  101. package/dashboard/dist/assets/{WorkflowsDashboard-CHCM6hUa.js.map → WorkflowsDashboard-CSYrYQsO.js.map} +1 -1
  102. package/dashboard/dist/assets/{WorkflowsOverview-WeOvl8-_.js → WorkflowsOverview-CaXWYZuw.js} +2 -2
  103. package/dashboard/dist/assets/{WorkflowsOverview-WeOvl8-_.js.map → WorkflowsOverview-CaXWYZuw.js.map} +1 -1
  104. package/dashboard/dist/assets/{YamlWorkflowDetailPage-6GfhVDpv.js → YamlWorkflowDetailPage-CRBXahFJ.js} +2 -2
  105. package/dashboard/dist/assets/{YamlWorkflowDetailPage-6GfhVDpv.js.map → YamlWorkflowDetailPage-CRBXahFJ.js.map} +1 -1
  106. package/dashboard/dist/assets/{YamlWorkflowsPage-DqcY3ocP.js → YamlWorkflowsPage-D5zc8Lta.js} +2 -2
  107. package/dashboard/dist/assets/{YamlWorkflowsPage-DqcY3ocP.js.map → YamlWorkflowsPage-D5zc8Lta.js.map} +1 -1
  108. package/dashboard/dist/assets/{agents-DlzvjNxE.js → agents-D7vYXeLj.js} +2 -2
  109. package/dashboard/dist/assets/{agents-DlzvjNxE.js.map → agents-D7vYXeLj.js.map} +1 -1
  110. package/dashboard/dist/assets/{bots-CWMN-KUI.js → bots-CKaYN2fL.js} +2 -2
  111. package/dashboard/dist/assets/{bots-CWMN-KUI.js.map → bots-CKaYN2fL.js.map} +1 -1
  112. package/dashboard/dist/assets/{capabilities-_WSZ7cxO.js → capabilities-BknM6oFm.js} +2 -2
  113. package/dashboard/dist/assets/{capabilities-_WSZ7cxO.js.map → capabilities-BknM6oFm.js.map} +1 -1
  114. package/dashboard/dist/assets/{controlplane-_k9nWZy3.js → controlplane-BodNGCr-.js} +2 -2
  115. package/dashboard/dist/assets/{controlplane-_k9nWZy3.js.map → controlplane-BodNGCr-.js.map} +1 -1
  116. package/dashboard/dist/assets/{escalation-CK8ElYzD.js → escalation-CH_XK2XM.js} +2 -2
  117. package/dashboard/dist/assets/{escalation-CK8ElYzD.js.map → escalation-CH_XK2XM.js.map} +1 -1
  118. package/dashboard/dist/assets/{escalation-columns-Dyrf6Tdp.js → escalation-columns-CcbLKRI4.js} +2 -2
  119. package/dashboard/dist/assets/{escalation-columns-Dyrf6Tdp.js.map → escalation-columns-CcbLKRI4.js.map} +1 -1
  120. package/dashboard/dist/assets/index--xNp5rx6.css +1 -0
  121. package/dashboard/dist/assets/{index-uUYXmvFf.js → index-B-LQ8fsJ.js} +2 -2
  122. package/dashboard/dist/assets/{index-uUYXmvFf.js.map → index-B-LQ8fsJ.js.map} +1 -1
  123. package/dashboard/dist/assets/{index-Dd4Si1Rl.js → index-BH67e1Ah.js} +2 -2
  124. package/dashboard/dist/assets/{index-Dd4Si1Rl.js.map → index-BH67e1Ah.js.map} +1 -1
  125. package/dashboard/dist/assets/{index-DwWP-Z_c.js → index-B_aFcGv9.js} +4 -4
  126. package/dashboard/dist/assets/{index-DwWP-Z_c.js.map → index-B_aFcGv9.js.map} +1 -1
  127. package/dashboard/dist/assets/{index-BiApvBEz.js → index-Bwofyfi8.js} +2 -2
  128. package/dashboard/dist/assets/{index-BiApvBEz.js.map → index-Bwofyfi8.js.map} +1 -1
  129. package/dashboard/dist/assets/{index-C3h0qGzG.js → index-C3QKGY5C.js} +2 -2
  130. package/dashboard/dist/assets/{index-C3h0qGzG.js.map → index-C3QKGY5C.js.map} +1 -1
  131. package/dashboard/dist/assets/{index-ZBj6Xgim.js → index-CJpywoA8.js} +2 -2
  132. package/dashboard/dist/assets/{index-ZBj6Xgim.js.map → index-CJpywoA8.js.map} +1 -1
  133. package/dashboard/dist/assets/{index-Ex5tEte8.js → index-CV8soXIM.js} +2 -2
  134. package/dashboard/dist/assets/{index-Ex5tEte8.js.map → index-CV8soXIM.js.map} +1 -1
  135. package/dashboard/dist/assets/{index-C5Yc3TT7.js → index-CdN-Z8-r.js} +2 -2
  136. package/dashboard/dist/assets/{index-C5Yc3TT7.js.map → index-CdN-Z8-r.js.map} +1 -1
  137. package/dashboard/dist/assets/{index-Dc-Ye2wk.js → index-D7NHjvA4.js} +2 -2
  138. package/dashboard/dist/assets/{index-Dc-Ye2wk.js.map → index-D7NHjvA4.js.map} +1 -1
  139. package/dashboard/dist/assets/{index-D8GcHxNJ.js → index-DHhz71yv.js} +2 -2
  140. package/dashboard/dist/assets/{index-D8GcHxNJ.js.map → index-DHhz71yv.js.map} +1 -1
  141. package/dashboard/dist/assets/{index-kKufOPLo.js → index-Gt2Rebs9.js} +2 -2
  142. package/dashboard/dist/assets/{index-kKufOPLo.js.map → index-Gt2Rebs9.js.map} +1 -1
  143. package/dashboard/dist/assets/index-IIq5Tkqs.js +6 -0
  144. package/dashboard/dist/assets/index-IIq5Tkqs.js.map +1 -0
  145. package/dashboard/dist/assets/{index-C7VXLKJs.js → index-_gh2K9DU.js} +2 -2
  146. package/dashboard/dist/assets/{index-C7VXLKJs.js.map → index-_gh2K9DU.js.map} +1 -1
  147. package/dashboard/dist/assets/{knowledge-fYoEF4Lx.js → knowledge-CE6gjN3G.js} +2 -2
  148. package/dashboard/dist/assets/{knowledge-fYoEF4Lx.js.map → knowledge-CE6gjN3G.js.map} +1 -1
  149. package/dashboard/dist/assets/{mcp-1lzlgtS8.js → mcp-B4F-T-7R.js} +2 -2
  150. package/dashboard/dist/assets/{mcp-1lzlgtS8.js.map → mcp-B4F-T-7R.js.map} +1 -1
  151. package/dashboard/dist/assets/{mcp-query-nlrAz7m_.js → mcp-query-CYOarL1K.js} +2 -2
  152. package/dashboard/dist/assets/{mcp-query-nlrAz7m_.js.map → mcp-query-CYOarL1K.js.map} +1 -1
  153. package/dashboard/dist/assets/{pipelines-Ihi7EKXi.js → pipelines-B4gB9qMx.js} +2 -2
  154. package/dashboard/dist/assets/{pipelines-Ihi7EKXi.js.map → pipelines-B4gB9qMx.js.map} +1 -1
  155. package/dashboard/dist/assets/{roles-D4Wn7kE9.js → roles-LZf98ePg.js} +2 -2
  156. package/dashboard/dist/assets/{roles-D4Wn7kE9.js.map → roles-LZf98ePg.js.map} +1 -1
  157. package/dashboard/dist/assets/{tasks-Crk9Y3C4.js → tasks-GG8c_U9w.js} +2 -2
  158. package/dashboard/dist/assets/{tasks-Crk9Y3C4.js.map → tasks-GG8c_U9w.js.map} +1 -1
  159. package/dashboard/dist/assets/{topics-CtfcCyw9.js → topics-C7-6oOgA.js} +2 -2
  160. package/dashboard/dist/assets/{topics-CtfcCyw9.js.map → topics-C7-6oOgA.js.map} +1 -1
  161. package/dashboard/dist/assets/{useEventHooks-Dn_vN2xE.js → useEventHooks-82IiMmOc.js} +2 -2
  162. package/dashboard/dist/assets/{useEventHooks-Dn_vN2xE.js.map → useEventHooks-82IiMmOc.js.map} +1 -1
  163. package/dashboard/dist/assets/{useNamespace-Cfs3vKWk.js → useNamespace-DQEqD2LA.js} +2 -2
  164. package/dashboard/dist/assets/{useNamespace-Cfs3vKWk.js.map → useNamespace-DQEqD2LA.js.map} +1 -1
  165. package/dashboard/dist/assets/{useYamlActivityEvents-ymobxH47.js → useYamlActivityEvents-Bm0-ewLx.js} +2 -2
  166. package/dashboard/dist/assets/{useYamlActivityEvents-ymobxH47.js.map → useYamlActivityEvents-Bm0-ewLx.js.map} +1 -1
  167. package/dashboard/dist/assets/{users-DngGIiC_.js → users-DHx2ium7.js} +2 -2
  168. package/dashboard/dist/assets/{users-DngGIiC_.js.map → users-DHx2ium7.js.map} +1 -1
  169. package/dashboard/dist/assets/{workflows-DuUspMAl.js → workflows-qIbkeQ_5.js} +2 -2
  170. package/dashboard/dist/assets/{workflows-DuUspMAl.js.map → workflows-qIbkeQ_5.js.map} +1 -1
  171. package/dashboard/dist/assets/{yaml-workflows-DXQCiOsP.js → yaml-workflows-FibyeHpo.js} +2 -2
  172. package/dashboard/dist/assets/{yaml-workflows-DXQCiOsP.js.map → yaml-workflows-FibyeHpo.js.map} +1 -1
  173. package/dashboard/dist/index.html +2 -2
  174. package/docs/api/http/escalations.md +20 -0
  175. package/docs/api/sdk/escalations.md +37 -2
  176. package/docs/dashboard.md +1 -1
  177. package/docs/data.md +1 -1
  178. package/docs/hitl-guide.md +112 -3
  179. package/docs/maintenance.md +6 -3
  180. package/docs/oauth-and-delegation.md +1 -1
  181. package/package.json +2 -2
  182. package/dashboard/dist/assets/EscalationSchemaPage-Br5sD8-N.js +0 -9
  183. package/dashboard/dist/assets/EscalationSchemaPage-Br5sD8-N.js.map +0 -1
  184. package/dashboard/dist/assets/OperationsPage-BaM-QDhy.js +0 -2
  185. package/dashboard/dist/assets/OperationsPage-BaM-QDhy.js.map +0 -1
  186. package/dashboard/dist/assets/RoleDetailPage-aR-ror5v.js +0 -11
  187. package/dashboard/dist/assets/RoleDetailPage-aR-ror5v.js.map +0 -1
  188. package/dashboard/dist/assets/index-BdqKh0UK.css +0 -1
  189. package/dashboard/dist/assets/index-OV1JoB_P.js +0 -6
  190. package/dashboard/dist/assets/index-OV1JoB_P.js.map +0 -1
@@ -3,7 +3,7 @@ export { listEscalations, listAvailableEscalations, listDistinctTypes, listFacet
3
3
  export { getEscalation, getEscalationsByWorkflowId, escalateToRole } from './single';
4
4
  export { claimEscalation, releaseEscalation } from './claim';
5
5
  export { releaseExpiredClaims, updatePriority, bulkClaim, bulkAssign, bulkEscalate, bulkTriage } from './bulk';
6
- export { resolveEscalation, resolveBySignalKey, resolveByIds } from './resolve';
6
+ export { resolveEscalation, resolveBySignalKey, resolveByIds, resolveAllOrNone } from './resolve';
7
7
  export { findByMetadata, claimByMetadata, resolveByMetadata } from './metadata';
8
8
  export { cancelSingleEscalation, bulkCancel } from './cancel';
9
9
  export { searchByFacets, claimGroups, claimByFacets } from './facets';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.claimByFacets = exports.claimGroups = exports.searchByFacets = exports.bulkCancel = exports.cancelSingleEscalation = exports.resolveByMetadata = exports.claimByMetadata = exports.findByMetadata = exports.resolveByIds = exports.resolveBySignalKey = exports.resolveEscalation = exports.bulkTriage = exports.bulkEscalate = exports.bulkAssign = exports.bulkClaim = exports.updatePriority = exports.releaseExpiredClaims = exports.releaseEscalation = exports.claimEscalation = exports.escalateToRole = exports.getEscalationsByWorkflowId = exports.getEscalation = exports.getStationMetrics = exports.getEscalationStats = exports.listFacetKeys = exports.listDistinctTypes = exports.listAvailableEscalations = exports.listEscalations = exports.createEscalation = void 0;
3
+ exports.claimByFacets = exports.claimGroups = exports.searchByFacets = exports.bulkCancel = exports.cancelSingleEscalation = exports.resolveByMetadata = exports.claimByMetadata = exports.findByMetadata = exports.resolveAllOrNone = exports.resolveByIds = exports.resolveBySignalKey = exports.resolveEscalation = exports.bulkTriage = exports.bulkEscalate = exports.bulkAssign = exports.bulkClaim = exports.updatePriority = exports.releaseExpiredClaims = exports.releaseEscalation = exports.claimEscalation = exports.escalateToRole = exports.getEscalationsByWorkflowId = exports.getEscalation = exports.getStationMetrics = exports.getEscalationStats = exports.listFacetKeys = exports.listDistinctTypes = exports.listAvailableEscalations = exports.listEscalations = exports.createEscalation = void 0;
4
4
  var create_1 = require("./create");
5
5
  Object.defineProperty(exports, "createEscalation", { enumerable: true, get: function () { return create_1.createEscalation; } });
6
6
  var list_1 = require("./list");
@@ -28,6 +28,7 @@ var resolve_1 = require("./resolve");
28
28
  Object.defineProperty(exports, "resolveEscalation", { enumerable: true, get: function () { return resolve_1.resolveEscalation; } });
29
29
  Object.defineProperty(exports, "resolveBySignalKey", { enumerable: true, get: function () { return resolve_1.resolveBySignalKey; } });
30
30
  Object.defineProperty(exports, "resolveByIds", { enumerable: true, get: function () { return resolve_1.resolveByIds; } });
31
+ Object.defineProperty(exports, "resolveAllOrNone", { enumerable: true, get: function () { return resolve_1.resolveAllOrNone; } });
31
32
  var metadata_1 = require("./metadata");
32
33
  Object.defineProperty(exports, "findByMetadata", { enumerable: true, get: function () { return metadata_1.findByMetadata; } });
33
34
  Object.defineProperty(exports, "claimByMetadata", { enumerable: true, get: function () { return metadata_1.claimByMetadata; } });
@@ -44,3 +44,31 @@ export declare function resolveByIds(input: {
44
44
  resolverPayload: Record<string, any>;
45
45
  metadata?: Record<string, any>;
46
46
  }, auth: LTApiAuth): Promise<LTApiResult>;
47
+ /**
48
+ * Atomic all-or-none bulk resolve with PER-ROW payloads — the gang-handoff
49
+ * sibling of {@link resolveByIds}. Every listed escalation must be pending and
50
+ * writable by the caller, or NOTHING resolves. Unlike resolveByIds, rows
51
+ * backing a live `condition()` waiter are first-class: each is woken with its
52
+ * own payload inside the single atomic statement (same wake contract as
53
+ * single resolve).
54
+ *
55
+ * RBAC matches resolveByIds: per-item write scope, 404 non-disclosure when any
56
+ * id is missing or out of scope, nothing resolved. `requireClaimed` adds a
57
+ * SQL-level assertion that every row is currently assigned to the caller —
58
+ * for claim-then-resolve flows (a broker resolving its claimed gang), this
59
+ * closes the window where another principal re-claims a member mid-flight.
60
+ *
61
+ * Rows whose resolution requires a non-atomic path (legacy signal routing via
62
+ * `metadata.signal_id` / `metadata.signal_routing`, which need a separate
63
+ * workflow signal) block the batch with 409 — bulk-resolving them would strand
64
+ * their workflows. Re-run/triage rows (workflow_type without any signal shape)
65
+ * resolve as bookkeeping acknowledgements, matching resolveByIds semantics.
66
+ */
67
+ export declare function resolveAllOrNone(input: {
68
+ items: Array<{
69
+ id: string;
70
+ resolverPayload: Record<string, any>;
71
+ }>;
72
+ metadata?: Record<string, any>;
73
+ requireClaimed?: boolean;
74
+ }, auth: LTApiAuth): Promise<LTApiResult>;
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.resolveEscalation = resolveEscalation;
37
37
  exports.resolveBySignalKey = resolveBySignalKey;
38
38
  exports.resolveByIds = resolveByIds;
39
+ exports.resolveAllOrNone = resolveAllOrNone;
39
40
  const escalationService = __importStar(require("../../services/escalation"));
40
41
  const taskService = __importStar(require("../../services/task"));
41
42
  const escalation_strategy_1 = require("../../services/escalation-strategy");
@@ -202,6 +203,103 @@ async function resolveByIds(input, auth) {
202
203
  return { status: 500, error: err.message };
203
204
  }
204
205
  }
206
+ /**
207
+ * Atomic all-or-none bulk resolve with PER-ROW payloads — the gang-handoff
208
+ * sibling of {@link resolveByIds}. Every listed escalation must be pending and
209
+ * writable by the caller, or NOTHING resolves. Unlike resolveByIds, rows
210
+ * backing a live `condition()` waiter are first-class: each is woken with its
211
+ * own payload inside the single atomic statement (same wake contract as
212
+ * single resolve).
213
+ *
214
+ * RBAC matches resolveByIds: per-item write scope, 404 non-disclosure when any
215
+ * id is missing or out of scope, nothing resolved. `requireClaimed` adds a
216
+ * SQL-level assertion that every row is currently assigned to the caller —
217
+ * for claim-then-resolve flows (a broker resolving its claimed gang), this
218
+ * closes the window where another principal re-claims a member mid-flight.
219
+ *
220
+ * Rows whose resolution requires a non-atomic path (legacy signal routing via
221
+ * `metadata.signal_id` / `metadata.signal_routing`, which need a separate
222
+ * workflow signal) block the batch with 409 — bulk-resolving them would strand
223
+ * their workflows. Re-run/triage rows (workflow_type without any signal shape)
224
+ * resolve as bookkeeping acknowledgements, matching resolveByIds semantics.
225
+ */
226
+ async function resolveAllOrNone(input, auth) {
227
+ try {
228
+ const { items, metadata, requireClaimed } = input;
229
+ if (!Array.isArray(items) || items.length === 0) {
230
+ return { status: 400, error: 'items must be a non-empty array' };
231
+ }
232
+ if (items.length > defaults_1.ESCALATION_BULK_RESOLVE_MAX) {
233
+ return { status: 400, error: `items exceeds the maximum of ${defaults_1.ESCALATION_BULK_RESOLVE_MAX}` };
234
+ }
235
+ const wellFormed = items.every((i) => i && typeof i.id === 'string' && i.id.length > 0
236
+ && i.resolverPayload && typeof i.resolverPayload === 'object');
237
+ if (!wellFormed) {
238
+ return { status: 400, error: 'every item requires an id and a resolverPayload object' };
239
+ }
240
+ const ids = items.map((i) => i.id);
241
+ if (new Set(ids).size !== ids.length) {
242
+ return { status: 400, error: 'items must not repeat ids' };
243
+ }
244
+ // One indexed read serves every pre-flight gate below (scope, path shape,
245
+ // redaction schema). Role and signal routing are immutable per escalation,
246
+ // so none of these checks race the guarded statement that follows — and
247
+ // row STATE (pending, assignee) is re-asserted inside that statement.
248
+ const rows = await escalationService.getEscalationsByIds(ids);
249
+ const rowById = new Map(rows.map((r) => [r.id, r]));
250
+ // Per-item write scope, same rule as resolveByIds: write_all roles may
251
+ // resolve any item in the role; write_self only items assigned to the
252
+ // caller. A missing id or any out-of-scope item → 404 (non-disclosure),
253
+ // nothing resolved. Global bypasses; the store then reports precise
254
+ // per-row blockers (including not-found) via the 409 below.
255
+ const writeScope = await (0, helpers_1.getEscalationWriteScope)(auth.userId);
256
+ if (!writeScope.global) {
257
+ const allSet = new Set(writeScope.allRoles);
258
+ const selfSet = new Set(writeScope.selfRoles);
259
+ const writable = (r) => (!!r.role && allSet.has(r.role)) ||
260
+ (!!r.role && selfSet.has(r.role) && r.assigned_to === auth.userId);
261
+ if (rows.length !== ids.length || !rows.every(writable)) {
262
+ return { status: 404, error: 'One or more escalations not found' };
263
+ }
264
+ }
265
+ // Fail loud on rows the atomic statement cannot wake: legacy signal shapes
266
+ // resume their workflow via a separate handle.signal, so bulk-resolving the
267
+ // row would mark it settled while the workflow stays parked forever.
268
+ const unsupported = rows.filter((r) => {
269
+ const meta = (r.metadata ?? {});
270
+ return !r.signal_key && (meta.signal_id || meta.signal_routing?.signalId);
271
+ });
272
+ if (unsupported.length > 0) {
273
+ const failed = unsupported.map((r) => ({ id: r.id, reason: 'unsupported-resolution-path' }));
274
+ // error rides inside data too: routes serialize `data ?? { error }`, and
275
+ // the 409 body must carry BOTH the message and the blocking ids
276
+ const error = 'One or more escalations require the single-resolve path (legacy signal routing)';
277
+ return { status: 409, error, data: { error, failedIds: failed.map((f) => f.id), failed } };
278
+ }
279
+ // Per-row password redaction against each row's own form schema — the
280
+ // payload enters the signal store and the audit record; plaintext never.
281
+ const serviceItems = await Promise.all(items.map(async (item) => ({
282
+ id: item.id,
283
+ resolverPayload: await redactPasswords(item.resolverPayload, rowById.get(item.id)?.metadata?.form_schema),
284
+ })));
285
+ const result = await escalationService.resolveEscalationsAllOrNone(serviceItems, metadata, requireClaimed ? auth.userId : undefined);
286
+ if (!result.ok) {
287
+ const error = 'One or more escalations blocked the batch; nothing was resolved';
288
+ return {
289
+ status: 409,
290
+ error,
291
+ data: { error, failedIds: result.failed.map((f) => f.id), failed: result.failed },
292
+ };
293
+ }
294
+ return {
295
+ status: 200,
296
+ data: { resolved: result.escalations.length, escalationIds: result.escalations.map((e) => e.id) },
297
+ };
298
+ }
299
+ catch (err) {
300
+ return { status: 500, error: err.message };
301
+ }
302
+ }
205
303
  // ── Resolution paths ─────────────────────────────────────────────────────
206
304
  /** Path A: lightweight conditionLT signal — inject $escalation_id and signal the running workflow. */
207
305
  async function resolveViaConditionSignal(escalation, resolverPayload, metadata) {
@@ -8,7 +8,18 @@ const config_1 = require("../../modules/config");
8
8
  let pool = null;
9
9
  function getPool() {
10
10
  if (!pool) {
11
- pool = new pg_1.Pool(config_1.postgres_options);
11
+ pool = new pg_1.Pool({
12
+ ...config_1.postgres_options,
13
+ // Long-tail's shared tables live in public. Postgres's default
14
+ // search_path is `"$user", public`: if any schema shares the connecting
15
+ // role's name (e.g. a HotMesh app schema named after the DB user), every
16
+ // unqualified statement — including CREATE TABLE in migrations — silently
17
+ // resolves there instead of public, forking the data across two schemas.
18
+ // Pinning the session search_path makes resolution independent of role
19
+ // and schema naming. HotMesh connections (getConnection) are unaffected:
20
+ // the engine fully qualifies its app schemas.
21
+ options: '-c search_path=public',
22
+ });
12
23
  }
13
24
  return pool;
14
25
  }
@@ -47,7 +47,34 @@ async function migrate() {
47
47
  // Uses a dedicated client so the lock is held for the entire sequence.
48
48
  const client = await pool.connect();
49
49
  try {
50
+ // Migrations define the shared public tables, so resolution is pinned on
51
+ // this client even if a future caller wires a pool without the pool-level
52
+ // search_path option. Without this, a schema named after the DB role
53
+ // (default search_path `"$user", public`) captures every unqualified
54
+ // CREATE TABLE below.
55
+ await client.query('SET search_path TO public');
50
56
  await client.query('SELECT pg_advisory_lock(8675309)');
57
+ // Fail loudly on a pre-existing split: an lt_migrations table in any other
58
+ // schema means a prior boot ran with `"$user"` shadowing public and forked
59
+ // the tables. Booting through it would either fork the data further or
60
+ // re-run every migration against empty public tables while the live rows
61
+ // sit in the shadow schema. An operator must consolidate first (move the
62
+ // live lt_* tables to public, archive the stale copies).
63
+ const drift = await client.query(`
64
+ SELECT n.nspname
65
+ FROM pg_class c
66
+ JOIN pg_namespace n ON n.oid = c.relnamespace
67
+ WHERE c.relname = 'lt_migrations' AND c.relkind = 'r' AND n.nspname <> 'public'
68
+ `);
69
+ if (drift.rows.length > 0) {
70
+ const schemas = drift.rows.map((r) => r.nspname).join(', ');
71
+ throw new Error(`[migrate] lt_migrations exists in non-public schema(s): ${schemas}. ` +
72
+ 'Long-tail tables must live in the public schema. This usually means the ' +
73
+ 'database user shares a name with another schema, so the default ' +
74
+ 'search_path ("$user", public) captured earlier migrations. Consolidate ' +
75
+ 'the schemas (ALTER TABLE ... SET SCHEMA public for the live lt_* tables, ' +
76
+ 'archive stale public copies) before starting the app.');
77
+ }
51
78
  // ensure migration tracking table
52
79
  await client.query(`
53
80
  CREATE TABLE IF NOT EXISTS lt_migrations (
@@ -49,6 +49,8 @@ export declare const QUERY_LIMIT_MAX: number;
49
49
  export declare const YAML_LIST_LIMIT: number;
50
50
  /** Default page size for YAML workflow version history. */
51
51
  export declare const YAML_VERSION_LIMIT: number;
52
+ /** Maximum items per atomic bulk resolve (POST /escalations/resolve-all-or-none). */
53
+ export declare const ESCALATION_BULK_RESOLVE_MAX: number;
52
54
  /**
53
55
  * Claim duration presets shown in the dashboard (minutes).
54
56
  * Override via JSON array, e.g. LT_CLAIM_DURATION_OPTIONS='[15,30,60,480]'
@@ -9,7 +9,7 @@
9
9
  * Grouped by domain so related knobs live together.
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.YAML_LINE_WIDTH = exports.STOP_WORDS = exports.CLAIM_DURATION_OPTIONS = exports.YAML_VERSION_LIMIT = exports.YAML_LIST_LIMIT = exports.QUERY_LIMIT_MAX = exports.QUERY_LIMIT_DEFAULT = exports.CONFIG_CACHE_TTL_MS = exports.MCP_TOOL_TIMEOUT_MS = exports.WORKFLOW_SYNC_TIMEOUT_MS = exports.JOB_EXPIRE_SECS = exports.WORKFLOW_EXPIRE_SECS = exports.TOOL_ARG_LIMIT_CAP = exports.TOOL_ROUNDS_MCP_QUERY = exports.TOOL_ROUNDS_TRIAGE = exports.TOOL_RESULT_MAX_CHARS = exports.LLM_MAX_INPUT_CHARS = exports.LLM_MAX_ARRAY_ITEMS = exports.LLM_MAX_TOKENS_VISION = exports.LLM_MAX_TOKENS_JSON = exports.LLM_MAX_TOKENS_DEFAULT = exports.LLM_BASE_URL = exports.LLM_MODEL_SECONDARY = exports.LLM_MODEL_PRIMARY = void 0;
12
+ exports.YAML_LINE_WIDTH = exports.STOP_WORDS = exports.CLAIM_DURATION_OPTIONS = exports.ESCALATION_BULK_RESOLVE_MAX = exports.YAML_VERSION_LIMIT = exports.YAML_LIST_LIMIT = exports.QUERY_LIMIT_MAX = exports.QUERY_LIMIT_DEFAULT = exports.CONFIG_CACHE_TTL_MS = exports.MCP_TOOL_TIMEOUT_MS = exports.WORKFLOW_SYNC_TIMEOUT_MS = exports.JOB_EXPIRE_SECS = exports.WORKFLOW_EXPIRE_SECS = exports.TOOL_ARG_LIMIT_CAP = exports.TOOL_ROUNDS_MCP_QUERY = exports.TOOL_ROUNDS_TRIAGE = exports.TOOL_RESULT_MAX_CHARS = exports.LLM_MAX_INPUT_CHARS = exports.LLM_MAX_ARRAY_ITEMS = exports.LLM_MAX_TOKENS_VISION = exports.LLM_MAX_TOKENS_JSON = exports.LLM_MAX_TOKENS_DEFAULT = exports.LLM_BASE_URL = exports.LLM_MODEL_SECONDARY = exports.LLM_MODEL_PRIMARY = void 0;
13
13
  function envInt(key, fallback) {
14
14
  const v = process.env[key];
15
15
  if (v === undefined || v === '')
@@ -67,6 +67,8 @@ exports.YAML_LIST_LIMIT = envInt('LT_YAML_LIST_LIMIT', 50);
67
67
  /** Default page size for YAML workflow version history. */
68
68
  exports.YAML_VERSION_LIMIT = envInt('LT_YAML_VERSION_LIMIT', 20);
69
69
  // ── Escalation ──────────────────────────────────────────────────────
70
+ /** Maximum items per atomic bulk resolve (POST /escalations/resolve-all-or-none). */
71
+ exports.ESCALATION_BULK_RESOLVE_MAX = envInt('LT_ESCALATION_BULK_RESOLVE_MAX', 100);
70
72
  /**
71
73
  * Claim duration presets shown in the dashboard (minutes).
72
74
  * Override via JSON array, e.g. LT_CLAIM_DURATION_OPTIONS='[15,30,60,480]'
@@ -66,6 +66,24 @@ function registerResolveRoutes(router) {
66
66
  }, req.auth);
67
67
  res.status(result.status).json(result.data ?? { error: result.error });
68
68
  });
69
+ /**
70
+ * POST /api/escalations/resolve-all-or-none
71
+ * Atomic bulk resolve with per-row payloads: every listed escalation resolves
72
+ * with its own resolverPayload in one statement, or nothing resolves. Rows
73
+ * backing a live condition() waiter are woken with their own payload (same
74
+ * wake contract as /:id/resolve). 409 returns { error, failedIds, failed }
75
+ * naming exactly the rows that blocked the batch. Max 100 items per call.
76
+ * Body: { items: Array<{ id: string, resolverPayload: Record<string, any> }>,
77
+ * metadata?: Record<string, any>, requireClaimed?: boolean }
78
+ */
79
+ router.post('/resolve-all-or-none', async (req, res) => {
80
+ const result = await api.resolveAllOrNone({
81
+ items: req.body?.items,
82
+ metadata: req.body?.metadata,
83
+ requireClaimed: req.body?.requireClaimed,
84
+ }, req.auth);
85
+ res.status(result.status).json(result.data ?? { error: result.error });
86
+ });
69
87
  /**
70
88
  * POST /api/escalations/:id/resolve
71
89
  * Resolve a pending escalation with a human-provided payload. Routes by
@@ -153,6 +153,14 @@ export declare function createClient(options?: LTClientOptions): {
153
153
  resolverPayload: Record<string, any>;
154
154
  metadata?: Record<string, any>;
155
155
  }, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
156
+ resolveAllOrNone: (input: {
157
+ items: Array<{
158
+ id: string;
159
+ resolverPayload: Record<string, any>;
160
+ }>;
161
+ metadata?: Record<string, any>;
162
+ requireClaimed?: boolean;
163
+ }, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
156
164
  releaseExpired: typeof escalationsApi.releaseExpiredClaims;
157
165
  updatePriority: (input: {
158
166
  ids: string[];
@@ -128,6 +128,7 @@ function createClient(options = {}) {
128
128
  resolve: bindAuth(escalationsApi.resolveEscalation, auth),
129
129
  resolveBySignalKey: bindAuth(escalationsApi.resolveBySignalKey, auth),
130
130
  resolveByIds: bindAuth(escalationsApi.resolveByIds, auth),
131
+ resolveAllOrNone: bindAuth(escalationsApi.resolveAllOrNone, auth),
131
132
  releaseExpired: escalationsApi.releaseExpiredClaims,
132
133
  updatePriority: bindAuth(escalationsApi.updatePriority, auth),
133
134
  bulkClaim: bindAuth(escalationsApi.bulkClaim, auth),
@@ -36,6 +36,42 @@ export declare function resolveEscalation(id: string, resolverPayload: Record<st
36
36
  * `resolveEscalation` (which delivers the signal).
37
37
  */
38
38
  export declare function resolveEscalationsByIds(ids: string[], resolverPayload: Record<string, any>, metadata?: Record<string, any>): Promise<LTEscalationRecord[]>;
39
+ /**
40
+ * Resolve a SET of escalations atomically — every listed row resolves, each
41
+ * with its OWN resolverPayload, or none do. One SQL statement locks the rows
42
+ * in deterministic id order, applies per-row payloads, and commits each
43
+ * waiter's wake WITH its resolve. Unlike {@link resolveEscalationsByIds},
44
+ * rows backing a live `condition()` waiter are first-class here: each is
45
+ * woken with its own payload as the condition's return value.
46
+ *
47
+ * On failure NOTHING is written and `failed` names exactly the rows that
48
+ * blocked the batch (`not-found`, `already-resolved`, `already-cancelled`,
49
+ * `already-expired`, `assignee-mismatch`) — rows that were themselves
50
+ * resolvable stay pending and are not listed.
51
+ *
52
+ * `assertAssignee` (optional) additionally requires every row to be assigned
53
+ * to that principal, asserted inside the same guarded statement — closing the
54
+ * claim-race window for claim-then-resolve flows.
55
+ */
56
+ export declare function resolveEscalationsAllOrNone(items: Array<{
57
+ id: string;
58
+ resolverPayload: Record<string, any>;
59
+ }>, metadata?: Record<string, any>, assertAssignee?: string): Promise<{
60
+ ok: true;
61
+ escalations: LTEscalationRecord[];
62
+ } | {
63
+ ok: false;
64
+ failed: Array<{
65
+ id: string;
66
+ reason: string;
67
+ }>;
68
+ }>;
69
+ /**
70
+ * Fetch full records for a set of escalation IDs in one indexed query.
71
+ * Used by bulk orchestrators that need per-row context beyond the scope
72
+ * fields — signal routing shape, `metadata.form_schema` for redaction.
73
+ */
74
+ export declare function getEscalationsByIds(ids: string[]): Promise<LTEscalationRecord[]>;
39
75
  /**
40
76
  * Look up an efficient (atomic) escalation by its `signal_key` — the signal id
41
77
  * passed to `conditionLT(signalId, config)` / `condition(signalId, config)`.
@@ -4,6 +4,8 @@ exports.createEscalation = createEscalation;
4
4
  exports.claimEscalation = claimEscalation;
5
5
  exports.resolveEscalation = resolveEscalation;
6
6
  exports.resolveEscalationsByIds = resolveEscalationsByIds;
7
+ exports.resolveEscalationsAllOrNone = resolveEscalationsAllOrNone;
8
+ exports.getEscalationsByIds = getEscalationsByIds;
7
9
  exports.getEscalationBySignalKey = getEscalationBySignalKey;
8
10
  exports.resolveEscalationBySignalKey = resolveEscalationBySignalKey;
9
11
  exports.cancelEscalation = cancelEscalation;
@@ -165,6 +167,57 @@ async function resolveEscalationsByIds(ids, resolverPayload, metadata) {
165
167
  }
166
168
  return records;
167
169
  }
170
+ /**
171
+ * Resolve a SET of escalations atomically — every listed row resolves, each
172
+ * with its OWN resolverPayload, or none do. One SQL statement locks the rows
173
+ * in deterministic id order, applies per-row payloads, and commits each
174
+ * waiter's wake WITH its resolve. Unlike {@link resolveEscalationsByIds},
175
+ * rows backing a live `condition()` waiter are first-class here: each is
176
+ * woken with its own payload as the condition's return value.
177
+ *
178
+ * On failure NOTHING is written and `failed` names exactly the rows that
179
+ * blocked the batch (`not-found`, `already-resolved`, `already-cancelled`,
180
+ * `already-expired`, `assignee-mismatch`) — rows that were themselves
181
+ * resolvable stay pending and are not listed.
182
+ *
183
+ * `assertAssignee` (optional) additionally requires every row to be assigned
184
+ * to that principal, asserted inside the same guarded statement — closing the
185
+ * claim-race window for claim-then-resolve flows.
186
+ */
187
+ async function resolveEscalationsAllOrNone(items, metadata, assertAssignee) {
188
+ if (items.length === 0)
189
+ return { ok: true, escalations: [] };
190
+ const client = await (0, client_1.escalations)();
191
+ const result = await client.resolveAllOrNone({ items, metadata, assertAssignee });
192
+ if (!result.ok)
193
+ return { ok: false, failed: result.failed };
194
+ const records = (0, map_1.toEscalationRecords)(result.entries);
195
+ for (const escalation of records) {
196
+ publishEscalationChange({
197
+ type: 'escalation.resolved',
198
+ source: 'service',
199
+ workflowId: escalation.workflow_id || '',
200
+ workflowName: escalation.workflow_type || '',
201
+ taskQueue: escalation.task_queue || '',
202
+ escalationId: escalation.id,
203
+ status: 'resolved',
204
+ data: {},
205
+ });
206
+ }
207
+ return { ok: true, escalations: records };
208
+ }
209
+ /**
210
+ * Fetch full records for a set of escalation IDs in one indexed query.
211
+ * Used by bulk orchestrators that need per-row context beyond the scope
212
+ * fields — signal routing shape, `metadata.form_schema` for redaction.
213
+ */
214
+ async function getEscalationsByIds(ids) {
215
+ if (ids.length === 0)
216
+ return [];
217
+ const client = await (0, client_1.escalations)();
218
+ const rows = await client.list({ ids, limit: LOOKUP_LIMIT });
219
+ return (0, map_1.toEscalationRecords)(rows);
220
+ }
168
221
  /**
169
222
  * Look up an efficient (atomic) escalation by its `signal_key` — the signal id
170
223
  * passed to `conditionLT(signalId, config)` / `condition(signalId, config)`.
@@ -38,6 +38,7 @@ const hotmesh_1 = require("@hotmeshio/hotmesh");
38
38
  const db_1 = require("../../lib/db");
39
39
  const logger_1 = require("../../lib/logger");
40
40
  const dbaService = __importStar(require("../dba"));
41
+ const client_1 = require("../escalation/client");
41
42
  const CRON_TOPIC = 'lt.maintenance.prune';
42
43
  const CRON_ID = 'lt-maintenance-nightly';
43
44
  /**
@@ -84,6 +85,27 @@ async function executeRule(appId, rule) {
84
85
  streams: false,
85
86
  });
86
87
  break;
88
+ // Age out terminal escalation rows (resolved/cancelled/expired). The
89
+ // engine-owned prune deletes at most one batch per call in one atomic
90
+ // statement; loop until the horizon is drained. Pending rows and live
91
+ // condition() waiters are never touched — every engine state transition
92
+ // guards on status='pending', so terminal rows are inert audit records.
93
+ case rule.target === 'escalations' && rule.action === 'delete': {
94
+ const client = await (0, client_1.escalations)();
95
+ let deleted = 0;
96
+ let batch;
97
+ do {
98
+ ({ deleted: batch } = await client.prune({
99
+ olderThan: rule.olderThan,
100
+ statuses: rule.statuses,
101
+ }));
102
+ deleted += batch;
103
+ } while (batch > 0);
104
+ if (deleted > 0) {
105
+ logger_1.loggerRegistry.info(`[lt-maintenance] escalations pruned: ${deleted} (olderThan: ${rule.olderThan})`);
106
+ }
107
+ break;
108
+ }
87
109
  default:
88
110
  logger_1.loggerRegistry.warn(`[lt-maintenance] unknown rule, skipping: ${JSON.stringify(rule)}`);
89
111
  }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export interface LTMaintenanceRule {
5
5
  /** Which resource to target */
6
- target: 'streams' | 'jobs';
6
+ target: 'streams' | 'jobs' | 'escalations';
7
7
  /** delete = hard-delete rows; prune = strip execution artifacts */
8
8
  action: 'delete' | 'prune';
9
9
  /** Postgres interval for the retention window, e.g. '7 days', '90 days' */
@@ -12,6 +12,11 @@ export interface LTMaintenanceRule {
12
12
  hasEntity?: boolean;
13
13
  /** When true, only target jobs that have already been pruned (pruned_at IS NOT NULL) */
14
14
  pruned?: boolean;
15
+ /**
16
+ * When target is 'escalations': which terminal statuses to age out.
17
+ * Defaults to all three. Pending rows and live waiters are never touched.
18
+ */
19
+ statuses?: Array<'resolved' | 'cancelled' | 'expired'>;
15
20
  }
16
21
  /**
17
22
  * Full maintenance configuration: schedule + ordered rules.
@@ -1,2 +1,2 @@
1
- import{j as o}from"./vendor-query-B2UbickB.js";import{c as n}from"./tasks-Crk9Y3C4.js";import{t as m}from"./index-DwWP-Z_c.js";import{f as c}from"./useEventHooks-Dn_vN2xE.js";import{u}from"./mcp-1lzlgtS8.js";import{P as d}from"./PageHeaderWithStats-W3akV6nB.js";import"./vendor-react-CXumBFUA.js";import"./vendor-icons-DOIDKgo6.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-B-JptT54.js.map
1
+ import{j as o}from"./vendor-query-B2UbickB.js";import{c as n}from"./tasks-GG8c_U9w.js";import{t as m}from"./index-B_aFcGv9.js";import{f as c}from"./useEventHooks-82IiMmOc.js";import{u}from"./mcp-B4F-T-7R.js";import{P as d}from"./PageHeaderWithStats-W3akV6nB.js";import"./vendor-react-CXumBFUA.js";import"./vendor-icons-DOIDKgo6.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-RrSvb8d-.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AdminDashboard-B-JptT54.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-RrSvb8d-.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"}