@hotmeshio/long-tail 0.5.11 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (350) hide show
  1. package/README.md +1 -0
  2. package/build/api/diagnostics.d.ts +5 -0
  3. package/build/api/diagnostics.js +5 -1
  4. package/build/api/escalations/bulk.js +9 -1
  5. package/build/api/escalations/cancel.js +5 -7
  6. package/build/api/escalations/claim.js +18 -15
  7. package/build/api/escalations/create.d.ts +6 -0
  8. package/build/api/escalations/create.js +11 -8
  9. package/build/api/escalations/facets.d.ts +18 -0
  10. package/build/api/escalations/facets.js +115 -0
  11. package/build/api/escalations/helpers.d.ts +70 -1
  12. package/build/api/escalations/helpers.js +101 -7
  13. package/build/api/escalations/index.d.ts +3 -2
  14. package/build/api/escalations/index.js +7 -1
  15. package/build/api/escalations/list.d.ts +23 -2
  16. package/build/api/escalations/list.js +111 -10
  17. package/build/api/escalations/metadata.js +22 -27
  18. package/build/api/escalations/resolve.d.ts +19 -1
  19. package/build/api/escalations/resolve.js +111 -26
  20. package/build/api/escalations/single.js +8 -8
  21. package/build/api/settings.d.ts +1 -1
  22. package/build/api/settings.js +3 -1
  23. package/build/api/users.d.ts +6 -0
  24. package/build/api/users.js +29 -1
  25. package/build/api/workflows/invocation.d.ts +6 -0
  26. package/build/api/workflows/invocation.js +6 -2
  27. package/build/bin/ltc.js +40 -0
  28. package/build/lib/cli/commands/escalations.d.ts +36 -0
  29. package/build/lib/cli/commands/escalations.js +98 -0
  30. package/build/lib/db/schemas/001_schema.sql +10 -5
  31. package/build/lib/db/schemas/012_lt_tasks_workflow_id_unique.sql +20 -0
  32. package/build/lib/db/schemas/013_role_scope.sql +37 -0
  33. package/build/modules/features.d.ts +19 -0
  34. package/build/modules/features.js +16 -0
  35. package/build/modules/version.d.ts +10 -5
  36. package/build/modules/version.js +27 -11
  37. package/build/routes/diagnostics.js +15 -2
  38. package/build/routes/escalations/facets.d.ts +7 -0
  39. package/build/routes/escalations/facets.js +81 -0
  40. package/build/routes/escalations/index.js +3 -0
  41. package/build/routes/escalations/list.js +48 -0
  42. package/build/routes/escalations/resolve.js +22 -4
  43. package/build/routes/users.js +9 -5
  44. package/build/routes/workflows/invocation.js +12 -4
  45. package/build/sdk/index.d.ts +35 -2
  46. package/build/sdk/index.js +7 -0
  47. package/build/services/diagnostics/index.d.ts +40 -6
  48. package/build/services/diagnostics/index.js +54 -5
  49. package/build/services/escalation/crud.d.ts +56 -6
  50. package/build/services/escalation/crud.js +102 -31
  51. package/build/services/escalation/facet-sql.d.ts +18 -0
  52. package/build/services/escalation/facet-sql.js +118 -0
  53. package/build/services/escalation/facets.d.ts +45 -0
  54. package/build/services/escalation/facets.js +218 -0
  55. package/build/services/escalation/index.d.ts +1 -0
  56. package/build/services/escalation/index.js +8 -1
  57. package/build/services/escalation/queries.d.ts +47 -0
  58. package/build/services/escalation/queries.js +185 -2
  59. package/build/services/escalation/sql.d.ts +15 -2
  60. package/build/services/escalation/sql.js +80 -3
  61. package/build/services/interceptor/activities/escalation.d.ts +2 -0
  62. package/build/services/interceptor/activities/escalation.js +1 -1
  63. package/build/services/interceptor/lifecycle.js +4 -0
  64. package/build/services/mcp/server-tools.js +10 -4
  65. package/build/services/orchestrator/condition.js +6 -2
  66. package/build/services/role/index.js +2 -3
  67. package/build/services/role/sql.d.ts +8 -0
  68. package/build/services/role/sql.js +17 -1
  69. package/build/services/task/crud.js +22 -14
  70. package/build/services/task/process.js +3 -21
  71. package/build/services/task/resolve.d.ts +5 -3
  72. package/build/services/task/resolve.js +9 -6
  73. package/build/services/task/sql.d.ts +30 -2
  74. package/build/services/task/sql.js +72 -2
  75. package/build/services/user/crud.d.ts +1 -0
  76. package/build/services/user/crud.js +29 -11
  77. package/build/services/user/index.d.ts +2 -1
  78. package/build/services/user/index.js +12 -1
  79. package/build/services/user/rbac.d.ts +18 -0
  80. package/build/services/user/rbac.js +27 -0
  81. package/build/services/user/roles.d.ts +7 -2
  82. package/build/services/user/roles.js +21 -5
  83. package/build/services/user/scope.d.ts +22 -0
  84. package/build/services/user/scope.js +50 -0
  85. package/build/services/user/seed-admin.js +34 -17
  86. package/build/services/user/sql.d.ts +18 -7
  87. package/build/services/user/sql.js +38 -13
  88. package/build/services/user/sso-provision.js +41 -24
  89. package/build/services/user/types.d.ts +9 -5
  90. package/build/start/adapters.js +3 -0
  91. package/build/system/mcp-servers/admin/diagnostics.d.ts +5 -4
  92. package/build/system/mcp-servers/admin/diagnostics.js +12 -10
  93. package/build/system/mcp-servers/admin/escalations.d.ts +6 -0
  94. package/build/system/mcp-servers/admin/escalations.js +247 -54
  95. package/build/system/mcp-servers/admin/index.js +3 -3
  96. package/build/system/mcp-servers/admin/schemas.d.ts +417 -3
  97. package/build/system/mcp-servers/admin/schemas.js +101 -5
  98. package/build/system/mcp-servers/admin/users.js +28 -2
  99. package/build/system/mcp-servers/admin/workflows.js +23 -12
  100. package/build/system/seed/tool-manifests-admin.d.ts +1324 -562
  101. package/build/system/seed/tool-manifests-admin.js +10 -2
  102. package/build/tsconfig.tsbuildinfo +1 -1
  103. package/build/types/envelope.d.ts +7 -0
  104. package/build/types/facets.d.ts +60 -0
  105. package/build/types/facets.js +10 -0
  106. package/build/types/index.d.ts +2 -1
  107. package/build/types/startup.d.ts +9 -0
  108. package/build/types/user.d.ts +11 -0
  109. package/dashboard/dist/assets/AdminDashboard-2CZ8py9X.js +2 -0
  110. package/dashboard/dist/assets/{AdminDashboard-DZpduYdW.js.map → AdminDashboard-2CZ8py9X.js.map} +1 -1
  111. package/dashboard/dist/assets/{AgentConfigPage-SFnHMIP6.js → AgentConfigPage-D68sodgo.js} +7 -7
  112. package/dashboard/dist/assets/{AgentConfigPage-SFnHMIP6.js.map → AgentConfigPage-D68sodgo.js.map} +1 -1
  113. package/dashboard/dist/assets/AgentDetailPage-BmhuWbKi.js +4 -0
  114. package/dashboard/dist/assets/AgentDetailPage-BmhuWbKi.js.map +1 -0
  115. package/dashboard/dist/assets/AgentsPage-C4SKQVeU.js +2 -0
  116. package/dashboard/dist/assets/AgentsPage-C4SKQVeU.js.map +1 -0
  117. package/dashboard/dist/assets/AvailableEscalationsPage-9RBEYwkt.js +2 -0
  118. package/dashboard/dist/assets/AvailableEscalationsPage-9RBEYwkt.js.map +1 -0
  119. package/dashboard/dist/assets/{BotPicker-Dse2jW4b.js → BotPicker-D-FvXJOM.js} +2 -2
  120. package/dashboard/dist/assets/{BotPicker-Dse2jW4b.js.map → BotPicker-D-FvXJOM.js.map} +1 -1
  121. package/dashboard/dist/assets/CapabilitiesPage-ByDf6WJr.js +2 -0
  122. package/dashboard/dist/assets/{CapabilitiesPage-DTfKCzBQ.js.map → CapabilitiesPage-ByDf6WJr.js.map} +1 -1
  123. package/dashboard/dist/assets/{CollapsibleSection-8vf38J6K.js → CollapsibleSection-BjGNYEvh.js} +2 -2
  124. package/dashboard/dist/assets/{CollapsibleSection-8vf38J6K.js.map → CollapsibleSection-BjGNYEvh.js.map} +1 -1
  125. package/dashboard/dist/assets/CopyableId-blg-gZvT.js +2 -0
  126. package/dashboard/dist/assets/CopyableId-blg-gZvT.js.map +1 -0
  127. package/dashboard/dist/assets/{CredentialsPage-7C4M-hrH.js → CredentialsPage-DvCA-wQN.js} +2 -2
  128. package/dashboard/dist/assets/{CredentialsPage-7C4M-hrH.js.map → CredentialsPage-DvCA-wQN.js.map} +1 -1
  129. package/dashboard/dist/assets/{CronLabel-DrGWtaSY.js → CronLabel-DBMurd_c.js} +2 -2
  130. package/dashboard/dist/assets/{CronLabel-DrGWtaSY.js.map → CronLabel-DBMurd_c.js.map} +1 -1
  131. package/dashboard/dist/assets/{CustomDurationPicker-Vcmr4LiR.js → CustomDurationPicker-DHflFoEa.js} +2 -2
  132. package/dashboard/dist/assets/{CustomDurationPicker-Vcmr4LiR.js.map → CustomDurationPicker-DHflFoEa.js.map} +1 -1
  133. package/dashboard/dist/assets/{DropZone-Dwpgbueb.js → DropZone-CUtdp99Z.js} +2 -2
  134. package/dashboard/dist/assets/{DropZone-Dwpgbueb.js.map → DropZone-CUtdp99Z.js.map} +1 -1
  135. package/dashboard/dist/assets/{ElapsedCell-BNexhR5d.js → ElapsedCell-CSjcVOpo.js} +2 -2
  136. package/dashboard/dist/assets/{ElapsedCell-BNexhR5d.js.map → ElapsedCell-CSjcVOpo.js.map} +1 -1
  137. package/dashboard/dist/assets/{EscalationsOverview-BI3DEwYP.js → EscalationsOverview-BUqRNJbK.js} +2 -2
  138. package/dashboard/dist/assets/{EscalationsOverview-BI3DEwYP.js.map → EscalationsOverview-BUqRNJbK.js.map} +1 -1
  139. package/dashboard/dist/assets/{EventTable-CwvX_L9t.js → EventTable-Chz-6XPE.js} +2 -2
  140. package/dashboard/dist/assets/{EventTable-CwvX_L9t.js.map → EventTable-Chz-6XPE.js.map} +1 -1
  141. package/dashboard/dist/assets/{GraphInvokePage-C-3b8WK0.js → GraphInvokePage-BXdgciWg.js} +2 -2
  142. package/dashboard/dist/assets/{GraphInvokePage-C-3b8WK0.js.map → GraphInvokePage-BXdgciWg.js.map} +1 -1
  143. package/dashboard/dist/assets/{HomePage-BS_-jcHr.js → HomePage-CEMxnk0r.js} +2 -2
  144. package/dashboard/dist/assets/{HomePage-BS_-jcHr.js.map → HomePage-CEMxnk0r.js.map} +1 -1
  145. package/dashboard/dist/assets/{ListToolbar-BH9rwQVE.js → ListToolbar-_73JCdbB.js} +2 -2
  146. package/dashboard/dist/assets/{ListToolbar-BH9rwQVE.js.map → ListToolbar-_73JCdbB.js.map} +1 -1
  147. package/dashboard/dist/assets/{McpOverview-C9iOdE7E.js → McpOverview-DfdqxhSz.js} +2 -2
  148. package/dashboard/dist/assets/{McpOverview-C9iOdE7E.js.map → McpOverview-DfdqxhSz.js.map} +1 -1
  149. package/dashboard/dist/assets/{McpQueryDetailPage-DMN-yqvJ.js → McpQueryDetailPage-DPAljieY.js} +2 -2
  150. package/dashboard/dist/assets/{McpQueryDetailPage-DMN-yqvJ.js.map → McpQueryDetailPage-DPAljieY.js.map} +1 -1
  151. package/dashboard/dist/assets/McpQueryPage-D5cSziYS.js +2 -0
  152. package/dashboard/dist/assets/McpQueryPage-D5cSziYS.js.map +1 -0
  153. package/dashboard/dist/assets/{McpRunDetailPage-Wb47sRvo.js → McpRunDetailPage-DwNb9wZg.js} +2 -2
  154. package/dashboard/dist/assets/{McpRunDetailPage-Wb47sRvo.js.map → McpRunDetailPage-DwNb9wZg.js.map} +1 -1
  155. package/dashboard/dist/assets/McpRunsPage-O5H6yStl.js +2 -0
  156. package/dashboard/dist/assets/McpRunsPage-O5H6yStl.js.map +1 -0
  157. package/dashboard/dist/assets/{NamespacePill-DnJl4Lre.js → NamespacePill-uW-xOedj.js} +2 -2
  158. package/dashboard/dist/assets/{NamespacePill-DnJl4Lre.js.map → NamespacePill-uW-xOedj.js.map} +1 -1
  159. package/dashboard/dist/assets/OperatorDashboard-DYw9Ekv5.js +2 -0
  160. package/dashboard/dist/assets/OperatorDashboard-DYw9Ekv5.js.map +1 -0
  161. package/dashboard/dist/assets/PageHeader-DVOZjBfL.js +2 -0
  162. package/dashboard/dist/assets/PageHeader-DVOZjBfL.js.map +1 -0
  163. package/dashboard/dist/assets/{PageHeaderWithStats-BuKc9MKt.js → PageHeaderWithStats-DtTpDHOd.js} +2 -2
  164. package/dashboard/dist/assets/{PageHeaderWithStats-BuKc9MKt.js.map → PageHeaderWithStats-DtTpDHOd.js.map} +1 -1
  165. package/dashboard/dist/assets/PriorityBadge-B4ykBH7f.js +2 -0
  166. package/dashboard/dist/assets/PriorityBadge-B4ykBH7f.js.map +1 -0
  167. package/dashboard/dist/assets/{ProcessDetailPage-CvPx-h8y.js → ProcessDetailPage-B0Dokcx9.js} +2 -2
  168. package/dashboard/dist/assets/{ProcessDetailPage-CvPx-h8y.js.map → ProcessDetailPage-B0Dokcx9.js.map} +1 -1
  169. package/dashboard/dist/assets/ProcessesListPage-Cc87WIjL.js +2 -0
  170. package/dashboard/dist/assets/ProcessesListPage-Cc87WIjL.js.map +1 -0
  171. package/dashboard/dist/assets/RolePill-BaW-30TC.js +2 -0
  172. package/dashboard/dist/assets/RolePill-BaW-30TC.js.map +1 -0
  173. package/dashboard/dist/assets/{RolesPage-W5ZjOHpg.js → RolesPage-cp6PiF08.js} +2 -2
  174. package/dashboard/dist/assets/{RolesPage-W5ZjOHpg.js.map → RolesPage-cp6PiF08.js.map} +1 -1
  175. package/dashboard/dist/assets/RowActions-BA9L9djf.js +2 -0
  176. package/dashboard/dist/assets/RowActions-BA9L9djf.js.map +1 -0
  177. package/dashboard/dist/assets/{RunAsSelector-CvxGTNGT.js → RunAsSelector-2LWkjSnO.js} +2 -2
  178. package/dashboard/dist/assets/{RunAsSelector-CvxGTNGT.js.map → RunAsSelector-2LWkjSnO.js.map} +1 -1
  179. package/dashboard/dist/assets/{StickyPagination-BWhFSr2d.js → StickyPagination-BQEm--kI.js} +2 -2
  180. package/dashboard/dist/assets/{StickyPagination-BWhFSr2d.js.map → StickyPagination-BQEm--kI.js.map} +1 -1
  181. package/dashboard/dist/assets/StreamMessageDetail-BTtw3GjX.js +2 -0
  182. package/dashboard/dist/assets/{StreamMessageDetail-BF0tM0cd.js.map → StreamMessageDetail-BTtw3GjX.js.map} +1 -1
  183. package/dashboard/dist/assets/{SwimlaneTimeline-Bv-KHY9s.js → SwimlaneTimeline-DdXxP4fO.js} +2 -2
  184. package/dashboard/dist/assets/{SwimlaneTimeline-Bv-KHY9s.js.map → SwimlaneTimeline-DdXxP4fO.js.map} +1 -1
  185. package/dashboard/dist/assets/{TagInput-B00uqhjX.js → TagInput-x9XTuqMb.js} +2 -2
  186. package/dashboard/dist/assets/{TagInput-B00uqhjX.js.map → TagInput-x9XTuqMb.js.map} +1 -1
  187. package/dashboard/dist/assets/{TaskDetailPage-Bzb_fuLy.js → TaskDetailPage-B8veYG4X.js} +2 -2
  188. package/dashboard/dist/assets/{TaskDetailPage-Bzb_fuLy.js.map → TaskDetailPage-B8veYG4X.js.map} +1 -1
  189. package/dashboard/dist/assets/{TaskQueuePill-CUsofm0X.js → TaskQueuePill-DSEQZ-HT.js} +2 -2
  190. package/dashboard/dist/assets/{TaskQueuePill-CUsofm0X.js.map → TaskQueuePill-DSEQZ-HT.js.map} +1 -1
  191. package/dashboard/dist/assets/{TasksListPage-CBezWaZL.js → TasksListPage-CsN1gZj5.js} +2 -2
  192. package/dashboard/dist/assets/{TasksListPage-CBezWaZL.js.map → TasksListPage-CsN1gZj5.js.map} +1 -1
  193. package/dashboard/dist/assets/{TimeAgo-CKHfTzat.js → TimeAgo-n182EcLx.js} +2 -2
  194. package/dashboard/dist/assets/{TimeAgo-CKHfTzat.js.map → TimeAgo-n182EcLx.js.map} +1 -1
  195. package/dashboard/dist/assets/{TimestampCell-Dsje8GH-.js → TimestampCell-2dlcQAfX.js} +2 -2
  196. package/dashboard/dist/assets/{TimestampCell-Dsje8GH-.js.map → TimestampCell-2dlcQAfX.js.map} +1 -1
  197. package/dashboard/dist/assets/{ToolPill-DjvedZSn.js → ToolPill-B_e4eT77.js} +2 -2
  198. package/dashboard/dist/assets/{ToolPill-DjvedZSn.js.map → ToolPill-B_e4eT77.js.map} +1 -1
  199. package/dashboard/dist/assets/{ToolTestPanel-3OcG18e5.js → ToolTestPanel-Bhnncc6M.js} +2 -2
  200. package/dashboard/dist/assets/{ToolTestPanel-3OcG18e5.js.map → ToolTestPanel-Bhnncc6M.js.map} +1 -1
  201. package/dashboard/dist/assets/{TopicDetailPage-DCtv91hH.js → TopicDetailPage-29lsNsqI.js} +3 -3
  202. package/dashboard/dist/assets/{TopicDetailPage-DCtv91hH.js.map → TopicDetailPage-29lsNsqI.js.map} +1 -1
  203. package/dashboard/dist/assets/{TopicsPage-DVGSNc_E.js → TopicsPage-KJ7_LAvo.js} +2 -2
  204. package/dashboard/dist/assets/{TopicsPage-DVGSNc_E.js.map → TopicsPage-KJ7_LAvo.js.map} +1 -1
  205. package/dashboard/dist/assets/{UserName-xHAgkk8M.js → UserName-CMoFi9zb.js} +2 -2
  206. package/dashboard/dist/assets/{UserName-xHAgkk8M.js.map → UserName-CMoFi9zb.js.map} +1 -1
  207. package/dashboard/dist/assets/{WorkflowExecutionPage-CWNxsS8a.js → WorkflowExecutionPage-Cymfx-Bp.js} +2 -2
  208. package/dashboard/dist/assets/{WorkflowExecutionPage-CWNxsS8a.js.map → WorkflowExecutionPage-Cymfx-Bp.js.map} +1 -1
  209. package/dashboard/dist/assets/{WorkflowPill-F1oKUzmc.js → WorkflowPill-B66_AnaY.js} +2 -2
  210. package/dashboard/dist/assets/{WorkflowPill-F1oKUzmc.js.map → WorkflowPill-B66_AnaY.js.map} +1 -1
  211. package/dashboard/dist/assets/WorkflowsDashboard-CqLN8spd.js +2 -0
  212. package/dashboard/dist/assets/WorkflowsDashboard-CqLN8spd.js.map +1 -0
  213. package/dashboard/dist/assets/{WorkflowsOverview-e7jWSj_n.js → WorkflowsOverview-0Rc2WT6q.js} +2 -2
  214. package/dashboard/dist/assets/{WorkflowsOverview-e7jWSj_n.js.map → WorkflowsOverview-0Rc2WT6q.js.map} +1 -1
  215. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CdAeam76.js → YamlWorkflowDetailPage-CARQ7_LN.js} +2 -2
  216. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CdAeam76.js.map → YamlWorkflowDetailPage-CARQ7_LN.js.map} +1 -1
  217. package/dashboard/dist/assets/{YamlWorkflowsPage-S_gKs2Di.js → YamlWorkflowsPage-B-7sz1nf.js} +2 -2
  218. package/dashboard/dist/assets/{YamlWorkflowsPage-S_gKs2Di.js.map → YamlWorkflowsPage-B-7sz1nf.js.map} +1 -1
  219. package/dashboard/dist/assets/{agents-JE4aL07D.js → agents-zM43d5Yf.js} +2 -2
  220. package/dashboard/dist/assets/{agents-JE4aL07D.js.map → agents-zM43d5Yf.js.map} +1 -1
  221. package/dashboard/dist/assets/api-path-u2Jf9QXS.js +2 -0
  222. package/dashboard/dist/assets/api-path-u2Jf9QXS.js.map +1 -0
  223. package/dashboard/dist/assets/{bots-cAzKkDtQ.js → bots-D5BasOGz.js} +2 -2
  224. package/dashboard/dist/assets/{bots-cAzKkDtQ.js.map → bots-D5BasOGz.js.map} +1 -1
  225. package/dashboard/dist/assets/{capabilities-RBFXLAXF.js → capabilities-BT3PW9CZ.js} +2 -2
  226. package/dashboard/dist/assets/{capabilities-RBFXLAXF.js.map → capabilities-BT3PW9CZ.js.map} +1 -1
  227. package/dashboard/dist/assets/{controlplane-DGhv3rwI.js → controlplane-NpJr49rN.js} +2 -2
  228. package/dashboard/dist/assets/{controlplane-DGhv3rwI.js.map → controlplane-NpJr49rN.js.map} +1 -1
  229. package/dashboard/dist/assets/{escalation-ne7dIaPa.js → escalation-DrzQolPG.js} +2 -2
  230. package/dashboard/dist/assets/{escalation-ne7dIaPa.js.map → escalation-DrzQolPG.js.map} +1 -1
  231. package/dashboard/dist/assets/escalation-columns-QzwmtD60.js +2 -0
  232. package/dashboard/dist/assets/escalation-columns-QzwmtD60.js.map +1 -0
  233. package/dashboard/dist/assets/index-B5w4Gjyk.js +6 -0
  234. package/dashboard/dist/assets/index-B5w4Gjyk.js.map +1 -0
  235. package/dashboard/dist/assets/{index-CByjpYlU.js → index-BCT4kqGR.js} +2 -2
  236. package/dashboard/dist/assets/{index-CByjpYlU.js.map → index-BCT4kqGR.js.map} +1 -1
  237. package/dashboard/dist/assets/{index-CgyucK0e.js → index-C69XvBfg.js} +2 -2
  238. package/dashboard/dist/assets/{index-CgyucK0e.js.map → index-C69XvBfg.js.map} +1 -1
  239. package/dashboard/dist/assets/index-CHw4Fl0t.css +1 -0
  240. package/dashboard/dist/assets/index-C_NwHTMh.js +2 -0
  241. package/dashboard/dist/assets/index-C_NwHTMh.js.map +1 -0
  242. package/dashboard/dist/assets/{index-DgzgRTNg.js → index-Cq0trGqf.js} +2 -2
  243. package/dashboard/dist/assets/{index-DgzgRTNg.js.map → index-Cq0trGqf.js.map} +1 -1
  244. package/dashboard/dist/assets/{index-DPJW96d2.js → index-DE0r9SEX.js} +26 -26
  245. package/dashboard/dist/assets/index-DE0r9SEX.js.map +1 -0
  246. package/dashboard/dist/assets/{index-BTqhAT6p.js → index-DH_CiD0W.js} +2 -2
  247. package/dashboard/dist/assets/{index-BTqhAT6p.js.map → index-DH_CiD0W.js.map} +1 -1
  248. package/dashboard/dist/assets/{index-C2l4GcZ7.js → index-K23FdS-T.js} +3 -3
  249. package/dashboard/dist/assets/{index-C2l4GcZ7.js.map → index-K23FdS-T.js.map} +1 -1
  250. package/dashboard/dist/assets/index-f6K1UNrn.js +2 -0
  251. package/dashboard/dist/assets/index-f6K1UNrn.js.map +1 -0
  252. package/dashboard/dist/assets/{index-BbJuC9kg.js → index-qr1fndqM.js} +2 -2
  253. package/dashboard/dist/assets/{index-BbJuC9kg.js.map → index-qr1fndqM.js.map} +1 -1
  254. package/dashboard/dist/assets/index-vKTvJ_li.js +2 -0
  255. package/dashboard/dist/assets/index-vKTvJ_li.js.map +1 -0
  256. package/dashboard/dist/assets/{index-CQDn-bLr.js → index-y-3ODtEE.js} +2 -2
  257. package/dashboard/dist/assets/{index-CQDn-bLr.js.map → index-y-3ODtEE.js.map} +1 -1
  258. package/dashboard/dist/assets/{index-QxAYCJ1S.js → index-y56Ds-LB.js} +2 -2
  259. package/dashboard/dist/assets/{index-QxAYCJ1S.js.map → index-y56Ds-LB.js.map} +1 -1
  260. package/dashboard/dist/assets/{knowledge-DzRpsm3D.js → knowledge-DSSATOTX.js} +2 -2
  261. package/dashboard/dist/assets/{knowledge-DzRpsm3D.js.map → knowledge-DSSATOTX.js.map} +1 -1
  262. package/dashboard/dist/assets/{mcp-B1lc6nL4.js → mcp-CfJFVo5k.js} +2 -2
  263. package/dashboard/dist/assets/{mcp-B1lc6nL4.js.map → mcp-CfJFVo5k.js.map} +1 -1
  264. package/dashboard/dist/assets/{mcp-query-CXuweaN3.js → mcp-query-DKVx2Q-X.js} +2 -2
  265. package/dashboard/dist/assets/{mcp-query-CXuweaN3.js.map → mcp-query-DKVx2Q-X.js.map} +1 -1
  266. package/dashboard/dist/assets/{pipelines-D4VLWDvu.js → pipelines-BSWzE-6M.js} +2 -2
  267. package/dashboard/dist/assets/{pipelines-D4VLWDvu.js.map → pipelines-BSWzE-6M.js.map} +1 -1
  268. package/dashboard/dist/assets/{roles-CSpHRRu8.js → roles-t9HzhI5N.js} +2 -2
  269. package/dashboard/dist/assets/{roles-CSpHRRu8.js.map → roles-t9HzhI5N.js.map} +1 -1
  270. package/dashboard/dist/assets/{tasks-CWUsKhM4.js → tasks-B7rUihoH.js} +2 -2
  271. package/dashboard/dist/assets/{tasks-CWUsKhM4.js.map → tasks-B7rUihoH.js.map} +1 -1
  272. package/dashboard/dist/assets/{topics-BXwstrzB.js → topics-PC2fEiyD.js} +2 -2
  273. package/dashboard/dist/assets/{topics-BXwstrzB.js.map → topics-PC2fEiyD.js.map} +1 -1
  274. package/dashboard/dist/assets/useDebouncedValue-BA5S7V54.js +2 -0
  275. package/dashboard/dist/assets/useDebouncedValue-BA5S7V54.js.map +1 -0
  276. package/dashboard/dist/assets/{useEventHooks-CjygrbYy.js → useEventHooks-DK9mw1cI.js} +2 -2
  277. package/dashboard/dist/assets/{useEventHooks-CjygrbYy.js.map → useEventHooks-DK9mw1cI.js.map} +1 -1
  278. package/dashboard/dist/assets/{useNamespace-CsepDyR5.js → useNamespace-3IjtUtAw.js} +2 -2
  279. package/dashboard/dist/assets/{useNamespace-CsepDyR5.js.map → useNamespace-3IjtUtAw.js.map} +1 -1
  280. package/dashboard/dist/assets/{useYamlActivityEvents-gWIG6akB.js → useYamlActivityEvents-uxukp3gO.js} +2 -2
  281. package/dashboard/dist/assets/{useYamlActivityEvents-gWIG6akB.js.map → useYamlActivityEvents-uxukp3gO.js.map} +1 -1
  282. package/dashboard/dist/assets/users-CC4B5Fm5.js +2 -0
  283. package/dashboard/dist/assets/users-CC4B5Fm5.js.map +1 -0
  284. package/dashboard/dist/assets/{vendor-icons-Dj2F0Jrb.js → vendor-icons-Dy5Jpknf.js} +114 -109
  285. package/dashboard/dist/assets/vendor-icons-Dy5Jpknf.js.map +1 -0
  286. package/dashboard/dist/assets/{workflows-C7Cam2Ok.js → workflows-S7MF1nNk.js} +2 -2
  287. package/dashboard/dist/assets/{workflows-C7Cam2Ok.js.map → workflows-S7MF1nNk.js.map} +1 -1
  288. package/dashboard/dist/assets/{yaml-workflows-ChUOE22W.js → yaml-workflows-WfdaMHNn.js} +2 -2
  289. package/dashboard/dist/assets/{yaml-workflows-ChUOE22W.js.map → yaml-workflows-WfdaMHNn.js.map} +1 -1
  290. package/dashboard/dist/index.html +3 -3
  291. package/docs/api/http/escalations.md +131 -10
  292. package/docs/api/http/roles.md +44 -9
  293. package/docs/api/http/users.md +15 -6
  294. package/docs/api/mcp/admin.md +164 -14
  295. package/docs/api/mcp/human-queue.md +34 -2
  296. package/docs/api/sdk/escalations.md +155 -2
  297. package/docs/api/sdk/roles.md +11 -0
  298. package/docs/api/sdk/users.md +26 -1
  299. package/docs/auth.md +1 -1
  300. package/docs/dashboard.md +5 -4
  301. package/docs/data.md +9 -2
  302. package/docs/faceted-routing.md +221 -0
  303. package/docs/hitl-guide.md +50 -0
  304. package/docs/iam.md +31 -0
  305. package/docs/mcp.md +8 -0
  306. package/package.json +2 -2
  307. package/dashboard/dist/assets/AdminDashboard-DZpduYdW.js +0 -2
  308. package/dashboard/dist/assets/AgentDetailPage-C-2iSaDs.js +0 -4
  309. package/dashboard/dist/assets/AgentDetailPage-C-2iSaDs.js.map +0 -1
  310. package/dashboard/dist/assets/AgentsPage-C3FztFd_.js +0 -2
  311. package/dashboard/dist/assets/AgentsPage-C3FztFd_.js.map +0 -1
  312. package/dashboard/dist/assets/AvailableEscalationsPage-DIqdBCwe.js +0 -2
  313. package/dashboard/dist/assets/AvailableEscalationsPage-DIqdBCwe.js.map +0 -1
  314. package/dashboard/dist/assets/CapabilitiesPage-DTfKCzBQ.js +0 -2
  315. package/dashboard/dist/assets/CopyableId-DaT0ZRHg.js +0 -2
  316. package/dashboard/dist/assets/CopyableId-DaT0ZRHg.js.map +0 -1
  317. package/dashboard/dist/assets/McpQueryPage-Db1LUKVs.js +0 -2
  318. package/dashboard/dist/assets/McpQueryPage-Db1LUKVs.js.map +0 -1
  319. package/dashboard/dist/assets/McpRunsPage--tgT5uo7.js +0 -2
  320. package/dashboard/dist/assets/McpRunsPage--tgT5uo7.js.map +0 -1
  321. package/dashboard/dist/assets/OperatorDashboard-BWVUbJkZ.js +0 -2
  322. package/dashboard/dist/assets/OperatorDashboard-BWVUbJkZ.js.map +0 -1
  323. package/dashboard/dist/assets/PageHeader-Bnt2iQQa.js +0 -2
  324. package/dashboard/dist/assets/PageHeader-Bnt2iQQa.js.map +0 -1
  325. package/dashboard/dist/assets/PriorityBadge-DfQY9St9.js +0 -2
  326. package/dashboard/dist/assets/PriorityBadge-DfQY9St9.js.map +0 -1
  327. package/dashboard/dist/assets/ProcessesListPage-CWiRM_h3.js +0 -2
  328. package/dashboard/dist/assets/ProcessesListPage-CWiRM_h3.js.map +0 -1
  329. package/dashboard/dist/assets/RolePill-DQTT1s9v.js +0 -2
  330. package/dashboard/dist/assets/RolePill-DQTT1s9v.js.map +0 -1
  331. package/dashboard/dist/assets/RowActions-Dg-Fsm5O.js +0 -2
  332. package/dashboard/dist/assets/RowActions-Dg-Fsm5O.js.map +0 -1
  333. package/dashboard/dist/assets/StreamMessageDetail-BF0tM0cd.js +0 -2
  334. package/dashboard/dist/assets/WorkflowsDashboard-M13lIaw7.js +0 -2
  335. package/dashboard/dist/assets/WorkflowsDashboard-M13lIaw7.js.map +0 -1
  336. package/dashboard/dist/assets/escalation-columns-DqTkKbCv.js +0 -2
  337. package/dashboard/dist/assets/escalation-columns-DqTkKbCv.js.map +0 -1
  338. package/dashboard/dist/assets/index-CEpw_Fh8.js +0 -2
  339. package/dashboard/dist/assets/index-CEpw_Fh8.js.map +0 -1
  340. package/dashboard/dist/assets/index-ClvYSNZd.css +0 -1
  341. package/dashboard/dist/assets/index-CucXk58o.js +0 -6
  342. package/dashboard/dist/assets/index-CucXk58o.js.map +0 -1
  343. package/dashboard/dist/assets/index-DPJW96d2.js.map +0 -1
  344. package/dashboard/dist/assets/index-DeZhNCf5.js +0 -2
  345. package/dashboard/dist/assets/index-DeZhNCf5.js.map +0 -1
  346. package/dashboard/dist/assets/index-Do8Xp3pa.js +0 -2
  347. package/dashboard/dist/assets/index-Do8Xp3pa.js.map +0 -1
  348. package/dashboard/dist/assets/users-DvhHbR0R.js +0 -2
  349. package/dashboard/dist/assets/users-DvhHbR0R.js.map +0 -1
  350. package/dashboard/dist/assets/vendor-icons-Dj2F0Jrb.js.map +0 -1
