@hotmeshio/long-tail 0.20.0 → 0.21.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 (351) hide show
  1. package/README.md +4 -4
  2. package/build/api/escalations/accumulate.d.ts +96 -0
  3. package/build/api/escalations/accumulate.js +516 -0
  4. package/build/api/escalations/index.d.ts +1 -0
  5. package/build/api/escalations/index.js +10 -1
  6. package/build/api/roles.d.ts +4 -5
  7. package/build/api/roles.js +53 -4
  8. package/build/api/scan-codes/execute.js +2 -0
  9. package/build/api/scan-codes/verbs.d.ts +15 -0
  10. package/build/api/scan-codes/verbs.js +65 -0
  11. package/build/index.js +60 -0
  12. package/build/lib/db/schemas/036_role_portals.sql +12 -0
  13. package/build/routes/escalations/accumulate.d.ts +7 -0
  14. package/build/routes/escalations/accumulate.js +150 -0
  15. package/build/routes/escalations/index.js +5 -0
  16. package/build/sdk/index.d.ts +25 -0
  17. package/build/sdk/index.js +8 -0
  18. package/build/services/escalation/accumulate.d.ts +81 -0
  19. package/build/services/escalation/accumulate.js +154 -0
  20. package/build/services/escalation/index.d.ts +1 -0
  21. package/build/services/escalation/index.js +1 -0
  22. package/build/services/mcp/playwright-server/schemas.d.ts +2 -2
  23. package/build/services/orchestrator/condition.d.ts +40 -3
  24. package/build/services/orchestrator/condition.js +42 -2
  25. package/build/services/role/index.js +1 -0
  26. package/build/services/role/seed.js +6 -1
  27. package/build/services/role/sql.d.ts +6 -3
  28. package/build/services/role/sql.js +7 -2
  29. package/build/services/role/types.d.ts +38 -10
  30. package/build/services/role/types.js +10 -1
  31. package/build/services/scan-code/validate.js +16 -0
  32. package/build/shared/form-validation/display-only-widgets.d.ts +16 -0
  33. package/build/shared/form-validation/display-only-widgets.js +25 -0
  34. package/build/shared/form-validation/index.d.ts +2 -0
  35. package/build/shared/form-validation/index.js +2 -0
  36. package/build/shared/form-validation/x-lt-bind.d.ts +2 -14
  37. package/build/shared/form-validation/x-lt-bind.js +12 -8
  38. package/build/shared/form-validation/x-lt-invoke.d.ts +38 -0
  39. package/build/shared/form-validation/x-lt-invoke.js +103 -0
  40. package/build/system/mcp-servers/admin/escalations.js +39 -0
  41. package/build/system/mcp-servers/admin/schemas.d.ts +192 -13
  42. package/build/system/mcp-servers/admin/schemas.js +39 -3
  43. package/build/system/mcp-servers/admin/users.js +1 -0
  44. package/build/system/mcp-servers/docs.js +4 -0
  45. package/build/system/mcp-servers/human-queue-schemas.d.ts +85 -0
  46. package/build/system/mcp-servers/human-queue-schemas.js +19 -1
  47. package/build/system/mcp-servers/human-queue.d.ts +2 -0
  48. package/build/system/mcp-servers/human-queue.js +77 -0
  49. package/build/system/seed/tool-manifests-admin.d.ts +922 -103
  50. package/build/system/seed/tool-manifests-admin.js +4 -1
  51. package/build/system/seed/tool-manifests-escalation.d.ts +174 -0
  52. package/build/system/seed/tool-manifests-escalation.js +56 -0
  53. package/build/tsconfig.tsbuildinfo +1 -1
  54. package/build/types/escalation.d.ts +52 -0
  55. package/build/types/escalation.js +29 -1
  56. package/build/types/index.d.ts +2 -2
  57. package/build/types/index.js +3 -1
  58. package/build/types/scan-code.d.ts +24 -0
  59. package/build/types/scan-code.js +9 -0
  60. package/build/types/startup.d.ts +20 -0
  61. package/dashboard/dist/assets/{AdminDashboard-DplvDBti.js → AdminDashboard-uarpHB88.js} +2 -2
  62. package/dashboard/dist/assets/{AdminDashboard-DplvDBti.js.map → AdminDashboard-uarpHB88.js.map} +1 -1
  63. package/dashboard/dist/assets/{AgentConfigPage-D8Bf6YxO.js → AgentConfigPage-BcUaDD5E.js} +6 -6
  64. package/dashboard/dist/assets/{AgentConfigPage-D8Bf6YxO.js.map → AgentConfigPage-BcUaDD5E.js.map} +1 -1
  65. package/dashboard/dist/assets/{AgentDetailPage-BN8g0Y2G.js → AgentDetailPage-BaZBhK6i.js} +3 -3
  66. package/dashboard/dist/assets/{AgentDetailPage-BN8g0Y2G.js.map → AgentDetailPage-BaZBhK6i.js.map} +1 -1
  67. package/dashboard/dist/assets/AgentsPage-CuVFSDc4.js +2 -0
  68. package/dashboard/dist/assets/{AgentsPage-7JJBHku8.js.map → AgentsPage-CuVFSDc4.js.map} +1 -1
  69. package/dashboard/dist/assets/AvailableEscalationsPage-iO5NyyIK.js +2 -0
  70. package/dashboard/dist/assets/AvailableEscalationsPage-iO5NyyIK.js.map +1 -0
  71. package/dashboard/dist/assets/{BotPicker-CGCnIz8I.js → BotPicker-CClMby6B.js} +2 -2
  72. package/dashboard/dist/assets/{BotPicker-CGCnIz8I.js.map → BotPicker-CClMby6B.js.map} +1 -1
  73. package/dashboard/dist/assets/BulkAssignModal-BL8FRgkN.js +2 -0
  74. package/dashboard/dist/assets/{BulkAssignModal-NJBcoj-f.js.map → BulkAssignModal-BL8FRgkN.js.map} +1 -1
  75. package/dashboard/dist/assets/CapabilitiesPage-D53ogPor.js +2 -0
  76. package/dashboard/dist/assets/{CapabilitiesPage-F8dpNn9B.js.map → CapabilitiesPage-D53ogPor.js.map} +1 -1
  77. package/dashboard/dist/assets/{CollapsibleSection-BZW6VpCU.js → CollapsibleSection-ow8jpbtD.js} +2 -2
  78. package/dashboard/dist/assets/{CollapsibleSection-BZW6VpCU.js.map → CollapsibleSection-ow8jpbtD.js.map} +1 -1
  79. package/dashboard/dist/assets/{ConfirmDeleteModal-64adXLdq.js → ConfirmDeleteModal-CeEDt9iJ.js} +2 -2
  80. package/dashboard/dist/assets/{ConfirmDeleteModal-64adXLdq.js.map → ConfirmDeleteModal-CeEDt9iJ.js.map} +1 -1
  81. package/dashboard/dist/assets/{CountdownTimer-BxDub9d2.js → CountdownTimer-CSqyZMCG.js} +2 -2
  82. package/dashboard/dist/assets/{CountdownTimer-BxDub9d2.js.map → CountdownTimer-CSqyZMCG.js.map} +1 -1
  83. package/dashboard/dist/assets/{CredentialsPage-CnLzopLL.js → CredentialsPage-Dx7SxA23.js} +2 -2
  84. package/dashboard/dist/assets/{CredentialsPage-CnLzopLL.js.map → CredentialsPage-Dx7SxA23.js.map} +1 -1
  85. package/dashboard/dist/assets/{CronLabel-CAD5UYDT.js → CronLabel-LYPxpvNN.js} +2 -2
  86. package/dashboard/dist/assets/{CronLabel-CAD5UYDT.js.map → CronLabel-LYPxpvNN.js.map} +1 -1
  87. package/dashboard/dist/assets/DataTable-spX1dFyb.js +2 -0
  88. package/dashboard/dist/assets/DataTable-spX1dFyb.js.map +1 -0
  89. package/dashboard/dist/assets/{DropZone-XlcY8hEH.js → DropZone-f1o-GLM8.js} +2 -2
  90. package/dashboard/dist/assets/{DropZone-XlcY8hEH.js.map → DropZone-f1o-GLM8.js.map} +1 -1
  91. package/dashboard/dist/assets/{ElapsedCell-CwO4ufd0.js → ElapsedCell-BZJTSm9N.js} +2 -2
  92. package/dashboard/dist/assets/{ElapsedCell-CwO4ufd0.js.map → ElapsedCell-BZJTSm9N.js.map} +1 -1
  93. package/dashboard/dist/assets/EntityTimelinePanel-0wIIW2en.js +2 -0
  94. package/dashboard/dist/assets/{EntityTimelinePanel-CkF-oW-m.js.map → EntityTimelinePanel-0wIIW2en.js.map} +1 -1
  95. package/dashboard/dist/assets/{EscalationListSchemaPage-h9JO_q5f.js → EscalationListSchemaPage-CoYvtMzj.js} +3 -3
  96. package/dashboard/dist/assets/{EscalationListSchemaPage-h9JO_q5f.js.map → EscalationListSchemaPage-CoYvtMzj.js.map} +1 -1
  97. package/dashboard/dist/assets/EscalationListView-DWFHPufv.js +2 -0
  98. package/dashboard/dist/assets/EscalationListView-DWFHPufv.js.map +1 -0
  99. package/dashboard/dist/assets/{EscalationSchemaPage-mJFL5_Se.js → EscalationSchemaPage-C9Xu_A25.js} +3 -3
  100. package/dashboard/dist/assets/{EscalationSchemaPage-mJFL5_Se.js.map → EscalationSchemaPage-C9Xu_A25.js.map} +1 -1
  101. package/dashboard/dist/assets/EscalationTimeline-D8W2LNNk.js +2 -0
  102. package/dashboard/dist/assets/EscalationTimeline-D8W2LNNk.js.map +1 -0
  103. package/dashboard/dist/assets/EscalationTitleSelect-DLK8NWMp.js +2 -0
  104. package/dashboard/dist/assets/EscalationTitleSelect-DLK8NWMp.js.map +1 -0
  105. package/dashboard/dist/assets/{EscalationsOverview-DlXUFqWJ.js → EscalationsOverview-CW57FaP9.js} +2 -2
  106. package/dashboard/dist/assets/{EscalationsOverview-DlXUFqWJ.js.map → EscalationsOverview-CW57FaP9.js.map} +1 -1
  107. package/dashboard/dist/assets/{EventTable-Ike2xchn.js → EventTable-D1ctWhKf.js} +2 -2
  108. package/dashboard/dist/assets/{EventTable-Ike2xchn.js.map → EventTable-D1ctWhKf.js.map} +1 -1
  109. package/dashboard/dist/assets/{FilterBar-DMOR-O1c.js → FilterBar-C-iur-Nj.js} +2 -2
  110. package/dashboard/dist/assets/{FilterBar-DMOR-O1c.js.map → FilterBar-C-iur-Nj.js.map} +1 -1
  111. package/dashboard/dist/assets/GraphInvokePage-CcA_44M4.js +2 -0
  112. package/dashboard/dist/assets/{GraphInvokePage-CKtvWowP.js.map → GraphInvokePage-CcA_44M4.js.map} +1 -1
  113. package/dashboard/dist/assets/HomePage-Dc085ghJ.js +2 -0
  114. package/dashboard/dist/assets/{HomePage-BQ3Q791Q.js.map → HomePage-Dc085ghJ.js.map} +1 -1
  115. package/dashboard/dist/assets/ListToolbar-h_ziBt4O.js +2 -0
  116. package/dashboard/dist/assets/{ListToolbar-DdJzj472.js.map → ListToolbar-h_ziBt4O.js.map} +1 -1
  117. package/dashboard/dist/assets/{McpOverview-BbtrduWn.js → McpOverview-qXXhbNWV.js} +2 -2
  118. package/dashboard/dist/assets/{McpOverview-BbtrduWn.js.map → McpOverview-qXXhbNWV.js.map} +1 -1
  119. package/dashboard/dist/assets/{McpQueryDetailPage-C1L4T-Wt.js → McpQueryDetailPage-SEzSbZrd.js} +2 -2
  120. package/dashboard/dist/assets/{McpQueryDetailPage-C1L4T-Wt.js.map → McpQueryDetailPage-SEzSbZrd.js.map} +1 -1
  121. package/dashboard/dist/assets/McpQueryPage-Cy0V0kv9.js +2 -0
  122. package/dashboard/dist/assets/{McpQueryPage-CfJy7HZ7.js.map → McpQueryPage-Cy0V0kv9.js.map} +1 -1
  123. package/dashboard/dist/assets/{McpRunDetailPage-CA9yv7he.js → McpRunDetailPage-DjJO5vSb.js} +2 -2
  124. package/dashboard/dist/assets/{McpRunDetailPage-CA9yv7he.js.map → McpRunDetailPage-DjJO5vSb.js.map} +1 -1
  125. package/dashboard/dist/assets/McpRunsPage-BfjiJ8mM.js +2 -0
  126. package/dashboard/dist/assets/{McpRunsPage-D7QXjW9z.js.map → McpRunsPage-BfjiJ8mM.js.map} +1 -1
  127. package/dashboard/dist/assets/{NamespacePill-Bb3revqD.js → NamespacePill-DADRJOUl.js} +2 -2
  128. package/dashboard/dist/assets/{NamespacePill-Bb3revqD.js.map → NamespacePill-DADRJOUl.js.map} +1 -1
  129. package/dashboard/dist/assets/OperationsPage-dJcER0T_.js +3 -0
  130. package/dashboard/dist/assets/OperationsPage-dJcER0T_.js.map +1 -0
  131. package/dashboard/dist/assets/OperatorDashboard-zCkW4eqk.js +2 -0
  132. package/dashboard/dist/assets/{OperatorDashboard-sXNDh1Ph.js.map → OperatorDashboard-zCkW4eqk.js.map} +1 -1
  133. package/dashboard/dist/assets/{PageHeader-Di5Sz3an.js → PageHeader-Csq434-v.js} +2 -2
  134. package/dashboard/dist/assets/{PageHeader-Di5Sz3an.js.map → PageHeader-Csq434-v.js.map} +1 -1
  135. package/dashboard/dist/assets/{PageHeaderWithStats-DutKJ-h2.js → PageHeaderWithStats-CSnk1p5A.js} +2 -2
  136. package/dashboard/dist/assets/{PageHeaderWithStats-DutKJ-h2.js.map → PageHeaderWithStats-CSnk1p5A.js.map} +1 -1
  137. package/dashboard/dist/assets/{PersonaDetailPage-NeHD-Gra.js → PersonaDetailPage-Cx6L3Jvu.js} +2 -2
  138. package/dashboard/dist/assets/{PersonaDetailPage-NeHD-Gra.js.map → PersonaDetailPage-Cx6L3Jvu.js.map} +1 -1
  139. package/dashboard/dist/assets/{PersonasPage-DavKXRWX.js → PersonasPage-DOgGUlJl.js} +2 -2
  140. package/dashboard/dist/assets/{PersonasPage-DavKXRWX.js.map → PersonasPage-DOgGUlJl.js.map} +1 -1
  141. package/dashboard/dist/assets/PortalPage-BKuL1BeJ.js +2 -0
  142. package/dashboard/dist/assets/PortalPage-BKuL1BeJ.js.map +1 -0
  143. package/dashboard/dist/assets/{ProcessDetailPage-DkdKJGe6.js → ProcessDetailPage-BFcFSDUv.js} +2 -2
  144. package/dashboard/dist/assets/{ProcessDetailPage-DkdKJGe6.js.map → ProcessDetailPage-BFcFSDUv.js.map} +1 -1
  145. package/dashboard/dist/assets/ProcessesListPage-BaHV2cXp.js +2 -0
  146. package/dashboard/dist/assets/{ProcessesListPage-CjwVKe32.js.map → ProcessesListPage-BaHV2cXp.js.map} +1 -1
  147. package/dashboard/dist/assets/ResolverForm-Bgc0Zrya.js +7 -0
  148. package/dashboard/dist/assets/ResolverForm-Bgc0Zrya.js.map +1 -0
  149. package/dashboard/dist/assets/RoleDetailPage-BPY6i3CU.js +8 -0
  150. package/dashboard/dist/assets/RoleDetailPage-BPY6i3CU.js.map +1 -0
  151. package/dashboard/dist/assets/{RolePill-DhnVPK4q.js → RolePill-BafrASDX.js} +2 -2
  152. package/dashboard/dist/assets/{RolePill-DhnVPK4q.js.map → RolePill-BafrASDX.js.map} +1 -1
  153. package/dashboard/dist/assets/{RolesPage-OM9KM8Pg.js → RolesPage-DSqqKPbv.js} +2 -2
  154. package/dashboard/dist/assets/{RolesPage-OM9KM8Pg.js.map → RolesPage-DSqqKPbv.js.map} +1 -1
  155. package/dashboard/dist/assets/RunAsSelector-B29iWwel.js +2 -0
  156. package/dashboard/dist/assets/{RunAsSelector-fFMt1bGe.js.map → RunAsSelector-B29iWwel.js.map} +1 -1
  157. package/dashboard/dist/assets/{ScanCodesPage-AujH-pPQ.js → ScanCodesPage-S8aAJfnC.js} +2 -2
  158. package/dashboard/dist/assets/{ScanCodesPage-AujH-pPQ.js.map → ScanCodesPage-S8aAJfnC.js.map} +1 -1
  159. package/dashboard/dist/assets/{ScanSchemeDetailPage-eKQpmsC_.js → ScanSchemeDetailPage-CUBRAtmJ.js} +2 -2
  160. package/dashboard/dist/assets/{ScanSchemeDetailPage-eKQpmsC_.js.map → ScanSchemeDetailPage-CUBRAtmJ.js.map} +1 -1
  161. package/dashboard/dist/assets/ScanStationPage-R9t1-CeQ.js +2 -0
  162. package/dashboard/dist/assets/{ScanStationPage-C1_ppDoZ.js.map → ScanStationPage-R9t1-CeQ.js.map} +1 -1
  163. package/dashboard/dist/assets/{ScopeBadge-CXUg0FHo.js → ScopeBadge-b6MIBiYD.js} +2 -2
  164. package/dashboard/dist/assets/{ScopeBadge-CXUg0FHo.js.map → ScopeBadge-b6MIBiYD.js.map} +1 -1
  165. package/dashboard/dist/assets/{StickyPagination-B91Pk9xh.js → StickyPagination-CkW_A507.js} +2 -2
  166. package/dashboard/dist/assets/{StickyPagination-B91Pk9xh.js.map → StickyPagination-CkW_A507.js.map} +1 -1
  167. package/dashboard/dist/assets/{StreamMessageDetail-C7SPqaJt.js → StreamMessageDetail-yzWX0wac.js} +2 -2
  168. package/dashboard/dist/assets/{StreamMessageDetail-C7SPqaJt.js.map → StreamMessageDetail-yzWX0wac.js.map} +1 -1
  169. package/dashboard/dist/assets/{SwimlaneTimeline-BcHR8ylf.js → SwimlaneTimeline-Cf4DXFxj.js} +2 -2
  170. package/dashboard/dist/assets/{SwimlaneTimeline-BcHR8ylf.js.map → SwimlaneTimeline-Cf4DXFxj.js.map} +1 -1
  171. package/dashboard/dist/assets/{TagInput-BZ8vb2oW.js → TagInput-ZrIIrEUP.js} +2 -2
  172. package/dashboard/dist/assets/{TagInput-BZ8vb2oW.js.map → TagInput-ZrIIrEUP.js.map} +1 -1
  173. package/dashboard/dist/assets/{TaskDetailPage-Bqj0I_I0.js → TaskDetailPage-DCDcEps9.js} +2 -2
  174. package/dashboard/dist/assets/{TaskDetailPage-Bqj0I_I0.js.map → TaskDetailPage-DCDcEps9.js.map} +1 -1
  175. package/dashboard/dist/assets/{TaskQueuePill-Bxir8WRl.js → TaskQueuePill-DkQ1uc6y.js} +2 -2
  176. package/dashboard/dist/assets/{TaskQueuePill-Bxir8WRl.js.map → TaskQueuePill-DkQ1uc6y.js.map} +1 -1
  177. package/dashboard/dist/assets/TasksListPage-BBATgpf7.js +2 -0
  178. package/dashboard/dist/assets/{TasksListPage-BB1f79lL.js.map → TasksListPage-BBATgpf7.js.map} +1 -1
  179. package/dashboard/dist/assets/{TimeAgo-BFnODmNe.js → TimeAgo-CSNVEjch.js} +2 -2
  180. package/dashboard/dist/assets/{TimeAgo-BFnODmNe.js.map → TimeAgo-CSNVEjch.js.map} +1 -1
  181. package/dashboard/dist/assets/{TimestampCell-BXgLOBsr.js → TimestampCell-Du1nBrPn.js} +2 -2
  182. package/dashboard/dist/assets/{TimestampCell-BXgLOBsr.js.map → TimestampCell-Du1nBrPn.js.map} +1 -1
  183. package/dashboard/dist/assets/{ToolPill-FkgTXIhq.js → ToolPill-Baxm02L6.js} +2 -2
  184. package/dashboard/dist/assets/{ToolPill-FkgTXIhq.js.map → ToolPill-Baxm02L6.js.map} +1 -1
  185. package/dashboard/dist/assets/ToolTestPanel-CF-h_5Rg.js +2 -0
  186. package/dashboard/dist/assets/{ToolTestPanel-Bwe3J5lj.js.map → ToolTestPanel-CF-h_5Rg.js.map} +1 -1
  187. package/dashboard/dist/assets/{TopicDetailPage-DAF07vZ9.js → TopicDetailPage-Dr1UmWcp.js} +3 -3
  188. package/dashboard/dist/assets/{TopicDetailPage-DAF07vZ9.js.map → TopicDetailPage-Dr1UmWcp.js.map} +1 -1
  189. package/dashboard/dist/assets/TopicsPage-CUUo-Ylf.js +2 -0
  190. package/dashboard/dist/assets/{TopicsPage-C1gxBUap.js.map → TopicsPage-CUUo-Ylf.js.map} +1 -1
  191. package/dashboard/dist/assets/{UserName-BzXJUE6q.js → UserName-kBh1dc39.js} +2 -2
  192. package/dashboard/dist/assets/{UserName-BzXJUE6q.js.map → UserName-kBh1dc39.js.map} +1 -1
  193. package/dashboard/dist/assets/{WorkflowExecutionPage-SkRU5cRX.js → WorkflowExecutionPage-CCRSbnDx.js} +2 -2
  194. package/dashboard/dist/assets/{WorkflowExecutionPage-SkRU5cRX.js.map → WorkflowExecutionPage-CCRSbnDx.js.map} +1 -1
  195. package/dashboard/dist/assets/{WorkflowPill--AYMW7u_.js → WorkflowPill-ZepbO_ny.js} +2 -2
  196. package/dashboard/dist/assets/{WorkflowPill--AYMW7u_.js.map → WorkflowPill-ZepbO_ny.js.map} +1 -1
  197. package/dashboard/dist/assets/WorkflowsDashboard-BNQVvyek.js +2 -0
  198. package/dashboard/dist/assets/{WorkflowsDashboard-CZAqRk1N.js.map → WorkflowsDashboard-BNQVvyek.js.map} +1 -1
  199. package/dashboard/dist/assets/{WorkflowsOverview-BoN44VTE.js → WorkflowsOverview-DswubNJN.js} +2 -2
  200. package/dashboard/dist/assets/{WorkflowsOverview-BoN44VTE.js.map → WorkflowsOverview-DswubNJN.js.map} +1 -1
  201. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CqjhtdJf.js → YamlWorkflowDetailPage-Cw9Dlmup.js} +11 -11
  202. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CqjhtdJf.js.map → YamlWorkflowDetailPage-Cw9Dlmup.js.map} +1 -1
  203. package/dashboard/dist/assets/{YamlWorkflowsPage-CwnJkzyb.js → YamlWorkflowsPage-DB8xnIXy.js} +2 -2
  204. package/dashboard/dist/assets/{YamlWorkflowsPage-CwnJkzyb.js.map → YamlWorkflowsPage-DB8xnIXy.js.map} +1 -1
  205. package/dashboard/dist/assets/{agents-gV0Ys-sY.js → agents-BwEnf6N9.js} +2 -2
  206. package/dashboard/dist/assets/{agents-gV0Ys-sY.js.map → agents-BwEnf6N9.js.map} +1 -1
  207. package/dashboard/dist/assets/{bots-B97itB3I.js → bots-CCmJTT2u.js} +2 -2
  208. package/dashboard/dist/assets/{bots-B97itB3I.js.map → bots-CCmJTT2u.js.map} +1 -1
  209. package/dashboard/dist/assets/{capabilities-CR9xZgGd.js → capabilities-BZHgp_nh.js} +2 -2
  210. package/dashboard/dist/assets/{capabilities-CR9xZgGd.js.map → capabilities-BZHgp_nh.js.map} +1 -1
  211. package/dashboard/dist/assets/{constants-BHkpVaqx.js → constants-CeBBTzf5.js} +2 -2
  212. package/dashboard/dist/assets/{constants-BHkpVaqx.js.map → constants-CeBBTzf5.js.map} +1 -1
  213. package/dashboard/dist/assets/{controlplane-YxvP1KCa.js → controlplane-CyfwUlFA.js} +2 -2
  214. package/dashboard/dist/assets/{controlplane-YxvP1KCa.js.map → controlplane-CyfwUlFA.js.map} +1 -1
  215. package/dashboard/dist/assets/escalation-columns-BJPTNmLW.js +2 -0
  216. package/dashboard/dist/assets/escalation-columns-BJPTNmLW.js.map +1 -0
  217. package/dashboard/dist/assets/index-3gbd5neL.js +67 -0
  218. package/dashboard/dist/assets/index-3gbd5neL.js.map +1 -0
  219. package/dashboard/dist/assets/index-BAAVTyZ-.js +2 -0
  220. package/dashboard/dist/assets/{index-BQpV-DTG.js.map → index-BAAVTyZ-.js.map} +1 -1
  221. package/dashboard/dist/assets/{index-B9BBCqLI.js → index-BC6Jenlo.js} +2 -2
  222. package/dashboard/dist/assets/{index-B9BBCqLI.js.map → index-BC6Jenlo.js.map} +1 -1
  223. package/dashboard/dist/assets/index-C7KHqOTQ.js +2 -0
  224. package/dashboard/dist/assets/{index-Bp9KBLT5.js.map → index-C7KHqOTQ.js.map} +1 -1
  225. package/dashboard/dist/assets/index-CDrqqbSR.js +3 -0
  226. package/dashboard/dist/assets/index-CDrqqbSR.js.map +1 -0
  227. package/dashboard/dist/assets/index-CVwzCZ43.js +2 -0
  228. package/dashboard/dist/assets/{index-CFbo9FU9.js.map → index-CVwzCZ43.js.map} +1 -1
  229. package/dashboard/dist/assets/index-CaGF6TCC.js +2 -0
  230. package/dashboard/dist/assets/index-CaGF6TCC.js.map +1 -0
  231. package/dashboard/dist/assets/index-ClVbfe4z.js +13 -0
  232. package/dashboard/dist/assets/{index-Cfvkl2J0.js.map → index-ClVbfe4z.js.map} +1 -1
  233. package/dashboard/dist/assets/{index-DMeaiKgf.js → index-CuVkSmj5.js} +2 -2
  234. package/dashboard/dist/assets/{index-DMeaiKgf.js.map → index-CuVkSmj5.js.map} +1 -1
  235. package/dashboard/dist/assets/{index-ipqwPavs.js → index-DAuX_PlL.js} +2 -2
  236. package/dashboard/dist/assets/{index-ipqwPavs.js.map → index-DAuX_PlL.js.map} +1 -1
  237. package/dashboard/dist/assets/{index-CIpHj4di.js → index-DBWS5QL8.js} +2 -2
  238. package/dashboard/dist/assets/{index-CIpHj4di.js.map → index-DBWS5QL8.js.map} +1 -1
  239. package/dashboard/dist/assets/index-DIWCI6HC.js +2 -0
  240. package/dashboard/dist/assets/{index-CUZ6LYye.js.map → index-DIWCI6HC.js.map} +1 -1
  241. package/dashboard/dist/assets/{index-DwOnWeu8.js → index-DZ8X_Gp4.js} +2 -2
  242. package/dashboard/dist/assets/{index-DwOnWeu8.js.map → index-DZ8X_Gp4.js.map} +1 -1
  243. package/dashboard/dist/assets/index-Dh8MJl3L.css +1 -0
  244. package/dashboard/dist/assets/{knowledge-XX6cW4Ob.js → knowledge-CqyLhUMg.js} +2 -2
  245. package/dashboard/dist/assets/{knowledge-XX6cW4Ob.js.map → knowledge-CqyLhUMg.js.map} +1 -1
  246. package/dashboard/dist/assets/{mcp-CH13hNH2.js → mcp-Cvu6bFYH.js} +2 -2
  247. package/dashboard/dist/assets/{mcp-CH13hNH2.js.map → mcp-Cvu6bFYH.js.map} +1 -1
  248. package/dashboard/dist/assets/{mcp-query-Duydd3JA.js → mcp-query-qC6A3e9l.js} +2 -2
  249. package/dashboard/dist/assets/{mcp-query-Duydd3JA.js.map → mcp-query-qC6A3e9l.js.map} +1 -1
  250. package/dashboard/dist/assets/metadata-display-COo3mMCr.js +2 -0
  251. package/dashboard/dist/assets/metadata-display-COo3mMCr.js.map +1 -0
  252. package/dashboard/dist/assets/{personas-mDk4lLQS.js → personas-BKN_lJuV.js} +2 -2
  253. package/dashboard/dist/assets/{personas-mDk4lLQS.js.map → personas-BKN_lJuV.js.map} +1 -1
  254. package/dashboard/dist/assets/{pipelines-B5GcgCeF.js → pipelines-BldIfv85.js} +2 -2
  255. package/dashboard/dist/assets/{pipelines-B5GcgCeF.js.map → pipelines-BldIfv85.js.map} +1 -1
  256. package/dashboard/dist/assets/{tasks-CItmNsRp.js → tasks-B-Uay8uL.js} +2 -2
  257. package/dashboard/dist/assets/{tasks-CItmNsRp.js.map → tasks-B-Uay8uL.js.map} +1 -1
  258. package/dashboard/dist/assets/{topics-CJYG7BX5.js → topics-438EQogt.js} +2 -2
  259. package/dashboard/dist/assets/{topics-CJYG7BX5.js.map → topics-438EQogt.js.map} +1 -1
  260. package/dashboard/dist/assets/useContainerWidth-DSLp1gEm.js +2 -0
  261. package/dashboard/dist/assets/useContainerWidth-DSLp1gEm.js.map +1 -0
  262. package/dashboard/dist/assets/{useDebouncedValue-BrwgXcp8.js → useDebouncedValue-Cw8hYZ8y.js} +2 -2
  263. package/dashboard/dist/assets/{useDebouncedValue-BrwgXcp8.js.map → useDebouncedValue-Cw8hYZ8y.js.map} +1 -1
  264. package/dashboard/dist/assets/{useNamespace-CHty0HAS.js → useNamespace-D1218GQ8.js} +2 -2
  265. package/dashboard/dist/assets/{useNamespace-CHty0HAS.js.map → useNamespace-D1218GQ8.js.map} +1 -1
  266. package/dashboard/dist/assets/{useYamlActivityEvents-CoTsia7t.js → useYamlActivityEvents-BAQf_y_U.js} +2 -2
  267. package/dashboard/dist/assets/{useYamlActivityEvents-CoTsia7t.js.map → useYamlActivityEvents-BAQf_y_U.js.map} +1 -1
  268. package/dashboard/dist/assets/{vendor-icons-DeBdvyKJ.js → vendor-icons-B7OcUM6b.js} +2 -2
  269. package/dashboard/dist/assets/{vendor-icons-DeBdvyKJ.js.map → vendor-icons-B7OcUM6b.js.map} +1 -1
  270. package/dashboard/dist/assets/{yaml-workflows-CiWwx5rM.js → yaml-workflows-CN01gEB0.js} +2 -2
  271. package/dashboard/dist/assets/{yaml-workflows-CiWwx5rM.js.map → yaml-workflows-CN01gEB0.js.map} +1 -1
  272. package/dashboard/dist/index.html +3 -3
  273. package/docs/accumulator.md +113 -0
  274. package/docs/api/http/escalations.md +89 -0
  275. package/docs/api/http/roles.md +1 -0
  276. package/docs/api/sdk/escalations.md +91 -0
  277. package/docs/api/sdk/roles.md +2 -0
  278. package/docs/architecture.md +1 -1
  279. package/docs/code-owned-configuration.md +2 -1
  280. package/docs/dashboard.md +10 -4
  281. package/docs/hitl/design.md +1 -1
  282. package/docs/hitl/escalation.md +37 -1
  283. package/docs/hitl/invoke-form.md +4 -0
  284. package/docs/hitl/pinned-views.md +4 -0
  285. package/docs/hitl/portal.md +97 -0
  286. package/docs/hitl/resolution.md +41 -0
  287. package/docs/hitl/x-lt-embed.md +1 -1
  288. package/docs/hitl/x-lt-invoke.md +95 -0
  289. package/docs/hitl/x-lt-list-schema.md +3 -1
  290. package/docs/hitl/x-lt-widget.md +1 -0
  291. package/docs/hitl-guide.md +8 -1
  292. package/docs/scan-codes.md +15 -2
  293. package/docs/sdk.md +1 -1
  294. package/docs/workflows.md +2 -2
  295. package/package.json +4 -2
  296. package/dashboard/dist/assets/AgentsPage-7JJBHku8.js +0 -2
  297. package/dashboard/dist/assets/AvailableEscalationsPage-lz5qwSjg.js +0 -2
  298. package/dashboard/dist/assets/AvailableEscalationsPage-lz5qwSjg.js.map +0 -1
  299. package/dashboard/dist/assets/BulkAssignModal-NJBcoj-f.js +0 -2
  300. package/dashboard/dist/assets/CapabilitiesPage-F8dpNn9B.js +0 -2
  301. package/dashboard/dist/assets/DataTable-7C7riavf.js +0 -2
  302. package/dashboard/dist/assets/DataTable-7C7riavf.js.map +0 -1
  303. package/dashboard/dist/assets/EntityTimelinePanel-CkF-oW-m.js +0 -2
  304. package/dashboard/dist/assets/EscalationListView-AHW2xtlr.js +0 -2
  305. package/dashboard/dist/assets/EscalationListView-AHW2xtlr.js.map +0 -1
  306. package/dashboard/dist/assets/GraphInvokePage-CKtvWowP.js +0 -2
  307. package/dashboard/dist/assets/HomePage-BQ3Q791Q.js +0 -2
  308. package/dashboard/dist/assets/ListToolbar-DdJzj472.js +0 -2
  309. package/dashboard/dist/assets/McpQueryPage-CfJy7HZ7.js +0 -2
  310. package/dashboard/dist/assets/McpRunsPage-D7QXjW9z.js +0 -2
  311. package/dashboard/dist/assets/OperationsPage-aLHHAP2X.js +0 -3
  312. package/dashboard/dist/assets/OperationsPage-aLHHAP2X.js.map +0 -1
  313. package/dashboard/dist/assets/OperatorDashboard-sXNDh1Ph.js +0 -2
  314. package/dashboard/dist/assets/ProcessesListPage-CjwVKe32.js +0 -2
  315. package/dashboard/dist/assets/ResolverForm-Bk-wDkN-.js +0 -3
  316. package/dashboard/dist/assets/ResolverForm-Bk-wDkN-.js.map +0 -1
  317. package/dashboard/dist/assets/RoleDetailPage-WQt0y5l7.js +0 -8
  318. package/dashboard/dist/assets/RoleDetailPage-WQt0y5l7.js.map +0 -1
  319. package/dashboard/dist/assets/RunAsSelector-fFMt1bGe.js +0 -2
  320. package/dashboard/dist/assets/ScanStationPage-C1_ppDoZ.js +0 -2
  321. package/dashboard/dist/assets/TasksListPage-BB1f79lL.js +0 -2
  322. package/dashboard/dist/assets/ToolTestPanel-Bwe3J5lj.js +0 -2
  323. package/dashboard/dist/assets/TopicsPage-C1gxBUap.js +0 -2
  324. package/dashboard/dist/assets/WorkflowsDashboard-CZAqRk1N.js +0 -2
  325. package/dashboard/dist/assets/escalation-columns-uq-IV2aj.js +0 -2
  326. package/dashboard/dist/assets/escalation-columns-uq-IV2aj.js.map +0 -1
  327. package/dashboard/dist/assets/index-3ezfWLkE.js +0 -6
  328. package/dashboard/dist/assets/index-3ezfWLkE.js.map +0 -1
  329. package/dashboard/dist/assets/index-BQpV-DTG.js +0 -2
  330. package/dashboard/dist/assets/index-Bp9KBLT5.js +0 -2
  331. package/dashboard/dist/assets/index-Bpvfr4OW.css +0 -1
  332. package/dashboard/dist/assets/index-CFbo9FU9.js +0 -2
  333. package/dashboard/dist/assets/index-CIwlVfvV.js +0 -67
  334. package/dashboard/dist/assets/index-CIwlVfvV.js.map +0 -1
  335. package/dashboard/dist/assets/index-CUZ6LYye.js +0 -2
  336. package/dashboard/dist/assets/index-Cfvkl2J0.js +0 -13
  337. package/dashboard/dist/assets/index-SGyrXGp8.js +0 -3
  338. package/dashboard/dist/assets/index-SGyrXGp8.js.map +0 -1
  339. package/dashboard/dist/assets/invoke-context-DrVyUEfs.js +0 -2
  340. package/dashboard/dist/assets/invoke-context-DrVyUEfs.js.map +0 -1
  341. package/dashboard/dist/assets/metadata-display--TzK0REC.js +0 -2
  342. package/dashboard/dist/assets/metadata-display--TzK0REC.js.map +0 -1
  343. package/dashboard/dist/assets/resolver-payload-m9AGKZ3a.js +0 -2
  344. package/dashboard/dist/assets/resolver-payload-m9AGKZ3a.js.map +0 -1
  345. package/docs/compilation.md +0 -152
  346. package/docs/compiler.md +0 -311
  347. package/docs/contributing.md +0 -56
  348. package/docs/design-principles.md +0 -245
  349. package/docs/schema-exchange.md +0 -173
  350. package/docs/self-test.md +0 -106
  351. package/docs/story.md +0 -184
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.accumulateItem = accumulateItem;
4
+ exports.accumulateItemBySignalKey = accumulateItemBySignalKey;
5
+ exports.accumulateItemByMetadata = accumulateItemByMetadata;
6
+ exports.removeAccumulatedItem = removeAccumulatedItem;
7
+ exports.removeAccumulatedItemBySignalKey = removeAccumulatedItemBySignalKey;
8
+ exports.removeAccumulatedItemByMetadata = removeAccumulatedItemByMetadata;
9
+ const escalation_wire_1 = require("../../lib/events/escalation-wire");
10
+ const uuid_1 = require("../../lib/uuid");
11
+ const client_1 = require("./client");
12
+ const crud_1 = require("./crud");
13
+ const map_1 = require("./map");
14
+ const NOT_FOUND = { outcome: 'not-found', count: -1, remaining: null, escalation: null };
15
+ const RECIPROCAL_NOT_FOUND = { ...NOT_FOUND, outcome: 'reciprocal-not-found' };
16
+ function reciprocalIdValid(reciprocal) {
17
+ return !reciprocal?.id || (0, uuid_1.isUuid)(reciprocal.id);
18
+ }
19
+ /**
20
+ * Adds one item to an accumulator escalation in a single atomic SDK
21
+ * statement (guarded append + facet recompute + resolve-and-wake at max,
22
+ * with the reciprocal row written in the same statement or not at all).
23
+ * Interim adds publish `escalation.updated` with the count; a completing
24
+ * add publishes the standard `escalation.resolved`. Both rows publish.
25
+ * Failure outcomes publish nothing because no row changed.
26
+ */
27
+ async function accumulateItem(id, input) {
28
+ if (!(0, uuid_1.isUuid)(id))
29
+ return NOT_FOUND;
30
+ if (!reciprocalIdValid(input.reciprocal))
31
+ return RECIPROCAL_NOT_FOUND;
32
+ const client = await (0, client_1.escalations)();
33
+ const result = await client.accumulateItem({ id, ...input });
34
+ return settleAccumulateOutcome(result, input);
35
+ }
36
+ /** Add selecting the container by its `signal_key`, the deterministic home signal id. */
37
+ async function accumulateItemBySignalKey(signalKey, input) {
38
+ if (!reciprocalIdValid(input.reciprocal))
39
+ return RECIPROCAL_NOT_FOUND;
40
+ const client = await (0, client_1.escalations)();
41
+ const result = await client.accumulateItem({ signalKey, ...input });
42
+ return settleAccumulateOutcome(result, input);
43
+ }
44
+ /** Add selecting the container by metadata facet, scoped by `roles`. */
45
+ async function accumulateItemByMetadata(key, value, input) {
46
+ if (!reciprocalIdValid(input.reciprocal))
47
+ return RECIPROCAL_NOT_FOUND;
48
+ const client = await (0, client_1.escalations)();
49
+ const result = await client.accumulateItemByMetadata({ key, value, ...input });
50
+ return settleAccumulateOutcome(result, input);
51
+ }
52
+ /**
53
+ * Removes one held item from a pending accumulator escalation (and the
54
+ * container's id from the reciprocal row) in one guarded statement. The
55
+ * waiter never wakes; both rows publish `escalation.updated`.
56
+ */
57
+ async function removeAccumulatedItem(id, input) {
58
+ if (!(0, uuid_1.isUuid)(id))
59
+ return { outcome: 'not-found', count: -1, escalation: null };
60
+ if (!reciprocalIdValid(input.reciprocal))
61
+ return { outcome: 'reciprocal-not-found', count: -1, escalation: null };
62
+ const client = await (0, client_1.escalations)();
63
+ const result = await client.removeAccumulatedItem({ id, ...input });
64
+ return settleRemoveOutcome(result, input);
65
+ }
66
+ async function removeAccumulatedItemBySignalKey(signalKey, input) {
67
+ if (!reciprocalIdValid(input.reciprocal))
68
+ return { outcome: 'reciprocal-not-found', count: -1, escalation: null };
69
+ const client = await (0, client_1.escalations)();
70
+ const result = await client.removeAccumulatedItem({ signalKey, ...input });
71
+ return settleRemoveOutcome(result, input);
72
+ }
73
+ async function removeAccumulatedItemByMetadata(key, value, input) {
74
+ if (!reciprocalIdValid(input.reciprocal))
75
+ return { outcome: 'reciprocal-not-found', count: -1, escalation: null };
76
+ const client = await (0, client_1.escalations)();
77
+ const result = await client.removeAccumulatedItemByMetadata({ key, value, ...input });
78
+ return settleRemoveOutcome(result, input);
79
+ }
80
+ function publishSide(escalation, completed, data) {
81
+ (0, crud_1.publishEscalationChange)({
82
+ type: completed ? 'escalation.resolved' : 'escalation.updated',
83
+ source: 'service',
84
+ workflowId: escalation.workflow_id || '',
85
+ workflowName: escalation.workflow_type || '',
86
+ taskQueue: escalation.task_queue || '',
87
+ escalationId: escalation.id,
88
+ role: escalation.role,
89
+ status: completed ? 'resolved' : 'pending',
90
+ data: (0, escalation_wire_1.escalationEventData)(escalation, data),
91
+ });
92
+ }
93
+ function settleAccumulateOutcome(result, input) {
94
+ if (!result.ok) {
95
+ return { outcome: result.outcome, count: -1, remaining: null, escalation: null };
96
+ }
97
+ const escalation = (0, map_1.toEscalationRecord)(result.entry);
98
+ const reciprocal = result.reciprocal
99
+ ? {
100
+ outcome: result.reciprocal.outcome,
101
+ count: result.reciprocal.count,
102
+ remaining: result.reciprocal.remaining,
103
+ escalation: (0, map_1.toEscalationRecord)(result.reciprocal.entry),
104
+ }
105
+ : undefined;
106
+ publishSide(escalation, result.outcome === 'completed', {
107
+ item_key: input.itemKey,
108
+ count: result.count,
109
+ remaining: result.remaining,
110
+ actor: input.actor ?? null,
111
+ reciprocal_id: reciprocal?.escalation.id ?? null,
112
+ });
113
+ if (reciprocal) {
114
+ publishSide(reciprocal.escalation, reciprocal.outcome === 'completed', {
115
+ item_key: escalation.id,
116
+ count: reciprocal.count,
117
+ remaining: reciprocal.remaining,
118
+ actor: input.actor ?? null,
119
+ reciprocal_id: escalation.id,
120
+ });
121
+ }
122
+ return {
123
+ outcome: result.outcome,
124
+ count: result.count,
125
+ remaining: result.remaining,
126
+ escalation,
127
+ ...(reciprocal ? { reciprocal } : {}),
128
+ };
129
+ }
130
+ function settleRemoveOutcome(result, input) {
131
+ if (!result.ok)
132
+ return { outcome: result.outcome, count: -1, escalation: null };
133
+ const escalation = (0, map_1.toEscalationRecord)(result.entry);
134
+ const reciprocal = result.reciprocal
135
+ ? { count: result.reciprocal.count, escalation: (0, map_1.toEscalationRecord)(result.reciprocal.entry) }
136
+ : undefined;
137
+ publishSide(escalation, false, {
138
+ item_key: input.itemKey,
139
+ count: result.count,
140
+ removed: true,
141
+ actor: input.actor ?? null,
142
+ reciprocal_id: reciprocal?.escalation.id ?? null,
143
+ });
144
+ if (reciprocal) {
145
+ publishSide(reciprocal.escalation, false, {
146
+ item_key: escalation.id,
147
+ count: reciprocal.count,
148
+ removed: true,
149
+ actor: input.actor ?? null,
150
+ reciprocal_id: escalation.id,
151
+ });
152
+ }
153
+ return { outcome: 'removed', count: result.count, escalation, ...(reciprocal ? { reciprocal } : {}) };
154
+ }
@@ -1,6 +1,7 @@
1
1
  export * from './types';
