@hotmeshio/long-tail 0.24.2 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/build/api/escalations/accumulate.js +8 -4
  2. package/build/api/escalations/metadata.js +4 -3
  3. package/build/api/escalations/related.d.ts +1 -1
  4. package/build/api/escalations/related.js +28 -18
  5. package/build/services/escalation/accumulate.d.ts +3 -1
  6. package/build/services/escalation/facet-sql.js +4 -2
  7. package/build/services/escalation/index.d.ts +1 -0
  8. package/build/services/escalation/index.js +4 -1
  9. package/build/services/escalation/related-extremes.d.ts +17 -0
  10. package/build/services/escalation/related-extremes.js +65 -0
  11. package/build/services/escalation/related.d.ts +4 -0
  12. package/build/services/escalation/related.js +2 -0
  13. package/build/services/escalation/resolver-validation.js +7 -0
  14. package/build/services/escalation/roster.d.ts +13 -0
  15. package/build/services/escalation/roster.js +37 -0
  16. package/build/services/escalation/submit-guard.d.ts +3 -0
  17. package/build/services/escalation/submit-guard.js +21 -2
  18. package/build/services/mcp/server-tools.js +1 -1
  19. package/build/shared/form-validation/display-only-widgets.d.ts +1 -0
  20. package/build/shared/form-validation/display-only-widgets.js +1 -0
  21. package/build/shared/form-validation/index.d.ts +1 -0
  22. package/build/shared/form-validation/index.js +1 -0
  23. package/build/shared/form-validation/validate-resolver-payload.d.ts +1 -0
  24. package/build/shared/form-validation/validate-resolver-payload.js +2 -1
  25. package/build/shared/form-validation/x-lt-help.d.ts +1 -1
  26. package/build/shared/form-validation/x-lt-help.js +2 -1
  27. package/build/shared/form-validation/x-lt-roster.d.ts +92 -0
  28. package/build/shared/form-validation/x-lt-roster.js +234 -0
  29. package/build/shared/form-validation/x-lt-show-if.d.ts +8 -0
  30. package/build/shared/form-validation/x-lt-show-if.js +13 -0
  31. package/build/shared/form-validation/x-lt-submit-guard.d.ts +14 -1
  32. package/build/shared/form-validation/x-lt-submit-guard.js +4 -1
  33. package/build/shared/list-schema/aggregate.d.ts +19 -0
  34. package/build/shared/list-schema/aggregate.js +66 -0
  35. package/build/shared/list-schema/index.d.ts +2 -0
  36. package/build/shared/list-schema/index.js +7 -1
  37. package/build/shared/list-schema/types.d.ts +15 -2
  38. package/build/shared/list-schema/types.js +6 -1
  39. package/build/shared/list-schema/validate.js +28 -2
  40. package/build/tsconfig.tsbuildinfo +1 -1
  41. package/dashboard/dist/assets/{AdminDashboard-B3mkMIOT.js → AdminDashboard-DWVRAu63.js} +2 -2
  42. package/dashboard/dist/assets/{AdminDashboard-B3mkMIOT.js.map → AdminDashboard-DWVRAu63.js.map} +1 -1
  43. package/dashboard/dist/assets/{AgentConfigPage-CQj2B678.js → AgentConfigPage-Exjtjbvp.js} +6 -6
  44. package/dashboard/dist/assets/{AgentConfigPage-CQj2B678.js.map → AgentConfigPage-Exjtjbvp.js.map} +1 -1
  45. package/dashboard/dist/assets/{AgentDetailPage-CzrD8JJI.js → AgentDetailPage-nDbZo6RB.js} +3 -3
  46. package/dashboard/dist/assets/{AgentDetailPage-CzrD8JJI.js.map → AgentDetailPage-nDbZo6RB.js.map} +1 -1
  47. package/dashboard/dist/assets/{AgentsPage-jg2OFwyW.js → AgentsPage-Dsk9iHps.js} +2 -2
  48. package/dashboard/dist/assets/{AgentsPage-jg2OFwyW.js.map → AgentsPage-Dsk9iHps.js.map} +1 -1
  49. package/dashboard/dist/assets/AvailableEscalationsPage-D1mCqj8Z.js +2 -0
  50. package/dashboard/dist/assets/{AvailableEscalationsPage-IS28XBRe.js.map → AvailableEscalationsPage-D1mCqj8Z.js.map} +1 -1
  51. package/dashboard/dist/assets/{BotPicker-DvEJFpwS.js → BotPicker-u5760MWZ.js} +2 -2
  52. package/dashboard/dist/assets/{BotPicker-DvEJFpwS.js.map → BotPicker-u5760MWZ.js.map} +1 -1
  53. package/dashboard/dist/assets/{BulkAssignModal-BoQCi-YC.js → BulkAssignModal-CtISXXmW.js} +2 -2
  54. package/dashboard/dist/assets/{BulkAssignModal-BoQCi-YC.js.map → BulkAssignModal-CtISXXmW.js.map} +1 -1
  55. package/dashboard/dist/assets/{CapabilitiesPage-kwlrcb_t.js → CapabilitiesPage-BKIlrQfU.js} +2 -2
  56. package/dashboard/dist/assets/{CapabilitiesPage-kwlrcb_t.js.map → CapabilitiesPage-BKIlrQfU.js.map} +1 -1
  57. package/dashboard/dist/assets/{CollapsibleSection-UMIV4KIj.js → CollapsibleSection-DlBVTFqc.js} +2 -2
  58. package/dashboard/dist/assets/{CollapsibleSection-UMIV4KIj.js.map → CollapsibleSection-DlBVTFqc.js.map} +1 -1
  59. package/dashboard/dist/assets/{ConfirmDeleteModal-C5puwMg7.js → ConfirmDeleteModal-Pabkchg_.js} +2 -2
  60. package/dashboard/dist/assets/{ConfirmDeleteModal-C5puwMg7.js.map → ConfirmDeleteModal-Pabkchg_.js.map} +1 -1
  61. package/dashboard/dist/assets/{ConnectedAppsPage-drZa65kP.js → ConnectedAppsPage-DG2YZGN3.js} +2 -2
  62. package/dashboard/dist/assets/{ConnectedAppsPage-drZa65kP.js.map → ConnectedAppsPage-DG2YZGN3.js.map} +1 -1
  63. package/dashboard/dist/assets/CountdownTimer-5t8S2qMi.js +2 -0
  64. package/dashboard/dist/assets/CountdownTimer-5t8S2qMi.js.map +1 -0
  65. package/dashboard/dist/assets/{CredentialsPage-CaFQ6vLb.js → CredentialsPage-CPVbYQow.js} +2 -2
  66. package/dashboard/dist/assets/{CredentialsPage-CaFQ6vLb.js.map → CredentialsPage-CPVbYQow.js.map} +1 -1
  67. package/dashboard/dist/assets/{CronLabel-Co5j7tzW.js → CronLabel-C7UbTrO-.js} +2 -2
  68. package/dashboard/dist/assets/{CronLabel-Co5j7tzW.js.map → CronLabel-C7UbTrO-.js.map} +1 -1
  69. package/dashboard/dist/assets/{DropZone-B1Tdfddc.js → DropZone-DCZpORx-.js} +2 -2
  70. package/dashboard/dist/assets/{DropZone-B1Tdfddc.js.map → DropZone-DCZpORx-.js.map} +1 -1
  71. package/dashboard/dist/assets/{ElapsedCell-WJyE9G0T.js → ElapsedCell-Yz7-LbtE.js} +2 -2
  72. package/dashboard/dist/assets/{ElapsedCell-WJyE9G0T.js.map → ElapsedCell-Yz7-LbtE.js.map} +1 -1
  73. package/dashboard/dist/assets/{EntityTimelinePanel-CDFFfX9d.js → EntityTimelinePanel-xgPRdKEq.js} +2 -2
  74. package/dashboard/dist/assets/{EntityTimelinePanel-CDFFfX9d.js.map → EntityTimelinePanel-xgPRdKEq.js.map} +1 -1
  75. package/dashboard/dist/assets/{EscalationListSchemaPage-CMrUlaKI.js → EscalationListSchemaPage-CqCd-y6B.js} +3 -3
  76. package/dashboard/dist/assets/{EscalationListSchemaPage-CMrUlaKI.js.map → EscalationListSchemaPage-CqCd-y6B.js.map} +1 -1
  77. package/dashboard/dist/assets/{EscalationSchemaPage-Dx2Lyfrz.js → EscalationSchemaPage-D8YVQNph.js} +3 -3
  78. package/dashboard/dist/assets/{EscalationSchemaPage-Dx2Lyfrz.js.map → EscalationSchemaPage-D8YVQNph.js.map} +1 -1
  79. package/dashboard/dist/assets/EscalationTimeline-D6jrDcBb.js +2 -0
  80. package/dashboard/dist/assets/{EscalationTimeline-d3nvshOk.js.map → EscalationTimeline-D6jrDcBb.js.map} +1 -1
  81. package/dashboard/dist/assets/{EscalationTitleSelect-DWQieOM9.js → EscalationTitleSelect-CGGT-QTu.js} +2 -2
  82. package/dashboard/dist/assets/{EscalationTitleSelect-DWQieOM9.js.map → EscalationTitleSelect-CGGT-QTu.js.map} +1 -1
  83. package/dashboard/dist/assets/{EscalationsOverview-BX8Cpi0X.js → EscalationsOverview-B7O4ttP4.js} +2 -2
  84. package/dashboard/dist/assets/{EscalationsOverview-BX8Cpi0X.js.map → EscalationsOverview-B7O4ttP4.js.map} +1 -1
  85. package/dashboard/dist/assets/{EventTable-D1-ITVXS.js → EventTable-DJniXnhe.js} +2 -2
  86. package/dashboard/dist/assets/{EventTable-D1-ITVXS.js.map → EventTable-DJniXnhe.js.map} +1 -1
  87. package/dashboard/dist/assets/{FilterBar-ABC9ctin.js → FilterBar-f-LEKcHI.js} +2 -2
  88. package/dashboard/dist/assets/{FilterBar-ABC9ctin.js.map → FilterBar-f-LEKcHI.js.map} +1 -1
  89. package/dashboard/dist/assets/{FormattedValue-k27T4bG7.js → FormattedValue-CUtv1g3k.js} +2 -2
  90. package/dashboard/dist/assets/{FormattedValue-k27T4bG7.js.map → FormattedValue-CUtv1g3k.js.map} +1 -1
  91. package/dashboard/dist/assets/{GraphInvokePage-DKUErxWc.js → GraphInvokePage-CR0MtYv8.js} +2 -2
  92. package/dashboard/dist/assets/{GraphInvokePage-DKUErxWc.js.map → GraphInvokePage-CR0MtYv8.js.map} +1 -1
  93. package/dashboard/dist/assets/{HomePage-C6u9dIpR.js → HomePage-HVw7T5ER.js} +2 -2
  94. package/dashboard/dist/assets/{HomePage-C6u9dIpR.js.map → HomePage-HVw7T5ER.js.map} +1 -1
  95. package/dashboard/dist/assets/{ListToolbar-gA5rFzkz.js → ListToolbar-CTGK5BXW.js} +2 -2
  96. package/dashboard/dist/assets/{ListToolbar-gA5rFzkz.js.map → ListToolbar-CTGK5BXW.js.map} +1 -1
  97. package/dashboard/dist/assets/{McpOverview-BOPo3J_i.js → McpOverview-B2bbKKu2.js} +2 -2
  98. package/dashboard/dist/assets/{McpOverview-BOPo3J_i.js.map → McpOverview-B2bbKKu2.js.map} +1 -1
  99. package/dashboard/dist/assets/{McpQueryDetailPage-BRVVi0Zh.js → McpQueryDetailPage-DgLxwwJy.js} +2 -2
  100. package/dashboard/dist/assets/{McpQueryDetailPage-BRVVi0Zh.js.map → McpQueryDetailPage-DgLxwwJy.js.map} +1 -1
  101. package/dashboard/dist/assets/{McpQueryPage-Dmbb6SAc.js → McpQueryPage-CSkczeJP.js} +2 -2
  102. package/dashboard/dist/assets/{McpQueryPage-Dmbb6SAc.js.map → McpQueryPage-CSkczeJP.js.map} +1 -1
  103. package/dashboard/dist/assets/McpRunDetailPage-CrUsDPRD.js +2 -0
  104. package/dashboard/dist/assets/{McpRunDetailPage-bMXNO-6V.js.map → McpRunDetailPage-CrUsDPRD.js.map} +1 -1
  105. package/dashboard/dist/assets/{McpRunsPage-Bi9AMWja.js → McpRunsPage-twxFdTtJ.js} +2 -2
  106. package/dashboard/dist/assets/{McpRunsPage-Bi9AMWja.js.map → McpRunsPage-twxFdTtJ.js.map} +1 -1
  107. package/dashboard/dist/assets/{NamespacePill-DwM5pNA4.js → NamespacePill-CSZT2fA4.js} +2 -2
  108. package/dashboard/dist/assets/{NamespacePill-DwM5pNA4.js.map → NamespacePill-CSZT2fA4.js.map} +1 -1
  109. package/dashboard/dist/assets/{OperationsPage-CvR74ZUJ.js → OperationsPage-gOVMrL_a.js} +3 -3
  110. package/dashboard/dist/assets/{OperationsPage-CvR74ZUJ.js.map → OperationsPage-gOVMrL_a.js.map} +1 -1
  111. package/dashboard/dist/assets/OperatorDashboard-BoeZIyup.js +2 -0
  112. package/dashboard/dist/assets/{OperatorDashboard-DctmZw10.js.map → OperatorDashboard-BoeZIyup.js.map} +1 -1
  113. package/dashboard/dist/assets/{PageHeader-CMd3f4bz.js → PageHeader-C4z1ExF7.js} +2 -2
  114. package/dashboard/dist/assets/{PageHeader-CMd3f4bz.js.map → PageHeader-C4z1ExF7.js.map} +1 -1
  115. package/dashboard/dist/assets/{PageHeaderWithStats-DHj8Mqox.js → PageHeaderWithStats-B_f_Sz_Q.js} +2 -2
  116. package/dashboard/dist/assets/{PageHeaderWithStats-DHj8Mqox.js.map → PageHeaderWithStats-B_f_Sz_Q.js.map} +1 -1
  117. package/dashboard/dist/assets/{PersonaDetailPage-Ubqm2rQH.js → PersonaDetailPage-CDktk1mi.js} +2 -2
  118. package/dashboard/dist/assets/{PersonaDetailPage-Ubqm2rQH.js.map → PersonaDetailPage-CDktk1mi.js.map} +1 -1
  119. package/dashboard/dist/assets/{PersonasPage-BpFL2rpo.js → PersonasPage-Bs097x07.js} +2 -2
  120. package/dashboard/dist/assets/{PersonasPage-BpFL2rpo.js.map → PersonasPage-Bs097x07.js.map} +1 -1
  121. package/dashboard/dist/assets/PortalPage-DjfjerpF.js +2 -0
  122. package/dashboard/dist/assets/{PortalPage-Dfc_Q02R.js.map → PortalPage-DjfjerpF.js.map} +1 -1
  123. package/dashboard/dist/assets/{ProcessDetailPage-liJspvQh.js → ProcessDetailPage-B30RatjD.js} +2 -2
  124. package/dashboard/dist/assets/{ProcessDetailPage-liJspvQh.js.map → ProcessDetailPage-B30RatjD.js.map} +1 -1
  125. package/dashboard/dist/assets/{ProcessesListPage-C3OM5ZUy.js → ProcessesListPage-DrvjzgWT.js} +2 -2
  126. package/dashboard/dist/assets/{ProcessesListPage-C3OM5ZUy.js.map → ProcessesListPage-DrvjzgWT.js.map} +1 -1
  127. package/dashboard/dist/assets/ResolverForm-Bl8Pibyz.js +8 -0
  128. package/dashboard/dist/assets/ResolverForm-Bl8Pibyz.js.map +1 -0
  129. package/dashboard/dist/assets/{RoleDetailPage-CrlYCh-R.js → RoleDetailPage-ClYgn-3d.js} +3 -3
  130. package/dashboard/dist/assets/{RoleDetailPage-CrlYCh-R.js.map → RoleDetailPage-ClYgn-3d.js.map} +1 -1
  131. package/dashboard/dist/assets/{RolePill-Di2CAHuD.js → RolePill-Bw_n7EpR.js} +2 -2
  132. package/dashboard/dist/assets/{RolePill-Di2CAHuD.js.map → RolePill-Bw_n7EpR.js.map} +1 -1
  133. package/dashboard/dist/assets/{RolesPage-BaazL_pt.js → RolesPage-B_3qWsvQ.js} +2 -2
  134. package/dashboard/dist/assets/{RolesPage-BaazL_pt.js.map → RolesPage-B_3qWsvQ.js.map} +1 -1
  135. package/dashboard/dist/assets/{RunAsSelector-DxuV0fa1.js → RunAsSelector-CbJT50Hp.js} +2 -2
  136. package/dashboard/dist/assets/{RunAsSelector-DxuV0fa1.js.map → RunAsSelector-CbJT50Hp.js.map} +1 -1
  137. package/dashboard/dist/assets/{ScanCodesPage-C0mvmYTq.js → ScanCodesPage-CIIDuh8w.js} +2 -2
  138. package/dashboard/dist/assets/{ScanCodesPage-C0mvmYTq.js.map → ScanCodesPage-CIIDuh8w.js.map} +1 -1
  139. package/dashboard/dist/assets/{ScanSchemeDetailPage-CiJgt5dZ.js → ScanSchemeDetailPage-Bd3P3eyh.js} +2 -2
  140. package/dashboard/dist/assets/{ScanSchemeDetailPage-CiJgt5dZ.js.map → ScanSchemeDetailPage-Bd3P3eyh.js.map} +1 -1
  141. package/dashboard/dist/assets/ScanStationPage-BiO34nov.js +2 -0
  142. package/dashboard/dist/assets/ScanStationPage-BiO34nov.js.map +1 -0
  143. package/dashboard/dist/assets/{ScopeBadge-CSItPVOH.js → ScopeBadge-CKgfwTy3.js} +2 -2
  144. package/dashboard/dist/assets/{ScopeBadge-CSItPVOH.js.map → ScopeBadge-CKgfwTy3.js.map} +1 -1
  145. package/dashboard/dist/assets/{StickyPagination-CqbjVY6T.js → StickyPagination-BNOuYZ1m.js} +2 -2
  146. package/dashboard/dist/assets/{StickyPagination-CqbjVY6T.js.map → StickyPagination-BNOuYZ1m.js.map} +1 -1
  147. package/dashboard/dist/assets/{StreamMessageDetail-wX3i0aqs.js → StreamMessageDetail-ALVUnfF1.js} +2 -2
  148. package/dashboard/dist/assets/{StreamMessageDetail-wX3i0aqs.js.map → StreamMessageDetail-ALVUnfF1.js.map} +1 -1
  149. package/dashboard/dist/assets/{SwimlaneTimeline-C50PsFoV.js → SwimlaneTimeline-B5b8-xqI.js} +2 -2
  150. package/dashboard/dist/assets/{SwimlaneTimeline-C50PsFoV.js.map → SwimlaneTimeline-B5b8-xqI.js.map} +1 -1
  151. package/dashboard/dist/assets/{TagInput-CAgdLN_b.js → TagInput-B6fMAqxd.js} +2 -2
  152. package/dashboard/dist/assets/{TagInput-CAgdLN_b.js.map → TagInput-B6fMAqxd.js.map} +1 -1
  153. package/dashboard/dist/assets/{TaskDetailPage-bbNSv4Ae.js → TaskDetailPage-CoV3WcTA.js} +2 -2
  154. package/dashboard/dist/assets/{TaskDetailPage-bbNSv4Ae.js.map → TaskDetailPage-CoV3WcTA.js.map} +1 -1
  155. package/dashboard/dist/assets/{TaskQueuePill-h0oorVMe.js → TaskQueuePill-BnDp_DE6.js} +2 -2
  156. package/dashboard/dist/assets/{TaskQueuePill-h0oorVMe.js.map → TaskQueuePill-BnDp_DE6.js.map} +1 -1
  157. package/dashboard/dist/assets/{TasksListPage-CDWnm_d9.js → TasksListPage-CkMmOYOE.js} +2 -2
  158. package/dashboard/dist/assets/{TasksListPage-CDWnm_d9.js.map → TasksListPage-CkMmOYOE.js.map} +1 -1
  159. package/dashboard/dist/assets/{TimeAgo-BLjqlfoX.js → TimeAgo-DVkFgECX.js} +2 -2
  160. package/dashboard/dist/assets/{TimeAgo-BLjqlfoX.js.map → TimeAgo-DVkFgECX.js.map} +1 -1
  161. package/dashboard/dist/assets/{TimestampCell-CnW0ENb5.js → TimestampCell-CfTc6Txy.js} +2 -2
  162. package/dashboard/dist/assets/{TimestampCell-CnW0ENb5.js.map → TimestampCell-CfTc6Txy.js.map} +1 -1
  163. package/dashboard/dist/assets/{ToolPill-CQCsVdzD.js → ToolPill-BRZWo4l8.js} +2 -2
  164. package/dashboard/dist/assets/{ToolPill-CQCsVdzD.js.map → ToolPill-BRZWo4l8.js.map} +1 -1
  165. package/dashboard/dist/assets/{ToolTestPanel-DkMgCB-k.js → ToolTestPanel-kvqZqM0A.js} +2 -2
  166. package/dashboard/dist/assets/{ToolTestPanel-DkMgCB-k.js.map → ToolTestPanel-kvqZqM0A.js.map} +1 -1
  167. package/dashboard/dist/assets/{TopicDetailPage-g3pljKKX.js → TopicDetailPage-CjkAAyy8.js} +4 -4
  168. package/dashboard/dist/assets/{TopicDetailPage-g3pljKKX.js.map → TopicDetailPage-CjkAAyy8.js.map} +1 -1
  169. package/dashboard/dist/assets/{TopicsPage-CVcCYdy-.js → TopicsPage-CJZnv50y.js} +2 -2
  170. package/dashboard/dist/assets/{TopicsPage-CVcCYdy-.js.map → TopicsPage-CJZnv50y.js.map} +1 -1
  171. package/dashboard/dist/assets/{UserName-D6zGIK2i.js → UserName-CPJPZnN1.js} +2 -2
  172. package/dashboard/dist/assets/{UserName-D6zGIK2i.js.map → UserName-CPJPZnN1.js.map} +1 -1
  173. package/dashboard/dist/assets/WorkflowExecutionPage-46UV5pJd.js +2 -0
  174. package/dashboard/dist/assets/{WorkflowExecutionPage-B8g81FCJ.js.map → WorkflowExecutionPage-46UV5pJd.js.map} +1 -1
  175. package/dashboard/dist/assets/{WorkflowPill-Dg7BDTyM.js → WorkflowPill-Cly9Ln_3.js} +2 -2
  176. package/dashboard/dist/assets/{WorkflowPill-Dg7BDTyM.js.map → WorkflowPill-Cly9Ln_3.js.map} +1 -1
  177. package/dashboard/dist/assets/{WorkflowsDashboard-nxT3bv6W.js → WorkflowsDashboard-DtxYdQbQ.js} +2 -2
  178. package/dashboard/dist/assets/{WorkflowsDashboard-nxT3bv6W.js.map → WorkflowsDashboard-DtxYdQbQ.js.map} +1 -1
  179. package/dashboard/dist/assets/{WorkflowsOverview-grI-KAI2.js → WorkflowsOverview-Cg4LSfck.js} +2 -2
  180. package/dashboard/dist/assets/{WorkflowsOverview-grI-KAI2.js.map → WorkflowsOverview-Cg4LSfck.js.map} +1 -1
  181. package/dashboard/dist/assets/{YamlWorkflowDetailPage-BoZ-hfBE.js → YamlWorkflowDetailPage-Del-RCgi.js} +12 -12
  182. package/dashboard/dist/assets/{YamlWorkflowDetailPage-BoZ-hfBE.js.map → YamlWorkflowDetailPage-Del-RCgi.js.map} +1 -1
  183. package/dashboard/dist/assets/{YamlWorkflowsPage-Bf04rwRv.js → YamlWorkflowsPage-BF6Jtx24.js} +2 -2
  184. package/dashboard/dist/assets/{YamlWorkflowsPage-Bf04rwRv.js.map → YamlWorkflowsPage-BF6Jtx24.js.map} +1 -1
  185. package/dashboard/dist/assets/{agents-Dphpdi8l.js → agents-wL-3dMOX.js} +2 -2
  186. package/dashboard/dist/assets/{agents-Dphpdi8l.js.map → agents-wL-3dMOX.js.map} +1 -1
  187. package/dashboard/dist/assets/{bots-DIFE298x.js → bots-D72EsztP.js} +2 -2
  188. package/dashboard/dist/assets/{bots-DIFE298x.js.map → bots-D72EsztP.js.map} +1 -1
  189. package/dashboard/dist/assets/{capabilities-D7Y7LClY.js → capabilities-DXFo6bRb.js} +2 -2
  190. package/dashboard/dist/assets/{capabilities-D7Y7LClY.js.map → capabilities-DXFo6bRb.js.map} +1 -1
  191. package/dashboard/dist/assets/{controlplane-D1TGcYsS.js → controlplane-gQdOgVtH.js} +2 -2
  192. package/dashboard/dist/assets/{controlplane-D1TGcYsS.js.map → controlplane-gQdOgVtH.js.map} +1 -1
  193. package/dashboard/dist/assets/escalation-columns-CSE5wfWQ.js +2 -0
  194. package/dashboard/dist/assets/escalation-columns-CSE5wfWQ.js.map +1 -0
  195. package/dashboard/dist/assets/escalation-items-BIgBWbaw.js +2 -0
  196. package/dashboard/dist/assets/escalation-items-BIgBWbaw.js.map +1 -0
  197. package/dashboard/dist/assets/{index-CeCtqujG.js → index-BaCDL5fh.js} +38 -38
  198. package/dashboard/dist/assets/index-BaCDL5fh.js.map +1 -0
  199. package/dashboard/dist/assets/{index-Dl_8hbYI.js → index-Btm8FtTQ.js} +2 -2
  200. package/dashboard/dist/assets/{index-Dl_8hbYI.js.map → index-Btm8FtTQ.js.map} +1 -1
  201. package/dashboard/dist/assets/index-BvH8T-jb.js +2 -0
  202. package/dashboard/dist/assets/{index-CxdjT1Yk.js.map → index-BvH8T-jb.js.map} +1 -1
  203. package/dashboard/dist/assets/{index-HLu98Sqh.js → index-C-QQ5rKF.js} +2 -2
  204. package/dashboard/dist/assets/{index-HLu98Sqh.js.map → index-C-QQ5rKF.js.map} +1 -1
  205. package/dashboard/dist/assets/{index-DpKOr311.js → index-C1iuZ4Q5.js} +2 -2
  206. package/dashboard/dist/assets/{index-DpKOr311.js.map → index-C1iuZ4Q5.js.map} +1 -1
  207. package/dashboard/dist/assets/{index-ChV7pBjM.js → index-CDxOQ84B.js} +2 -2
  208. package/dashboard/dist/assets/{index-ChV7pBjM.js.map → index-CDxOQ84B.js.map} +1 -1
  209. package/dashboard/dist/assets/index-CED9cLE2.js +3 -0
  210. package/dashboard/dist/assets/index-CED9cLE2.js.map +1 -0
  211. package/dashboard/dist/assets/index-CnU7Jjz3.css +1 -0
  212. package/dashboard/dist/assets/{index-DAvi5_2T.js → index-CptTEhWp.js} +2 -2
  213. package/dashboard/dist/assets/{index-DAvi5_2T.js.map → index-CptTEhWp.js.map} +1 -1
  214. package/dashboard/dist/assets/{index-ag2pCAPu.js → index-Cu0xdX2t.js} +2 -2
  215. package/dashboard/dist/assets/{index-ag2pCAPu.js.map → index-Cu0xdX2t.js.map} +1 -1
  216. package/dashboard/dist/assets/index-D1lfq5iZ.js +13 -0
  217. package/dashboard/dist/assets/{index-gkxPN7Vx.js.map → index-D1lfq5iZ.js.map} +1 -1
  218. package/dashboard/dist/assets/{index-Dy1wWu2e.js → index-czgLyfSo.js} +2 -2
  219. package/dashboard/dist/assets/{index-Dy1wWu2e.js.map → index-czgLyfSo.js.map} +1 -1
  220. package/dashboard/dist/assets/{index-DN-kX7hL.js → index-h1Useskt.js} +2 -2
  221. package/dashboard/dist/assets/{index-DN-kX7hL.js.map → index-h1Useskt.js.map} +1 -1
  222. package/dashboard/dist/assets/{index-BzYcUPdD.js → index-ujGmmwl6.js} +2 -2
  223. package/dashboard/dist/assets/{index-BzYcUPdD.js.map → index-ujGmmwl6.js.map} +1 -1
  224. package/dashboard/dist/assets/{knowledge-DnMs-SOJ.js → knowledge-150lsM68.js} +2 -2
  225. package/dashboard/dist/assets/{knowledge-DnMs-SOJ.js.map → knowledge-150lsM68.js.map} +1 -1
  226. package/dashboard/dist/assets/{mcp-CwW-K3r4.js → mcp-CRtY4v5W.js} +2 -2
  227. package/dashboard/dist/assets/{mcp-CwW-K3r4.js.map → mcp-CRtY4v5W.js.map} +1 -1
  228. package/dashboard/dist/assets/{mcp-query-BZt5e8_Q.js → mcp-query-CDsSMaYq.js} +2 -2
  229. package/dashboard/dist/assets/{mcp-query-BZt5e8_Q.js.map → mcp-query-CDsSMaYq.js.map} +1 -1
  230. package/dashboard/dist/assets/{personas-UA-Xn60f.js → personas-C2Wm4ng1.js} +2 -2
  231. package/dashboard/dist/assets/{personas-UA-Xn60f.js.map → personas-C2Wm4ng1.js.map} +1 -1
  232. package/dashboard/dist/assets/{pipelines-Cu3PARum.js → pipelines-BH0F9-jf.js} +2 -2
  233. package/dashboard/dist/assets/{pipelines-Cu3PARum.js.map → pipelines-BH0F9-jf.js.map} +1 -1
  234. package/dashboard/dist/assets/{tasks-BO6h8GJE.js → tasks-BkUVpaOa.js} +2 -2
  235. package/dashboard/dist/assets/{tasks-BO6h8GJE.js.map → tasks-BkUVpaOa.js.map} +1 -1
  236. package/dashboard/dist/assets/{topics-CWjCR-17.js → topics-Crl8HKHq.js} +2 -2
  237. package/dashboard/dist/assets/{topics-CWjCR-17.js.map → topics-Crl8HKHq.js.map} +1 -1
  238. package/dashboard/dist/assets/{useDebouncedValue-6t0jx1RB.js → useDebouncedValue-Dk3r5xo-.js} +2 -2
  239. package/dashboard/dist/assets/{useDebouncedValue-6t0jx1RB.js.map → useDebouncedValue-Dk3r5xo-.js.map} +1 -1
  240. package/dashboard/dist/assets/{useNamespace-CqpoQx6D.js → useNamespace-BXuyHKAs.js} +2 -2
  241. package/dashboard/dist/assets/{useNamespace-CqpoQx6D.js.map → useNamespace-BXuyHKAs.js.map} +1 -1
  242. package/dashboard/dist/assets/{useYamlActivityEvents-hmCQQwzB.js → useYamlActivityEvents-DSlkjQfb.js} +2 -2
  243. package/dashboard/dist/assets/{useYamlActivityEvents-hmCQQwzB.js.map → useYamlActivityEvents-DSlkjQfb.js.map} +1 -1
  244. package/dashboard/dist/assets/{vendor-icons-CeVtUKyP.js → vendor-icons-C_DQEeBy.js} +2 -2
  245. package/dashboard/dist/assets/{vendor-icons-CeVtUKyP.js.map → vendor-icons-C_DQEeBy.js.map} +1 -1
  246. package/dashboard/dist/assets/{yaml-workflows-ziUdZhKY.js → yaml-workflows-B230v5Za.js} +2 -2
  247. package/dashboard/dist/assets/{yaml-workflows-ziUdZhKY.js.map → yaml-workflows-B230v5Za.js.map} +1 -1
  248. package/dashboard/dist/index.html +3 -3
  249. package/docs/faceted-routing.md +14 -1
  250. package/docs/hitl/x-lt-embed.md +4 -1
  251. package/docs/hitl/x-lt-list-schema.md +19 -2
  252. package/docs/hitl/x-lt-roster.md +112 -0
  253. package/docs/hitl/x-lt-show-if.md +15 -0
  254. package/docs/hitl/x-lt-widget.md +1 -0
  255. package/docs/hitl-guide.md +3 -1
  256. package/docs/scan-codes.md +4 -0
  257. package/docs/schema-enforcement.md +5 -0
  258. package/package.json +2 -2
  259. package/dashboard/dist/assets/AvailableEscalationsPage-IS28XBRe.js +0 -2
  260. package/dashboard/dist/assets/CountdownTimer-LG03dVgR.js +0 -2
  261. package/dashboard/dist/assets/CountdownTimer-LG03dVgR.js.map +0 -1
  262. package/dashboard/dist/assets/EscalationTimeline-d3nvshOk.js +0 -2
  263. package/dashboard/dist/assets/McpRunDetailPage-bMXNO-6V.js +0 -2
  264. package/dashboard/dist/assets/OperatorDashboard-DctmZw10.js +0 -2
  265. package/dashboard/dist/assets/PortalPage-Dfc_Q02R.js +0 -2
  266. package/dashboard/dist/assets/ResolverForm-B1_x8Blv.js +0 -8
  267. package/dashboard/dist/assets/ResolverForm-B1_x8Blv.js.map +0 -1
  268. package/dashboard/dist/assets/ScanStationPage-DzGaXc40.js +0 -2
  269. package/dashboard/dist/assets/ScanStationPage-DzGaXc40.js.map +0 -1
  270. package/dashboard/dist/assets/WorkflowExecutionPage-B8g81FCJ.js +0 -2
  271. package/dashboard/dist/assets/escalation-columns-cwZE6xyo.js +0 -2
  272. package/dashboard/dist/assets/escalation-columns-cwZE6xyo.js.map +0 -1
  273. package/dashboard/dist/assets/index-CeCtqujG.js.map +0 -1
  274. package/dashboard/dist/assets/index-CniRa65p.js +0 -3
  275. package/dashboard/dist/assets/index-CniRa65p.js.map +0 -1
  276. package/dashboard/dist/assets/index-CxdjT1Yk.js +0 -2
  277. package/dashboard/dist/assets/index-gkxPN7Vx.js +0 -13
  278. package/dashboard/dist/assets/index-m9A3UYst.css +0 -1
  279. package/dashboard/dist/assets/validate-BIRn4a6d.js +0 -2
  280. package/dashboard/dist/assets/validate-BIRn4a6d.js.map +0 -1
