@hotmeshio/long-tail 0.5.12 → 0.6.2

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 (337) hide show
  1. package/README.md +1 -0
  2. package/build/api/escalations/bulk.js +9 -1
  3. package/build/api/escalations/cancel.js +5 -7
  4. package/build/api/escalations/claim.js +18 -15
  5. package/build/api/escalations/create.d.ts +6 -0
  6. package/build/api/escalations/create.js +11 -8
  7. package/build/api/escalations/facets.d.ts +18 -0
  8. package/build/api/escalations/facets.js +115 -0
  9. package/build/api/escalations/helpers.d.ts +70 -1
  10. package/build/api/escalations/helpers.js +101 -7
  11. package/build/api/escalations/index.d.ts +3 -2
  12. package/build/api/escalations/index.js +7 -1
  13. package/build/api/escalations/list.d.ts +21 -2
  14. package/build/api/escalations/list.js +109 -10
  15. package/build/api/escalations/metadata.js +22 -27
  16. package/build/api/escalations/resolve.d.ts +19 -1
  17. package/build/api/escalations/resolve.js +111 -26
  18. package/build/api/escalations/single.js +8 -8
  19. package/build/api/users.d.ts +6 -0
  20. package/build/api/users.js +29 -1
  21. package/build/bin/ltc.js +40 -0
  22. package/build/lib/cli/commands/escalations.d.ts +36 -0
  23. package/build/lib/cli/commands/escalations.js +98 -0
  24. package/build/lib/db/schemas/001_schema.sql +10 -5
  25. package/build/lib/db/schemas/012_lt_tasks_workflow_id_unique.sql +20 -0
  26. package/build/lib/db/schemas/013_role_scope.sql +37 -0
  27. package/build/modules/version.d.ts +10 -5
  28. package/build/modules/version.js +27 -11
  29. package/build/routes/escalations/facets.d.ts +7 -0
  30. package/build/routes/escalations/facets.js +81 -0
  31. package/build/routes/escalations/index.js +3 -0
  32. package/build/routes/escalations/list.js +46 -0
  33. package/build/routes/escalations/resolve.js +22 -4
  34. package/build/routes/users.js +9 -5
  35. package/build/sdk/index.d.ts +33 -2
  36. package/build/sdk/index.js +7 -0
  37. package/build/services/escalation/crud.d.ts +56 -6
  38. package/build/services/escalation/crud.js +102 -31
  39. package/build/services/escalation/facet-sql.d.ts +18 -0
  40. package/build/services/escalation/facet-sql.js +118 -0
  41. package/build/services/escalation/facets.d.ts +45 -0
  42. package/build/services/escalation/facets.js +218 -0
  43. package/build/services/escalation/index.d.ts +1 -0
  44. package/build/services/escalation/index.js +8 -1
  45. package/build/services/escalation/queries.d.ts +45 -0
  46. package/build/services/escalation/queries.js +107 -6
  47. package/build/services/escalation/sql.d.ts +10 -4
  48. package/build/services/escalation/sql.js +36 -8
  49. package/build/services/interceptor/activities/escalation.d.ts +2 -0
  50. package/build/services/interceptor/activities/escalation.js +1 -1
  51. package/build/services/interceptor/lifecycle.js +4 -0
  52. package/build/services/mcp/server-tools.js +10 -4
  53. package/build/services/orchestrator/condition.js +6 -2
  54. package/build/services/role/index.js +2 -3
  55. package/build/services/role/sql.d.ts +8 -0
  56. package/build/services/role/sql.js +17 -1
  57. package/build/services/task/crud.js +22 -14
  58. package/build/services/task/process.js +3 -21
  59. package/build/services/task/sql.d.ts +24 -1
  60. package/build/services/task/sql.js +65 -1
  61. package/build/services/user/crud.d.ts +1 -0
  62. package/build/services/user/crud.js +29 -11
  63. package/build/services/user/index.d.ts +2 -1
  64. package/build/services/user/index.js +12 -1
  65. package/build/services/user/rbac.d.ts +18 -0
  66. package/build/services/user/rbac.js +27 -0
  67. package/build/services/user/roles.d.ts +7 -2
  68. package/build/services/user/roles.js +21 -5
  69. package/build/services/user/scope.d.ts +22 -0
  70. package/build/services/user/scope.js +50 -0
  71. package/build/services/user/seed-admin.js +34 -17
  72. package/build/services/user/sql.d.ts +18 -7
  73. package/build/services/user/sql.js +38 -13
  74. package/build/services/user/sso-provision.js +41 -24
  75. package/build/services/user/types.d.ts +9 -5
  76. package/build/system/mcp-servers/admin/escalations.js +65 -0
  77. package/build/system/mcp-servers/admin/schemas.d.ts +325 -0
  78. package/build/system/mcp-servers/admin/schemas.js +63 -2
  79. package/build/system/mcp-servers/admin/users.js +28 -2
  80. package/build/tsconfig.tsbuildinfo +1 -1
  81. package/build/types/envelope.d.ts +7 -0
  82. package/build/types/facets.d.ts +60 -0
  83. package/build/types/facets.js +10 -0
  84. package/build/types/index.d.ts +2 -1
  85. package/build/types/user.d.ts +11 -0
  86. package/dashboard/dist/assets/AdminDashboard-C5gfVEeL.js +2 -0
  87. package/dashboard/dist/assets/{AdminDashboard-LTiYLuzq.js.map → AdminDashboard-C5gfVEeL.js.map} +1 -1
  88. package/dashboard/dist/assets/{AgentConfigPage-nlOudfpZ.js → AgentConfigPage-CWEnuiGN.js} +6 -6
  89. package/dashboard/dist/assets/{AgentConfigPage-nlOudfpZ.js.map → AgentConfigPage-CWEnuiGN.js.map} +1 -1
  90. package/dashboard/dist/assets/{AgentDetailPage-BSUnDvGp.js → AgentDetailPage-B6IE27iK.js} +3 -3
  91. package/dashboard/dist/assets/AgentDetailPage-B6IE27iK.js.map +1 -0
  92. package/dashboard/dist/assets/AgentsPage-Blhh2RsK.js +2 -0
  93. package/dashboard/dist/assets/{AgentsPage-DpS0cCYe.js.map → AgentsPage-Blhh2RsK.js.map} +1 -1
  94. package/dashboard/dist/assets/AvailableEscalationsPage-ClwAle76.js +2 -0
  95. package/dashboard/dist/assets/AvailableEscalationsPage-ClwAle76.js.map +1 -0
  96. package/dashboard/dist/assets/{BotPicker-BhKmq7M7.js → BotPicker-DSozotGk.js} +2 -2
  97. package/dashboard/dist/assets/{BotPicker-BhKmq7M7.js.map → BotPicker-DSozotGk.js.map} +1 -1
  98. package/dashboard/dist/assets/CapabilitiesPage-CrS_DTA1.js +2 -0
  99. package/dashboard/dist/assets/CapabilitiesPage-CrS_DTA1.js.map +1 -0
  100. package/dashboard/dist/assets/{CollapsibleSection-D7SVwNVk.js → CollapsibleSection-1i6bOQ1L.js} +2 -2
  101. package/dashboard/dist/assets/{CollapsibleSection-D7SVwNVk.js.map → CollapsibleSection-1i6bOQ1L.js.map} +1 -1
  102. package/dashboard/dist/assets/CopyableId-blg-gZvT.js +2 -0
  103. package/dashboard/dist/assets/CopyableId-blg-gZvT.js.map +1 -0
  104. package/dashboard/dist/assets/{CredentialsPage-fat5Z2U9.js → CredentialsPage-BxJio06E.js} +2 -2
  105. package/dashboard/dist/assets/{CredentialsPage-fat5Z2U9.js.map → CredentialsPage-BxJio06E.js.map} +1 -1
  106. package/dashboard/dist/assets/{CronLabel-OOP4P2mJ.js → CronLabel-BAfIHHz4.js} +2 -2
  107. package/dashboard/dist/assets/{CronLabel-OOP4P2mJ.js.map → CronLabel-BAfIHHz4.js.map} +1 -1
  108. package/dashboard/dist/assets/{CustomDurationPicker-COacSAXO.js → CustomDurationPicker-BLF0NFJK.js} +2 -2
  109. package/dashboard/dist/assets/{CustomDurationPicker-COacSAXO.js.map → CustomDurationPicker-BLF0NFJK.js.map} +1 -1
  110. package/dashboard/dist/assets/{DataTable-D9yuBv0w.js → DataTable-ZWgVQg7F.js} +2 -2
  111. package/dashboard/dist/assets/DataTable-ZWgVQg7F.js.map +1 -0
  112. package/dashboard/dist/assets/{DropZone-Bfw2YLVS.js → DropZone-CEx_wk-g.js} +2 -2
  113. package/dashboard/dist/assets/{DropZone-Bfw2YLVS.js.map → DropZone-CEx_wk-g.js.map} +1 -1
  114. package/dashboard/dist/assets/{ElapsedCell-CkfCD-m7.js → ElapsedCell-nKGJvznH.js} +2 -2
  115. package/dashboard/dist/assets/{ElapsedCell-CkfCD-m7.js.map → ElapsedCell-nKGJvznH.js.map} +1 -1
  116. package/dashboard/dist/assets/{EscalationsOverview-BmI8jxlh.js → EscalationsOverview-bNNVA6R2.js} +2 -2
  117. package/dashboard/dist/assets/{EscalationsOverview-BmI8jxlh.js.map → EscalationsOverview-bNNVA6R2.js.map} +1 -1
  118. package/dashboard/dist/assets/{EventTable-CeKfFk3m.js → EventTable-BCuDdqlU.js} +2 -2
  119. package/dashboard/dist/assets/{EventTable-CeKfFk3m.js.map → EventTable-BCuDdqlU.js.map} +1 -1
  120. package/dashboard/dist/assets/FilterBar-BQ2JGg8U.js +2 -0
  121. package/dashboard/dist/assets/FilterBar-BQ2JGg8U.js.map +1 -0
  122. package/dashboard/dist/assets/GraphInvokePage-BPAvqHls.js +2 -0
  123. package/dashboard/dist/assets/GraphInvokePage-BPAvqHls.js.map +1 -0
  124. package/dashboard/dist/assets/HomePage-BZ1YTrjR.js +2 -0
  125. package/dashboard/dist/assets/HomePage-BZ1YTrjR.js.map +1 -0
  126. package/dashboard/dist/assets/{ListToolbar-BJaCzAXS.js → ListToolbar-DIJZfEgu.js} +2 -2
  127. package/dashboard/dist/assets/{ListToolbar-BJaCzAXS.js.map → ListToolbar-DIJZfEgu.js.map} +1 -1
  128. package/dashboard/dist/assets/{McpOverview-CvnDG5OB.js → McpOverview-DCfSCfPg.js} +2 -2
  129. package/dashboard/dist/assets/{McpOverview-CvnDG5OB.js.map → McpOverview-DCfSCfPg.js.map} +1 -1
  130. package/dashboard/dist/assets/{McpQueryDetailPage-DwmSIcIL.js → McpQueryDetailPage-mb7rmtNe.js} +2 -2
  131. package/dashboard/dist/assets/{McpQueryDetailPage-DwmSIcIL.js.map → McpQueryDetailPage-mb7rmtNe.js.map} +1 -1
  132. package/dashboard/dist/assets/{McpQueryPage-CU6FMEEk.js → McpQueryPage-D9b1T0I3.js} +2 -2
  133. package/dashboard/dist/assets/{McpQueryPage-CU6FMEEk.js.map → McpQueryPage-D9b1T0I3.js.map} +1 -1
  134. package/dashboard/dist/assets/{McpRunDetailPage-8a6lsehv.js → McpRunDetailPage-Bz2UyuNm.js} +2 -2
  135. package/dashboard/dist/assets/{McpRunDetailPage-8a6lsehv.js.map → McpRunDetailPage-Bz2UyuNm.js.map} +1 -1
  136. package/dashboard/dist/assets/McpRunsPage-Dw7w_ZO-.js +2 -0
  137. package/dashboard/dist/assets/McpRunsPage-Dw7w_ZO-.js.map +1 -0
  138. package/dashboard/dist/assets/{NamespacePill-D6btr6e8.js → NamespacePill-D27vqDXy.js} +2 -2
  139. package/dashboard/dist/assets/{NamespacePill-D6btr6e8.js.map → NamespacePill-D27vqDXy.js.map} +1 -1
  140. package/dashboard/dist/assets/OperatorDashboard-CTzSDW3N.js +2 -0
  141. package/dashboard/dist/assets/{OperatorDashboard-g9o7I925.js.map → OperatorDashboard-CTzSDW3N.js.map} +1 -1
  142. package/dashboard/dist/assets/PageHeader-B_1zTx2q.js +2 -0
  143. package/dashboard/dist/assets/PageHeader-B_1zTx2q.js.map +1 -0
  144. package/dashboard/dist/assets/{PageHeaderWithStats-DJQCZ0FR.js → PageHeaderWithStats-D-cPg7UD.js} +2 -2
  145. package/dashboard/dist/assets/{PageHeaderWithStats-DJQCZ0FR.js.map → PageHeaderWithStats-D-cPg7UD.js.map} +1 -1
  146. package/dashboard/dist/assets/PriorityBadge-B4ykBH7f.js +2 -0
  147. package/dashboard/dist/assets/PriorityBadge-B4ykBH7f.js.map +1 -0
  148. package/dashboard/dist/assets/{ProcessDetailPage-ByyWCs2A.js → ProcessDetailPage-olG2CS-h.js} +2 -2
  149. package/dashboard/dist/assets/{ProcessDetailPage-ByyWCs2A.js.map → ProcessDetailPage-olG2CS-h.js.map} +1 -1
  150. package/dashboard/dist/assets/{ProcessesListPage-BTsXds4l.js → ProcessesListPage-CUZSL06Y.js} +2 -2
  151. package/dashboard/dist/assets/{ProcessesListPage-BTsXds4l.js.map → ProcessesListPage-CUZSL06Y.js.map} +1 -1
  152. package/dashboard/dist/assets/RolePill-B-V-31lC.js +2 -0
  153. package/dashboard/dist/assets/RolePill-B-V-31lC.js.map +1 -0
  154. package/dashboard/dist/assets/RolesPage-DLnaW6iD.js +2 -0
  155. package/dashboard/dist/assets/RolesPage-DLnaW6iD.js.map +1 -0
  156. package/dashboard/dist/assets/RowActions-BA9L9djf.js +2 -0
  157. package/dashboard/dist/assets/RowActions-BA9L9djf.js.map +1 -0
  158. package/dashboard/dist/assets/{RunAsSelector-BzkZXpSX.js → RunAsSelector-BoLHF4fy.js} +2 -2
  159. package/dashboard/dist/assets/{RunAsSelector-BzkZXpSX.js.map → RunAsSelector-BoLHF4fy.js.map} +1 -1
  160. package/dashboard/dist/assets/StickyPagination-BEMY1L-H.js +2 -0
  161. package/dashboard/dist/assets/StickyPagination-BEMY1L-H.js.map +1 -0
  162. package/dashboard/dist/assets/{StreamMessageDetail-B6ch-6SY.js → StreamMessageDetail-CVRVWXcU.js} +2 -2
  163. package/dashboard/dist/assets/{StreamMessageDetail-B6ch-6SY.js.map → StreamMessageDetail-CVRVWXcU.js.map} +1 -1
  164. package/dashboard/dist/assets/{SwimlaneTimeline-CjvfUkls.js → SwimlaneTimeline-DDpU0-Jn.js} +2 -2
  165. package/dashboard/dist/assets/{SwimlaneTimeline-CjvfUkls.js.map → SwimlaneTimeline-DDpU0-Jn.js.map} +1 -1
  166. package/dashboard/dist/assets/{TagInput-CZSeyesi.js → TagInput-BHVfG307.js} +2 -2
  167. package/dashboard/dist/assets/{TagInput-CZSeyesi.js.map → TagInput-BHVfG307.js.map} +1 -1
  168. package/dashboard/dist/assets/{TaskDetailPage-BjHU6opi.js → TaskDetailPage-B_xQtJMg.js} +2 -2
  169. package/dashboard/dist/assets/{TaskDetailPage-BjHU6opi.js.map → TaskDetailPage-B_xQtJMg.js.map} +1 -1
  170. package/dashboard/dist/assets/{TaskQueuePill-CQrXrSxk.js → TaskQueuePill-CGlxXqWt.js} +2 -2
  171. package/dashboard/dist/assets/{TaskQueuePill-CQrXrSxk.js.map → TaskQueuePill-CGlxXqWt.js.map} +1 -1
  172. package/dashboard/dist/assets/{TasksListPage-Bem44zd0.js → TasksListPage-CsrdIOKk.js} +2 -2
  173. package/dashboard/dist/assets/{TasksListPage-Bem44zd0.js.map → TasksListPage-CsrdIOKk.js.map} +1 -1
  174. package/dashboard/dist/assets/TimeAgo-DmicaxjT.js +2 -0
  175. package/dashboard/dist/assets/{TimeAgo-CUIYqSt_.js.map → TimeAgo-DmicaxjT.js.map} +1 -1
  176. package/dashboard/dist/assets/{TimestampCell--tnreI1i.js → TimestampCell-DeK89eRV.js} +2 -2
  177. package/dashboard/dist/assets/{TimestampCell--tnreI1i.js.map → TimestampCell-DeK89eRV.js.map} +1 -1
  178. package/dashboard/dist/assets/{ToolPill-O09jsTQM.js → ToolPill-NV7PxSpA.js} +2 -2
  179. package/dashboard/dist/assets/{ToolPill-O09jsTQM.js.map → ToolPill-NV7PxSpA.js.map} +1 -1
  180. package/dashboard/dist/assets/{ToolTestPanel-OD99H7Pk.js → ToolTestPanel-D3s2n9-9.js} +2 -2
  181. package/dashboard/dist/assets/{ToolTestPanel-OD99H7Pk.js.map → ToolTestPanel-D3s2n9-9.js.map} +1 -1
  182. package/dashboard/dist/assets/{TopicDetailPage-rh_dsTJI.js → TopicDetailPage-qyv7UWT_.js} +3 -3
  183. package/dashboard/dist/assets/TopicDetailPage-qyv7UWT_.js.map +1 -0
  184. package/dashboard/dist/assets/TopicsPage-CEUfMoed.js +2 -0
  185. package/dashboard/dist/assets/TopicsPage-CEUfMoed.js.map +1 -0
  186. package/dashboard/dist/assets/{UserName-C__c8BN0.js → UserName-Bn_BxI8K.js} +2 -2
  187. package/dashboard/dist/assets/{UserName-C__c8BN0.js.map → UserName-Bn_BxI8K.js.map} +1 -1
  188. package/dashboard/dist/assets/{WorkflowExecutionPage-Bw6QdtUO.js → WorkflowExecutionPage-DAk2RqpB.js} +2 -2
  189. package/dashboard/dist/assets/{WorkflowExecutionPage-Bw6QdtUO.js.map → WorkflowExecutionPage-DAk2RqpB.js.map} +1 -1
  190. package/dashboard/dist/assets/{WorkflowPill-CS-IsR0U.js → WorkflowPill-DDR0B6DN.js} +2 -2
  191. package/dashboard/dist/assets/{WorkflowPill-CS-IsR0U.js.map → WorkflowPill-DDR0B6DN.js.map} +1 -1
  192. package/dashboard/dist/assets/WorkflowsDashboard-DfBgM80t.js +2 -0
  193. package/dashboard/dist/assets/WorkflowsDashboard-DfBgM80t.js.map +1 -0
  194. package/dashboard/dist/assets/{WorkflowsOverview-BRc0QbA7.js → WorkflowsOverview--Dkoo9Jq.js} +2 -2
  195. package/dashboard/dist/assets/{WorkflowsOverview-BRc0QbA7.js.map → WorkflowsOverview--Dkoo9Jq.js.map} +1 -1
  196. package/dashboard/dist/assets/{YamlWorkflowDetailPage-DdzspNQR.js → YamlWorkflowDetailPage-B6HYbfFj.js} +25 -25
  197. package/dashboard/dist/assets/{YamlWorkflowDetailPage-DdzspNQR.js.map → YamlWorkflowDetailPage-B6HYbfFj.js.map} +1 -1
  198. package/dashboard/dist/assets/{YamlWorkflowsPage-Djw5ZbgQ.js → YamlWorkflowsPage-CJE-PxC0.js} +2 -2
  199. package/dashboard/dist/assets/{YamlWorkflowsPage-Djw5ZbgQ.js.map → YamlWorkflowsPage-CJE-PxC0.js.map} +1 -1
  200. package/dashboard/dist/assets/{agents-xstNkF6c.js → agents-DUciUZpt.js} +2 -2
  201. package/dashboard/dist/assets/{agents-xstNkF6c.js.map → agents-DUciUZpt.js.map} +1 -1
  202. package/dashboard/dist/assets/{bots-BztAI0s_.js → bots-BnyqCfuC.js} +2 -2
  203. package/dashboard/dist/assets/{bots-BztAI0s_.js.map → bots-BnyqCfuC.js.map} +1 -1
  204. package/dashboard/dist/assets/{capabilities-CEDwtxNL.js → capabilities-CkTWWT0q.js} +2 -2
  205. package/dashboard/dist/assets/{capabilities-CEDwtxNL.js.map → capabilities-CkTWWT0q.js.map} +1 -1
  206. package/dashboard/dist/assets/{controlplane-BlGEsRKe.js → controlplane-D9HaFZsC.js} +2 -2
  207. package/dashboard/dist/assets/{controlplane-BlGEsRKe.js.map → controlplane-D9HaFZsC.js.map} +1 -1
  208. package/dashboard/dist/assets/{escalation-iI4QKlP-.js → escalation-De9JnTKI.js} +2 -2
  209. package/dashboard/dist/assets/{escalation-iI4QKlP-.js.map → escalation-De9JnTKI.js.map} +1 -1
  210. package/dashboard/dist/assets/escalation-columns-Df7Pluzg.js +2 -0
  211. package/dashboard/dist/assets/escalation-columns-Df7Pluzg.js.map +1 -0
  212. package/dashboard/dist/assets/index-7hqtQI43.js +2 -0
  213. package/dashboard/dist/assets/index-7hqtQI43.js.map +1 -0
  214. package/dashboard/dist/assets/{index-CAqEy2Db.js → index-B07xLlyz.js} +2 -2
  215. package/dashboard/dist/assets/{index-CAqEy2Db.js.map → index-B07xLlyz.js.map} +1 -1
  216. package/dashboard/dist/assets/{index-D1xVY4JR.js → index-B1kc6itM.js} +24 -24
  217. package/dashboard/dist/assets/index-B1kc6itM.js.map +1 -0
  218. package/dashboard/dist/assets/index-BAhkWcOq.js +9 -0
  219. package/dashboard/dist/assets/index-BAhkWcOq.js.map +1 -0
  220. package/dashboard/dist/assets/{index-Dsi5o7dx.js → index-BsIaUbKD.js} +2 -2
  221. package/dashboard/dist/assets/{index-Dsi5o7dx.js.map → index-BsIaUbKD.js.map} +1 -1
  222. package/dashboard/dist/assets/index-BxdiKgnH.js +6 -0
  223. package/dashboard/dist/assets/index-BxdiKgnH.js.map +1 -0
  224. package/dashboard/dist/assets/{index-B7VC0vjf.js → index-BzMsh6Ui.js} +2 -2
  225. package/dashboard/dist/assets/{index-B7VC0vjf.js.map → index-BzMsh6Ui.js.map} +1 -1
  226. package/dashboard/dist/assets/index-CN0efCE9.js +6 -0
  227. package/dashboard/dist/assets/index-CN0efCE9.js.map +1 -0
  228. package/dashboard/dist/assets/{index-B5qsp8lb.js → index-CgD9fA9P.js} +2 -2
  229. package/dashboard/dist/assets/{index-B5qsp8lb.js.map → index-CgD9fA9P.js.map} +1 -1
  230. package/dashboard/dist/assets/{index-CUfgt3mV.js → index-Cqjf-yVP.js} +2 -2
  231. package/dashboard/dist/assets/{index-CUfgt3mV.js.map → index-Cqjf-yVP.js.map} +1 -1
  232. package/dashboard/dist/assets/{index-DjJ6VCuc.js → index-DNugmBs7.js} +2 -2
  233. package/dashboard/dist/assets/{index-DjJ6VCuc.js.map → index-DNugmBs7.js.map} +1 -1
  234. package/dashboard/dist/assets/{index-BUmnJ4eT.js → index-DjxTV3cn.js} +2 -2
  235. package/dashboard/dist/assets/{index-BUmnJ4eT.js.map → index-DjxTV3cn.js.map} +1 -1
  236. package/dashboard/dist/assets/index-DpAS4-DA.js +2 -0
  237. package/dashboard/dist/assets/index-DpAS4-DA.js.map +1 -0
  238. package/dashboard/dist/assets/index-nO0cim3_.css +1 -0
  239. package/dashboard/dist/assets/{knowledge-BKg0cr39.js → knowledge-D4SvdNv5.js} +2 -2
  240. package/dashboard/dist/assets/{knowledge-BKg0cr39.js.map → knowledge-D4SvdNv5.js.map} +1 -1
  241. package/dashboard/dist/assets/{mcp-CVdHpKlz.js → mcp-DVxt4T9J.js} +2 -2
  242. package/dashboard/dist/assets/{mcp-CVdHpKlz.js.map → mcp-DVxt4T9J.js.map} +1 -1
  243. package/dashboard/dist/assets/{mcp-query-CYxZcbwQ.js → mcp-query-CLP9EnnU.js} +2 -2
  244. package/dashboard/dist/assets/{mcp-query-CYxZcbwQ.js.map → mcp-query-CLP9EnnU.js.map} +1 -1
  245. package/dashboard/dist/assets/{pipelines-BOEv7P6O.js → pipelines-C_x0LTBN.js} +2 -2
  246. package/dashboard/dist/assets/{pipelines-BOEv7P6O.js.map → pipelines-C_x0LTBN.js.map} +1 -1
  247. package/dashboard/dist/assets/{roles-c5cV2QYQ.js → roles-QaGFZQ58.js} +2 -2
  248. package/dashboard/dist/assets/{roles-c5cV2QYQ.js.map → roles-QaGFZQ58.js.map} +1 -1
  249. package/dashboard/dist/assets/{tasks-JV3BjeEF.js → tasks-1eTuP02d.js} +2 -2
  250. package/dashboard/dist/assets/{tasks-JV3BjeEF.js.map → tasks-1eTuP02d.js.map} +1 -1
  251. package/dashboard/dist/assets/{topics-BDaPnhnQ.js → topics-B3p8K0PW.js} +2 -2
  252. package/dashboard/dist/assets/{topics-BDaPnhnQ.js.map → topics-B3p8K0PW.js.map} +1 -1
  253. package/dashboard/dist/assets/{useEventHooks-a7Dnh8G4.js → useEventHooks-BNZky4xM.js} +2 -2
  254. package/dashboard/dist/assets/{useEventHooks-a7Dnh8G4.js.map → useEventHooks-BNZky4xM.js.map} +1 -1
  255. package/dashboard/dist/assets/{useNamespace-BSwEV0e9.js → useNamespace-Dx81_JM0.js} +2 -2
  256. package/dashboard/dist/assets/{useNamespace-BSwEV0e9.js.map → useNamespace-Dx81_JM0.js.map} +1 -1
  257. package/dashboard/dist/assets/{useYamlActivityEvents-BuqvL-cn.js → useYamlActivityEvents-D5T3TbE7.js} +2 -2
  258. package/dashboard/dist/assets/{useYamlActivityEvents-BuqvL-cn.js.map → useYamlActivityEvents-D5T3TbE7.js.map} +1 -1
  259. package/dashboard/dist/assets/users-BEMysNdR.js +2 -0
  260. package/dashboard/dist/assets/users-BEMysNdR.js.map +1 -0
  261. package/dashboard/dist/assets/{vendor-icons-D5ycKPA2.js → vendor-icons--Ivmp-RX.js} +132 -112
  262. package/dashboard/dist/assets/vendor-icons--Ivmp-RX.js.map +1 -0
  263. package/dashboard/dist/assets/{workflows-DF-9Voyi.js → workflows-C4rjvQbI.js} +2 -2
  264. package/dashboard/dist/assets/{workflows-DF-9Voyi.js.map → workflows-C4rjvQbI.js.map} +1 -1
  265. package/dashboard/dist/assets/{yaml-workflows-2roKaSSK.js → yaml-workflows-4rJ5v5rJ.js} +2 -2
  266. package/dashboard/dist/assets/{yaml-workflows-2roKaSSK.js.map → yaml-workflows-4rJ5v5rJ.js.map} +1 -1
  267. package/dashboard/dist/index.html +3 -3
  268. package/docs/api/http/escalations.md +131 -10
  269. package/docs/api/http/roles.md +44 -9
  270. package/docs/api/http/users.md +15 -6
  271. package/docs/api/mcp/admin.md +8 -2
  272. package/docs/api/mcp/human-queue.md +34 -2
  273. package/docs/api/sdk/escalations.md +155 -2
  274. package/docs/api/sdk/roles.md +11 -0
  275. package/docs/api/sdk/users.md +26 -1
  276. package/docs/auth.md +1 -1
  277. package/docs/dashboard.md +5 -4
  278. package/docs/data.md +9 -2
  279. package/docs/faceted-routing.md +221 -0
  280. package/docs/hitl-guide.md +50 -0
  281. package/docs/iam.md +31 -0
  282. package/docs/mcp.md +8 -0
  283. package/package.json +2 -2
  284. package/dashboard/dist/assets/AdminDashboard-LTiYLuzq.js +0 -2
  285. package/dashboard/dist/assets/AgentDetailPage-BSUnDvGp.js.map +0 -1
  286. package/dashboard/dist/assets/AgentsPage-DpS0cCYe.js +0 -2
  287. package/dashboard/dist/assets/AvailableEscalationsPage-BEylRqjP.js +0 -2
  288. package/dashboard/dist/assets/AvailableEscalationsPage-BEylRqjP.js.map +0 -1
  289. package/dashboard/dist/assets/CapabilitiesPage-DLIleX2L.js +0 -2
  290. package/dashboard/dist/assets/CapabilitiesPage-DLIleX2L.js.map +0 -1
  291. package/dashboard/dist/assets/CopyableId-DaT0ZRHg.js +0 -2
  292. package/dashboard/dist/assets/CopyableId-DaT0ZRHg.js.map +0 -1
  293. package/dashboard/dist/assets/DataTable-D9yuBv0w.js.map +0 -1
  294. package/dashboard/dist/assets/FilterBar-Ck4K4rzu.js +0 -2
  295. package/dashboard/dist/assets/FilterBar-Ck4K4rzu.js.map +0 -1
  296. package/dashboard/dist/assets/GraphInvokePage-BZBPBCSq.js +0 -2
  297. package/dashboard/dist/assets/GraphInvokePage-BZBPBCSq.js.map +0 -1
  298. package/dashboard/dist/assets/HomePage-dM7U2tl6.js +0 -2
  299. package/dashboard/dist/assets/HomePage-dM7U2tl6.js.map +0 -1
  300. package/dashboard/dist/assets/McpRunsPage-CPMYWgm_.js +0 -2
  301. package/dashboard/dist/assets/McpRunsPage-CPMYWgm_.js.map +0 -1
  302. package/dashboard/dist/assets/OperatorDashboard-g9o7I925.js +0 -2
  303. package/dashboard/dist/assets/PageHeader-Dk2Pe44Q.js +0 -2
  304. package/dashboard/dist/assets/PageHeader-Dk2Pe44Q.js.map +0 -1
  305. package/dashboard/dist/assets/PriorityBadge-DfQY9St9.js +0 -2
  306. package/dashboard/dist/assets/PriorityBadge-DfQY9St9.js.map +0 -1
  307. package/dashboard/dist/assets/RolePill-Du-aNnjR.js +0 -2
  308. package/dashboard/dist/assets/RolePill-Du-aNnjR.js.map +0 -1
  309. package/dashboard/dist/assets/RolesPage-B2Kdf-L9.js +0 -2
  310. package/dashboard/dist/assets/RolesPage-B2Kdf-L9.js.map +0 -1
  311. package/dashboard/dist/assets/RowActions-Dg-Fsm5O.js +0 -2
  312. package/dashboard/dist/assets/RowActions-Dg-Fsm5O.js.map +0 -1
  313. package/dashboard/dist/assets/StickyPagination-BWhFSr2d.js +0 -2
  314. package/dashboard/dist/assets/StickyPagination-BWhFSr2d.js.map +0 -1
  315. package/dashboard/dist/assets/TimeAgo-CUIYqSt_.js +0 -2
  316. package/dashboard/dist/assets/TopicDetailPage-rh_dsTJI.js.map +0 -1
  317. package/dashboard/dist/assets/TopicsPage-CD_40_v-.js +0 -2
  318. package/dashboard/dist/assets/TopicsPage-CD_40_v-.js.map +0 -1
  319. package/dashboard/dist/assets/WorkflowsDashboard-BgI-iOP6.js +0 -2
  320. package/dashboard/dist/assets/WorkflowsDashboard-BgI-iOP6.js.map +0 -1
  321. package/dashboard/dist/assets/escalation-columns-nVYVt7Gl.js +0 -2
  322. package/dashboard/dist/assets/escalation-columns-nVYVt7Gl.js.map +0 -1
  323. package/dashboard/dist/assets/index-CMviPjXQ.js +0 -9
  324. package/dashboard/dist/assets/index-CMviPjXQ.js.map +0 -1
  325. package/dashboard/dist/assets/index-CP0JEQhZ.js +0 -6
  326. package/dashboard/dist/assets/index-CP0JEQhZ.js.map +0 -1
  327. package/dashboard/dist/assets/index-ClvYSNZd.css +0 -1
  328. package/dashboard/dist/assets/index-D1xVY4JR.js.map +0 -1
  329. package/dashboard/dist/assets/index-DPLy-jwO.js +0 -2
  330. package/dashboard/dist/assets/index-DPLy-jwO.js.map +0 -1
  331. package/dashboard/dist/assets/index-DzVYjoex.js +0 -6
  332. package/dashboard/dist/assets/index-DzVYjoex.js.map +0 -1
  333. package/dashboard/dist/assets/index-FuhiJuHL.js +0 -2
  334. package/dashboard/dist/assets/index-FuhiJuHL.js.map +0 -1
  335. package/dashboard/dist/assets/users-Pn85K_3C.js +0 -2
  336. package/dashboard/dist/assets/users-Pn85K_3C.js.map +0 -1
  337. package/dashboard/dist/assets/vendor-icons-D5ycKPA2.js.map +0 -1