2
2
  export * from './crud';
3
3
  export * from './batch';
4
+ export * from './accumulate';
4
5
  export * from './bulk';
5
6
  export * from './queries';
6
7
  export * from './resolver-validation';
@@ -18,6 +18,7 @@ exports.AnalyticsInputError = exports.resetAnalyticsCaches = exports.resolveEnti
18
18
  __exportStar(require("./types"), exports);
19
19
  __exportStar(require("./crud"), exports);
20
20
  __exportStar(require("./batch"), exports);
21
+ __exportStar(require("./accumulate"), exports);
21
22
  __exportStar(require("./bulk"), exports);
22
23
  __exportStar(require("./queries"), exports);
23
24
  __exportStar(require("./resolver-validation"), exports);
@@ -54,12 +54,12 @@ export declare const waitForSchema: z.ZodObject<{
54
54
  timeout: z.ZodOptional<z.ZodNumber>;
55
55
  }, "strip", z.ZodTypeAny, {
56
56
  selector: string;
57
- page_id?: string | undefined;
58
57
  timeout?: number | undefined;
58
+ page_id?: string | undefined;
59
59
  }, {
60
60
  selector: string;
61
- page_id?: string | undefined;
62
61
  timeout?: number | undefined;
62
+ page_id?: string | undefined;
63
63
  }>;