@@ -177,6 +177,10 @@ async function gateReciprocal(input, auth) {
177
177
  }
178
178
  return { reciprocal: { id: row.id, payload: input.payload } };
179
179
  }
180
+ /** The reciprocal of an add, stamped with who added it, as the container is. */
181
+ function completedBy(reciprocal, userId) {
182
+ return reciprocal ? { ...reciprocal, metadata: { resolved_by: userId } } : undefined;
183
+ }
180
184
  /** Validates the item payload against the container's versioned role form. */
181
185
  async function gatePayload(escalation, payload, userId) {
182
186
  if (payload === undefined)
@@ -245,7 +249,7 @@ async function accumulateItem(input, auth) {
245
249
  actor: initiator.actor,
246
250
  assertClaim: input.assertClaim ? auth.userId : undefined,
247
251
  resolvedBy: await (0, resolve_1.resolverIdentity)(auth),
248
- reciprocal: reciprocal.reciprocal,
252
+ reciprocal: completedBy(reciprocal.reciprocal, auth.userId),
249
253
  });
250
254
  return accumulateOutcomeResult(result, itemKey, escalation.workflow_id);
251
255
  }
@@ -291,7 +295,7 @@ async function accumulateItemBySignalKey(input, auth) {
291
295
  metadata: { ...metadata, resolved_by: auth.userId },
292
296
  actor: initiator.actor,
293
297
  resolvedBy: await (0, resolve_1.resolverIdentity)(auth),
294
- reciprocal: reciprocal.reciprocal,
298
+ reciprocal: completedBy(reciprocal.reciprocal, auth.userId),
295
299
  });