@@ -48,6 +48,7 @@ const userService = __importStar(require("../services/user"));
48
48
  * @param input.role — filter by role name
49
49
  * @param input.roleType — filter by role type (superadmin, admin, member)
50
50
  * @param input.status — filter by user status
51
+ * @param input.search — free-text match on display name, email, or external_id
51
52
  * @param input.limit — maximum number of users to return
52
53
  * @param input.offset — number of users to skip for pagination
53
54
  * @returns `{ status: 200, data: User[] }` on success
@@ -105,6 +106,17 @@ async function createUser(input) {
105
106
  error: 'Each role must have a role name and type (superadmin, admin, member)',
106
107
  };
107
108
  }
109
+ if (r.read_scope !== undefined && !userService.isValidReadScope(r.read_scope)) {
110
+ return { status: 400, error: 'read_scope must be self or all' };
111
+ }
112
+ if (r.write_scope !== undefined && !userService.isValidWriteScope(r.write_scope)) {
113
+ return { status: 400, error: 'write_scope must be none, self, or all' };
114
+ }
115
+ const read = (r.read_scope ?? userService.DEFAULT_READ_SCOPE);
116
+ const write = (r.write_scope ?? userService.DEFAULT_WRITE_SCOPE);
117
+ if (!userService.isValidScopePair(read, write)) {
118
+ return { status: 400, error: 'write_scope=all requires read_scope=all' };
119
+ }
108
120
  }