64
64
  export declare const evaluateSchema: z.ZodObject<{
65
65
  page_id: z.ZodOptional<z.ZodString>;
@@ -1,5 +1,5 @@
1
1
  import type { Types } from '@hotmeshio/hotmesh';
2
- import { type EscalationLookupRef } from '../../types/escalation';
2
+ import { type AccumulateConfig, type AccumulatorResult, type EscalationLookupRef } from '../../types/escalation';
3
3
  /**
4
4
  * HotMesh's escalation config plus long-tail sugar. `schemaVersion` pins the
5
5
  * role form version (lt_role_schemas) the resolve UI renders; `lookups` pins
@@ -116,8 +116,32 @@ export type ConditionEscalationConfig = Types.ConditionQueueConfig & {
116
116
  * ```
117
117
  *
118
118
  * `timeout`/cancel semantics are unchanged (`false`/`null`); partially filled
119
- * items persist on the terminal row for audit. A plain resolve on a batch row
120
- * remains an admin override that resolves the whole row with its payload.
119
+ * items persist on the terminal row for audit. Add `partialOnTimeout: true`
120
+ * (hotmesh 0.29.0+) and the timer instead resumes with the items filled so
121
+ * far plus `$trigger: 'timeout'`. A plain resolve on a batch row remains an
122
+ * admin override that resolves the whole row with its payload.
123
+ *
124
+ * **Open accumulation — items arrive over time (hotmesh 0.29.0+).** Declare
125
+ * `accumulate` and the escalation holds items added via `accumulateItem`
126
+ * (HTTP: POST /:id/accumulate, /accumulate-by-signal-key,
127
+ * /accumulate-by-metadata) until `max` items are held, the `timeout` fires,
128
+ * or someone resolves the row. Every path except cancel delivers the ordered
129
+ * collection with the trigger that ended the wait, so a timeout is a
130
+ * delivery window, never a failure. Progress rides `metadata.accumulate_count`
131
+ * / `accumulate_max` / `accumulate_keys` as queryable facets; entries live in
132
+ * `envelope.accumulate_items`. Use {@link conditionalAccumulator} for the
133
+ * typed form:
134
+ *
135
+ * ```typescript
136
+ * const bin = await conditionalAccumulator<BagV1>(signalId, {
137
+ * role: 'bin',
138
+ * metadata: { binKey },
139
+ * accumulate: { max: 12 },
140
+ * timeout: '4h',
141
+ * });
142
+ * if (bin === null) { /* cancelled *​/ }
143
+ * else bin.$trigger; // 'count' | 'timeout' | 'resolve'
144
+ * ```
121
145
  *
122
146
  * **Resolution provenance — the reserved `$resolution` key.** When the resolve
123
147
  * carries the resolver's identity (the API layer supplies it for interactive
@@ -155,3 +179,16 @@ export type ConditionEscalationConfig = Types.ConditionQueueConfig & {
155
179
  export declare function conditional<T = Record<string, any>>(signalId: string, escalation?: ConditionEscalationConfig): Promise<T | false | null>;
156
180
  /** @deprecated Alias of {@link conditional}. */
157
181
  export declare const conditionLT: typeof conditional;
182
+ /** {@link ConditionEscalationConfig} with the accumulator declaration required. */
183
+ export type ConditionAccumulatorConfig = ConditionEscalationConfig & {
184
+ accumulate: AccumulateConfig;
185
+ };
186
+ /**
187
+ * {@link conditional} for an open accumulator: the same wait, typed for the
188
+ * contract an accumulator row keeps. It resolves with the ordered
189
+ * `$accumulated` collection and its `$trigger` on every terminal path
190
+ * (`count`, `timeout`, `resolve`), so `false` is not in the return type;
191
+ * cancellation still yields `null`. `P` types each item's payload, `R` the
192
+ * manual resolver payload merged in on `resolve`.
193
+ */
194
+ export declare function conditionalAccumulator<P = Record<string, any>, R extends Record<string, any> = Record<string, any>>(signalId: string, escalation: ConditionAccumulatorConfig): Promise<AccumulatorResult<P, R> | null>;
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.conditionLT = void 0;
37
37
  exports.conditional = conditional;
38
+ exports.conditionalAccumulator = conditionalAccumulator;
38
39
  const hotmesh_1 = require("@hotmeshio/hotmesh");
39
40
  const escalation_1 = require("../../types/escalation");
40
41
  const interceptorActivities = __importStar(require("../interceptor/activities"));
@@ -162,8 +163,32 @@ function toEngineConfig(escalation) {
162
163
  * ```
163
164
  *
164
165
  * `timeout`/cancel semantics are unchanged (`false`/`null`); partially filled
165
- * items persist on the terminal row for audit. A plain resolve on a batch row
166
- * remains an admin override that resolves the whole row with its payload.
166
+ * items persist on the terminal row for audit. Add `partialOnTimeout: true`
167
+ * (hotmesh 0.29.0+) and the timer instead resumes with the items filled so
168
+ * far plus `$trigger: 'timeout'`. A plain resolve on a batch row remains an
169
+ * admin override that resolves the whole row with its payload.
170
+ *
171
+ * **Open accumulation — items arrive over time (hotmesh 0.29.0+).** Declare
172
+ * `accumulate` and the escalation holds items added via `accumulateItem`
173
+ * (HTTP: POST /:id/accumulate, /accumulate-by-signal-key,
174
+ * /accumulate-by-metadata) until `max` items are held, the `timeout` fires,
175
+ * or someone resolves the row. Every path except cancel delivers the ordered
176
+ * collection with the trigger that ended the wait, so a timeout is a
177
+ * delivery window, never a failure. Progress rides `metadata.accumulate_count`
178
+ * / `accumulate_max` / `accumulate_keys` as queryable facets; entries live in
179
+ * `envelope.accumulate_items`. Use {@link conditionalAccumulator} for the
180
+ * typed form:
181
+ *
182
+ * ```typescript
183
+ * const bin = await conditionalAccumulator<BagV1>(signalId, {
184
+ * role: 'bin',
185
+ * metadata: { binKey },
186
+ * accumulate: { max: 12 },
187
+ * timeout: '4h',
188
+ * });
189
+ * if (bin === null) { /* cancelled *​/ }
190
+ * else bin.$trigger; // 'count' | 'timeout' | 'resolve'
191
+ * ```
167
192
  *
168
193
  * **Resolution provenance — the reserved `$resolution` key.** When the resolve
169
194
  * carries the resolver's identity (the API layer supplies it for interactive
@@ -231,3 +256,18 @@ async function conditional(signalId, escalation) {
231
256
  }
232
257
  /** @deprecated Alias of {@link conditional}. */
233
258
  exports.conditionLT = conditional;
259
+ /**
260
+ * {@link conditional} for an open accumulator: the same wait, typed for the
261
+ * contract an accumulator row keeps. It resolves with the ordered
262
+ * `$accumulated` collection and its `$trigger` on every terminal path
263
+ * (`count`, `timeout`, `resolve`), so `false` is not in the return type;
264
+ * cancellation still yields `null`. `P` types each item's payload, `R` the
265
+ * manual resolver payload merged in on `resolve`.
266
+ */
267
+ async function conditionalAccumulator(signalId, escalation) {
268
+ const result = await conditional(signalId, escalation);
269
+ if (result === false) {
270
+ throw new Error(`Accumulator wait ${signalId} resumed with false; expected a delivered collection`);
271
+ }
272
+ return result;
273
+ }
@@ -153,6 +153,7 @@ async function updateRoleMetadata(role, input) {
153
153
  provided('ops_home_default'), input.ops_home_default ?? null,
154
154
  provided('entity_facet'), input.entity_facet ?? null,
155
155
  provided('entity_state_source'), input.entity_state_source ?? null,
156
+ provided('portals'), input.portals != null ? JSON.stringify(input.portals) : null,
156
157
  ]);
157
158
  if (!rows[0])
158
159
  return null;
@@ -14,10 +14,12 @@ exports.STARTUP_CHANGE_SUMMARY = 'startup apply (code)';
14
14
  const METADATA_FIELDS = [
15
15
  'title', 'description', 'form_schema', 'metadata_schema', 'list_schema',
16
16
  'properties', 'ops_visible', 'ops_home_default', 'parent_role',
17
- 'upstream_roles', 'default_pins', 'enforce_schema', 'sla_minutes',
17
+ 'upstream_roles', 'default_pins', 'portals', 'enforce_schema', 'sla_minutes',
18
18
  'target_per_hour', 'worker_count', 'priority_threshold_minutes',
19
19
  'priority_facet', 'entity_facet', 'entity_state_source',
20
20
  ];
21
+ // Arrays whose order is meaning (portals and their rows), compared as declared.
22
+ const ORDERED_ARRAY_FIELDS = new Set(['portals']);
21
23
  /**
22
24
  * Compare one declared field against the stored row. jsonb round-trips lose
23
25
  * key order, so structured values must be compared as parsed values — never
@@ -25,6 +27,9 @@ const METADATA_FIELDS = [
25
27
  */
26
28
  function fieldDiffers(field, declared, row) {
27
29
  const stored = row[field];
30
+ if (Array.isArray(declared) && ORDERED_ARRAY_FIELDS.has(field)) {
31
+ return !(0, node_util_1.isDeepStrictEqual)(declared, stored ?? null);
32
+ }
28
33
  if (Array.isArray(declared)) {
29
34
  const a = [...declared].sort();
30
35
  const b = Array.isArray(stored) ? [...stored].sort() : [];
@@ -21,7 +21,7 @@ export declare const LIST_ROLES = "\n SELECT role FROM lt_roles ORDER BY role";
21
21
  */
22
22
  export declare const LIST_CONFIGURED_ROLES = "\n SELECT role FROM lt_roles\n WHERE title IS NOT NULL OR form_schema IS NOT NULL\n ORDER BY role";
23
23
  /** One role's full metadata row (plus upstream inputs) for startup diffing. */
24
- export declare const GET_ROLE_ROW = "\n SELECT\n r.role, r.title, r.description, r.form_schema, r.metadata_schema,\n r.properties, r.ops_visible, r.ops_home_default, r.parent_role,\n r.sla_minutes, r.target_per_hour, r.worker_count,\n r.priority_threshold_minutes, r.priority_facet,\n r.entity_facet, r.entity_state_source,\n r.list_schema, r.default_pins, r.enforce_schema,\n r.current_schema_version, r.current_list_schema_version,\n COALESCE((SELECT array_agg(u.upstream_role ORDER BY u.upstream_role)\n FROM lt_role_upstreams u WHERE u.role = r.role), '{}') AS upstream_roles\n FROM lt_roles r\n WHERE r.role = $1";
24
+ export declare const GET_ROLE_ROW = "\n SELECT\n r.role, r.title, r.description, r.form_schema, r.metadata_schema,\n r.properties, r.ops_visible, r.ops_home_default, r.parent_role,\n r.sla_minutes, r.target_per_hour, r.worker_count,\n r.priority_threshold_minutes, r.priority_facet,\n r.entity_facet, r.entity_state_source,\n r.list_schema, r.default_pins, r.portals, r.enforce_schema,\n r.current_schema_version, r.current_list_schema_version,\n COALESCE((SELECT array_agg(u.upstream_role ORDER BY u.upstream_role)\n FROM lt_role_upstreams u WHERE u.role = r.role), '{}') AS upstream_roles\n FROM lt_roles r\n WHERE r.role = $1";
25
25
  export declare const DELETE_ROLE = "\n DELETE FROM lt_roles WHERE role = $1";
26
26
  /**
27
27
  * PATCH semantics in ONE atomic statement: each column has a boolean
@@ -66,8 +66,11 @@ export declare const DELETE_ROLE = "\n DELETE FROM lt_roles WHERE role = $1";
66
66
  * entity_state_source ($39 = provided sentinel, $40 = value) is unversioned
67
67
  * config: 'role' | 'subtype' — how this role names its contribution to the
68
68
  * entity's state space (the station itself, or its subtypes).
69
+ *
70
+ * portals ($41 = provided sentinel, $42 = value) is unversioned config: the
71
+ * role's named portal views, each a matrix of pin cells rendered as one page.
69
72
  */
70
- export declare const UPDATE_ROLE_METADATA = "\n WITH home_clear AS (\n UPDATE lt_roles SET ops_home_default = false\n WHERE $35::boolean AND COALESCE($36::boolean, false) AND role <> $1 AND ops_home_default\n ), updated AS (\n UPDATE lt_roles SET\n title = CASE WHEN $2::boolean THEN $3 ELSE title END,\n description = CASE WHEN $4::boolean THEN $5 ELSE description END,\n form_schema = CASE WHEN $6::boolean THEN $7::jsonb ELSE form_schema END,\n metadata_schema = CASE WHEN $8::boolean THEN $9::jsonb ELSE metadata_schema END,\n properties = CASE WHEN $10::boolean THEN COALESCE($11::jsonb, '{}'::jsonb) ELSE properties END,\n ops_visible = CASE WHEN $12::boolean THEN $13::boolean ELSE ops_visible END,\n parent_role = CASE WHEN $14::boolean THEN $15 ELSE parent_role END,\n sla_minutes = CASE WHEN $16::boolean THEN $17::numeric ELSE sla_minutes END,\n target_per_hour = CASE WHEN $18::boolean THEN $19::numeric ELSE target_per_hour END,\n worker_count = CASE WHEN $20::boolean THEN $21::int ELSE worker_count END,\n priority_threshold_minutes\n = CASE WHEN $22::boolean THEN $23::numeric ELSE priority_threshold_minutes END,\n priority_facet = CASE WHEN $24::boolean THEN $25 ELSE priority_facet END,\n entity_facet = CASE WHEN $37::boolean THEN $38 ELSE entity_facet END,\n entity_state_source\n = CASE WHEN $39::boolean THEN COALESCE($40, 'role') ELSE entity_state_source END,\n list_schema = CASE WHEN $29::boolean THEN $30::jsonb ELSE list_schema END,\n default_pins = CASE WHEN $31::boolean THEN $32::jsonb ELSE default_pins END,\n enforce_schema = CASE WHEN $33::boolean THEN COALESCE($34::boolean, false) ELSE enforce_schema END,\n ops_home_default = CASE WHEN $35::boolean THEN COALESCE($36::boolean, false) ELSE ops_home_default END,\n current_schema_version = CASE\n WHEN ($6::boolean AND $7::jsonb IS DISTINCT FROM form_schema)\n OR ($8::boolean AND $9::jsonb IS DISTINCT FROM metadata_schema)\n THEN COALESCE(current_schema_version, 0) + 1\n ELSE current_schema_version END,\n current_list_schema_version = CASE\n WHEN $29::boolean AND $30::jsonb IS DISTINCT FROM list_schema\n THEN COALESCE(current_list_schema_version, 0) + 1\n ELSE current_list_schema_version END\n WHERE role = $1\n RETURNING\n role, title, description, form_schema, metadata_schema, properties,\n ops_visible, ops_home_default, parent_role, sla_minutes, target_per_hour, worker_count,\n priority_threshold_minutes, priority_facet, entity_facet, entity_state_source,\n current_schema_version, list_schema, current_list_schema_version,\n default_pins, enforce_schema\n ), snapshot AS (\n INSERT INTO lt_role_schemas (role, version, form_schema, metadata_schema, change_summary)\n SELECT role, current_schema_version, form_schema, metadata_schema, $26\n FROM updated\n WHERE ($6::boolean OR $8::boolean) AND current_schema_version IS NOT NULL\n ON CONFLICT (role, version) DO NOTHING\n ), list_snapshot AS (\n INSERT INTO lt_role_list_schemas (role, version, list_schema, change_summary)\n SELECT role, current_list_schema_version, list_schema, $26\n FROM updated\n WHERE $29::boolean AND current_list_schema_version IS NOT NULL\n ON CONFLICT (role, version) DO NOTHING\n ), upstream_prune AS (\n DELETE FROM lt_role_upstreams\n WHERE $27::boolean AND role = $1 AND upstream_role <> ALL($28::text[])\n ), upstream_add AS (\n INSERT INTO lt_role_upstreams (role, upstream_role)\n SELECT $1, u FROM unnest($28::text[]) AS u\n WHERE $27::boolean\n ON CONFLICT DO NOTHING\n )\n SELECT * FROM updated";
73
+ export declare const UPDATE_ROLE_METADATA = "\n WITH home_clear AS (\n UPDATE lt_roles SET ops_home_default = false\n WHERE $35::boolean AND COALESCE($36::boolean, false) AND role <> $1 AND ops_home_default\n ), updated AS (\n UPDATE lt_roles SET\n title = CASE WHEN $2::boolean THEN $3 ELSE title END,\n description = CASE WHEN $4::boolean THEN $5 ELSE description END,\n form_schema = CASE WHEN $6::boolean THEN $7::jsonb ELSE form_schema END,\n metadata_schema = CASE WHEN $8::boolean THEN $9::jsonb ELSE metadata_schema END,\n properties = CASE WHEN $10::boolean THEN COALESCE($11::jsonb, '{}'::jsonb) ELSE properties END,\n ops_visible = CASE WHEN $12::boolean THEN $13::boolean ELSE ops_visible END,\n parent_role = CASE WHEN $14::boolean THEN $15 ELSE parent_role END,\n sla_minutes = CASE WHEN $16::boolean THEN $17::numeric ELSE sla_minutes END,\n target_per_hour = CASE WHEN $18::boolean THEN $19::numeric ELSE target_per_hour END,\n worker_count = CASE WHEN $20::boolean THEN $21::int ELSE worker_count END,\n priority_threshold_minutes\n = CASE WHEN $22::boolean THEN $23::numeric ELSE priority_threshold_minutes END,\n priority_facet = CASE WHEN $24::boolean THEN $25 ELSE priority_facet END,\n entity_facet = CASE WHEN $37::boolean THEN $38 ELSE entity_facet END,\n entity_state_source\n = CASE WHEN $39::boolean THEN COALESCE($40, 'role') ELSE entity_state_source END,\n list_schema = CASE WHEN $29::boolean THEN $30::jsonb ELSE list_schema END,\n default_pins = CASE WHEN $31::boolean THEN $32::jsonb ELSE default_pins END,\n portals = CASE WHEN $41::boolean THEN $42::jsonb ELSE portals END,\n enforce_schema = CASE WHEN $33::boolean THEN COALESCE($34::boolean, false) ELSE enforce_schema END,\n ops_home_default = CASE WHEN $35::boolean THEN COALESCE($36::boolean, false) ELSE ops_home_default END,\n current_schema_version = CASE\n WHEN ($6::boolean AND $7::jsonb IS DISTINCT FROM form_schema)\n OR ($8::boolean AND $9::jsonb IS DISTINCT FROM metadata_schema)\n THEN COALESCE(current_schema_version, 0) + 1\n ELSE current_schema_version END,\n current_list_schema_version = CASE\n WHEN $29::boolean AND $30::jsonb IS DISTINCT FROM list_schema\n THEN COALESCE(current_list_schema_version, 0) + 1\n ELSE current_list_schema_version END\n WHERE role = $1\n RETURNING\n role, title, description, form_schema, metadata_schema, properties,\n ops_visible, ops_home_default, parent_role, sla_minutes, target_per_hour, worker_count,\n priority_threshold_minutes, priority_facet, entity_facet, entity_state_source,\n current_schema_version, list_schema, current_list_schema_version,\n default_pins, portals, enforce_schema\n ), snapshot AS (\n INSERT INTO lt_role_schemas (role, version, form_schema, metadata_schema, change_summary)\n SELECT role, current_schema_version, form_schema, metadata_schema, $26\n FROM updated\n WHERE ($6::boolean OR $8::boolean) AND current_schema_version IS NOT NULL\n ON CONFLICT (role, version) DO NOTHING\n ), list_snapshot AS (\n INSERT INTO lt_role_list_schemas (role, version, list_schema, change_summary)\n SELECT role, current_list_schema_version, list_schema, $26\n FROM updated\n WHERE $29::boolean AND current_list_schema_version IS NOT NULL\n ON CONFLICT (role, version) DO NOTHING\n ), upstream_prune AS (\n DELETE FROM lt_role_upstreams\n WHERE $27::boolean AND role = $1 AND upstream_role <> ALL($28::text[])\n ), upstream_add AS (\n INSERT INTO lt_role_upstreams (role, upstream_role)\n SELECT $1, u FROM unnest($28::text[]) AS u\n WHERE $27::boolean\n ON CONFLICT DO NOTHING\n )\n SELECT * FROM updated";
71
74
  export declare const GET_ROLE_FORM_SCHEMA = "\n SELECT form_schema FROM lt_roles WHERE role = $1";
72
75
  /**
73
76
  * The set of roles with server-side resolver validation turned on. Small and
@@ -92,7 +95,7 @@ export declare const GET_ROLE_LIST_SCHEMA_VERSION = "\n SELECT s.role, s.versio
92
95
  * never versioned its list schema still answers, with version NULL).
93
96
  */
94
97
  export declare const GET_ROLE_LIST_SCHEMA_CURRENT = "\n SELECT r.role, r.current_list_schema_version AS version, r.list_schema,\n s.change_summary, s.created_at,\n r.current_list_schema_version AS latest_version\n FROM lt_roles r\n LEFT JOIN lt_role_list_schemas s\n ON s.role = r.role AND s.version = r.current_list_schema_version\n WHERE r.role = $1";
95
- export declare const LIST_ROLES_WITH_DETAILS = "\n WITH\n user_counts AS (\n SELECT role, COUNT(DISTINCT user_id)::int AS cnt\n FROM lt_user_roles\n GROUP BY role\n ),\n chain_counts AS (\n SELECT role, COUNT(*)::int AS cnt\n FROM (\n SELECT source_role AS role FROM lt_config_role_escalations\n UNION ALL\n SELECT target_role AS role FROM lt_config_role_escalations\n ) c\n GROUP BY role\n ),\n workflow_counts AS (\n SELECT role, COUNT(*)::int AS cnt\n FROM lt_config_roles\n GROUP BY role\n ),\n upstreams AS (\n SELECT role, array_agg(upstream_role ORDER BY upstream_role) AS ups\n FROM lt_role_upstreams\n GROUP BY role\n )\n SELECT\n r.role,\n r.title,\n r.description,\n r.form_schema,\n r.metadata_schema,\n r.properties,\n r.ops_visible,\n r.ops_home_default,\n r.parent_role,\n r.sla_minutes,\n r.target_per_hour,\n r.worker_count,\n r.priority_threshold_minutes,\n r.priority_facet,\n r.entity_facet,\n r.entity_state_source,\n r.current_schema_version,\n r.list_schema,\n r.current_list_schema_version,\n r.default_pins,\n r.enforce_schema,\n COALESCE(up.ups, '{}') AS upstream_roles,\n COALESCE(uc.cnt, 0) AS user_count,\n COALESCE(cc.cnt, 0) AS chain_count,\n COALESCE(wc.cnt, 0) AS workflow_count\n FROM lt_roles r\n LEFT JOIN user_counts uc ON uc.role = r.role\n LEFT JOIN chain_counts cc ON cc.role = r.role\n LEFT JOIN workflow_counts wc ON wc.role = r.role\n LEFT JOIN upstreams up ON up.role = r.role\n ORDER BY r.role";
98
+ export declare const LIST_ROLES_WITH_DETAILS = "\n WITH\n user_counts AS (\n SELECT role, COUNT(DISTINCT user_id)::int AS cnt\n FROM lt_user_roles\n GROUP BY role\n ),\n chain_counts AS (\n SELECT role, COUNT(*)::int AS cnt\n FROM (\n SELECT source_role AS role FROM lt_config_role_escalations\n UNION ALL\n SELECT target_role AS role FROM lt_config_role_escalations\n ) c\n GROUP BY role\n ),\n workflow_counts AS (\n SELECT role, COUNT(*)::int AS cnt\n FROM lt_config_roles\n GROUP BY role\n ),\n upstreams AS (\n SELECT role, array_agg(upstream_role ORDER BY upstream_role) AS ups\n FROM lt_role_upstreams\n GROUP BY role\n )\n SELECT\n r.role,\n r.title,\n r.description,\n r.form_schema,\n r.metadata_schema,\n r.properties,\n r.ops_visible,\n r.ops_home_default,\n r.parent_role,\n r.sla_minutes,\n r.target_per_hour,\n r.worker_count,\n r.priority_threshold_minutes,\n r.priority_facet,\n r.entity_facet,\n r.entity_state_source,\n r.current_schema_version,\n r.list_schema,\n r.current_list_schema_version,\n r.default_pins,\n r.portals,\n r.enforce_schema,\n COALESCE(up.ups, '{}') AS upstream_roles,\n COALESCE(uc.cnt, 0) AS user_count,\n COALESCE(cc.cnt, 0) AS chain_count,\n COALESCE(wc.cnt, 0) AS workflow_count\n FROM lt_roles r\n LEFT JOIN user_counts uc ON uc.role = r.role\n LEFT JOIN chain_counts cc ON cc.role = r.role\n LEFT JOIN workflow_counts wc ON wc.role = r.role\n LEFT JOIN upstreams up ON up.role = r.role\n ORDER BY r.role";
96
99
  export declare const COUNT_USER_ROLE_REFS = "\n SELECT COUNT(*)::int AS cnt FROM lt_user_roles WHERE role = $1";
97
100
  export declare const COUNT_CHAIN_REFS = "\n SELECT COUNT(*)::int AS cnt\n FROM lt_config_role_escalations\n WHERE source_role = $1 OR target_role = $1";
98
101
  export declare const COUNT_WORKFLOW_REFS = "\n SELECT COUNT(*)::int AS cnt FROM lt_config_roles WHERE role = $1";
@@ -64,7 +64,7 @@ exports.GET_ROLE_ROW = `
64
64
  r.sla_minutes, r.target_per_hour, r.worker_count,
65
65
  r.priority_threshold_minutes, r.priority_facet,
66
66
  r.entity_facet, r.entity_state_source,
67
- r.list_schema, r.default_pins, r.enforce_schema,
67
+ r.list_schema, r.default_pins, r.portals, r.enforce_schema,
68
68
  r.current_schema_version, r.current_list_schema_version,
69
69
  COALESCE((SELECT array_agg(u.upstream_role ORDER BY u.upstream_role)
70
70
  FROM lt_role_upstreams u WHERE u.role = r.role), '{}') AS upstream_roles
@@ -115,6 +115,9 @@ exports.DELETE_ROLE = `
115
115
  * entity_state_source ($39 = provided sentinel, $40 = value) is unversioned
116
116
  * config: 'role' | 'subtype' — how this role names its contribution to the
117
117
  * entity's state space (the station itself, or its subtypes).
118
+ *
119
+ * portals ($41 = provided sentinel, $42 = value) is unversioned config: the
120
+ * role's named portal views, each a matrix of pin cells rendered as one page.
118
121
  */
119
122
  exports.UPDATE_ROLE_METADATA = `
120
123
  WITH home_clear AS (
@@ -140,6 +143,7 @@ exports.UPDATE_ROLE_METADATA = `
140
143
  = CASE WHEN $39::boolean THEN COALESCE($40, 'role') ELSE entity_state_source END,
141
144
  list_schema = CASE WHEN $29::boolean THEN $30::jsonb ELSE list_schema END,
142
145
  default_pins = CASE WHEN $31::boolean THEN $32::jsonb ELSE default_pins END,
146
+ portals = CASE WHEN $41::boolean THEN $42::jsonb ELSE portals END,
143
147
  enforce_schema = CASE WHEN $33::boolean THEN COALESCE($34::boolean, false) ELSE enforce_schema END,
144
148
  ops_home_default = CASE WHEN $35::boolean THEN COALESCE($36::boolean, false) ELSE ops_home_default END,
145
149
  current_schema_version = CASE
@@ -157,7 +161,7 @@ exports.UPDATE_ROLE_METADATA = `
157
161
  ops_visible, ops_home_default, parent_role, sla_minutes, target_per_hour, worker_count,
158
162
  priority_threshold_minutes, priority_facet, entity_facet, entity_state_source,
159
163
  current_schema_version, list_schema, current_list_schema_version,
160
- default_pins, enforce_schema
164
+ default_pins, portals, enforce_schema
161
165
  ), snapshot AS (
162
166
  INSERT INTO lt_role_schemas (role, version, form_schema, metadata_schema, change_summary)
163
167
  SELECT role, current_schema_version, form_schema, metadata_schema, $26
@@ -304,6 +308,7 @@ exports.LIST_ROLES_WITH_DETAILS = `
304
308
  r.list_schema,
305
309
  r.current_list_schema_version,
306
310
  r.default_pins,
311
+ r.portals,
307
312
  r.enforce_schema,
308
313
  COALESCE(up.ups, '{}') AS upstream_roles,
309
314
  COALESCE(uc.cnt, 0) AS user_count,
@@ -35,6 +35,35 @@ export declare const ROLE_PROPERTY_KEYS: {
35
35
  * binding. Values are strings — jsonb containment is type-sensitive, so
36
36
  * numeric facets are not templatable.
37
37
  */
38
+ /** One pinned view: a label over a dashboard-relative URL, optionally badged with its live count. */
39
+ export interface RolePin {
40
+ label: string;
41
+ url: string;
42
+ badge?: boolean;
43
+ }
44
+ /** Bounds for a role's portals: how many, and the matrix of each (rows of cells, each cell a pin). */
45
+ export declare const PORTAL_LIMITS: {
46
+ readonly MAX_PORTALS: 12;
47
+ readonly MAX_ROWS: 4;
48
+ readonly MAX_COLS: 6;
49
+ readonly MAX_COUNTS: 8;
50
+ };
51
+ /** One count tile above a portal: a label, a blurb, and the live total of an escalations-list URL. */
52
+ export interface PortalCount {
53
+ label: string;
54
+ url: string;
55
+ blurb?: string;
56
+ }
57
+ /** A portal key: a short url-safe slug, unique within the role. */
58
+ export declare const PORTAL_KEY: RegExp;
59
+ /** One named portal view: a matrix of pins rendered as one page. */
60
+ export interface RolePortal {
61
+ key: string;
62
+ label: string;
63
+ rows: RolePin[][];
64
+ /** Count tiles shown above the panels, each the live total of a list URL. */
65
+ counts?: PortalCount[];
66
+ }
38
67
  export interface RoleLinkVariable {
39
68
  name: string;
40
69
  label?: string;
@@ -125,11 +154,12 @@ export interface RoleDetail {
125
154
  * in their Pinned nav section (marked role-provided); users promote, hide,
126
155
  * or reorder them through their own preferences. URLs only — never data.
127
156
  */
128
- default_pins: {
129
- label: string;
130
- url: string;
131
- badge?: boolean;
132
- }[] | null;
157
+ default_pins: RolePin[] | null;
158
+ /**
159
+ * The role's portals: named matrices of pins, each rendered as one page of
160
+ * live list panels at /portal/:role/:portal. Null when the role declares none.
161
+ */
162
+ portals: RolePortal[] | null;
133
163
  /**
134
164
  * Roles this station draws input from that live in OTHER sequences.
135
165
  * parent_role is the single "prior step" placing the role in one sequence;
@@ -185,11 +215,9 @@ export interface UpdateRoleInput {
185
215
  metadata_schema?: Record<string, any> | null;
186
216
  /** JSON contract that richly formats this role's escalation list page. */
187
217
  list_schema?: Record<string, any> | null;
188
- default_pins?: {
189
- label: string;
190
- url: string;
191
- badge?: boolean;
192
- }[] | null;
218
+ default_pins?: RolePin[] | null;
219
+ /** The role's named portals; null clears. */
220
+ portals?: RolePortal[] | null;
193
221
  properties?: Record<string, any> | null;
194
222
  ops_visible?: boolean;
195
223
  /** Make this role's sequence the home Pace Board's default segment (single-holder). */
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  /** Type definitions for the role and escalation chain service. */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.ROLE_PROPERTY_KEYS = void 0;
4
+ exports.PORTAL_KEY = exports.PORTAL_LIMITS = exports.ROLE_PROPERTY_KEYS = void 0;
5
5
  /**
6
6
  * Reserved keys inside `lt_roles.properties`. Everything else in the bag is
7
7
  * user-owned. Readers type-guard (the bag is open, PATCH can write anything).
@@ -27,3 +27,12 @@ exports.ROLE_PROPERTY_KEYS = {
27
27
  KIOSK: 'kiosk',
28
28
  LINK_VARIABLES: 'link_variables',
29
29
  };
30
+ /** Bounds for a role's portals: how many, and the matrix of each (rows of cells, each cell a pin). */
31
+ exports.PORTAL_LIMITS = {
32
+ MAX_PORTALS: 12,
33
+ MAX_ROWS: 4,
34
+ MAX_COLS: 6,
35
+ MAX_COUNTS: 8,
36
+ };
37
+ /** A portal key: a short url-safe slug, unique within the role. */
38
+ exports.PORTAL_KEY = /^[a-z0-9][a-z0-9-]{0,63}$/;
@@ -4,6 +4,7 @@ exports.assertValidScheme = assertValidScheme;
4
4
  exports.assertValidIdentityRule = assertValidIdentityRule;
5
5
  exports.assertValidSteps = assertValidSteps;
6
6
  const types_1 = require("../../types");
7
+ const facet_sql_1 = require("../escalation/facet-sql");
7
8
  const VALID_VERBS = new Set(Object.values(types_1.SCAN_VERBS));
8
9
  /** Double-scan selection tokens — short, label-printable, never scheme-shaped. */
9
10
  const CHOICE_CODE = /^[A-Za-z0-9_-]{1,32}$/;
@@ -145,6 +146,21 @@ function assertValidSteps(steps) {
145
146
  if (step.verb === types_1.SCAN_VERBS.RESOLVE && !step.params?.resolverPayload) {
146
147
  throw new Error(`${at}: resolve requires params.resolverPayload`);
147
148
  }
149
+ if (step.verb === types_1.SCAN_VERBS.ACCUMULATE) {
150
+ const options = step.params?.accumulate;
151
+ if (options !== undefined && (!options || typeof options !== 'object' || Array.isArray(options))) {
152
+ throw new Error(`${at}: params.accumulate must be an object`);
153
+ }
154
+ if (options?.containerFacet !== undefined && !facet_sql_1.FACET_KEY.test(String(options.containerFacet))) {
155
+ throw new Error(`${at}: params.accumulate.containerFacet must be a facet key`);
156
+ }
157
+ if (options?.containerRoles !== undefined && !Array.isArray(options.containerRoles)) {
158
+ throw new Error(`${at}: params.accumulate.containerRoles must be an array`);
159
+ }
160
+ if (!options?.containerFacet && !step.params?.itemKey) {
161
+ throw new Error(`${at}: accumulate requires params.itemKey or params.accumulate.containerFacet`);
162
+ }
163
+ }
148
164
  if (step.query && step.query.roles && !Array.isArray(step.query.roles)) {
149
165
  throw new Error(`${at}: query.roles must be an array`);
150
166
  }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Widgets that render from the escalation context and produce no answer of
3
+ * their own: navigation links, embedded records and lists, and invoke
4
+ * controls. Their form slot exists only to place them in the layout, so
5
+ * the payload mapper drops them and the server never sees a value.
6
+ */
7
+ export declare const DISPLAY_ONLY_WIDGET_NAMES: {
8
+ readonly LINK: "link";
9
+ readonly ESCALATION: "escalation";
10
+ readonly ESCALATION_LIST: "escalation-list";
11
+ readonly INVOKE: "invoke";
12
+ };
13
+ export declare const DISPLAY_ONLY_WIDGETS: ReadonlySet<string>;
14
+ export declare function isDisplayOnlyWidget(name: unknown): boolean;
15
+ /** Whether a property definition renders a display-only widget. */
16
+ export declare function isDisplayOnlyField(def: Record<string, unknown> | null | undefined): boolean;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DISPLAY_ONLY_WIDGETS = exports.DISPLAY_ONLY_WIDGET_NAMES = void 0;
4
+ exports.isDisplayOnlyWidget = isDisplayOnlyWidget;
5
+ exports.isDisplayOnlyField = isDisplayOnlyField;
6
+ /**
7
+ * Widgets that render from the escalation context and produce no answer of
8
+ * their own: navigation links, embedded records and lists, and invoke
9
+ * controls. Their form slot exists only to place them in the layout, so
10
+ * the payload mapper drops them and the server never sees a value.
11
+ */
12
+ exports.DISPLAY_ONLY_WIDGET_NAMES = {
13
+ LINK: 'link',
14
+ ESCALATION: 'escalation',
15
+ ESCALATION_LIST: 'escalation-list',
16
+ INVOKE: 'invoke',
17
+ };
18
+ exports.DISPLAY_ONLY_WIDGETS = new Set(Object.values(exports.DISPLAY_ONLY_WIDGET_NAMES));
19
+ function isDisplayOnlyWidget(name) {
20
+ return typeof name === 'string' && exports.DISPLAY_ONLY_WIDGETS.has(name);
21
+ }
22
+ /** Whether a property definition renders a display-only widget. */
23
+ function isDisplayOnlyField(def) {
24
+ return isDisplayOnlyWidget(def?.['x-lt-widget']);
25
+ }
@@ -20,3 +20,5 @@ export * from './ctx-path';
20
20
  export * from './field-validator';
21
21
  export * from './validate-resolver-payload';
22
22
  export * from './invoke-context';
23
+ export * from './display-only-widgets';
24
+ export * from './x-lt-invoke';
@@ -36,3 +36,5 @@ __exportStar(require("./ctx-path"), exports);
36
36
  __exportStar(require("./field-validator"), exports);
37
37
  __exportStar(require("./validate-resolver-payload"), exports);
38
38
  __exportStar(require("./invoke-context"), exports);
39
+ __exportStar(require("./display-only-widgets"), exports);
40
+ __exportStar(require("./x-lt-invoke"), exports);