296
300
  return accumulateOutcomeResult(result, itemKey, escalation.workflow_id);
297
301
  }
@@ -344,7 +348,7 @@ async function accumulateItemByMetadata(input, auth) {
344
348
  actor: initiator.actor,
345
349
  resolvedBy,
346
350
  roles: allowedRoles ?? undefined,
347
- reciprocal: reciprocal.reciprocal,
351
+ reciprocal: completedBy(reciprocal.reciprocal, auth.userId),
348
352
  });
349
353
  if (result.outcome === 'not-found')
350
354
  return { status: 404, error: NO_ACCUMULATOR_FOR_FACET };
@@ -364,7 +368,7 @@ async function accumulateItemByMetadata(input, auth) {
364
368
  metadata: outcome,
365
369
  actor: initiator.actor,
366
370
  resolvedBy,
367
- reciprocal: reciprocal.reciprocal,
371
+ reciprocal: completedBy(reciprocal.reciprocal, auth.userId),
368
372
  });
369
373
  if (result.outcome === 'not-found') {
370
374
  return { status: 409, error: 'A concurrent change is already in progress for this escalation' };
@@ -175,12 +175,13 @@ async function resolveByMetadata(input, auth) {
175
175
  // writing; the payload validates here, then a second asserted pass claims
176
176
  // + resolves the same row with pending re-checked inside the statement.
177
177
  const enforcing = await (0, enforcement_cache_1.getEnforcingRoles)();
178
- let result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, enforcing.size > 0 ? [...enforcing] : null, input.assertId ?? null, input.extraFacets, input.availability);
178
+ const outcome = { ...input.metadata, resolved_by: auth.userId };
179
+ let result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, outcome, writeAllRoles, writeSelfRoles, enforcing.size > 0 ? [...enforcing] : null, input.assertId ?? null, input.extraFacets, input.availability);
179
180
  if (result.outcome === 'validation_required' && result.row) {
180
181
  const report = await (0, resolver_validation_1.checkResolverPayload)(result.row, input.resolverPayload, undefined, resolveUserId);
181
182
  if (report)
182
183
  return (0, resolve_1.validationFailure)(report);
183
- result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, null, result.row.id, input.extraFacets, input.availability);
184
+ result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, outcome, writeAllRoles, writeSelfRoles, null, result.row.id, input.extraFacets, input.availability);
184
185
  // The asserted row left pending between the two passes — a concurrent
