@hotmeshio/long-tail 0.10.9 → 0.10.11
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.
- package/build/api/escalations/list.js +11 -4
- package/build/api/index.d.ts +1 -0
- package/build/api/index.js +2 -1
- package/build/api/personas.d.ts +121 -0
- package/build/api/personas.js +341 -0
- package/build/api/roles.d.ts +2 -0
- package/build/api/roles.js +4 -0
- package/build/bin/ltc.js +23 -0
- package/build/lib/cli/commands/personas.d.ts +16 -0
- package/build/lib/cli/commands/personas.js +42 -0
- package/build/lib/db/schemas/024_personas.sql +53 -0
- package/build/lib/db/schemas/025_ops_home_default.sql +11 -0
- package/build/modules/features.d.ts +9 -0
- package/build/modules/features.js +1 -0
- package/build/routes/index.js +2 -0
- package/build/routes/personas.d.ts +2 -0
- package/build/routes/personas.js +118 -0
- package/build/routes/users.js +35 -0
- package/build/sdk/index.d.ts +15 -0
- package/build/sdk/index.js +16 -0
- package/build/services/persona/index.d.ts +92 -0
- package/build/services/persona/index.js +217 -0
- package/build/services/persona/sql.d.ts +24 -0
- package/build/services/persona/sql.js +158 -0
- package/build/services/persona/types.d.ts +23 -0
- package/build/services/persona/types.js +33 -0
- package/build/services/role/index.js +1 -0
- package/build/services/role/sql.d.ts +6 -2
- package/build/services/role/sql.js +11 -2
- package/build/services/role/types.d.ts +9 -0
- package/build/services/user/sql.d.ts +8 -5
- package/build/services/user/sql.js +15 -5
- package/build/system/mcp-servers/admin/index.d.ts +1 -0
- package/build/system/mcp-servers/admin/index.js +5 -2
- package/build/system/mcp-servers/admin/personas.d.ts +8 -0
- package/build/system/mcp-servers/admin/personas.js +186 -0
- package/build/system/mcp-servers/admin/schemas.d.ts +94 -0
- package/build/system/mcp-servers/admin/schemas.js +43 -2
- package/build/system/mcp-servers/admin/users.js +1 -0
- package/build/system/seed/tool-manifests-admin.d.ts +1057 -0
- package/build/system/seed/tool-manifests-admin.js +12 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/persona.d.ts +56 -0
- package/build/types/persona.js +2 -0
- package/build/types/startup.d.ts +8 -0
- package/build/types/user.d.ts +2 -0
- package/dashboard/dist/assets/{AdminDashboard-DWSYdAeW.js → AdminDashboard-CkTbRfY9.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-DWSYdAeW.js.map → AdminDashboard-CkTbRfY9.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-Dm6gL76m.js → AgentConfigPage-Cm8FRpXi.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-Dm6gL76m.js.map → AgentConfigPage-Cm8FRpXi.js.map} +1 -1
- package/dashboard/dist/assets/AgentDetailPage-sQ1-UT46.js +4 -0
- package/dashboard/dist/assets/AgentDetailPage-sQ1-UT46.js.map +1 -0
- package/dashboard/dist/assets/{AgentsPage-DKaDRk-Y.js → AgentsPage-bSx_mdae.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-DKaDRk-Y.js.map → AgentsPage-bSx_mdae.js.map} +1 -1
- package/dashboard/dist/assets/AutoGrowTextarea-y-oNY51_.js +2 -0
- package/dashboard/dist/assets/AutoGrowTextarea-y-oNY51_.js.map +1 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-8pMC7Xv6.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-8pMC7Xv6.js.map +1 -0
- package/dashboard/dist/assets/{BotPicker-DRv_orzI.js → BotPicker-C4uGH2x9.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-DRv_orzI.js.map → BotPicker-C4uGH2x9.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-DqRVzMol.js → CapabilitiesPage-BRoOeKcc.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-DqRVzMol.js.map → CapabilitiesPage-BRoOeKcc.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-D0psvw8i.js → CollapsibleSection-CIj8Adc9.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-D0psvw8i.js.map → CollapsibleSection-CIj8Adc9.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-DD7SEMeX.js → ConfirmDeleteModal-Ugi_9Ukq.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-DD7SEMeX.js.map → ConfirmDeleteModal-Ugi_9Ukq.js.map} +1 -1
- package/dashboard/dist/assets/{CopyableId-BpB-NvDh.js → CopyableId-GUEdiiL5.js} +2 -2
- package/dashboard/dist/assets/{CopyableId-BpB-NvDh.js.map → CopyableId-GUEdiiL5.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-D3t0XMhE.js +2 -0
- package/dashboard/dist/assets/CountdownTimer-D3t0XMhE.js.map +1 -0
- package/dashboard/dist/assets/{CredentialsPage-Axdci1z-.js → CredentialsPage-B73Si6K1.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-Axdci1z-.js.map → CredentialsPage-B73Si6K1.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-BjZ_wZA8.js → CronLabel-Ca1aHolt.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-BjZ_wZA8.js.map → CronLabel-Ca1aHolt.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-CkUCMUfk.js → CustomDurationPicker-_9E9x1YN.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-CkUCMUfk.js.map → CustomDurationPicker-_9E9x1YN.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-_tmC3jEe.js → DropZone-NYn6TWHz.js} +2 -2
- package/dashboard/dist/assets/{DropZone-_tmC3jEe.js.map → DropZone-NYn6TWHz.js.map} +1 -1
- package/dashboard/dist/assets/ElapsedCell-karxia93.js +2 -0
- package/dashboard/dist/assets/{ElapsedCell-BE_CN5sP.js.map → ElapsedCell-karxia93.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-CgcVIiYR.js → EscalationListSchemaPage-CDaNmbUA.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-CgcVIiYR.js.map → EscalationListSchemaPage-CDaNmbUA.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-BaAn1Hcr.js → EscalationSchemaPage-k-2hFT2t.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-BaAn1Hcr.js.map → EscalationSchemaPage-k-2hFT2t.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-Dbq7tKzr.js → EscalationsOverview-C1e7IPn_.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-Dbq7tKzr.js.map → EscalationsOverview-C1e7IPn_.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-0RUK9jqt.js → EventTable-CIrrtL7_.js} +2 -2
- package/dashboard/dist/assets/{EventTable-0RUK9jqt.js.map → EventTable-CIrrtL7_.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-B_dy2Jhj.js → FilterBar-CzjtH74v.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-B_dy2Jhj.js.map → FilterBar-CzjtH74v.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-CvLYp1nL.js → GraphInvokePage-LMpWw8z1.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-CvLYp1nL.js.map → GraphInvokePage-LMpWw8z1.js.map} +1 -1
- package/dashboard/dist/assets/HomePage-Kl2DBG6l.js +2 -0
- package/dashboard/dist/assets/HomePage-Kl2DBG6l.js.map +1 -0
- package/dashboard/dist/assets/ListToolbar-B2fub0DY.js +2 -0
- package/dashboard/dist/assets/ListToolbar-B2fub0DY.js.map +1 -0
- package/dashboard/dist/assets/{McpOverview-Ca8cpc8g.js → McpOverview-odYnCZCC.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-Ca8cpc8g.js.map → McpOverview-odYnCZCC.js.map} +1 -1
- package/dashboard/dist/assets/McpQueryDetailPage-BtqwHUAg.js +5 -0
- package/dashboard/dist/assets/McpQueryDetailPage-BtqwHUAg.js.map +1 -0
- package/dashboard/dist/assets/McpQueryPage-CPkVwNIK.js +2 -0
- package/dashboard/dist/assets/McpQueryPage-CPkVwNIK.js.map +1 -0
- package/dashboard/dist/assets/{McpRunDetailPage-C76mfUtG.js → McpRunDetailPage-D-Rz9MRw.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-C76mfUtG.js.map → McpRunDetailPage-D-Rz9MRw.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-B43BqEyw.js → McpRunsPage-rdpZ2yMh.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-B43BqEyw.js.map → McpRunsPage-rdpZ2yMh.js.map} +1 -1
- package/dashboard/dist/assets/{Modal-CA2Iv02H.js → Modal-Dr1Xy0j0.js} +2 -2
- package/dashboard/dist/assets/{Modal-CA2Iv02H.js.map → Modal-Dr1Xy0j0.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-B5gHotsd.js → NamespacePill-GwO-WfhX.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-B5gHotsd.js.map → NamespacePill-GwO-WfhX.js.map} +1 -1
- package/dashboard/dist/assets/OperationsPage-DlyGLPAs.js +2 -0
- package/dashboard/dist/assets/OperationsPage-DlyGLPAs.js.map +1 -0
- package/dashboard/dist/assets/OperatorDashboard-Csei5vj-.js +2 -0
- package/dashboard/dist/assets/OperatorDashboard-Csei5vj-.js.map +1 -0
- package/dashboard/dist/assets/{PageHeader-DrbNMGxm.js → PageHeader-Bo9BU9pK.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-DrbNMGxm.js.map → PageHeader-Bo9BU9pK.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-SbQkaQLG.js → PageHeaderWithStats-8_5cOSKL.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-SbQkaQLG.js.map → PageHeaderWithStats-8_5cOSKL.js.map} +1 -1
- package/dashboard/dist/assets/PersonaDetailPage--ZL6Or6v.js +2 -0
- package/dashboard/dist/assets/PersonaDetailPage--ZL6Or6v.js.map +1 -0
- package/dashboard/dist/assets/PersonasPage-Bdcoay3P.js +2 -0
- package/dashboard/dist/assets/PersonasPage-Bdcoay3P.js.map +1 -0
- package/dashboard/dist/assets/ProcessDetailPage-HrmVQq7S.js +2 -0
- package/dashboard/dist/assets/ProcessDetailPage-HrmVQq7S.js.map +1 -0
- package/dashboard/dist/assets/{ProcessesListPage-Di0n8TR4.js → ProcessesListPage-_xmj6Bo-.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-Di0n8TR4.js.map → ProcessesListPage-_xmj6Bo-.js.map} +1 -1
- package/dashboard/dist/assets/RoleDetailPage-C0ju2-4K.js +8 -0
- package/dashboard/dist/assets/RoleDetailPage-C0ju2-4K.js.map +1 -0
- package/dashboard/dist/assets/{RolePill-Cz-AAWqA.js → RolePill-CQlnEWkK.js} +2 -2
- package/dashboard/dist/assets/{RolePill-Cz-AAWqA.js.map → RolePill-CQlnEWkK.js.map} +1 -1
- package/dashboard/dist/assets/RolesPage-CKluVSpB.js +2 -0
- package/dashboard/dist/assets/RolesPage-CKluVSpB.js.map +1 -0
- package/dashboard/dist/assets/{RunAsSelector-DFv0VNVZ.js → RunAsSelector-DdfecQ1U.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-DFv0VNVZ.js.map → RunAsSelector-DdfecQ1U.js.map} +1 -1
- package/dashboard/dist/assets/ScopeBadge-BBYkevuR.js +2 -0
- package/dashboard/dist/assets/ScopeBadge-BBYkevuR.js.map +1 -0
- package/dashboard/dist/assets/StatCard-Ca-ngCaD.js +2 -0
- package/dashboard/dist/assets/StatCard-Ca-ngCaD.js.map +1 -0
- package/dashboard/dist/assets/{StatusBadge-BbqghFMi.js → StatusBadge-BwUvykDo.js} +2 -2
- package/dashboard/dist/assets/{StatusBadge-BbqghFMi.js.map → StatusBadge-BwUvykDo.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-D5zxe_l9.js → StickyPagination-cLddIdtT.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-D5zxe_l9.js.map → StickyPagination-cLddIdtT.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-BmBfNSEr.js → StreamMessageDetail-CZXWDawC.js} +2 -2
- package/dashboard/dist/assets/StreamMessageDetail-CZXWDawC.js.map +1 -0
- package/dashboard/dist/assets/{SwimlaneTimeline-CA0TKDIi.js → SwimlaneTimeline-fWY0gaf3.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-CA0TKDIi.js.map → SwimlaneTimeline-fWY0gaf3.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-Bf9dZSG6.js → TagInput-CDKbslLx.js} +2 -2
- package/dashboard/dist/assets/{TagInput-Bf9dZSG6.js.map → TagInput-CDKbslLx.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-C15nADUW.js → TaskDetailPage-BjE4G2yn.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-C15nADUW.js.map → TaskDetailPage-BjE4G2yn.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-DfiBYQy2.js → TaskQueuePill-G3RuYRNZ.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-DfiBYQy2.js.map → TaskQueuePill-G3RuYRNZ.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-DQdAayqc.js → TasksListPage-KAhmCWB2.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-DQdAayqc.js.map → TasksListPage-KAhmCWB2.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-CvslqTB7.js → TimeAgo-C_H2TyZw.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-CvslqTB7.js.map → TimeAgo-C_H2TyZw.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-BZCQQONl.js → TimestampCell-COG_4Flg.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-BZCQQONl.js.map → TimestampCell-COG_4Flg.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-gA4sXukc.js → ToolPill-ChSyRJZC.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-gA4sXukc.js.map → ToolPill-ChSyRJZC.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-BgLVc6R5.js → ToolTestPanel-BPdJECW0.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-BgLVc6R5.js.map → ToolTestPanel-BPdJECW0.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-9A0aPb4t.js → TopicDetailPage-DAqx5JqA.js} +3 -3
- package/dashboard/dist/assets/{TopicDetailPage-9A0aPb4t.js.map → TopicDetailPage-DAqx5JqA.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-o0EZxKbR.js → TopicsPage-DoGqAdPm.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-o0EZxKbR.js.map → TopicsPage-DoGqAdPm.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-DKMLxBJ5.js → UserName-CKO_rk1R.js} +2 -2
- package/dashboard/dist/assets/{UserName-DKMLxBJ5.js.map → UserName-CKO_rk1R.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-C-snB_dD.js → WorkflowExecutionPage-D3VQ9iQV.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-C-snB_dD.js.map → WorkflowExecutionPage-D3VQ9iQV.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-Djt2AtZk.js → WorkflowPill-CNbwug5p.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-Djt2AtZk.js.map → WorkflowPill-CNbwug5p.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-BRQmgsLR.js → WorkflowsDashboard-DdJ86We6.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-BRQmgsLR.js.map → WorkflowsDashboard-DdJ86We6.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-DmMdIRHQ.js → WorkflowsOverview-ZfFBzePp.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-DmMdIRHQ.js.map → WorkflowsOverview-ZfFBzePp.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-Bj7QkCry.js → YamlWorkflowDetailPage-4bd5yXdA.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-Bj7QkCry.js.map → YamlWorkflowDetailPage-4bd5yXdA.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-BIi77mE0.js → YamlWorkflowsPage-iHPNXjQj.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-BIi77mE0.js.map → YamlWorkflowsPage-iHPNXjQj.js.map} +1 -1
- package/dashboard/dist/assets/{agents-EBIsjLCr.js → agents-DjD5U3Wb.js} +2 -2
- package/dashboard/dist/assets/{agents-EBIsjLCr.js.map → agents-DjD5U3Wb.js.map} +1 -1
- package/dashboard/dist/assets/{bots-BXzxybS6.js → bots-DiljVapH.js} +2 -2
- package/dashboard/dist/assets/{bots-BXzxybS6.js.map → bots-DiljVapH.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-CnprG6q_.js → capabilities-DV_5ghHT.js} +2 -2
- package/dashboard/dist/assets/{capabilities-CnprG6q_.js.map → capabilities-DV_5ghHT.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DiC0xtNq.js → controlplane-BKMvfWCB.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DiC0xtNq.js.map → controlplane-BKMvfWCB.js.map} +1 -1
- package/dashboard/dist/assets/escalation-columns-BQpCaJId.js +2 -0
- package/dashboard/dist/assets/escalation-columns-BQpCaJId.js.map +1 -0
- package/dashboard/dist/assets/{index-BzRXMicE.js → index-B-WkiNRN.js} +2 -2
- package/dashboard/dist/assets/{index-BzRXMicE.js.map → index-B-WkiNRN.js.map} +1 -1
- package/dashboard/dist/assets/index-BO-7S9Xw.js +2 -0
- package/dashboard/dist/assets/index-BO-7S9Xw.js.map +1 -0
- package/dashboard/dist/assets/{index-C7KY8GTF.js → index-BaV3l0UE.js} +2 -2
- package/dashboard/dist/assets/{index-C7KY8GTF.js.map → index-BaV3l0UE.js.map} +1 -1
- package/dashboard/dist/assets/{index-B6ldRx_s.js → index-BsOxMMmb.js} +2 -2
- package/dashboard/dist/assets/{index-B6ldRx_s.js.map → index-BsOxMMmb.js.map} +1 -1
- package/dashboard/dist/assets/index-CI8rrKjx.js +2 -0
- package/dashboard/dist/assets/{index-CjBdB8Ht.js.map → index-CI8rrKjx.js.map} +1 -1
- package/dashboard/dist/assets/index-CItsikDw.js +2 -0
- package/dashboard/dist/assets/index-CItsikDw.js.map +1 -0
- package/dashboard/dist/assets/{index-CcMIca5t.js → index-CStR4uIU.js} +2 -2
- package/dashboard/dist/assets/{index-CcMIca5t.js.map → index-CStR4uIU.js.map} +1 -1
- package/dashboard/dist/assets/{index-CSTwyrwu.js → index-DbTD-dio.js} +26 -26
- package/dashboard/dist/assets/index-DbTD-dio.js.map +1 -0
- package/dashboard/dist/assets/{index-gBnGEubX.js → index-DhATO1cS.js} +2 -2
- package/dashboard/dist/assets/{index-gBnGEubX.js.map → index-DhATO1cS.js.map} +1 -1
- package/dashboard/dist/assets/index-DnlsDaAw.css +1 -0
- package/dashboard/dist/assets/{index-ovFEZ9SV.js → index-Tx_ETzcH.js} +2 -2
- package/dashboard/dist/assets/{index-ovFEZ9SV.js.map → index-Tx_ETzcH.js.map} +1 -1
- package/dashboard/dist/assets/{index-DVmC_UfQ.js → index-kzIIeVbx.js} +4 -4
- package/dashboard/dist/assets/{index-DVmC_UfQ.js.map → index-kzIIeVbx.js.map} +1 -1
- package/dashboard/dist/assets/{index-BHAjQoOy.js → index-nIrYejxe.js} +3 -3
- package/dashboard/dist/assets/{index-BHAjQoOy.js.map → index-nIrYejxe.js.map} +1 -1
- package/dashboard/dist/assets/{index-Dht0ihGT.js → index-xZqQxqu2.js} +2 -2
- package/dashboard/dist/assets/{index-Dht0ihGT.js.map → index-xZqQxqu2.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-W5QSKkYQ.js → knowledge-BocTnSiA.js} +2 -2
- package/dashboard/dist/assets/{knowledge-W5QSKkYQ.js.map → knowledge-BocTnSiA.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-n877HyOj.js → mcp-C1KBjKQ_.js} +2 -2
- package/dashboard/dist/assets/{mcp-n877HyOj.js.map → mcp-C1KBjKQ_.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-C9kV4sUm.js → mcp-query-B3cjukkA.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-C9kV4sUm.js.map → mcp-query-B3cjukkA.js.map} +1 -1
- package/dashboard/dist/assets/personas-DiA2bJaX.js +2 -0
- package/dashboard/dist/assets/personas-DiA2bJaX.js.map +1 -0
- package/dashboard/dist/assets/{pipelines-CBR68T8R.js → pipelines-Dt2d2EFR.js} +2 -2
- package/dashboard/dist/assets/{pipelines-CBR68T8R.js.map → pipelines-Dt2d2EFR.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-DHpWqKMk.js → tasks-cDh2hNml.js} +2 -2
- package/dashboard/dist/assets/{tasks-DHpWqKMk.js.map → tasks-cDh2hNml.js.map} +1 -1
- package/dashboard/dist/assets/{topics-CaLtyqSh.js → topics-yFlGF-u1.js} +2 -2
- package/dashboard/dist/assets/{topics-CaLtyqSh.js.map → topics-yFlGF-u1.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-B8p56JlB.js → useEventHooks-D2R_ckS8.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-B8p56JlB.js.map → useEventHooks-D2R_ckS8.js.map} +1 -1
- package/dashboard/dist/assets/{useFilterParams-CvRyYHJN.js → useFilterParams-B7suPsIK.js} +2 -2
- package/dashboard/dist/assets/{useFilterParams-CvRyYHJN.js.map → useFilterParams-B7suPsIK.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-ej71FCvu.js → useNamespace-u-V1GVUD.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-ej71FCvu.js.map → useNamespace-u-V1GVUD.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-DgpiFXib.js → useYamlActivityEvents-BhOZeqgE.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-DgpiFXib.js.map → useYamlActivityEvents-BhOZeqgE.js.map} +1 -1
- package/dashboard/dist/assets/{users-CHnjI_Ca.js → users-BoXPwdee.js} +2 -2
- package/dashboard/dist/assets/{users-CHnjI_Ca.js.map → users-BoXPwdee.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-Bg6eJX4Z.js → vendor-icons-D71XjkNy.js} +133 -128
- package/dashboard/dist/assets/vendor-icons-D71XjkNy.js.map +1 -0
- package/dashboard/dist/assets/{vendor-react-BpdAFEQc.js → vendor-react-C1YOyCSV.js} +2 -2
- package/dashboard/dist/assets/{vendor-react-BpdAFEQc.js.map → vendor-react-C1YOyCSV.js.map} +1 -1
- package/dashboard/dist/assets/{workflows-DtnXUL0U.js → workflows-mCoyKuLZ.js} +2 -2
- package/dashboard/dist/assets/{workflows-DtnXUL0U.js.map → workflows-mCoyKuLZ.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-DDclYAID.js → yaml-workflows-CWxXGDpn.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-DDclYAID.js.map → yaml-workflows-CWxXGDpn.js.map} +1 -1
- package/dashboard/dist/index.html +4 -4
- package/docs/api/http/personas.md +160 -0
- package/docs/cli.md +12 -0
- package/docs/dashboard.md +25 -3
- package/docs/design-principles.md +13 -5
- package/docs/hitl/pinned-views.md +3 -3
- package/docs/hitl/x-lt-list-schema.md +2 -3
- package/docs/iam.md +47 -0
- package/docs/operations.md +1 -1
- package/docs/sdk.md +1 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/AgentDetailPage-D-Xbyrb6.js +0 -4
- package/dashboard/dist/assets/AgentDetailPage-D-Xbyrb6.js.map +0 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-B-aHvGKD.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-B-aHvGKD.js.map +0 -1
- package/dashboard/dist/assets/CountdownTimer-BhF3oqS8.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-BhF3oqS8.js.map +0 -1
- package/dashboard/dist/assets/ElapsedCell-BE_CN5sP.js +0 -2
- package/dashboard/dist/assets/HomePage-B6s1ZeyA.js +0 -2
- package/dashboard/dist/assets/HomePage-B6s1ZeyA.js.map +0 -1
- package/dashboard/dist/assets/ListToolbar-DVhlAKZ3.js +0 -2
- package/dashboard/dist/assets/ListToolbar-DVhlAKZ3.js.map +0 -1
- package/dashboard/dist/assets/McpQueryDetailPage-D0r2lyZg.js +0 -5
- package/dashboard/dist/assets/McpQueryDetailPage-D0r2lyZg.js.map +0 -1
- package/dashboard/dist/assets/McpQueryPage-DPP6BB3d.js +0 -2
- package/dashboard/dist/assets/McpQueryPage-DPP6BB3d.js.map +0 -1
- package/dashboard/dist/assets/OperationsPage-DbHzQCuE.js +0 -2
- package/dashboard/dist/assets/OperationsPage-DbHzQCuE.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-B70nS_Ah.js +0 -2
- package/dashboard/dist/assets/OperatorDashboard-B70nS_Ah.js.map +0 -1
- package/dashboard/dist/assets/ProcessDetailPage-eLLUCWFf.js +0 -2
- package/dashboard/dist/assets/ProcessDetailPage-eLLUCWFf.js.map +0 -1
- package/dashboard/dist/assets/RoleDetailPage-Dhn9zU5l.js +0 -8
- package/dashboard/dist/assets/RoleDetailPage-Dhn9zU5l.js.map +0 -1
- package/dashboard/dist/assets/RolesPage-BnAwjUiG.js +0 -2
- package/dashboard/dist/assets/RolesPage-BnAwjUiG.js.map +0 -1
- package/dashboard/dist/assets/StatCard-DBANWIss.js +0 -2
- package/dashboard/dist/assets/StatCard-DBANWIss.js.map +0 -1
- package/dashboard/dist/assets/StreamMessageDetail-BmBfNSEr.js.map +0 -1
- package/dashboard/dist/assets/escalation-columns-D0aYpJkF.js +0 -2
- package/dashboard/dist/assets/escalation-columns-D0aYpJkF.js.map +0 -1
- package/dashboard/dist/assets/index-B2iZG_HP.css +0 -1
- package/dashboard/dist/assets/index-CSTwyrwu.js.map +0 -1
- package/dashboard/dist/assets/index-CjBdB8Ht.js +0 -2
- package/dashboard/dist/assets/index-D-7mT0ew.js +0 -2
- package/dashboard/dist/assets/index-D-7mT0ew.js.map +0 -1
- package/dashboard/dist/assets/index-DDA7FvqT.js +0 -2
- package/dashboard/dist/assets/index-DDA7FvqT.js.map +0 -1
- package/dashboard/dist/assets/role-display-Dvo2lDpU.js +0 -2
- package/dashboard/dist/assets/role-display-Dvo2lDpU.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-Bg6eJX4Z.js.map +0 -1
|
@@ -40,6 +40,7 @@ exports.listDistinctTypes = listDistinctTypes;
|
|
|
40
40
|
exports.getEscalationStats = getEscalationStats;
|
|
41
41
|
exports.getStationMetrics = getStationMetrics;
|
|
42
42
|
const escalationService = __importStar(require("../../services/escalation"));
|
|
43
|
+
const features_1 = require("../../modules/features");
|
|
43
44
|
const helpers_1 = require("./helpers");
|
|
44
45
|
/** True when the caller asked for anything the plain list path can't express. */
|
|
45
46
|
function hasFacetQuery(i) {
|
|
@@ -278,10 +279,16 @@ async function getStationMetrics(input, auth) {
|
|
|
278
279
|
try {
|
|
279
280
|
// Station metrics are aggregate queue-SHAPE counts (pending/claimed/resolved
|
|
280
281
|
// + jeopardy) per role — the depth of a lane, not the disclosure of any one
|
|
281
|
-
// item.
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
//
|
|
282
|
+
// item. With publicPaceBoard (the default) every authenticated caller sees
|
|
283
|
+
// every station: the board is trends, and per-item lists stay behind their
|
|
284
|
+
// own RBAC. With the flag off, the view narrows to role membership,
|
|
285
|
+
// including read_scope='self' roles (whose per-item lists stay narrowed
|
|
286
|
+
// elsewhere) — without the selfRoles union, a self-scoped operator would
|
|
287
|
+
// see an empty board on their own lanes.
|
|
288
|
+
if ((0, features_1.getFeatureFlags)().publicPaceBoard) {
|
|
289
|
+
const stations = await escalationService.getStationMetrics(undefined, input.period);
|
|
290
|
+
return { status: 200, data: { stations } };
|
|
291
|
+
}
|
|
285
292
|
const scope = await (0, helpers_1.getEscalationReadScope)(auth.userId);
|
|
286
293
|
const memberRoles = [...scope.allRoles, ...scope.selfRoles];
|
|
287
294
|
if (!scope.global && memberRoles.length === 0) {
|
package/build/api/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * as workflows from './workflows';
|
|
|
4
4
|
export * as yamlWorkflows from './yaml-workflows';
|
|
5
5
|
export * as users from './users';
|
|
6
6
|
export * as roles from './roles';
|
|
7
|
+
export * as personas from './personas';
|
|
7
8
|
export * as auth from './auth';
|
|
8
9
|
export * as mcp from './mcp';
|
|
9
10
|
export * as pipelines from './pipelines';
|
package/build/api/index.js
CHANGED
|
@@ -33,13 +33,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.maintenance = exports.namespaces = exports.dba = exports.workflowSets = exports.botAccounts = exports.controlplane = exports.exports = exports.settings = exports.insight = exports.mcpRuns = exports.pipelines = exports.mcp = exports.auth = exports.roles = exports.users = exports.yamlWorkflows = exports.workflows = exports.escalations = exports.tasks = void 0;
|
|
36
|
+
exports.maintenance = exports.namespaces = exports.dba = exports.workflowSets = exports.botAccounts = exports.controlplane = exports.exports = exports.settings = exports.insight = exports.mcpRuns = exports.pipelines = exports.mcp = exports.auth = exports.personas = exports.roles = exports.users = exports.yamlWorkflows = exports.workflows = exports.escalations = exports.tasks = void 0;
|
|
37
37
|
exports.tasks = __importStar(require("./tasks"));
|
|
38
38
|
exports.escalations = __importStar(require("./escalations"));
|
|
39
39
|
exports.workflows = __importStar(require("./workflows"));
|
|
40
40
|
exports.yamlWorkflows = __importStar(require("./yaml-workflows"));
|
|
41
41
|
exports.users = __importStar(require("./users"));
|
|
42
42
|
exports.roles = __importStar(require("./roles"));
|
|
43
|
+
exports.personas = __importStar(require("./personas"));
|
|
43
44
|
exports.auth = __importStar(require("./auth"));
|
|
44
45
|
exports.mcp = __importStar(require("./mcp"));
|
|
45
46
|
exports.pipelines = __importStar(require("./pipelines"));
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { LTApiResult } from '../types/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* List all personas with their role links and holder counts.
|
|
4
|
+
*
|
|
5
|
+
* @returns `{ status: 200, data: { personas: LTPersonaRecord[] } }` on success
|
|
6
|
+
*/
|
|
7
|
+
export declare function listPersonas(): Promise<LTApiResult>;
|
|
8
|
+
/**
|
|
9
|
+
* Retrieve a single persona by key, including its role links and assignees.
|
|
10
|
+
*
|
|
11
|
+
* @param input.key — the persona's stable key
|
|
12
|
+
* @returns `{ status: 200, data: LTPersonaRecord & { assignees } }` or 404
|
|
13
|
+
*/
|
|
14
|
+
export declare function getPersona(input: {
|
|
15
|
+
key: string;
|
|
16
|
+
}): Promise<LTApiResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Create a persona. The key is trimmed, lowercased, and validated against
|
|
19
|
+
* `^[a-z][a-z0-9_-]*$` (the role-name alphabet).
|
|
20
|
+
*
|
|
21
|
+
* @returns `{ status: 201, data: LTPersonaRecord }` on success, 409 on duplicate key
|
|
22
|
+
*/
|
|
23
|
+
export declare function createPersona(input: {
|
|
24
|
+
key: string;
|
|
25
|
+
title?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
}): Promise<LTApiResult>;
|
|
28
|
+
/**
|
|
29
|
+
* Update a persona's title/description with PATCH semantics — omitted fields
|
|
30
|
+
* keep their values; null clears.
|
|
31
|
+
*
|
|
32
|
+
* @returns `{ status: 200, data: LTPersonaRecord }` or 404
|
|
33
|
+
*/
|
|
34
|
+
export declare function updatePersona(input: {
|
|
35
|
+
key: string;
|
|
36
|
+
title?: string | null;
|
|
37
|
+
description?: string | null;
|
|
38
|
+
}): Promise<LTApiResult>;
|
|
39
|
+
/**
|
|
40
|
+
* Delete a persona. Memberships it sustains are removed (or re-homed to a
|
|
41
|
+
* sibling persona the user still holds); direct grants are never touched.
|
|
42
|
+
*
|
|
43
|
+
* @returns `{ status: 200, data: { deleted: true, recompute } }` or 404
|
|
44
|
+
*/
|
|
45
|
+
export declare function deletePersona(input: {
|
|
46
|
+
key: string;
|
|
47
|
+
}): Promise<LTApiResult>;
|
|
48
|
+
/**
|
|
49
|
+
* Link a role to a persona (or change the link's relationship). Every current
|
|
50
|
+
* holder's memberships are reconciled in the same transaction.
|
|
51
|
+
*
|
|
52
|
+
* @param input.relationship — write-all | write-self | read-all (write-none = read-all)
|
|
53
|
+
* @returns `{ status: 201, data: { role, relationship, recompute } }` or 404
|
|
54
|
+
*/
|
|
55
|
+
export declare function linkPersonaRole(input: {
|
|
56
|
+
key: string;
|
|
57
|
+
role: string;
|
|
58
|
+
relationship: string;
|
|
59
|
+
}): Promise<LTApiResult>;
|
|
60
|
+
/**
|
|
61
|
+
* Unlink a role from a persona and reconcile every holder's memberships.
|
|
62
|
+
*
|
|
63
|
+
* @returns `{ status: 200, data: { unlinked: true, recompute } }` or 404
|
|
64
|
+
*/
|
|
65
|
+
export declare function unlinkPersonaRole(input: {
|
|
66
|
+
key: string;
|
|
67
|
+
role: string;
|
|
68
|
+
}): Promise<LTApiResult>;
|
|
69
|
+
/**
|
|
70
|
+
* Assign a persona to a user — shorthand for adding the user to each linked
|
|
71
|
+
* role at the linked scope. Idempotent: re-assigning overlays fresh from the
|
|
72
|
+
* persona's current links. Direct grants are only ever raised, never lowered.
|
|
73
|
+
*
|
|
74
|
+
* @param input.id — the user's unique identifier
|
|
75
|
+
* @param input.key — the persona key
|
|
76
|
+
* @returns `{ status: 200, data: { assigned: true, recompute } }` or 404
|
|
77
|
+
*/
|
|
78
|
+
export declare function assignPersona(input: {
|
|
79
|
+
id: string;
|
|
80
|
+
key: string;
|
|
81
|
+
}): Promise<LTApiResult>;
|
|
82
|
+
/**
|
|
83
|
+
* Unassign a persona from a user. Removes only the memberships the persona
|
|
84
|
+
* sustains; memberships another held persona still grants are re-homed to it,
|
|
85
|
+
* and direct grants are never touched.
|
|
86
|
+
*
|
|
87
|
+
* @returns `{ status: 200, data: { unassigned: true, recompute } }` or 404
|
|
88
|
+
*/
|
|
89
|
+
export declare function unassignPersona(input: {
|
|
90
|
+
id: string;
|
|
91
|
+
key: string;
|
|
92
|
+
}): Promise<LTApiResult>;
|
|
93
|
+
/**
|
|
94
|
+
* The personas a user holds plus the composed role/scope map their memberships
|
|
95
|
+
* form (each row names the sustaining persona, or null for a direct grant).
|
|
96
|
+
*
|
|
97
|
+
* @returns `{ status: 200, data: { personas, roles } }` on success
|
|
98
|
+
*/
|
|
99
|
+
export declare function getUserPersonas(input: {
|
|
100
|
+
id: string;
|
|
101
|
+
}): Promise<LTApiResult>;
|
|
102
|
+
/**
|
|
103
|
+
* Declarative, idempotent persona seeding — the static-config twin of the API
|
|
104
|
+
* surface. Each spec is authoritative for its persona: title/description
|
|
105
|
+
* overlaid, role links synced (absent links pruned), linked roles ensured, and
|
|
106
|
+
* every holder reconciled so re-running the seed re-applies edits.
|
|
107
|
+
*
|
|
108
|
+
* @param input.personas — array of { key, title?, description?, roles: [{ role, relationship }] }
|
|
109
|
+
* @returns `{ status: 200, data: { personas, links, recompute } }` on success
|
|
110
|
+
*/
|
|
111
|
+
export declare function seedPersonas(input: {
|
|
112
|
+
personas: {
|
|
113
|
+
key: string;
|
|
114
|
+
title?: string;
|
|
115
|
+
description?: string;
|
|
116
|
+
roles?: {
|
|
117
|
+
role: string;
|
|
118
|
+
relationship: string;
|
|
119
|
+
}[];
|
|
120
|
+
}[];
|
|
121
|
+
}): Promise<LTApiResult>;
|
|
@@ -0,0 +1,341 @@
|
|
|
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.listPersonas = listPersonas;
|
|
37
|
+
exports.getPersona = getPersona;
|
|
38
|
+
exports.createPersona = createPersona;
|
|
39
|
+
exports.updatePersona = updatePersona;
|
|
40
|
+
exports.deletePersona = deletePersona;
|
|
41
|
+
exports.linkPersonaRole = linkPersonaRole;
|
|
42
|
+
exports.unlinkPersonaRole = unlinkPersonaRole;
|
|
43
|
+
exports.assignPersona = assignPersona;
|
|
44
|
+
exports.unassignPersona = unassignPersona;
|
|
45
|
+
exports.getUserPersonas = getUserPersonas;
|
|
46
|
+
exports.seedPersonas = seedPersonas;
|
|
47
|
+
const personaService = __importStar(require("../services/persona"));
|
|
48
|
+
/** Persona keys share the role-name alphabet: kebab/underscore, letter-first. */
|
|
49
|
+
const PERSONA_KEY = /^[a-z][a-z0-9_-]*$/;
|
|
50
|
+
function validateKey(key) {
|
|
51
|
+
if (typeof key !== 'string' || !key.trim())
|
|
52
|
+
return null;
|
|
53
|
+
const trimmed = key.trim().toLowerCase();
|
|
54
|
+
return PERSONA_KEY.test(trimmed) ? trimmed : null;
|
|
55
|
+
}
|
|
56
|
+
const RELATIONSHIP_ERROR = 'relationship must be write-all, write-self, or read-all (write-none is accepted as read-all)';
|
|
57
|
+
/**
|
|
58
|
+
* List all personas with their role links and holder counts.
|
|
59
|
+
*
|
|
60
|
+
* @returns `{ status: 200, data: { personas: LTPersonaRecord[] } }` on success
|
|
61
|
+
*/
|
|
62
|
+
async function listPersonas() {
|
|
63
|
+
try {
|
|
64
|
+
const personas = await personaService.listPersonas();
|
|
65
|
+
return { status: 200, data: { personas } };
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
return { status: 500, error: err.message };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Retrieve a single persona by key, including its role links and assignees.
|
|
73
|
+
*
|
|
74
|
+
* @param input.key — the persona's stable key
|
|
75
|
+
* @returns `{ status: 200, data: LTPersonaRecord & { assignees } }` or 404
|
|
76
|
+
*/
|
|
77
|
+
async function getPersona(input) {
|
|
78
|
+
try {
|
|
79
|
+
if (!input.key) {
|
|
80
|
+
return { status: 400, error: 'key is required' };
|
|
81
|
+
}
|
|
82
|
+
const persona = await personaService.getPersona(input.key);
|
|
83
|
+
if (!persona) {
|
|
84
|
+
return { status: 404, error: `Persona '${input.key}' not found` };
|
|
85
|
+
}
|
|
86
|
+
return { status: 200, data: persona };
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
return { status: 500, error: err.message };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Create a persona. The key is trimmed, lowercased, and validated against
|
|
94
|
+
* `^[a-z][a-z0-9_-]*$` (the role-name alphabet).
|
|
95
|
+
*
|
|
96
|
+
* @returns `{ status: 201, data: LTPersonaRecord }` on success, 409 on duplicate key
|
|
97
|
+
*/
|
|
98
|
+
async function createPersona(input) {
|
|
99
|
+
try {
|
|
100
|
+
const key = validateKey(input.key);
|
|
101
|
+
if (!key) {
|
|
102
|
+
return {
|
|
103
|
+
status: 400,
|
|
104
|
+
error: 'key must start with a letter and contain only lowercase letters, numbers, hyphens, and underscores',
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const persona = await personaService.createPersona({
|
|
108
|
+
key,
|
|
109
|
+
title: input.title,
|
|
110
|
+
description: input.description,
|
|
111
|
+
});
|
|
112
|
+
return { status: 201, data: persona };
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
if (err.code === '23505') {
|
|
116
|
+
return { status: 409, error: 'Persona with this key already exists' };
|
|
117
|
+
}
|
|
118
|
+
return { status: 500, error: err.message };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Update a persona's title/description with PATCH semantics — omitted fields
|
|
123
|
+
* keep their values; null clears.
|
|
124
|
+
*
|
|
125
|
+
* @returns `{ status: 200, data: LTPersonaRecord }` or 404
|
|
126
|
+
*/
|
|
127
|
+
async function updatePersona(input) {
|
|
128
|
+
try {
|
|
129
|
+
if (!input.key) {
|
|
130
|
+
return { status: 400, error: 'key is required' };
|
|
131
|
+
}
|
|
132
|
+
const persona = await personaService.updatePersona(input.key, {
|
|
133
|
+
title: input.title,
|
|
134
|
+
description: input.description,
|
|
135
|
+
});
|
|
136
|
+
if (!persona) {
|
|
137
|
+
return { status: 404, error: `Persona '${input.key}' not found` };
|
|
138
|
+
}
|
|
139
|
+
return { status: 200, data: persona };
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
return { status: 500, error: err.message };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Delete a persona. Memberships it sustains are removed (or re-homed to a
|
|
147
|
+
* sibling persona the user still holds); direct grants are never touched.
|
|
148
|
+
*
|
|
149
|
+
* @returns `{ status: 200, data: { deleted: true, recompute } }` or 404
|
|
150
|
+
*/
|
|
151
|
+
async function deletePersona(input) {
|
|
152
|
+
try {
|
|
153
|
+
if (!input.key) {
|
|
154
|
+
return { status: 400, error: 'key is required' };
|
|
155
|
+
}
|
|
156
|
+
const result = await personaService.deletePersona(input.key);
|
|
157
|
+
if (!result.deleted) {
|
|
158
|
+
return { status: 404, error: `Persona '${input.key}' not found` };
|
|
159
|
+
}
|
|
160
|
+
return { status: 200, data: { deleted: true, recompute: result.recompute } };
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
return { status: 500, error: err.message };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Link a role to a persona (or change the link's relationship). Every current
|
|
168
|
+
* holder's memberships are reconciled in the same transaction.
|
|
169
|
+
*
|
|
170
|
+
* @param input.relationship — write-all | write-self | read-all (write-none = read-all)
|
|
171
|
+
* @returns `{ status: 201, data: { role, relationship, recompute } }` or 404
|
|
172
|
+
*/
|
|
173
|
+
async function linkPersonaRole(input) {
|
|
174
|
+
try {
|
|
175
|
+
if (!input.key || !input.role) {
|
|
176
|
+
return { status: 400, error: 'key and role are required' };
|
|
177
|
+
}
|
|
178
|
+
const role = input.role.trim().toLowerCase();
|
|
179
|
+
if (!PERSONA_KEY.test(role)) {
|
|
180
|
+
return {
|
|
181
|
+
status: 400,
|
|
182
|
+
error: 'Role must start with a letter and contain only lowercase letters, numbers, hyphens, and underscores',
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
const relationship = personaService.normalizeRelationship(input.relationship ?? '');
|
|
186
|
+
if (!relationship) {
|
|
187
|
+
return { status: 400, error: RELATIONSHIP_ERROR };
|
|
188
|
+
}
|
|
189
|
+
const result = await personaService.linkPersonaRole(input.key, role, relationship);
|
|
190
|
+
if (!result) {
|
|
191
|
+
return { status: 404, error: `Persona '${input.key}' not found` };
|
|
192
|
+
}
|
|
193
|
+
return { status: 201, data: result };
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
return { status: 500, error: err.message };
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Unlink a role from a persona and reconcile every holder's memberships.
|
|
201
|
+
*
|
|
202
|
+
* @returns `{ status: 200, data: { unlinked: true, recompute } }` or 404
|
|
203
|
+
*/
|
|
204
|
+
async function unlinkPersonaRole(input) {
|
|
205
|
+
try {
|
|
206
|
+
if (!input.key || !input.role) {
|
|
207
|
+
return { status: 400, error: 'key and role are required' };
|
|
208
|
+
}
|
|
209
|
+
const result = await personaService.unlinkPersonaRole(input.key, input.role);
|
|
210
|
+
if (!result.personaFound) {
|
|
211
|
+
return { status: 404, error: `Persona '${input.key}' not found` };
|
|
212
|
+
}
|
|
213
|
+
if (!result.unlinked) {
|
|
214
|
+
return { status: 404, error: `Persona '${input.key}' does not link role '${input.role}'` };
|
|
215
|
+
}
|
|
216
|
+
return { status: 200, data: { unlinked: true, recompute: result.recompute } };
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
return { status: 500, error: err.message };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Assign a persona to a user — shorthand for adding the user to each linked
|
|
224
|
+
* role at the linked scope. Idempotent: re-assigning overlays fresh from the
|
|
225
|
+
* persona's current links. Direct grants are only ever raised, never lowered.
|
|
226
|
+
*
|
|
227
|
+
* @param input.id — the user's unique identifier
|
|
228
|
+
* @param input.key — the persona key
|
|
229
|
+
* @returns `{ status: 200, data: { assigned: true, recompute } }` or 404
|
|
230
|
+
*/
|
|
231
|
+
async function assignPersona(input) {
|
|
232
|
+
try {
|
|
233
|
+
if (!input.id || !input.key) {
|
|
234
|
+
return { status: 400, error: 'user id and persona key are required' };
|
|
235
|
+
}
|
|
236
|
+
const recompute = await personaService.assignPersona(input.id, input.key);
|
|
237
|
+
if (!recompute) {
|
|
238
|
+
return { status: 404, error: `Persona '${input.key}' not found` };
|
|
239
|
+
}
|
|
240
|
+
return { status: 200, data: { assigned: true, recompute } };
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
if (err.code === '23503') {
|
|
244
|
+
return { status: 404, error: 'User not found' };
|
|
245
|
+
}
|
|
246
|
+
if (err.code === '22P02') {
|
|
247
|
+
return { status: 400, error: 'user id must be a UUID' };
|
|
248
|
+
}
|
|
249
|
+
return { status: 500, error: err.message };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Unassign a persona from a user. Removes only the memberships the persona
|
|
254
|
+
* sustains; memberships another held persona still grants are re-homed to it,
|
|
255
|
+
* and direct grants are never touched.
|
|
256
|
+
*
|
|
257
|
+
* @returns `{ status: 200, data: { unassigned: true, recompute } }` or 404
|
|
258
|
+
*/
|
|
259
|
+
async function unassignPersona(input) {
|
|
260
|
+
try {
|
|
261
|
+
if (!input.id || !input.key) {
|
|
262
|
+
return { status: 400, error: 'user id and persona key are required' };
|
|
263
|
+
}
|
|
264
|
+
const result = await personaService.unassignPersona(input.id, input.key);
|
|
265
|
+
if (!result.personaFound) {
|
|
266
|
+
return { status: 404, error: `Persona '${input.key}' not found` };
|
|
267
|
+
}
|
|
268
|
+
if (!result.unassigned) {
|
|
269
|
+
return { status: 404, error: `User does not hold persona '${input.key}'` };
|
|
270
|
+
}
|
|
271
|
+
return { status: 200, data: { unassigned: true, recompute: result.recompute } };
|
|
272
|
+
}
|
|
273
|
+
catch (err) {
|
|
274
|
+
if (err.code === '22P02') {
|
|
275
|
+
return { status: 400, error: 'user id must be a UUID' };
|
|
276
|
+
}
|
|
277
|
+
return { status: 500, error: err.message };
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* The personas a user holds plus the composed role/scope map their memberships
|
|
282
|
+
* form (each row names the sustaining persona, or null for a direct grant).
|
|
283
|
+
*
|
|
284
|
+
* @returns `{ status: 200, data: { personas, roles } }` on success
|
|
285
|
+
*/
|
|
286
|
+
async function getUserPersonas(input) {
|
|
287
|
+
try {
|
|
288
|
+
if (!input.id) {
|
|
289
|
+
return { status: 400, error: 'user id is required' };
|
|
290
|
+
}
|
|
291
|
+
const result = await personaService.getUserPersonas(input.id);
|
|
292
|
+
return { status: 200, data: result };
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
if (err.code === '22P02') {
|
|
296
|
+
return { status: 400, error: 'user id must be a UUID' };
|
|
297
|
+
}
|
|
298
|
+
return { status: 500, error: err.message };
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Declarative, idempotent persona seeding — the static-config twin of the API
|
|
303
|
+
* surface. Each spec is authoritative for its persona: title/description
|
|
304
|
+
* overlaid, role links synced (absent links pruned), linked roles ensured, and
|
|
305
|
+
* every holder reconciled so re-running the seed re-applies edits.
|
|
306
|
+
*
|
|
307
|
+
* @param input.personas — array of { key, title?, description?, roles: [{ role, relationship }] }
|
|
308
|
+
* @returns `{ status: 200, data: { personas, links, recompute } }` on success
|
|
309
|
+
*/
|
|
310
|
+
async function seedPersonas(input) {
|
|
311
|
+
try {
|
|
312
|
+
if (!Array.isArray(input.personas)) {
|
|
313
|
+
return { status: 400, error: 'personas must be an array of persona specs' };
|
|
314
|
+
}
|
|
315
|
+
const specs = [];
|
|
316
|
+
for (const spec of input.personas) {
|
|
317
|
+
const key = validateKey(spec?.key);
|
|
318
|
+
if (!key) {
|
|
319
|
+
return { status: 400, error: `Invalid persona key: '${spec?.key}'` };
|
|
320
|
+
}
|
|
321
|
+
const roles = [];
|
|
322
|
+
for (const link of spec.roles ?? []) {
|
|
323
|
+
const role = validateKey(link?.role);
|
|
324
|
+
if (!role) {
|
|
325
|
+
return { status: 400, error: `Persona '${key}': invalid role '${link?.role}'` };
|
|
326
|
+
}
|
|
327
|
+
const relationship = personaService.normalizeRelationship(link?.relationship ?? '');
|
|
328
|
+
if (!relationship) {
|
|
329
|
+
return { status: 400, error: `Persona '${key}', role '${role}': ${RELATIONSHIP_ERROR}` };
|
|
330
|
+
}
|
|
331
|
+
roles.push({ role, relationship });
|
|
332
|
+
}
|
|
333
|
+
specs.push({ key, title: spec.title, description: spec.description, roles });
|
|
334
|
+
}
|
|
335
|
+
const result = await personaService.seedPersonas(specs);
|
|
336
|
+
return { status: 200, data: result };
|
|
337
|
+
}
|
|
338
|
+
catch (err) {
|
|
339
|
+
return { status: 500, error: err.message };
|
|
340
|
+
}
|
|
341
|
+
}
|
package/build/api/roles.d.ts
CHANGED
|
@@ -96,6 +96,8 @@ export declare function updateRole(input: {
|
|
|
96
96
|
}[] | null;
|
|
97
97
|
properties?: Record<string, any> | null;
|
|
98
98
|
ops_visible?: boolean;
|
|
99
|
+
/** Make this role's sequence the home Pace Board's default segment (single-holder: setting it clears the previous holder). */
|
|
100
|
+
ops_home_default?: boolean;
|
|
99
101
|
parent_role?: string | null;
|
|
100
102
|
sla_minutes?: number | null;
|
|
101
103
|
target_per_hour?: number | null;
|
package/build/api/roles.js
CHANGED
|
@@ -225,6 +225,9 @@ async function updateRole(input) {
|
|
|
225
225
|
if (input.ops_visible !== undefined && typeof input.ops_visible !== 'boolean') {
|
|
226
226
|
return { status: 400, error: 'ops_visible must be a boolean' };
|
|
227
227
|
}
|
|
228
|
+
if (input.ops_home_default !== undefined && typeof input.ops_home_default !== 'boolean') {
|
|
229
|
+
return { status: 400, error: 'ops_home_default must be a boolean' };
|
|
230
|
+
}
|
|
228
231
|
if (input.enforce_schema !== undefined && typeof input.enforce_schema !== 'boolean') {
|
|
229
232
|
return { status: 400, error: 'enforce_schema must be a boolean' };
|
|
230
233
|
}
|
|
@@ -262,6 +265,7 @@ async function updateRole(input) {
|
|
|
262
265
|
default_pins: input.default_pins,
|
|
263
266
|
properties: input.properties,
|
|
264
267
|
ops_visible: input.ops_visible,
|
|
268
|
+
ops_home_default: input.ops_home_default,
|
|
265
269
|
parent_role: input.parent_role,
|
|
266
270
|
sla_minutes: input.sla_minutes,
|
|
267
271
|
target_per_hour: input.target_per_hour,
|
package/build/bin/ltc.js
CHANGED
|
@@ -55,6 +55,7 @@ const kb = __importStar(require("../lib/cli/commands/knowledge"));
|
|
|
55
55
|
const mcp = __importStar(require("../lib/cli/commands/mcp"));
|
|
56
56
|
const usr = __importStar(require("../lib/cli/commands/users"));
|
|
57
57
|
const roles = __importStar(require("../lib/cli/commands/roles"));
|
|
58
|
+
const personas = __importStar(require("../lib/cli/commands/personas"));
|
|
58
59
|
const streams = __importStar(require("../lib/cli/commands/streams"));
|
|
59
60
|
const pkg = require('../package.json');
|
|
60
61
|
const envPath = path.resolve(process.cwd(), '.env');
|
|
@@ -309,6 +310,28 @@ rolesCmd.command('save-schema <role>')
|
|
|
309
310
|
.option('--summary <text>', 'Change summary recorded on the new version')
|
|
310
311
|
.option('--json', 'JSON output')
|
|
311
312
|
.action(wrap(roles.saveRoleSchema));
|
|
313
|
+
// ── Personas ─────────────────────────────────────────────────────────────
|
|
314
|
+
const personasCmd = commander_1.program.command('personas').description('Personas — named role bundles with per-role relationship scope');
|
|
315
|
+
personasCmd.command('list')
|
|
316
|
+
.option('--json', 'JSON output')
|
|
317
|
+
.option('-q, --quiet', 'Keys only')
|
|
318
|
+
.action(wrap(personas.listPersonas));
|
|
319
|
+
personasCmd.command('get <key>')
|
|
320
|
+
.description('Show a persona with its role links and assignees')
|
|
321
|
+
.option('--json', 'JSON output')
|
|
322
|
+
.action(wrap(personas.getPersona));
|
|
323
|
+
personasCmd.command('assign <key> <userId>')
|
|
324
|
+
.description('Assign a persona to a user (idempotent; re-assigning overlays fresh)')
|
|
325
|
+
.option('--json', 'JSON output')
|
|
326
|
+
.action(wrap(personas.assignPersona));
|
|
327
|
+
personasCmd.command('unassign <key> <userId>')
|
|
328
|
+
.description('Unassign a persona — removes only the memberships it sustains')
|
|
329
|
+
.option('--json', 'JSON output')
|
|
330
|
+
.action(wrap(personas.unassignPersona));
|
|
331
|
+
personasCmd.command('for-user <userId>')
|
|
332
|
+
.description('Show the personas a user holds and the composed role/scope map')
|
|
333
|
+
.option('--json', 'JSON output')
|
|
334
|
+
.action(wrap(personas.getUserPersonas));
|
|
312
335
|
// ── Streams ─────────────────────────────────────────────────────────────
|
|
313
336
|
const streamsCmd = commander_1.program.command('streams').description('Browse stream messages (admin)');
|
|
314
337
|
streamsCmd.command('list')
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare function listPersonas(opts: {
|
|
2
|
+
json?: boolean;
|
|
3
|
+
quiet?: boolean;
|
|
4
|
+
}): Promise<void>;
|
|
5
|
+
export declare function getPersona(key: string, opts: {
|
|
6
|
+
json?: boolean;
|
|
7
|
+
}): Promise<void>;
|
|
8
|
+
export declare function assignPersona(key: string, userId: string, opts: {
|
|
9
|
+
json?: boolean;
|
|
10
|
+
}): Promise<void>;
|
|
11
|
+
export declare function unassignPersona(key: string, userId: string, opts: {
|
|
12
|
+
json?: boolean;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
export declare function getUserPersonas(userId: string, opts: {
|
|
15
|
+
json?: boolean;
|
|
16
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listPersonas = listPersonas;
|
|
4
|
+
exports.getPersona = getPersona;
|
|
5
|
+
exports.assignPersona = assignPersona;
|
|
6
|
+
exports.unassignPersona = unassignPersona;
|
|
7
|
+
exports.getUserPersonas = getUserPersonas;
|
|
8
|
+
const client_1 = require("../client");
|
|
9
|
+
const format_1 = require("../format");
|
|
10
|
+
const COLUMNS = [
|
|
11
|
+
{ key: 'key', label: 'Key', width: 20 },
|
|
12
|
+
{ key: 'title', label: 'Title', width: 24 },
|
|
13
|
+
{
|
|
14
|
+
key: 'roles', label: 'Roles', width: 8,
|
|
15
|
+
format: (v) => String(Array.isArray(v) ? v.length : 0),
|
|
16
|
+
},
|
|
17
|
+
{ key: 'user_count', label: 'Users', width: 6, format: (v) => String(v ?? 0) },
|
|
18
|
+
{ key: 'description', label: 'Description', width: 40 },
|
|
19
|
+
];
|
|
20
|
+
async function listPersonas(opts) {
|
|
21
|
+
const data = await (0, client_1.apiFetch)('/personas');
|
|
22
|
+
(0, format_1.output)(data, data.personas || [], COLUMNS, opts, 'key');
|
|
23
|
+
}
|
|
24
|
+
async function getPersona(key, opts) {
|
|
25
|
+
const data = await (0, client_1.apiFetch)(`/personas/${encodeURIComponent(key)}`);
|
|
26
|
+
console.log(JSON.stringify(data, null, 2));
|
|
27
|
+
}
|
|
28
|
+
async function assignPersona(key, userId, opts) {
|
|
29
|
+
const data = await (0, client_1.apiFetch)(`/users/${encodeURIComponent(userId)}/personas`, {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
body: JSON.stringify({ persona: key }),
|
|
32
|
+
});
|
|
33
|
+
console.log(JSON.stringify(data, null, 2));
|
|
34
|
+
}
|
|
35
|
+
async function unassignPersona(key, userId, opts) {
|
|
36
|
+
const data = await (0, client_1.apiFetch)(`/users/${encodeURIComponent(userId)}/personas/${encodeURIComponent(key)}`, { method: 'DELETE' });
|
|
37
|
+
console.log(JSON.stringify(data, null, 2));
|
|
38
|
+
}
|
|
39
|
+
async function getUserPersonas(userId, opts) {
|
|
40
|
+
const data = await (0, client_1.apiFetch)(`/users/${encodeURIComponent(userId)}/personas`);
|
|
41
|
+
console.log(JSON.stringify(data, null, 2));
|
|
42
|
+
}
|