109
121
  }
110
122
  const user = await userService.createUser({
@@ -201,7 +213,23 @@ async function addUserRole(input) {
201
213
  if (!userService.isValidRoleType(input.type)) {
202
214
  return { status: 400, error: 'type must be superadmin, admin, or member' };
203
215
  }
204
- const result = await userService.addUserRole(input.id, input.role, input.type);
216
+ // Work-surface scope (optional; defaults to all/all = full worker). Only
217
+ // meaningful for `member`; admin/superadmin normalize to all/all.
218
+ if (input.read_scope !== undefined && !userService.isValidReadScope(input.read_scope)) {
219
+ return { status: 400, error: 'read_scope must be self or all' };
220
+ }
221
+ if (input.write_scope !== undefined && !userService.isValidWriteScope(input.write_scope)) {
222
+ return { status: 400, error: 'write_scope must be none, self, or all' };
223
+ }
224
+ const read = (input.read_scope ?? userService.DEFAULT_READ_SCOPE);
225
+ const write = (input.write_scope ?? userService.DEFAULT_WRITE_SCOPE);
226
+ if (!userService.isValidScopePair(read, write)) {
227
+ return { status: 400, error: 'write_scope=all requires read_scope=all (cannot act on what you cannot see)' };
228
+ }
229
+ const result = await userService.addUserRole(input.id, input.role, input.type, {
230
+ read_scope: read,
231
+ write_scope: write,
232
+ });
205
233
  return { status: 201, data: result };
206
234
  }
207
235
  catch (err) {
package/build/bin/ltc.js CHANGED
@@ -120,6 +120,13 @@ escCmd.command('list')
120
120
  .option('--status <status>', 'Filter by status (pending, resolved, cancelled)')
121
121
  .option('--role <role>', 'Filter by role')
122
122
  .option('--limit <n>', 'Max results')
123
+ .option('--facets <json>', 'Required metadata facets, JSON object (metadata @>), e.g. \'{"filament":"pla"}\'')
124
+ .option('--block <json>', 'Exclude rows containing ANY of these facet sets, JSON array')
125
+ .option('--range <json>', 'Numeric ranges over facets, JSON array e.g. \'[{"facet":"confidence","op":"<=","value":0.7}]\'')
126
+ .option('--exists <json>', 'Metadata keys that must be present, JSON array of strings')
127
+ .option('--roles <json>', 'Restrict to these roles, JSON array (narrows within scope)')
128
+ .option('--available <bool>', 'true = unclaimed/expired only; false = held now')
129
+ .option('--order-by <json>', 'Sort keys, JSON array e.g. \'[{"field":"metadata.confidence","numeric":true,"direction":"asc"}]\'')
123
130
  .option('--json', 'JSON output')
124
131
  .option('-q, --quiet', 'IDs only')
125
132
  .action(wrap(esc.listEscalations));
@@ -153,6 +160,39 @@ escCmd.command('resolve-by-meta <key> <value>')
153
160
  .option('--assignee <external_id>', 'Resolve on behalf of user (external_id)')
154
161
  .option('--meta <json>', 'Merge metadata (JSON object)')
155
162
  .action(wrap(esc.resolveByMetadata));
163
+ escCmd.command('resolve-by-ids <ids...>')
164
+ .description('Resolve a set of escalations by id')
165
+ .requiredOption('--payload <json>', 'Resolver payload (JSON string)')
166
+ .option('--metadata <json>', 'Merge metadata (JSON object)')
167
+ .action(wrap(esc.resolveByIds));
168
+ escCmd.command('search-facets')
169
+ .description('Item-level faceted search over a pond (role-scoped)')
170
+ .requiredOption('--role <role>', 'Pond role to search')
171
+ .option('--status <status>', 'Filter by status')
172
+ .option('--available', 'Only available (unclaimed/expired)')
173
+ .option('--facets <json>', 'Required facets (JSON object)')
174
+ .option('--limit <n>', 'Max results')
175
+ .option('--json', 'JSON output')
176
+ .option('-q, --quiet', 'IDs only')
177
+ .action(wrap(esc.searchByFacets));
178
+ escCmd.command('claim-groups')
179
+ .description('Batch-claim complete origin groups in priority order')
180
+ .requiredOption('--role <role>', 'Pond role to claim from')
181
+ .option('--facets <json>', 'Required facets (JSON object)')
182
+ .option('--limit <n>', 'Max groups to claim')
183
+ .option('--duration <minutes>', 'Claim duration in minutes')
184
+ .option('--size-facet <key>', 'Metadata facet declaring group size')
185
+ .option('--json', 'JSON output')
186
+ .action(wrap(esc.claimGroups));
187
+ escCmd.command('claim-by-facets')
188
+ .description('Batch-claim individual rows matching facets')
189
+ .requiredOption('--role <role>', 'Pond role to claim from')
190
+ .option('--facets <json>', 'Required facets (JSON object)')
191
+ .option('--limit <n>', 'Max rows to claim')
192
+ .option('--duration <minutes>', 'Claim duration in minutes')
193
+ .option('--all-or-none', 'Claim all matched rows or none')
194
+ .option('--json', 'JSON output')
195
+ .action(wrap(esc.claimByFacets));
156
196
  // ── Workflows ────────────────────────────────────────────────────────────
157
197
  const wfCmd = commander_1.program.command('workflows').alias('wf').description('Manage durable workflows');
158
198
  wfCmd.command('list')
@@ -4,6 +4,13 @@ interface ListOptions {
4
4
  limit?: string;
5
5
  json?: boolean;
6
6
  quiet?: boolean;
7
+ facets?: string;
8
+ block?: string;
9
+ range?: string;
10
+ exists?: string;
11
+ roles?: string;
12
+ available?: string;
13
+ orderBy?: string;
7
14
  }
8
15
  export declare function listEscalations(opts: ListOptions): Promise<void>;
9
16
  export declare function getEscalation(id: string, opts: {
@@ -27,4 +34,33 @@ export declare function resolveByMetadata(key: string, value: string, opts: {
27
34
  assignee?: string;
28
35
  meta?: string;
29
36
  }): Promise<void>;
37
+ export declare function resolveByIds(ids: string[], opts: {
38
+ payload: string;
39
+ metadata?: string;
40
+ }): Promise<void>;
41
+ export declare function searchByFacets(opts: {
42
+ role: string;
43
+ status?: string;
44
+ available?: boolean;
45
+ facets?: string;
46
+ limit?: string;
47
+ json?: boolean;
48
+ quiet?: boolean;
49
+ }): Promise<void>;
50
+ export declare function claimGroups(opts: {
51
+ role: string;
52
+ facets?: string;
53
+ limit?: string;
54
+ duration?: string;
55
+ sizeFacet?: string;
56
+ json?: boolean;
57
+ }): Promise<void>;
58
+ export declare function claimByFacets(opts: {
59
+ role: string;
60
+ facets?: string;
61
+ limit?: string;
62
+ duration?: string;
63
+ allOrNone?: boolean;
64
+ json?: boolean;
65
+ }): Promise<void>;
30
66
  export {};
@@ -11,6 +11,10 @@ exports.resolveEscalation = resolveEscalation;
11
11
  exports.findByMetadata = findByMetadata;
12
12
  exports.claimByMetadata = claimByMetadata;
13
13
  exports.resolveByMetadata = resolveByMetadata;
14
+ exports.resolveByIds = resolveByIds;
15
+ exports.searchByFacets = searchByFacets;
16
+ exports.claimGroups = claimGroups;
17
+ exports.claimByFacets = claimByFacets;
14
18
  const picocolors_1 = __importDefault(require("picocolors"));
15
19
  const client_1 = require("../client");
16
20
  const format_1 = require("../format");
@@ -30,6 +34,22 @@ async function listEscalations(opts) {
30
34
  params.set('role', opts.role);
31
35
  if (opts.limit)
32
36
  params.set('limit', opts.limit);
37
+ // Faceted query elements travel as JSON-encoded query params (the route JSON-parses
38
+ // them). parseJsonOption validates the input and throws a friendly error on bad JSON.
39
+ if (opts.facets)
40
+ params.set('facets', JSON.stringify(parseJsonOption('--facets', opts.facets)));
41
+ if (opts.block)
42
+ params.set('block', JSON.stringify(parseJsonOption('--block', opts.block)));
43
+ if (opts.range)
44
+ params.set('range', JSON.stringify(parseJsonOption('--range', opts.range)));
45
+ if (opts.exists)
46
+ params.set('exists', JSON.stringify(parseJsonOption('--exists', opts.exists)));
47
+ if (opts.roles)
48
+ params.set('roles', JSON.stringify(parseJsonOption('--roles', opts.roles)));
49
+ if (opts.orderBy)
50
+ params.set('orderBy', JSON.stringify(parseJsonOption('--order-by', opts.orderBy)));
51
+ if (opts.available != null)
52
+ params.set('available', opts.available);
33
53
  const data = await (0, client_1.apiFetch)(`/escalations?${params}`);
34
54
  (0, format_1.output)(data, data.escalations || [], COLUMNS, opts);
35
55
  }
@@ -107,3 +127,81 @@ async function resolveByMetadata(key, value, opts) {
107
127
  });
108
128
  console.log(`\n ${picocolors_1.default.green('✓')} Resolved by ${key}=${value}\n`);
109
129
  }
130
+ // --- Faceted routing commands -----------------------------------------------
131
+ function parseJsonOption(label, raw) {
132
+ try {
133
+ return JSON.parse(raw);
134
+ }
135
+ catch {
136
+ throw new Error(`Invalid JSON for ${label}: ${raw}`);
137
+ }
138
+ }
139
+ async function resolveByIds(ids, opts) {
140
+ const resolverPayload = parseJsonOption('--payload', opts.payload);
141
+ const body = { ids, resolverPayload };
142
+ if (opts.metadata)
143
+ body.metadata = parseJsonOption('--metadata', opts.metadata);
144
+ const data = await (0, client_1.apiFetch)('/escalations/resolve-by-ids', {
145
+ method: 'POST',
146
+ body: JSON.stringify(body),
147
+ });
148
+ console.log(`\n ${picocolors_1.default.green('✓')} Resolved ${data.resolved} escalation(s)\n`);
149
+ }
150
+ async function searchByFacets(opts) {
151
+ const query = { role: opts.role };
152
+ if (opts.status)
153
+ query.status = opts.status;
154
+ if (opts.available)
155
+ query.available = true;
156
+ if (opts.facets)
157
+ query.facets = parseJsonOption('--facets', opts.facets);
158
+ if (opts.limit)
159
+ query.limit = parseInt(opts.limit, 10);
160
+ const data = await (0, client_1.apiFetch)('/escalations/search-by-facets', {
161
+ method: 'POST',
162
+ body: JSON.stringify(query),
163
+ });
164
+ (0, format_1.output)(data, data.escalations || [], COLUMNS, opts);
165
+ }
166
+ async function claimGroups(opts) {
167
+ const query = { role: opts.role };
168
+ if (opts.facets)
169
+ query.facets = parseJsonOption('--facets', opts.facets);
170
+ const body = { query };
171
+ if (opts.limit)
172
+ body.limit = parseInt(opts.limit, 10);
173
+ if (opts.duration)
174
+ body.durationMinutes = parseInt(opts.duration, 10);
175
+ if (opts.sizeFacet)
176
+ body.sizeFacet = opts.sizeFacet;
177
+ const data = await (0, client_1.apiFetch)('/escalations/claim-groups', {
178
+ method: 'POST',
179
+ body: JSON.stringify(body),
180
+ });
181
+ if (opts.json) {
182
+ console.log(JSON.stringify(data, null, 2));
183
+ return;
184
+ }
185
+ console.log(`\n ${picocolors_1.default.green('✓')} Claimed ${data.groups?.length || 0} group(s)\n`);
186
+ }
187
+ async function claimByFacets(opts) {
188
+ const query = { role: opts.role };
189
+ if (opts.facets)
190
+ query.facets = parseJsonOption('--facets', opts.facets);
191
+ const body = { query };
192
+ if (opts.limit)
193
+ body.limit = parseInt(opts.limit, 10);
194
+ if (opts.duration)
195
+ body.durationMinutes = parseInt(opts.duration, 10);
196
+ if (opts.allOrNone)
197
+ body.allOrNone = true;
198
+ const data = await (0, client_1.apiFetch)('/escalations/claim-by-facets', {
199
+ method: 'POST',
200
+ body: JSON.stringify(body),
201
+ });
202
+ if (opts.json) {
203
+ console.log(JSON.stringify(data, null, 2));
204
+ return;
205
+ }
206
+ console.log(`\n ${picocolors_1.default.green('✓')} Claimed ${data.claimed?.length || 0} escalation(s)\n`);
207
+ }
@@ -99,11 +99,16 @@ CREATE OR REPLACE TRIGGER lt_users_updated_at
99
99
  -- ─── lt_user_roles ───────────────────────────────────────────────────────────
100
100
 
101
101
  CREATE TABLE IF NOT EXISTS lt_user_roles (
102
- user_id UUID NOT NULL REFERENCES lt_users(id) ON DELETE CASCADE,
103
- role TEXT NOT NULL REFERENCES lt_roles(role),
104
- type TEXT NOT NULL DEFAULT 'member' CHECK (type IN ('superadmin', 'admin', 'member')),
105
- created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
106
- PRIMARY KEY (user_id, role)
102
+ user_id UUID NOT NULL REFERENCES lt_users(id) ON DELETE CASCADE,
103
+ role TEXT NOT NULL REFERENCES lt_roles(role),
104
+ type TEXT NOT NULL DEFAULT 'member' CHECK (type IN ('superadmin', 'admin', 'member')),
105
+ -- Work-surface scope (orthogonal to `type`, ignored for admin/superadmin).
106
+ -- read governs search, write governs claim/ack/delete. write ⊆ read.
107
+ read_scope TEXT NOT NULL DEFAULT 'all' CHECK (read_scope IN ('self', 'all')),
108
+ write_scope TEXT NOT NULL DEFAULT 'all' CHECK (write_scope IN ('none', 'self', 'all')),
109
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
110
+ PRIMARY KEY (user_id, role),
111
+ CONSTRAINT chk_lt_user_roles_scope CHECK (NOT (write_scope = 'all' AND read_scope = 'self'))
107
112
  );
108
113
 
109
114
  CREATE INDEX IF NOT EXISTS idx_lt_user_roles_type ON lt_user_roles (type);
@@ -0,0 +1,20 @@
1
+ -- ─── 012: lt_tasks.workflow_id uniqueness ─────────────────────────────────────
2
+ -- A task is 1:1 with its workflow_id. Every createTask caller keys the row by a
3
+ -- deterministic workflow_id (orchestrator childWorkflowId, interceptor
4
+ -- wf.workflowId, escalation triage-<id>), and createTask runs inside a
5
+ -- proxyActivity with retry { maximumAttempts: 3 }. Without a unique constraint a
6
+ -- retry — or a re-driven triage saga — double-inserts a task row. The unique
7
+ -- index lets createTask use ON CONFLICT (workflow_id) so retries converge instead
8
+ -- of duplicating, matching how HotMesh upserts the sibling job by (workflowId, app_id).
9
+
10
+ -- Collapse any pre-existing duplicates, keeping the most recent row per workflow_id
11
+ -- (tie-break on id so exactly one survives and the unique index can be built).
12
+ DELETE FROM lt_tasks a
13
+ USING lt_tasks b
14
+ WHERE a.workflow_id = b.workflow_id
15
+ AND (a.created_at < b.created_at
16
+ OR (a.created_at = b.created_at AND a.id < b.id));
17
+
18
+ -- Replace the non-unique lookup index with a unique one (it still serves lookups).
19
+ DROP INDEX IF EXISTS idx_lt_tasks_workflow_id;
20
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_lt_tasks_workflow_id ON lt_tasks (workflow_id);
@@ -0,0 +1,37 @@
1
+ -- ─── lt_user_roles: read/write work-surface scope ──────────────────────────
2
+ --
3
+ -- Open roles split the worker capability into two orthogonal axes so that
4
+ -- one-time and limited-surface users are first-class:
5
+ --
6
+ -- read_scope (self | all) → governs SEARCH (which items appear)
7
+ -- write_scope (none | self | all) → governs CLAIM / ACK / DELETE
8
+ --
9
+ -- `self` = escalations assigned to the user (assigned_to = userId); `all` = the
10
+ -- whole role queue. The only constraint is write ⊆ read (you cannot act on what
11
+ -- you cannot see). `type` (member/admin/superadmin) is unchanged — it remains the
12
+ -- management/global tier, and admin/superadmin ignore scope (always act on all).
13
+ --
14
+ -- Existing rows default to ('all','all') = today's `member` behavior, so this is
15
+ -- backward compatible with zero data backfill. Idempotent: no-op on fresh installs
16
+ -- where 001_schema.sql already created the columns and the named constraint.
17
+
18
+ ALTER TABLE lt_user_roles
19
+ ADD COLUMN IF NOT EXISTS read_scope TEXT NOT NULL DEFAULT 'all'
20
+ CHECK (read_scope IN ('self', 'all'));
21
+
22
+ ALTER TABLE lt_user_roles
23
+ ADD COLUMN IF NOT EXISTS write_scope TEXT NOT NULL DEFAULT 'all'
24
+ CHECK (write_scope IN ('none', 'self', 'all'));
25
+
26
+ -- write ⊆ read: cannot act on the whole queue while only reading your own.
27
+ -- Guarded so a re-run (or a fresh install where 001 already added it) is a no-op.
28
+ DO $$
29
+ BEGIN
30
+ IF NOT EXISTS (
31
+ SELECT 1 FROM pg_constraint WHERE conname = 'chk_lt_user_roles_scope'
32
+ ) THEN
33
+ ALTER TABLE lt_user_roles
34
+ ADD CONSTRAINT chk_lt_user_roles_scope
35
+ CHECK (NOT (write_scope = 'all' AND read_scope = 'self'));
36
+ END IF;
37
+ END $$;
@@ -7,10 +7,15 @@
7
7
  */
8
8
  export declare const HOTMESH_VERSION: string;
9
9
  /**
10
- * The long-tail app version. Read from the root package.json at runtime via the
11
- * process working directory (which is the app root in both dev and the Docker
12
- * image, where CMD runs `node build/index.js` from /app). A static
13
- * `../package.json` import would resolve to build/package.json after compile
14
- * a path the Dockerfile does not copy so this reads from cwd instead.
10
+ * The long-tail package version.
11
+ *
12
+ * Resolved from long-tail's OWN package.json by walking up from this module's
13
+ * directory to the first package.json named `@hotmeshio/long-tail`. Reading
14
+ * `process.cwd()/package.json` is wrong when long-tail is consumed as a
15
+ * dependency (e.g. mounted as a NestJS module) — cwd is then the HOST app's
16
+ * root, so it reported the host's version. The upward walk resolves correctly in
17
+ * dev (source tree), the standalone Docker image (`/app`), and under
18
+ * `node_modules/@hotmeshio/long-tail`. A static `../package.json` import can't be
19
+ * used: post-compile it resolves to `build/package.json`, which is not shipped.
15
20
  */
16
21
  export declare const LONG_TAIL_VERSION: string;
@@ -15,20 +15,36 @@ const package_json_1 = __importDefault(require("@hotmeshio/hotmesh/package.json"
15
15
  * node_modules), and resolveJsonModule handles the static import at compile time.
16
16
  */
17
17
  exports.HOTMESH_VERSION = package_json_1.default.version ?? 'unknown';
18
+ const LONG_TAIL_PACKAGE_NAME = '@hotmeshio/long-tail';
18
19
  /**
19
- * The long-tail app version. Read from the root package.json at runtime via the
20
- * process working directory (which is the app root in both dev and the Docker
21
- * image, where CMD runs `node build/index.js` from /app). A static
22
- * `../package.json` import would resolve to build/package.json after compile
23
- * a path the Dockerfile does not copy so this reads from cwd instead.
20
+ * The long-tail package version.
21
+ *
22
+ * Resolved from long-tail's OWN package.json by walking up from this module's
23
+ * directory to the first package.json named `@hotmeshio/long-tail`. Reading
24
+ * `process.cwd()/package.json` is wrong when long-tail is consumed as a
25
+ * dependency (e.g. mounted as a NestJS module) — cwd is then the HOST app's
26
+ * root, so it reported the host's version. The upward walk resolves correctly in
27
+ * dev (source tree), the standalone Docker image (`/app`), and under
28
+ * `node_modules/@hotmeshio/long-tail`. A static `../package.json` import can't be
29
+ * used: post-compile it resolves to `build/package.json`, which is not shipped.
24
30
  */
25
31
  exports.LONG_TAIL_VERSION = readLongTailVersion();
26
32
  function readLongTailVersion() {
27
- try {
28
- const raw = (0, fs_1.readFileSync)((0, path_1.resolve)(process.cwd(), 'package.json'), 'utf8');
29
- return JSON.parse(raw).version ?? 'unknown';
30
- }
31
- catch {
32
- return 'unknown';
33
+ let dir = __dirname;
34
+ const { root } = (0, path_1.parse)(dir);
35
+ // eslint-disable-next-line no-constant-condition
36
+ while (true) {
37
+ try {
38
+ const pkg = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(dir, 'package.json'), 'utf8'));
39
+ if (pkg.name === LONG_TAIL_PACKAGE_NAME)
40
+ return pkg.version ?? 'unknown';
41
+ }
42
+ catch {
43
+ /* no readable package.json here — keep walking up */
44
+ }
45
+ if (dir === root)
46
+ break;
47
+ dir = (0, path_1.dirname)(dir);
33
48
  }
49
+ return 'unknown';
34
50
  }
@@ -0,0 +1,7 @@
1
+ import { Router } from 'express';
2
+ /**
3
+ * Faceted-routing HTTP surface — pond search + batch claim. Each operation targets a
4
+ * single pond `role` and is RBAC-scoped to it (the api layer enforces the gate). These
5
+ * mirror the SDK `escalations.searchByFacets / claimGroups / claimByFacets`.
6
+ */
7
+ export declare function registerFacetRoutes(router: Router): void;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.registerFacetRoutes = registerFacetRoutes;
37
+ const api = __importStar(require("../../api/escalations"));
38
+ /**
39
+ * Faceted-routing HTTP surface — pond search + batch claim. Each operation targets a
40
+ * single pond `role` and is RBAC-scoped to it (the api layer enforces the gate). These
41
+ * mirror the SDK `escalations.searchByFacets / claimGroups / claimByFacets`.
42
+ */
43
+ function registerFacetRoutes(router) {
44
+ /**
45
+ * POST /api/escalations/search-by-facets
46
+ * Item-level faceted search over a pond, scoped to the caller's role.
47
+ * Body: FacetQuery — { role, status?, available?, facets?, orderBy?, limit?, offset? }
48
+ */
49
+ router.post('/search-by-facets', async (req, res) => {
50
+ const result = await api.searchByFacets(req.body ?? {}, req.auth);
51
+ res.status(result.status).json(result.data ?? { error: result.error });
52
+ });
53
+ /**
54
+ * POST /api/escalations/claim-groups
55
+ * Batch-claim complete origin groups in priority order, assigned to the caller.
56
+ * Body: { query: FacetQuery, limit?, durationMinutes?, sizeFacet? }
57
+ */
58
+ router.post('/claim-groups', async (req, res) => {
59
+ const result = await api.claimGroups({
60
+ query: req.body?.query,
61
+ limit: req.body?.limit,
62
+ durationMinutes: req.body?.durationMinutes,
63
+ sizeFacet: req.body?.sizeFacet,
64
+ }, req.auth);
65
+ res.status(result.status).json(result.data ?? { error: result.error });
66
+ });
67
+ /**
68
+ * POST /api/escalations/claim-by-facets
69
+ * Batch-claim individual rows (FOR UPDATE SKIP LOCKED), assigned to the caller.
70
+ * Body: { query: FacetQuery, limit?, durationMinutes?, allOrNone? }
71
+ */
72
+ router.post('/claim-by-facets', async (req, res) => {
73
+ const result = await api.claimByFacets({
74
+ query: req.body?.query,
75
+ limit: req.body?.limit,
76
+ durationMinutes: req.body?.durationMinutes,
77
+ allOrNone: req.body?.allOrNone,
78
+ }, req.auth);
79
+ res.status(result.status).json(result.data ?? { error: result.error });
80
+ });
81
+ }
@@ -6,6 +6,7 @@ const bulk_1 = require("./bulk");
6
6
  const metadata_1 = require("./metadata");
7
7
  const single_1 = require("./single");
8
8
  const resolve_1 = require("./resolve");
9
+ const facets_1 = require("./facets");
9
10
  const router = (0, express_1.Router)();
10
11
  // Registration order matters: literal paths before parameterized /:id routes.
11
12
  // GET /, /available, /types, /stats
@@ -15,6 +16,8 @@ const router = (0, express_1.Router)();
15
16
  (0, bulk_1.registerBulkRoutes)(router);
16
17
  // GET /by-metadata, POST /claim-by-metadata, POST /resolve-by-metadata
17
18
  (0, metadata_1.registerMetadataRoutes)(router);
19
+ // POST /search-by-facets, /claim-groups, /claim-by-facets
20
+ (0, facets_1.registerFacetRoutes)(router);
18
21
  // PATCH /:id/escalate, GET /by-workflow/:workflowId,
19
22
  // GET /:id, POST /:id/claim, POST /:id/release
20
23
  (0, single_1.registerSingleRoutes)(router);
@@ -35,6 +35,21 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.registerListRoutes = registerListRoutes;
37
37
  const api = __importStar(require("../../api/escalations"));
38
+ /**
39
+ * Parse a JSON-encoded query param (facets/block/range/exists/orderBy/roles) so the
40
+ * full faceted query rides on a GET URL — keeps the dashboard's copy-URL/curl path
41
+ * reproducible. Returns undefined on absent/invalid JSON (never throws to the caller).
42
+ */
43
+ function jsonParam(v) {
44
+ if (typeof v !== 'string' || !v)
45
+ return undefined;
46
+ try {
47
+ return JSON.parse(v);
48
+ }
49
+ catch {
50
+ return undefined;
51
+ }
52
+ }
38
53
  function registerListRoutes(router) {
39
54
  /**
40
55
  * POST /api/escalations
@@ -55,6 +70,13 @@ function registerListRoutes(router) {
55
70
  envelope: req.body?.envelope,
56
71
  metadata: req.body?.metadata,
57
72
  escalation_payload: req.body?.escalation_payload,
73
+ // Workflow-linkage (optional): an advert for a running workflow.
74
+ origin_id: req.body?.origin_id,
75
+ parent_id: req.body?.parent_id,
76
+ task_id: req.body?.task_id,
77
+ workflow_id: req.body?.workflow_id,
78
+ task_queue: req.body?.task_queue,
79
+ workflow_type: req.body?.workflow_type,
58
80
  }, req.auth);
59
81
  res.status(result.status).json(result.data ?? { error: result.error });
60
82
  });
@@ -77,6 +99,14 @@ function registerListRoutes(router) {
77
99
  sort_by: req.query.sort_by,
78
100
  order: req.query.order,
79
101
  search: req.query.search,
102
+ // Faceted query elements (JSON-encoded on the URL).
103
+ roles: jsonParam(req.query.roles),
104
+ facets: jsonParam(req.query.facets),
105
+ block: jsonParam(req.query.block),
106
+ range: jsonParam(req.query.range),
107
+ exists: jsonParam(req.query.exists),
108
+ orderBy: jsonParam(req.query.orderBy),
109
+ available: req.query.available != null ? req.query.available === 'true' : undefined,
80
110
  }, req.auth);
81
111
  res.status(result.status).json(result.data ?? { error: result.error });
82
112
  });
@@ -96,6 +126,13 @@ function registerListRoutes(router) {
96
126
  sort_by: req.query.sort_by,
97
127
  order: req.query.order,
98
128
  search: req.query.search,
129
+ // Faceted query elements (JSON-encoded on the URL).
130
+ roles: jsonParam(req.query.roles),
131
+ facets: jsonParam(req.query.facets),
132
+ block: jsonParam(req.query.block),
133
+ range: jsonParam(req.query.range),
134
+ exists: jsonParam(req.query.exists),
135
+ orderBy: jsonParam(req.query.orderBy),
99
136
  }, req.auth);
100
137
  res.status(result.status).json(result.data ?? { error: result.error });
101
138
  });
@@ -107,6 +144,15 @@ function registerListRoutes(router) {
107
144
  const result = await api.listDistinctTypes();
108
145
  res.status(result.status).json(result.data ?? { error: result.error });
109
146
  });
147
+ /**
148
+ * GET /api/escalations/facet-keys
149
+ * Distinct top-level metadata facet keys visible to the caller (role-scoped).
150
+ * Powers the faceted-query UI's key autocomplete.
151
+ */
152
+ router.get('/facet-keys', async (req, res) => {
153
+ const result = await api.listFacetKeys(undefined, req.auth);
154
+ res.status(result.status).json(result.data ?? { error: result.error });
155
+ });
110
156
  /**
111
157
  * GET /api/escalations/stats
112
158
  * Aggregated escalation statistics.
@@ -42,10 +42,28 @@ function registerResolveRoutes(router) {
42
42
  * waiting workflow in place. For webhook callers that know the deterministic
43
43
  * signal id. Literal single-segment path — registered before /:id/resolve so
44
44
  * it is never shadowed by the parameterized route.
45
- * Body: { signalKey: string, resolverPayload: Record<string, any> }
45
+ * Body: { signalKey: string, resolverPayload: Record<string, any>, metadata?: Record<string, any> }
46
46
  */
47
47
  router.post('/resolve-by-signal-key', async (req, res) => {
48
- const result = await api.resolveBySignalKey({ signalKey: req.body?.signalKey, resolverPayload: req.body?.resolverPayload }, req.auth);
48
+ const result = await api.resolveBySignalKey({
49
+ signalKey: req.body?.signalKey,
50
+ resolverPayload: req.body?.resolverPayload,
51
+ metadata: req.body?.metadata,
52
+ }, req.auth);
53
+ res.status(result.status).json(result.data ?? { error: result.error });
54
+ });
55
+ /**
56
+ * POST /api/escalations/resolve-by-ids
57
+ * Resolve a SET of escalations by id in one guarded statement (set-based sibling of
58
+ * /:id/resolve). RBAC: scoped callers may only resolve rows whose role they hold.
59
+ * Body: { ids: string[], resolverPayload: Record<string, any>, metadata?: Record<string, any> }
60
+ */
61
+ router.post('/resolve-by-ids', async (req, res) => {
62
+ const result = await api.resolveByIds({
63
+ ids: req.body?.ids,
64
+ resolverPayload: req.body?.resolverPayload,
65
+ metadata: req.body?.metadata,
66
+ }, req.auth);
49
67
  res.status(result.status).json(result.data ?? { error: result.error });
50
68
  });
51
69
  /**
@@ -53,10 +71,10 @@ function registerResolveRoutes(router) {
53
71
  * Resolve a pending escalation with a human-provided payload. Routes by
54
72
  * escalation shape: efficient (signal_key) resumes the job in place; legacy
55
73
  * paths signal via routing metadata or re-run the original workflow.
56
- * Body: { resolverPayload: Record<string, any> }
74
+ * Body: { resolverPayload: Record<string, any>, metadata?: Record<string, any> }
57
75
  */
58
76
  router.post('/:id/resolve', async (req, res) => {
59
- const result = await api.resolveEscalation({ id: req.params.id, resolverPayload: req.body?.resolverPayload }, req.auth);
77
+ const result = await api.resolveEscalation({ id: req.params.id, resolverPayload: req.body?.resolverPayload, metadata: req.body?.metadata }, req.auth);
60
78
  res.status(result.status).json(result.data ?? { error: result.error });
61
79
  });
62
80
  }