185
186
  // resolution won the row; surface it as the conflict it is.
186
187
  if (result.outcome === 'not_found') {
@@ -199,7 +200,7 @@ async function resolveByMetadata(input, auth) {
199
200
  // Atomic conditional escalation (signal_key set) — SDK resolve atomically marks
200
201
  // resolved AND delivers the signal to the waiting condition(), resuming the workflow.
201
202
  if (result.signalKey) {
202
- const resolved = await escalationService.resolveEscalation(result.escalationId, input.resolverPayload);
203
+ const resolved = await escalationService.resolveEscalation(result.escalationId, input.resolverPayload, outcome);
203
204
  if (!resolved) {
204
205
  return { status: 409, error: 'Escalation not available for resolution' };
205
206
  }
@@ -1,7 +1,7 @@
1
1
  import type { LTApiAuth, LTApiResult } from '../../types/sdk';
2
2
  /**
3
3
  * Aggregate every related set the role's list schema declares, for one page
4
- * of host rows. One statement per (set, split) pair, whatever the page size.
4
+ * of host rows. One statement per (set, aggregate) pair, whatever the page size.
5
5
  */
6
6
  export declare function getRelatedAggregates(input: {
7
7
  role: string;
@@ -84,16 +84,24 @@ async function resolveQueryRoles(query, readScope) {
84
84
  const restricted = readScope.global ? [] : roles.filter((r) => !readScope.allRoles.includes(r));
85
85
  return { roles, roleLabels, restricted };
86
86
  }
87
- /** The split paths the declared columns ask of one set ('' when unsplit). */
88
- function splitsFor(relations, set) {
89
- const splits = new Set(relations.columns.filter((c) => c.related === set).map((c) => c.splitBy ?? ''));
90
- if (!splits.size)
91
- splits.add('');
92
- return [...splits];
87
+ /** The distinct aggregates the declared columns ask of one set; an unsplit count when none does. */
88
+ function asksFor(relations, set, source) {
89
+ const asks = new Map();
90
+ for (const col of relations.columns.filter((c) => c.related === set)) {
91
+ const key = (0, list_schema_1.relatedAggregateKey)(col, source);
92
+ if (asks.has(key))
93
+ continue;
94
+ asks.set(key, (0, list_schema_1.isExtremeAggregate)(col.aggregate)
95
+ ? { key, extreme: { fold: col.aggregate, path: (0, list_schema_1.relatedValuePath)(source, col.value) } }
96
+ : { key, ...(col.splitBy ? { splitBy: col.splitBy } : {}) });
97
+ }
98
+ if (!asks.size)
99
+ asks.set('', { key: '' });
100
+ return [...asks.values()];
93
101
  }
94
102
  /**
95
103
  * Aggregate every related set the role's list schema declares, for one page
96
- * of host rows. One statement per (set, split) pair, whatever the page size.
104
+ * of host rows. One statement per (set, aggregate) pair, whatever the page size.
97
105
  */
98
106
  async function getRelatedAggregates(input, auth) {
99
107
  try {
@@ -118,11 +126,13 @@ async function getRelatedAggregates(input, auth) {
118
126
  const result = { source: decl.source, aggregates: {} };
119
127
  if (decl.source === list_schema_1.RELATED_SOURCES.ITEMS) {
120
128
  const roles = new Set();
121
- for (const splitBy of splitsFor(relations, name)) {
122
- const read = await escalationService.aggregateRelatedItems({
123
- hostIds, scope, splitBy: splitBy || undefined,
124
- });
125
- result.aggregates[splitBy] = read.aggregates;
129
+ for (const ask of asksFor(relations, name, decl.source)) {
130
+ if (ask.extreme) {
131
+ result.aggregates[ask.key] = await escalationService.extremeRelatedItems({ hostIds, scope, ...ask.extreme });
132
+ continue;
133
+ }
134
+ const read = await escalationService.aggregateRelatedItems({ hostIds, scope, splitBy: ask.splitBy });
135
+ result.aggregates[ask.key] = read.aggregates;
126
136
  read.roles.forEach((r) => roles.add(r));
127
137
  }
128
138
  if (roles.size)
@@ -142,14 +152,14 @@ async function getRelatedAggregates(input, auth) {
142
152
  else
143
153
  unresolved.push(host.id);
144
154
  }
145
- for (const splitBy of splitsFor(relations, name)) {
146
- const agg = await escalationService.aggregateRelatedQuery({
147
- hosts: matched, roles: resolved.roles, status: decl.query.status ?? DEFAULT_STATUS, scope,
148
- splitBy: splitBy || undefined,
149
- });
155
+ for (const ask of asksFor(relations, name, decl.source)) {
156
+ const query = { hosts: matched, roles: resolved.roles, status: decl.query.status ?? DEFAULT_STATUS, scope };
157
+ const agg = ask.extreme
158
+ ? await escalationService.extremeRelatedQuery({ ...query, ...ask.extreme })
159
+ : await escalationService.aggregateRelatedQuery({ ...query, splitBy: ask.splitBy });
150
160
  for (const id of unresolved)
151
161
  agg[id] = { count: 0, unresolved: true };
152
- result.aggregates[splitBy] = agg;
162
+ result.aggregates[ask.key] = agg;
153
163
  }
154
164
  }
155
165
  data.sets[name] = result;
@@ -8,6 +8,8 @@ export interface AccumulateReciprocal {
8
8
  roles?: string[];
9
9
  /** Stored as the reciprocal entry's payload. */
10
10
  payload?: Record<string, any>;
11
+ /** Merge patch for the reciprocal row's metadata, same statement. */
12
+ metadata?: Record<string, any>;
11
13
  }
12
14
  export interface AccumulateItemInput {
13
15
  itemKey: string;
@@ -43,7 +45,7 @@ export interface AccumulateItemServiceOutcome {
43
45
  export interface RemoveItemInput {
44
46
  itemKey: string;
45
47
  actor?: string;
46
- reciprocal?: Omit<AccumulateReciprocal, 'payload'>;
48
+ reciprocal?: Omit<AccumulateReciprocal, 'payload' | 'metadata'>;
47
49
  }
48
50
  export interface RemoveItemServiceOutcome {
49
51
  outcome: RemoveAccumulatedItemOutcome;
@@ -13,7 +13,9 @@ exports.buildFacetOrder = buildFacetOrder;
13
13
  exports.buildGroupOrder = buildGroupOrder;
14
14
  // Top-level columns a caller may sort/range on directly. Anything else must be a
15
15
  // `metadata.<key>` facet. Keeps interpolation to a fixed, audited set.
16
- const ORDER_COLUMNS = new Set(['priority', 'created_at', 'updated_at', 'status', 'role']);
16
+ const ORDER_COLUMNS = new Set(['priority', 'created_at', 'updated_at', 'resolved_at', 'status', 'role']);
17
+ // Columns a pending row leaves empty: they sort after every value, either direction.
18
+ const NULLABLE_ORDER_COLUMNS = new Set(['resolved_at']);
17
19
  const RANGE_OPS = new Set(['<', '<=', '>', '>=', '=']);
18
20
  // Metadata keys are interpolated (as a JSON path), so they are strictly validated.
19
21
  // Exported so role config (priority_facet) validates keys against the same rule.
@@ -140,7 +142,7 @@ function buildFacetOrder(orderBy) {
140
142
  for (const o of orderBy) {
141
143
  const dir = o.direction === 'desc' ? 'DESC' : 'ASC';
142
144
  if (ORDER_COLUMNS.has(o.field)) {
143
- parts.push(`${o.field} ${dir}`);
145
+ parts.push(`${o.field} ${dir}${NULLABLE_ORDER_COLUMNS.has(o.field) ? ' NULLS LAST' : ''}`);
144
146
  }
145
147
  else if (o.field.startsWith('metadata.')) {
146
148
  const key = o.field.slice('metadata.'.length);
@@ -14,3 +14,4 @@ export { searchEscalationsGrouped } from './grouped-list';
14
14
  export type { EscalationGroup } from './grouped-list';
15
15
  export { aggregateRelatedItems, listRelatedItems, aggregateRelatedQuery, listRelatedQueryRows, readRelatedHosts, } from './related';
16
16
  export type { RelatedQueryHost } from './related';
17
+ export { extremeRelatedItems, extremeRelatedQuery } from './related-extremes';
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.readRelatedHosts = exports.listRelatedQueryRows = exports.aggregateRelatedQuery = exports.listRelatedItems = exports.aggregateRelatedItems = exports.searchEscalationsGrouped = exports.AnalyticsInputError = exports.resetAnalyticsCaches = exports.resolveEntitySystem = exports.timelineByFacet = exports.aggregateByFacets = exports.claimByFacets = exports.claimGroups = exports.countByFacets = exports.searchGroups = exports.searchByFacets = exports.ensureFacetReady = exports.ensureEscalationCompatView = exports.claimAssertedByMetadata = void 0;
17
+ exports.extremeRelatedQuery = exports.extremeRelatedItems = exports.readRelatedHosts = exports.listRelatedQueryRows = exports.aggregateRelatedQuery = exports.listRelatedItems = exports.aggregateRelatedItems = exports.searchEscalationsGrouped = exports.AnalyticsInputError = exports.resetAnalyticsCaches = exports.resolveEntitySystem = exports.timelineByFacet = exports.aggregateByFacets = exports.claimByFacets = exports.claimGroups = exports.countByFacets = exports.searchGroups = exports.searchByFacets = exports.ensureFacetReady = exports.ensureEscalationCompatView = exports.claimAssertedByMetadata = void 0;
18
18
  __exportStar(require("./types"), exports);
19
19
  __exportStar(require("./crud"), exports);
20
20
  var claim_asserted_1 = require("./claim-asserted");
@@ -48,3 +48,6 @@ Object.defineProperty(exports, "listRelatedItems", { enumerable: true, get: func
48
48
  Object.defineProperty(exports, "aggregateRelatedQuery", { enumerable: true, get: function () { return related_1.aggregateRelatedQuery; } });
49
49
  Object.defineProperty(exports, "listRelatedQueryRows", { enumerable: true, get: function () { return related_1.listRelatedQueryRows; } });
50
50
  Object.defineProperty(exports, "readRelatedHosts", { enumerable: true, get: function () { return related_1.readRelatedHosts; } });
51
+ var related_extremes_1 = require("./related-extremes");
52
+ Object.defineProperty(exports, "extremeRelatedItems", { enumerable: true, get: function () { return related_extremes_1.extremeRelatedItems; } });
53
+ Object.defineProperty(exports, "extremeRelatedQuery", { enumerable: true, get: function () { return related_extremes_1.extremeRelatedQuery; } });
@@ -0,0 +1,17 @@
1
+ import { type RelatedExtreme, type RelatedHostAggregate } from '../../shared/list-schema';
2
+ import { type RelatedQueryInput } from './related';
3
+ import type { ReadScopeInput } from './read-scope-sql';
4
+ type Aggregates = Record<string, RelatedHostAggregate>;
5
+ /** The least or greatest `payload.<path>` among each host's items. */
6
+ export declare function extremeRelatedItems(opts: {
7
+ hostIds: string[];
8
+ scope: ReadScopeInput;
9
+ fold: RelatedExtreme;
10
+ path: string;
11
+ }): Promise<Aggregates>;
12
+ /** The least or greatest `metadata.<key>` among the rows sharing each host's facets. */
13
+ export declare function extremeRelatedQuery(input: RelatedQueryInput & {
14
+ fold: RelatedExtreme;
15
+ path: string;
16
+ }): Promise<Aggregates>;
17
+ export {};
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ // ---------------------------------------------------------------------------
3
+ // min/max over a related set: the least or greatest item payload value, or
4
+ // related row metadata value, per host. One statement per (set, value) pair,
5
+ // under the same read scope as the set's counts.
6
+ // ---------------------------------------------------------------------------
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.extremeRelatedItems = extremeRelatedItems;
9
+ exports.extremeRelatedQuery = extremeRelatedQuery;
10
+ const db_1 = require("../../lib/db");
11
+ const list_schema_1 = require("../../shared/list-schema");
12
+ const client_1 = require("./client");
13
+ const related_1 = require("./related");
14
+ const NUMBER_TEXT = '^-?[0-9]+(\\.[0-9]+)?([eE][-+]?[0-9]+)?$';
15
+ /**
16
+ * Per host: how many values, whether every one is numeric, and the extreme
17
+ * as a number and as text. `v` is the jsonb value; objects, arrays, nulls and
18
+ * blanks are not values. Text compares in code-unit order, as the dashboard folds.
19
+ */
20
+ function extremeSelect(fold, hostId, v, from) {
21
+ const fn = fold === list_schema_1.RELATED_AGGREGATES.MIN ? 'min' : 'max';
22
+ return `SELECT host_id, count(*)::int AS n, bool_and(t ~ '${NUMBER_TEXT}') AS numeric,
23
+ ${fn}(CASE WHEN t ~ '${NUMBER_TEXT}' THEN t::numeric END)::text AS num,
24
+ ${fn}(t COLLATE "C") AS txt
25
+ FROM (SELECT h_id AS host_id, x #>> '{}' AS t
26
+ FROM (SELECT ${hostId}::text AS h_id, ${v} AS x ${from}) raw
27
+ WHERE jsonb_typeof(x) IN ('string', 'number', 'boolean') AND x #>> '{}' <> '') vals
28
+ GROUP BY host_id`;
29
+ }
30
+ function foldExtremeRows(rows, hostIds) {
31
+ const out = {};
32
+ for (const id of hostIds)
33
+ out[id] = { count: 0 };
34
+ for (const row of rows) {
35
+ if (!out[row.host_id])
36
+ continue;
37
+ const value = row.numeric && row.num !== null ? Number(row.num) : row.txt;
38
+ out[row.host_id] = value === null ? { count: row.n } : { count: row.n, value };
39
+ }
40
+ return out;
41
+ }
42
+ /** The least or greatest `payload.<path>` among each host's items. */
43
+ async function extremeRelatedItems(opts) {
44
+ if (!opts.hostIds.length)
45
+ return {};
46
+ await (0, client_1.ensureEscalationCompatView)();
47
+ const params = [];
48
+ const cte = (0, related_1.itemEntriesCte)(params, opts.scope, opts.hostIds);
49
+ const pi = params.push(opts.path.slice(list_schema_1.SPLIT_PATHS.PAYLOAD.length).split('.'));
50
+ const v = `(CASE WHEN en.acc THEN en.entry->'payload' ELSE en.entry END) #> $${pi}::text[]`;
51
+ const { rows } = await (0, db_1.getPool)().query(`WITH ${cte} ${extremeSelect(opts.fold, 'en.host_id', v, 'FROM entries en')}`, params);
52
+ return foldExtremeRows(rows, opts.hostIds);
53
+ }
54
+ /** The least or greatest `metadata.<key>` among the rows sharing each host's facets. */
55
+ async function extremeRelatedQuery(input) {
56
+ const hostIds = input.hosts.map((h) => h.hostId);
57
+ if (!hostIds.length || !input.roles.length)
58
+ return foldExtremeRows([], hostIds);
59
+ await (0, client_1.ensureEscalationCompatView)();
60
+ const params = [];
61
+ const from = (0, related_1.querySetFrom)(params, input);
62
+ const ki = params.push(input.path.slice(list_schema_1.SPLIT_PATHS.METADATA.length));
63
+ const { rows } = await (0, db_1.getPool)().query(extremeSelect(input.fold, 'h.host_id', `e.metadata->$${ki}`, from), params);
64
+ return foldExtremeRows(rows, hostIds);
65
+ }
@@ -12,6 +12,8 @@ export interface RelatedQueryInput {
12
12
  scope: ReadScopeInput;
13
13
  }
14
14
  type Aggregates = Record<string, RelatedHostAggregate>;
15
+ /** The hosts and their item entries, read under the caller's scope. */
16
+ export declare function itemEntriesCte(params: unknown[], scope: ReadScopeInput, hostIds: string[]): string;
15
17
  /**
16
18
  * Count each host's items, optionally split by `payload.<path>` or
17
19
  * `reciprocal.metadata.<key>`. A reciprocal split counts only reciprocal rows
@@ -35,6 +37,8 @@ export declare function listRelatedItems(opts: {
35
37
  rows: RelatedRow[];
36
38
  total: number;
37
39
  }>;
40
+ /** The shared FROM/WHERE of a query set: hosts unnested beside their matches. */
41
+ export declare function querySetFrom(params: unknown[], input: RelatedQueryInput): string;
38
42
  /**
39
43
  * Count the rows that share each host's facets, grouped by role and an
40
44
  * optional `metadata.<key>` split. The GIN index serves each host's match.
@@ -7,8 +7,10 @@
7
7
  // the page size or the item count.
8
8
  // ---------------------------------------------------------------------------
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.itemEntriesCte = itemEntriesCte;
10
11
  exports.aggregateRelatedItems = aggregateRelatedItems;
11
12
  exports.listRelatedItems = listRelatedItems;
13
+ exports.querySetFrom = querySetFrom;
12
14
  exports.aggregateRelatedQuery = aggregateRelatedQuery;
13
15
  exports.listRelatedQueryRows = listRelatedQueryRows;
14
16
  exports.readRelatedHosts = readRelatedHosts;
@@ -23,6 +23,7 @@ exports.toValidationErrorBody = toValidationErrorBody;
23
23
  */
24
24
  const form_validation_1 = require("../../shared/form-validation");
25
25
  const submit_guard_1 = require("./submit-guard");
26
+ const roster_1 = require("./roster");
26
27
  const enforcement_cache_1 = require("../role/enforcement-cache");
27
28
  const knowledge_1 = require("../knowledge");
28
29
  const escalation_1 = require("../../types/escalation");
@@ -85,6 +86,12 @@ async function checkResolverPayload(escalation, resolverPayload, loadEnvelope, r
85
86
  payload: parseJsonOrNull(escalation.escalation_payload),
86
87
  ...(lookup ? { lookup } : {}),
87
88
  };
89
+ // Roster counts read the submitted form values (an `in` source may name a
90
+ // form field), then join the context so showIf and the guard see them.
91
+ const formValues = (0, form_validation_1.mapPayloadToForm)(resolverPayload, schema);
92
+ const roster = await (0, roster_1.loadRosterCounts)(schema, { ...ctx, resolver: formValues, input: formValues });
93
+ if (Object.keys(roster).length)
94
+ ctx.roster = roster;
88
95
  const violations = (0, form_validation_1.validateResolverPayload)(schema, resolverPayload, ctx);
89
96
  // The query precondition (x-lt-submit-guard): reject while the embedded query
90
97
  // still returns rows. Enforced on the same enforce_schema opt-in as the field
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Server-side roster counts: the API-first counterpart of the dashboard's
3
+ * roster widget. For each `x-lt-roster` field of a form schema, the member
4
+ * rows are read with the same query the widget runs and the shared
5
+ * `computeRoster` turns them into counts, so `roster.*` showIf conditions and
6
+ * a roster submit guard evaluate at resolve exactly as the form showed them.
7
+ *
8
+ * Member rows are read with `global: true`: a resolver who cannot see a
9
+ * member must never be told the roster is complete.
10
+ */
11
+ import { type RosterCounts, type ShowIfContext } from '../../shared/form-validation';
12
+ /** Each roster field's counts, keyed by field name; empty when the schema declares none. */
13
+ export declare function loadRosterCounts(schema: Record<string, unknown> | null | undefined, ctx: ShowIfContext): Promise<Record<string, RosterCounts>>;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadRosterCounts = loadRosterCounts;
4
+ /**
5
+ * Server-side roster counts: the API-first counterpart of the dashboard's
6
+ * roster widget. For each `x-lt-roster` field of a form schema, the member
7
+ * rows are read with the same query the widget runs and the shared
8
+ * `computeRoster` turns them into counts, so `roster.*` showIf conditions and
9
+ * a roster submit guard evaluate at resolve exactly as the form showed them.
10
+ *
11
+ * Member rows are read with `global: true`: a resolver who cannot see a
12
+ * member must never be told the roster is complete.
13
+ */
14
+ const form_validation_1 = require("../../shared/form-validation");
15
+ const queries_1 = require("./queries");
16
+ /** Each roster field's counts, keyed by field name; empty when the schema declares none. */
17
+ async function loadRosterCounts(schema, ctx) {
18
+ const defs = (0, form_validation_1.readRosterDefs)(schema);
19
+ const counts = {};
20
+ for (const [field, def] of Object.entries(defs)) {
21
+ counts[field] = (0, form_validation_1.computeRoster)(def, ctx, await readMemberRows(def, ctx)).counts;
22
+ }
23
+ return counts;
24
+ }
25
+ async function readMemberRows(def, ctx) {
26
+ const query = (0, form_validation_1.rosterQueryOf)(def);
27
+ const scoped = query ? (0, form_validation_1.resolveRosterQuery)(query, ctx) : null;
28
+ if (!scoped)
29
+ return [];
30
+ const { escalations } = await (0, queries_1.searchEscalationsFaceted)({
31
+ global: true,
32
+ facet: { roles: scoped.roles, status: scoped.status, facets: scoped.facets },
33
+ limit: scoped.limit,
34
+ offset: 0,
35
+ });
36
+ return escalations.map((row) => (0, form_validation_1.rosterRowContext)(row));
37
+ }
@@ -15,6 +15,9 @@
15
15
  * - A guard whose scope cannot be evaluated (e.g. `assigned:'me'` on a surface
16
16
  * with no resolving user, like an MCP resolve) is skipped here; the consuming
17
17
  * workflow's own verification remains the durable backstop.
18
+ *
19
+ * A roster guard reads the counts the caller placed under `ctx.roster`
20
+ * (services/escalation/roster.ts) and rejects while entries are outstanding.
18
21
  */
19
22
  import { type ShowIfContext } from '../../shared/form-validation';
20
23
  import type { LTFieldViolation } from '../../types/validation';
@@ -19,6 +19,9 @@ exports.checkSubmitGuard = checkSubmitGuard;
19
19
  * - A guard whose scope cannot be evaluated (e.g. `assigned:'me'` on a surface
20
20
  * with no resolving user, like an MCP resolve) is skipped here; the consuming
21
21
  * workflow's own verification remains the durable backstop.
22
+ *
23
+ * A roster guard reads the counts the caller placed under `ctx.roster`
24
+ * (services/escalation/roster.ts) and rejects while entries are outstanding.
22
25
  */
23
26
  const form_validation_1 = require("../../shared/form-validation");
24
27
  const queries_1 = require("./queries");
@@ -34,6 +37,10 @@ async function checkSubmitGuard(schema, ctx, resolvingUserId) {
34
37
  const guard = (0, form_validation_1.readSubmitGuard)(schema);
35
38
  if (!guard || guard.mustBeEmpty === false)
36
39
  return null;
40
+ if (guard.roster)
41
+ return checkRosterGuard(guard, ctx);
42
+ if (!guard.query)
43
+ return null;
37
44
  const scoped = (0, form_validation_1.resolveScopedQuery)(guard.query, ctx, resolvingUserId);
38
45
  if (!scoped.enabled)
39
46
  return null;
@@ -51,7 +58,19 @@ async function checkSubmitGuard(schema, ctx, resolvingUserId) {
51
58
  });
52
59
  if (total <= 0)
53
60
  return null;
54
- const template = guard.message ?? form_validation_1.SUBMIT_GUARD_DEFAULT_MESSAGE;
55
- const message = (0, form_validation_1.interpolateHelp)(template.replace(/\{\{count\}\}/g, String(total)), ctx);
61
+ return guardViolation(guard.message ?? form_validation_1.SUBMIT_GUARD_DEFAULT_MESSAGE, total, ctx);
62
+ }
63
+ /** A roster guard: outstanding entries reject; a roster the schema does not declare rejects too. */
64
+ function checkRosterGuard(guard, ctx) {
65
+ const counts = ctx.roster?.[guard.roster];
66
+ if (!counts) {
67
+ return { field: exports.SUBMIT_GUARD_VIOLATION_FIELD, message: `Submit guard names roster "${guard.roster}", which the form does not declare` };
68
+ }
69
+ if (counts.outstanding <= 0)
70
+ return null;
71
+ return guardViolation(guard.message ?? form_validation_1.ROSTER_GUARD_DEFAULT_MESSAGE, counts.outstanding, ctx);
72
+ }
73
+ function guardViolation(template, count, ctx) {
74
+ const message = (0, form_validation_1.interpolateHelp)(template.replace(/\{\{count\}\}/g, String(count)), ctx);
56
75
  return { field: exports.SUBMIT_GUARD_VIOLATION_FIELD, message };
57
76
  }
@@ -225,7 +225,7 @@ function registerHumanQueueTools(server) {
225
225
  isError: true,
226
226
  };
227
227
  }
228
- const resolved = await escalationService.resolveEscalation(args.escalation_id, args.payload, args.metadata);
228
+ const resolved = await escalationService.resolveEscalation(args.escalation_id, args.payload, { ...args.metadata, resolved_by: args.resolver_id });
229
229
  if (!resolved) {
230
230
  return {
231
231
  content: [{
@@ -9,6 +9,7 @@ export declare const DISPLAY_ONLY_WIDGET_NAMES: {
9
9
  readonly ESCALATION: "escalation";
10
10
  readonly ESCALATION_LIST: "escalation-list";
11
11
  readonly INVOKE: "invoke";
12
+ readonly ROSTER: "roster";
12
13
  };
13
14
  export declare const DISPLAY_ONLY_WIDGETS: ReadonlySet<string>;
14
15
  export declare function isDisplayOnlyWidget(name: unknown): boolean;
@@ -14,6 +14,7 @@ exports.DISPLAY_ONLY_WIDGET_NAMES = {
14
14
  ESCALATION: 'escalation',
15
15
  ESCALATION_LIST: 'escalation-list',
16
16
  INVOKE: 'invoke',
17
+ ROSTER: 'roster',
17
18
  };
18
19
  exports.DISPLAY_ONLY_WIDGETS = new Set(Object.values(exports.DISPLAY_ONLY_WIDGET_NAMES));
19
20
  function isDisplayOnlyWidget(name) {
@@ -23,3 +23,4 @@ export * from './invoke-context';
23
23
  export * from './display-only-widgets';
24
24
  export * from './x-lt-invoke';
25
25
  export * from './x-lt-scan';
26
+ export * from './x-lt-roster';
@@ -39,3 +39,4 @@ __exportStar(require("./invoke-context"), exports);
39
39
  __exportStar(require("./display-only-widgets"), exports);
40
40
  __exportStar(require("./x-lt-invoke"), exports);
41
41
  __exportStar(require("./x-lt-scan"), exports);
42
+ __exportStar(require("./x-lt-roster"), exports);
@@ -9,6 +9,7 @@
9
9
  * Semantics per field:
10
10
  * - x-lt-showIf-hidden fields are skipped entirely (a field the submitter
11
11
  * cannot see never blocks submission)
12
+ * - x-lt-hidden fields are never required; a value they carry is checked
12
13
  * - required (schema.required membership), with checklist/empty-object rules
13
14
  * - declared-type check (string/number/integer/boolean/array/object)
14
15
  * - enum membership
@@ -13,6 +13,7 @@ exports.validateResolverPayload = validateResolverPayload;
13
13
  * Semantics per field:
14
14
  * - x-lt-showIf-hidden fields are skipped entirely (a field the submitter
15
15
  * cannot see never blocks submission)
16
+ * - x-lt-hidden fields are never required; a value they carry is checked
16
17
  * - required (schema.required membership), with checklist/empty-object rules
17
18
  * - declared-type check (string/number/integer/boolean/array/object)
18
19
  * - enum membership
@@ -50,7 +51,7 @@ function validateResolverForm(schema, formValues, ctx) {
50
51
  for (const [field, fieldSchema] of Object.entries(properties)) {
51
52
  if (!(0, x_lt_show_if_1.evaluateShowIf)(fieldSchema['x-lt-showIf'], liveCtx))
52
53
  continue;
53
- const err = (0, field_validator_1.validateField)(formValues[field], fieldSchema, required.has(field), true, liveCtx);
54
+ const err = (0, field_validator_1.validateField)(formValues[field], fieldSchema, required.has(field) && !(0, x_lt_show_if_1.isHiddenField)(fieldSchema), true, liveCtx);
54
55
  if (err)
55
56
  errors.push({ field, message: err });
56
57
  }
@@ -1,5 +1,5 @@
1
1
  /** The token domains a help template may reference. `input` is the invoke-form name for the live values `resolver` also carries. */
2
- export declare const HELP_DOMAINS: readonly ["escalation", "metadata", "envelope", "payload", "resolver", "lookup", "input"];
2
+ export declare const HELP_DOMAINS: readonly ["escalation", "metadata", "envelope", "payload", "resolver", "lookup", "input", "roster"];
3
3
  export type HelpDomain = (typeof HELP_DOMAINS)[number];
4
4
  export type HelpTokenContext = Partial<Record<HelpDomain, Record<string, unknown> | null>>;
5
5
  /** Replace every `{{domain.path}}` token with its value from the context. */
@@ -17,6 +17,7 @@ exports.defaultHelpMarkdown = defaultHelpMarkdown;
17
17
  * {{payload.category}} — the escalation context payload
18
18
  * {{resolver.notes}} — the submitted resolver payload
19
19
  * {{lookup.materials.items}} — versioned knowledge lookups pinned on the row
20
+ * {{roster.orders.outstanding}} (a roster field's counts, x-lt-roster.ts)
20
21
  *
21
22
  * Paths reuse the x-lt-bind syntax (`a.b[0].c`). A missing value renders as an
22
23
  * em dash. `x-lt-context` is accepted as the plain-text fallback source when
@@ -24,7 +25,7 @@ exports.defaultHelpMarkdown = defaultHelpMarkdown;
24
25
  */
25
26
  const x_lt_bind_1 = require("./x-lt-bind");
26
27
  /** The token domains a help template may reference. `input` is the invoke-form name for the live values `resolver` also carries. */
27
- exports.HELP_DOMAINS = ['escalation', 'metadata', 'envelope', 'payload', 'resolver', 'lookup', 'input'];
28
+ exports.HELP_DOMAINS = ['escalation', 'metadata', 'envelope', 'payload', 'resolver', 'lookup', 'input', 'roster'];
28
29
  const TOKEN_PATTERN = /\{\{\s*([^{}]+?)\s*\}\}/g;
29
30
  const MISSING_VALUE = '—';
30
31
  function formatTokenValue(value) {