package/docs/data.md CHANGED
@@ -74,6 +74,11 @@ backward-compatible **view** over it — `SELECT *` plus a computed `available`
74
74
  column — so existing read queries and the public API are unchanged. Indexes are
75
75
  managed by the SDK on `hmsh_escalations` (see below).
76
76
 
77
+ Role read/write scope does **not** add columns here. An escalation carries a `role`
78
+ and an optional `assigned_to`; work-surface scope lives on the membership table
79
+ (`lt_user_roles`) and is applied at read time. `condition()` / `conditionLT()` and
80
+ the escalation engine are unaffected.
81
+
77
82
  The columns below are the `hmsh_escalations` table. The public API record
78
83
  (`LTEscalationRecord`) is mapped from these: the JSONB `envelope` /
79
84
  `escalation_payload` / `resolver_payload` are serialized to JSON **strings**, and
@@ -179,12 +184,14 @@ Maps users to roles. Each user can hold multiple roles with different permission
179
184
  |--------|------|---------|-------------|
180
185
  | `user_id` | `UUID NOT NULL` | — | FK to `lt_users(id)`, CASCADE on delete |
181
186
  | `role` | `TEXT NOT NULL` | — | Role name (e.g., `reviewer`, `senior-reviewer`) |
182
- | `type` | `TEXT NOT NULL` | `'member'` | `superadmin`, `admin`, or `member` |
187
+ | `type` | `TEXT NOT NULL` | `'member'` | `superadmin`, `admin`, or `member` — the management tier |
188
+ | `read_scope` | `TEXT NOT NULL` | `'all'` | `self` or `all` — search breadth for a `member`: which escalations in the role queue the member sees. `self` = items where `assigned_to = user`; `all` = the whole queue. Ignored for `admin`/`superadmin`, which always see the whole queue. |
189
+ | `write_scope` | `TEXT NOT NULL` | `'all'` | `none`, `self`, or `all` — claim/ack/delete breadth for a `member`. `none` = read-only; `self` = items assigned to the member; `all` = the whole queue. Ignored for `admin`/`superadmin`. |
183
190
  | `created_at` | `TIMESTAMPTZ NOT NULL` | `NOW()` | When the role was assigned |
