@hotmeshio/long-tail 0.30.2 → 0.30.4

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 (282) hide show
  1. package/build/api/escalations/accumulate.d.ts +2 -1
  2. package/build/api/escalations/accumulate.js +2 -1
  3. package/build/api/escalations/metadata.d.ts +3 -2
  4. package/build/api/escalations/metadata.js +4 -3
  5. package/build/api/escalations/resolve-batch.d.ts +3 -1
  6. package/build/api/escalations/resolve-batch.js +14 -1
  7. package/build/api/scan-codes/choice.js +3 -2
  8. package/build/api/scan-codes/context.d.ts +6 -0
  9. package/build/api/scan-codes/context.js +10 -1
  10. package/build/api/scan-codes/locate.js +1 -0
  11. package/build/api/scan-codes/subject.js +32 -3
  12. package/build/api/scan-codes/verb-accumulate.js +1 -1
  13. package/build/api/scan-codes/verb-fill.js +2 -1
  14. package/build/api/scan-codes/verb-into-subject.js +1 -1
  15. package/build/api/scan-codes/verbs-subject.d.ts +3 -1
  16. package/build/api/scan-codes/verbs-subject.js +8 -5
  17. package/build/api/scan-codes/verbs.js +4 -4
  18. package/build/lib/db/schemas/043_scan_pattern_and_member_targets.sql +26 -0
  19. package/build/lib/facet-value.d.ts +3 -0
  20. package/build/lib/facet-value.js +9 -0
  21. package/build/routes/scan-codes.js +3 -0
  22. package/build/sdk/index.d.ts +3 -3
  23. package/build/services/escalation/batch.d.ts +4 -3
  24. package/build/services/escalation/batch.js +5 -3
  25. package/build/services/escalation/claim-asserted.d.ts +2 -1
  26. package/build/services/escalation/crud.d.ts +3 -2
  27. package/build/services/orchestrator/condition.d.ts +6 -0
  28. package/build/services/orchestrator/condition.js +6 -0
  29. package/build/services/scan-code/read.js +3 -0
  30. package/build/services/scan-code/sql.d.ts +3 -3
  31. package/build/services/scan-code/sql.js +19 -8
  32. package/build/services/scan-code/validate-scheme-pattern.d.ts +16 -0
  33. package/build/services/scan-code/validate-scheme-pattern.js +75 -0
  34. package/build/services/scan-code/validate.d.ts +3 -1
  35. package/build/services/scan-code/validate.js +6 -1
  36. package/build/services/scan-code/write.d.ts +3 -0
  37. package/build/services/scan-code/write.js +3 -0
  38. package/build/shared/scan-code/index.d.ts +2 -1
  39. package/build/shared/scan-code/index.js +8 -1
  40. package/build/shared/scan-code/parse.d.ts +22 -1
  41. package/build/shared/scan-code/parse.js +78 -0
  42. package/build/shared/scan-code/target.d.ts +4 -0
  43. package/build/shared/scan-code/target.js +14 -0
  44. package/build/system/mcp-servers/admin/schemas.d.ts +86 -77
  45. package/build/system/mcp-servers/admin/schemas.js +4 -1
  46. package/build/system/mcp-servers/human-queue-lookups.d.ts +7 -0
  47. package/build/system/mcp-servers/human-queue-lookups.js +31 -0
  48. package/build/system/mcp-servers/human-queue-schemas.d.ts +7 -0
  49. package/build/system/mcp-servers/human-queue-schemas.js +4 -1
  50. package/build/system/mcp-servers/human-queue.d.ts +1 -0
  51. package/build/system/mcp-servers/human-queue.js +3 -0
  52. package/build/system/seed/tool-manifests-admin.js +1 -1
  53. package/build/system/seed/tool-manifests-escalation.js +2 -2
  54. package/build/tsconfig.tsbuildinfo +1 -1
  55. package/build/types/escalation.d.ts +15 -0
  56. package/build/types/escalation.js +16 -1
  57. package/build/types/facets.d.ts +5 -0
  58. package/build/types/index.d.ts +3 -3
  59. package/build/types/index.js +5 -1
  60. package/build/types/scan-code/constants.d.ts +20 -0
  61. package/build/types/scan-code/constants.js +20 -1
  62. package/build/types/scan-code/response.d.ts +2 -1
  63. package/build/types/scan-code/rule.d.ts +12 -2
  64. package/dashboard/dist/assets/{AdminDashboard-NVtdLI4I.js → AdminDashboard-VQ1fhhJP.js} +2 -2
  65. package/dashboard/dist/assets/{AdminDashboard-NVtdLI4I.js.map → AdminDashboard-VQ1fhhJP.js.map} +1 -1
  66. package/dashboard/dist/assets/{AgentConfigPage-Db1Oi72V.js → AgentConfigPage-BOe_W2Ij.js} +2 -2
  67. package/dashboard/dist/assets/{AgentConfigPage-Db1Oi72V.js.map → AgentConfigPage-BOe_W2Ij.js.map} +1 -1
  68. package/dashboard/dist/assets/{AgentDetailPage-BF4mw1bD.js → AgentDetailPage-5ov5D9V2.js} +2 -2
  69. package/dashboard/dist/assets/{AgentDetailPage-BF4mw1bD.js.map → AgentDetailPage-5ov5D9V2.js.map} +1 -1
  70. package/dashboard/dist/assets/{AgentsPage-DmF0m3Ro.js → AgentsPage-DDFMKHhI.js} +2 -2
  71. package/dashboard/dist/assets/{AgentsPage-DmF0m3Ro.js.map → AgentsPage-DDFMKHhI.js.map} +1 -1
  72. package/dashboard/dist/assets/{AvailableEscalationsPage-jy2WKDjr.js → AvailableEscalationsPage-GFn8Sgg1.js} +2 -2
  73. package/dashboard/dist/assets/{AvailableEscalationsPage-jy2WKDjr.js.map → AvailableEscalationsPage-GFn8Sgg1.js.map} +1 -1
  74. package/dashboard/dist/assets/{BotPicker-HJtVHdNe.js → BotPicker-Dqpo36dM.js} +2 -2
  75. package/dashboard/dist/assets/{BotPicker-HJtVHdNe.js.map → BotPicker-Dqpo36dM.js.map} +1 -1
  76. package/dashboard/dist/assets/{BulkAssignModal-DsJJZ9X4.js → BulkAssignModal-CmLVxkz-.js} +2 -2
  77. package/dashboard/dist/assets/{BulkAssignModal-DsJJZ9X4.js.map → BulkAssignModal-CmLVxkz-.js.map} +1 -1
  78. package/dashboard/dist/assets/{CapabilitiesPage-iCn7PxDP.js → CapabilitiesPage-Dfkip6_b.js} +2 -2
  79. package/dashboard/dist/assets/{CapabilitiesPage-iCn7PxDP.js.map → CapabilitiesPage-Dfkip6_b.js.map} +1 -1
  80. package/dashboard/dist/assets/{CollapsibleSection-DFfVr_Ut.js → CollapsibleSection-CYNYMYSa.js} +2 -2
  81. package/dashboard/dist/assets/{CollapsibleSection-DFfVr_Ut.js.map → CollapsibleSection-CYNYMYSa.js.map} +1 -1
  82. package/dashboard/dist/assets/{ConfirmDeleteModal-D6TwO-yT.js → ConfirmDeleteModal-CpJNP-8w.js} +2 -2
  83. package/dashboard/dist/assets/{ConfirmDeleteModal-D6TwO-yT.js.map → ConfirmDeleteModal-CpJNP-8w.js.map} +1 -1
  84. package/dashboard/dist/assets/{ConnectedAppsPage-BOD-tgY0.js → ConnectedAppsPage-DXIp2Dpl.js} +2 -2
  85. package/dashboard/dist/assets/{ConnectedAppsPage-BOD-tgY0.js.map → ConnectedAppsPage-DXIp2Dpl.js.map} +1 -1
  86. package/dashboard/dist/assets/{CountdownTimer-u_o3OygV.js → CountdownTimer-CuPY7zkb.js} +2 -2
  87. package/dashboard/dist/assets/{CountdownTimer-u_o3OygV.js.map → CountdownTimer-CuPY7zkb.js.map} +1 -1
  88. package/dashboard/dist/assets/{CredentialsPage-C3dnRsMh.js → CredentialsPage-CtrnkHcj.js} +2 -2
  89. package/dashboard/dist/assets/{CredentialsPage-C3dnRsMh.js.map → CredentialsPage-CtrnkHcj.js.map} +1 -1
  90. package/dashboard/dist/assets/{CronLabel-BFh5TCsB.js → CronLabel-DVjTw5Ri.js} +2 -2
  91. package/dashboard/dist/assets/{CronLabel-BFh5TCsB.js.map → CronLabel-DVjTw5Ri.js.map} +1 -1
  92. package/dashboard/dist/assets/{ElapsedCell-D0jYuFKh.js → ElapsedCell-gY_mGMTF.js} +2 -2
  93. package/dashboard/dist/assets/{ElapsedCell-D0jYuFKh.js.map → ElapsedCell-gY_mGMTF.js.map} +1 -1
  94. package/dashboard/dist/assets/{EntityTimelinePanel-Ch-BsRu8.js → EntityTimelinePanel-DJN_ZEQa.js} +2 -2
  95. package/dashboard/dist/assets/{EntityTimelinePanel-Ch-BsRu8.js.map → EntityTimelinePanel-DJN_ZEQa.js.map} +1 -1
  96. package/dashboard/dist/assets/{EscalationListSchemaPage-DuSLiInU.js → EscalationListSchemaPage-A4KpTdJA.js} +3 -3
  97. package/dashboard/dist/assets/{EscalationListSchemaPage-DuSLiInU.js.map → EscalationListSchemaPage-A4KpTdJA.js.map} +1 -1
  98. package/dashboard/dist/assets/{EscalationSchemaPage-D_mYri6e.js → EscalationSchemaPage-nfCn42hT.js} +2 -2
  99. package/dashboard/dist/assets/{EscalationSchemaPage-D_mYri6e.js.map → EscalationSchemaPage-nfCn42hT.js.map} +1 -1
  100. package/dashboard/dist/assets/{EscalationTimeline-DiN8ImWF.js → EscalationTimeline-CLvSr1SD.js} +2 -2
  101. package/dashboard/dist/assets/{EscalationTimeline-DiN8ImWF.js.map → EscalationTimeline-CLvSr1SD.js.map} +1 -1
  102. package/dashboard/dist/assets/{EscalationTitleSelect-36tkc2TE.js → EscalationTitleSelect-CT7mYHkb.js} +2 -2
  103. package/dashboard/dist/assets/{EscalationTitleSelect-36tkc2TE.js.map → EscalationTitleSelect-CT7mYHkb.js.map} +1 -1
  104. package/dashboard/dist/assets/{EscalationsOverview-yHY6JKiV.js → EscalationsOverview-CKaGRh-E.js} +2 -2
  105. package/dashboard/dist/assets/{EscalationsOverview-yHY6JKiV.js.map → EscalationsOverview-CKaGRh-E.js.map} +1 -1
  106. package/dashboard/dist/assets/{EventTable-DTtu2iM_.js → EventTable-2ywJsOLy.js} +2 -2
  107. package/dashboard/dist/assets/{EventTable-DTtu2iM_.js.map → EventTable-2ywJsOLy.js.map} +1 -1
  108. package/dashboard/dist/assets/{FilterBar-ByZiD0ty.js → FilterBar-Dy0b7wwf.js} +2 -2
  109. package/dashboard/dist/assets/{FilterBar-ByZiD0ty.js.map → FilterBar-Dy0b7wwf.js.map} +1 -1
  110. package/dashboard/dist/assets/{GraphInvokePage-Cbn6igr_.js → GraphInvokePage-yOVpraAy.js} +2 -2
  111. package/dashboard/dist/assets/{GraphInvokePage-Cbn6igr_.js.map → GraphInvokePage-yOVpraAy.js.map} +1 -1
  112. package/dashboard/dist/assets/{HomePage-CtLKm_S4.js → HomePage-67xXjKjN.js} +2 -2
  113. package/dashboard/dist/assets/{HomePage-CtLKm_S4.js.map → HomePage-67xXjKjN.js.map} +1 -1
  114. package/dashboard/dist/assets/{LinePage-Q5Cgjd3N.js → LinePage-CMsYtukW.js} +3 -3
  115. package/dashboard/dist/assets/{LinePage-Q5Cgjd3N.js.map → LinePage-CMsYtukW.js.map} +1 -1
  116. package/dashboard/dist/assets/{LinesPage-BX3d-rj0.js → LinesPage-pwL46mOS.js} +3 -3
  117. package/dashboard/dist/assets/{LinesPage-BX3d-rj0.js.map → LinesPage-pwL46mOS.js.map} +1 -1
  118. package/dashboard/dist/assets/{ListToolbar-bj2sgAK4.js → ListToolbar-CJmvGy2B.js} +2 -2
  119. package/dashboard/dist/assets/{ListToolbar-bj2sgAK4.js.map → ListToolbar-CJmvGy2B.js.map} +1 -1
  120. package/dashboard/dist/assets/{McpOverview-BD3UWbcC.js → McpOverview-DA9LLvNG.js} +2 -2
  121. package/dashboard/dist/assets/{McpOverview-BD3UWbcC.js.map → McpOverview-DA9LLvNG.js.map} +1 -1
  122. package/dashboard/dist/assets/{McpQueryDetailPage-ISzY-BfT.js → McpQueryDetailPage-N7qLmfE8.js} +2 -2
  123. package/dashboard/dist/assets/{McpQueryDetailPage-ISzY-BfT.js.map → McpQueryDetailPage-N7qLmfE8.js.map} +1 -1
  124. package/dashboard/dist/assets/{McpQueryPage-t555QJ3m.js → McpQueryPage-CpsP3w7x.js} +2 -2
  125. package/dashboard/dist/assets/{McpQueryPage-t555QJ3m.js.map → McpQueryPage-CpsP3w7x.js.map} +1 -1
  126. package/dashboard/dist/assets/{McpRunDetailPage-C4jozQFh.js → McpRunDetailPage-qHRQ1pEY.js} +2 -2
  127. package/dashboard/dist/assets/{McpRunDetailPage-C4jozQFh.js.map → McpRunDetailPage-qHRQ1pEY.js.map} +1 -1
  128. package/dashboard/dist/assets/{McpRunsPage-Z-mtyRBp.js → McpRunsPage-BRDDYpTM.js} +2 -2
  129. package/dashboard/dist/assets/{McpRunsPage-Z-mtyRBp.js.map → McpRunsPage-BRDDYpTM.js.map} +1 -1
  130. package/dashboard/dist/assets/{OperationsPage-ClYilVyZ.js → OperationsPage-zUaab-CL.js} +3 -3
  131. package/dashboard/dist/assets/{OperationsPage-ClYilVyZ.js.map → OperationsPage-zUaab-CL.js.map} +1 -1
  132. package/dashboard/dist/assets/{OperatorDashboard-3Hi2IiHi.js → OperatorDashboard-el5BquXN.js} +2 -2
  133. package/dashboard/dist/assets/{OperatorDashboard-3Hi2IiHi.js.map → OperatorDashboard-el5BquXN.js.map} +1 -1
  134. package/dashboard/dist/assets/{PersonaDetailPage-xb7O3tn9.js → PersonaDetailPage-B_tb8gfl.js} +2 -2
  135. package/dashboard/dist/assets/{PersonaDetailPage-xb7O3tn9.js.map → PersonaDetailPage-B_tb8gfl.js.map} +1 -1
  136. package/dashboard/dist/assets/{PersonasPage-uCYVhRBB.js → PersonasPage-BPI7mqM8.js} +2 -2
  137. package/dashboard/dist/assets/{PersonasPage-uCYVhRBB.js.map → PersonasPage-BPI7mqM8.js.map} +1 -1
  138. package/dashboard/dist/assets/{PortalPage-D1MOMJ9Q.js → PortalPage-e_rBb1do.js} +2 -2
  139. package/dashboard/dist/assets/{PortalPage-D1MOMJ9Q.js.map → PortalPage-e_rBb1do.js.map} +1 -1
  140. package/dashboard/dist/assets/{ProcessDetailPage-Tf8FQCUm.js → ProcessDetailPage-D35RX1bB.js} +2 -2
  141. package/dashboard/dist/assets/{ProcessDetailPage-Tf8FQCUm.js.map → ProcessDetailPage-D35RX1bB.js.map} +1 -1
  142. package/dashboard/dist/assets/{ProcessesListPage-DPLRgznC.js → ProcessesListPage-CT81miI5.js} +2 -2
  143. package/dashboard/dist/assets/{ProcessesListPage-DPLRgznC.js.map → ProcessesListPage-CT81miI5.js.map} +1 -1
  144. package/dashboard/dist/assets/{ResolverForm-BXqJEPte.js → ResolverForm-BxJkoKAO.js} +2 -2
  145. package/dashboard/dist/assets/{ResolverForm-BXqJEPte.js.map → ResolverForm-BxJkoKAO.js.map} +1 -1
  146. package/dashboard/dist/assets/{RoleDetailPage-KJnZGPPY.js → RoleDetailPage-DtU7vsJm.js} +2 -2
  147. package/dashboard/dist/assets/{RoleDetailPage-KJnZGPPY.js.map → RoleDetailPage-DtU7vsJm.js.map} +1 -1
  148. package/dashboard/dist/assets/{RolesPage-C5f-3zcs.js → RolesPage-BE7RWt9q.js} +2 -2
  149. package/dashboard/dist/assets/{RolesPage-C5f-3zcs.js.map → RolesPage-BE7RWt9q.js.map} +1 -1
  150. package/dashboard/dist/assets/{RosterWidget-WCtpUEzc.js → RosterWidget-BJMx0a8Z.js} +2 -2
  151. package/dashboard/dist/assets/{RosterWidget-WCtpUEzc.js.map → RosterWidget-BJMx0a8Z.js.map} +1 -1
  152. package/dashboard/dist/assets/{RunAsSelector-CzabsFYU.js → RunAsSelector-Co6s9bqA.js} +2 -2
  153. package/dashboard/dist/assets/{RunAsSelector-CzabsFYU.js.map → RunAsSelector-Co6s9bqA.js.map} +1 -1
  154. package/dashboard/dist/assets/ScanCodesPage-C2TETaj5.js +2 -0
  155. package/dashboard/dist/assets/ScanCodesPage-C2TETaj5.js.map +1 -0
  156. package/dashboard/dist/assets/ScanSchemeDetailPage-C2UgU8l-.js +5 -0
  157. package/dashboard/dist/assets/ScanSchemeDetailPage-C2UgU8l-.js.map +1 -0
  158. package/dashboard/dist/assets/ScanStationPage-nWYz-OD3.js +2 -0
  159. package/dashboard/dist/assets/ScanStationPage-nWYz-OD3.js.map +1 -0
  160. package/dashboard/dist/assets/SchemeMatchFields-9H7SmbED.js +4 -0
  161. package/dashboard/dist/assets/SchemeMatchFields-9H7SmbED.js.map +1 -0
  162. package/dashboard/dist/assets/{StickyPagination-C2fzclxr.js → StickyPagination-miUdVAKw.js} +2 -2
  163. package/dashboard/dist/assets/{StickyPagination-C2fzclxr.js.map → StickyPagination-miUdVAKw.js.map} +1 -1
  164. package/dashboard/dist/assets/{StreamMessageDetail-wF4NM8gi.js → StreamMessageDetail-D5Rk7pn7.js} +2 -2
  165. package/dashboard/dist/assets/{StreamMessageDetail-wF4NM8gi.js.map → StreamMessageDetail-D5Rk7pn7.js.map} +1 -1
  166. package/dashboard/dist/assets/{SwimlaneTimeline-B4Hg97qO.js → SwimlaneTimeline-B1QY1ZzH.js} +2 -2
  167. package/dashboard/dist/assets/{SwimlaneTimeline-B4Hg97qO.js.map → SwimlaneTimeline-B1QY1ZzH.js.map} +1 -1
  168. package/dashboard/dist/assets/{TaskDetailPage-DAxxcFDD.js → TaskDetailPage-DKUM37o8.js} +2 -2
  169. package/dashboard/dist/assets/{TaskDetailPage-DAxxcFDD.js.map → TaskDetailPage-DKUM37o8.js.map} +1 -1
  170. package/dashboard/dist/assets/{TasksListPage-BmghuHbc.js → TasksListPage-CUulwvm-.js} +2 -2
  171. package/dashboard/dist/assets/{TasksListPage-BmghuHbc.js.map → TasksListPage-CUulwvm-.js.map} +1 -1
  172. package/dashboard/dist/assets/{TimeAgo-CFeB6U2O.js → TimeAgo-CHTelacB.js} +2 -2
  173. package/dashboard/dist/assets/{TimeAgo-CFeB6U2O.js.map → TimeAgo-CHTelacB.js.map} +1 -1
  174. package/dashboard/dist/assets/{TimestampCell-M_FD9JEc.js → TimestampCell-NanLWLKo.js} +2 -2
  175. package/dashboard/dist/assets/{TimestampCell-M_FD9JEc.js.map → TimestampCell-NanLWLKo.js.map} +1 -1
  176. package/dashboard/dist/assets/{ToolTestPanel-D7PihZG9.js → ToolTestPanel-CF1CHzgz.js} +2 -2
  177. package/dashboard/dist/assets/{ToolTestPanel-D7PihZG9.js.map → ToolTestPanel-CF1CHzgz.js.map} +1 -1
  178. package/dashboard/dist/assets/{TopicDetailPage-T0dLt7Ao.js → TopicDetailPage-CGO8XV_a.js} +2 -2
  179. package/dashboard/dist/assets/{TopicDetailPage-T0dLt7Ao.js.map → TopicDetailPage-CGO8XV_a.js.map} +1 -1
  180. package/dashboard/dist/assets/{TopicsPage-DP5ox5oX.js → TopicsPage-Bt8gOKYr.js} +2 -2
  181. package/dashboard/dist/assets/{TopicsPage-DP5ox5oX.js.map → TopicsPage-Bt8gOKYr.js.map} +1 -1
  182. package/dashboard/dist/assets/{UserName-ET3r3u-A.js → UserName-DKXnK7DD.js} +2 -2
  183. package/dashboard/dist/assets/{UserName-ET3r3u-A.js.map → UserName-DKXnK7DD.js.map} +1 -1
  184. package/dashboard/dist/assets/{WorkflowExecutionPage-DBq2lZ_C.js → WorkflowExecutionPage-Crf7AIFc.js} +2 -2
  185. package/dashboard/dist/assets/{WorkflowExecutionPage-DBq2lZ_C.js.map → WorkflowExecutionPage-Crf7AIFc.js.map} +1 -1
  186. package/dashboard/dist/assets/{WorkflowsDashboard-WO4cH8sU.js → WorkflowsDashboard--isjt06C.js} +2 -2
  187. package/dashboard/dist/assets/{WorkflowsDashboard-WO4cH8sU.js.map → WorkflowsDashboard--isjt06C.js.map} +1 -1
  188. package/dashboard/dist/assets/{WorkflowsOverview-CJfg0rQH.js → WorkflowsOverview-D7Oqf4-V.js} +2 -2
  189. package/dashboard/dist/assets/{WorkflowsOverview-CJfg0rQH.js.map → WorkflowsOverview-D7Oqf4-V.js.map} +1 -1
  190. package/dashboard/dist/assets/{YamlWorkflowDetailPage-C8rkvYCp.js → YamlWorkflowDetailPage-B0wxgrGP.js} +8 -8
  191. package/dashboard/dist/assets/{YamlWorkflowDetailPage-C8rkvYCp.js.map → YamlWorkflowDetailPage-B0wxgrGP.js.map} +1 -1
  192. package/dashboard/dist/assets/{YamlWorkflowsPage-DHQ4ZVzM.js → YamlWorkflowsPage-BVdLnm6K.js} +2 -2
  193. package/dashboard/dist/assets/{YamlWorkflowsPage-DHQ4ZVzM.js.map → YamlWorkflowsPage-BVdLnm6K.js.map} +1 -1
  194. package/dashboard/dist/assets/{agents-zulmHig2.js → agents-CHjbjHXA.js} +2 -2
  195. package/dashboard/dist/assets/{agents-zulmHig2.js.map → agents-CHjbjHXA.js.map} +1 -1
  196. package/dashboard/dist/assets/{bots-D4mtcPHB.js → bots-WrUhEPWs.js} +2 -2
  197. package/dashboard/dist/assets/{bots-D4mtcPHB.js.map → bots-WrUhEPWs.js.map} +1 -1
  198. package/dashboard/dist/assets/{capabilities-rFZDH0zF.js → capabilities-CunMmkj8.js} +2 -2
  199. package/dashboard/dist/assets/{capabilities-rFZDH0zF.js.map → capabilities-CunMmkj8.js.map} +1 -1
  200. package/dashboard/dist/assets/{controlplane-INfcW_9F.js → controlplane-D6IZIZoh.js} +2 -2
  201. package/dashboard/dist/assets/{controlplane-INfcW_9F.js.map → controlplane-D6IZIZoh.js.map} +1 -1
  202. package/dashboard/dist/assets/{escalation-columns-8ker-czW.js → escalation-columns-Bvo6JI4Z.js} +2 -2
  203. package/dashboard/dist/assets/{escalation-columns-8ker-czW.js.map → escalation-columns-Bvo6JI4Z.js.map} +1 -1
  204. package/dashboard/dist/assets/{escalation-items-B6eDMoTN.js → escalation-items-DFGRwo49.js} +2 -2
  205. package/dashboard/dist/assets/{escalation-items-B6eDMoTN.js.map → escalation-items-DFGRwo49.js.map} +1 -1
  206. package/dashboard/dist/assets/{index-Cfg4TFDb.js → index-B8qrHwp9.js} +2 -2
  207. package/dashboard/dist/assets/{index-Cfg4TFDb.js.map → index-B8qrHwp9.js.map} +1 -1
  208. package/dashboard/dist/assets/{index-D-Fd0gQ_.js → index-B95LbYhW.js} +2 -2
  209. package/dashboard/dist/assets/{index-D-Fd0gQ_.js.map → index-B95LbYhW.js.map} +1 -1
  210. package/dashboard/dist/assets/{index-BpillEP7.js → index-BZFSXEkr.js} +2 -2
  211. package/dashboard/dist/assets/{index-BpillEP7.js.map → index-BZFSXEkr.js.map} +1 -1
  212. package/dashboard/dist/assets/index-BmzscsXK.css +1 -0
  213. package/dashboard/dist/assets/{index-ChF-l2z9.js → index-Bo8QU31k.js} +2 -2
  214. package/dashboard/dist/assets/{index-ChF-l2z9.js.map → index-Bo8QU31k.js.map} +1 -1
  215. package/dashboard/dist/assets/{index-0LXkjZjt.js → index-C7EIu1mG.js} +2 -2
  216. package/dashboard/dist/assets/{index-0LXkjZjt.js.map → index-C7EIu1mG.js.map} +1 -1
  217. package/dashboard/dist/assets/{index-Cm6_Peh7.js → index-CpCchhQv.js} +2 -2
  218. package/dashboard/dist/assets/{index-Cm6_Peh7.js.map → index-CpCchhQv.js.map} +1 -1
  219. package/dashboard/dist/assets/{index-5XUBZtlv.js → index-DCJ483vt.js} +2 -2
  220. package/dashboard/dist/assets/{index-5XUBZtlv.js.map → index-DCJ483vt.js.map} +1 -1
  221. package/dashboard/dist/assets/{index-BcVkiaCv.js → index-DRK7M1_9.js} +2 -2
  222. package/dashboard/dist/assets/{index-BcVkiaCv.js.map → index-DRK7M1_9.js.map} +1 -1
  223. package/dashboard/dist/assets/{index-D-EVgGsm.js → index-DRw0FXdX.js} +2 -2
  224. package/dashboard/dist/assets/{index-D-EVgGsm.js.map → index-DRw0FXdX.js.map} +1 -1
  225. package/dashboard/dist/assets/{index-CV7KmPdF.js → index-OuKQ_0eB.js} +2 -2
  226. package/dashboard/dist/assets/{index-CV7KmPdF.js.map → index-OuKQ_0eB.js.map} +1 -1
  227. package/dashboard/dist/assets/index-P-DlgAWj.js +3 -0
  228. package/dashboard/dist/assets/index-P-DlgAWj.js.map +1 -0
  229. package/dashboard/dist/assets/{index-Cg9W61lM.js → index-boT612Jo.js} +2 -2
  230. package/dashboard/dist/assets/{index-Cg9W61lM.js.map → index-boT612Jo.js.map} +1 -1
  231. package/dashboard/dist/assets/index-ygxyAKcc.js +67 -0
  232. package/dashboard/dist/assets/index-ygxyAKcc.js.map +1 -0
  233. package/dashboard/dist/assets/{knowledge-_WaBsrbC.js → knowledge-BubJBTwg.js} +2 -2
  234. package/dashboard/dist/assets/{knowledge-_WaBsrbC.js.map → knowledge-BubJBTwg.js.map} +1 -1
  235. package/dashboard/dist/assets/{machines-D6ig2Q8z.js → machines-DSm5NFgs.js} +2 -2
  236. package/dashboard/dist/assets/{machines-D6ig2Q8z.js.map → machines-DSm5NFgs.js.map} +1 -1
  237. package/dashboard/dist/assets/{mcp-DtWRQM1G.js → mcp-D6MckqOV.js} +2 -2
  238. package/dashboard/dist/assets/{mcp-DtWRQM1G.js.map → mcp-D6MckqOV.js.map} +1 -1
  239. package/dashboard/dist/assets/{mcp-query-vQm92kTd.js → mcp-query-VyCdOag6.js} +2 -2
  240. package/dashboard/dist/assets/{mcp-query-vQm92kTd.js.map → mcp-query-VyCdOag6.js.map} +1 -1
  241. package/dashboard/dist/assets/{personas-BLxQpGNz.js → personas-CyJc10xe.js} +2 -2
  242. package/dashboard/dist/assets/{personas-BLxQpGNz.js.map → personas-CyJc10xe.js.map} +1 -1
  243. package/dashboard/dist/assets/{pipelines-ClmRtlkR.js → pipelines-B2inDtx3.js} +2 -2
  244. package/dashboard/dist/assets/{pipelines-ClmRtlkR.js.map → pipelines-B2inDtx3.js.map} +1 -1
  245. package/dashboard/dist/assets/{tasks-CVZT1pf0.js → tasks-DOP4d3M6.js} +2 -2
  246. package/dashboard/dist/assets/{tasks-CVZT1pf0.js.map → tasks-DOP4d3M6.js.map} +1 -1
  247. package/dashboard/dist/assets/{topics-rkG9-6El.js → topics-CNOjSWpX.js} +2 -2
  248. package/dashboard/dist/assets/{topics-rkG9-6El.js.map → topics-CNOjSWpX.js.map} +1 -1
  249. package/dashboard/dist/assets/{useDebouncedValue-D2aCC74y.js → useDebouncedValue-CgO0TGMd.js} +2 -2
  250. package/dashboard/dist/assets/{useDebouncedValue-D2aCC74y.js.map → useDebouncedValue-CgO0TGMd.js.map} +1 -1
  251. package/dashboard/dist/assets/{useNamespace-BGfkF4ej.js → useNamespace-BWHvUKtK.js} +2 -2
  252. package/dashboard/dist/assets/{useNamespace-BGfkF4ej.js.map → useNamespace-BWHvUKtK.js.map} +1 -1
  253. package/dashboard/dist/assets/{useYamlActivityEvents-DOU0_nfZ.js → useYamlActivityEvents-BZQ__ZGD.js} +2 -2
  254. package/dashboard/dist/assets/{useYamlActivityEvents-DOU0_nfZ.js.map → useYamlActivityEvents-BZQ__ZGD.js.map} +1 -1
  255. package/dashboard/dist/assets/{validate-bHZ917pZ.js → validate-CAin6WM_.js} +2 -2
  256. package/dashboard/dist/assets/{validate-bHZ917pZ.js.map → validate-CAin6WM_.js.map} +1 -1
  257. package/dashboard/dist/assets/{yaml-workflows-S7qlgdg6.js → yaml-workflows-Dyln3od-.js} +2 -2
  258. package/dashboard/dist/assets/{yaml-workflows-S7qlgdg6.js.map → yaml-workflows-Dyln3od-.js.map} +1 -1
  259. package/dashboard/dist/index.html +2 -2
  260. package/docs/accumulator.md +1 -1
  261. package/docs/api/http/escalations.md +1 -1
  262. package/docs/api/mcp/human-queue.md +5 -1
  263. package/docs/api/sdk/escalations.md +1 -1
  264. package/docs/dashboard.md +4 -2
  265. package/docs/hitl/escalation.md +16 -0
  266. package/docs/hitl/lookups.md +2 -0
  267. package/docs/mcp.md +2 -0
  268. package/docs/scan-codes.md +34 -11
  269. package/package.json +2 -2
  270. package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js +0 -2
  271. package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js.map +0 -1
  272. package/dashboard/dist/assets/ScanCodesPage-D51d17HH.js +0 -2
  273. package/dashboard/dist/assets/ScanCodesPage-D51d17HH.js.map +0 -1
  274. package/dashboard/dist/assets/ScanSchemeDetailPage-CUK6Skxj.js +0 -2
  275. package/dashboard/dist/assets/ScanSchemeDetailPage-CUK6Skxj.js.map +0 -1
  276. package/dashboard/dist/assets/ScanStationPage-7vK0ddiV.js +0 -2
  277. package/dashboard/dist/assets/ScanStationPage-7vK0ddiV.js.map +0 -1
  278. package/dashboard/dist/assets/index-BpJ77OST.js +0 -3
  279. package/dashboard/dist/assets/index-BpJ77OST.js.map +0 -1
  280. package/dashboard/dist/assets/index-C_dp4WgY.css +0 -1
  281. package/dashboard/dist/assets/index-xycFf66M.js +0 -67
  282. package/dashboard/dist/assets/index-xycFf66M.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import{j as p,a as U}from"./vendor-query-DvWWuNIB.js";import{a as j}from"./StatusBadge-DHVwxre2.js";import{r as k}from"./index-xycFf66M.js";import{b as P}from"./vendor-icons-en0_uSRD.js";import{u as q,a as Y}from"./vendor-react-_9U4mKFr.js";function v(t){return!!(t.assigned_to&&t.assigned_until&&new Date(t.assigned_until)>new Date)}function ft(t){return!t.workflow_type}function W(t){return t.replace(/[_\-.]+/g," ").replace(/([a-z\d])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/([a-zA-Z])(\d)/g,"$1 $2").trim().split(/\s+/).filter(Boolean).map(e=>e===e.toUpperCase()&&e.length>1?e:e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function mt(t){return t.status==="pending"?v(t)?"bg-status-claimed-graphic":"bg-status-active":j[t.status]??"bg-status-active"}function At(t){const s=e=>{if(!e)return null;try{const o=JSON.parse(e);return o&&typeof o=="object"?o:null}catch{return null}};return{escalation:t,metadata:t.metadata??null,envelope:s(t.envelope),payload:s(t.escalation_payload),resolver:s(t.resolver_payload)}}const pt="200px";function gt(t){return`${Math.max(6,Math.round(t.length*.55+3.5))}rem`}const X=30;function K(t){return t.status==="pending"&&!v(t)}function yt({row:t,def:s,onView:e,prominent:o,forceView:i}){const r=(s==null?void 0:s.action)??"claim",a=i?"view":r,l=r===a&&(s!=null&&s.label)?s.label:a==="claim"?"Claim":"View",A=k(),R=q(),L=Y(),[T,h]=U.useState(""),$=a==="claim"&&!K(t),D=I=>{if(I.stopPropagation(),a==="view"){e==null||e();return}if(s!=null&&s.submitOnClaim){R(`/escalations/detail/${t.id}`,{state:{autoStart:!0,durationMinutes:s==null?void 0:s.durationMinutes,from:L.pathname}});return}h(""),A.mutate({id:t.id,durationMinutes:(s==null?void 0:s.durationMinutes)??X},{onSuccess:()=>e==null?void 0:e(),onError:N=>h(N.message)})},C=o?"btn-primary text-xs shrink-0 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent":"px-2 py-0.5 rounded text-2xs font-medium text-accent/70 border border-accent/30 enabled:hover:text-accent enabled:hover:border-accent/60 enabled:hover:bg-accent/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap";return p.jsxs("span",{className:"inline-flex flex-col items-end gap-0.5",children:[p.jsx("button",{type:"button",onClick:D,disabled:A.isPending||$,title:$?t.status==="pending"?"claimed":t.status:void 0,className:C,"data-testid":"row-action-button",children:A.isPending?"Claiming…":l}),T&&p.jsx("span",{className:"text-2xs text-status-error","data-testid":"row-action-error",children:T})]})}const Z=/^\{\{\s*metadata\.([a-zA-Z0-9_]+)\s*\}\}$/;function x(t){return typeof t=="string"&&t!==""||typeof t=="number"||typeof t=="boolean"}function Et(t,s){var r;const e=[],o=new Set,i=t.metadata??{};for(const a of s){const l=typeof a.value=="string"?(r=a.value.match(Z))==null?void 0:r[1]:void 0;if(!l||o.has(l))continue;const A=i[l];x(A)&&(o.add(l),e.push({key:l,label:a.label,value:A,bound:!0}))}for(const[a,l]of Object.entries(i))o.has(a)||!x(l)||(o.add(a),e.push({key:a,label:W(a),value:l}));return e}function bt({onOpen:t,className:s=""}){return p.jsx("button",{type:"button",onClick:e=>{e.stopPropagation(),t()},className:`p-1.5 rounded text-text-quaternary/70 hover:text-accent hover:bg-surface-hover transition-colors ${s}`,title:"Refine — filter or search by this row's values","aria-label":"Refine — filter or search by this row's values","data-testid":"row-refine",children:p.jsx(P,{className:"w-3.5 h-3.5",strokeWidth:1.5})})}const g={RELATED:"x-lt-related",COLUMNS:"x-lt-columns",ROW_DETAIL:"x-lt-row-detail",GROUP_BY:"x-lt-group-by",LAYOUT:"x-lt-layout"},f={ITEMS:"items",QUERY:"query"},E={COUNT:"count",MIN:"min",MAX:"max"},z={FIRST:"first",MIN:"min",MAX:"max",SUM:"sum",COUNT:"count",DISTINCT:"distinct"},u={ROLE:"role",METADATA:"metadata.",PAYLOAD:"payload.",RECIPROCAL_METADATA:"reciprocal.metadata."},d={MAX_SETS:4,MAX_QUERY_ROLES:12,MAX_ROW_DETAIL_SECTIONS:4,ROWS_MAX:100},G="facet-table",M="default",F=/^\{\{\s*([^{}]+?)\s*\}\}$/,_="item.",Q=/^[a-zA-Z0-9_]+$/,B=/^[a-zA-Z0-9_]+$/,H=/\{n\}/g;function b(t){return t===E.MIN||t===E.MAX}function O(t,s){var i;if(typeof s!="string")return null;const e=(i=s.match(F))==null?void 0:i[1];if(!e)return null;if(t===f.ITEMS){if(!e.startsWith(`${_}${u.PAYLOAD}`))return null;const r=e.slice(_.length+u.PAYLOAD.length);return r&&r.split(".").every(a=>Q.test(a))?`${u.PAYLOAD}${r}`:null}if(!e.startsWith(u.METADATA))return null;const o=e.slice(u.METADATA.length);return B.test(o)?e:null}function Tt(t,s){return b(t.aggregate)?`${t.aggregate}:${O(s,t.value)??""}`:t.splitBy??""}function ht(t,s){if(!t)return null;const e=t[String(s)]??t[M];return e===void 0?null:e.replace(H,String(s))}function $t(t,s){if(!s.length)return;const e=t===E.MIN;if(s.every(i=>typeof i=="number"))return e?Math.min(...s):Math.max(...s);const o=s.map(String).sort((i,r)=>i<r?-1:i>r?1:0);return e?o[0]:o[o.length-1]}const y=/^[a-zA-Z0-9_]+$/,J=/^[a-zA-Z][a-zA-Z0-9_-]{0,47}$/,w=/^[a-zA-Z0-9_]+$/,V=/^(0|[1-9][0-9]*)$/;class tt extends Error{}function n(t){throw new tt(t)}function c(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}function m(t){return typeof t=="string"&&t.trim().length>0}function et(t){return t.length>0&&t.split(".").every(s=>w.test(s))}function st(t,s){return t===f.QUERY?s===u.ROLE||s.startsWith(u.METADATA)&&y.test(s.slice(u.METADATA.length))?null:`splitBy "${s}" on a query set must be "role" or "metadata.<key>"`:s.startsWith(u.PAYLOAD)&&et(s.slice(u.PAYLOAD.length))||s.startsWith(u.RECIPROCAL_METADATA)&&y.test(s.slice(u.RECIPROCAL_METADATA.length))?null:`splitBy "${s}" on an items set must be "payload.<path>" or "reciprocal.metadata.<key>"`}function rt(t,s){if(J.test(t)||n(`x-lt-related name "${t}" must start with a letter (letters, digits, _ or -)`),c(s)||n(`x-lt-related.${t} must be an object`),s.source===f.ITEMS)return s.query!==void 0&&n(`x-lt-related.${t}: an items set takes no query`),{source:f.ITEMS};s.source!==f.QUERY&&n(`x-lt-related.${t}.source must be "items" or "query"`);const e=s.query;c(e)||n(`x-lt-related.${t}.query is required for a query set`);const o=e.roles!==void 0,i=e.segment!==void 0;if(o===i&&n(`x-lt-related.${t}.query takes exactly one of roles or segment`),o){const r=e.roles;(!Array.isArray(r)||r.length===0||r.length>d.MAX_QUERY_ROLES||!r.every(m))&&n(`x-lt-related.${t}.query.roles must be 1..${d.MAX_QUERY_ROLES} role names`)}else m(e.segment)||n(`x-lt-related.${t}.query.segment must be a role name`);(!c(e.facets)||Object.keys(e.facets).length===0)&&n(`x-lt-related.${t}.query.facets must name at least one facet`);for(const[r,a]of Object.entries(e.facets))y.test(r)||n(`x-lt-related.${t}.query.facets key "${r}" must be letters, digits or _`),(a===null||typeof a=="object")&&n(`x-lt-related.${t}.query.facets.${r} must be a scalar or template`);if(e.narrow!==void 0){(!c(e.narrow)||Object.keys(e.narrow).length===0)&&n(`x-lt-related.${t}.query.narrow must name at least one facet`);for(const[r,a]of Object.entries(e.narrow))y.test(r)||n(`x-lt-related.${t}.query.narrow key "${r}" must be letters, digits or _`),r in e.facets&&n(`x-lt-related.${t}.query.narrow.${r} is already a required facet`),(a===null||typeof a=="object")&&n(`x-lt-related.${t}.query.narrow.${r} must be a scalar or template`)}return e.status!==void 0&&!m(e.status)&&n(`x-lt-related.${t}.query.status must be a status`),{source:f.QUERY,query:{...o?{roles:[...e.roles]}:{segment:e.segment},facets:{...e.facets},...e.narrow!==void 0?{narrow:{...e.narrow}}:{},...e.status!==void 0?{status:e.status}:{}}}}function at(t,s,e){const o=t.related;(!m(o)||!s[o])&&n(`${e}.related must name a set declared in x-lt-related`),t.aggregate!==void 0&&t.aggregate!==E.COUNT&&!b(t.aggregate)&&n(`${e}.aggregate must be "count", "min" or "max"`);const i=s[o].source;if(b(t.aggregate)?(O(i,t.value)||n(i===f.ITEMS?`${e}.value must be "{{item.payload.<path>}}" on an items set`:`${e}.value must be "{{metadata.<key>}}" on a query set`),t.splitBy!==void 0&&n(`${e}: a ${t.aggregate} column takes no splitBy`),t.display!==void 0&&n(`${e}: display applies to a count column`)):t.value!==void 0&&n(`${e}.value applies to a min or max column`),t.format!==void 0&&typeof t.format!="string"&&n(`${e}.format must be a format name`),t.display!==void 0&&(!c(t.display)||Object.keys(t.display).length===0||!Object.entries(t.display).every(([r,a])=>(r===M||V.test(r))&&typeof a=="string"))&&n(`${e}.display must map counts (or "default") to display text`),t.splitBy!==void 0){m(t.splitBy)||n(`${e}.splitBy must be a path`);const r=st(s[o].source,t.splitBy);r&&n(`${e}: ${r}`)}return t.labels!==void 0&&(!c(t.labels)||!Object.values(t.labels).every(r=>typeof r=="string"))&&n(`${e}.labels must map values to display text`),t}function nt(t,s){return t===void 0?[]:((!Array.isArray(t)||t.length===0||t.length>d.MAX_ROW_DETAIL_SECTIONS)&&n(`x-lt-row-detail must be 1..${d.MAX_ROW_DETAIL_SECTIONS} sections`),t.map((e,o)=>{const i=`x-lt-row-detail[${o}]`;c(e)||n(`${i} must be an object`),(!m(e.related)||!s[e.related])&&n(`${i}.related must name a set declared in x-lt-related`),(!Array.isArray(e.columns)||e.columns.length===0)&&n(`${i}.columns must list at least one column`);for(const[r,a]of e.columns.entries())(!c(a)||!m(a.label)||typeof a.value!="string")&&n(`${i}.columns[${r}] needs a label and a value template`);return e.limit!==void 0&&(!Number.isInteger(e.limit)||e.limit<1||e.limit>d.ROWS_MAX)&&n(`${i}.limit must be 1..${d.ROWS_MAX}`),e}))}function ot(t){const s=t[g.GROUP_BY];if(s===void 0||t[g.LAYOUT]!==G)return null;const e=typeof s=="string"&&s.startsWith(u.METADATA)?s.slice(u.METADATA.length):"";return y.test(e)||n('x-lt-group-by on a facet-table must be "metadata.<key>"'),e}const S=new Set(Object.values(z));function xt(t){const s={sets:{},columns:[],rowDetail:[],groupKey:null};if(!c(t))return s;const e=t[g.RELATED],o={};if(e!==void 0){c(e)||n("x-lt-related must map set names to declarations");const a=Object.keys(e);(a.length===0||a.length>d.MAX_SETS)&&n(`x-lt-related must declare 1..${d.MAX_SETS} sets`);for(const l of a)o[l]=rt(l,e[l])}const i=[],r=t[g.COLUMNS];return Array.isArray(r)&&r.forEach((a,l)=>{c(a)&&(a.related!==void 0&&i.push(at(a,o,`x-lt-columns[${l}]`)),a.group!==void 0&&(typeof a.group!="string"||!S.has(a.group))&&n(`x-lt-columns[${l}].group must be one of ${[...S].join(", ")}`))}),{sets:o,columns:i,rowDetail:nt(t[g.ROW_DETAIL],o),groupKey:ot(t)}}export{z as G,pt as I,Z as M,bt as R,u as S,W as a,xt as b,b as c,ht as d,mt as e,$t as f,Et as g,yt as h,v as i,gt as j,Tt as k,ft as l,At as r};
2
- //# sourceMappingURL=validate-bHZ917pZ.js.map
1
+ import{j as p,a as U}from"./vendor-query-DvWWuNIB.js";import{a as j}from"./StatusBadge-DHVwxre2.js";import{r as k}from"./index-ygxyAKcc.js";import{b as P}from"./vendor-icons-en0_uSRD.js";import{u as q,a as Y}from"./vendor-react-_9U4mKFr.js";function v(t){return!!(t.assigned_to&&t.assigned_until&&new Date(t.assigned_until)>new Date)}function ft(t){return!t.workflow_type}function W(t){return t.replace(/[_\-.]+/g," ").replace(/([a-z\d])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/([a-zA-Z])(\d)/g,"$1 $2").trim().split(/\s+/).filter(Boolean).map(e=>e===e.toUpperCase()&&e.length>1?e:e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function mt(t){return t.status==="pending"?v(t)?"bg-status-claimed-graphic":"bg-status-active":j[t.status]??"bg-status-active"}function At(t){const s=e=>{if(!e)return null;try{const o=JSON.parse(e);return o&&typeof o=="object"?o:null}catch{return null}};return{escalation:t,metadata:t.metadata??null,envelope:s(t.envelope),payload:s(t.escalation_payload),resolver:s(t.resolver_payload)}}const pt="200px";function gt(t){return`${Math.max(6,Math.round(t.length*.55+3.5))}rem`}const X=30;function K(t){return t.status==="pending"&&!v(t)}function yt({row:t,def:s,onView:e,prominent:o,forceView:i}){const r=(s==null?void 0:s.action)??"claim",a=i?"view":r,l=r===a&&(s!=null&&s.label)?s.label:a==="claim"?"Claim":"View",A=k(),R=q(),L=Y(),[T,h]=U.useState(""),$=a==="claim"&&!K(t),D=I=>{if(I.stopPropagation(),a==="view"){e==null||e();return}if(s!=null&&s.submitOnClaim){R(`/escalations/detail/${t.id}`,{state:{autoStart:!0,durationMinutes:s==null?void 0:s.durationMinutes,from:L.pathname}});return}h(""),A.mutate({id:t.id,durationMinutes:(s==null?void 0:s.durationMinutes)??X},{onSuccess:()=>e==null?void 0:e(),onError:N=>h(N.message)})},C=o?"btn-primary text-xs shrink-0 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent":"px-2 py-0.5 rounded text-2xs font-medium text-accent/70 border border-accent/30 enabled:hover:text-accent enabled:hover:border-accent/60 enabled:hover:bg-accent/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap";return p.jsxs("span",{className:"inline-flex flex-col items-end gap-0.5",children:[p.jsx("button",{type:"button",onClick:D,disabled:A.isPending||$,title:$?t.status==="pending"?"claimed":t.status:void 0,className:C,"data-testid":"row-action-button",children:A.isPending?"Claiming…":l}),T&&p.jsx("span",{className:"text-2xs text-status-error","data-testid":"row-action-error",children:T})]})}const Z=/^\{\{\s*metadata\.([a-zA-Z0-9_]+)\s*\}\}$/;function x(t){return typeof t=="string"&&t!==""||typeof t=="number"||typeof t=="boolean"}function Et(t,s){var r;const e=[],o=new Set,i=t.metadata??{};for(const a of s){const l=typeof a.value=="string"?(r=a.value.match(Z))==null?void 0:r[1]:void 0;if(!l||o.has(l))continue;const A=i[l];x(A)&&(o.add(l),e.push({key:l,label:a.label,value:A,bound:!0}))}for(const[a,l]of Object.entries(i))o.has(a)||!x(l)||(o.add(a),e.push({key:a,label:W(a),value:l}));return e}function bt({onOpen:t,className:s=""}){return p.jsx("button",{type:"button",onClick:e=>{e.stopPropagation(),t()},className:`p-1.5 rounded text-text-quaternary/70 hover:text-accent hover:bg-surface-hover transition-colors ${s}`,title:"Refine — filter or search by this row's values","aria-label":"Refine — filter or search by this row's values","data-testid":"row-refine",children:p.jsx(P,{className:"w-3.5 h-3.5",strokeWidth:1.5})})}const g={RELATED:"x-lt-related",COLUMNS:"x-lt-columns",ROW_DETAIL:"x-lt-row-detail",GROUP_BY:"x-lt-group-by",LAYOUT:"x-lt-layout"},f={ITEMS:"items",QUERY:"query"},E={COUNT:"count",MIN:"min",MAX:"max"},z={FIRST:"first",MIN:"min",MAX:"max",SUM:"sum",COUNT:"count",DISTINCT:"distinct"},u={ROLE:"role",METADATA:"metadata.",PAYLOAD:"payload.",RECIPROCAL_METADATA:"reciprocal.metadata."},d={MAX_SETS:4,MAX_QUERY_ROLES:12,MAX_ROW_DETAIL_SECTIONS:4,ROWS_MAX:100},G="facet-table",M="default",F=/^\{\{\s*([^{}]+?)\s*\}\}$/,_="item.",Q=/^[a-zA-Z0-9_]+$/,B=/^[a-zA-Z0-9_]+$/,H=/\{n\}/g;function b(t){return t===E.MIN||t===E.MAX}function O(t,s){var i;if(typeof s!="string")return null;const e=(i=s.match(F))==null?void 0:i[1];if(!e)return null;if(t===f.ITEMS){if(!e.startsWith(`${_}${u.PAYLOAD}`))return null;const r=e.slice(_.length+u.PAYLOAD.length);return r&&r.split(".").every(a=>Q.test(a))?`${u.PAYLOAD}${r}`:null}if(!e.startsWith(u.METADATA))return null;const o=e.slice(u.METADATA.length);return B.test(o)?e:null}function Tt(t,s){return b(t.aggregate)?`${t.aggregate}:${O(s,t.value)??""}`:t.splitBy??""}function ht(t,s){if(!t)return null;const e=t[String(s)]??t[M];return e===void 0?null:e.replace(H,String(s))}function $t(t,s){if(!s.length)return;const e=t===E.MIN;if(s.every(i=>typeof i=="number"))return e?Math.min(...s):Math.max(...s);const o=s.map(String).sort((i,r)=>i<r?-1:i>r?1:0);return e?o[0]:o[o.length-1]}const y=/^[a-zA-Z0-9_]+$/,J=/^[a-zA-Z][a-zA-Z0-9_-]{0,47}$/,w=/^[a-zA-Z0-9_]+$/,V=/^(0|[1-9][0-9]*)$/;class tt extends Error{}function n(t){throw new tt(t)}function c(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}function m(t){return typeof t=="string"&&t.trim().length>0}function et(t){return t.length>0&&t.split(".").every(s=>w.test(s))}function st(t,s){return t===f.QUERY?s===u.ROLE||s.startsWith(u.METADATA)&&y.test(s.slice(u.METADATA.length))?null:`splitBy "${s}" on a query set must be "role" or "metadata.<key>"`:s.startsWith(u.PAYLOAD)&&et(s.slice(u.PAYLOAD.length))||s.startsWith(u.RECIPROCAL_METADATA)&&y.test(s.slice(u.RECIPROCAL_METADATA.length))?null:`splitBy "${s}" on an items set must be "payload.<path>" or "reciprocal.metadata.<key>"`}function rt(t,s){if(J.test(t)||n(`x-lt-related name "${t}" must start with a letter (letters, digits, _ or -)`),c(s)||n(`x-lt-related.${t} must be an object`),s.source===f.ITEMS)return s.query!==void 0&&n(`x-lt-related.${t}: an items set takes no query`),{source:f.ITEMS};s.source!==f.QUERY&&n(`x-lt-related.${t}.source must be "items" or "query"`);const e=s.query;c(e)||n(`x-lt-related.${t}.query is required for a query set`);const o=e.roles!==void 0,i=e.segment!==void 0;if(o===i&&n(`x-lt-related.${t}.query takes exactly one of roles or segment`),o){const r=e.roles;(!Array.isArray(r)||r.length===0||r.length>d.MAX_QUERY_ROLES||!r.every(m))&&n(`x-lt-related.${t}.query.roles must be 1..${d.MAX_QUERY_ROLES} role names`)}else m(e.segment)||n(`x-lt-related.${t}.query.segment must be a role name`);(!c(e.facets)||Object.keys(e.facets).length===0)&&n(`x-lt-related.${t}.query.facets must name at least one facet`);for(const[r,a]of Object.entries(e.facets))y.test(r)||n(`x-lt-related.${t}.query.facets key "${r}" must be letters, digits or _`),(a===null||typeof a=="object")&&n(`x-lt-related.${t}.query.facets.${r} must be a scalar or template`);if(e.narrow!==void 0){(!c(e.narrow)||Object.keys(e.narrow).length===0)&&n(`x-lt-related.${t}.query.narrow must name at least one facet`);for(const[r,a]of Object.entries(e.narrow))y.test(r)||n(`x-lt-related.${t}.query.narrow key "${r}" must be letters, digits or _`),r in e.facets&&n(`x-lt-related.${t}.query.narrow.${r} is already a required facet`),(a===null||typeof a=="object")&&n(`x-lt-related.${t}.query.narrow.${r} must be a scalar or template`)}return e.status!==void 0&&!m(e.status)&&n(`x-lt-related.${t}.query.status must be a status`),{source:f.QUERY,query:{...o?{roles:[...e.roles]}:{segment:e.segment},facets:{...e.facets},...e.narrow!==void 0?{narrow:{...e.narrow}}:{},...e.status!==void 0?{status:e.status}:{}}}}function at(t,s,e){const o=t.related;(!m(o)||!s[o])&&n(`${e}.related must name a set declared in x-lt-related`),t.aggregate!==void 0&&t.aggregate!==E.COUNT&&!b(t.aggregate)&&n(`${e}.aggregate must be "count", "min" or "max"`);const i=s[o].source;if(b(t.aggregate)?(O(i,t.value)||n(i===f.ITEMS?`${e}.value must be "{{item.payload.<path>}}" on an items set`:`${e}.value must be "{{metadata.<key>}}" on a query set`),t.splitBy!==void 0&&n(`${e}: a ${t.aggregate} column takes no splitBy`),t.display!==void 0&&n(`${e}: display applies to a count column`)):t.value!==void 0&&n(`${e}.value applies to a min or max column`),t.format!==void 0&&typeof t.format!="string"&&n(`${e}.format must be a format name`),t.display!==void 0&&(!c(t.display)||Object.keys(t.display).length===0||!Object.entries(t.display).every(([r,a])=>(r===M||V.test(r))&&typeof a=="string"))&&n(`${e}.display must map counts (or "default") to display text`),t.splitBy!==void 0){m(t.splitBy)||n(`${e}.splitBy must be a path`);const r=st(s[o].source,t.splitBy);r&&n(`${e}: ${r}`)}return t.labels!==void 0&&(!c(t.labels)||!Object.values(t.labels).every(r=>typeof r=="string"))&&n(`${e}.labels must map values to display text`),t}function nt(t,s){return t===void 0?[]:((!Array.isArray(t)||t.length===0||t.length>d.MAX_ROW_DETAIL_SECTIONS)&&n(`x-lt-row-detail must be 1..${d.MAX_ROW_DETAIL_SECTIONS} sections`),t.map((e,o)=>{const i=`x-lt-row-detail[${o}]`;c(e)||n(`${i} must be an object`),(!m(e.related)||!s[e.related])&&n(`${i}.related must name a set declared in x-lt-related`),(!Array.isArray(e.columns)||e.columns.length===0)&&n(`${i}.columns must list at least one column`);for(const[r,a]of e.columns.entries())(!c(a)||!m(a.label)||typeof a.value!="string")&&n(`${i}.columns[${r}] needs a label and a value template`);return e.limit!==void 0&&(!Number.isInteger(e.limit)||e.limit<1||e.limit>d.ROWS_MAX)&&n(`${i}.limit must be 1..${d.ROWS_MAX}`),e}))}function ot(t){const s=t[g.GROUP_BY];if(s===void 0||t[g.LAYOUT]!==G)return null;const e=typeof s=="string"&&s.startsWith(u.METADATA)?s.slice(u.METADATA.length):"";return y.test(e)||n('x-lt-group-by on a facet-table must be "metadata.<key>"'),e}const S=new Set(Object.values(z));function xt(t){const s={sets:{},columns:[],rowDetail:[],groupKey:null};if(!c(t))return s;const e=t[g.RELATED],o={};if(e!==void 0){c(e)||n("x-lt-related must map set names to declarations");const a=Object.keys(e);(a.length===0||a.length>d.MAX_SETS)&&n(`x-lt-related must declare 1..${d.MAX_SETS} sets`);for(const l of a)o[l]=rt(l,e[l])}const i=[],r=t[g.COLUMNS];return Array.isArray(r)&&r.forEach((a,l)=>{c(a)&&(a.related!==void 0&&i.push(at(a,o,`x-lt-columns[${l}]`)),a.group!==void 0&&(typeof a.group!="string"||!S.has(a.group))&&n(`x-lt-columns[${l}].group must be one of ${[...S].join(", ")}`))}),{sets:o,columns:i,rowDetail:nt(t[g.ROW_DETAIL],o),groupKey:ot(t)}}export{z as G,pt as I,Z as M,bt as R,u as S,W as a,xt as b,b as c,ht as d,mt as e,$t as f,Et as g,yt as h,v as i,gt as j,Tt as k,ft as l,At as r};
2
+ //# sourceMappingURL=validate-CAin6WM_.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate-bHZ917pZ.js","sources":["../../src/lib/escalation.ts","../../src/lib/identifier-label.ts","../../src/components/escalation/list-view/row-parts.tsx","../../../shared/list-schema/types.ts","../../../shared/list-schema/aggregate.ts","../../../shared/list-schema/validate.ts"],"sourcesContent":["import type { LTEscalationRecord } from '../api/types';\n\nexport function isEffectivelyClaimed(esc: LTEscalationRecord): boolean {\n return !!(\n esc.assigned_to &&\n esc.assigned_until &&\n new Date(esc.assigned_until) > new Date()\n );\n}\n\n/** An ACK escalation has no associated workflow — it's a notification, not a task. */\nexport function isAckEscalation(esc: LTEscalationRecord): boolean {\n return !esc.workflow_type;\n}\n\nexport function isAvailable(esc: LTEscalationRecord): boolean {\n return (\n esc.status === 'pending' &&\n (!esc.assigned_to ||\n !esc.assigned_until ||\n new Date(esc.assigned_until) <= new Date())\n );\n}\n","/**\n * A human label for a code identifier: camelCase, snake_case, kebab-case, and\n * digit runs become Title Case words. `fleetTools` → `Fleet Tools`,\n * `print_order2` → `Print Order 2`. Acronyms keep their capitals: `mcpQuery`\n * → `Mcp Query` is avoided by treating an all-caps run as one word.\n */\nexport function identifierToTitle(id: string): string {\n const words = id\n .replace(/[_\\-.]+/g, ' ')\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/([a-zA-Z])(\\d)/g, '$1 $2')\n .trim()\n .split(/\\s+/)\n .filter(Boolean);\n return words\n .map((w) => (w === w.toUpperCase() && w.length > 1 ? w : w.charAt(0).toUpperCase() + w.slice(1)))\n .join(' ');\n}\n","import { useState } from 'react';\nimport { useNavigate, useLocation } from 'react-router-dom';\nimport { Search } from 'lucide-react';\nimport type { HelpTokenContext } from '../../../lib/x-lt-help';\nimport { STATUS_DOT_STYLES } from '../../common/display/StatusBadge';\nimport { useClaimEscalation } from '../../../api/escalations';\nimport { isEffectivelyClaimed } from '../../../lib/escalation';\nimport { identifierToTitle } from '../../../lib/identifier-label';\nimport type { RefinePair } from '../RefineDialog';\nimport type { LTEscalationRecord } from '../../../api/types';\n\n/** The row-level pieces every list layout shares: column and action\n * declarations, the row's token context, the row action, and refine. */\n\n/** Dot colour matches the standard table view: blue = pending unclaimed,\n * orange = under a live claim; other statuses follow the shared map. */\nexport function escalationDotClass(e: LTEscalationRecord): string {\n if (e.status === 'pending') {\n return isEffectivelyClaimed(e) ? 'bg-status-claimed-graphic' : 'bg-status-active';\n }\n return STATUS_DOT_STYLES[e.status] ?? 'bg-status-active';\n}\n\nexport interface ColumnDef {\n label: string;\n value: string;\n /** \"age\" renders an ISO timestamp as a compact age with an absolute tooltip. */\n format?: string;\n /**\n * Card-fold behavior when the table folds at narrow widths (same contract\n * as the engineer table): 1 = identity — always visible, forms the card's\n * title line; 2 = folds into the card body as a label/value pair; 3 =\n * dropped in card mode. Undeclared, the first column is the identity and\n * the rest fold.\n */\n priority?: 1 | 2 | 3;\n /** CSS column width (\"40%\", \"12rem\"). Unset columns share the remainder;\n * when no column declares one, the first column holds a fixed 200px so\n * the identity stays legible and every other value keeps its room. */\n width?: string;\n}\n\n/**\n * The per-row action button — the queue-working gesture, always available on\n * every layout. Template-driven: the schema author sets the action, its text,\n * and (for claim) the hold time.\n */\nexport interface RowActionDef {\n /** \"claim\" fires a one-click claim then opens the detail page already\n * claimed; \"view\" just opens it. Default \"claim\". */\n action?: 'claim' | 'view';\n /** Button text. Defaults \"Claim\" / \"View\" by action. */\n label?: string;\n /** Claim hold time in minutes. Default 30 (the platform claim default). */\n durationMinutes?: number;\n /**\n * Launch the detail page's claim-and-submit flow instead of a plain claim:\n * the row is claimed, the form's seeded defaults are resolved, and — when the\n * form declares `x-lt-transition` — the wait screen bridges to the born-assigned\n * follow-on. One list gesture (\"Start Harvesting\") starts the work and lands\n * the person on the next step. The behavior lives on the detail page (form\n * defaults, validation, transition); the list only points there with intent.\n */\n submitOnClaim?: boolean;\n}\n\n/** Build the token context for one escalation row (payloads are JSON strings). */\nexport function rowContext(e: LTEscalationRecord): HelpTokenContext {\n const parse = (s: string | null | undefined): Record<string, unknown> | null => {\n if (!s) return null;\n try {\n const v = JSON.parse(s);\n return v && typeof v === 'object' ? v : null;\n } catch {\n return null;\n }\n };\n return {\n escalation: e as unknown as Record<string, unknown>,\n metadata: e.metadata ?? null,\n envelope: parse(e.envelope),\n payload: parse(e.escalation_payload),\n resolver: parse(e.resolver_payload),\n };\n}\n\n/** The identity column's width when no column declares one: room for a label, no more. */\nexport const IDENTITY_COLUMN_WIDTH = '200px';\n\n/** The action column sizes to its label so the button never wraps or truncates. */\nexport function actionColumnWidth(label: string): string {\n return `${Math.max(6, Math.round(label.length * 0.55 + 3.5))}rem`;\n}\n\nconst DEFAULT_CLAIM_MINUTES = 30;\n\n/** Claim targets pending rows without a live claim window. */\nfunction isClaimable(row: LTEscalationRecord): boolean {\n return row.status === 'pending' && !isEffectivelyClaimed(row);\n}\n\n/**\n * The x-lt-row-action button. `claim` is one click: claim for the template's\n * duration, then open the detail page already claimed — the fast path for\n * working a queue. `view` opens the detail page. Persistent (light accent at\n * rest, saturating on hover); a rejected claim surfaces its message inline.\n */\nexport function RowActionButton({ row, def, onView, prominent, forceView }: {\n row: LTEscalationRecord;\n def?: RowActionDef;\n onView?: () => void;\n /** Hero treatment for the active-card CTA; default is the compact row button. */\n prominent?: boolean;\n /** Render claim templates as view actions (see EscalationListView). */\n forceView?: boolean;\n}) {\n const authored = def?.action ?? 'claim';\n const action = forceView ? 'view' : authored;\n // The authored label describes the authored gesture. When view is forced\n // over a claim template, claim wording would mislead — use the view default.\n const label = authored === action && def?.label\n ? def.label\n : action === 'claim' ? 'Claim' : 'View';\n const claim = useClaimEscalation();\n const navigate = useNavigate();\n const location = useLocation();\n const [error, setError] = useState('');\n\n // A spent gesture stays visible — the disabled button keeps every row's\n // layout uniform instead of leaving a hole on resolved/held rows.\n const spent = action === 'claim' && !isClaimable(row);\n\n const fire = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (action === 'view') {\n onView?.();\n return;\n }\n // Launch the detail page's claim → submit → transition flow. The detail\n // page owns the heavy lifting (seed defaults, validate, resolve, hand-off);\n // the list points there with the intent and the authored claim duration.\n if (def?.submitOnClaim) {\n navigate(`/escalations/detail/${row.id}`, {\n state: { autoStart: true, durationMinutes: def?.durationMinutes, from: location.pathname },\n });\n return;\n }\n setError('');\n claim.mutate(\n { id: row.id, durationMinutes: def?.durationMinutes ?? DEFAULT_CLAIM_MINUTES },\n {\n onSuccess: () => onView?.(),\n onError: (err) => setError((err as Error).message),\n },\n );\n };\n\n const classes = prominent\n ? 'btn-primary text-xs shrink-0 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent'\n : 'px-2 py-0.5 rounded text-2xs font-medium text-accent/70 border border-accent/30 enabled:hover:text-accent enabled:hover:border-accent/60 enabled:hover:bg-accent/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap';\n\n return (\n <span className=\"inline-flex flex-col items-end gap-0.5\">\n <button\n type=\"button\"\n onClick={fire}\n disabled={claim.isPending || spent}\n title={spent ? (row.status === 'pending' ? 'claimed' : row.status) : undefined}\n className={classes}\n data-testid=\"row-action-button\"\n >\n {claim.isPending ? 'Claiming…' : label}\n </button>\n {error && <span className=\"text-2xs text-status-error\" data-testid=\"row-action-error\">{error}</span>}\n </span>\n );\n}\n\n/** A field value token that is a pure metadata binding — facet-linkable. */\nexport const METADATA_TOKEN = /^\\{\\{\\s*metadata\\.([a-zA-Z0-9_]+)\\s*\\}\\}$/;\n\n/** A metadata value the faceted query can match on: a scalar with something in it. */\nfunction isFacetValue(raw: unknown): raw is string | number | boolean {\n return (typeof raw === 'string' && raw !== '') || typeof raw === 'number' || typeof raw === 'boolean';\n}\n\n/**\n * The refinable facts one row offers: every metadata facet the row carries.\n * Columns the author bound to a metadata value lead, under their authored\n * labels; every other scalar facet follows under a label derived from its\n * key, so the dialog reaches the whole record, not only what the columns\n * show. Feeds the row's RefineDialog.\n */\nexport function rowRefinePairs(row: LTEscalationRecord, columnDefs: ColumnDef[]): RefinePair[] {\n const pairs: RefinePair[] = [];\n const seen = new Set<string>();\n const metadata = row.metadata ?? {};\n for (const col of columnDefs) {\n const bound = typeof col.value === 'string' ? col.value.match(METADATA_TOKEN)?.[1] : undefined;\n if (!bound || seen.has(bound)) continue;\n const raw = metadata[bound];\n if (!isFacetValue(raw)) continue;\n seen.add(bound);\n pairs.push({ key: bound, label: col.label, value: raw, bound: true });\n }\n for (const [key, raw] of Object.entries(metadata)) {\n if (seen.has(key) || !isFacetValue(raw)) continue;\n seen.add(key);\n pairs.push({ key, label: identifierToTitle(key), value: raw });\n }\n return pairs;\n}\n\n/** The always-tappable row/card refine trigger — one magnifier, dialog behind it. */\nexport function RefineTrigger({ onOpen, className = '' }: { onOpen: () => void; className?: string }) {\n return (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); onOpen(); }}\n className={`p-1.5 rounded text-text-quaternary/70 hover:text-accent hover:bg-surface-hover transition-colors ${className}`}\n title=\"Refine — filter or search by this row's values\"\n aria-label=\"Refine — filter or search by this row's values\"\n data-testid=\"row-refine\"\n >\n <Search className=\"w-3.5 h-3.5\" strokeWidth={1.5} />\n </button>\n );\n}\n","/**\n * Related sets on a role's list schema. A set is named once under\n * `x-lt-related`; columns (`related`) and row details (`x-lt-row-detail`)\n * reference it by name. The server reads the declaration from the stored\n * list schema, never from the caller.\n *\n * items the host row's accumulated or batch items, each read through its\n * payload or its reciprocal row\n * query rows in other roles that share facets with the host row; facet\n * values are `{{domain.path}}` templates over the host row\n */\n\nexport const LIST_SCHEMA_KEYS = {\n RELATED: 'x-lt-related',\n COLUMNS: 'x-lt-columns',\n ROW_DETAIL: 'x-lt-row-detail',\n GROUP_BY: 'x-lt-group-by',\n LAYOUT: 'x-lt-layout',\n} as const;\n\nexport const RELATED_SOURCES = {\n ITEMS: 'items',\n QUERY: 'query',\n} as const;\nexport type RelatedSource = (typeof RELATED_SOURCES)[keyof typeof RELATED_SOURCES];\n\nexport const RELATED_AGGREGATES = {\n COUNT: 'count',\n /** The least item or row value: numbers as numbers, everything else as text. */\n MIN: 'min',\n MAX: 'max',\n} as const;\nexport type RelatedAggregate = (typeof RELATED_AGGREGATES)[keyof typeof RELATED_AGGREGATES];\n\n/** How a grouped table folds a plain column across a group's rows. */\nexport const GROUP_FOLDS = {\n FIRST: 'first',\n MIN: 'min',\n MAX: 'max',\n SUM: 'sum',\n COUNT: 'count',\n /** The distinct values, in row order, joined: \"standard, express\". */\n DISTINCT: 'distinct',\n} as const;\nexport type GroupFold = (typeof GROUP_FOLDS)[keyof typeof GROUP_FOLDS];\n\n/** Split prefixes. `role` splits a query set by the related row's role. */\nexport const SPLIT_PATHS = {\n ROLE: 'role',\n METADATA: 'metadata.',\n PAYLOAD: 'payload.',\n RECIPROCAL_METADATA: 'reciprocal.metadata.',\n} as const;\n\nexport const RELATED_LIMITS = {\n MAX_SETS: 4,\n MAX_QUERY_ROLES: 12,\n MAX_ROW_DETAIL_SECTIONS: 4,\n MAX_HOSTS: 100,\n ROWS_DEFAULT: 25,\n ROWS_MAX: 100,\n} as const;\n\n/** The table layout that renders related columns, row details, and groups. */\nexport const FACET_TABLE_LAYOUT = 'facet-table';\n\nexport interface RelatedQueryDecl {\n /** Related roles, in display order. Exclusive with `segment`. */\n roles?: string[];\n /** A Pace Board sequence by its first role; resolves to the ordered chain. */\n segment?: string;\n /** Facet containment; string values may be `{{domain.path}}` templates. */\n facets?: Record<string, unknown>;\n /**\n * Facets that narrow the match when the host row carries a value, and\n * drop away when it does not: a lane narrows its tub's look-ahead to its\n * own service level, a tub without lanes keeps the whole destination.\n */\n narrow?: Record<string, unknown>;\n /** Default `pending`. */\n status?: string;\n}\n\nexport interface RelatedSetDecl {\n source: RelatedSource;\n query?: RelatedQueryDecl;\n}\n\n/** A count column's text keyed by count; `default` covers the rest, `{n}` reads the count. */\nexport const RELATED_DISPLAY_DEFAULT = 'default';\n\nexport interface RelatedColumnDecl {\n label: string;\n related: string;\n aggregate?: RelatedAggregate;\n /** min/max: `{{item.payload.<path>}}` on an items set, `{{metadata.<key>}}` on a query set. */\n value?: string;\n /** min/max: how the value renders, as on any facet-table column. */\n format?: string;\n /** count: text by count, e.g. `{ \"0\": \"Ready\", \"default\": \"Waiting on {n}\" }`. */\n display?: Record<string, string>;\n splitBy?: string;\n labels?: Record<string, string>;\n priority?: 1 | 2 | 3;\n /** CSS width, as on any facet-table column. */\n width?: string;\n}\n\nexport interface RowDetailColumnDecl {\n label: string;\n value: string;\n format?: string;\n priority?: 1 | 2 | 3;\n}\n\nexport interface RowDetailSectionDecl {\n related: string;\n label?: string;\n columns: RowDetailColumnDecl[];\n limit?: number;\n}\n\n/** The validated, normalized related declaration of one list schema. */\nexport interface ListSchemaRelations {\n sets: Record<string, RelatedSetDecl>;\n columns: RelatedColumnDecl[];\n rowDetail: RowDetailSectionDecl[];\n /** The metadata key a facet-table groups by, when declared. */\n groupKey: string | null;\n}\n\n/** Per-host aggregate for one (set, splitBy) pair, or one (set, min/max, value) triple. */\nexport interface RelatedHostAggregate {\n count: number;\n /** min/max: the extreme value among `count` values; absent when none carries one. */\n value?: string | number;\n /** Split value to count; a null value is keyed by the empty string. */\n splits?: Record<string, number>;\n /** Items whose reciprocal row the viewer cannot read. */\n hidden?: number;\n /** A host whose facet templates resolved to nothing; the set did not run. */\n unresolved?: boolean;\n}\n\nexport interface RelatedSetResult {\n source: RelatedSource;\n /**\n * The roles whose rows the set reads, which a list follows for live\n * changes: a query set's resolved roles in order, or the roles of an item\n * set's readable reciprocal rows when a column splits by them.\n */\n roles?: string[];\n /** Query sets: role titles, keyed by role. */\n roleLabels?: Record<string, string>;\n /** Query sets: declared roles outside the viewer's full read scope. */\n restricted?: string[];\n /** Keyed by relatedAggregateKey (the splitBy, '' when unsplit, or `min:<path>`), then host id. */\n aggregates: Record<string, Record<string, RelatedHostAggregate>>;\n}\n\nexport interface RelatedAggregatesResponse {\n version: number | null;\n sets: Record<string, RelatedSetResult>;\n}\n\nexport interface RelatedItemEntry {\n itemKey: string;\n payload?: unknown;\n at?: string;\n actor?: string;\n reciprocalId?: string;\n}\n\nexport interface RelatedRow {\n /** Items sets only. */\n item?: RelatedItemEntry;\n /** The reciprocal row (items) or the related row (query); null when unreadable. */\n escalation: Record<string, unknown> | null;\n}\n\nexport interface RelatedRowsResponse {\n source: RelatedSource;\n rows: RelatedRow[];\n total: number;\n restricted?: string[];\n roleLabels?: Record<string, string>;\n}\n","import {\n RELATED_AGGREGATES,\n RELATED_DISPLAY_DEFAULT,\n RELATED_SOURCES,\n SPLIT_PATHS,\n type RelatedAggregate,\n type RelatedColumnDecl,\n} from './types';\n\nconst VALUE_TOKEN = /^\\{\\{\\s*([^{}]+?)\\s*\\}\\}$/;\nconst ITEM_PREFIX = 'item.';\nconst PATH_SEGMENT = /^[a-zA-Z0-9_]+$/;\nconst METADATA_KEY = /^[a-zA-Z0-9_]+$/;\nconst COUNT_TOKEN = /\\{n\\}/g;\n\nexport type RelatedExtreme = typeof RELATED_AGGREGATES.MIN | typeof RELATED_AGGREGATES.MAX;\n\n/** True for the aggregates that pick one value rather than count. */\nexport function isExtremeAggregate(aggregate: unknown): aggregate is RelatedExtreme {\n return aggregate === RELATED_AGGREGATES.MIN || aggregate === RELATED_AGGREGATES.MAX;\n}\n\n/**\n * The stored path a min/max `value` template reads: `payload.<path>` for an\n * items set, `metadata.<key>` for a query set. Null when the template does\n * not fit the set's source.\n */\nexport function relatedValuePath(source: string, value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const token = value.match(VALUE_TOKEN)?.[1];\n if (!token) return null;\n if (source === RELATED_SOURCES.ITEMS) {\n if (!token.startsWith(`${ITEM_PREFIX}${SPLIT_PATHS.PAYLOAD}`)) return null;\n const path = token.slice(ITEM_PREFIX.length + SPLIT_PATHS.PAYLOAD.length);\n return path && path.split('.').every((s) => PATH_SEGMENT.test(s)) ? `${SPLIT_PATHS.PAYLOAD}${path}` : null;\n }\n if (!token.startsWith(SPLIT_PATHS.METADATA)) return null;\n const key = token.slice(SPLIT_PATHS.METADATA.length);\n return METADATA_KEY.test(key) ? token : null;\n}\n\n/** The key a column's per-host aggregates are stored under in its set's result. */\nexport function relatedAggregateKey(col: Pick<RelatedColumnDecl, 'aggregate' | 'splitBy' | 'value'>, source: string): string {\n if (isExtremeAggregate(col.aggregate)) return `${col.aggregate}:${relatedValuePath(source, col.value) ?? ''}`;\n return col.splitBy ?? '';\n}\n\n/** A count column's display text, or null when the column declares none for this count. */\nexport function relatedCountText(display: Record<string, string> | undefined, count: number): string | null {\n if (!display) return null;\n const text = display[String(count)] ?? display[RELATED_DISPLAY_DEFAULT];\n return text === undefined ? null : text.replace(COUNT_TOKEN, String(count));\n}\n\n/**\n * The least or greatest of several values: numbers when every value is a\n * number, otherwise text in code-unit order (ISO instants order as text).\n */\nexport function foldExtreme(fold: RelatedAggregate, values: Array<string | number>): string | number | undefined {\n if (!values.length) return undefined;\n const pickMin = fold === RELATED_AGGREGATES.MIN;\n if (values.every((v) => typeof v === 'number')) {\n return pickMin ? Math.min(...(values as number[])) : Math.max(...(values as number[]));\n }\n const texts = values.map(String).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n return pickMin ? texts[0] : texts[texts.length - 1];\n}\n","import {\n FACET_TABLE_LAYOUT,\n GROUP_FOLDS,\n LIST_SCHEMA_KEYS,\n RELATED_AGGREGATES,\n RELATED_DISPLAY_DEFAULT,\n RELATED_LIMITS,\n RELATED_SOURCES,\n SPLIT_PATHS,\n type ListSchemaRelations,\n type RelatedColumnDecl,\n type RelatedSetDecl,\n type RowDetailSectionDecl,\n} from './types';\nimport { isExtremeAggregate, relatedValuePath } from './aggregate';\n\n/** A metadata key: interpolated as a JSON path, so strictly validated. */\nexport const METADATA_KEY = /^[a-zA-Z0-9_]+$/;\nconst SET_NAME = /^[a-zA-Z][a-zA-Z0-9_-]{0,47}$/;\nconst PATH_SEGMENT = /^[a-zA-Z0-9_]+$/;\nconst COUNT_KEY = /^(0|[1-9][0-9]*)$/;\n\ntype Obj = Record<string, unknown>;\n\nclass ListSchemaError extends Error {}\n\nfunction fail(message: string): never {\n throw new ListSchemaError(message);\n}\n\nfunction isObj(value: unknown): value is Obj {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\n/** True when a dotted path has only plain segments. */\nfunction isPlainPath(path: string): boolean {\n return path.length > 0 && path.split('.').every((s) => PATH_SEGMENT.test(s));\n}\n\n/** The split paths a set's source accepts. */\nexport function splitPathError(source: string, splitBy: string): string | null {\n if (source === RELATED_SOURCES.QUERY) {\n if (splitBy === SPLIT_PATHS.ROLE) return null;\n if (splitBy.startsWith(SPLIT_PATHS.METADATA) && METADATA_KEY.test(splitBy.slice(SPLIT_PATHS.METADATA.length))) return null;\n return `splitBy \"${splitBy}\" on a query set must be \"role\" or \"metadata.<key>\"`;\n }\n if (splitBy.startsWith(SPLIT_PATHS.PAYLOAD) && isPlainPath(splitBy.slice(SPLIT_PATHS.PAYLOAD.length))) return null;\n if (splitBy.startsWith(SPLIT_PATHS.RECIPROCAL_METADATA)\n && METADATA_KEY.test(splitBy.slice(SPLIT_PATHS.RECIPROCAL_METADATA.length))) return null;\n return `splitBy \"${splitBy}\" on an items set must be \"payload.<path>\" or \"reciprocal.metadata.<key>\"`;\n}\n\nfunction readSet(name: string, raw: unknown): RelatedSetDecl {\n if (!SET_NAME.test(name)) fail(`x-lt-related name \"${name}\" must start with a letter (letters, digits, _ or -)`);\n if (!isObj(raw)) fail(`x-lt-related.${name} must be an object`);\n if (raw.source === RELATED_SOURCES.ITEMS) {\n if (raw.query !== undefined) fail(`x-lt-related.${name}: an items set takes no query`);\n return { source: RELATED_SOURCES.ITEMS };\n }\n if (raw.source !== RELATED_SOURCES.QUERY) fail(`x-lt-related.${name}.source must be \"items\" or \"query\"`);\n const q = raw.query;\n if (!isObj(q)) fail(`x-lt-related.${name}.query is required for a query set`);\n const hasRoles = q.roles !== undefined;\n const hasSegment = q.segment !== undefined;\n if (hasRoles === hasSegment) fail(`x-lt-related.${name}.query takes exactly one of roles or segment`);\n if (hasRoles) {\n const roles = q.roles;\n if (!Array.isArray(roles) || roles.length === 0 || roles.length > RELATED_LIMITS.MAX_QUERY_ROLES\n || !roles.every(isNonEmptyString)) {\n fail(`x-lt-related.${name}.query.roles must be 1..${RELATED_LIMITS.MAX_QUERY_ROLES} role names`);\n }\n } else if (!isNonEmptyString(q.segment)) {\n fail(`x-lt-related.${name}.query.segment must be a role name`);\n }\n if (!isObj(q.facets) || Object.keys(q.facets).length === 0) {\n fail(`x-lt-related.${name}.query.facets must name at least one facet`);\n }\n for (const [key, value] of Object.entries(q.facets)) {\n if (!METADATA_KEY.test(key)) fail(`x-lt-related.${name}.query.facets key \"${key}\" must be letters, digits or _`);\n if (value === null || typeof value === 'object') fail(`x-lt-related.${name}.query.facets.${key} must be a scalar or template`);\n }\n if (q.narrow !== undefined) {\n if (!isObj(q.narrow) || Object.keys(q.narrow).length === 0) fail(`x-lt-related.${name}.query.narrow must name at least one facet`);\n for (const [key, value] of Object.entries(q.narrow)) {\n if (!METADATA_KEY.test(key)) fail(`x-lt-related.${name}.query.narrow key \"${key}\" must be letters, digits or _`);\n if (key in q.facets) fail(`x-lt-related.${name}.query.narrow.${key} is already a required facet`);\n if (value === null || typeof value === 'object') fail(`x-lt-related.${name}.query.narrow.${key} must be a scalar or template`);\n }\n }\n if (q.status !== undefined && !isNonEmptyString(q.status)) fail(`x-lt-related.${name}.query.status must be a status`);\n return {\n source: RELATED_SOURCES.QUERY,\n query: {\n ...(hasRoles ? { roles: [...(q.roles as string[])] } : { segment: q.segment as string }),\n facets: { ...q.facets },\n ...(q.narrow !== undefined ? { narrow: { ...(q.narrow as Obj) } } : {}),\n ...(q.status !== undefined ? { status: q.status as string } : {}),\n },\n };\n}\n\nfunction readRelatedColumn(raw: Obj, sets: Record<string, RelatedSetDecl>, at: string): RelatedColumnDecl {\n const name = raw.related;\n if (!isNonEmptyString(name) || !sets[name]) fail(`${at}.related must name a set declared in x-lt-related`);\n if (raw.aggregate !== undefined && raw.aggregate !== RELATED_AGGREGATES.COUNT && !isExtremeAggregate(raw.aggregate)) {\n fail(`${at}.aggregate must be \"count\", \"min\" or \"max\"`);\n }\n const source = sets[name].source;\n if (isExtremeAggregate(raw.aggregate)) {\n if (!relatedValuePath(source, raw.value)) {\n fail(source === RELATED_SOURCES.ITEMS\n ? `${at}.value must be \"{{item.payload.<path>}}\" on an items set`\n : `${at}.value must be \"{{metadata.<key>}}\" on a query set`);\n }\n if (raw.splitBy !== undefined) fail(`${at}: a ${raw.aggregate} column takes no splitBy`);\n if (raw.display !== undefined) fail(`${at}: display applies to a count column`);\n } else if (raw.value !== undefined) {\n fail(`${at}.value applies to a min or max column`);\n }\n if (raw.format !== undefined && typeof raw.format !== 'string') fail(`${at}.format must be a format name`);\n if (raw.display !== undefined) {\n if (!isObj(raw.display) || Object.keys(raw.display).length === 0\n || !Object.entries(raw.display).every(([k, v]) => (k === RELATED_DISPLAY_DEFAULT || COUNT_KEY.test(k)) && typeof v === 'string')) {\n fail(`${at}.display must map counts (or \"default\") to display text`);\n }\n }\n if (raw.splitBy !== undefined) {\n if (!isNonEmptyString(raw.splitBy)) fail(`${at}.splitBy must be a path`);\n const err = splitPathError(sets[name].source, raw.splitBy);\n if (err) fail(`${at}: ${err}`);\n }\n if (raw.labels !== undefined && (!isObj(raw.labels) || !Object.values(raw.labels).every((v) => typeof v === 'string'))) {\n fail(`${at}.labels must map values to display text`);\n }\n return raw as unknown as RelatedColumnDecl;\n}\n\nfunction readRowDetail(raw: unknown, sets: Record<string, RelatedSetDecl>): RowDetailSectionDecl[] {\n if (raw === undefined) return [];\n if (!Array.isArray(raw) || raw.length === 0 || raw.length > RELATED_LIMITS.MAX_ROW_DETAIL_SECTIONS) {\n fail(`x-lt-row-detail must be 1..${RELATED_LIMITS.MAX_ROW_DETAIL_SECTIONS} sections`);\n }\n return raw.map((section, i) => {\n const at = `x-lt-row-detail[${i}]`;\n if (!isObj(section)) fail(`${at} must be an object`);\n if (!isNonEmptyString(section.related) || !sets[section.related]) fail(`${at}.related must name a set declared in x-lt-related`);\n if (!Array.isArray(section.columns) || section.columns.length === 0) fail(`${at}.columns must list at least one column`);\n for (const [j, col] of section.columns.entries()) {\n if (!isObj(col) || !isNonEmptyString(col.label) || typeof col.value !== 'string') {\n fail(`${at}.columns[${j}] needs a label and a value template`);\n }\n }\n if (section.limit !== undefined && (!Number.isInteger(section.limit) || (section.limit as number) < 1\n || (section.limit as number) > RELATED_LIMITS.ROWS_MAX)) {\n fail(`${at}.limit must be 1..${RELATED_LIMITS.ROWS_MAX}`);\n }\n return section as unknown as RowDetailSectionDecl;\n });\n}\n\nfunction readGroupKey(schema: Obj): string | null {\n const raw = schema[LIST_SCHEMA_KEYS.GROUP_BY];\n if (raw === undefined || schema[LIST_SCHEMA_KEYS.LAYOUT] !== FACET_TABLE_LAYOUT) return null;\n const key = typeof raw === 'string' && raw.startsWith(SPLIT_PATHS.METADATA) ? raw.slice(SPLIT_PATHS.METADATA.length) : '';\n if (!METADATA_KEY.test(key)) fail('x-lt-group-by on a facet-table must be \"metadata.<key>\"');\n return key;\n}\n\nconst FOLDS = new Set<string>(Object.values(GROUP_FOLDS));\n\n/**\n * Validate and normalize the related declaration of a list schema. Throws on\n * an invalid declaration; keys outside this vocabulary stay opaque.\n */\nexport function readListSchemaRelations(schema: unknown): ListSchemaRelations {\n const empty: ListSchemaRelations = { sets: {}, columns: [], rowDetail: [], groupKey: null };\n if (!isObj(schema)) return empty;\n const rawSets = schema[LIST_SCHEMA_KEYS.RELATED];\n const sets: Record<string, RelatedSetDecl> = {};\n if (rawSets !== undefined) {\n if (!isObj(rawSets)) fail('x-lt-related must map set names to declarations');\n const names = Object.keys(rawSets);\n if (names.length === 0 || names.length > RELATED_LIMITS.MAX_SETS) fail(`x-lt-related must declare 1..${RELATED_LIMITS.MAX_SETS} sets`);\n for (const name of names) sets[name] = readSet(name, rawSets[name]);\n }\n const columns: RelatedColumnDecl[] = [];\n const rawColumns = schema[LIST_SCHEMA_KEYS.COLUMNS];\n if (Array.isArray(rawColumns)) {\n rawColumns.forEach((col, i) => {\n if (!isObj(col)) return;\n if (col.related !== undefined) columns.push(readRelatedColumn(col, sets, `x-lt-columns[${i}]`));\n if (col.group !== undefined && (typeof col.group !== 'string' || !FOLDS.has(col.group))) {\n fail(`x-lt-columns[${i}].group must be one of ${[...FOLDS].join(', ')}`);\n }\n });\n }\n return { sets, columns, rowDetail: readRowDetail(schema[LIST_SCHEMA_KEYS.ROW_DETAIL], sets), groupKey: readGroupKey(schema) };\n}\n\n/** The declaration's first error, or null when valid. */\nexport function listSchemaRelationsError(schema: unknown): string | null {\n try {\n readListSchemaRelations(schema);\n return null;\n } catch (err) {\n if (err instanceof ListSchemaError) return err.message;\n throw err;\n }\n}\n"],"names":["isEffectivelyClaimed","esc","isAckEscalation","identifierToTitle","id","w","escalationDotClass","e","STATUS_DOT_STYLES","rowContext","parse","s","v","IDENTITY_COLUMN_WIDTH","actionColumnWidth","label","DEFAULT_CLAIM_MINUTES","isClaimable","row","RowActionButton","def","onView","prominent","forceView","authored","action","claim","useClaimEscalation","navigate","useNavigate","location","useLocation","error","setError","useState","spent","fire","err","classes","jsxs","jsx","METADATA_TOKEN","isFacetValue","raw","rowRefinePairs","columnDefs","pairs","seen","metadata","col","bound","_a","key","RefineTrigger","onOpen","className","Search","LIST_SCHEMA_KEYS","RELATED_SOURCES","RELATED_AGGREGATES","GROUP_FOLDS","SPLIT_PATHS","RELATED_LIMITS","FACET_TABLE_LAYOUT","RELATED_DISPLAY_DEFAULT","VALUE_TOKEN","ITEM_PREFIX","PATH_SEGMENT","METADATA_KEY","COUNT_TOKEN","isExtremeAggregate","aggregate","relatedValuePath","source","value","token","path","relatedAggregateKey","relatedCountText","display","count","text","foldExtreme","fold","values","pickMin","texts","a","b","SET_NAME","COUNT_KEY","ListSchemaError","fail","message","isObj","isNonEmptyString","isPlainPath","splitPathError","splitBy","readSet","name","q","hasRoles","hasSegment","roles","readRelatedColumn","sets","at","k","readRowDetail","section","i","j","readGroupKey","schema","FOLDS","readListSchemaRelations","empty","rawSets","names","columns","rawColumns"],"mappings":"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"}
1
+ {"version":3,"file":"validate-CAin6WM_.js","sources":["../../src/lib/escalation.ts","../../src/lib/identifier-label.ts","../../src/components/escalation/list-view/row-parts.tsx","../../../shared/list-schema/types.ts","../../../shared/list-schema/aggregate.ts","../../../shared/list-schema/validate.ts"],"sourcesContent":["import type { LTEscalationRecord } from '../api/types';\n\nexport function isEffectivelyClaimed(esc: LTEscalationRecord): boolean {\n return !!(\n esc.assigned_to &&\n esc.assigned_until &&\n new Date(esc.assigned_until) > new Date()\n );\n}\n\n/** An ACK escalation has no associated workflow — it's a notification, not a task. */\nexport function isAckEscalation(esc: LTEscalationRecord): boolean {\n return !esc.workflow_type;\n}\n\nexport function isAvailable(esc: LTEscalationRecord): boolean {\n return (\n esc.status === 'pending' &&\n (!esc.assigned_to ||\n !esc.assigned_until ||\n new Date(esc.assigned_until) <= new Date())\n );\n}\n","/**\n * A human label for a code identifier: camelCase, snake_case, kebab-case, and\n * digit runs become Title Case words. `fleetTools` → `Fleet Tools`,\n * `print_order2` → `Print Order 2`. Acronyms keep their capitals: `mcpQuery`\n * → `Mcp Query` is avoided by treating an all-caps run as one word.\n */\nexport function identifierToTitle(id: string): string {\n const words = id\n .replace(/[_\\-.]+/g, ' ')\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/([a-zA-Z])(\\d)/g, '$1 $2')\n .trim()\n .split(/\\s+/)\n .filter(Boolean);\n return words\n .map((w) => (w === w.toUpperCase() && w.length > 1 ? w : w.charAt(0).toUpperCase() + w.slice(1)))\n .join(' ');\n}\n","import { useState } from 'react';\nimport { useNavigate, useLocation } from 'react-router-dom';\nimport { Search } from 'lucide-react';\nimport type { HelpTokenContext } from '../../../lib/x-lt-help';\nimport { STATUS_DOT_STYLES } from '../../common/display/StatusBadge';\nimport { useClaimEscalation } from '../../../api/escalations';\nimport { isEffectivelyClaimed } from '../../../lib/escalation';\nimport { identifierToTitle } from '../../../lib/identifier-label';\nimport type { RefinePair } from '../RefineDialog';\nimport type { LTEscalationRecord } from '../../../api/types';\n\n/** The row-level pieces every list layout shares: column and action\n * declarations, the row's token context, the row action, and refine. */\n\n/** Dot colour matches the standard table view: blue = pending unclaimed,\n * orange = under a live claim; other statuses follow the shared map. */\nexport function escalationDotClass(e: LTEscalationRecord): string {\n if (e.status === 'pending') {\n return isEffectivelyClaimed(e) ? 'bg-status-claimed-graphic' : 'bg-status-active';\n }\n return STATUS_DOT_STYLES[e.status] ?? 'bg-status-active';\n}\n\nexport interface ColumnDef {\n label: string;\n value: string;\n /** \"age\" renders an ISO timestamp as a compact age with an absolute tooltip. */\n format?: string;\n /**\n * Card-fold behavior when the table folds at narrow widths (same contract\n * as the engineer table): 1 = identity — always visible, forms the card's\n * title line; 2 = folds into the card body as a label/value pair; 3 =\n * dropped in card mode. Undeclared, the first column is the identity and\n * the rest fold.\n */\n priority?: 1 | 2 | 3;\n /** CSS column width (\"40%\", \"12rem\"). Unset columns share the remainder;\n * when no column declares one, the first column holds a fixed 200px so\n * the identity stays legible and every other value keeps its room. */\n width?: string;\n}\n\n/**\n * The per-row action button — the queue-working gesture, always available on\n * every layout. Template-driven: the schema author sets the action, its text,\n * and (for claim) the hold time.\n */\nexport interface RowActionDef {\n /** \"claim\" fires a one-click claim then opens the detail page already\n * claimed; \"view\" just opens it. Default \"claim\". */\n action?: 'claim' | 'view';\n /** Button text. Defaults \"Claim\" / \"View\" by action. */\n label?: string;\n /** Claim hold time in minutes. Default 30 (the platform claim default). */\n durationMinutes?: number;\n /**\n * Launch the detail page's claim-and-submit flow instead of a plain claim:\n * the row is claimed, the form's seeded defaults are resolved, and — when the\n * form declares `x-lt-transition` — the wait screen bridges to the born-assigned\n * follow-on. One list gesture (\"Start Harvesting\") starts the work and lands\n * the person on the next step. The behavior lives on the detail page (form\n * defaults, validation, transition); the list only points there with intent.\n */\n submitOnClaim?: boolean;\n}\n\n/** Build the token context for one escalation row (payloads are JSON strings). */\nexport function rowContext(e: LTEscalationRecord): HelpTokenContext {\n const parse = (s: string | null | undefined): Record<string, unknown> | null => {\n if (!s) return null;\n try {\n const v = JSON.parse(s);\n return v && typeof v === 'object' ? v : null;\n } catch {\n return null;\n }\n };\n return {\n escalation: e as unknown as Record<string, unknown>,\n metadata: e.metadata ?? null,\n envelope: parse(e.envelope),\n payload: parse(e.escalation_payload),\n resolver: parse(e.resolver_payload),\n };\n}\n\n/** The identity column's width when no column declares one: room for a label, no more. */\nexport const IDENTITY_COLUMN_WIDTH = '200px';\n\n/** The action column sizes to its label so the button never wraps or truncates. */\nexport function actionColumnWidth(label: string): string {\n return `${Math.max(6, Math.round(label.length * 0.55 + 3.5))}rem`;\n}\n\nconst DEFAULT_CLAIM_MINUTES = 30;\n\n/** Claim targets pending rows without a live claim window. */\nfunction isClaimable(row: LTEscalationRecord): boolean {\n return row.status === 'pending' && !isEffectivelyClaimed(row);\n}\n\n/**\n * The x-lt-row-action button. `claim` is one click: claim for the template's\n * duration, then open the detail page already claimed — the fast path for\n * working a queue. `view` opens the detail page. Persistent (light accent at\n * rest, saturating on hover); a rejected claim surfaces its message inline.\n */\nexport function RowActionButton({ row, def, onView, prominent, forceView }: {\n row: LTEscalationRecord;\n def?: RowActionDef;\n onView?: () => void;\n /** Hero treatment for the active-card CTA; default is the compact row button. */\n prominent?: boolean;\n /** Render claim templates as view actions (see EscalationListView). */\n forceView?: boolean;\n}) {\n const authored = def?.action ?? 'claim';\n const action = forceView ? 'view' : authored;\n // The authored label describes the authored gesture. When view is forced\n // over a claim template, claim wording would mislead — use the view default.\n const label = authored === action && def?.label\n ? def.label\n : action === 'claim' ? 'Claim' : 'View';\n const claim = useClaimEscalation();\n const navigate = useNavigate();\n const location = useLocation();\n const [error, setError] = useState('');\n\n // A spent gesture stays visible — the disabled button keeps every row's\n // layout uniform instead of leaving a hole on resolved/held rows.\n const spent = action === 'claim' && !isClaimable(row);\n\n const fire = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (action === 'view') {\n onView?.();\n return;\n }\n // Launch the detail page's claim → submit → transition flow. The detail\n // page owns the heavy lifting (seed defaults, validate, resolve, hand-off);\n // the list points there with the intent and the authored claim duration.\n if (def?.submitOnClaim) {\n navigate(`/escalations/detail/${row.id}`, {\n state: { autoStart: true, durationMinutes: def?.durationMinutes, from: location.pathname },\n });\n return;\n }\n setError('');\n claim.mutate(\n { id: row.id, durationMinutes: def?.durationMinutes ?? DEFAULT_CLAIM_MINUTES },\n {\n onSuccess: () => onView?.(),\n onError: (err) => setError((err as Error).message),\n },\n );\n };\n\n const classes = prominent\n ? 'btn-primary text-xs shrink-0 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent'\n : 'px-2 py-0.5 rounded text-2xs font-medium text-accent/70 border border-accent/30 enabled:hover:text-accent enabled:hover:border-accent/60 enabled:hover:bg-accent/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap';\n\n return (\n <span className=\"inline-flex flex-col items-end gap-0.5\">\n <button\n type=\"button\"\n onClick={fire}\n disabled={claim.isPending || spent}\n title={spent ? (row.status === 'pending' ? 'claimed' : row.status) : undefined}\n className={classes}\n data-testid=\"row-action-button\"\n >\n {claim.isPending ? 'Claiming…' : label}\n </button>\n {error && <span className=\"text-2xs text-status-error\" data-testid=\"row-action-error\">{error}</span>}\n </span>\n );\n}\n\n/** A field value token that is a pure metadata binding — facet-linkable. */\nexport const METADATA_TOKEN = /^\\{\\{\\s*metadata\\.([a-zA-Z0-9_]+)\\s*\\}\\}$/;\n\n/** A metadata value the faceted query can match on: a scalar with something in it. */\nfunction isFacetValue(raw: unknown): raw is string | number | boolean {\n return (typeof raw === 'string' && raw !== '') || typeof raw === 'number' || typeof raw === 'boolean';\n}\n\n/**\n * The refinable facts one row offers: every metadata facet the row carries.\n * Columns the author bound to a metadata value lead, under their authored\n * labels; every other scalar facet follows under a label derived from its\n * key, so the dialog reaches the whole record, not only what the columns\n * show. Feeds the row's RefineDialog.\n */\nexport function rowRefinePairs(row: LTEscalationRecord, columnDefs: ColumnDef[]): RefinePair[] {\n const pairs: RefinePair[] = [];\n const seen = new Set<string>();\n const metadata = row.metadata ?? {};\n for (const col of columnDefs) {\n const bound = typeof col.value === 'string' ? col.value.match(METADATA_TOKEN)?.[1] : undefined;\n if (!bound || seen.has(bound)) continue;\n const raw = metadata[bound];\n if (!isFacetValue(raw)) continue;\n seen.add(bound);\n pairs.push({ key: bound, label: col.label, value: raw, bound: true });\n }\n for (const [key, raw] of Object.entries(metadata)) {\n if (seen.has(key) || !isFacetValue(raw)) continue;\n seen.add(key);\n pairs.push({ key, label: identifierToTitle(key), value: raw });\n }\n return pairs;\n}\n\n/** The always-tappable row/card refine trigger — one magnifier, dialog behind it. */\nexport function RefineTrigger({ onOpen, className = '' }: { onOpen: () => void; className?: string }) {\n return (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); onOpen(); }}\n className={`p-1.5 rounded text-text-quaternary/70 hover:text-accent hover:bg-surface-hover transition-colors ${className}`}\n title=\"Refine — filter or search by this row's values\"\n aria-label=\"Refine — filter or search by this row's values\"\n data-testid=\"row-refine\"\n >\n <Search className=\"w-3.5 h-3.5\" strokeWidth={1.5} />\n </button>\n );\n}\n","/**\n * Related sets on a role's list schema. A set is named once under\n * `x-lt-related`; columns (`related`) and row details (`x-lt-row-detail`)\n * reference it by name. The server reads the declaration from the stored\n * list schema, never from the caller.\n *\n * items the host row's accumulated or batch items, each read through its\n * payload or its reciprocal row\n * query rows in other roles that share facets with the host row; facet\n * values are `{{domain.path}}` templates over the host row\n */\n\nexport const LIST_SCHEMA_KEYS = {\n RELATED: 'x-lt-related',\n COLUMNS: 'x-lt-columns',\n ROW_DETAIL: 'x-lt-row-detail',\n GROUP_BY: 'x-lt-group-by',\n LAYOUT: 'x-lt-layout',\n} as const;\n\nexport const RELATED_SOURCES = {\n ITEMS: 'items',\n QUERY: 'query',\n} as const;\nexport type RelatedSource = (typeof RELATED_SOURCES)[keyof typeof RELATED_SOURCES];\n\nexport const RELATED_AGGREGATES = {\n COUNT: 'count',\n /** The least item or row value: numbers as numbers, everything else as text. */\n MIN: 'min',\n MAX: 'max',\n} as const;\nexport type RelatedAggregate = (typeof RELATED_AGGREGATES)[keyof typeof RELATED_AGGREGATES];\n\n/** How a grouped table folds a plain column across a group's rows. */\nexport const GROUP_FOLDS = {\n FIRST: 'first',\n MIN: 'min',\n MAX: 'max',\n SUM: 'sum',\n COUNT: 'count',\n /** The distinct values, in row order, joined: \"standard, express\". */\n DISTINCT: 'distinct',\n} as const;\nexport type GroupFold = (typeof GROUP_FOLDS)[keyof typeof GROUP_FOLDS];\n\n/** Split prefixes. `role` splits a query set by the related row's role. */\nexport const SPLIT_PATHS = {\n ROLE: 'role',\n METADATA: 'metadata.',\n PAYLOAD: 'payload.',\n RECIPROCAL_METADATA: 'reciprocal.metadata.',\n} as const;\n\nexport const RELATED_LIMITS = {\n MAX_SETS: 4,\n MAX_QUERY_ROLES: 12,\n MAX_ROW_DETAIL_SECTIONS: 4,\n MAX_HOSTS: 100,\n ROWS_DEFAULT: 25,\n ROWS_MAX: 100,\n} as const;\n\n/** The table layout that renders related columns, row details, and groups. */\nexport const FACET_TABLE_LAYOUT = 'facet-table';\n\nexport interface RelatedQueryDecl {\n /** Related roles, in display order. Exclusive with `segment`. */\n roles?: string[];\n /** A Pace Board sequence by its first role; resolves to the ordered chain. */\n segment?: string;\n /** Facet containment; string values may be `{{domain.path}}` templates. */\n facets?: Record<string, unknown>;\n /**\n * Facets that narrow the match when the host row carries a value, and\n * drop away when it does not: a lane narrows its tub's look-ahead to its\n * own service level, a tub without lanes keeps the whole destination.\n */\n narrow?: Record<string, unknown>;\n /** Default `pending`. */\n status?: string;\n}\n\nexport interface RelatedSetDecl {\n source: RelatedSource;\n query?: RelatedQueryDecl;\n}\n\n/** A count column's text keyed by count; `default` covers the rest, `{n}` reads the count. */\nexport const RELATED_DISPLAY_DEFAULT = 'default';\n\nexport interface RelatedColumnDecl {\n label: string;\n related: string;\n aggregate?: RelatedAggregate;\n /** min/max: `{{item.payload.<path>}}` on an items set, `{{metadata.<key>}}` on a query set. */\n value?: string;\n /** min/max: how the value renders, as on any facet-table column. */\n format?: string;\n /** count: text by count, e.g. `{ \"0\": \"Ready\", \"default\": \"Waiting on {n}\" }`. */\n display?: Record<string, string>;\n splitBy?: string;\n labels?: Record<string, string>;\n priority?: 1 | 2 | 3;\n /** CSS width, as on any facet-table column. */\n width?: string;\n}\n\nexport interface RowDetailColumnDecl {\n label: string;\n value: string;\n format?: string;\n priority?: 1 | 2 | 3;\n}\n\nexport interface RowDetailSectionDecl {\n related: string;\n label?: string;\n columns: RowDetailColumnDecl[];\n limit?: number;\n}\n\n/** The validated, normalized related declaration of one list schema. */\nexport interface ListSchemaRelations {\n sets: Record<string, RelatedSetDecl>;\n columns: RelatedColumnDecl[];\n rowDetail: RowDetailSectionDecl[];\n /** The metadata key a facet-table groups by, when declared. */\n groupKey: string | null;\n}\n\n/** Per-host aggregate for one (set, splitBy) pair, or one (set, min/max, value) triple. */\nexport interface RelatedHostAggregate {\n count: number;\n /** min/max: the extreme value among `count` values; absent when none carries one. */\n value?: string | number;\n /** Split value to count; a null value is keyed by the empty string. */\n splits?: Record<string, number>;\n /** Items whose reciprocal row the viewer cannot read. */\n hidden?: number;\n /** A host whose facet templates resolved to nothing; the set did not run. */\n unresolved?: boolean;\n}\n\nexport interface RelatedSetResult {\n source: RelatedSource;\n /**\n * The roles whose rows the set reads, which a list follows for live\n * changes: a query set's resolved roles in order, or the roles of an item\n * set's readable reciprocal rows when a column splits by them.\n */\n roles?: string[];\n /** Query sets: role titles, keyed by role. */\n roleLabels?: Record<string, string>;\n /** Query sets: declared roles outside the viewer's full read scope. */\n restricted?: string[];\n /** Keyed by relatedAggregateKey (the splitBy, '' when unsplit, or `min:<path>`), then host id. */\n aggregates: Record<string, Record<string, RelatedHostAggregate>>;\n}\n\nexport interface RelatedAggregatesResponse {\n version: number | null;\n sets: Record<string, RelatedSetResult>;\n}\n\nexport interface RelatedItemEntry {\n itemKey: string;\n payload?: unknown;\n at?: string;\n actor?: string;\n reciprocalId?: string;\n}\n\nexport interface RelatedRow {\n /** Items sets only. */\n item?: RelatedItemEntry;\n /** The reciprocal row (items) or the related row (query); null when unreadable. */\n escalation: Record<string, unknown> | null;\n}\n\nexport interface RelatedRowsResponse {\n source: RelatedSource;\n rows: RelatedRow[];\n total: number;\n restricted?: string[];\n roleLabels?: Record<string, string>;\n}\n","import {\n RELATED_AGGREGATES,\n RELATED_DISPLAY_DEFAULT,\n RELATED_SOURCES,\n SPLIT_PATHS,\n type RelatedAggregate,\n type RelatedColumnDecl,\n} from './types';\n\nconst VALUE_TOKEN = /^\\{\\{\\s*([^{}]+?)\\s*\\}\\}$/;\nconst ITEM_PREFIX = 'item.';\nconst PATH_SEGMENT = /^[a-zA-Z0-9_]+$/;\nconst METADATA_KEY = /^[a-zA-Z0-9_]+$/;\nconst COUNT_TOKEN = /\\{n\\}/g;\n\nexport type RelatedExtreme = typeof RELATED_AGGREGATES.MIN | typeof RELATED_AGGREGATES.MAX;\n\n/** True for the aggregates that pick one value rather than count. */\nexport function isExtremeAggregate(aggregate: unknown): aggregate is RelatedExtreme {\n return aggregate === RELATED_AGGREGATES.MIN || aggregate === RELATED_AGGREGATES.MAX;\n}\n\n/**\n * The stored path a min/max `value` template reads: `payload.<path>` for an\n * items set, `metadata.<key>` for a query set. Null when the template does\n * not fit the set's source.\n */\nexport function relatedValuePath(source: string, value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const token = value.match(VALUE_TOKEN)?.[1];\n if (!token) return null;\n if (source === RELATED_SOURCES.ITEMS) {\n if (!token.startsWith(`${ITEM_PREFIX}${SPLIT_PATHS.PAYLOAD}`)) return null;\n const path = token.slice(ITEM_PREFIX.length + SPLIT_PATHS.PAYLOAD.length);\n return path && path.split('.').every((s) => PATH_SEGMENT.test(s)) ? `${SPLIT_PATHS.PAYLOAD}${path}` : null;\n }\n if (!token.startsWith(SPLIT_PATHS.METADATA)) return null;\n const key = token.slice(SPLIT_PATHS.METADATA.length);\n return METADATA_KEY.test(key) ? token : null;\n}\n\n/** The key a column's per-host aggregates are stored under in its set's result. */\nexport function relatedAggregateKey(col: Pick<RelatedColumnDecl, 'aggregate' | 'splitBy' | 'value'>, source: string): string {\n if (isExtremeAggregate(col.aggregate)) return `${col.aggregate}:${relatedValuePath(source, col.value) ?? ''}`;\n return col.splitBy ?? '';\n}\n\n/** A count column's display text, or null when the column declares none for this count. */\nexport function relatedCountText(display: Record<string, string> | undefined, count: number): string | null {\n if (!display) return null;\n const text = display[String(count)] ?? display[RELATED_DISPLAY_DEFAULT];\n return text === undefined ? null : text.replace(COUNT_TOKEN, String(count));\n}\n\n/**\n * The least or greatest of several values: numbers when every value is a\n * number, otherwise text in code-unit order (ISO instants order as text).\n */\nexport function foldExtreme(fold: RelatedAggregate, values: Array<string | number>): string | number | undefined {\n if (!values.length) return undefined;\n const pickMin = fold === RELATED_AGGREGATES.MIN;\n if (values.every((v) => typeof v === 'number')) {\n return pickMin ? Math.min(...(values as number[])) : Math.max(...(values as number[]));\n }\n const texts = values.map(String).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n return pickMin ? texts[0] : texts[texts.length - 1];\n}\n","import {\n FACET_TABLE_LAYOUT,\n GROUP_FOLDS,\n LIST_SCHEMA_KEYS,\n RELATED_AGGREGATES,\n RELATED_DISPLAY_DEFAULT,\n RELATED_LIMITS,\n RELATED_SOURCES,\n SPLIT_PATHS,\n type ListSchemaRelations,\n type RelatedColumnDecl,\n type RelatedSetDecl,\n type RowDetailSectionDecl,\n} from './types';\nimport { isExtremeAggregate, relatedValuePath } from './aggregate';\n\n/** A metadata key: interpolated as a JSON path, so strictly validated. */\nexport const METADATA_KEY = /^[a-zA-Z0-9_]+$/;\nconst SET_NAME = /^[a-zA-Z][a-zA-Z0-9_-]{0,47}$/;\nconst PATH_SEGMENT = /^[a-zA-Z0-9_]+$/;\nconst COUNT_KEY = /^(0|[1-9][0-9]*)$/;\n\ntype Obj = Record<string, unknown>;\n\nclass ListSchemaError extends Error {}\n\nfunction fail(message: string): never {\n throw new ListSchemaError(message);\n}\n\nfunction isObj(value: unknown): value is Obj {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\n/** True when a dotted path has only plain segments. */\nfunction isPlainPath(path: string): boolean {\n return path.length > 0 && path.split('.').every((s) => PATH_SEGMENT.test(s));\n}\n\n/** The split paths a set's source accepts. */\nexport function splitPathError(source: string, splitBy: string): string | null {\n if (source === RELATED_SOURCES.QUERY) {\n if (splitBy === SPLIT_PATHS.ROLE) return null;\n if (splitBy.startsWith(SPLIT_PATHS.METADATA) && METADATA_KEY.test(splitBy.slice(SPLIT_PATHS.METADATA.length))) return null;\n return `splitBy \"${splitBy}\" on a query set must be \"role\" or \"metadata.<key>\"`;\n }\n if (splitBy.startsWith(SPLIT_PATHS.PAYLOAD) && isPlainPath(splitBy.slice(SPLIT_PATHS.PAYLOAD.length))) return null;\n if (splitBy.startsWith(SPLIT_PATHS.RECIPROCAL_METADATA)\n && METADATA_KEY.test(splitBy.slice(SPLIT_PATHS.RECIPROCAL_METADATA.length))) return null;\n return `splitBy \"${splitBy}\" on an items set must be \"payload.<path>\" or \"reciprocal.metadata.<key>\"`;\n}\n\nfunction readSet(name: string, raw: unknown): RelatedSetDecl {\n if (!SET_NAME.test(name)) fail(`x-lt-related name \"${name}\" must start with a letter (letters, digits, _ or -)`);\n if (!isObj(raw)) fail(`x-lt-related.${name} must be an object`);\n if (raw.source === RELATED_SOURCES.ITEMS) {\n if (raw.query !== undefined) fail(`x-lt-related.${name}: an items set takes no query`);\n return { source: RELATED_SOURCES.ITEMS };\n }\n if (raw.source !== RELATED_SOURCES.QUERY) fail(`x-lt-related.${name}.source must be \"items\" or \"query\"`);\n const q = raw.query;\n if (!isObj(q)) fail(`x-lt-related.${name}.query is required for a query set`);\n const hasRoles = q.roles !== undefined;\n const hasSegment = q.segment !== undefined;\n if (hasRoles === hasSegment) fail(`x-lt-related.${name}.query takes exactly one of roles or segment`);\n if (hasRoles) {\n const roles = q.roles;\n if (!Array.isArray(roles) || roles.length === 0 || roles.length > RELATED_LIMITS.MAX_QUERY_ROLES\n || !roles.every(isNonEmptyString)) {\n fail(`x-lt-related.${name}.query.roles must be 1..${RELATED_LIMITS.MAX_QUERY_ROLES} role names`);\n }\n } else if (!isNonEmptyString(q.segment)) {\n fail(`x-lt-related.${name}.query.segment must be a role name`);\n }\n if (!isObj(q.facets) || Object.keys(q.facets).length === 0) {\n fail(`x-lt-related.${name}.query.facets must name at least one facet`);\n }\n for (const [key, value] of Object.entries(q.facets)) {\n if (!METADATA_KEY.test(key)) fail(`x-lt-related.${name}.query.facets key \"${key}\" must be letters, digits or _`);\n if (value === null || typeof value === 'object') fail(`x-lt-related.${name}.query.facets.${key} must be a scalar or template`);\n }\n if (q.narrow !== undefined) {\n if (!isObj(q.narrow) || Object.keys(q.narrow).length === 0) fail(`x-lt-related.${name}.query.narrow must name at least one facet`);\n for (const [key, value] of Object.entries(q.narrow)) {\n if (!METADATA_KEY.test(key)) fail(`x-lt-related.${name}.query.narrow key \"${key}\" must be letters, digits or _`);\n if (key in q.facets) fail(`x-lt-related.${name}.query.narrow.${key} is already a required facet`);\n if (value === null || typeof value === 'object') fail(`x-lt-related.${name}.query.narrow.${key} must be a scalar or template`);\n }\n }\n if (q.status !== undefined && !isNonEmptyString(q.status)) fail(`x-lt-related.${name}.query.status must be a status`);\n return {\n source: RELATED_SOURCES.QUERY,\n query: {\n ...(hasRoles ? { roles: [...(q.roles as string[])] } : { segment: q.segment as string }),\n facets: { ...q.facets },\n ...(q.narrow !== undefined ? { narrow: { ...(q.narrow as Obj) } } : {}),\n ...(q.status !== undefined ? { status: q.status as string } : {}),\n },\n };\n}\n\nfunction readRelatedColumn(raw: Obj, sets: Record<string, RelatedSetDecl>, at: string): RelatedColumnDecl {\n const name = raw.related;\n if (!isNonEmptyString(name) || !sets[name]) fail(`${at}.related must name a set declared in x-lt-related`);\n if (raw.aggregate !== undefined && raw.aggregate !== RELATED_AGGREGATES.COUNT && !isExtremeAggregate(raw.aggregate)) {\n fail(`${at}.aggregate must be \"count\", \"min\" or \"max\"`);\n }\n const source = sets[name].source;\n if (isExtremeAggregate(raw.aggregate)) {\n if (!relatedValuePath(source, raw.value)) {\n fail(source === RELATED_SOURCES.ITEMS\n ? `${at}.value must be \"{{item.payload.<path>}}\" on an items set`\n : `${at}.value must be \"{{metadata.<key>}}\" on a query set`);\n }\n if (raw.splitBy !== undefined) fail(`${at}: a ${raw.aggregate} column takes no splitBy`);\n if (raw.display !== undefined) fail(`${at}: display applies to a count column`);\n } else if (raw.value !== undefined) {\n fail(`${at}.value applies to a min or max column`);\n }\n if (raw.format !== undefined && typeof raw.format !== 'string') fail(`${at}.format must be a format name`);\n if (raw.display !== undefined) {\n if (!isObj(raw.display) || Object.keys(raw.display).length === 0\n || !Object.entries(raw.display).every(([k, v]) => (k === RELATED_DISPLAY_DEFAULT || COUNT_KEY.test(k)) && typeof v === 'string')) {\n fail(`${at}.display must map counts (or \"default\") to display text`);\n }\n }\n if (raw.splitBy !== undefined) {\n if (!isNonEmptyString(raw.splitBy)) fail(`${at}.splitBy must be a path`);\n const err = splitPathError(sets[name].source, raw.splitBy);\n if (err) fail(`${at}: ${err}`);\n }\n if (raw.labels !== undefined && (!isObj(raw.labels) || !Object.values(raw.labels).every((v) => typeof v === 'string'))) {\n fail(`${at}.labels must map values to display text`);\n }\n return raw as unknown as RelatedColumnDecl;\n}\n\nfunction readRowDetail(raw: unknown, sets: Record<string, RelatedSetDecl>): RowDetailSectionDecl[] {\n if (raw === undefined) return [];\n if (!Array.isArray(raw) || raw.length === 0 || raw.length > RELATED_LIMITS.MAX_ROW_DETAIL_SECTIONS) {\n fail(`x-lt-row-detail must be 1..${RELATED_LIMITS.MAX_ROW_DETAIL_SECTIONS} sections`);\n }\n return raw.map((section, i) => {\n const at = `x-lt-row-detail[${i}]`;\n if (!isObj(section)) fail(`${at} must be an object`);\n if (!isNonEmptyString(section.related) || !sets[section.related]) fail(`${at}.related must name a set declared in x-lt-related`);\n if (!Array.isArray(section.columns) || section.columns.length === 0) fail(`${at}.columns must list at least one column`);\n for (const [j, col] of section.columns.entries()) {\n if (!isObj(col) || !isNonEmptyString(col.label) || typeof col.value !== 'string') {\n fail(`${at}.columns[${j}] needs a label and a value template`);\n }\n }\n if (section.limit !== undefined && (!Number.isInteger(section.limit) || (section.limit as number) < 1\n || (section.limit as number) > RELATED_LIMITS.ROWS_MAX)) {\n fail(`${at}.limit must be 1..${RELATED_LIMITS.ROWS_MAX}`);\n }\n return section as unknown as RowDetailSectionDecl;\n });\n}\n\nfunction readGroupKey(schema: Obj): string | null {\n const raw = schema[LIST_SCHEMA_KEYS.GROUP_BY];\n if (raw === undefined || schema[LIST_SCHEMA_KEYS.LAYOUT] !== FACET_TABLE_LAYOUT) return null;\n const key = typeof raw === 'string' && raw.startsWith(SPLIT_PATHS.METADATA) ? raw.slice(SPLIT_PATHS.METADATA.length) : '';\n if (!METADATA_KEY.test(key)) fail('x-lt-group-by on a facet-table must be \"metadata.<key>\"');\n return key;\n}\n\nconst FOLDS = new Set<string>(Object.values(GROUP_FOLDS));\n\n/**\n * Validate and normalize the related declaration of a list schema. Throws on\n * an invalid declaration; keys outside this vocabulary stay opaque.\n */\nexport function readListSchemaRelations(schema: unknown): ListSchemaRelations {\n const empty: ListSchemaRelations = { sets: {}, columns: [], rowDetail: [], groupKey: null };\n if (!isObj(schema)) return empty;\n const rawSets = schema[LIST_SCHEMA_KEYS.RELATED];\n const sets: Record<string, RelatedSetDecl> = {};\n if (rawSets !== undefined) {\n if (!isObj(rawSets)) fail('x-lt-related must map set names to declarations');\n const names = Object.keys(rawSets);\n if (names.length === 0 || names.length > RELATED_LIMITS.MAX_SETS) fail(`x-lt-related must declare 1..${RELATED_LIMITS.MAX_SETS} sets`);\n for (const name of names) sets[name] = readSet(name, rawSets[name]);\n }\n const columns: RelatedColumnDecl[] = [];\n const rawColumns = schema[LIST_SCHEMA_KEYS.COLUMNS];\n if (Array.isArray(rawColumns)) {\n rawColumns.forEach((col, i) => {\n if (!isObj(col)) return;\n if (col.related !== undefined) columns.push(readRelatedColumn(col, sets, `x-lt-columns[${i}]`));\n if (col.group !== undefined && (typeof col.group !== 'string' || !FOLDS.has(col.group))) {\n fail(`x-lt-columns[${i}].group must be one of ${[...FOLDS].join(', ')}`);\n }\n });\n }\n return { sets, columns, rowDetail: readRowDetail(schema[LIST_SCHEMA_KEYS.ROW_DETAIL], sets), groupKey: readGroupKey(schema) };\n}\n\n/** The declaration's first error, or null when valid. */\nexport function listSchemaRelationsError(schema: unknown): string | null {\n try {\n readListSchemaRelations(schema);\n return null;\n } catch (err) {\n if (err instanceof ListSchemaError) return err.message;\n throw err;\n }\n}\n"],"names":["isEffectivelyClaimed","esc","isAckEscalation","identifierToTitle","id","w","escalationDotClass","e","STATUS_DOT_STYLES","rowContext","parse","s","v","IDENTITY_COLUMN_WIDTH","actionColumnWidth","label","DEFAULT_CLAIM_MINUTES","isClaimable","row","RowActionButton","def","onView","prominent","forceView","authored","action","claim","useClaimEscalation","navigate","useNavigate","location","useLocation","error","setError","useState","spent","fire","err","classes","jsxs","jsx","METADATA_TOKEN","isFacetValue","raw","rowRefinePairs","columnDefs","pairs","seen","metadata","col","bound","_a","key","RefineTrigger","onOpen","className","Search","LIST_SCHEMA_KEYS","RELATED_SOURCES","RELATED_AGGREGATES","GROUP_FOLDS","SPLIT_PATHS","RELATED_LIMITS","FACET_TABLE_LAYOUT","RELATED_DISPLAY_DEFAULT","VALUE_TOKEN","ITEM_PREFIX","PATH_SEGMENT","METADATA_KEY","COUNT_TOKEN","isExtremeAggregate","aggregate","relatedValuePath","source","value","token","path","relatedAggregateKey","relatedCountText","display","count","text","foldExtreme","fold","values","pickMin","texts","a","b","SET_NAME","COUNT_KEY","ListSchemaError","fail","message","isObj","isNonEmptyString","isPlainPath","splitPathError","splitBy","readSet","name","q","hasRoles","hasSegment","roles","readRelatedColumn","sets","at","k","readRowDetail","section","i","j","readGroupKey","schema","FOLDS","readListSchemaRelations","empty","rawSets","names","columns","rawColumns"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{u as l,b as a,c as s}from"./vendor-query-DvWWuNIB.js";import{m as r}from"./index-xycFf66M.js";function f(e={}){const o=new URLSearchParams;return e.status&&o.set("status",e.status),e.graph_topic&&o.set("graph_topic",e.graph_topic),e.app_id&&o.set("app_id",e.app_id),e.search&&o.set("search",e.search),e.set_id&&o.set("set_id",e.set_id),e.limit&&o.set("limit",String(e.limit)),e.offset!==void 0&&o.set("offset",String(e.offset)),l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows?${o}`)})}function m(){return l({queryKey:["yamlWorkflowAppIds"],queryFn:()=>r("/yaml-workflows/app-ids")})}function c(e){return l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows/${e}`),enabled:!!e})}function w(){const e=a();return s({mutationFn:o=>r("/yaml-workflows",{method:"POST",body:JSON.stringify(o)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function k(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/deploy`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function p(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/activate`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function d(){const e=a();return s({mutationFn:({id:o,data:t,sync:n,execute_as:u})=>r(`/yaml-workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:t,sync:n,...u?{execute_as:u}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function h(){const e=a();return s({mutationFn:({id:o,task_queue:t,compilation_feedback:n})=>r(`/yaml-workflows/${o}/regenerate`,{method:"POST",body:JSON.stringify({task_queue:t,compilation_feedback:n})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function q(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/archive`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function W(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/restore`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"}),e.invalidateQueries({queryKey:["yamlWorkflow"],refetchType:"all"})}})}function S(){const e=a();return s({mutationFn:({id:o,...t})=>r(`/yaml-workflows/${o}`,{method:"PUT",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function v(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function T(e){return l({queryKey:["yamlWorkflows",e,"versions"],queryFn:()=>r(`/yaml-workflows/${e}/versions`),enabled:!!e})}function F(e,o){return l({queryKey:["yamlWorkflows",e,"versions",o],queryFn:()=>r(`/yaml-workflows/${e}/versions/${o}`),enabled:!!e&&o!==null})}export{m as a,S as b,c,T as d,k as e,p as f,q as g,W as h,v as i,h as j,F as k,d as l,w as m,f as u};
2
- //# sourceMappingURL=yaml-workflows-S7qlgdg6.js.map
1
+ import{u as l,b as a,c as s}from"./vendor-query-DvWWuNIB.js";import{m as r}from"./index-ygxyAKcc.js";function f(e={}){const o=new URLSearchParams;return e.status&&o.set("status",e.status),e.graph_topic&&o.set("graph_topic",e.graph_topic),e.app_id&&o.set("app_id",e.app_id),e.search&&o.set("search",e.search),e.set_id&&o.set("set_id",e.set_id),e.limit&&o.set("limit",String(e.limit)),e.offset!==void 0&&o.set("offset",String(e.offset)),l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows?${o}`)})}function m(){return l({queryKey:["yamlWorkflowAppIds"],queryFn:()=>r("/yaml-workflows/app-ids")})}function c(e){return l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows/${e}`),enabled:!!e})}function w(){const e=a();return s({mutationFn:o=>r("/yaml-workflows",{method:"POST",body:JSON.stringify(o)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function k(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/deploy`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function p(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/activate`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function d(){const e=a();return s({mutationFn:({id:o,data:t,sync:n,execute_as:u})=>r(`/yaml-workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:t,sync:n,...u?{execute_as:u}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function h(){const e=a();return s({mutationFn:({id:o,task_queue:t,compilation_feedback:n})=>r(`/yaml-workflows/${o}/regenerate`,{method:"POST",body:JSON.stringify({task_queue:t,compilation_feedback:n})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function q(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/archive`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function W(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/restore`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"}),e.invalidateQueries({queryKey:["yamlWorkflow"],refetchType:"all"})}})}function S(){const e=a();return s({mutationFn:({id:o,...t})=>r(`/yaml-workflows/${o}`,{method:"PUT",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function v(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function T(e){return l({queryKey:["yamlWorkflows",e,"versions"],queryFn:()=>r(`/yaml-workflows/${e}/versions`),enabled:!!e})}function F(e,o){return l({queryKey:["yamlWorkflows",e,"versions",o],queryFn:()=>r(`/yaml-workflows/${e}/versions/${o}`),enabled:!!e&&o!==null})}export{m as a,S as b,c,T as d,k as e,p as f,q as g,W as h,v as i,h as j,F as k,d as l,w as m,f as u};
2
+ //# sourceMappingURL=yaml-workflows-Dyln3od-.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"yaml-workflows-S7qlgdg6.js","sources":["../../src/api/yaml-workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { LTYamlWorkflowRecord, LTYamlWorkflowStatus, LTYamlWorkflowVersion } from './types';\n\ninterface YamlWorkflowListResponse {\n workflows: LTYamlWorkflowRecord[];\n total: number;\n}\n\ninterface YamlWorkflowFilters {\n status?: LTYamlWorkflowStatus;\n graph_topic?: string;\n app_id?: string;\n search?: string;\n set_id?: string;\n limit?: number;\n offset?: number;\n}\n\nexport function useYamlWorkflows(filters: YamlWorkflowFilters = {}) {\n const params = new URLSearchParams();\n if (filters.status) params.set('status', filters.status);\n if (filters.graph_topic) params.set('graph_topic', filters.graph_topic);\n if (filters.app_id) params.set('app_id', filters.app_id);\n if (filters.search) params.set('search', filters.search);\n if (filters.set_id) params.set('set_id', filters.set_id);\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', filters],\n queryFn: () => apiFetch(`/yaml-workflows?${params}`),\n });\n}\n\nexport function useYamlWorkflowAppIds() {\n return useQuery<{ app_ids: string[] }>({\n queryKey: ['yamlWorkflowAppIds'],\n queryFn: () => apiFetch('/yaml-workflows/app-ids'),\n });\n}\n\nexport function useYamlWorkflowByTopic(graphTopic: string | undefined, appId?: string) {\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', 'byTopic', graphTopic, appId],\n queryFn: () => {\n const params = new URLSearchParams({ graph_topic: graphTopic!, limit: '1' });\n if (appId) params.set('app_id', appId);\n return apiFetch(`/yaml-workflows?${params}`);\n },\n enabled: !!graphTopic,\n });\n}\n\nexport function useYamlWorkflow(id: string) {\n return useQuery<LTYamlWorkflowRecord>({\n queryKey: ['yamlWorkflows', id],\n queryFn: () => apiFetch(`/yaml-workflows/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useCreateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (input: {\n workflow_id: string;\n task_queue: string;\n workflow_name: string;\n name: string;\n description?: string;\n app_id?: string;\n subscribes?: string;\n tags?: string[];\n compilation_feedback?: string;\n }) =>\n apiFetch<LTYamlWorkflowRecord>('/yaml-workflows', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeployYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/deploy`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useActivateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/activate`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, data, sync, execute_as }: { id: string; data: Record<string, unknown>; sync?: boolean; execute_as?: string }) =>\n apiFetch<{ result?: unknown; job_id?: string }>(`/yaml-workflows/${id}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, sync, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRegenerateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, task_queue, compilation_feedback }: { id: string; task_queue?: string; compilation_feedback?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/regenerate`, {\n method: 'POST',\n body: JSON.stringify({ task_queue, compilation_feedback }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useArchiveYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/archive`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRestoreYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/restore`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflow'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpdateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...updates }: { id: string; yaml_content?: string; name?: string; description?: string; input_schema?: Record<string, unknown>; output_schema?: Record<string, unknown>; tags?: string[]; app_id?: string; graph_topic?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify(updates),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ deleted: boolean }>(`/yaml-workflows/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Cron scheduling ─────────────────────────────────────────────\n\nexport function useSetYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, cron_schedule, cron_envelope, execute_as }: {\n id: string;\n cron_schedule: string;\n cron_envelope?: Record<string, unknown> | null;\n execute_as?: string | null;\n }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'PUT',\n body: JSON.stringify({ cron_schedule, cron_envelope, execute_as }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useClearYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Version history ─────────────────────────────────────────────\n\nexport function useYamlWorkflowVersions(id: string) {\n return useQuery<{ versions: LTYamlWorkflowVersion[]; total: number }>({\n queryKey: ['yamlWorkflows', id, 'versions'],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions`),\n enabled: !!id,\n });\n}\n\nexport function useYamlWorkflowVersion(id: string, version: number | null) {\n return useQuery<LTYamlWorkflowVersion>({\n queryKey: ['yamlWorkflows', id, 'versions', version],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions/${version}`),\n enabled: !!id && version !== null,\n });\n}\n"],"names":["useYamlWorkflows","filters","params","useQuery","apiFetch","useYamlWorkflowAppIds","useYamlWorkflow","id","useCreateYamlWorkflow","queryClient","useQueryClient","useMutation","input","useDeployYamlWorkflow","useActivateYamlWorkflow","useInvokeYamlWorkflow","data","sync","execute_as","useRegenerateYamlWorkflow","task_queue","compilation_feedback","useArchiveYamlWorkflow","useRestoreYamlWorkflow","useUpdateYamlWorkflow","updates","useDeleteYamlWorkflow","useYamlWorkflowVersions","useYamlWorkflowVersion","version"],"mappings":"qGAmBO,SAASA,EAAiBC,EAA+B,GAAI,CAClE,MAAMC,EAAS,IAAI,gBACnB,OAAID,EAAQ,QAAQC,EAAO,IAAI,SAAUD,EAAQ,MAAM,EACnDA,EAAQ,aAAaC,EAAO,IAAI,cAAeD,EAAQ,WAAW,EAClEA,EAAQ,QAAQC,EAAO,IAAI,SAAUD,EAAQ,MAAM,EACnDA,EAAQ,QAAQC,EAAO,IAAI,SAAUD,EAAQ,MAAM,EACnDA,EAAQ,QAAQC,EAAO,IAAI,SAAUD,EAAQ,MAAM,EACnDA,EAAQ,OAAOC,EAAO,IAAI,QAAS,OAAOD,EAAQ,KAAK,CAAC,EACxDA,EAAQ,SAAW,QAAWC,EAAO,IAAI,SAAU,OAAOD,EAAQ,MAAM,CAAC,EAEtEE,EAAmC,CACxC,SAAU,CAAC,gBAAiBF,CAAO,EACnC,QAAS,IAAMG,EAAS,mBAAmBF,CAAM,EAAE,CAAA,CACpD,CACH,CAEO,SAASG,GAAwB,CACtC,OAAOF,EAAgC,CACrC,SAAU,CAAC,oBAAoB,EAC/B,QAAS,IAAMC,EAAS,yBAAyB,CAAA,CAClD,CACH,CAcO,SAASE,EAAgBC,EAAY,CAC1C,OAAOJ,EAA+B,CACpC,SAAU,CAAC,gBAAiBI,CAAE,EAC9B,QAAS,IAAMH,EAAS,mBAAmBG,CAAE,EAAE,EAC/C,QAAS,CAAC,CAACA,CAAA,CACZ,CACH,CAEO,SAASC,GAAwB,CACtC,MAAMC,EAAcC,EAAA,EACpB,OAAOC,EAAY,CACjB,WAAaC,GAWXR,EAA+B,kBAAmB,CAChD,OAAQ,OACR,KAAM,KAAK,UAAUQ,CAAK,CAAA,CAC3B,EACH,UAAW,IAAM,CACfH,EAAY,kBAAkB,CAAE,SAAU,CAAC,eAAe,EAAG,YAAa,MAAO,CACnF,CAAA,CACD,CACH,CAEO,SAASI,GAAwB,CACtC,MAAMJ,EAAcC,EAAA,EACpB,OAAOC,EAAY,CACjB,WAAaJ,GACXH,EAA+B,mBAAmBG,CAAE,UAAW,CAC7D,OAAQ,MAAA,CACT,EACH,UAAW,IAAM,CACfE,EAAY,kBAAkB,CAAE,SAAU,CAAC,eAAe,EAAG,YAAa,MAAO,CACnF,CAAA,CACD,CACH,CAEO,SAASK,GAA0B,CACxC,MAAML,EAAcC,EAAA,EACpB,OAAOC,EAAY,CACjB,WAAaJ,GACXH,EAA+B,mBAAmBG,CAAE,YAAa,CAC/D,OAAQ,MAAA,CACT,EACH,UAAW,IAAM,CACfE,EAAY,kBAAkB,CAAE,SAAU,CAAC,eAAe,EAAG,YAAa,MAAO,CACnF,CAAA,CACD,CACH,CAEO,SAASM,GAAwB,CACtC,MAAMN,EAAcC,EAAA,EACpB,OAAOC,EAAY,CACjB,WAAY,CAAC,CAAE,GAAAJ,EAAI,KAAAS,EAAM,KAAAC,EAAM,WAAAC,KAC7Bd,EAAgD,mBAAmBG,CAAE,UAAW,CAC9E,OAAQ,OACR,KAAM,KAAK,UAAU,CAAE,KAAAS,EAAM,KAAAC,EAAM,GAAIC,EAAa,CAAE,WAAAA,CAAA,EAAe,GAAK,CAAA,CAC3E,EACH,UAAW,IAAM,CACfT,EAAY,kBAAkB,CAAE,SAAU,CAAC,eAAe,EAAG,YAAa,MAAO,CACnF,CAAA,CACD,CACH,CAEO,SAASU,GAA4B,CAC1C,MAAMV,EAAcC,EAAA,EACpB,OAAOC,EAAY,CACjB,WAAY,CAAC,CAAE,GAAAJ,EAAI,WAAAa,EAAY,qBAAAC,KAC7BjB,EAA+B,mBAAmBG,CAAE,cAAe,CACjE,OAAQ,OACR,KAAM,KAAK,UAAU,CAAE,WAAAa,EAAY,qBAAAC,EAAsB,CAAA,CAC1D,EACH,UAAW,IAAM,CACfZ,EAAY,kBAAkB,CAAE,SAAU,CAAC,eAAe,EAAG,YAAa,MAAO,CACnF,CAAA,CACD,CACH,CAEO,SAASa,GAAyB,CACvC,MAAMb,EAAcC,EAAA,EACpB,OAAOC,EAAY,CACjB,WAAaJ,GACXH,EAA+B,mBAAmBG,CAAE,WAAY,CAC9D,OAAQ,MAAA,CACT,EACH,UAAW,IAAM,CACfE,EAAY,kBAAkB,CAAE,SAAU,CAAC,eAAe,EAAG,YAAa,MAAO,CACnF,CAAA,CACD,CACH,CAEO,SAASc,GAAyB,CACvC,MAAMd,EAAcC,EAAA,EACpB,OAAOC,EAAY,CACjB,WAAaJ,GACXH,EAA+B,mBAAmBG,CAAE,WAAY,CAC9D,OAAQ,MAAA,CACT,EACH,UAAW,IAAM,CACfE,EAAY,kBAAkB,CAAE,SAAU,CAAC,eAAe,EAAG,YAAa,MAAO,EACjFA,EAAY,kBAAkB,CAAE,SAAU,CAAC,cAAc,EAAG,YAAa,MAAO,CAClF,CAAA,CACD,CACH,CAEO,SAASe,GAAwB,CACtC,MAAMf,EAAcC,EAAA,EACpB,OAAOC,EAAY,CACjB,WAAY,CAAC,CAAE,GAAAJ,EAAI,GAAGkB,KACpBrB,EAA+B,mBAAmBG,CAAE,GAAI,CACtD,OAAQ,MACR,KAAM,KAAK,UAAUkB,CAAO,CAAA,CAC7B,EACH,UAAW,IAAM,CACfhB,EAAY,kBAAkB,CAAE,SAAU,CAAC,eAAe,EAAG,YAAa,MAAO,CACnF,CAAA,CACD,CACH,CAEO,SAASiB,GAAwB,CACtC,MAAMjB,EAAcC,EAAA,EACpB,OAAOC,EAAY,CACjB,WAAaJ,GACXH,EAA+B,mBAAmBG,CAAE,GAAI,CACtD,OAAQ,QAAA,CACT,EACH,UAAW,IAAM,CACfE,EAAY,kBAAkB,CAAE,SAAU,CAAC,eAAe,EAAG,YAAa,MAAO,CACnF,CAAA,CACD,CACH,CAsCO,SAASkB,EAAwBpB,EAAY,CAClD,OAAOJ,EAA+D,CACpE,SAAU,CAAC,gBAAiBI,EAAI,UAAU,EAC1C,QAAS,IAAMH,EAAS,mBAAmBG,CAAE,WAAW,EACxD,QAAS,CAAC,CAACA,CAAA,CACZ,CACH,CAEO,SAASqB,EAAuBrB,EAAYsB,EAAwB,CACzE,OAAO1B,EAAgC,CACrC,SAAU,CAAC,gBAAiBI,EAAI,WAAYsB,CAAO,EACnD,QAAS,IAAMzB,EAAS,mBAAmBG,CAAE,aAAasB,CAAO,EAAE,EACnE,QAAS,CAAC,CAACtB,GAAMsB,IAAY,IAAA,CAC9B,CACH"}
1
+ {"version":3,"file":"yaml-workflows-Dyln3od-.js","sources":["../../src/api/yaml-workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { LTYamlWorkflowRecord, LTYamlWorkflowStatus, LTYamlWorkflowVersion } from './types';\n\ninterface YamlWorkflowListResponse {\n workflows: LTYamlWorkflowRecord[];\n total: number;\n}\n\ninterface YamlWorkflowFilters {\n status?: LTYamlWorkflowStatus;\n graph_topic?: string;\n app_id?: string;\n search?: string;\n set_id?: string;\n limit?: number;\n offset?: number;\n}\n\nexport function useYamlWorkflows(filters: YamlWorkflowFilters = {}) {\n const params = new URLSearchParams();\n if (filters.status) params.set('status', filters.status);\n if (filters.graph_topic) params.set('graph_topic', filters.graph_topic);\n if (filters.app_id) params.set('app_id', filters.app_id);\n if (filters.search) params.set('search', filters.search);\n if (filters.set_id) params.set('set_id', filters.set_id);\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', filters],\n queryFn: () => apiFetch(`/yaml-workflows?${params}`),\n });\n}\n\nexport function useYamlWorkflowAppIds() {\n return useQuery<{ app_ids: string[] }>({\n queryKey: ['yamlWorkflowAppIds'],\n queryFn: () => apiFetch('/yaml-workflows/app-ids'),\n });\n}\n\nexport function useYamlWorkflowByTopic(graphTopic: string | undefined, appId?: string) {\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', 'byTopic', graphTopic, appId],\n queryFn: () => {\n const params = new URLSearchParams({ graph_topic: graphTopic!, limit: '1' });\n if (appId) params.set('app_id', appId);\n return apiFetch(`/yaml-workflows?${params}`);\n },\n enabled: !!graphTopic,\n });\n}\n\nexport function useYamlWorkflow(id: string) {\n return useQuery<LTYamlWorkflowRecord>({\n queryKey: ['yamlWorkflows', id],\n queryFn: () => apiFetch(`/yaml-workflows/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useCreateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (input: {\n workflow_id: string;\n task_queue: string;\n workflow_name: string;\n name: string;\n description?: string;\n app_id?: string;\n subscribes?: string;\n tags?: string[];\n compilation_feedback?: string;\n }) =>\n apiFetch<LTYamlWorkflowRecord>('/yaml-workflows', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeployYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/deploy`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useActivateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/activate`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, data, sync, execute_as }: { id: string; data: Record<string, unknown>; sync?: boolean; execute_as?: string }) =>\n apiFetch<{ result?: unknown; job_id?: string }>(`/yaml-workflows/${id}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, sync, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRegenerateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, task_queue, compilation_feedback }: { id: string; task_queue?: string; compilation_feedback?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/regenerate`, {\n method: 'POST',\n body: JSON.stringify({ task_queue, compilation_feedback }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useArchiveYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/archive`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRestoreYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/restore`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflow'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpdateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...updates }: { id: string; yaml_content?: string; name?: string; description?: string; input_schema?: Record<string, unknown>; output_schema?: Record<string, unknown>; tags?: string[]; app_id?: string; graph_topic?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify(updates),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ deleted: boolean }>(`/yaml-workflows/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Cron scheduling ─────────────────────────────────────────────\n\nexport function useSetYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, cron_schedule, cron_envelope, execute_as }: {\n id: string;\n cron_schedule: string;\n cron_envelope?: Record<string, unknown> | null;\n execute_as?: string | null;\n }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'PUT',\n body: JSON.stringify({ cron_schedule, cron_envelope, execute_as }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useClearYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Version history ─────────────────────────────────────────────\n\nexport function useYamlWorkflowVersions(id: string) {\n return useQuery<{ versions: LTYamlWorkflowVersion[]; total: number }>({\n queryKey: ['yamlWorkflows', id, 'versions'],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions`),\n enabled: !!id,\n });\n}\n\nexport function useYamlWorkflowVersion(id: string, version: number | null) {\n return useQuery<LTYamlWorkflowVersion>({\n queryKey: ['yamlWorkflows', id, 'versions', version],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions/${version}`),\n enabled: !!id && version !== null,\n });\n}\n"],"names":["useYamlWorkflows","filters","params","useQuery","apiFetch","useYamlWorkflowAppIds","useYamlWorkflow","id","useCreateYamlWorkflow","queryClient","useQueryClient","useMutation","input","useDeployYamlWorkflow","useActivateYamlWorkflow","useInvokeYamlWorkflow","data","sync","execute_as","useRegenerateYamlWorkflow","task_queue","compilation_feedback","useArchiveYamlWorkflow","useRestoreYamlWorkflow","useUpdateYamlWorkflow","updates","useDeleteYamlWorkflow","useYamlWorkflowVersions","useYamlWorkflowVersion","version"],"mappings":"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"}
@@ -8,11 +8,11 @@
8
8
  <link rel="preconnect" href="https://fonts.googleapis.com" />
9
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
10
  <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
11
- <script type="module" crossorigin src="./assets/index-xycFf66M.js"></script>
11
+ <script type="module" crossorigin src="./assets/index-ygxyAKcc.js"></script>
12
12
  <link rel="modulepreload" crossorigin href="./assets/vendor-query-DvWWuNIB.js">
13
13
  <link rel="modulepreload" crossorigin href="./assets/vendor-react-_9U4mKFr.js">
14
14
  <link rel="modulepreload" crossorigin href="./assets/vendor-icons-en0_uSRD.js">
15
- <link rel="stylesheet" crossorigin href="./assets/index-C_dp4WgY.css">
15
+ <link rel="stylesheet" crossorigin href="./assets/index-BmzscsXK.css">
16
16
  </head>
17
17
  <body>
18
18
  <div id="root"></div>
@@ -53,7 +53,7 @@ Written by the fold at creation, inside the row's Leg1 commit, and maintained by
53
53
  | `envelope` | `accumulate_items` | `Record<itemKey, { payload?, at, actor?, reciprocalId? }>` |
54
54
  | `envelope` | `accumulate_config` | the folded `{ unique, resolveAtMax }` |
55
55
 
56
- A batch row records each fill's time and actor under `envelope.batch_filled_at` and `envelope.batch_filled_by`, and may start with entries already satisfied through `filled` (see [Creating Escalations](hitl/escalation.md)). A batch wait may add `partialOnTimeout: true`; it stores `envelope.batch_partial_on_timeout` and its timer delivers `{ ...filledItems, $trigger: 'timeout' }` instead of `false`. A pending key may carry a flag in `envelope.batch_flags` (it stays pending and still fills); a wait that adds `wakeOnFlag: true` ends on the first flag and delivers `{ ...filledItems, $flags, $trigger: 'flag' }`.
56
+ A batch row records each fill's time and actor under `envelope.batch_filled_at` and `envelope.batch_filled_by`, and may start with entries already satisfied through `filled` (see [Creating Escalations](hitl/escalation.md)). A batch wait may add `partialOnTimeout: true`; it stores `envelope.batch_partial_on_timeout` and its timer delivers `{ ...filledItems, $trigger: 'timeout' }` instead of `false`. A pending key may carry a flag in `envelope.batch_flags` (it stays pending and still fills); a wait that adds `wakeOnFlag: true` ends on the first flag and delivers `{ ...filledItems, $flags, $trigger: 'flag' }`. A wait that adds `wakeOnFill: true` (or a list of keys) ends on a fill and delivers `{ ...filledItems, $filled: [itemKey], $filledAt, $filledBy, $trigger: 'fill' }`; the fill answers `woke`, and the workflow parks its next round with the fills carried forward in `filled`.
57
57
 
58
58
  ## Operations
59
59
 
@@ -1131,7 +1131,7 @@ POST /api/escalations/resolve-batch-item-by-signal-key
1131
1131
  POST /api/escalations/resolve-batch-item-by-metadata
1132
1132
  ```
1133
1133
 
1134
- Submit ONE declared item of a batch escalation (a `conditional` wait created with `batch: [...]`). Interim items answer `{ outcome: 'accepted', remaining }`; the LAST item answers `{ outcome: 'completed', remaining: 0, signaled, escalationId, workflowId }` and the waiting workflow resumes with the full collection, in the same statement. Each item validates against the row's versioned role form (canonical 422). Duplicates answer 409 (`Batch item already submitted`), undeclared keys 400, a non-batch row 400.
1134
+ Submit ONE declared item of a batch escalation (a `conditional` wait created with `batch: [...]`). Interim items answer `{ outcome: 'accepted', remaining }`; the LAST item answers `{ outcome: 'completed', remaining: 0, signaled, escalationId, workflowId }` and the waiting workflow resumes with the full collection, in the same statement. On a wait declared with `wakeOnFill` for the key, a fill with items remaining answers `{ outcome: 'woke', remaining, signaled, escalationId, workflowId }`: the row resolves and the workflow resumes with the items so far and `$trigger: 'fill'`. Each item validates against the row's versioned role form (canonical 422). Duplicates answer 409 (`Batch item already submitted`), undeclared keys 400, a non-batch row 400.
1135
1135
 
1136
1136
  **Body (by id):** `{ itemKey, resolverPayload, metadata?, assertClaim? }`. **By signal key:** `{ signalKey, itemKey, resolverPayload, metadata? }`. **By metadata:** `{ key, value, itemKey, resolverPayload, metadata?, restrictRoles? }`.
1137
1137
 
@@ -13,6 +13,8 @@ Built-in escalation and human queue management. Exposes the escalation API as MC
13
13
 
14
14
  These tools act with full authority. At `/mcp` they are listed for superadmin accounts only. Other accounts work the queue through the role-checked escalation tools on [long-tail-admin](admin.md).
15
15
 
16
+ `get_escalation_lookups` is listed for every account. It runs as the caller, with the read check `GET /api/escalations/:id/lookups` runs.
17
+
16
18
  ## Compile Hints
17
19
 
18
20
  escalate_and_wait creates a durable pause point. The step AFTER escalate_and_wait is always a signal step (kind: "signal") that receives the human response. Fields from the signal step output (e.g., password) must be wired via data_flow edges to ALL downstream steps that need them.
@@ -55,7 +57,9 @@ Check the status of an escalation. Returns status and resolver payload if resolv
55
57
 
56
58
  ### get_escalation_lookups
57
59
 
58
- Resolve the versioned knowledge lookups pinned on an escalation (`envelope.lookups`). Each ref answers with its immutable edition; a ref whose snapshot does not exist answers with `missing: true`. Like the other tools on this server, the call carries no per-user identity — the MCP surface reads at service scope.
60
+ Resolve the versioned knowledge lookups pinned on an escalation (`envelope.lookups`). Each ref answers with its edition; a ref whose snapshot does not exist answers with `missing: true`. A closed row answers with the editions current when it closed.
61
+
62
+ Any caller who may read the escalation may call it: a superadmin, a member of the row's role with read scope `all`, or a read scope `self` member while the row is assigned to them. Others get `Not authorized to view this escalation` and no edition content. The refs on the row are the grant, so a member reads the editions their row names without a knowledge grant. An internal call reads as lt-system.
59
63
 
60
64
  | | |
61
65
  |---|---|
@@ -453,7 +453,7 @@ if (bin === null) return cancelled();
453
453
  ship(bin.$accumulated.map((item) => item.itemKey), bin.$trigger);
454
454
  ```
455
455
 
456
- Requires hotmesh 0.29.0+. `conditional` accepts the same `accumulate` field and returns `T | false | null`; `partialOnTimeout: true` on a `batch` wait likewise makes the timer deliver the filled items with `$trigger: 'timeout'`, and `wakeOnFlag: true` makes a flag on a pending key deliver them with `$flags` and `$trigger: 'flag'` (hotmesh 0.31.3+). See [Creating Escalations](../../hitl/escalation.md#open-accumulation--items-arrive-over-time).
456
+ Requires hotmesh 0.29.0+. `conditional` accepts the same `accumulate` field and returns `T | false | null`; `partialOnTimeout: true` on a `batch` wait likewise makes the timer deliver the filled items with `$trigger: 'timeout'`, `wakeOnFlag: true` makes a flag on a pending key deliver them with `$flags` and `$trigger: 'flag'` (hotmesh 0.31.3+), and `wakeOnFill: true` (or a list of keys) makes a fill deliver them with `$filled`, `$filledAt`, `$filledBy` and `$trigger: 'fill'` (hotmesh 0.32.0+). See [Creating Escalations](../../hitl/escalation.md#open-accumulation--items-arrive-over-time).
457
457
 
458
458
  ### Two-step form
459
459
 
package/docs/dashboard.md CHANGED
@@ -507,7 +507,7 @@ Accessible at `/knowledge` (builder-only — superadmin or the `engineer` role).
507
507
  - **Version rail** — the entry detail's version dropdown lists every edition, newest first, the current one marked. Selecting a past edition sets `?version=<N>` and shows an immutable, read-only snapshot with a "back to current" affordance.
508
508
  - **Field-level edits** — set or remove a value at a dot-path (`jsonb_set` / path delete) without clobbering sibling keys; each still mints an edition when the data changes.
509
509
 
510
- **How workflows and forms consume it.** A workflow pins knowledge onto an escalation as versioned lookup refs on the reserved `envelope.lookups` key — `{ domain, key, version, as? }`. Because the ref names an exact edition, the resolver always sees the data the workflow was written against, even as the entry later evolves. Resolving those refs (`GET /api/escalations/:id/lookups`, in-process LRU cached) exposes a `lookup.<key>` domain to the form: a field's `x-lt-options` reads `lookup.materials.items`, and cascades interpolate the live form — `lookup.geo.regions.{{resolver.country}}` narrows the second select from the first. The reader needs no separate knowledge grant; the ref on an escalation they can read *is* the grant. Agents reach the same data through the `get_knowledge` MCP tool (with an optional `version`).
510
+ **How workflows and forms consume it.** A workflow pins knowledge onto an escalation as versioned lookup refs on the reserved `envelope.lookups` key — `{ domain, key, version, as? }`. Because the ref names an exact edition, the resolver always sees the data the workflow was written against, even as the entry later evolves. Resolving those refs (`GET /api/escalations/:id/lookups`, in-process LRU cached) exposes a `lookup.<key>` domain to the form: a field's `x-lt-options` reads `lookup.materials.items`, and cascades interpolate the live form — `lookup.geo.regions.{{resolver.country}}` narrows the second select from the first. The reader needs no separate knowledge grant; the ref on an escalation they can read *is* the grant. Agents read a row's editions with the `get_escalation_lookups` MCP tool under the same grant; builders reach any entry through `get_knowledge` (with an optional `version`).
511
511
 
512
512
  **API:** `GET /api/knowledge/domains` and `/entries?domain=` list; `GET /api/knowledge/entry?domain=&key=&version=` fetches the live entry or a pinned edition; `GET /api/knowledge/entry/versions?domain=&key=` returns the lineage. `POST /api/knowledge/entry` creates or merges, `PUT /api/knowledge/field` sets a path, `DELETE /api/knowledge/field` removes one, `DELETE /api/knowledge/entry` deletes (cascading its editions). See [Knowledge HTTP API](api/http/knowledge.md).
513
513
 
@@ -607,7 +607,9 @@ in the placeholder. Type the target and press Enter: the bar composes
607
607
  the outcome navigates, confirms, or answers exactly as a physical scan would.
608
608
  An outcome that answers in place (a fallback, a conflict, a closed row) is
609
609
  narrated right under the bar. A whole code pasted into a Run mode executes
610
- as-is; fixed-encoding rules accept digits only and say so inline. The menu
610
+ as-is; fixed-encoding rules accept digits only and say so inline. A gtin or
611
+ pattern rule runs the typed code itself, and a pattern rule names a code that
612
+ matches none of its patterns inline. The menu
611
613
  footer opens the scan panel for scanner settings and the barcode preview.
612
614
  See [Scan codes](scan-codes.md).
613
615
 
@@ -115,6 +115,22 @@ const result = await conditional<Record<string, unknown>>(signalId, {
115
115
  if (result && result.$trigger === 'flag') return sendToManager(orderId, result.$flags);
116
116
  ```
117
117
 
118
+ Add `wakeOnFill: true` (hotmesh 0.32.0+), or a list of keys, and a fill ends the wait so the workflow acts on each item as it lands: the fill resolves the row and the wait resumes with the items so far, `$filled: [itemKey]`, `$filledAt` and `$filledBy` (every filled key's time and actor) and `$trigger: 'fill'`. The workflow parks the next round with every fill carried forward through `filled`, built from `$filledAt` and `$filledBy`; the last key completes as on any batch. The fill answers `woke` with the remaining count.
119
+
120
+ ```typescript
121
+ let filled: Record<string, BatchFilledEntry> | undefined;
122
+ for (let round = 1; ; round++) {
123
+ const out = await conditional<Record<string, any>>(`receive-${orderId}-${round}`, {
124
+ role: 'receiving', metadata: { orderId, trackingNumbers }, batch: boxKeys, wakeOnFill: true,
125
+ ...(filled ? { filled } : {}),
126
+ });
127
+ if (!out || out.$trigger !== 'fill') return out; // complete, expired, or cancelled
128
+ await recordReceipt(orderId, out.$filled[0]); // a proxied activity
129
+ filled = Object.fromEntries(Object.keys(out.$filledAt).map((key) =>
130
+ [key, { payload: out[key], at: out.$filledAt[key], actor: out.$filledBy?.[key] }]));
131
+ }
132
+ ```
133
+
118
134
  Entries already satisfied before the wait begins go in `filled` (hotmesh 0.31.0+), keyed by item key with their `payload`, the `at` they were satisfied (from the source of record, never a clock read in the workflow), and an optional `actor`. The row starts with that progress: those keys are left out of `batch_pending`, their payloads, times, and actors are written beside the rest, and the completing wake delivers them with the collection. Every key in `filled` must be declared in `batch`, and at least one must stay open; a `filled` that covers every key throws, so skip the wait instead.
119
135
 
120
136
  ```typescript
@@ -88,6 +88,8 @@ GET /api/escalations/:id/lookups
88
88
 
89
89
  `version` is the edition served; `current: true` marks a ref that follows the newest edition.
90
90
 
91
+ An agent reads the same answer with the `get_escalation_lookups` MCP tool, as the account it signed in with and under the same read check.
92
+
91
93
  The general knowledge API (`/api/knowledge/*`) is a builder surface — superadmin or engineer. A member never queries the knowledge store directly; the escalation-scoped endpoint serves them precisely the editions their work item carries, and nothing else. A ref whose snapshot does not exist answers with `missing: true` for that ref — the batch never fails.
92
94
 
93
95
  ## Form Addressing
package/docs/mcp.md CHANGED
@@ -371,6 +371,8 @@ The Human Queue is a built-in MCP server that exposes Long Tail's escalation API
371
371
 
372
372
  These tools act with full authority, so at `/mcp` they are listed for superadmin accounts. Workflows and agents inside Long Tail call them directly. An external agent with any other role works the queue through the role-checked escalation tools: `find_escalations`, `claim_escalation`, `admin_resolve_escalation`.
373
373
 
374
+ `get_escalation_lookups` is listed for every account and runs as the caller: anyone who may read the escalation reads the knowledge editions it names, the same grant `GET /api/escalations/:id/lookups` serves.
375
+
374
376
  ### Tools
375
377
 
376
378
  | Tool | Purpose |