@hotmeshio/long-tail 0.10.1 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/build/api/me.d.ts +16 -0
  2. package/build/api/me.js +79 -0
  3. package/build/api/roles.d.ts +6 -0
  4. package/build/api/roles.js +10 -0
  5. package/build/lib/db/schemas/022_user_preferences.sql +18 -0
  6. package/build/routes/index.js +2 -0
  7. package/build/routes/me.d.ts +2 -0
  8. package/build/routes/me.js +57 -0
  9. package/build/sdk/index.d.ts +6 -0
  10. package/build/sdk/index.js +11 -0
  11. package/build/services/role/index.js +1 -0
  12. package/build/services/role/sql.d.ts +5 -2
  13. package/build/services/role/sql.js +7 -1
  14. package/build/services/role/types.d.ts +16 -0
  15. package/build/services/user/index.d.ts +1 -0
  16. package/build/services/user/index.js +5 -1
  17. package/build/services/user/preferences.d.ts +15 -0
  18. package/build/services/user/preferences.js +38 -0
  19. package/build/system/mcp-servers/admin/schemas.d.ts +26 -0
  20. package/build/system/mcp-servers/admin/schemas.js +6 -0
  21. package/build/system/mcp-servers/admin/users.js +6 -3
  22. package/build/system/seed/tool-manifests-admin.d.ts +167 -0
  23. package/build/system/seed/tool-manifests-admin.js +1 -1
  24. package/build/tsconfig.tsbuildinfo +1 -1
  25. package/dashboard/dist/assets/{AdminDashboard-D7Amh-EJ.js → AdminDashboard-Dy031e9g.js} +2 -2
  26. package/dashboard/dist/assets/{AdminDashboard-D7Amh-EJ.js.map → AdminDashboard-Dy031e9g.js.map} +1 -1
  27. package/dashboard/dist/assets/{AgentConfigPage-CW2udbSO.js → AgentConfigPage-CqmtYBbC.js} +6 -6
  28. package/dashboard/dist/assets/{AgentConfigPage-CW2udbSO.js.map → AgentConfigPage-CqmtYBbC.js.map} +1 -1
  29. package/dashboard/dist/assets/{AgentDetailPage-Dy3Qvlfk.js → AgentDetailPage-oYLBrN74.js} +3 -3
  30. package/dashboard/dist/assets/{AgentDetailPage-Dy3Qvlfk.js.map → AgentDetailPage-oYLBrN74.js.map} +1 -1
  31. package/dashboard/dist/assets/{AgentsPage-D7WePZ0o.js → AgentsPage-CHczRx5N.js} +2 -2
  32. package/dashboard/dist/assets/{AgentsPage-D7WePZ0o.js.map → AgentsPage-CHczRx5N.js.map} +1 -1
  33. package/dashboard/dist/assets/AvailableEscalationsPage-DDVuivEE.js +2 -0
  34. package/dashboard/dist/assets/AvailableEscalationsPage-DDVuivEE.js.map +1 -0
  35. package/dashboard/dist/assets/BotPicker-2QEIpc-K.js +2 -0
  36. package/dashboard/dist/assets/{BotPicker-KebTxTDi.js.map → BotPicker-2QEIpc-K.js.map} +1 -1
  37. package/dashboard/dist/assets/{CapabilitiesPage-3VTLEPGO.js → CapabilitiesPage-lQJGZ_-t.js} +2 -2
  38. package/dashboard/dist/assets/{CapabilitiesPage-3VTLEPGO.js.map → CapabilitiesPage-lQJGZ_-t.js.map} +1 -1
  39. package/dashboard/dist/assets/{CollapsibleSection-BYgeZz9M.js → CollapsibleSection-CHWP0WI6.js} +2 -2
  40. package/dashboard/dist/assets/{CollapsibleSection-BYgeZz9M.js.map → CollapsibleSection-CHWP0WI6.js.map} +1 -1
  41. package/dashboard/dist/assets/CountdownTimer-TXsRlTU4.js +2 -0
  42. package/dashboard/dist/assets/CountdownTimer-TXsRlTU4.js.map +1 -0
  43. package/dashboard/dist/assets/{CredentialsPage-CaH3J3SE.js → CredentialsPage-BKxS-1sA.js} +2 -2
  44. package/dashboard/dist/assets/{CredentialsPage-CaH3J3SE.js.map → CredentialsPage-BKxS-1sA.js.map} +1 -1
  45. package/dashboard/dist/assets/{CronLabel-Bma_4AC2.js → CronLabel-Bd2G0Rap.js} +2 -2
  46. package/dashboard/dist/assets/{CronLabel-Bma_4AC2.js.map → CronLabel-Bd2G0Rap.js.map} +1 -1
  47. package/dashboard/dist/assets/{CustomDurationPicker-BxyjEX27.js → CustomDurationPicker-j4bBrDJ6.js} +2 -2
  48. package/dashboard/dist/assets/{CustomDurationPicker-BxyjEX27.js.map → CustomDurationPicker-j4bBrDJ6.js.map} +1 -1
  49. package/dashboard/dist/assets/{DropZone-zxH-9B8c.js → DropZone-DNDEgMpJ.js} +2 -2
  50. package/dashboard/dist/assets/{DropZone-zxH-9B8c.js.map → DropZone-DNDEgMpJ.js.map} +1 -1
  51. package/dashboard/dist/assets/{ElapsedCell-Dr1cEwoi.js → ElapsedCell-g7GO7f8L.js} +2 -2
  52. package/dashboard/dist/assets/{ElapsedCell-Dr1cEwoi.js.map → ElapsedCell-g7GO7f8L.js.map} +1 -1
  53. package/dashboard/dist/assets/{EscalationListSchemaPage-CLdsR-hK.js → EscalationListSchemaPage-CIJ-OgVC.js} +3 -3
  54. package/dashboard/dist/assets/{EscalationListSchemaPage-CLdsR-hK.js.map → EscalationListSchemaPage-CIJ-OgVC.js.map} +1 -1
  55. package/dashboard/dist/assets/{EscalationSchemaPage-DnEnvolM.js → EscalationSchemaPage-C7dHgG8e.js} +3 -3
  56. package/dashboard/dist/assets/{EscalationSchemaPage-DnEnvolM.js.map → EscalationSchemaPage-C7dHgG8e.js.map} +1 -1
  57. package/dashboard/dist/assets/{EscalationsOverview-BH8cxgLI.js → EscalationsOverview-D8NrATg2.js} +2 -2
  58. package/dashboard/dist/assets/{EscalationsOverview-BH8cxgLI.js.map → EscalationsOverview-D8NrATg2.js.map} +1 -1
  59. package/dashboard/dist/assets/{EventTable-p-xsfYYg.js → EventTable-DBV1P2ME.js} +2 -2
  60. package/dashboard/dist/assets/{EventTable-p-xsfYYg.js.map → EventTable-DBV1P2ME.js.map} +1 -1
  61. package/dashboard/dist/assets/{GraphInvokePage-Cf9c_LJ-.js → GraphInvokePage-DbHvggQ_.js} +2 -2
  62. package/dashboard/dist/assets/{GraphInvokePage-Cf9c_LJ-.js.map → GraphInvokePage-DbHvggQ_.js.map} +1 -1
  63. package/dashboard/dist/assets/{HomePage-BdCtKXAV.js → HomePage-BpexnDO_.js} +2 -2
  64. package/dashboard/dist/assets/{HomePage-BdCtKXAV.js.map → HomePage-BpexnDO_.js.map} +1 -1
  65. package/dashboard/dist/assets/ListToolbar-KC6LGtKP.js +2 -0
  66. package/dashboard/dist/assets/{ListToolbar-CDlol8XJ.js.map → ListToolbar-KC6LGtKP.js.map} +1 -1
  67. package/dashboard/dist/assets/{McpOverview-ChZ36p9t.js → McpOverview-BDZC9Hvl.js} +2 -2
  68. package/dashboard/dist/assets/{McpOverview-ChZ36p9t.js.map → McpOverview-BDZC9Hvl.js.map} +1 -1
  69. package/dashboard/dist/assets/{McpQueryDetailPage-X4j_jm3r.js → McpQueryDetailPage-CXhgX1pS.js} +2 -2
  70. package/dashboard/dist/assets/{McpQueryDetailPage-X4j_jm3r.js.map → McpQueryDetailPage-CXhgX1pS.js.map} +1 -1
  71. package/dashboard/dist/assets/{McpQueryPage-C30HsQfZ.js → McpQueryPage-CsKNXUhb.js} +2 -2
  72. package/dashboard/dist/assets/{McpQueryPage-C30HsQfZ.js.map → McpQueryPage-CsKNXUhb.js.map} +1 -1
  73. package/dashboard/dist/assets/{McpRunDetailPage-18d7Iqfy.js → McpRunDetailPage-BM3mUSlH.js} +2 -2
  74. package/dashboard/dist/assets/{McpRunDetailPage-18d7Iqfy.js.map → McpRunDetailPage-BM3mUSlH.js.map} +1 -1
  75. package/dashboard/dist/assets/{McpRunsPage-BHZHCwMM.js → McpRunsPage-f5hDbpLo.js} +2 -2
  76. package/dashboard/dist/assets/{McpRunsPage-BHZHCwMM.js.map → McpRunsPage-f5hDbpLo.js.map} +1 -1
  77. package/dashboard/dist/assets/{NamespacePill-BQNMfY0m.js → NamespacePill-C4u6Go1W.js} +2 -2
  78. package/dashboard/dist/assets/{NamespacePill-BQNMfY0m.js.map → NamespacePill-C4u6Go1W.js.map} +1 -1
  79. package/dashboard/dist/assets/OperationsPage-D37cZ8Qh.js +2 -0
  80. package/dashboard/dist/assets/{OperationsPage-GMojwL3q.js.map → OperationsPage-D37cZ8Qh.js.map} +1 -1
  81. package/dashboard/dist/assets/OperatorDashboard-_axS17fp.js +2 -0
  82. package/dashboard/dist/assets/{OperatorDashboard-BGJrxLMU.js.map → OperatorDashboard-_axS17fp.js.map} +1 -1
  83. package/dashboard/dist/assets/{PageHeader-BIY1YvKR.js → PageHeader-Bxa1XFz0.js} +2 -2
  84. package/dashboard/dist/assets/{PageHeader-BIY1YvKR.js.map → PageHeader-Bxa1XFz0.js.map} +1 -1
  85. package/dashboard/dist/assets/{PageHeaderWithStats-TUyglVW0.js → PageHeaderWithStats-D_sO0MqJ.js} +2 -2
  86. package/dashboard/dist/assets/{PageHeaderWithStats-TUyglVW0.js.map → PageHeaderWithStats-D_sO0MqJ.js.map} +1 -1
  87. package/dashboard/dist/assets/{ProcessDetailPage-Bcp3GKFo.js → ProcessDetailPage-D8pAWUXx.js} +2 -2
  88. package/dashboard/dist/assets/{ProcessDetailPage-Bcp3GKFo.js.map → ProcessDetailPage-D8pAWUXx.js.map} +1 -1
  89. package/dashboard/dist/assets/{ProcessesListPage-DPrvuLoU.js → ProcessesListPage-CoQEi_Su.js} +2 -2
  90. package/dashboard/dist/assets/{ProcessesListPage-DPrvuLoU.js.map → ProcessesListPage-CoQEi_Su.js.map} +1 -1
  91. package/dashboard/dist/assets/RoleDetailPage-ufbypNNR.js +8 -0
  92. package/dashboard/dist/assets/RoleDetailPage-ufbypNNR.js.map +1 -0
  93. package/dashboard/dist/assets/{RolePill-4LO_CuO3.js → RolePill-DLwmVMam.js} +2 -2
  94. package/dashboard/dist/assets/{RolePill-4LO_CuO3.js.map → RolePill-DLwmVMam.js.map} +1 -1
  95. package/dashboard/dist/assets/RolesPage-CxpXm4Sw.js +2 -0
  96. package/dashboard/dist/assets/{RolesPage-D3NNU92h.js.map → RolesPage-CxpXm4Sw.js.map} +1 -1
  97. package/dashboard/dist/assets/RunAsSelector-BebF8Lib.js +2 -0
  98. package/dashboard/dist/assets/{RunAsSelector-Z2Yunqdf.js.map → RunAsSelector-BebF8Lib.js.map} +1 -1
  99. package/dashboard/dist/assets/{SlidePanel-DK4sWXmp.js → SlidePanel-BDVDuwIf.js} +2 -2
  100. package/dashboard/dist/assets/{SlidePanel-DK4sWXmp.js.map → SlidePanel-BDVDuwIf.js.map} +1 -1
  101. package/dashboard/dist/assets/{StickyPagination-CeLsnCIS.js → StickyPagination-Cd83AHd_.js} +2 -2
  102. package/dashboard/dist/assets/{StickyPagination-CeLsnCIS.js.map → StickyPagination-Cd83AHd_.js.map} +1 -1
  103. package/dashboard/dist/assets/{StreamMessageDetail-DWs7XkmH.js → StreamMessageDetail-BIXbrZM0.js} +2 -2
  104. package/dashboard/dist/assets/{StreamMessageDetail-DWs7XkmH.js.map → StreamMessageDetail-BIXbrZM0.js.map} +1 -1
  105. package/dashboard/dist/assets/{SwimlaneTimeline-Dxl9a51q.js → SwimlaneTimeline-CC5qZjYo.js} +2 -2
  106. package/dashboard/dist/assets/{SwimlaneTimeline-Dxl9a51q.js.map → SwimlaneTimeline-CC5qZjYo.js.map} +1 -1
  107. package/dashboard/dist/assets/{TagInput-CK-JhBG2.js → TagInput-C2gi47M8.js} +2 -2
  108. package/dashboard/dist/assets/{TagInput-CK-JhBG2.js.map → TagInput-C2gi47M8.js.map} +1 -1
  109. package/dashboard/dist/assets/{TaskDetailPage-DVr31zDE.js → TaskDetailPage-DnjhW7qv.js} +2 -2
  110. package/dashboard/dist/assets/{TaskDetailPage-DVr31zDE.js.map → TaskDetailPage-DnjhW7qv.js.map} +1 -1
  111. package/dashboard/dist/assets/{TaskQueuePill-C_Vo2Clc.js → TaskQueuePill-BPP0Almh.js} +2 -2
  112. package/dashboard/dist/assets/{TaskQueuePill-C_Vo2Clc.js.map → TaskQueuePill-BPP0Almh.js.map} +1 -1
  113. package/dashboard/dist/assets/{TasksListPage-DNGp5lfi.js → TasksListPage-DySfZFgs.js} +2 -2
  114. package/dashboard/dist/assets/{TasksListPage-DNGp5lfi.js.map → TasksListPage-DySfZFgs.js.map} +1 -1
  115. package/dashboard/dist/assets/{TimeAgo-j2Q4w4lY.js → TimeAgo-BKOl-7Tt.js} +2 -2
  116. package/dashboard/dist/assets/{TimeAgo-j2Q4w4lY.js.map → TimeAgo-BKOl-7Tt.js.map} +1 -1
  117. package/dashboard/dist/assets/{TimestampCell-BLEfob2C.js → TimestampCell-DGOsba-A.js} +2 -2
  118. package/dashboard/dist/assets/{TimestampCell-BLEfob2C.js.map → TimestampCell-DGOsba-A.js.map} +1 -1
  119. package/dashboard/dist/assets/ToolPill-D74TkYB-.js +2 -0
  120. package/dashboard/dist/assets/{ToolPill-BCi101Jh.js.map → ToolPill-D74TkYB-.js.map} +1 -1
  121. package/dashboard/dist/assets/{ToolTestPanel-ZJZT_mDP.js → ToolTestPanel-Bez6OyRL.js} +2 -2
  122. package/dashboard/dist/assets/{ToolTestPanel-ZJZT_mDP.js.map → ToolTestPanel-Bez6OyRL.js.map} +1 -1
  123. package/dashboard/dist/assets/{TopicDetailPage-ynUkO1A8.js → TopicDetailPage-BHccgkU_.js} +2 -2
  124. package/dashboard/dist/assets/{TopicDetailPage-ynUkO1A8.js.map → TopicDetailPage-BHccgkU_.js.map} +1 -1
  125. package/dashboard/dist/assets/{TopicsPage-Ctb_85Tw.js → TopicsPage-5yW63ELl.js} +2 -2
  126. package/dashboard/dist/assets/{TopicsPage-Ctb_85Tw.js.map → TopicsPage-5yW63ELl.js.map} +1 -1
  127. package/dashboard/dist/assets/{UserName-CkFpUqVK.js → UserName-DcXhOSVm.js} +2 -2
  128. package/dashboard/dist/assets/{UserName-CkFpUqVK.js.map → UserName-DcXhOSVm.js.map} +1 -1
  129. package/dashboard/dist/assets/{WorkflowExecutionPage-CSw2aQJC.js → WorkflowExecutionPage-CDDLled5.js} +2 -2
  130. package/dashboard/dist/assets/{WorkflowExecutionPage-CSw2aQJC.js.map → WorkflowExecutionPage-CDDLled5.js.map} +1 -1
  131. package/dashboard/dist/assets/WorkflowPill-Fjc2q9U9.js +2 -0
  132. package/dashboard/dist/assets/{WorkflowPill-DHxrAkp3.js.map → WorkflowPill-Fjc2q9U9.js.map} +1 -1
  133. package/dashboard/dist/assets/{WorkflowsDashboard-DOyZbqzf.js → WorkflowsDashboard-C0Bbrd5M.js} +2 -2
  134. package/dashboard/dist/assets/{WorkflowsDashboard-DOyZbqzf.js.map → WorkflowsDashboard-C0Bbrd5M.js.map} +1 -1
  135. package/dashboard/dist/assets/{WorkflowsOverview-CRyHvUBx.js → WorkflowsOverview-D8MkSMex.js} +2 -2
  136. package/dashboard/dist/assets/{WorkflowsOverview-CRyHvUBx.js.map → WorkflowsOverview-D8MkSMex.js.map} +1 -1
  137. package/dashboard/dist/assets/{YamlWorkflowDetailPage-DRBmQXY6.js → YamlWorkflowDetailPage-BcbrYhDI.js} +11 -11
  138. package/dashboard/dist/assets/{YamlWorkflowDetailPage-DRBmQXY6.js.map → YamlWorkflowDetailPage-BcbrYhDI.js.map} +1 -1
  139. package/dashboard/dist/assets/{YamlWorkflowsPage-HnI-9eBW.js → YamlWorkflowsPage-9Ki54d-9.js} +2 -2
  140. package/dashboard/dist/assets/{YamlWorkflowsPage-HnI-9eBW.js.map → YamlWorkflowsPage-9Ki54d-9.js.map} +1 -1
  141. package/dashboard/dist/assets/{agents-BA2CvQO9.js → agents-CopQ3t5o.js} +2 -2
  142. package/dashboard/dist/assets/{agents-BA2CvQO9.js.map → agents-CopQ3t5o.js.map} +1 -1
  143. package/dashboard/dist/assets/{bots-DHHnoo8x.js → bots-CAYJYL9E.js} +2 -2
  144. package/dashboard/dist/assets/{bots-DHHnoo8x.js.map → bots-CAYJYL9E.js.map} +1 -1
  145. package/dashboard/dist/assets/{capabilities-BYBKLRRI.js → capabilities-5JRieYUy.js} +2 -2
  146. package/dashboard/dist/assets/{capabilities-BYBKLRRI.js.map → capabilities-5JRieYUy.js.map} +1 -1
  147. package/dashboard/dist/assets/{controlplane-H0Ljhb-1.js → controlplane-B4rT6tIw.js} +2 -2
  148. package/dashboard/dist/assets/{controlplane-H0Ljhb-1.js.map → controlplane-B4rT6tIw.js.map} +1 -1
  149. package/dashboard/dist/assets/{escalation-columns-BV3Ztn7D.js → escalation-columns-BbS5X61l.js} +2 -2
  150. package/dashboard/dist/assets/{escalation-columns-BV3Ztn7D.js.map → escalation-columns-BbS5X61l.js.map} +1 -1
  151. package/dashboard/dist/assets/{index-D1Q8WfGN.js → index-B68A3v-S.js} +2 -2
  152. package/dashboard/dist/assets/{index-D1Q8WfGN.js.map → index-B68A3v-S.js.map} +1 -1
  153. package/dashboard/dist/assets/{index-DSjih1iX.js → index-BAi89Xpm.js} +2 -2
  154. package/dashboard/dist/assets/{index-DSjih1iX.js.map → index-BAi89Xpm.js.map} +1 -1
  155. package/dashboard/dist/assets/index-BJ0jjFsI.js +5 -0
  156. package/dashboard/dist/assets/index-BJ0jjFsI.js.map +1 -0
  157. package/dashboard/dist/assets/index-BOJMUk4F.js +2 -0
  158. package/dashboard/dist/assets/{index-BXrm76Hm.js.map → index-BOJMUk4F.js.map} +1 -1
  159. package/dashboard/dist/assets/{index-Dx6-4esw.js → index-BrgYykPV.js} +2 -2
  160. package/dashboard/dist/assets/{index-Dx6-4esw.js.map → index-BrgYykPV.js.map} +1 -1
  161. package/dashboard/dist/assets/{index-BI-9M7z3.js → index-BxgtIqvl.js} +2 -2
  162. package/dashboard/dist/assets/{index-BI-9M7z3.js.map → index-BxgtIqvl.js.map} +1 -1
  163. package/dashboard/dist/assets/index-C0cHXaX-.css +1 -0
  164. package/dashboard/dist/assets/{index-YWvrMcqh.js → index-CDHDoHYz.js} +2 -2
  165. package/dashboard/dist/assets/{index-YWvrMcqh.js.map → index-CDHDoHYz.js.map} +1 -1
  166. package/dashboard/dist/assets/index-CUZJHXew.js +2 -0
  167. package/dashboard/dist/assets/{index-B4FaugP1.js.map → index-CUZJHXew.js.map} +1 -1
  168. package/dashboard/dist/assets/index-D5n_e59T.js +2 -0
  169. package/dashboard/dist/assets/{index-CVMA5PVQ.js.map → index-D5n_e59T.js.map} +1 -1
  170. package/dashboard/dist/assets/index-DIgiIoou.js +63 -0
  171. package/dashboard/dist/assets/index-DIgiIoou.js.map +1 -0
  172. package/dashboard/dist/assets/{index-CP6D_Gtw.js → index-Dd1RxGNw.js} +2 -2
  173. package/dashboard/dist/assets/{index-CP6D_Gtw.js.map → index-Dd1RxGNw.js.map} +1 -1
  174. package/dashboard/dist/assets/index-iOb3sGsC.js +5 -0
  175. package/dashboard/dist/assets/{index-O2wWcCLo.js.map → index-iOb3sGsC.js.map} +1 -1
  176. package/dashboard/dist/assets/{index-CWkAN6wc.js → index-mcAkQblr.js} +2 -2
  177. package/dashboard/dist/assets/{index-CWkAN6wc.js.map → index-mcAkQblr.js.map} +1 -1
  178. package/dashboard/dist/assets/{knowledge-BVbElRHf.js → knowledge-B9bmoXOe.js} +2 -2
  179. package/dashboard/dist/assets/{knowledge-BVbElRHf.js.map → knowledge-B9bmoXOe.js.map} +1 -1
  180. package/dashboard/dist/assets/{mcp-CstDdowJ.js → mcp-DYMFBOFz.js} +2 -2
  181. package/dashboard/dist/assets/{mcp-CstDdowJ.js.map → mcp-DYMFBOFz.js.map} +1 -1
  182. package/dashboard/dist/assets/{mcp-query-DHUs0N8H.js → mcp-query-wloSpyPM.js} +2 -2
  183. package/dashboard/dist/assets/{mcp-query-DHUs0N8H.js.map → mcp-query-wloSpyPM.js.map} +1 -1
  184. package/dashboard/dist/assets/{pipelines-BDmAzE3U.js → pipelines-DBXX6TEi.js} +2 -2
  185. package/dashboard/dist/assets/{pipelines-BDmAzE3U.js.map → pipelines-DBXX6TEi.js.map} +1 -1
  186. package/dashboard/dist/assets/{tasks--qZocuG-.js → tasks-CD3-C7tP.js} +2 -2
  187. package/dashboard/dist/assets/{tasks--qZocuG-.js.map → tasks-CD3-C7tP.js.map} +1 -1
  188. package/dashboard/dist/assets/{topics-P3jkjMsx.js → topics-D8pKi6zA.js} +2 -2
  189. package/dashboard/dist/assets/{topics-P3jkjMsx.js.map → topics-D8pKi6zA.js.map} +1 -1
  190. package/dashboard/dist/assets/{useEventHooks-CqH8Pasj.js → useEventHooks-DV9pLDOW.js} +2 -2
  191. package/dashboard/dist/assets/{useEventHooks-CqH8Pasj.js.map → useEventHooks-DV9pLDOW.js.map} +1 -1
  192. package/dashboard/dist/assets/{useNamespace-aI3tPfo3.js → useNamespace-DykYhZY9.js} +2 -2
  193. package/dashboard/dist/assets/{useNamespace-aI3tPfo3.js.map → useNamespace-DykYhZY9.js.map} +1 -1
  194. package/dashboard/dist/assets/{useYamlActivityEvents-CPVyuW8i.js → useYamlActivityEvents-By044UAv.js} +2 -2
  195. package/dashboard/dist/assets/{useYamlActivityEvents-CPVyuW8i.js.map → useYamlActivityEvents-By044UAv.js.map} +1 -1
  196. package/dashboard/dist/assets/{users-BrcmIH7O.js → users-mI9goDjj.js} +2 -2
  197. package/dashboard/dist/assets/{users-BrcmIH7O.js.map → users-mI9goDjj.js.map} +1 -1
  198. package/dashboard/dist/assets/{vendor-icons-Qk9qLjF_.js → vendor-icons-ihWGa7_d.js} +147 -132
  199. package/dashboard/dist/assets/vendor-icons-ihWGa7_d.js.map +1 -0
  200. package/dashboard/dist/assets/{workflows-DPhX5L5C.js → workflows-DCUilz68.js} +2 -2
  201. package/dashboard/dist/assets/{workflows-DPhX5L5C.js.map → workflows-DCUilz68.js.map} +1 -1
  202. package/dashboard/dist/assets/{yaml-workflows-KZI2cufF.js → yaml-workflows-DWNMP1PT.js} +2 -2
  203. package/dashboard/dist/assets/{yaml-workflows-KZI2cufF.js.map → yaml-workflows-DWNMP1PT.js.map} +1 -1
  204. package/dashboard/dist/index.html +3 -3
  205. package/docs/api/http/escalations.md +1 -0
  206. package/docs/api/http/roles.md +2 -0
  207. package/docs/api/http/users.md +39 -0
  208. package/docs/api/sdk/roles.md +5 -0
  209. package/docs/api/sdk/users.md +39 -0
  210. package/docs/hitl/pinned-views.md +45 -0
  211. package/docs/hitl/x-lt-list-schema.md +30 -2
  212. package/docs/hitl/x-lt-show-if.md +11 -0
  213. package/docs/hitl/x-lt-widget.md +22 -0
  214. package/docs/hitl-guide.md +6 -3
  215. package/package.json +1 -1
  216. package/dashboard/dist/assets/AvailableEscalationsPage-Dx51E6s_.js +0 -2
  217. package/dashboard/dist/assets/AvailableEscalationsPage-Dx51E6s_.js.map +0 -1
  218. package/dashboard/dist/assets/BotPicker-KebTxTDi.js +0 -2
  219. package/dashboard/dist/assets/CountdownTimer-DFqEYmiF.js +0 -2
  220. package/dashboard/dist/assets/CountdownTimer-DFqEYmiF.js.map +0 -1
  221. package/dashboard/dist/assets/ListToolbar-CDlol8XJ.js +0 -2
  222. package/dashboard/dist/assets/OperationsPage-GMojwL3q.js +0 -2
  223. package/dashboard/dist/assets/OperatorDashboard-BGJrxLMU.js +0 -2
  224. package/dashboard/dist/assets/RoleDetailPage-Ws3umQKQ.js +0 -8
  225. package/dashboard/dist/assets/RoleDetailPage-Ws3umQKQ.js.map +0 -1
  226. package/dashboard/dist/assets/RolesPage-D3NNU92h.js +0 -2
  227. package/dashboard/dist/assets/RunAsSelector-Z2Yunqdf.js +0 -2
  228. package/dashboard/dist/assets/ToolPill-BCi101Jh.js +0 -2
  229. package/dashboard/dist/assets/WorkflowPill-DHxrAkp3.js +0 -2
  230. package/dashboard/dist/assets/index-B4FaugP1.js +0 -2
  231. package/dashboard/dist/assets/index-BXrm76Hm.js +0 -2
  232. package/dashboard/dist/assets/index-BeFjLCIQ.js +0 -5
  233. package/dashboard/dist/assets/index-BeFjLCIQ.js.map +0 -1
  234. package/dashboard/dist/assets/index-BrEcQQ1p.css +0 -1
  235. package/dashboard/dist/assets/index-CVMA5PVQ.js +0 -2
  236. package/dashboard/dist/assets/index-O2wWcCLo.js +0 -5
  237. package/dashboard/dist/assets/index-iX8HLLB9.js +0 -63
  238. package/dashboard/dist/assets/index-iX8HLLB9.js.map +0 -1
  239. package/dashboard/dist/assets/vendor-icons-Qk9qLjF_.js.map +0 -1