184
191
 
185
192
  Primary key: `(user_id, role)` — a user can hold each role at most once.
186
193
 
187
- Type is enforced by a CHECK constraint: `type IN ('superadmin', 'admin', 'member')`.
194
+ Type is enforced by a CHECK constraint: `type IN ('superadmin', 'admin', 'member')`. Scope is enforced by CHECK constraints: `read_scope IN ('self', 'all')`, `write_scope IN ('none', 'self', 'all')`, and **write ⊆ read** — `write_scope = 'all'` requires `read_scope = 'all'` (a member cannot act on what it cannot see). Both scopes default to `all`, the full-queue worker.
188
195
 
189
196
  ### lt_bot_api_keys
190
197
 
@@ -0,0 +1,221 @@
1
+ # Faceted Routing
2
+
3
+ The escalation queue is more than a HITL inbox — it is a durable, queryable pool of work
4
+ that any number of consumers can search and atomically claim by its **facets**. Faceted
5
+ routing is the platform surface for that: a composable query language over the queue and a
6
+ set of atomic claim primitives. The platform supplies the surface; the *policy* — what a
7
+ facet means, how capability and priority map onto it, the matching loop — is the consuming
8
+ app's. The [print-routing example](../examples/workflows/print-routing/README.md) is a full
9
+ worked policy built entirely on these primitives.
10
+
11
+ ## Contents
12
+
13
+ - [The model](#the-model)
14
+ - [The query — `FacetQuery`](#the-query--facetquery)
15
+ - [Reads](#reads)
16
+ - [Atomic claims](#atomic-claims)
17
+ - [The dispatcher pattern](#the-dispatcher-pattern)
18
+ - [Recording the outcome on resolve](#recording-the-outcome-on-resolve)
19
+ - [Safety](#safety)
20
+
21
+ ## The model
22
+
23
+ Every escalation row carries a `role` (the hard isolation boundary) and a `metadata` JSONB
24
+ object (the soft facets a late-binding consumer queries, sorts, and claims by). Routing
25
+ work is a funnel over those columns:
26
+
27
+ - **Capability** — the hard wall — is the `role`. A consumer bound to one role can never
28
+ see another role's work. Soft capability is `metadata @>` containment.
29
+ - **Preference / priority** — ordering — is `orderBy` over top-level columns and facets.
30
+ - **Capacity** — how much to take — is the page `limit` of a claim.
31
+
32
+ An **order** (or any multi-unit job) is a set of rows sharing an `origin_id`; its unit
33
+ count lives in a metadata facet so a group can be claimed all-or-nothing only when complete.
34
+
35
+ ## The query — `FacetQuery`
36
+
37
+ ```typescript
38
+ interface FacetQuery {
39
+ role?: string; // hard isolation (exact)
40
+ roles?: string[]; // role = ANY(...)
41
+ facets?: Record<string, any>; // metadata @> facets — required (AND), GIN-served
42
+ block?: Record<string, any>[]; // NOT (metadata @> ANY(block)) — exclusion list
43
+ range?: { facet: string; op: '<' | '<=' | '>' | '>=' | '='; value: number }[];
44
+ exists?: string[]; // metadata ? key — facet must be present
45
+ status?: string; // e.g. 'pending'
46
+ available?: boolean; // true = unclaimed/expired only; false = held now
47
+ orderBy?: { field: string; direction?: 'asc' | 'desc'; numeric?: boolean }[];
48
+ limit?: number;
49
+ offset?: number;
50
+ }
51
+ ```
52
+
53
+ `orderBy.field` is either a whitelisted top-level column (`priority`, `created_at`,
54
+ `updated_at`, `status`, `role`) or a metadata path written as `metadata.<key>` (extracted as
55
+ text, or numeric when `numeric` is set). Every value is parameterized; only validated column
56
+ names / metadata keys and a fixed operator set are ever interpolated.
57
+
58
+ ```typescript
59
+ // Pending, available diabetic-certified work needing PLA, soonest-deadline first.
60
+ const query: FacetQuery = {
61
+ role: 'print-farm-diabetic',
62
+ status: 'pending',
63
+ available: true,
64
+ facets: { filament: 'pla' },
65
+ orderBy: [{ field: 'metadata.mustCompleteBy', numeric: true, direction: 'asc' }],
66
+ };
67
+ ```
68
+
69
+ ## Reads
70
+
71
+ ```typescript
72
+ import { searchByFacets, searchGroups, countByFacets } from '@hotmeshio/long-tail';
73
+
74
+ // Item-level: filter/sort over columns and metadata facets.
75
+ const { escalations, total } = await searchByFacets(query);
76
+
77
+ // Order-level: each row is an origin group with its unit count, availability and
78
+ // completeness — what a batched dispatcher reads to page by capacity.
79
+ const groups = await searchGroups(query, { sizeFacet: 'orderSize', limit: 10 });
80
+
81
+ // Aggregate: capacity / in-flight soft-limit checks.
82
+ const inFlight = await countByFacets({ role: 'print-farm-diabetic', available: false });
83
+ ```
84
+
85
+ ## Atomic claims
86
+
87
+ Two claim primitives, both `FOR UPDATE SKIP LOCKED` so many consumers run without
88
+ contention. Each takes the `FacetQuery`, a `consumer` id, and options.
89
+
90
+ ```typescript
91
+ import { claimGroups, claimByFacets } from '@hotmeshio/long-tail';
92
+
93
+ // Claim whole orders (origin groups), all-or-nothing, in rank order. The page `limit`
94
+ // is how many consumers/printers are free, so a dependent grabs exactly what it can
95
+ // distribute. A group is only eligible when complete (member count = declared size).
96
+ const orders = await claimGroups(query, 'broker-1', { limit: 4, sizeFacet: 'orderSize' });
97
+
98
+ // Claim individual rows by facet — the single-row sibling. Locks up to `limit` available
99
+ // rows in rank order. With { allOrNone: true } the claim commits only when the full limit
100
+ // is acquired, otherwise it rolls back and returns [] — the all-or-none lock a dispatcher
101
+ // wants over a counted set it anticipated.
102
+ const printers = await claimByFacets(
103
+ { role: 'printer-pool-diabetic', facets: { state: 'ready' } },
104
+ 'broker-1',
105
+ { limit: 4 },
106
+ );
107
+ ```
108
+
109
+ A claim sets `assigned_to` + `assigned_until` (default 30 minutes). Availability is a
110
+ query, not a flag: a row is held iff `assigned_to` is set and `assigned_until > NOW()`.
111
+ Resolve, release, or let the claim expire to return it to the pool.
112
+
113
+ ## The dispatcher pattern
114
+
115
+ The primitives compose into a market: pull a *page* of complete orders sized to how many
116
+ consumers are free, then distribute one per consumer. Reads go through the
117
+ `public.lt_escalations` view (it adds the computed `available` flag); atomic claims run on
118
+ the shared `public.hmsh_escalations` table — the same raw-SQL-on-the-shared-table pattern as
119
+ the rest of the escalation service. Metadata facets use the GIN index (`@>`).
120
+
121
+ ```typescript
122
+ // 1. Anticipate supply.
123
+ const free = await searchByFacets({ role: 'printer-pool', available: true, facets: { state: 'ready' } });
124
+ // 2. Claim that much demand by priority.
125
+ const orders = await claimGroups(demandQuery, consumer, { limit: free.escalations.length });
126
+ // 3. Lock the printers for the claimed orders, all-or-none.
127
+ const printers = await claimByFacets(supplyQuery, consumer, { limit: orders.length, allOrNone: true });
128
+ // 4. Pair, do the work, resolve both.
129
+ ```
130
+
131
+ See the [print-routing example](../examples/workflows/print-routing/README.md) for the full
132
+ two-sided market, carry-forward under contention, and the inspection/convergence loop.
133
+
134
+ ## Recording the outcome on resolve
135
+
136
+ A row is created carrying **intent** — the facets that route and claim it. Resolving it can
137
+ record the **outcome** onto the same row: pass a `metadata` patch and it is merged (not
138
+ replaced) into the GIN-indexed metadata in the same atomic UPDATE, on the winning resolve
139
+ only. "What actually happened" becomes `@>`-queryable next to "what was asked".
140
+
141
+ ```typescript
142
+ import { resolveEscalation } from '@hotmeshio/long-tail';
143
+
144
+ // The work is done; resolve the row AND stamp the outcome onto it — one atomic call.
145
+ await resolveEscalation(rowId, { result: 'success' }, {
146
+ outcome: 'success',
147
+ unitsPrinted: 6,
148
+ });
149
+ // Duration needs no facet: the row's own created_at → resolved_at is the elapsed time.
150
+ ```
151
+
152
+ The third argument is distinct from the second: `resolverPayload` (arg 2) is delivered to a
153
+ waiting workflow as `condition()`'s return value and is **not** indexed; the `metadata` patch
154
+ (arg 3) is the durable, queryable record on the row. With both, the row alone answers what was
155
+ asked, what happened, and how long it took:
156
+
157
+ ```typescript
158
+ searchByFacets({ role: 'printer-pool-diabetic', facets: { state: 'printing', outcome: 'success' } });
159
+ // → every completed job: which consumer, which origin, how long — no side table to reconcile
160
+ ```
161
+
162
+ The print farm leans on this: a printer resolves its in-flight `printing` row with the run's
163
+ result and units in one atomic call, so the supply pond is also the production log — and the
164
+ row's `created_at` → `resolved_at` is the print duration, no stored field required.
165
+
166
+ ## The human / operations query
167
+
168
+ The same query language is also the operations team's read surface. Where the dispatcher
169
+ sections above target a **single pond** for a workflow consumer, a **person** — a superadmin, or
170
+ a member of several roles — queries "what work needs doing / was done" across **their** roles by
171
+ the same facets, through the scoped list API.
172
+
173
+ ```typescript
174
+ import { createClient } from '@hotmeshio/long-tail/sdk';
175
+ const lt = createClient({ auth }); // auth carries the caller's userId
176
+
177
+ // Faceted, role-scoped, paginated — the filter AND the count run in SQL.
178
+ const res = await lt.escalations.list({
179
+ status: 'pending',
180
+ facets: { flags: 'too_short' }, // metadata @> (GIN-served)
181
+ range: [{ facet: 'confidence', op: '<=', value: 0.7 }],
182
+ exists: ['needsReview'],
183
+ block: [{ outcome: 'success' }], // exclude completed
184
+ orderBy: [{ field: 'metadata.confidence', numeric: true, direction: 'asc' }],
185
+ limit: 50, offset: 0,
186
+ });
187
+ // res.data → { escalations, total }
188
+ ```
189
+
190
+ `list` and `listAvailable` accept the FacetQuery elements (`facets`, `block`, `range`, `exists`,
191
+ `roles`, `available`, `orderBy`) on top of the plain filters. When any are present the request
192
+ runs through the scoped faceted query; otherwise the simple list path is used.
193
+
194
+ **Role scope is enforced in SQL, not in the controller.** The result is the read-scope predicate
195
+ ANDed with the facets:
196
+
197
+ - **superadmin / admin-of-admin** (global) — every role's queue, no role filter.
198
+ - **`read_all` on a role** — the whole pond for that role.
199
+ - **`read_self` on a role** — only items assigned to the caller (`assigned_to = me`).
200
+
201
+ A caller may **narrow** within their scope (pass `role`/`roles`) but can never **widen** past it —
202
+ a `role` they don't hold simply matches nothing. The page total is computed by the same WHERE, so
203
+ pagination stays correct; the controller never filters a fetched page client-side.
204
+
205
+ Over HTTP the faceted elements are JSON-encoded query params, so the whole query rides on a GET
206
+ URL and the dashboard's copy-URL / copy-curl reproduces the exact request:
207
+
208
+ ```
209
+ GET /api/escalations?status=pending&facets=%7B%22flags%22%3A%22too_short%22%7D&range=%5B%7B%22facet%22%3A%22confidence%22%2C%22op%22%3A%22%3C%3D%22%2C%22value%22%3A0.7%7D%5D
210
+ ```
211
+
212
+ ## Safety
213
+
214
+ - **Parameterized** — every value is a bound parameter; only audited column names, metadata
215
+ keys (strict `^[a-zA-Z0-9_]+$`), and a fixed operator set are interpolated.
216
+ - **Atomic** — claims are single transactions with `FOR UPDATE SKIP LOCKED`; group claims
217
+ re-check completeness *inside* the lock, so concurrent dispatchers never split a group or
218
+ double-claim a row.
219
+ - **Durable consumers** — because the surface is a query, a consumer that holds a claim it
220
+ cannot yet place can carry it across `continueAsNew` and converge later rather than
221
+ releasing — the durable workflow is the coordinator, not a distributed transaction.
@@ -158,6 +158,29 @@ export async function reviewWorkflow(envelope: LTEnvelope) {
158
158
 
159
159
  ---
160
160
 
161
+ ## Recording the Outcome on Resolution
162
+
163
+ An escalation row is created carrying **intent** — what was asked, who it routed to. Resolving it can stamp the **outcome** onto the same row: every resolve surface takes an optional `metadata` patch, merged into the row's GIN-indexed metadata.
164
+
165
+ | Surface | How to pass it |
166
+ |---------|----------------|
167
+ | HTTP | `metadata` in the resolve body (`POST /api/escalations/:id/resolve`, `/resolve-by-signal-key`) |
168
+ | SDK facade | `lt.escalations.resolve({ id, resolverPayload, metadata })` |
169
+ | MCP | `metadata` arg on `claim_and_resolve` / `resolve_escalation` |
170
+ | In-process library | `resolveEscalation(id, payload, metadata)` / `resolveEscalationBySignalKey(signalKey, payload, metadata)` |
171
+
172
+ ```typescript
173
+ await lt.escalations.resolve({
174
+ id,
175
+ resolverPayload: { approved: true }, // resumes the workflow; not indexed
176
+ metadata: { outcome: 'approved', reviewedBy: 'alice', durationMs: elapsed },
177
+ });
178
+ ```
179
+
180
+ The patch is distinct from the resolver payload: the payload resumes the paused workflow and is not indexed; the metadata patch is the durable, queryable record on the row. Use it for the audit trail and analytics — disposition, reviewer, time-to-resolve — so the escalation table answers *what was asked, what was decided, and how long it took* without a parallel log.
181
+
182
+ ---
183
+
161
184
  ## JSON Schema Form Authoring
162
185
 
163
186
  The dashboard renders forms automatically from JSON Schema. No frontend code needed.
@@ -456,6 +479,33 @@ await ltCreateEscalation({
456
479
  });
457
480
  ```
458
481
 
482
+ ### Work-Surface Scope
483
+
484
+ A `member` of a role carries a work-surface scope that narrows what they see and act on within that queue: `read_scope` (`self` | `all`) governs which escalations they see, and `write_scope` (`none` | `self` | `all`) governs which they can claim, resolve, or cancel. `self` means escalations assigned to that member (`assigned_to = user`); `all` means the whole role queue. `admin` and `superadmin` always work the whole queue. See the [Roles API](api/http/roles.md#work-surface-scope) for the five member profiles and the assignment contract.
485
+
486
+ Scope is a property of the **membership** (`lt_user_roles`), not of the escalation. The escalation engine is unchanged: `condition()` / `conditionLT()`, `ltCreateEscalation`, and the interceptor write escalation rows (`hmsh_escalations`) exactly as before — an escalation carries a `role` and an optional `assigned_to`, with no scope column. Scope is resolved at read time, when a *user* lists or acts on the queue. Escalating to a role that does not exist yet still registers the role name only — roles are typeless; `type` and scope are set per user when the role is granted. The one place scope affects creation is the standalone `POST /api/escalations` HTTP endpoint, which requires `write_scope=all`; workflow-emitted escalations (`conditionLT`, interceptor returns, `ltCreateEscalation`) do not pass through that check.
487
+
488
+ ### One-Time and Pre-Assigned Users
489
+
490
+ To route a single item to a named person, assign the escalation to them and provision them with `read_scope=self` + `write_scope=self`. The workflow sets `assigned_to` to the person's user ID (a pre-claim) when it creates the escalation, then provisions or updates that user as a `member` with self/self scope on the target role. They land directly on that one item — a just-in-time form scoped by RBAC, with no access to the rest of the queue and no direct table access. An update or follow-up is simply another workflow firing another escalation to that same person.
491
+
492
+ ```typescript
493
+ // Pre-assign the escalation to a specific person and route a one-time form to them
494
+ await ltCreateEscalation({
495
+ role: 'customer-triage',
496
+ assigned_to: userId, // pre-claim — durable, keyed off the user, not the soft-lock TTL
497
+ description: 'Confirm your shipping address',
498
+ metadata: {
499
+ form_schema: {
500
+ title: 'Confirm Address',
501
+ properties: { address: { type: 'string' }, confirmed: { type: 'boolean' } },
502
+ required: ['confirmed'],
503
+ },
504
+ },
505
+ });
506
+ // The person is provisioned as a member of `customer-triage` with read_scope=self, write_scope=self.
507
+ ```
508
+
459
509
  ### Escalation Chains
460
510
 
461
511
  Users can escalate to other roles via the "Escalate" tab:
package/docs/iam.md CHANGED
@@ -14,6 +14,37 @@ Each workflow execution carries three pieces of identity:
14
14
 
15
15
  **Credentials** — OAuth tokens and API keys available to the principal. Resolved at runtime through a cascade: principal's stored credentials, then the initiating user's credentials, then system environment variables.
16
16
 
17
+ ## Work-Surface Scope
18
+
19
+ Identity says *who* a principal is. Work-surface scope says *what* that principal sees and does within a role's queue. It is the fourth axis, orthogonal to initiator, principal, and credentials.
20
+
21
+ A role is a task queue with four verbs — **search**, **claim**, **ack** (resolve), **delete** (cancel). A `member` grant carries two scope axes stored on `lt_user_roles` that set the breadth of those verbs:
22
+
23
+ - `read_scope` (`self` | `all`, default `all`) — governs **search**: which escalations the member sees. `self` = items assigned to the member (`assigned_to = user`); `all` = the whole role queue.
24
+ - `write_scope` (`none` | `self` | `all`, default `all`) — governs **claim / ack / delete**: which escalations the member may act on. `none` = read-only.
25
+
26
+ The constraint is **write ⊆ read** — you cannot act on what you cannot see — so `write_scope=all` requires `read_scope=all`. `admin` and `superadmin` ignore scope and always act on the whole queue. The default `all`/`all` is the full-queue worker.
27
+
28
+ The five member profiles:
29
+
30
+ | read_scope | write_scope | Profile |
31
+ |-----------|------------|---------|
32
+ | `all` | `all` | Full worker — search and act on the whole queue (default) |
33
+ | `all` | `self` | See the whole queue, act only on own items (e.g. a chat-style room) |
34
+ | `self` | `self` | Own items only — a one-time user filling in their pre-assigned form |
35
+ | `all` | `none` | Read-only observer / auditor of the queue |
36
+ | `self` | `none` | Read-only view of one's own items |
37
+
38
+ ### One-Time Users
39
+
40
+ Scope makes limited-surface users first-class. A workflow assigns an escalation to a named person — a pre-claim, setting `assigned_to` to that user — and provisions them as a `member` with `read_scope=self` and `write_scope=self`. They see and act on exactly that one item: a just-in-time form surface scoped by RBAC, with no access to the rest of the queue and no direct table access. A follow-up or update is simply another workflow firing another escalation to that same person. Because `self` scope keys off durable `assigned_to` (independent of the soft-lock claim TTL), the assignment persists until the workflow resolves it.
41
+
42
+ See the [Roles API](api/http/roles.md#work-surface-scope) for the assignment contract and the [HITL Guide](hitl-guide.md#role-based-routing) for the workflow-side flow.
43
+
44
+ ### Enforcement
45
+
46
+ Scope folds into the SQL, so it is atomic with no TOCTOU window. Read scope becomes part of the escalation search query — a member sees a row when `role ∈ allRoles OR (role ∈ selfRoles AND assigned_to = me)`. Write scope folds into the atomic resolve-by-metadata query and gates the by-id claim/resolve/cancel paths. `assigned_to` is indexed, so `self` scope scales to large queues.
47
+
17
48
  ## Workflow Types and IAM
18
49
 
19
50
  Long Tail has three workflow types (see the [Workflows Guide](workflows.md#three-workflow-types) for full details). IAM applies to all three:
package/docs/mcp.md CHANGED
@@ -354,6 +354,14 @@ Returns:
354
354
 
355
355
  Returns `isError: true` if the escalation isn't available (already claimed, already resolved, or doesn't exist).
356
356
 
357
+ ### Scope and one-time users
358
+
359
+ An escalation created here lands in the target role's queue, where each member sees and acts on it according to their work-surface scope. A role membership carries a `type` (`member`, `admin`, or `superadmin`) plus two scope axes: `read_scope` (`self` | `all`) sets which escalations a member sees, and `write_scope` (`none` | `self` | `all`) sets which they may claim and resolve, with write ⊆ read. A `read_all` member sees the whole queue; a `read_self` member sees only items assigned to them. An `admin` or `superadmin` always acts on the whole queue. The defaults, `all`/`all`, are the full-queue worker.
360
+
361
+ `get_available_work` returns the pending, unassigned items for a role — the shared pool that whole-queue (`write_all`) workers draw from. A `write_self` member does not pull from the pool; their item is pre-assigned to them.
362
+
363
+ The one-time-user pattern builds on this. A workflow routes a single escalation to a named person by setting `assigned_to` when it creates the escalation — the `assigned_to` field on `escalate_and_wait` pre-claims the item — and that person is provisioned as a `member` of the role with `read_self` + `write_self`. They then see and act on exactly that one item: a scoped, single-item surface with no access to the rest of the queue. The scoped membership is provisioned through the platform's user and escalation APIs (see the [Roles API](api/http/roles.md)); the escalate tools supply the `assigned_to` pre-claim.
364
+
357
365
  ### Connecting
358
366
 
359
367
  **In-process (testing or co-located agents):**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/long-tail",
3
- "version": "0.5.11",
3
+ "version": "0.6.0",
4
4
  "description": "Long Tail Workflows — Durable AI workflows with human-in-the-loop escalation. Powered by PostgreSQL.",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -70,7 +70,7 @@
70
70
  "@anthropic-ai/sdk": "^0.92.0",
71
71
  "@aws-sdk/client-s3": "^3.1017.0",
72
72
  "@aws-sdk/s3-request-presigner": "^3.1045.0",
73
- "@hotmeshio/hotmesh": "^0.22.8",
73
+ "@hotmeshio/hotmesh": "^0.24.1",
74
74
  "@modelcontextprotocol/sdk": "^1.27.1",
75
75
  "@opentelemetry/exporter-trace-otlp-proto": "^0.215.0",
76
76
  "@opentelemetry/resources": "^2.5.1",
@@ -1,2 +0,0 @@
1
- import{j as o}from"./vendor-query-B2UbickB.js";import{c as n}from"./tasks-CWUsKhM4.js";import{s as m}from"./index-DPJW96d2.js";import{f as c}from"./useEventHooks-CjygrbYy.js";import{u}from"./mcp-B1lc6nL4.js";import{P as d}from"./PageHeaderWithStats-BuKc9MKt.js";import"./vendor-react-CXumBFUA.js";import"./vendor-icons-Dj2F0Jrb.js";function j(){var a;c();const{data:t}=n({limit:1}),{data:e}=m({status:"pending",limit:1}),{data:s}=u(),r=((a=s==null?void 0:s.servers)==null?void 0:a.filter(i=>i.status==="connected").length)??0,l=s?`${r}/${s.total}`:"—";return o.jsx("div",{children:o.jsx(d,{title:"Admin",stats:[{label:"Tasks",value:(t==null?void 0:t.total)??"—"},{label:"Pending Escalations",value:(e==null?void 0:e.total)??"—",dotClass:"bg-status-pending"},{label:"MCP Servers",value:l},{label:"System",value:"Healthy",dotClass:"bg-status-success"}]})})}export{j as AdminDashboard};
2
- //# sourceMappingURL=AdminDashboard-DZpduYdW.js.map
@@ -1,4 +0,0 @@
1
- import{j as e,a as y}from"./vendor-query-B2UbickB.js";import{a as D,b as L,c as R}from"./agents-JE4aL07D.js";import{u as W,b as K,N as M}from"./index-DPJW96d2.js";import{u as z,E,C as S}from"./CronLabel-DrGWtaSY.js";import{i as I}from"./useEventHooks-CjygrbYy.js";import{W as N}from"./WorkflowPill-F1oKUzmc.js";import{a as U,B as F,Q as H,P as G,aK as J,q as O,aL as Q,R as _,a7 as X,d as Y,aM as V}from"./vendor-icons-Dj2F0Jrb.js";import{e as Z,c as ee}from"./vendor-react-CXumBFUA.js";function te(a){return new Date(a).toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"})}function u({icon:a,color:i,children:c,actions:h}){return e.jsxs("div",{className:"flex items-center justify-between mb-3 pb-2 border-b border-surface-border",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(a,{className:`w-4 h-4 ${i}`,strokeWidth:1.5}),e.jsx("h2",{className:"text-xs font-semibold uppercase tracking-widest text-accent/80",children:c})]}),h]})}function j({text:a}){return e.jsx("p",{className:"text-[11px] text-text-quaternary py-2",children:a})}let se=0;function ae(a){const[i,c]=y.useState([]),[h,d]=y.useState(!1),t=y.useCallback(r=>{var m,g,p;if((m=r.type)!=null&&m.startsWith("mesh."))return;const x=r.activityName||((g=r.data)==null?void 0:g.domain)||((p=r.workflowId)==null?void 0:p.slice(0,16))||"";c(f=>[{id:++se,type:r.type,timestamp:r.timestamp,label:x},...f].slice(0,10)),d(!0),setTimeout(()=>d(!1),2e3)},[]);return K(a?`${M}.system.agent.${a}.>`:"",t),{events:i,pulse:h}}function me(){var b,w,k,C,$;const{id:a}=Z(),i=ee(),{data:c}=W(),d=!!((b=c==null?void 0:c.ai)!=null&&b.enabled)?"Agent":"Automation",{data:t,isLoading:r}=D(a??null),{data:x}=z(a??null),m=L(),g=R(),{events:p,pulse:f}=ae(a);if(I(),r)return e.jsxs("div",{className:"animate-pulse space-y-4",children:[e.jsx("div",{className:"h-8 bg-surface-sunken rounded w-48"}),e.jsx("div",{className:"h-40 bg-surface-sunken rounded"})]});if(!t)return e.jsxs("div",{className:"flex flex-col items-center justify-center py-20 text-center",children:[e.jsx(U,{className:"w-12 h-12 text-text-quaternary mb-4",strokeWidth:1}),e.jsxs("h2",{className:"text-lg font-medium text-text-primary mb-2",children:[d," not found"]}),e.jsxs("button",{onClick:()=>i("/agents"),className:"text-sm text-accent hover:text-accent-hover transition-colors",children:["Back to ",d.toLowerCase(),"s"]})]});const A=t.status==="active"?"bg-emerald-400":t.status==="paused"?"bg-amber-400":t.status==="error"?"bg-red-400":"bg-zinc-500",n=(x==null?void 0:x.subscriptions)??[],P=t.status==="active"?"Active":t.status==="paused"?"Paused":t.status==="error"?"Error":"Inactive",l=(w=t.behaviors)==null?void 0:w.schedules,v=(k=t.behaviors)==null?void 0:k.cron,o=(l==null?void 0:l.length)||(v?1:0),q=()=>{const s=[`Pause "${t.id}"?`,"","This will:",n.length>0?`• Stop ${n.length} event subscription${n.length!==1?"s":""}`:null,o>0?`• Stop ${o} schedule${o!==1?"s":""}`:null,"","Knowledge and workflow history are preserved. You can reactivate anytime."].filter(Boolean).join(`
2
- `);confirm(s)&&m.mutate({id:t.id,status:"paused"})},T=()=>{const s=[`Delete "${t.id}"?`,"","This permanently removes:","• The agent configuration",n.length>0?`• ${n.length} event subscription${n.length!==1?"s":""}`:null,o>0?`• ${o} schedule${o!==1?"s":""}`:null,"","Knowledge entries and workflow history are preserved."].filter(Boolean).join(`
3
- `);confirm(s)&&g.mutate(t.id,{onSuccess:()=>i("/agents")})};return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-start justify-between mb-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("h1",{className:"text-3xl font-light text-text-primary",children:[d,": ",t.id]}),e.jsx("button",{onClick:()=>{window.location.hash="#docs:agents.md"},className:"text-text-quaternary hover:text-accent transition-colors mt-1",title:"Docs",children:e.jsx(F,{className:"w-4 h-4",strokeWidth:1.5})})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("div",{className:"flex items-center gap-1.5 mr-2",children:[e.jsx("span",{className:`w-2 h-2 rounded-full ${A}`}),e.jsx("span",{className:"text-xs text-text-secondary capitalize",children:P})]}),e.jsxs("button",{onClick:()=>i(`/agents/${t.id}/edit`),className:"flex items-center gap-1.5 px-4 py-1.5 text-xs rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors",children:[e.jsx(H,{className:"w-3 h-3"})," Edit"]}),t.status!=="active"&&e.jsxs("button",{onClick:()=>m.mutate({id:t.id,status:"active"}),className:"flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md text-emerald-400 hover:bg-emerald-600/10 transition-colors",children:[e.jsx(G,{className:"w-3 h-3"})," Activate"]}),t.status==="active"&&e.jsxs("button",{onClick:q,className:"flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md text-text-tertiary hover:text-text-primary hover:bg-surface-hover transition-colors",children:[e.jsx(J,{className:"w-3 h-3"})," Pause"]}),e.jsxs("button",{onClick:T,className:"flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md text-red-400/60 hover:text-red-400 hover:bg-red-600/10 transition-colors",children:[e.jsx(O,{className:"w-3 h-3"})," Delete"]})]})]}),t.description&&e.jsx("div",{className:"border-l-2 border-accent/30 pl-4 py-1 mb-10",children:e.jsx("p",{className:"text-[13px] text-text-secondary italic leading-relaxed",children:t.description})}),(t.goals||t.rules)&&e.jsxs("div",{className:"mb-10",children:[e.jsx(u,{icon:Q,color:"text-rose-400",children:"Motivation"}),e.jsxs("div",{className:"grid grid-cols-2 gap-x-14 bg-surface-sunken/20 rounded-lg px-5 py-4",children:[t.goals&&e.jsxs("div",{children:[e.jsx("p",{className:"text-[9px] text-text-quaternary uppercase tracking-widest mb-1.5",children:"Goals"}),e.jsx("p",{className:"text-[13px] text-text-primary leading-relaxed",children:t.goals})]}),t.rules&&e.jsxs("div",{children:[e.jsx("p",{className:"text-[9px] text-text-quaternary uppercase tracking-widest mb-1.5",children:"Rules"}),e.jsx("p",{className:"text-[13px] text-text-primary leading-relaxed",children:t.rules})]})]})]}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-3 gap-x-14 gap-y-10",children:[e.jsxs("div",{children:[e.jsxs(u,{icon:_,color:"text-cyan-400",children:["Subscriptions (",n.length,")"]}),n.length===0?e.jsx(j,{text:"No event subscriptions"}):e.jsx("div",{className:"divide-y divide-surface-border/30",children:n.map(s=>e.jsxs("div",{className:"flex items-center py-2",children:[e.jsx("div",{className:"flex-1 min-w-0",children:e.jsx(E,{topic:s.topic})}),e.jsxs("div",{className:"flex items-center gap-1.5 shrink-0",children:[e.jsx("span",{className:"text-text-quaternary text-[10px]",children:"→"}),e.jsx(N,{type:s.reaction_type==="capability"?s.tool_name:s.workflow_type||s.reaction_type,variant:s.reaction_type==="pipeline"?"pipeline":s.reaction_type==="capability"?"capability":"durable"})]})]},s.id))})]}),e.jsxs("div",{children:[e.jsxs(u,{icon:X,color:"text-amber-400",children:["Schedules (",o,")"]}),l!=null&&l.length?e.jsx("div",{className:"divide-y divide-surface-border/30",children:l.map((s,B)=>e.jsxs("div",{className:"flex items-center py-2",children:[e.jsx("div",{className:"flex-1 min-w-0",children:e.jsx(S,{cron:s.cron})}),e.jsxs("div",{className:"flex items-center gap-1.5 shrink-0",children:[e.jsx("span",{className:"text-text-quaternary text-[10px]",children:"→"}),e.jsx(N,{type:s.workflow_type||"workflow"})]})]},B))}):v?e.jsxs("div",{className:"flex items-center py-1",children:[e.jsx("div",{className:"flex-1 min-w-0",children:e.jsx(S,{cron:v})}),t.workflow_type&&e.jsxs("div",{className:"flex items-center gap-1.5 shrink-0",children:[e.jsx("span",{className:"text-text-quaternary text-[10px]",children:"→"}),e.jsx(N,{type:t.workflow_type})]})]}):e.jsx(j,{text:"No schedules configured"})]}),e.jsxs("div",{className:"space-y-10",children:[e.jsxs("div",{children:[e.jsx(u,{icon:Y,color:"text-emerald-400",children:"Knowledge"}),t.knowledge_domain?e.jsxs("button",{onClick:()=>i(`/knowledge?domain=${t.knowledge_domain}`),className:"group text-left flex items-center gap-3",children:[e.jsx("span",{className:"text-sm font-mono text-text-primary group-hover:text-accent transition-colors",children:t.knowledge_domain}),e.jsxs("span",{className:"text-[10px] text-text-quaternary",children:[(($=(C=t.stats)==null?void 0:C.knowledge_count)==null?void 0:$.toLocaleString())??0," entries"]}),e.jsx(V,{className:"w-3 h-3 text-accent opacity-0 group-hover:opacity-100 transition-opacity"})]}):e.jsx(j,{text:"No knowledge domain"})]}),e.jsxs("div",{children:[e.jsx(u,{icon:_,color:"text-cyan-400",actions:e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:`w-1.5 h-1.5 rounded-full transition-colors duration-500 ${f?"bg-emerald-400":"bg-zinc-600"}`}),e.jsx("span",{className:"text-[10px] text-text-quaternary",children:"live"})]}),children:"Activity"}),p.length===0?e.jsx(j,{text:"Events appear here as the agent runs"}):e.jsx("div",{className:"space-y-1.5",children:p.map(s=>e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-0.5",children:[e.jsx("span",{className:"text-[11px] text-text-primary font-mono truncate flex-1",children:s.label||"—"}),e.jsx("span",{className:"text-[10px] text-text-quaternary shrink-0 ml-2",children:te(s.timestamp)})]}),e.jsx(E,{topic:s.type})]},s.id))})]})]})]})]})}export{me as AgentDetailPage};
4
- //# sourceMappingURL=AgentDetailPage-C-2iSaDs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AgentDetailPage-C-2iSaDs.js","sources":["../../src/pages/agents/AgentDetailPage.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n Bot, Play, Pause, Trash2, ArrowRight, Pencil, BookOpen,\n Radio, Clock, Brain, Compass,\n} from 'lucide-react';\nimport { useAgent, useUpdateAgent, useDeleteAgent } from '../../api/agents';\nimport { useSettings } from '../../api/settings';\nimport { useAgentSubscriptions } from '../../api/agent-subscriptions';\nimport { useAgentEvents } from '../../hooks/useEventHooks';\nimport { useEventSubscription } from '../../hooks/useEventContext';\nimport { NATS_SUBJECT_PREFIX } from '../../lib/nats/config';\nimport { EventTopicPill } from '../../components/common/display/EventTopicPill';\nimport { CronLabel } from '../../components/common/display/CronLabel';\nimport { WorkflowPill } from '../../components/common/display/WorkflowPill';\n\n// ── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction formatTime(iso: string): string {\n return new Date(iso).toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nfunction SectionHeader({ icon: Icon, color, children, actions }: { icon: React.ElementType; color: string; children: React.ReactNode; actions?: React.ReactNode }) {\n return (\n <div className=\"flex items-center justify-between mb-3 pb-2 border-b border-surface-border\">\n <div className=\"flex items-center gap-2\">\n <Icon className={`w-4 h-4 ${color}`} strokeWidth={1.5} />\n <h2 className=\"text-xs font-semibold uppercase tracking-widest text-accent/80\">{children}</h2>\n </div>\n {actions}\n </div>\n );\n}\n\nfunction EmptyHint({ text }: { text: string }) {\n return <p className=\"text-[11px] text-text-quaternary py-2\">{text}</p>;\n}\n\n// ── Live feed ───────────────────────────────────────────────────────────────\n\ninterface FeedEvent { id: number; type: string; timestamp: string; label: string; }\nlet feedCounter = 0;\n\nfunction useAgentFeed(agentName?: string) {\n const [events, setEvents] = useState<FeedEvent[]>([]);\n const [pulse, setPulse] = useState(false);\n const handler = useCallback((event: any) => {\n if (event.type?.startsWith('mesh.')) return;\n const label = event.activityName || event.data?.domain || event.workflowId?.slice(0, 16) || '';\n setEvents((prev) => [{ id: ++feedCounter, type: event.type, timestamp: event.timestamp, label }, ...prev].slice(0, 10));\n setPulse(true);\n setTimeout(() => setPulse(false), 2000);\n }, []);\n useEventSubscription(\n agentName ? `${NATS_SUBJECT_PREFIX}.system.agent.${agentName}.>` : '',\n handler,\n );\n return { events, pulse };\n}\n\n// ── Page ─────────────────────────────────────────────────────────────────────\n\nexport function AgentDetailPage() {\n const { id } = useParams<{ id: string }>();\n const navigate = useNavigate();\n const { data: settings } = useSettings();\n const aiEnabled = !!settings?.ai?.enabled;\n const label = aiEnabled ? 'Agent' : 'Automation';\n const { data: agent, isLoading } = useAgent(id ?? null);\n const { data: subsData } = useAgentSubscriptions(id ?? null);\n const updateMutation = useUpdateAgent();\n const deleteMutation = useDeleteAgent();\n const { events: liveEvents, pulse } = useAgentFeed(id);\n useAgentEvents();\n\n if (isLoading) {\n return <div className=\"animate-pulse space-y-4\"><div className=\"h-8 bg-surface-sunken rounded w-48\" /><div className=\"h-40 bg-surface-sunken rounded\" /></div>;\n }\n\n if (!agent) {\n return (\n <div className=\"flex flex-col items-center justify-center py-20 text-center\">\n <Bot className=\"w-12 h-12 text-text-quaternary mb-4\" strokeWidth={1} />\n <h2 className=\"text-lg font-medium text-text-primary mb-2\">{label} not found</h2>\n <button onClick={() => navigate('/agents')} className=\"text-sm text-accent hover:text-accent-hover transition-colors\">Back to {label.toLowerCase()}s</button>\n </div>\n );\n }\n\n const statusDot = agent.status === 'active' ? 'bg-emerald-400' : agent.status === 'paused' ? 'bg-amber-400' : agent.status === 'error' ? 'bg-red-400' : 'bg-zinc-500';\n const subs = subsData?.subscriptions ?? [];\n const statusLabel = agent.status === 'active' ? 'Active' : agent.status === 'paused' ? 'Paused' : agent.status === 'error' ? 'Error' : 'Inactive';\n const schedules = (agent.behaviors as any)?.schedules as any[] | undefined;\n const legacyCron = agent.behaviors?.cron;\n const schedCount = schedules?.length || (legacyCron ? 1 : 0);\n\n const handlePause = () => {\n const msg = [\n `Pause \"${agent.id}\"?`,\n '',\n 'This will:',\n subs.length > 0 ? `• Stop ${subs.length} event subscription${subs.length !== 1 ? 's' : ''}` : null,\n schedCount > 0 ? `• Stop ${schedCount} schedule${schedCount !== 1 ? 's' : ''}` : null,\n '',\n 'Knowledge and workflow history are preserved. You can reactivate anytime.',\n ].filter(Boolean).join('\\n');\n if (confirm(msg)) updateMutation.mutate({ id: agent.id, status: 'paused' as any });\n };\n\n const handleDelete = () => {\n const msg = [\n `Delete \"${agent.id}\"?`,\n '',\n 'This permanently removes:',\n '• The agent configuration',\n subs.length > 0 ? `• ${subs.length} event subscription${subs.length !== 1 ? 's' : ''}` : null,\n schedCount > 0 ? `• ${schedCount} schedule${schedCount !== 1 ? 's' : ''}` : null,\n '',\n 'Knowledge entries and workflow history are preserved.',\n ].filter(Boolean).join('\\n');\n if (confirm(msg)) deleteMutation.mutate(agent.id, { onSuccess: () => navigate('/agents') });\n };\n\n return (\n <div>\n {/* ── Hero ──────────────────────────────────────────────────────────── */}\n <div className=\"flex items-start justify-between mb-3\">\n <div className=\"flex items-center gap-2\">\n <h1 className=\"text-3xl font-light text-text-primary\">{label}: {agent.id}</h1>\n <button onClick={() => { window.location.hash = '#docs:agents.md'; }} className=\"text-text-quaternary hover:text-accent transition-colors mt-1\" title=\"Docs\">\n <BookOpen className=\"w-4 h-4\" strokeWidth={1.5} />\n </button>\n </div>\n <div className=\"flex items-center gap-3\">\n <div className=\"flex items-center gap-1.5 mr-2\">\n <span className={`w-2 h-2 rounded-full ${statusDot}`} />\n <span className=\"text-xs text-text-secondary capitalize\">{statusLabel}</span>\n </div>\n <button onClick={() => navigate(`/agents/${agent.id}/edit`)} className=\"flex items-center gap-1.5 px-4 py-1.5 text-xs rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors\">\n <Pencil className=\"w-3 h-3\" /> Edit\n </button>\n {agent.status !== 'active' && (\n <button onClick={() => updateMutation.mutate({ id: agent.id, status: 'active' as any })} className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md text-emerald-400 hover:bg-emerald-600/10 transition-colors\">\n <Play className=\"w-3 h-3\" /> Activate\n </button>\n )}\n {agent.status === 'active' && (\n <button onClick={handlePause} className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md text-text-tertiary hover:text-text-primary hover:bg-surface-hover transition-colors\">\n <Pause className=\"w-3 h-3\" /> Pause\n </button>\n )}\n <button onClick={handleDelete} className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md text-red-400/60 hover:text-red-400 hover:bg-red-600/10 transition-colors\">\n <Trash2 className=\"w-3 h-3\" /> Delete\n </button>\n </div>\n </div>\n\n {/* Description callout */}\n {agent.description && (\n <div className=\"border-l-2 border-accent/30 pl-4 py-1 mb-10\">\n <p className=\"text-[13px] text-text-secondary italic leading-relaxed\">{agent.description}</p>\n </div>\n )}\n\n {/* Motivation */}\n {(agent.goals || agent.rules) && (\n <div className=\"mb-10\">\n <SectionHeader icon={Compass} color=\"text-rose-400\">Motivation</SectionHeader>\n <div className=\"grid grid-cols-2 gap-x-14 bg-surface-sunken/20 rounded-lg px-5 py-4\">\n {agent.goals && (\n <div>\n <p className=\"text-[9px] text-text-quaternary uppercase tracking-widest mb-1.5\">Goals</p>\n <p className=\"text-[13px] text-text-primary leading-relaxed\">{agent.goals}</p>\n </div>\n )}\n {agent.rules && (\n <div>\n <p className=\"text-[9px] text-text-quaternary uppercase tracking-widest mb-1.5\">Rules</p>\n <p className=\"text-[13px] text-text-primary leading-relaxed\">{agent.rules}</p>\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* ── 3-column grid ─────────────────────────────────────────────────── */}\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-x-14 gap-y-10\">\n\n {/* Col 1: Subscriptions */}\n <div>\n <SectionHeader icon={Radio} color=\"text-cyan-400\">\n Subscriptions ({subs.length})\n </SectionHeader>\n {subs.length === 0 ? (\n <EmptyHint text=\"No event subscriptions\" />\n ) : (\n <div className=\"divide-y divide-surface-border/30\">\n {subs.map((sub: any) => (\n <div key={sub.id} className=\"flex items-center py-2\">\n <div className=\"flex-1 min-w-0\"><EventTopicPill topic={sub.topic} /></div>\n <div className=\"flex items-center gap-1.5 shrink-0\">\n <span className=\"text-text-quaternary text-[10px]\">→</span>\n <WorkflowPill\n type={sub.reaction_type === 'capability' ? sub.tool_name : sub.workflow_type || sub.reaction_type}\n variant={sub.reaction_type === 'pipeline' ? 'pipeline' : sub.reaction_type === 'capability' ? 'capability' : 'durable'}\n />\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Col 2: Schedules */}\n <div>\n <SectionHeader icon={Clock} color=\"text-amber-400\">Schedules ({schedCount})</SectionHeader>\n {schedules?.length ? (\n <div className=\"divide-y divide-surface-border/30\">\n {schedules.map((s: any, i: number) => (\n <div key={i} className=\"flex items-center py-2\">\n <div className=\"flex-1 min-w-0\"><CronLabel cron={s.cron} /></div>\n <div className=\"flex items-center gap-1.5 shrink-0\"><span className=\"text-text-quaternary text-[10px]\">→</span><WorkflowPill type={s.workflow_type || 'workflow'} /></div>\n </div>\n ))}\n </div>\n ) : legacyCron ? (\n <div className=\"flex items-center py-1\">\n <div className=\"flex-1 min-w-0\"><CronLabel cron={legacyCron} /></div>\n {agent.workflow_type && <div className=\"flex items-center gap-1.5 shrink-0\"><span className=\"text-text-quaternary text-[10px]\">→</span><WorkflowPill type={agent.workflow_type} /></div>}\n </div>\n ) : (\n <EmptyHint text=\"No schedules configured\" />\n )}\n </div>\n\n {/* Col 3: Knowledge + Activity */}\n <div className=\"space-y-10\">\n <div>\n <SectionHeader icon={Brain} color=\"text-emerald-400\">Knowledge</SectionHeader>\n {agent.knowledge_domain ? (\n <button onClick={() => navigate(`/knowledge?domain=${agent.knowledge_domain}`)} className=\"group text-left flex items-center gap-3\">\n <span className=\"text-sm font-mono text-text-primary group-hover:text-accent transition-colors\">{agent.knowledge_domain}</span>\n <span className=\"text-[10px] text-text-quaternary\">{agent.stats?.knowledge_count?.toLocaleString() ?? 0} entries</span>\n <ArrowRight className=\"w-3 h-3 text-accent opacity-0 group-hover:opacity-100 transition-opacity\" />\n </button>\n ) : (\n <EmptyHint text=\"No knowledge domain\" />\n )}\n </div>\n\n <div>\n <SectionHeader icon={Radio} color=\"text-cyan-400\"\n actions={\n <div className=\"flex items-center gap-1.5\">\n <span className={`w-1.5 h-1.5 rounded-full transition-colors duration-500 ${pulse ? 'bg-emerald-400' : 'bg-zinc-600'}`} />\n <span className=\"text-[10px] text-text-quaternary\">live</span>\n </div>\n }\n >\n Activity\n </SectionHeader>\n {liveEvents.length === 0 ? (\n <EmptyHint text=\"Events appear here as the agent runs\" />\n ) : (\n <div className=\"space-y-1.5\">\n {liveEvents.map((ev) => (\n <div key={ev.id}>\n <div className=\"flex items-center justify-between mb-0.5\">\n <span className=\"text-[11px] text-text-primary font-mono truncate flex-1\">{ev.label || '—'}</span>\n <span className=\"text-[10px] text-text-quaternary shrink-0 ml-2\">{formatTime(ev.timestamp)}</span>\n </div>\n <EventTopicPill topic={ev.type} />\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"names":["formatTime","iso","SectionHeader","Icon","color","children","actions","jsxs","jsx","EmptyHint","text","feedCounter","useAgentFeed","agentName","events","setEvents","useState","pulse","setPulse","handler","useCallback","event","_a","label","_b","_c","prev","useEventSubscription","NATS_SUBJECT_PREFIX","AgentDetailPage","id","useParams","navigate","useNavigate","settings","useSettings","agent","isLoading","useAgent","subsData","useAgentSubscriptions","updateMutation","useUpdateAgent","deleteMutation","useDeleteAgent","liveEvents","useAgentEvents","Bot","statusDot","subs","statusLabel","schedules","legacyCron","schedCount","handlePause","msg","handleDelete","BookOpen","Pencil","Play","Pause","Trash2","Compass","Radio","sub","EventTopicPill","WorkflowPill","Clock","i","CronLabel","Brain","_e","_d","ArrowRight","ev"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{j as e}from"./vendor-query-B2UbickB.js";import{u as h}from"./agents-JE4aL07D.js";import{u as f,c as b}from"./index-DPJW96d2.js";import{i as j}from"./useEventHooks-CjygrbYy.js";import{u as v}from"./useFilterParams-x-Dg0Vgz.js";import{D as N}from"./DataTable-D9yuBv0w.js";import{S as y}from"./StickyPagination-BWhFSr2d.js";import{F as P,b as S}from"./FilterBar-Ck4K4rzu.js";import{P as k}from"./PageHeader-Bnt2iQQa.js";import{L as w}from"./ListToolbar-BH9rwQVE.js";import{m as _}from"./vendor-icons-Dj2F0Jrb.js";import{c as A}from"./vendor-react-CXumBFUA.js";import"./EmptyState-BcsfPq9T.js";const $=[{value:"active",label:"Active"},{value:"inactive",label:"Inactive"},{value:"paused",label:"Paused"},{value:"error",label:"Error"}],z=[{key:"name",label:"Agent",render:t=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`w-1.5 h-1.5 rounded-full shrink-0 ${t.status==="active"?"bg-emerald-400":t.status==="paused"?"bg-amber-400":t.status==="error"?"bg-red-400":"bg-zinc-500"}`}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("span",{className:"text-xs font-medium text-text-primary block",children:t.id}),t.description&&e.jsx("p",{className:"text-[10px] text-text-tertiary truncate",children:t.description})]})]})},{key:"knowledge_domain",label:"Knowledge",render:t=>t.knowledge_domain?e.jsx("span",{className:"text-[10px] font-mono text-text-secondary whitespace-nowrap",children:t.knowledge_domain}):e.jsx("span",{className:"text-text-quaternary",children:"—"}),className:"w-28"},{key:"schedules",label:"Schedules",render:t=>{var o,r;const s=(o=t.behaviors)==null?void 0:o.schedules,a=s!=null&&s.length?s.map(i=>i.cron):(r=t.behaviors)!=null&&r.cron?[t.behaviors.cron]:[];return a.length?e.jsxs("span",{className:"text-[10px] font-mono text-text-secondary whitespace-nowrap",children:[a[0],a.length>1?` +${a.length-1}`:""]}):e.jsx("span",{className:"text-text-quaternary",children:"—"})},className:"w-28"},{key:"subscriptions",label:"Subscriptions",render:t=>{var r;const s=t.subscription_count??0,a=t.sub_topics??[];if(!s)return e.jsx("span",{className:"text-text-quaternary",children:"—"});const o=((r=a[0])==null?void 0:r.replace(/^lt\.events\./,""))??"";return e.jsxs("span",{className:"text-[10px] font-mono text-text-secondary whitespace-nowrap",children:[o,s>1?` +${s-1}`:""]})},className:"w-36"},{key:"last_run_at",label:"Last Run",render:t=>t.last_run_at?e.jsx("span",{className:"whitespace-nowrap",children:e.jsx(b,{date:t.last_run_at})}):e.jsx("span",{className:"text-text-quaternary",children:"—"}),className:"w-32"}];function M(){var u;const t=A(),{data:s}=f(),a=!!((u=s==null?void 0:s.ai)!=null&&u.enabled),o=a?"Agent":"Automation",r=a?"Agents":"Automations";j();const{filters:i,setFilter:p,pagination:n}=v({filters:{status:""}}),{data:l,isLoading:d,refetch:x,isFetching:g}=h({status:i.status||void 0,limit:n.pageSize,offset:n.offset}),m=(l==null?void 0:l.total)??0;return e.jsxs("div",{children:[e.jsx(k,{title:r,docsHash:"#docs:agents.md",actions:e.jsxs("button",{onClick:()=>t("/agents/new"),className:"flex items-center gap-2 px-4 py-2 text-sm rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors",children:[e.jsx(_,{className:"w-4 h-4"})," Create ",o]})}),e.jsx(P,{actions:e.jsx(w,{onRefresh:()=>x(),isFetching:g,apiPath:`/agents?limit=${n.pageSize}&offset=${n.offset}${i.status?`&status=${i.status}`:""}`}),children:e.jsx(S,{label:"Status",value:i.status,onChange:c=>p("status",c),options:$})}),e.jsx(N,{columns:z,data:(l==null?void 0:l.agents)??[],keyFn:c=>c.id,onRowClick:c=>t(`/agents/${c.id}`),isLoading:d,emptyMessage:`No ${r.toLowerCase()} found`}),e.jsx(y,{page:n.page,totalPages:n.totalPages(m),onPageChange:n.setPage,total:m,pageSize:n.pageSize,onPageSizeChange:n.setPageSize})]})}export{M as AgentsPage};
2
- //# sourceMappingURL=AgentsPage-C3FztFd_.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AgentsPage-C3FztFd_.js","sources":["../../src/pages/agents/AgentsPage.tsx"],"sourcesContent":["import { useNavigate } from 'react-router-dom';\nimport { Plus } from 'lucide-react';\nimport { useAgents, type Agent } from '../../api/agents';\nimport { useSettings } from '../../api/settings';\nimport { useAgentEvents } from '../../hooks/useEventHooks';\nimport { useFilterParams } from '../../hooks/useFilterParams';\nimport { DataTable, type Column } from '../../components/common/data/DataTable';\nimport { StickyPagination } from '../../components/common/data/StickyPagination';\nimport { FilterBar, FilterSelect } from '../../components/common/data/FilterBar';\nimport { PageHeader } from '../../components/common/layout/PageHeader';\nimport { ListToolbar } from '../../components/common/data/ListToolbar';\nimport { DateValue } from '../../components/common/display/DateValue';\n\nconst STATUS_OPTIONS = [\n { value: 'active', label: 'Active' },\n { value: 'inactive', label: 'Inactive' },\n { value: 'paused', label: 'Paused' },\n { value: 'error', label: 'Error' },\n];\n\nconst columns: Column<Agent>[] = [\n {\n key: 'name',\n label: 'Agent',\n render: (row) => (\n <div className=\"flex items-center gap-2\">\n <span className={`w-1.5 h-1.5 rounded-full shrink-0 ${row.status === 'active' ? 'bg-emerald-400' : row.status === 'paused' ? 'bg-amber-400' : row.status === 'error' ? 'bg-red-400' : 'bg-zinc-500'}`} />\n <div className=\"min-w-0\">\n <span className=\"text-xs font-medium text-text-primary block\">{row.id}</span>\n {row.description && <p className=\"text-[10px] text-text-tertiary truncate\">{row.description}</p>}\n </div>\n </div>\n ),\n },\n {\n key: 'knowledge_domain',\n label: 'Knowledge',\n render: (row) => row.knowledge_domain\n ? <span className=\"text-[10px] font-mono text-text-secondary whitespace-nowrap\">{row.knowledge_domain}</span>\n : <span className=\"text-text-quaternary\">—</span>,\n className: 'w-28',\n },\n {\n key: 'schedules',\n label: 'Schedules',\n render: (row) => {\n const scheds = (row.behaviors as any)?.schedules as any[] | undefined;\n const crons = scheds?.length ? scheds.map((s: any) => s.cron) : row.behaviors?.cron ? [row.behaviors.cron] : [];\n if (!crons.length) return <span className=\"text-text-quaternary\">—</span>;\n return <span className=\"text-[10px] font-mono text-text-secondary whitespace-nowrap\">{crons[0]}{crons.length > 1 ? ` +${crons.length - 1}` : ''}</span>;\n },\n className: 'w-28',\n },\n {\n key: 'subscriptions',\n label: 'Subscriptions',\n render: (row) => {\n const count = row.subscription_count ?? 0;\n const topics = row.sub_topics ?? [];\n if (!count) return <span className=\"text-text-quaternary\">—</span>;\n const first = topics[0]?.replace(/^lt\\.events\\./, '') ?? '';\n return <span className=\"text-[10px] font-mono text-text-secondary whitespace-nowrap\">{first}{count > 1 ? ` +${count - 1}` : ''}</span>;\n },\n className: 'w-36',\n },\n {\n key: 'last_run_at',\n label: 'Last Run',\n render: (row) => row.last_run_at\n ? <span className=\"whitespace-nowrap\"><DateValue date={row.last_run_at} /></span>\n : <span className=\"text-text-quaternary\">—</span>,\n className: 'w-32',\n },\n];\n\nexport function AgentsPage() {\n const navigate = useNavigate();\n const { data: settings } = useSettings();\n const aiEnabled = !!settings?.ai?.enabled;\n const label = aiEnabled ? 'Agent' : 'Automation';\n const labelPlural = aiEnabled ? 'Agents' : 'Automations';\n useAgentEvents();\n\n const { filters, setFilter, pagination } = useFilterParams({\n filters: { status: '' },\n });\n\n const { data, isLoading, refetch, isFetching } = useAgents({\n status: filters.status || undefined,\n limit: pagination.pageSize,\n offset: pagination.offset,\n });\n\n const total = data?.total ?? 0;\n\n return (\n <div>\n <PageHeader\n title={labelPlural}\n docsHash=\"#docs:agents.md\"\n actions={\n <button\n onClick={() => navigate('/agents/new')}\n className=\"flex items-center gap-2 px-4 py-2 text-sm rounded-md bg-accent text-text-inverse hover:bg-accent-hover transition-colors\"\n >\n <Plus className=\"w-4 h-4\" /> Create {label}\n </button>\n }\n />\n\n <FilterBar actions={\n <ListToolbar\n onRefresh={() => refetch()}\n isFetching={isFetching}\n apiPath={`/agents?limit=${pagination.pageSize}&offset=${pagination.offset}${filters.status ? `&status=${filters.status}` : ''}`}\n />\n }>\n <FilterSelect\n label=\"Status\"\n value={filters.status}\n onChange={(v) => setFilter('status', v)}\n options={STATUS_OPTIONS}\n />\n </FilterBar>\n\n <DataTable\n columns={columns}\n data={data?.agents ?? []}\n keyFn={(row) => row.id}\n onRowClick={(row) => navigate(`/agents/${row.id}`)}\n isLoading={isLoading}\n emptyMessage={`No ${labelPlural.toLowerCase()} found`}\n />\n\n <StickyPagination\n page={pagination.page}\n totalPages={pagination.totalPages(total)}\n onPageChange={pagination.setPage}\n total={total}\n pageSize={pagination.pageSize}\n onPageSizeChange={pagination.setPageSize}\n />\n </div>\n );\n}\n"],"names":["STATUS_OPTIONS","columns","row","jsxs","jsx","scheds","_a","crons","s","_b","count","topics","first","DateValue","AgentsPage","navigate","useNavigate","settings","useSettings","aiEnabled","label","labelPlural","useAgentEvents","filters","setFilter","pagination","useFilterParams","data","isLoading","refetch","isFetching","useAgents","total","PageHeader","Plus","FilterBar","ListToolbar","FilterSelect","v","DataTable","StickyPagination"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{j as e,a as o}from"./vendor-query-B2UbickB.js";import{j as pe,g as Ce,k as fe,l as be,m as ye,n as je,o as ve,p as ke,q as Se,r as Ne,s as Pe,t as Ae}from"./index-DPJW96d2.js";import{f as we}from"./useEventHooks-CjygrbYy.js";import{u as q,C as K,a as Ee}from"./CustomDurationPicker-Vcmr4LiR.js";import{u as Be}from"./roles-CSpHRRu8.js";import{u as Me}from"./useFilterParams-x-Dg0Vgz.js";import{D as Te}from"./DataTable-D9yuBv0w.js";import{S as Le}from"./StickyPagination-BWhFSr2d.js";import{P as ze}from"./PageHeader-Bnt2iQQa.js";import{P as Fe}from"./constants-BHkpVaqx.js";import{M as D}from"./Modal-CSrxpXeM.js";import{u as Ie}from"./users-DvhHbR0R.js";import{E as Oe,a as $e}from"./escalation-columns-DqTkKbCv.js";import{R as Re,a as _e}from"./RowActions-Dg-Fsm5O.js";import{L as Ue}from"./ListToolbar-BH9rwQVE.js";import{a4 as He}from"./vendor-icons-Dj2F0Jrb.js";import{c as qe}from"./vendor-react-CXumBFUA.js";import"./EmptyState-BcsfPq9T.js";import"./FilterBar-Ck4K4rzu.js";import"./PriorityBadge-DfQY9St9.js";import"./RolePill-DQTT1s9v.js";import"./WorkflowPill-F1oKUzmc.js";import"./TimestampCell-Dsje8GH-.js";import"./escalation-ne7dIaPa.js";const De=t=>t.isPriorityPending||t.isClaimPending||t.isAssignPending||t.isEscalatePending||t.isTriagePending||t.isCancelPending;function Qe(t){const a=De(t),c=q();return e.jsxs("div",{className:"flex flex-wrap items-center gap-3 px-4 py-3 bg-accent/5 border border-accent/20 rounded-lg mb-4",children:[e.jsxs("span",{className:"text-xs font-medium text-accent",children:[t.selectedCount," selected"]}),e.jsx("div",{className:"w-px h-5 bg-surface-border"}),e.jsxs("select",{onChange:s=>{s.target.value&&(t.onSetPriority(parseInt(s.target.value)),s.target.value="")},disabled:a,className:"select text-xs py-1.5",defaultValue:"",children:[e.jsx("option",{value:"",disabled:!0,children:"Priority..."}),Fe.map(s=>e.jsx("option",{value:s.value,children:s.label},s.value))]}),e.jsxs("select",{onChange:s=>{s.target.value&&(t.onClaim(parseInt(s.target.value)),s.target.value="")},disabled:a,className:"select text-xs py-1.5",defaultValue:"",children:[e.jsx("option",{value:"",disabled:!0,children:"Claim for..."}),c.map(s=>e.jsx("option",{value:s.value,children:s.label},s.value))]}),e.jsx("button",{onClick:t.onAssign,disabled:a,className:"btn-secondary text-xs py-1.5",children:t.isAssignPending?"Assigning...":"Assign to..."}),t.availableRoles.length>0&&e.jsxs("select",{onChange:s=>{s.target.value&&(t.onEscalate(s.target.value),s.target.value="")},disabled:a,className:"select text-xs py-1.5",defaultValue:"",children:[e.jsx("option",{value:"",disabled:!0,children:"Escalate to..."}),t.availableRoles.map(s=>e.jsx("option",{value:s,children:s},s))]}),e.jsx("button",{onClick:t.onTriage,disabled:a,className:"btn-secondary text-xs py-1.5",children:t.isTriagePending?"Triaging...":"Triage"}),e.jsx("button",{onClick:t.onCancel,disabled:a,className:"text-xs py-1.5 px-3 rounded-md border border-status-error/40 text-status-error hover:bg-status-error/10 transition-colors disabled:opacity-50",children:t.isCancelPending?"Cancelling...":"Cancel"}),e.jsx("div",{className:"flex-1"}),e.jsx("button",{onClick:t.onClearSelection,className:"text-xs text-text-tertiary hover:text-text-primary transition-colors",children:"Clear"}),a&&e.jsx("span",{className:"text-xs text-text-tertiary animate-pulse",children:"Processing..."})]})}function Ve({open:t,onClose:a,selectedCount:c,selectedRoles:s,onSubmit:m,isPending:x}){const{isSuperAdmin:C}=pe(),u=q(),[i,g]=o.useState("user"),[y,E]=o.useState(null),[j,F]=o.useState(""),[r,h]=o.useState("30"),[R,v]=o.useState(0),_=o.useCallback(l=>v(l),[]),B=!C&&s.length===1?s[0]:void 0,{data:f,isLoading:N}=Ie({role:B,status:"active",limit:200}),M=o.useMemo(()=>{const l=(f==null?void 0:f.users)??[];if(!j.trim())return l;const k=j.toLowerCase();return l.filter(p=>{var P,S;return((P=p.display_name)==null?void 0:P.toLowerCase().includes(k))||((S=p.email)==null?void 0:S.toLowerCase().includes(k))})},[f==null?void 0:f.users,j]),T=()=>{g("user"),E(null),F(""),h("30"),v(0),a()},I=l=>{E(l),g("duration")},L=()=>{g("user")},O=()=>{if(!y)return;const l=r==="custom"?R:parseInt(r);!l||l<=0||m(y.id,l)};return e.jsx(D,{open:t,onClose:T,title:"Assign Escalations",children:e.jsxs("div",{className:"space-y-4",children:[i==="user"&&e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"text-sm text-text-secondary",children:["Select a user to assign"," ",e.jsx("span",{className:"font-medium text-text-primary",children:c})," ","escalation(s) to:"]}),e.jsx("input",{type:"text",value:j,onChange:l=>F(l.target.value),placeholder:"Search by name or email...",className:"input text-xs w-full",autoFocus:!0}),e.jsxs("div",{className:"max-h-60 overflow-y-auto border border-surface-border rounded-lg divide-y divide-surface-border",children:[N&&e.jsx("p",{className:"text-xs text-text-tertiary p-3",children:"Loading users..."}),!N&&M.length===0&&e.jsx("p",{className:"text-xs text-text-tertiary p-3",children:"No users found"}),M.map(l=>e.jsxs("button",{onClick:()=>I(l),className:"w-full text-left px-3 py-2 hover:bg-surface-hover transition-colors",children:[e.jsx("p",{className:"text-xs font-medium text-text-primary",children:l.display_name||l.external_id}),l.email&&e.jsx("p",{className:"text-[10px] text-text-tertiary",children:l.email})]},l.id))]}),e.jsx("div",{className:"flex justify-end pt-2",children:e.jsx("button",{onClick:T,className:"btn-secondary text-xs",children:"Cancel"})})]}),i==="duration"&&y&&e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"text-sm text-text-secondary",children:["Assign to"," ",e.jsx("span",{className:"font-medium text-text-primary",children:y.display_name||y.external_id})," ","for:"]}),e.jsxs("select",{value:r,onChange:l=>{h(l.target.value),v(0)},className:"select w-full text-sm",children:[u.map(l=>e.jsx("option",{value:l.value,children:l.label},l.value)),e.jsx("option",{value:"custom",children:"Other..."})]}),r==="custom"&&e.jsx(K,{onChange:_,autoFocus:!0}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:L,className:"btn-secondary text-xs",children:"Back"}),e.jsx("button",{onClick:O,disabled:x,className:"btn-primary text-xs",children:x?"Assigning...":"Assign"})]})]})]})})}function Ge({open:t,onClose:a,selectedCount:c,onSubmit:s,isPending:m}){const[x,C]=o.useState(""),u=()=>{s(x||void 0)};return e.jsx(D,{open:t,onClose:a,title:"Submit for AI Triage",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("p",{className:"text-sm text-text-secondary",children:["Submit ",e.jsx("span",{className:"font-medium text-text-primary",children:c})," escalation(s) for AI triage? The triage orchestrator will take over resolution."]}),e.jsxs("div",{children:[e.jsxs("label",{className:"text-xs font-medium text-text-secondary block mb-1",children:["Triage hint ",e.jsx("span",{className:"text-text-tertiary",children:"(optional)"})]}),e.jsx("input",{type:"text",value:x,onChange:i=>C(i.target.value),placeholder:"e.g., image_orientation",className:"input text-xs font-mono w-full"}),e.jsx("p",{className:"text-[10px] text-text-tertiary mt-1",children:"Guides the triage workflow on what remediation to apply"})]}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:a,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:u,disabled:m,className:"btn-primary text-xs",children:m?"Submitting...":"Submit for Triage"})]})]})})}function w(t,a,c){return s=>{t.mutate(s,{onSuccess:()=>{a(),c==null||c()}})}}function Ye(t){const a=()=>[...t.selectedIds];return{handleSetPriority:i=>{w(t.setPriority,t.clearSelection)({ids:a(),priority:i})},handleBulkClaim:i=>{w(t.bulkClaim,t.clearSelection)({ids:a(),durationMinutes:i})},handleBulkEscalate:i=>{w(t.bulkEscalate,t.clearSelection)({ids:a(),targetRole:i})},handleBulkTriage:i=>{w(t.bulkTriage,t.clearSelection,t.closeTriageModal)({ids:a(),hint:i})},handleBulkAssign:(i,g)=>{w(t.bulkAssign,t.clearSelection,t.closeAssignModal)({ids:a(),targetUserId:i,durationMinutes:g})},handleBulkCancel:()=>{w(t.bulkCancel,t.clearSelection,t.closeCancelModal)({ids:a()})}}}function Je({claimTarget:t,onClose:a,claimDuration:c,onDurationChange:s,claimDurations:m,onCustomClaimChange:x,onClaim:C,isPending:u}){return e.jsx(D,{open:!!t,onClose:a,title:"Claim Escalation",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("p",{className:"text-sm text-text-secondary",children:["Claim ",e.jsx("span",{className:"font-medium text-text-primary",children:t==null?void 0:t.type})," for:"]}),e.jsxs("select",{value:c,onChange:i=>{s(i.target.value)},className:"select w-full text-sm",children:[m.map(i=>e.jsx("option",{value:i.value,children:i.label},i.value)),e.jsx("option",{value:"custom",children:"Other..."})]}),c==="custom"&&e.jsx(K,{onChange:x,autoFocus:!0}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{onClick:a,className:"btn-secondary text-xs",children:"Cancel"}),e.jsx("button",{onClick:C,className:"btn-primary text-xs",disabled:u,children:u?"Claiming...":"Claim"})]})]})})}function yt(){we();const t=qe(),{filters:a,setFilter:c,pagination:s,sort:m,setSort:x}=Me({filters:{role:"",type:"",priority:"",status:"available",search:""}}),C=q(),[u,i]=o.useState(null),[g,y]=o.useState("30"),[E,j]=o.useState(0),F=o.useCallback(n=>j(n),[]),[r,h]=o.useState(new Set),[R,v]=o.useState(!1),[_,B]=o.useState(!1),[f,N]=o.useState(!1),M=Ce(),T=fe(),I=be(),L=ye(),O=je(),l=ve(),k=ke(),{data:p}=Be(),{data:P}=Se();o.useEffect(()=>{h(new Set)},[a.role,a.type,a.priority,a.status,s.page,s.pageSize]);const S=a.status||"",z=S==="available",Q=S==="claimed",U=Q?"pending":S==="resolved"?"resolved":S==="cancelled"?"cancelled":void 0,V={role:a.role||void 0,type:a.type||void 0,priority:a.priority?parseInt(a.priority):void 0,limit:s.pageSize,offset:s.offset,sort_by:m.sort_by||"created_at",order:m.order||"desc"},W=Ne({...V,enabled:z}),X=Pe({status:U,claimed:Q||void 0,...V,enabled:!z}),Z=z?W:X,{data:A,isLoading:ee,error:$,refetch:te,isFetching:se}=Z,G=(A==null?void 0:A.escalations)??[],H=(a.search??"").toLowerCase(),b=H?G.filter(n=>{const d=[n.id,n.type,n.subtype,n.description,n.workflow_id,n.origin_id,n.role];return n.metadata&&d.push(...Object.values(n.metadata).map(String)),d.some(J=>J&&String(J).toLowerCase().includes(H))}):G,Y=H?b.length:(A==null?void 0:A.total)??0,{canBulk:ae}=Ae(),ne=o.useMemo(()=>{const n=new Set;for(const d of b)r.has(d.id)&&n.add(d.role);return[...n]},[b,r]),le=o.useCallback(()=>h(new Set),[]),ie=()=>{if(!u)return;const n=g==="custom"?E:parseInt(g);!n||n<=0||M.mutate({id:u.id,durationMinutes:n},{onSuccess:()=>{i(null),t(`/escalations/detail/${u.id}`)}})},{handleSetPriority:oe,handleBulkClaim:re,handleBulkEscalate:ce,handleBulkTriage:de,handleBulkAssign:ue,handleBulkCancel:me}=Ye({selectedIds:r,clearSelection:le,setPriority:T,bulkClaim:I,bulkEscalate:O,bulkTriage:l,bulkAssign:L,bulkCancel:k,closeTriageModal:()=>v(!1),closeAssignModal:()=>B(!1),closeCancelModal:()=>N(!1)}),xe=n=>{const d=new Set(r);d.has(n)?d.delete(n):d.add(n),h(d)},ge=()=>{r.size===b.length?h(new Set):h(new Set(b.map(n=>n.id)))},he=[ae?{key:"select",label:e.jsx("input",{type:"checkbox",checked:b.length>0&&r.size===b.length,onChange:ge,className:"rounded"}),render:n=>e.jsx("input",{type:"checkbox",checked:r.has(n.id),onChange:d=>{d.stopPropagation(),xe(n.id)},onClick:d=>d.stopPropagation(),className:"rounded"}),className:"w-10"}:{key:"spacer",label:"",render:()=>null,className:"w-10"},...Oe,{key:"actions",label:"",render:n=>e.jsx(Re,{children:e.jsx(_e,{icon:He,title:"Claim escalation",onClick:()=>i(n)})}),className:"w-16 text-right"}];return e.jsxs("div",{children:[e.jsx(ze,{title:"Available Escalations",docsHash:"#docs:dashboard.md:all-escalations"}),e.jsx($e,{filters:a,setFilter:c,roles:(p==null?void 0:p.roles)??[],types:(P==null?void 0:P.types)??[],showStatus:!0,actions:e.jsx(Ue,{onRefresh:()=>te(),isFetching:se,apiPath:`/escalations${z?"/available":""}?limit=${s.pageSize}&offset=${s.offset}${U?`&status=${U}`:""}${a.role?`&role=${a.role}`:""}${a.type?`&type=${a.type}`:""}${a.priority?`&priority=${a.priority}`:""}`})}),r.size>0&&e.jsx(Qe,{selectedCount:r.size,onClearSelection:()=>h(new Set),onSetPriority:oe,onClaim:re,onAssign:()=>B(!0),onEscalate:ce,onTriage:()=>v(!0),onCancel:()=>N(!0),isPriorityPending:T.isPending,isClaimPending:I.isPending,isAssignPending:L.isPending,isEscalatePending:O.isPending,isTriagePending:l.isPending,isCancelPending:k.isPending,availableRoles:(p==null?void 0:p.roles)??[]}),$&&e.jsx("div",{className:"mb-4 px-4 py-3 rounded-md bg-status-error/10 border border-status-error/20 text-xs text-status-error",children:$.message==="Session expired"?"Your session has expired. Please log in again.":`Failed to load escalations: ${$.message}`}),e.jsx(Te,{columns:he,data:b,keyFn:n=>n.id,onRowClick:n=>t(`/escalations/detail/${n.id}`,{state:{from:"/escalations/available"}}),isLoading:ee,emptyMessage:$?"Unable to load data":"No available escalations",sort:m,onSort:x}),e.jsx(Le,{page:s.page,totalPages:s.totalPages(Y),onPageChange:s.setPage,total:Y,pageSize:s.pageSize,onPageSizeChange:s.setPageSize}),e.jsx(Je,{claimTarget:u,onClose:()=>i(null),claimDuration:g,onDurationChange:n=>{y(n),j(0)},claimDurations:C,customClaimMinutes:E,onCustomClaimChange:F,onClaim:ie,isPending:M.isPending}),e.jsx(Ge,{open:R,onClose:()=>v(!1),selectedCount:r.size,onSubmit:de,isPending:l.isPending}),e.jsx(Ve,{open:_,onClose:()=>B(!1),selectedCount:r.size,selectedRoles:ne,onSubmit:ue,isPending:L.isPending}),e.jsx(Ee,{open:f,onClose:()=>N(!1),onConfirm:me,selectedCount:r.size,isPending:k.isPending,error:k.error})]})}export{yt as AvailableEscalationsPage};
2
- //# sourceMappingURL=AvailableEscalationsPage-DIqdBCwe.js.map