@@ -0,0 +1,16 @@
1
+ import type { LTApiResult, LTApiAuth } from '../types/sdk';
2
+ /**
3
+ * The caller's preferences document — a generic per-user JSON store for
4
+ * presentation state (pinned views are the first tenant). Always an object;
5
+ * an unset store reads as {}.
6
+ */
7
+ export declare function getMyPreferences(auth: LTApiAuth): Promise<LTApiResult>;
8
+ /**
9
+ * Shallow-merge a patch into the caller's preferences. Top-level keys
10
+ * overwrite; a `null` value deletes its key. The patch and the merged
11
+ * document are both size-capped; the merge itself is a single guarded
12
+ * UPDATE (no read-then-write).
13
+ */
14
+ export declare function patchMyPreferences(input: {
15
+ patch: unknown;
16
+ }, auth: LTApiAuth): Promise<LTApiResult>;
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getMyPreferences = getMyPreferences;
37
+ exports.patchMyPreferences = patchMyPreferences;
38
+ const userService = __importStar(require("../services/user"));
39
+ // ── Self-service surface (/api/me) ─────────────────────────────────────────
40
+ // Operations on the AUTHENTICATED user only — no ids, no admin gates.
41
+ /**
42
+ * The caller's preferences document — a generic per-user JSON store for
43
+ * presentation state (pinned views are the first tenant). Always an object;
44
+ * an unset store reads as {}.
45
+ */
46
+ async function getMyPreferences(auth) {
47
+ try {
48
+ const preferences = await userService.getPreferences(auth.userId);
49
+ return { status: 200, data: { preferences } };
50
+ }
51
+ catch (err) {
52
+ return { status: 500, error: err.message };
53
+ }
54
+ }
55
+ /**
56
+ * Shallow-merge a patch into the caller's preferences. Top-level keys
57
+ * overwrite; a `null` value deletes its key. The patch and the merged
58
+ * document are both size-capped; the merge itself is a single guarded
59
+ * UPDATE (no read-then-write).
60
+ */
61
+ async function patchMyPreferences(input, auth) {
62
+ try {
63
+ const { patch } = input;
64
+ if (!patch || typeof patch !== 'object' || Array.isArray(patch)) {
65
+ return { status: 400, error: 'Body must be a JSON object of preference keys' };
66
+ }
67
+ if (JSON.stringify(patch).length > userService.PREFERENCES_MAX_BYTES) {
68
+ return { status: 413, error: `Preferences patch exceeds ${userService.PREFERENCES_MAX_BYTES} bytes` };
69
+ }
70
+ const preferences = await userService.patchPreferences(auth.userId, patch);
71
+ if (preferences === null) {
72
+ return { status: 413, error: `Merged preferences would exceed ${userService.PREFERENCES_MAX_BYTES} bytes` };
73
+ }
74
+ return { status: 200, data: { preferences } };
75
+ }
76
+ catch (err) {
77
+ return { status: 500, error: err.message };
78
+ }
79
+ }
@@ -88,6 +88,12 @@ export declare function updateRole(input: {
88
88
  metadata_schema?: Record<string, any> | null;
89
89
  /** The escalation LIST schema — rich formatting for this role's list page. */
90
90
  list_schema?: Record<string, any> | null;
91
+ /** Pinned-view seeds for the role's members: [{ label, url, badge? }] or null to clear. */
92
+ default_pins?: {
93
+ label: string;
94
+ url: string;
95
+ badge?: boolean;
96
+ }[] | null;
91
97
  properties?: Record<string, any> | null;
92
98
  ops_visible?: boolean;
93
99
  parent_role?: string | null;
@@ -228,6 +228,15 @@ async function updateRole(input) {
228
228
  if (input.parent_role != null && input.parent_role === input.role) {
229
229
  return { status: 400, error: 'parent_role must reference a different role' };
230
230
  }
231
+ if (input.default_pins != null) {
232
+ const pinsValid = Array.isArray(input.default_pins) && input.default_pins.every((p) => p && typeof p === 'object'
233
+ && typeof p.label === 'string' && p.label.trim() !== ''
234
+ && typeof p.url === 'string' && p.url.startsWith('/')
235
+ && (p.badge === undefined || typeof p.badge === 'boolean'));
236
+ if (!pinsValid) {
237
+ return { status: 400, error: 'default_pins must be [{ label, url, badge? }] with dashboard-relative urls' };
238
+ }
239
+ }
231
240
  if (input.upstream_roles != null) {
232
241
  if (!Array.isArray(input.upstream_roles) || input.upstream_roles.some((u) => typeof u !== 'string' || !u.trim())) {
233
242
  return { status: 400, error: 'upstream_roles must be an array of role names' };
@@ -247,6 +256,7 @@ async function updateRole(input) {
247
256
  form_schema: input.form_schema,
248
257
  metadata_schema: input.metadata_schema,
249
258
  list_schema: input.list_schema,
259
+ default_pins: input.default_pins,
250
260
  properties: input.properties,
251
261
  ops_visible: input.ops_visible,
252
262
  parent_role: input.parent_role,
@@ -0,0 +1,18 @@
1
+ -- Migration 022: Per-user preferences + role default pins
2
+ --
3
+ -- lt_users.preferences is a generic per-user JSON store (pinned views are the
4
+ -- first tenant, not the schema): read via GET /api/me/preferences, written via
5
+ -- PATCH with shallow top-level merge (null deletes a key), size-capped at the
6
+ -- API layer. Preferences carry presentation state only — never data and never
7
+ -- authorization; read-scope enforcement stays with the queries a preference
8
+ -- may point at.
9
+ --
10
+ -- lt_roles.default_pins seeds a role's members with the persona's starting
11
+ -- pinned views ([{ label, url, badge? }]). Users promote, hide, or reorder
12
+ -- them through their own preferences.
13
+
14
+ ALTER TABLE lt_users
15
+ ADD COLUMN IF NOT EXISTS preferences JSONB;
16
+
17
+ ALTER TABLE lt_roles
18
+ ADD COLUMN IF NOT EXISTS default_pins JSONB;
@@ -14,6 +14,7 @@ const escalations_1 = __importDefault(require("./escalations"));
14
14
  const workflows_1 = __importDefault(require("./workflows"));
15
15
  const exports_1 = __importDefault(require("./exports"));
16
16
  const users_1 = __importDefault(require("./users"));
17
+ const me_1 = __importDefault(require("./me"));
17
18
  const roles_1 = __importDefault(require("./roles"));
18
19
  const dba_1 = __importDefault(require("./dba"));
19
20
  const maintenance_1 = __importDefault(require("./maintenance"));
@@ -51,6 +52,7 @@ router.use('/workflows', workflows_1.default);
51
52
  router.use('/workflow-states', exports_1.default);
52
53
  router.use('/config/maintenance', maintenance_1.default);
53
54
  router.use('/users', users_1.default);
55
+ router.use('/me', me_1.default);
54
56
  router.use('/roles', roles_1.default);
55
57
  router.use('/dba', dba_1.default);
56
58
  router.use('/mcp', mcp_1.default);
@@ -0,0 +1,2 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const express_1 = require("express");
37
+ const api = __importStar(require("../api/me"));
38
+ const router = (0, express_1.Router)();
39
+ // ── Self-service (/api/me) — the authenticated user, no admin gates ─────────
40
+ /**
41
+ * GET /api/me/preferences
42
+ * The caller's preferences document ({} when unset).
43
+ */
44
+ router.get('/preferences', async (req, res) => {
45
+ const result = await api.getMyPreferences(req.auth);
46
+ res.status(result.status).json(result.data ?? { error: result.error });
47
+ });
48
+ /**
49
+ * PATCH /api/me/preferences
50
+ * Shallow-merge the body into the caller's preferences; null deletes a key.
51
+ * Returns the merged document. 413 when the result would exceed the cap.
52
+ */
53
+ router.patch('/preferences', async (req, res) => {
54
+ const result = await api.patchMyPreferences({ patch: req.body }, req.auth);
55
+ res.status(result.status).json(result.data ?? { error: result.error });
56
+ });
57
+ exports.default = router;
@@ -275,6 +275,12 @@ export declare function createClient(options?: LTClientOptions): {
275
275
  addRole: typeof usersApi.addUserRole;
276
276
  removeRole: typeof usersApi.removeUserRole;
277
277
  };
278
+ me: {
279
+ getPreferences: (callAuth?: LTApiAuth) => Promise<LTApiResult<any>>;
280
+ patchPreferences: (input: {
281
+ patch: unknown;
282
+ }, auth?: LTApiAuth) => Promise<LTApiResult<any>>;
283
+ };
278
284
  roles: {
279
285
  list: typeof rolesApi.listRoles;
280
286
  listWithDetails: typeof rolesApi.listRolesWithDetails;
@@ -39,6 +39,7 @@ const escalationsApi = __importStar(require("../api/escalations"));
39
39
  const workflowsApi = __importStar(require("../api/workflows"));
40
40
  const yamlWorkflowsApi = __importStar(require("../api/yaml-workflows"));
41
41
  const usersApi = __importStar(require("../api/users"));
42
+ const meApi = __importStar(require("../api/me"));
42
43
  const rolesApi = __importStar(require("../api/roles"));
43
44
  const authApi = __importStar(require("../api/auth"));
44
45
  const mcpApi = __importStar(require("../api/mcp"));
@@ -190,6 +191,16 @@ function createClient(options = {}) {
190
191
  addRole: usersApi.addUserRole,
191
192
  removeRole: usersApi.removeUserRole,
192
193
  },
194
+ // ── Me — the authenticated caller (preferences, presentation state) ────
195
+ me: {
196
+ getPreferences: (callAuth) => {
197
+ const resolved = callAuth ?? auth;
198
+ if (!resolved)
199
+ return Promise.resolve({ status: 401, error: 'Auth context required' });
200
+ return meApi.getMyPreferences(resolved);
201
+ },
202
+ patchPreferences: bindAuth(meApi.patchMyPreferences, auth),
203
+ },
193
204
  // ── Roles ──────────────────────────────────────────────────────────────
194
205
  roles: {
195
206
  list: rolesApi.listRoles,
@@ -146,6 +146,7 @@ async function updateRoleMetadata(role, input) {
146
146
  input.change_summary ?? null,
147
147
  provided('upstream_roles'), upstreams,
148
148
  provided('list_schema'), input.list_schema != null ? JSON.stringify(input.list_schema) : null,
149
+ provided('default_pins'), input.default_pins != null ? JSON.stringify(input.default_pins) : null,
149
150
  ]);
150
151
  if (!rows[0])
151
152
  return null;
@@ -39,8 +39,11 @@ export declare const DELETE_ROLE = "\n DELETE FROM lt_roles WHERE role = $1";
39
39
  * of the form/metadata pair: its own current_list_schema_version and its own
40
40
  * snapshot table (lt_role_list_schemas), so a list-view edit never advances the
41
41
  * resolve form's version. It shares $26 as the change summary.
42
+ *
43
+ * default_pins ($31 = provided sentinel, $32 = value) is unversioned config:
44
+ * the pinned-view seeds a role hands its members.
42
45
  */
43
- export declare const UPDATE_ROLE_METADATA = "\n WITH 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 list_schema = CASE WHEN $29::boolean THEN $30::jsonb ELSE list_schema 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, parent_role, sla_minutes, target_per_hour, worker_count,\n priority_threshold_minutes, priority_facet,\n current_schema_version, list_schema, current_list_schema_version\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";
46
+ export declare const UPDATE_ROLE_METADATA = "\n WITH 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 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 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, parent_role, sla_minutes, target_per_hour, worker_count,\n priority_threshold_minutes, priority_facet,\n current_schema_version, list_schema, current_list_schema_version,\n default_pins\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";
44
47
  export declare const GET_ROLE_FORM_SCHEMA = "\n SELECT form_schema FROM lt_roles WHERE role = $1";
45
48
  export declare const GET_ROLE_METADATA_SCHEMA = "\n SELECT metadata_schema FROM lt_roles WHERE role = $1";
46
49
  export declare const GET_ROLE_UPSTREAMS = "\n SELECT upstream_role FROM lt_role_upstreams WHERE role = $1 ORDER BY upstream_role";
@@ -58,7 +61,7 @@ export declare const GET_ROLE_LIST_SCHEMA_VERSION = "\n SELECT s.role, s.versio
58
61
  * never versioned its list schema still answers, with version NULL).
59
62
  */
60
63
  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";
61
- 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.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.current_schema_version,\n r.list_schema,\n r.current_list_schema_version,\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";
64
+ 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.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.current_schema_version,\n r.list_schema,\n r.current_list_schema_version,\n r.default_pins,\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";
62
65
  export declare const COUNT_USER_ROLE_REFS = "\n SELECT COUNT(*)::int AS cnt FROM lt_user_roles WHERE role = $1";
63
66
  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";
64
67
  export declare const COUNT_WORKFLOW_REFS = "\n SELECT COUNT(*)::int AS cnt FROM lt_config_roles WHERE role = $1";
@@ -73,6 +73,9 @@ exports.DELETE_ROLE = `
73
73
  * of the form/metadata pair: its own current_list_schema_version and its own
74
74
  * snapshot table (lt_role_list_schemas), so a list-view edit never advances the
75
75
  * resolve form's version. It shares $26 as the change summary.
76
+ *
77
+ * default_pins ($31 = provided sentinel, $32 = value) is unversioned config:
78
+ * the pinned-view seeds a role hands its members.
76
79
  */
77
80
  exports.UPDATE_ROLE_METADATA = `
78
81
  WITH updated AS (
@@ -91,6 +94,7 @@ exports.UPDATE_ROLE_METADATA = `
91
94
  = CASE WHEN $22::boolean THEN $23::numeric ELSE priority_threshold_minutes END,
92
95
  priority_facet = CASE WHEN $24::boolean THEN $25 ELSE priority_facet END,
93
96
  list_schema = CASE WHEN $29::boolean THEN $30::jsonb ELSE list_schema END,
97
+ default_pins = CASE WHEN $31::boolean THEN $32::jsonb ELSE default_pins END,
94
98
  current_schema_version = CASE
95
99
  WHEN ($6::boolean AND $7::jsonb IS DISTINCT FROM form_schema)
96
100
  OR ($8::boolean AND $9::jsonb IS DISTINCT FROM metadata_schema)
@@ -105,7 +109,8 @@ exports.UPDATE_ROLE_METADATA = `
105
109
  role, title, description, form_schema, metadata_schema, properties,
106
110
  ops_visible, parent_role, sla_minutes, target_per_hour, worker_count,
107
111
  priority_threshold_minutes, priority_facet,
108
- current_schema_version, list_schema, current_list_schema_version
112
+ current_schema_version, list_schema, current_list_schema_version,
113
+ default_pins
109
114
  ), snapshot AS (
110
115
  INSERT INTO lt_role_schemas (role, version, form_schema, metadata_schema, change_summary)
111
116
  SELECT role, current_schema_version, form_schema, metadata_schema, $26
@@ -239,6 +244,7 @@ exports.LIST_ROLES_WITH_DETAILS = `
239
244
  r.current_schema_version,
240
245
  r.list_schema,
241
246
  r.current_list_schema_version,
247
+ r.default_pins,
242
248
  COALESCE(up.ups, '{}') AS upstream_roles,
243
249
  COALESCE(uc.cnt, 0) AS user_count,
244
250
  COALESCE(cc.cnt, 0) AS chain_count,
@@ -54,6 +54,17 @@ export interface RoleDetail {
54
54
  list_schema: Record<string, any> | null;
55
55
  /** Version of the live list_schema; null until the role first carries one. */
56
56
  current_list_schema_version: number | null;
57
+ /**
58
+ * Pinned-view seeds this role hands its members: [{ label, url, badge? }].
59
+ * On first render, a member without an own pin of the same label sees these
60
+ * in their Pinned nav section (marked role-provided); users promote, hide,
61
+ * or reorder them through their own preferences. URLs only — never data.
62
+ */
63
+ default_pins: {
64
+ label: string;
65
+ url: string;
66
+ badge?: boolean;
67
+ }[] | null;
57
68
  /**
58
69
  * Roles this station draws input from that live in OTHER sequences.
59
70
  * parent_role is the single "prior step" placing the role in one sequence;
@@ -109,6 +120,11 @@ export interface UpdateRoleInput {
109
120
  metadata_schema?: Record<string, any> | null;
110
121
  /** JSON contract that richly formats this role's escalation list page. */
111
122
  list_schema?: Record<string, any> | null;
123
+ default_pins?: {
124
+ label: string;
125
+ url: string;
126
+ badge?: boolean;
127
+ }[] | null;
112
128
  properties?: Record<string, any> | null;
113
129
  ops_visible?: boolean;
114
130
  parent_role?: string | null;
@@ -5,3 +5,4 @@ export { isSuperAdmin, isGroupAdmin, canManageRole, hasGlobalEscalationAccess, h
5
5
  export { READ_SCOPES, WRITE_SCOPES, DEFAULT_READ_SCOPE, DEFAULT_WRITE_SCOPE, isValidReadScope, isValidWriteScope, isValidScopePair, effectiveScope, } from './scope';
6
6
  export { verifyPassword } from './auth';
7
7
  export { seedAdmin } from './seed-admin';
8
+ export { getPreferences, patchPreferences, PREFERENCES_MAX_BYTES } from './preferences';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.seedAdmin = exports.verifyPassword = exports.effectiveScope = exports.isValidScopePair = exports.isValidWriteScope = exports.isValidReadScope = exports.DEFAULT_WRITE_SCOPE = exports.DEFAULT_READ_SCOPE = exports.WRITE_SCOPES = exports.READ_SCOPES = exports.getRoleWriteScope = exports.getRoleScope = exports.hasRolesAsAdmin = exports.hasGlobalEscalationAccess = exports.canManageRole = exports.isGroupAdmin = exports.isSuperAdmin = exports.hasRoleType = exports.hasRole = exports.getUserRoles = exports.removeUserRole = exports.addUserRole = exports.isValidRoleType = exports.listUsers = exports.deleteUser = exports.updateUser = exports.getUserByEmail = exports.getUserByExternalId = exports.getUser = exports.createUser = exports.VALID_ROLE_TYPES = void 0;
3
+ exports.PREFERENCES_MAX_BYTES = exports.patchPreferences = exports.getPreferences = exports.seedAdmin = exports.verifyPassword = exports.effectiveScope = exports.isValidScopePair = exports.isValidWriteScope = exports.isValidReadScope = exports.DEFAULT_WRITE_SCOPE = exports.DEFAULT_READ_SCOPE = exports.WRITE_SCOPES = exports.READ_SCOPES = exports.getRoleWriteScope = exports.getRoleScope = exports.hasRolesAsAdmin = exports.hasGlobalEscalationAccess = exports.canManageRole = exports.isGroupAdmin = exports.isSuperAdmin = exports.hasRoleType = exports.hasRole = exports.getUserRoles = exports.removeUserRole = exports.addUserRole = exports.isValidRoleType = exports.listUsers = exports.deleteUser = exports.updateUser = exports.getUserByEmail = exports.getUserByExternalId = exports.getUser = exports.createUser = exports.VALID_ROLE_TYPES = void 0;
4
4
  var types_1 = require("./types");
5
5
  Object.defineProperty(exports, "VALID_ROLE_TYPES", { enumerable: true, get: function () { return types_1.VALID_ROLE_TYPES; } });
6
6
  var crud_1 = require("./crud");
@@ -39,3 +39,7 @@ var auth_1 = require("./auth");
39
39
  Object.defineProperty(exports, "verifyPassword", { enumerable: true, get: function () { return auth_1.verifyPassword; } });
40
40
  var seed_admin_1 = require("./seed-admin");
41
41
  Object.defineProperty(exports, "seedAdmin", { enumerable: true, get: function () { return seed_admin_1.seedAdmin; } });
42
+ var preferences_1 = require("./preferences");
43
+ Object.defineProperty(exports, "getPreferences", { enumerable: true, get: function () { return preferences_1.getPreferences; } });
44
+ Object.defineProperty(exports, "patchPreferences", { enumerable: true, get: function () { return preferences_1.patchPreferences; } });
45
+ Object.defineProperty(exports, "PREFERENCES_MAX_BYTES", { enumerable: true, get: function () { return preferences_1.PREFERENCES_MAX_BYTES; } });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Per-user preferences — a generic JSON store for presentation state (pinned
3
+ * views are the first tenant, not the schema). Preferences carry URLs and UI
4
+ * choices only, never data and never authorization.
5
+ */
6
+ /** Server-side ceiling on the stored document (the API rejects beyond it). */
7
+ export declare const PREFERENCES_MAX_BYTES: number;
8
+ export declare function getPreferences(userId: string): Promise<Record<string, unknown>>;
9
+ /**
10
+ * Shallow-merge `patch` into the user's preferences in ONE guarded UPDATE:
11
+ * top-level keys overwrite, a `null` value deletes its key, and the statement
12
+ * refuses to commit a document over the size cap (returns null → 413 at the
13
+ * API). No read-then-write — concurrent patches serialize on the row.
14
+ */
15
+ export declare function patchPreferences(userId: string, patch: Record<string, unknown>): Promise<Record<string, unknown> | null>;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PREFERENCES_MAX_BYTES = void 0;
4
+ exports.getPreferences = getPreferences;
5
+ exports.patchPreferences = patchPreferences;
6
+ const db_1 = require("../../lib/db");
7
+ /**
8
+ * Per-user preferences — a generic JSON store for presentation state (pinned
9
+ * views are the first tenant, not the schema). Preferences carry URLs and UI
10
+ * choices only, never data and never authorization.
11
+ */
12
+ /** Server-side ceiling on the stored document (the API rejects beyond it). */
13
+ exports.PREFERENCES_MAX_BYTES = 32 * 1024;
14
+ async function getPreferences(userId) {
15
+ const { rows } = await (0, db_1.getPool)().query('SELECT preferences FROM lt_users WHERE id = $1', [userId]);
16
+ return rows[0]?.preferences ?? {};
17
+ }
18
+ /**
19
+ * Shallow-merge `patch` into the user's preferences in ONE guarded UPDATE:
20
+ * top-level keys overwrite, a `null` value deletes its key, and the statement
21
+ * refuses to commit a document over the size cap (returns null → 413 at the
22
+ * API). No read-then-write — concurrent patches serialize on the row.
23
+ */
24
+ async function patchPreferences(userId, patch) {
25
+ const deletions = Object.keys(patch).filter((k) => patch[k] === null);
26
+ const additions = {};
27
+ for (const [k, v] of Object.entries(patch)) {
28
+ if (v !== null)
29
+ additions[k] = v;
30
+ }
31
+ const { rows } = await (0, db_1.getPool)().query(`UPDATE lt_users u
32
+ SET preferences = ((COALESCE(u.preferences, '{}'::jsonb) || $2::jsonb) - $3::text[]),
33
+ updated_at = NOW()
34
+ WHERE u.id = $1
35
+ AND length(((COALESCE(u.preferences, '{}'::jsonb) || $2::jsonb) - $3::text[])::text) <= $4
36
+ RETURNING u.preferences`, [userId, JSON.stringify(additions), deletions, exports.PREFERENCES_MAX_BYTES]);
37
+ return rows[0]?.preferences ?? null;
38
+ }
@@ -568,6 +568,20 @@ export declare const updateRoleSchema: z.ZodObject<{
568
568
  priority_threshold_minutes: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
569
569
  priority_facet: z.ZodOptional<z.ZodNullable<z.ZodString>>;
570
570
  upstream_roles: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
571
+ list_schema: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodAny>>>;
572
+ default_pins: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
573
+ label: z.ZodString;
574
+ url: z.ZodString;
575
+ badge: z.ZodOptional<z.ZodBoolean>;
576
+ }, "strip", z.ZodTypeAny, {
577
+ url: string;
578
+ label: string;
579
+ badge?: boolean | undefined;
580
+ }, {
581
+ url: string;
582
+ label: string;
583
+ badge?: boolean | undefined;
584
+ }>, "many">>>;
571
585
  change_summary: z.ZodOptional<z.ZodString>;
572
586
  }, "strip", z.ZodTypeAny, {
573
587
  role: string;
@@ -576,6 +590,12 @@ export declare const updateRoleSchema: z.ZodObject<{
576
590
  title?: string | null | undefined;
577
591
  properties?: Record<string, any> | null | undefined;
578
592
  metadata_schema?: Record<string, any> | null | undefined;
593
+ list_schema?: Record<string, any> | null | undefined;
594
+ default_pins?: {
595
+ url: string;
596
+ label: string;
597
+ badge?: boolean | undefined;
598
+ }[] | null | undefined;
579
599
  ops_visible?: boolean | undefined;
580
600
  parent_role?: string | null | undefined;
581
601
  sla_minutes?: number | null | undefined;
@@ -592,6 +612,12 @@ export declare const updateRoleSchema: z.ZodObject<{
592
612
  title?: string | null | undefined;
593
613
  properties?: Record<string, any> | null | undefined;
594
614
  metadata_schema?: Record<string, any> | null | undefined;
615
+ list_schema?: Record<string, any> | null | undefined;
616
+ default_pins?: {
617
+ url: string;
618
+ label: string;
619
+ badge?: boolean | undefined;
620
+ }[] | null | undefined;
595
621
  ops_visible?: boolean | undefined;
596
622
  parent_role?: string | null | undefined;
597
623
  sla_minutes?: number | null | undefined;
@@ -250,6 +250,12 @@ exports.updateRoleSchema = zod_1.z.object({
250
250
  priority_threshold_minutes: zod_1.z.number().min(0).nullable().optional().describe('Max age in minutes before a pending unclaimed escalation counts toward the Pace Board priority count. Falls back to sla_minutes when null.'),
251
251
  priority_facet: zod_1.z.string().regex(facet_sql_1.FACET_KEY).nullable().optional().describe('lt_escalations.metadata key holding the age origin for the priority count as an ISO 8601 UTC timestamp (e.g. authorized_at). Falls back to created_at when null. When set, items missing the key or holding an unparseable value are not counted.'),
252
252
  upstream_roles: zod_1.z.array(zod_1.z.string()).nullable().optional().describe('Replace the set of roles this station draws input from across other sequences (parent_role stays the single prior step in its own sequence). Omitted = preserve; null or [] = clear.'),
253
+ list_schema: zod_1.z.record(zod_1.z.any()).nullable().optional().describe('JSON contract (x-lt-* markup) that richly formats this role\'s escalation LIST page. Versioned independently of form_schema; the list always renders the latest version.'),
254
+ default_pins: zod_1.z.array(zod_1.z.object({
255
+ label: zod_1.z.string().describe('Pin label shown in the member\'s Pinned nav section'),
256
+ url: zod_1.z.string().describe('Dashboard-relative deep link (must start with /)'),
257
+ badge: zod_1.z.boolean().optional().describe('Render a live count beside the label (escalations-list URLs)'),
258
+ })).nullable().optional().describe('Pinned-view seeds handed to every member of this role. Members promote, hide, or reorder them via their own preferences. Null clears.'),
253
259
  change_summary: zod_1.z.string().optional().describe('Recorded on the schema version snapshot when this update changes form_schema or metadata_schema'),
254
260
  });
255
261
  exports.getRoleSchemaSchema = zod_1.z.object({
@@ -194,9 +194,10 @@ function registerUserTools(server) {
194
194
  server.registerTool('update_role', {
195
195
  title: 'Update Role',
196
196
  description: 'Update role metadata with PATCH semantics — omitted fields keep their ' +
197
- 'values. Covers display name, description, form/metadata schemas, the ' +
198
- 'free properties bag, ops_visible flag, parent role, and the typed ' +
199
- 'operational targets (sla_minutes, target_per_hour, worker_count, ' +
197
+ 'values. Covers display name, description, form/metadata/list schemas, ' +
198
+ 'the free properties bag, ops_visible flag, parent role, default_pins ' +
199
+ '(member pinned-view seeds), and the typed operational targets ' +
200
+ '(sla_minutes, target_per_hour, worker_count, ' +
200
201
  'priority_threshold_minutes, priority_facet).',
201
202
  inputSchema: schemas_1.updateRoleSchema,
202
203
  }, async (args) => {
@@ -214,6 +215,8 @@ function registerUserTools(server) {
214
215
  priority_threshold_minutes: args.priority_threshold_minutes,
215
216
  priority_facet: args.priority_facet,
216
217
  upstream_roles: args.upstream_roles,
218
+ list_schema: args.list_schema,
219
+ default_pins: args.default_pins,
217
220
  change_summary: args.change_summary,
218
221
  });
219
222
  if (!updated) {