@hotmeshio/long-tail 0.7.1 → 0.7.3
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/create.js +30 -9
- package/build/api/roles.d.ts +32 -0
- package/build/api/roles.js +73 -0
- package/build/bin/ltc.js +23 -0
- package/build/lib/cli/commands/roles.d.ts +17 -0
- package/build/lib/cli/commands/roles.js +102 -0
- package/build/lib/db/schemas/017_role_schema_versions.sql +40 -0
- package/build/lib/db/schemas/018_role_upstreams.sql +21 -0
- package/build/routes/roles.js +20 -0
- package/build/scripts/ortho-populate.d.ts +80 -8
- package/build/scripts/ortho-populate.js +204 -52
- package/build/sdk/index.d.ts +2 -0
- package/build/sdk/index.js +2 -0
- package/build/services/orchestrator/condition.d.ts +25 -1
- package/build/services/orchestrator/condition.js +29 -1
- package/build/services/role/index.d.ts +15 -1
- package/build/services/role/index.js +45 -1
- package/build/services/role/sql.d.ts +23 -2
- package/build/services/role/sql.js +93 -16
- package/build/services/role/types.d.ts +41 -0
- package/build/system/mcp-servers/admin/index.js +3 -3
- package/build/system/mcp-servers/admin/schemas.d.ts +25 -2
- package/build/system/mcp-servers/admin/schemas.js +11 -2
- package/build/system/mcp-servers/admin/users.js +42 -0
- package/build/system/mcp-servers/human-queue-schemas.d.ts +6 -0
- package/build/system/mcp-servers/human-queue-schemas.js +4 -0
- package/build/system/mcp-servers/human-queue.js +10 -2
- package/build/system/seed/tool-manifests-admin.d.ts +371 -0
- package/build/system/seed/tool-manifests-admin.js +3 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/escalation.d.ts +16 -0
- package/build/types/escalation.js +17 -0
- package/dashboard/dist/assets/{AdminDashboard-Bg1HgukI.js → AdminDashboard-C9eE1VEp.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-Bg1HgukI.js.map → AdminDashboard-C9eE1VEp.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-HBe_YDU_.js → AgentConfigPage-Ba8QfXM2.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-HBe_YDU_.js.map → AgentConfigPage-Ba8QfXM2.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-BsaiYbwL.js → AgentDetailPage-DVmec0CP.js} +2 -2
- package/dashboard/dist/assets/{AgentDetailPage-BsaiYbwL.js.map → AgentDetailPage-DVmec0CP.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-DhN2lIBh.js → AgentsPage-DNiCYMh3.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-DhN2lIBh.js.map → AgentsPage-DNiCYMh3.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-_xcWvlIz.js → AvailableEscalationsPage-gDIF8ocC.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-_xcWvlIz.js.map → AvailableEscalationsPage-gDIF8ocC.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-DY6iUVC9.js → BotPicker-3wBcBavT.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-DY6iUVC9.js.map → BotPicker-3wBcBavT.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-w1owqsmN.js → CapabilitiesPage-WoPkND2y.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-w1owqsmN.js.map → CapabilitiesPage-WoPkND2y.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-DIMGjlJ-.js → CollapsibleSection-Cx99mqNN.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-DIMGjlJ-.js.map → CollapsibleSection-Cx99mqNN.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-D1OmMHux.js → CredentialsPage-DbNaoPbF.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-D1OmMHux.js.map → CredentialsPage-DbNaoPbF.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-CQy3DrUQ.js → CronLabel-DLW4_Zg4.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-CQy3DrUQ.js.map → CronLabel-DLW4_Zg4.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-BoBkl9tw.js → CustomDurationPicker-BRUFjkiu.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-BoBkl9tw.js.map → CustomDurationPicker-BRUFjkiu.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-QXbiuU0b.js → DropZone-DEX0BBqt.js} +2 -2
- package/dashboard/dist/assets/{DropZone-QXbiuU0b.js.map → DropZone-DEX0BBqt.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-Donjm9gT.js → ElapsedCell-BtmDQaym.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-Donjm9gT.js.map → ElapsedCell-BtmDQaym.js.map} +1 -1
- package/dashboard/dist/assets/EscalationSchemaPage-Bm4yBEGN.js +9 -0
- package/dashboard/dist/assets/EscalationSchemaPage-Bm4yBEGN.js.map +1 -0
- package/dashboard/dist/assets/{EscalationsOverview-CvHIJ_GG.js → EscalationsOverview-B3xZwTQA.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-CvHIJ_GG.js.map → EscalationsOverview-B3xZwTQA.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-DpAXMmT3.js → EventTable-Bh9FKXLI.js} +2 -2
- package/dashboard/dist/assets/{EventTable-DpAXMmT3.js.map → EventTable-Bh9FKXLI.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-De1XVx5d.js → GraphInvokePage-ov_ANlaE.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-De1XVx5d.js.map → GraphInvokePage-ov_ANlaE.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-BYR5VXXw.js → HomePage-D0DV6izb.js} +2 -2
- package/dashboard/dist/assets/{HomePage-BYR5VXXw.js.map → HomePage-D0DV6izb.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-Bx7jGzPA.js → ListToolbar-FpcvqNkN.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-Bx7jGzPA.js.map → ListToolbar-FpcvqNkN.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-DXRKcJN0.js → McpOverview-DcuRiAff.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-DXRKcJN0.js.map → McpOverview-DcuRiAff.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-CmW15w5e.js → McpQueryDetailPage-BcYl67KP.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-CmW15w5e.js.map → McpQueryDetailPage-BcYl67KP.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-BE6I011z.js → McpQueryPage-C3GDzqZM.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-BE6I011z.js.map → McpQueryPage-C3GDzqZM.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-Dsa3G3XQ.js → McpRunDetailPage-SzOyhDBW.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-Dsa3G3XQ.js.map → McpRunDetailPage-SzOyhDBW.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-uTbym66Y.js → McpRunsPage-BwgB6mRV.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-uTbym66Y.js.map → McpRunsPage-BwgB6mRV.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-BGf0jHwE.js → NamespacePill-CwKdoyRM.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-BGf0jHwE.js.map → NamespacePill-CwKdoyRM.js.map} +1 -1
- package/dashboard/dist/assets/OperationsPage-BCr21p8I.js +2 -0
- package/dashboard/dist/assets/OperationsPage-BCr21p8I.js.map +1 -0
- package/dashboard/dist/assets/{OperatorDashboard-i8cxaDlk.js → OperatorDashboard-DSXh-yYw.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-i8cxaDlk.js.map → OperatorDashboard-DSXh-yYw.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-BZJsEVOC.js → PageHeader-BhaWTWcM.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-BZJsEVOC.js.map → PageHeader-BhaWTWcM.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-BWuD7s9c.js → PageHeaderWithStats-yex5WmHB.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-BWuD7s9c.js.map → PageHeaderWithStats-yex5WmHB.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-CP7GZhgs.js → ProcessDetailPage-iIB1rwEt.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-CP7GZhgs.js.map → ProcessDetailPage-iIB1rwEt.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-btsU6hBR.js → ProcessesListPage-BrqWR2zr.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-btsU6hBR.js.map → ProcessesListPage-BrqWR2zr.js.map} +1 -1
- package/dashboard/dist/assets/RoleDetailPage-DS37tJhq.js +11 -0
- package/dashboard/dist/assets/RoleDetailPage-DS37tJhq.js.map +1 -0
- package/dashboard/dist/assets/{RolePill-Pb9TKSQN.js → RolePill-Cl71eDUA.js} +2 -2
- package/dashboard/dist/assets/{RolePill-Pb9TKSQN.js.map → RolePill-Cl71eDUA.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-1DBoEMsb.js → RolesPage-Bzp9FhAl.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-1DBoEMsb.js.map → RolesPage-Bzp9FhAl.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-Cp6j3FEY.js → RunAsSelector-DXbHRxQs.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-Cp6j3FEY.js.map → RunAsSelector-DXbHRxQs.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-Pr8kawv8.js → StickyPagination-D8XuMSWD.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-Pr8kawv8.js.map → StickyPagination-D8XuMSWD.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-BqmQ-N3y.js → StreamMessageDetail-D5v95pmz.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-BqmQ-N3y.js.map → StreamMessageDetail-D5v95pmz.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-y1YmXrsj.js → SwimlaneTimeline-CUEf2R5R.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-y1YmXrsj.js.map → SwimlaneTimeline-CUEf2R5R.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-Df4myuYF.js → TagInput-B_WQiuer.js} +2 -2
- package/dashboard/dist/assets/{TagInput-Df4myuYF.js.map → TagInput-B_WQiuer.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-CT5rXHK5.js → TaskDetailPage-BJvKNwEe.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-CT5rXHK5.js.map → TaskDetailPage-BJvKNwEe.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-YalYdCNo.js → TaskQueuePill-Lgn2obNU.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-YalYdCNo.js.map → TaskQueuePill-Lgn2obNU.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-DOy6JlKS.js → TasksListPage-CM7BWh_h.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-DOy6JlKS.js.map → TasksListPage-CM7BWh_h.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-BAQwZSpq.js → TimeAgo-D1K7xKq5.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-BAQwZSpq.js.map → TimeAgo-D1K7xKq5.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-BK_jufns.js → TimestampCell-7G0echgP.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-BK_jufns.js.map → TimestampCell-7G0echgP.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-VGpT6Quy.js → ToolPill-uVqcbHPE.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-VGpT6Quy.js.map → ToolPill-uVqcbHPE.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-5PMQyUCe.js → ToolTestPanel-LxuJvURK.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-5PMQyUCe.js.map → ToolTestPanel-LxuJvURK.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-Cn1ShfR8.js → TopicDetailPage-JvAX6rrR.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-Cn1ShfR8.js.map → TopicDetailPage-JvAX6rrR.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-D67tjS8L.js → TopicsPage-tFT2AcTz.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-D67tjS8L.js.map → TopicsPage-tFT2AcTz.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-Dsu1Jk4N.js → UserName-Djz0nmaZ.js} +2 -2
- package/dashboard/dist/assets/{UserName-Dsu1Jk4N.js.map → UserName-Djz0nmaZ.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-BwQoOmUE.js → WorkflowExecutionPage-f53hilbI.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-BwQoOmUE.js.map → WorkflowExecutionPage-f53hilbI.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-pPUqmx6Q.js → WorkflowPill-IDjTRfQ8.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-pPUqmx6Q.js.map → WorkflowPill-IDjTRfQ8.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-D3z7COgH.js → WorkflowsDashboard-DM9Xe665.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-D3z7COgH.js.map → WorkflowsDashboard-DM9Xe665.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-C15JcxyY.js → WorkflowsOverview-CUGSrx9N.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-C15JcxyY.js.map → WorkflowsOverview-CUGSrx9N.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-BYq3t7E-.js → YamlWorkflowDetailPage-B1_yqxAw.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-BYq3t7E-.js.map → YamlWorkflowDetailPage-B1_yqxAw.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-B44WgwE_.js → YamlWorkflowsPage-NtGvqiu7.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-B44WgwE_.js.map → YamlWorkflowsPage-NtGvqiu7.js.map} +1 -1
- package/dashboard/dist/assets/{agents-BRmmK6Y9.js → agents-tML6AjDj.js} +2 -2
- package/dashboard/dist/assets/{agents-BRmmK6Y9.js.map → agents-tML6AjDj.js.map} +1 -1
- package/dashboard/dist/assets/{bots-BD75mzGG.js → bots-Cb0WTwhY.js} +2 -2
- package/dashboard/dist/assets/{bots-BD75mzGG.js.map → bots-Cb0WTwhY.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-DDgC_Kds.js → capabilities-BGZogsi_.js} +2 -2
- package/dashboard/dist/assets/{capabilities-DDgC_Kds.js.map → capabilities-BGZogsi_.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-BJh12lMv.js → controlplane-B7VJTlZD.js} +2 -2
- package/dashboard/dist/assets/{controlplane-BJh12lMv.js.map → controlplane-B7VJTlZD.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-DIJt2sgn.js → escalation-Bl-SQV_u.js} +2 -2
- package/dashboard/dist/assets/{escalation-DIJt2sgn.js.map → escalation-Bl-SQV_u.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-zl6E94Up.js → escalation-columns-BlJOswRx.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-zl6E94Up.js.map → escalation-columns-BlJOswRx.js.map} +1 -1
- package/dashboard/dist/assets/{index-BhznDv-4.js → index--WeZDfeN.js} +2 -2
- package/dashboard/dist/assets/{index-BhznDv-4.js.map → index--WeZDfeN.js.map} +1 -1
- package/dashboard/dist/assets/{index-DU7YumVJ.js → index-0o71lRuY.js} +2 -2
- package/dashboard/dist/assets/{index-DU7YumVJ.js.map → index-0o71lRuY.js.map} +1 -1
- package/dashboard/dist/assets/{index-CV4lEd4I.js → index-3A_5CL81.js} +2 -2
- package/dashboard/dist/assets/{index-CV4lEd4I.js.map → index-3A_5CL81.js.map} +1 -1
- package/dashboard/dist/assets/{index-DVVIeBBk.js → index-BorpZbZA.js} +2 -2
- package/dashboard/dist/assets/{index-DVVIeBBk.js.map → index-BorpZbZA.js.map} +1 -1
- package/dashboard/dist/assets/{index-CknKy4RA.js → index-CBv3UxF2.js} +2 -2
- package/dashboard/dist/assets/{index-CknKy4RA.js.map → index-CBv3UxF2.js.map} +1 -1
- package/dashboard/dist/assets/{index-BUbzfEA9.js → index-D0-8byNu.js} +2 -2
- package/dashboard/dist/assets/{index-BUbzfEA9.js.map → index-D0-8byNu.js.map} +1 -1
- package/dashboard/dist/assets/{index-j-C7g_Ej.js → index-DcbEIXit.js} +2 -2
- package/dashboard/dist/assets/{index-j-C7g_Ej.js.map → index-DcbEIXit.js.map} +1 -1
- package/dashboard/dist/assets/{index-DrUkTcn-.js → index-DfDfJivY.js} +2 -2
- package/dashboard/dist/assets/{index-DrUkTcn-.js.map → index-DfDfJivY.js.map} +1 -1
- package/dashboard/dist/assets/{index-CtDf8vvQ.js → index-Dgw1KKpq.js} +9 -9
- package/dashboard/dist/assets/index-Dgw1KKpq.js.map +1 -0
- package/dashboard/dist/assets/index-Il_g7kw5.js +6 -0
- package/dashboard/dist/assets/{index-DccCwyZl.js.map → index-Il_g7kw5.js.map} +1 -1
- package/dashboard/dist/assets/{index-B0kmiSmt.js → index-SCrD3l-K.js} +2 -2
- package/dashboard/dist/assets/{index-B0kmiSmt.js.map → index-SCrD3l-K.js.map} +1 -1
- package/dashboard/dist/assets/{index-CDPBXB4e.js → index-TiKh2Ctj.js} +2 -2
- package/dashboard/dist/assets/{index-CDPBXB4e.js.map → index-TiKh2Ctj.js.map} +1 -1
- package/dashboard/dist/assets/index-Wny0bRgq.css +1 -0
- package/dashboard/dist/assets/{index-CpgV4Kkp.js → index-e97M6GoI.js} +2 -2
- package/dashboard/dist/assets/{index-CpgV4Kkp.js.map → index-e97M6GoI.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-pNDWACXB.js → knowledge-CDzw4E6q.js} +2 -2
- package/dashboard/dist/assets/{knowledge-pNDWACXB.js.map → knowledge-CDzw4E6q.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-xddLBwUW.js → mcp-D_-NQtnG.js} +2 -2
- package/dashboard/dist/assets/{mcp-xddLBwUW.js.map → mcp-D_-NQtnG.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-CmNjvxTG.js → mcp-query-BqZXdf9A.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-CmNjvxTG.js.map → mcp-query-BqZXdf9A.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-B05sd2nB.js → pipelines-CNLhgj8b.js} +2 -2
- package/dashboard/dist/assets/{pipelines-B05sd2nB.js.map → pipelines-CNLhgj8b.js.map} +1 -1
- package/dashboard/dist/assets/roles-CFD2eYap.js +2 -0
- package/dashboard/dist/assets/roles-CFD2eYap.js.map +1 -0
- package/dashboard/dist/assets/{tasks-Bm1OKrJA.js → tasks-DcSvF636.js} +2 -2
- package/dashboard/dist/assets/{tasks-Bm1OKrJA.js.map → tasks-DcSvF636.js.map} +1 -1
- package/dashboard/dist/assets/{topics-BVIqtmd4.js → topics-DI8TFSZv.js} +2 -2
- package/dashboard/dist/assets/{topics-BVIqtmd4.js.map → topics-DI8TFSZv.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-_qCzU74s.js → useEventHooks-DcIgMDh3.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-_qCzU74s.js.map → useEventHooks-DcIgMDh3.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-CDnCSFpG.js → useNamespace-C88ZxGoX.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-CDnCSFpG.js.map → useNamespace-C88ZxGoX.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-zrHMhaFM.js → useYamlActivityEvents-D2-yVjJ7.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-zrHMhaFM.js.map → useYamlActivityEvents-D2-yVjJ7.js.map} +1 -1
- package/dashboard/dist/assets/{users-BPBMZg27.js → users-C0WV36X8.js} +2 -2
- package/dashboard/dist/assets/{users-BPBMZg27.js.map → users-C0WV36X8.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-C1zVP_dv.js → vendor-icons-CEWCGPeJ.js} +76 -76
- package/dashboard/dist/assets/vendor-icons-CEWCGPeJ.js.map +1 -0
- package/dashboard/dist/assets/{workflows-CT6nTL1I.js → workflows-CkPv7xk-.js} +2 -2
- package/dashboard/dist/assets/{workflows-CT6nTL1I.js.map → workflows-CkPv7xk-.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-CdfjkOKU.js → yaml-workflows-BjrMQLTK.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-CdfjkOKU.js.map → yaml-workflows-BjrMQLTK.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/roles.md +62 -0
- package/docs/api/mcp/admin.md +32 -1
- package/docs/api/mcp/human-queue.md +2 -0
- package/docs/api/sdk/roles.md +39 -0
- package/docs/cli.md +13 -0
- package/docs/dashboard.md +66 -17
- package/docs/data.md +34 -0
- package/docs/hitl-guide.md +25 -3
- package/package.json +2 -2
- package/dashboard/dist/assets/OperationsPage-CAmiFHI6.js +0 -2
- package/dashboard/dist/assets/OperationsPage-CAmiFHI6.js.map +0 -1
- package/dashboard/dist/assets/RoleDetailPage-BB_e330f.js +0 -16
- package/dashboard/dist/assets/RoleDetailPage-BB_e330f.js.map +0 -1
- package/dashboard/dist/assets/index-BRtKQtQZ.css +0 -1
- package/dashboard/dist/assets/index-CtDf8vvQ.js.map +0 -1
- package/dashboard/dist/assets/index-DccCwyZl.js +0 -6
- package/dashboard/dist/assets/roles-bRgaMcdy.js +0 -2
- package/dashboard/dist/assets/roles-bRgaMcdy.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-C1zVP_dv.js.map +0 -1
|
@@ -40,22 +40,24 @@ exports.createEscalation = createEscalation;
|
|
|
40
40
|
const ajv_1 = __importDefault(require("ajv"));
|
|
41
41
|
const escalationService = __importStar(require("../../services/escalation"));
|
|
42
42
|
const roleService = __importStar(require("../../services/role"));
|
|
43
|
+
const escalation_1 = require("../../types/escalation");
|
|
43
44
|
const helpers_1 = require("./helpers");
|
|
44
45
|
// strict: false — role metadata_schemas use the project's house extension
|
|
45
46
|
// keywords (x-lt-widget etc., the same style as seeded form_schemas); Ajv 8's
|
|
46
47
|
// strict mode throws at compile on any unknown keyword, which would turn every
|
|
47
48
|
// metadata-bearing create for that role into a 500.
|
|
48
49
|
const ajv = new ajv_1.default({ allErrors: true, strict: false });
|
|
49
|
-
// Compiled validators cached per role, keyed by the schema's serialized
|
|
50
|
-
// so an admin's schema edit invalidates the stale validator on the next
|
|
50
|
+
// Compiled validators cached per role+version, keyed by the schema's serialized
|
|
51
|
+
// form so an admin's schema edit invalidates the stale validator on the next
|
|
52
|
+
// create. Pinned versions are immutable, but the same key logic covers both.
|
|
51
53
|
const validatorCache = new Map();
|
|
52
|
-
function compileRoleValidator(
|
|
54
|
+
function compileRoleValidator(cacheId, schema) {
|
|
53
55
|
const key = JSON.stringify(schema);
|
|
54
|
-
const cached = validatorCache.get(
|
|
56
|
+
const cached = validatorCache.get(cacheId);
|
|
55
57
|
if (cached && cached.key === key)
|
|
56
58
|
return cached.validate;
|
|
57
59
|
const validate = ajv.compile(schema);
|
|
58
|
-
validatorCache.set(
|
|
60
|
+
validatorCache.set(cacheId, { key, validate });
|
|
59
61
|
return validate;
|
|
60
62
|
}
|
|
61
63
|
// ── Create ────────────────────────────────────────────────────────────────
|
|
@@ -92,13 +94,29 @@ async function createEscalation(input, auth) {
|
|
|
92
94
|
if (denied) {
|
|
93
95
|
return { status: 403, error: `You must have write access to the "${role}" role or be a superadmin to create escalations for it` };
|
|
94
96
|
}
|
|
95
|
-
// Validate metadata against the role's declared schema (if any).
|
|
97
|
+
// Validate metadata against the role's declared schema (if any). A
|
|
98
|
+
// metadata.schema_version pin selects that immutable snapshot; a pin that
|
|
99
|
+
// names a missing version is a 400, never a silent fall-through to latest.
|
|
96
100
|
if (input.metadata) {
|
|
97
|
-
const
|
|
101
|
+
const pinned = input.metadata[escalation_1.ESCALATION_METADATA_KEYS.SCHEMA_VERSION];
|
|
102
|
+
if (pinned !== undefined && (!Number.isInteger(pinned) || pinned < 1)) {
|
|
103
|
+
return { status: 400, error: `metadata.${escalation_1.ESCALATION_METADATA_KEYS.SCHEMA_VERSION} must be a positive integer` };
|
|
104
|
+
}
|
|
105
|
+
let schema;
|
|
106
|
+
if (pinned !== undefined) {
|
|
107
|
+
const snapshot = await roleService.getRoleSchema(role, pinned);
|
|
108
|
+
if (!snapshot) {
|
|
109
|
+
return { status: 400, error: `Schema version ${pinned} does not exist for role "${role}"` };
|
|
110
|
+
}
|
|
111
|
+
schema = snapshot.metadata_schema;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
schema = await roleService.getRoleMetadataSchema(role);
|
|
115
|
+
}
|
|
98
116
|
if (schema) {
|
|
99
117
|
let validate;
|
|
100
118
|
try {
|
|
101
|
-
validate = compileRoleValidator(role
|
|
119
|
+
validate = compileRoleValidator(`${role}@${pinned ?? 'live'}`, schema);
|
|
102
120
|
}
|
|
103
121
|
catch (compileErr) {
|
|
104
122
|
// A broken stored schema is the role admin's bug, not the creator's —
|
|
@@ -108,7 +126,10 @@ async function createEscalation(input, auth) {
|
|
|
108
126
|
error: `metadata_schema for role "${role}" is not a valid JSON Schema: ${compileErr.message}`,
|
|
109
127
|
};
|
|
110
128
|
}
|
|
111
|
-
|
|
129
|
+
// The pin is a system key, not caller data — strip it so schemas with
|
|
130
|
+
// additionalProperties: false still validate the caller's bag.
|
|
131
|
+
const { [escalation_1.ESCALATION_METADATA_KEYS.SCHEMA_VERSION]: _pin, ...callerMetadata } = input.metadata;
|
|
132
|
+
const valid = validate(callerMetadata);
|
|
112
133
|
if (!valid) {
|
|
113
134
|
const msgs = (validate.errors ?? []).map((e) => `${e.instancePath || '(root)'} ${e.message}`).join('; ');
|
|
114
135
|
return { status: 400, error: `metadata does not match the role schema: ${msgs}` };
|
package/build/api/roles.d.ts
CHANGED
|
@@ -91,6 +91,38 @@ export declare function updateRole(input: {
|
|
|
91
91
|
sla_minutes?: number | null;
|
|
92
92
|
target_per_hour?: number | null;
|
|
93
93
|
worker_count?: number | null;
|
|
94
|
+
/** Replace the upstream-input set (omitted = preserve; null or [] = clear). */
|
|
95
|
+
upstream_roles?: string[] | null;
|
|
96
|
+
/** Recorded on the schema snapshot when this update changes a schema field. */
|
|
97
|
+
change_summary?: string;
|
|
98
|
+
}): Promise<LTApiResult>;
|
|
99
|
+
/**
|
|
100
|
+
* Fetch a role's schema pair (form_schema + metadata_schema).
|
|
101
|
+
*
|
|
102
|
+
* With `version`, returns that immutable snapshot from the version history —
|
|
103
|
+
* a missing version is a 404, never a silent fall-through to latest. Without
|
|
104
|
+
* `version`, returns the live (latest) schema along with the current version
|
|
105
|
+
* number so callers can tell what they got.
|
|
106
|
+
*
|
|
107
|
+
* @param input.role — the role whose schema to fetch
|
|
108
|
+
* @param input.version — optional version pin (positive integer)
|
|
109
|
+
* @returns `{ status: 200, data: RoleSchemaVersion }` on success
|
|
110
|
+
*/
|
|
111
|
+
export declare function getRoleSchema(input: {
|
|
112
|
+
role: string;
|
|
113
|
+
version?: number;
|
|
114
|
+
}): Promise<LTApiResult>;
|
|
115
|
+
/**
|
|
116
|
+
* List a role's schema version history, newest first. Each entry carries the
|
|
117
|
+
* version number, presence flags for the two schemas, the change summary, and
|
|
118
|
+
* whether it is the role's current version. Full snapshots come from
|
|
119
|
+
* `getRoleSchema({ role, version })`.
|
|
120
|
+
*
|
|
121
|
+
* @param input.role — the role whose history to list
|
|
122
|
+
* @returns `{ status: 200, data: { versions: RoleSchemaVersionSummary[] } }` on success
|
|
123
|
+
*/
|
|
124
|
+
export declare function listRoleSchemaVersions(input: {
|
|
125
|
+
role: string;
|
|
94
126
|
}): Promise<LTApiResult>;
|
|
95
127
|
/**
|
|
96
128
|
* Delete a role from the system. Requires admin privileges.
|
package/build/api/roles.js
CHANGED
|
@@ -42,6 +42,8 @@ exports.removeEscalationChain = removeEscalationChain;
|
|
|
42
42
|
exports.getEscalationTargets = getEscalationTargets;
|
|
43
43
|
exports.replaceEscalationTargets = replaceEscalationTargets;
|
|
44
44
|
exports.updateRole = updateRole;
|
|
45
|
+
exports.getRoleSchema = getRoleSchema;
|
|
46
|
+
exports.listRoleSchemaVersions = listRoleSchemaVersions;
|
|
45
47
|
exports.deleteRole = deleteRole;
|
|
46
48
|
const roleService = __importStar(require("../services/role"));
|
|
47
49
|
/**
|
|
@@ -220,6 +222,19 @@ async function updateRole(input) {
|
|
|
220
222
|
if (input.parent_role != null && input.parent_role === input.role) {
|
|
221
223
|
return { status: 400, error: 'parent_role must reference a different role' };
|
|
222
224
|
}
|
|
225
|
+
if (input.upstream_roles != null) {
|
|
226
|
+
if (!Array.isArray(input.upstream_roles) || input.upstream_roles.some((u) => typeof u !== 'string' || !u.trim())) {
|
|
227
|
+
return { status: 400, error: 'upstream_roles must be an array of role names' };
|
|
228
|
+
}
|
|
229
|
+
if (input.upstream_roles.includes(input.role)) {
|
|
230
|
+
return { status: 400, error: 'upstream_roles must not include the role itself' };
|
|
231
|
+
}
|
|
232
|
+
const known = new Set(await roleService.listDistinctRoles());
|
|
233
|
+
const unknown = input.upstream_roles.filter((u) => !known.has(u));
|
|
234
|
+
if (unknown.length > 0) {
|
|
235
|
+
return { status: 400, error: `upstream_roles reference unknown role(s): ${unknown.join(', ')}` };
|
|
236
|
+
}
|
|
237
|
+
}
|
|
223
238
|
const updated = await roleService.updateRoleMetadata(input.role, {
|
|
224
239
|
title: input.title,
|
|
225
240
|
description: input.description,
|
|
@@ -231,6 +246,8 @@ async function updateRole(input) {
|
|
|
231
246
|
sla_minutes: input.sla_minutes,
|
|
232
247
|
target_per_hour: input.target_per_hour,
|
|
233
248
|
worker_count: input.worker_count,
|
|
249
|
+
upstream_roles: input.upstream_roles,
|
|
250
|
+
change_summary: input.change_summary,
|
|
234
251
|
});
|
|
235
252
|
if (!updated) {
|
|
236
253
|
return { status: 404, error: `Role '${input.role}' not found` };
|
|
@@ -241,6 +258,62 @@ async function updateRole(input) {
|
|
|
241
258
|
return { status: 500, error: err.message };
|
|
242
259
|
}
|
|
243
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Fetch a role's schema pair (form_schema + metadata_schema).
|
|
263
|
+
*
|
|
264
|
+
* With `version`, returns that immutable snapshot from the version history —
|
|
265
|
+
* a missing version is a 404, never a silent fall-through to latest. Without
|
|
266
|
+
* `version`, returns the live (latest) schema along with the current version
|
|
267
|
+
* number so callers can tell what they got.
|
|
268
|
+
*
|
|
269
|
+
* @param input.role — the role whose schema to fetch
|
|
270
|
+
* @param input.version — optional version pin (positive integer)
|
|
271
|
+
* @returns `{ status: 200, data: RoleSchemaVersion }` on success
|
|
272
|
+
*/
|
|
273
|
+
async function getRoleSchema(input) {
|
|
274
|
+
try {
|
|
275
|
+
if (!input.role) {
|
|
276
|
+
return { status: 400, error: 'role is required' };
|
|
277
|
+
}
|
|
278
|
+
if (input.version !== undefined && (!Number.isInteger(input.version) || input.version < 1)) {
|
|
279
|
+
return { status: 400, error: 'version must be a positive integer' };
|
|
280
|
+
}
|
|
281
|
+
const schema = await roleService.getRoleSchema(input.role, input.version);
|
|
282
|
+
if (!schema) {
|
|
283
|
+
return {
|
|
284
|
+
status: 404,
|
|
285
|
+
error: input.version !== undefined
|
|
286
|
+
? `Schema version ${input.version} not found for role '${input.role}'`
|
|
287
|
+
: `Role '${input.role}' not found`,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
return { status: 200, data: schema };
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
return { status: 500, error: err.message };
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* List a role's schema version history, newest first. Each entry carries the
|
|
298
|
+
* version number, presence flags for the two schemas, the change summary, and
|
|
299
|
+
* whether it is the role's current version. Full snapshots come from
|
|
300
|
+
* `getRoleSchema({ role, version })`.
|
|
301
|
+
*
|
|
302
|
+
* @param input.role — the role whose history to list
|
|
303
|
+
* @returns `{ status: 200, data: { versions: RoleSchemaVersionSummary[] } }` on success
|
|
304
|
+
*/
|
|
305
|
+
async function listRoleSchemaVersions(input) {
|
|
306
|
+
try {
|
|
307
|
+
if (!input.role) {
|
|
308
|
+
return { status: 400, error: 'role is required' };
|
|
309
|
+
}
|
|
310
|
+
const versions = await roleService.listRoleSchemaVersions(input.role);
|
|
311
|
+
return { status: 200, data: { versions } };
|
|
312
|
+
}
|
|
313
|
+
catch (err) {
|
|
314
|
+
return { status: 500, error: err.message };
|
|
315
|
+
}
|
|
316
|
+
}
|
|
244
317
|
/**
|
|
245
318
|
* Delete a role from the system. Requires admin privileges.
|
|
246
319
|
*
|
package/build/bin/ltc.js
CHANGED
|
@@ -54,6 +54,7 @@ const pip = __importStar(require("../lib/cli/commands/pipelines"));
|
|
|
54
54
|
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
|
+
const roles = __importStar(require("../lib/cli/commands/roles"));
|
|
57
58
|
const streams = __importStar(require("../lib/cli/commands/streams"));
|
|
58
59
|
const pkg = require('../package.json');
|
|
59
60
|
const envPath = path.resolve(process.cwd(), '.env');
|
|
@@ -277,6 +278,28 @@ usrCmd.command('list')
|
|
|
277
278
|
usrCmd.command('get <id>')
|
|
278
279
|
.option('--json', 'JSON output')
|
|
279
280
|
.action(wrap(usr.getUser));
|
|
281
|
+
// ── Roles ────────────────────────────────────────────────────────────────
|
|
282
|
+
const rolesCmd = commander_1.program.command('roles').description('Roles — the queue-backed work surfaces where workflows hand off to people');
|
|
283
|
+
rolesCmd.command('list')
|
|
284
|
+
.option('--json', 'JSON output')
|
|
285
|
+
.option('-q, --quiet', 'Names only')
|
|
286
|
+
.action(wrap(roles.listRoles));
|
|
287
|
+
rolesCmd.command('schema <role>')
|
|
288
|
+
.description('Show a role\'s form/metadata schema (latest, or a pinned version)')
|
|
289
|
+
.option('--version <n>', 'Read an immutable snapshot from the version history')
|
|
290
|
+
.option('--json', 'JSON output')
|
|
291
|
+
.action(wrap(roles.getRoleSchema));
|
|
292
|
+
rolesCmd.command('schema-versions <role>')
|
|
293
|
+
.description('List a role\'s schema version history (newest first)')
|
|
294
|
+
.option('--json', 'JSON output')
|
|
295
|
+
.option('-q, --quiet', 'Versions only')
|
|
296
|
+
.action(wrap(roles.listRoleSchemaVersions));
|
|
297
|
+
rolesCmd.command('save-schema <role>')
|
|
298
|
+
.description('Save the role\'s escalation form schema (a change creates the next version)')
|
|
299
|
+
.option('--file <path>', 'JSON Schema file (reads stdin when omitted)')
|
|
300
|
+
.option('--summary <text>', 'Change summary recorded on the new version')
|
|
301
|
+
.option('--json', 'JSON output')
|
|
302
|
+
.action(wrap(roles.saveRoleSchema));
|
|
280
303
|
// ── Streams ─────────────────────────────────────────────────────────────
|
|
281
304
|
const streamsCmd = commander_1.program.command('streams').description('Browse stream messages (admin)');
|
|
282
305
|
streamsCmd.command('list')
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare function listRoles(opts: {
|
|
2
|
+
json?: boolean;
|
|
3
|
+
quiet?: boolean;
|
|
4
|
+
}): Promise<void>;
|
|
5
|
+
export declare function getRoleSchema(role: string, opts: {
|
|
6
|
+
version?: string;
|
|
7
|
+
json?: boolean;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
export declare function listRoleSchemaVersions(role: string, opts: {
|
|
10
|
+
json?: boolean;
|
|
11
|
+
quiet?: boolean;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
export declare function saveRoleSchema(role: string, opts: {
|
|
14
|
+
file?: string;
|
|
15
|
+
summary?: string;
|
|
16
|
+
json?: boolean;
|
|
17
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,102 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.listRoles = listRoles;
|
|
40
|
+
exports.getRoleSchema = getRoleSchema;
|
|
41
|
+
exports.listRoleSchemaVersions = listRoleSchemaVersions;
|
|
42
|
+
exports.saveRoleSchema = saveRoleSchema;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
45
|
+
const client_1 = require("../client");
|
|
46
|
+
const format_1 = require("../format");
|
|
47
|
+
const ROLE_COLUMNS = [
|
|
48
|
+
{ key: 'role', label: 'Role', width: 20 },
|
|
49
|
+
{ key: 'title', label: 'Title', width: 24 },
|
|
50
|
+
{ key: 'current_schema_version', label: 'Schema v', width: 8, align: 'right' },
|
|
51
|
+
{ key: 'user_count', label: 'Users', width: 6, align: 'right' },
|
|
52
|
+
{ key: 'workflow_count', label: 'Workflows', width: 9, align: 'right' },
|
|
53
|
+
];
|
|
54
|
+
const VERSION_COLUMNS = [
|
|
55
|
+
{ key: 'version', label: 'Version', width: 8, align: 'right' },
|
|
56
|
+
{ key: 'is_current', label: 'Current', width: 8, format: (v) => (v ? '●' : '') },
|
|
57
|
+
{ key: 'change_summary', label: 'Summary', width: 40 },
|
|
58
|
+
{ key: 'created_at', label: 'Created', width: 12, format: format_1.formatTime },
|
|
59
|
+
];
|
|
60
|
+
async function listRoles(opts) {
|
|
61
|
+
const data = await (0, client_1.apiFetch)('/roles/details');
|
|
62
|
+
(0, format_1.output)(data, data.roles || [], ROLE_COLUMNS, opts, 'role');
|
|
63
|
+
}
|
|
64
|
+
async function getRoleSchema(role, opts) {
|
|
65
|
+
const params = new URLSearchParams();
|
|
66
|
+
if (opts.version)
|
|
67
|
+
params.set('version', opts.version);
|
|
68
|
+
const qs = params.toString();
|
|
69
|
+
const data = await (0, client_1.apiFetch)(`/roles/${encodeURIComponent(role)}/schema${qs ? `?${qs}` : ''}`);
|
|
70
|
+
if (opts.json) {
|
|
71
|
+
console.log(JSON.stringify(data, null, 2));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const versionLabel = data.version != null ? `v${data.version}` : 'unversioned';
|
|
75
|
+
const pinNote = opts.version ? ' (pinned)' : ` (latest: v${data.latest_version ?? '—'})`;
|
|
76
|
+
console.log(`\n ${picocolors_1.default.bold(role)} schema ${versionLabel}${pinNote}`);
|
|
77
|
+
if (data.change_summary)
|
|
78
|
+
console.log(` ${data.change_summary}`);
|
|
79
|
+
console.log(`\n ${picocolors_1.default.bold('form_schema')}\n${JSON.stringify(data.form_schema, null, 2)}`);
|
|
80
|
+
console.log(`\n ${picocolors_1.default.bold('metadata_schema')}\n${JSON.stringify(data.metadata_schema, null, 2)}`);
|
|
81
|
+
console.log();
|
|
82
|
+
}
|
|
83
|
+
async function listRoleSchemaVersions(role, opts) {
|
|
84
|
+
const data = await (0, client_1.apiFetch)(`/roles/${encodeURIComponent(role)}/schema/versions`);
|
|
85
|
+
(0, format_1.output)(data, data.versions || [], VERSION_COLUMNS, opts, 'version');
|
|
86
|
+
}
|
|
87
|
+
async function saveRoleSchema(role, opts) {
|
|
88
|
+
// One PATCH carrying only the schema (and its summary) — a schema change
|
|
89
|
+
// appends the next immutable version; an identical save leaves it alone.
|
|
90
|
+
const raw = opts.file ? fs.readFileSync(opts.file, 'utf8') : fs.readFileSync(0, 'utf8');
|
|
91
|
+
const schema = JSON.parse(raw);
|
|
92
|
+
const data = await (0, client_1.apiFetch)(`/roles/${encodeURIComponent(role)}`, {
|
|
93
|
+
method: 'PATCH',
|
|
94
|
+
body: JSON.stringify({ form_schema: schema, change_summary: opts.summary }),
|
|
95
|
+
});
|
|
96
|
+
if (opts.json) {
|
|
97
|
+
console.log(JSON.stringify(data, null, 2));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const version = data.current_schema_version != null ? ` — v${data.current_schema_version} in use` : '';
|
|
101
|
+
console.log(`\n ${picocolors_1.default.green('✓')} Saved ${role} escalation schema${version}\n`);
|
|
102
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
-- Migration 017: Versioned role schemas
|
|
2
|
+
--
|
|
3
|
+
-- lt_role_schemas holds an immutable snapshot of a role's form_schema and
|
|
4
|
+
-- metadata_schema per version. lt_roles.form_schema / metadata_schema remain
|
|
5
|
+
-- the live "latest" copy (single-query reads stay cheap); every schema edit
|
|
6
|
+
-- also appends the next (role, version) snapshot and advances
|
|
7
|
+
-- lt_roles.current_schema_version — see UPDATE_ROLE_METADATA in
|
|
8
|
+
-- services/role/sql.ts, which does both in one atomic statement.
|
|
9
|
+
--
|
|
10
|
+
-- Why: an escalation can pin the exact schema it was created against
|
|
11
|
+
-- (metadata.schema_version, set via conditionLT's schemaVersion config field).
|
|
12
|
+
-- The resolver UI then renders the pinned version even after the role's
|
|
13
|
+
-- schema moves on. Escalations without a pin always use the latest.
|
|
14
|
+
|
|
15
|
+
CREATE TABLE IF NOT EXISTS lt_role_schemas (
|
|
16
|
+
role TEXT NOT NULL REFERENCES lt_roles(role) ON DELETE CASCADE,
|
|
17
|
+
version INTEGER NOT NULL,
|
|
18
|
+
form_schema JSONB,
|
|
19
|
+
metadata_schema JSONB,
|
|
20
|
+
change_summary TEXT,
|
|
21
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
22
|
+
PRIMARY KEY (role, version)
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
ALTER TABLE lt_roles
|
|
26
|
+
ADD COLUMN IF NOT EXISTS current_schema_version INTEGER;
|
|
27
|
+
|
|
28
|
+
-- Seed version 1 from the live columns for roles that already carry a schema.
|
|
29
|
+
-- ON CONFLICT keeps re-runs (and multi-container boot races behind the
|
|
30
|
+
-- advisory lock) no-ops.
|
|
31
|
+
INSERT INTO lt_role_schemas (role, version, form_schema, metadata_schema, change_summary)
|
|
32
|
+
SELECT role, 1, form_schema, metadata_schema, 'Initial version (seeded from lt_roles)'
|
|
33
|
+
FROM lt_roles
|
|
34
|
+
WHERE form_schema IS NOT NULL OR metadata_schema IS NOT NULL
|
|
35
|
+
ON CONFLICT (role, version) DO NOTHING;
|
|
36
|
+
|
|
37
|
+
UPDATE lt_roles
|
|
38
|
+
SET current_schema_version = 1
|
|
39
|
+
WHERE current_schema_version IS NULL
|
|
40
|
+
AND (form_schema IS NOT NULL OR metadata_schema IS NOT NULL);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- Migration 018: Role upstream inputs
|
|
2
|
+
--
|
|
3
|
+
-- Execution is a graph; the Operations page tells its story as sequences.
|
|
4
|
+
-- lt_roles.parent_role stays the sequence membership — the single "prior
|
|
5
|
+
-- step" that places a station in one line. lt_role_upstreams carries the
|
|
6
|
+
-- other edges: the roles a station draws input from that live in OTHER
|
|
7
|
+
-- sequences (mixin-like, many allowed). The Operations chart renders these
|
|
8
|
+
-- as a merge affordance on the station rather than bending the line —
|
|
9
|
+
-- the table stays true to the queue, the SVG stays honest about the graph.
|
|
10
|
+
--
|
|
11
|
+
-- Example: a shoe side-quest (ordering → inserting) feeds shipping. ordering
|
|
12
|
+
-- roots its own sequence; shipping declares inserting as an upstream input
|
|
13
|
+
-- instead of pretending ordering descends from qa.
|
|
14
|
+
|
|
15
|
+
CREATE TABLE IF NOT EXISTS lt_role_upstreams (
|
|
16
|
+
role TEXT NOT NULL REFERENCES lt_roles(role) ON DELETE CASCADE,
|
|
17
|
+
upstream_role TEXT NOT NULL REFERENCES lt_roles(role) ON DELETE CASCADE,
|
|
18
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
19
|
+
PRIMARY KEY (role, upstream_role),
|
|
20
|
+
CHECK (role <> upstream_role)
|
|
21
|
+
);
|
package/build/routes/roles.js
CHANGED
|
@@ -103,6 +103,26 @@ router.patch('/:role', auth_1.requireRoleManager, async (req, res) => {
|
|
|
103
103
|
const result = await api.updateRole({ ...req.body, role: req.params.role });
|
|
104
104
|
res.status(result.status).json(result.data ?? { error: result.error });
|
|
105
105
|
});
|
|
106
|
+
/**
|
|
107
|
+
* GET /api/roles/:role/schema
|
|
108
|
+
* Fetch the role's schema pair. `?version=N` pins an immutable snapshot from
|
|
109
|
+
* the version history; omitted, the live (latest) schema is returned with its
|
|
110
|
+
* current version number.
|
|
111
|
+
*/
|
|
112
|
+
router.get('/:role/schema', async (req, res) => {
|
|
113
|
+
const versionParam = req.query.version;
|
|
114
|
+
const version = versionParam !== undefined ? Number(versionParam) : undefined;
|
|
115
|
+
const result = await api.getRoleSchema({ role: req.params.role, version });
|
|
116
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
117
|
+
});
|
|
118
|
+
/**
|
|
119
|
+
* GET /api/roles/:role/schema/versions
|
|
120
|
+
* List the role's schema version history (newest first).
|
|
121
|
+
*/
|
|
122
|
+
router.get('/:role/schema/versions', async (req, res) => {
|
|
123
|
+
const result = await api.listRoleSchemaVersions({ role: req.params.role });
|
|
124
|
+
res.status(result.status).json(result.data ?? { error: result.error });
|
|
125
|
+
});
|
|
106
126
|
/**
|
|
107
127
|
* GET /api/roles/:role/escalation-targets
|
|
108
128
|
* Get allowed escalation targets for a specific role.
|
|
@@ -2,26 +2,73 @@
|
|
|
2
2
|
* ortho-populate — Populate the Operations dashboard with ortho pipeline history.
|
|
3
3
|
*
|
|
4
4
|
* Adapted from the boilerplate's 08-day-resolver.ts pattern:
|
|
5
|
-
* - concurrent claim loop + resolve loop + watchdog via Promise.all
|
|
5
|
+
* - concurrent enqueue + claim loop + resolve loop + watchdog via Promise.all
|
|
6
6
|
* - hold time read from esc.claimed_at (API), not tracked in memory
|
|
7
7
|
* - simple resolve payload { approved: true, station: role }
|
|
8
8
|
*
|
|
9
9
|
* Usage:
|
|
10
10
|
* npx ts-node scripts/ortho-populate.ts
|
|
11
11
|
* ORDERS=50 HOLD_S=3 npx ts-node scripts/ortho-populate.ts
|
|
12
|
-
* ORDERS=
|
|
12
|
+
* ORDERS=10 HOLD_S=25 npx ts-node scripts/ortho-populate.ts
|
|
13
|
+
* ORDERS=5 HOLD_S=0 QUEUE_S=0 SHOES_PCT=0 POLL_MS=500 npx ts-node scripts/ortho-populate.ts
|
|
13
14
|
*
|
|
14
15
|
* Env vars:
|
|
15
|
-
* ORDERS
|
|
16
|
-
* HOLD_S
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* ORDERS — number of orders to run (default 20)
|
|
17
|
+
* HOLD_S — average seconds to hold each claimed escalation before
|
|
18
|
+
* resolving (default 2)
|
|
19
|
+
* QUEUE_S — average seconds an escalation waits in the queue before being
|
|
20
|
+
* claimed (default: HOLD_S). This is what builds a visible
|
|
21
|
+
* backlog: on the Operations chart, queued-but-unclaimed and
|
|
22
|
+
* claimed-and-worked are two different bands — with QUEUE_S=0
|
|
23
|
+
* everything is claimed the moment it lands and pending always
|
|
24
|
+
* equals active.
|
|
25
|
+
* SHOES_PCT — percent of orders that include shoes (default 50). A shoe
|
|
26
|
+
* order runs the side-quest sequence (ordering → inserting)
|
|
27
|
+
* alongside its manufacturing line — see below.
|
|
28
|
+
* ARRIVAL_S — average seconds between order arrivals (default: HOLD_S).
|
|
29
|
+
* Orders trickle in at this rate instead of landing as one
|
|
30
|
+
* wave, so the chart shows throughput, not a step function.
|
|
31
|
+
* POLL_MS — poll interval ms (default 1000)
|
|
32
|
+
* BASE_URL — server URL (default http://localhost:3000)
|
|
33
|
+
*
|
|
34
|
+
* All durations are per-item averages, not fixed delays: each escalation gets
|
|
35
|
+
* its own wait and hold spread across 0.4×–1.6× of the configured value (a
|
|
36
|
+
* stable hash of its id — no state to track between polls). That staggering is
|
|
37
|
+
* what makes the Operations chart read like a real floor: at any moment a
|
|
38
|
+
* station holds a mix of waiting and active items, claims burn the backlog
|
|
39
|
+
* down gradually, and resolves feed the next station a trickle instead of a
|
|
40
|
+
* wave.
|
|
41
|
+
*
|
|
42
|
+
* ── The shoe side-quest ──────────────────────────────────────────────────────
|
|
43
|
+
* A shoe order exercises the cross-sequence model (ordering → inserting feeds
|
|
44
|
+
* ship via upstream_roles — its own Operations sequence, not a bend in the
|
|
45
|
+
* main line). Timing tells the physical story, scaled to the manufacturing
|
|
46
|
+
* duration (MFG ≈ 8 stages × (QUEUE_S + HOLD_S)):
|
|
47
|
+
*
|
|
48
|
+
* arrival ordering escalation created with the order
|
|
49
|
+
* + ~½·QUEUE claimed quickly — the shoes are on order, work is underway
|
|
50
|
+
* + ~35% MFG shoes arrive → ordering resolves → inserting created
|
|
51
|
+
* + ~35% MFG inserting sits AVAILABLE (you cannot stuff inserts until the
|
|
52
|
+
* insole is made) — a long sky band on its station
|
|
53
|
+
* + HOLD claimed and resolved just ahead of shipping
|
|
54
|
+
*
|
|
55
|
+
* The script provisions the side-quest roles idempotently on start (ordering,
|
|
56
|
+
* inserting under it, ship fed by inserting).
|
|
19
57
|
*/
|
|
20
58
|
declare const BASE_URL: string;
|
|
21
59
|
declare const ORDERS: number;
|
|
22
60
|
declare const HOLD_S: number;
|
|
61
|
+
declare const QUEUE_S: number;
|
|
62
|
+
declare const SHOES_PCT: number;
|
|
63
|
+
declare const ARRIVAL_S: number;
|
|
23
64
|
declare const POLL_MS: number;
|
|
24
65
|
declare const ORTHO_ROLES: string[];
|
|
66
|
+
declare const SIDE_ROLES: string[];
|
|
67
|
+
declare const ALL_ROLES: string[];
|
|
68
|
+
declare const MFG_S: number;
|
|
69
|
+
declare const TRANSIT_S: number;
|
|
70
|
+
declare const INSERT_QUEUE_S: number;
|
|
71
|
+
declare const ORDERING_QUEUE_S: number;
|
|
25
72
|
declare let token: string;
|
|
26
73
|
declare let userId: string;
|
|
27
74
|
declare let totalClaimed: number;
|
|
@@ -29,9 +76,34 @@ declare let totalResolved: number;
|
|
|
29
76
|
declare function ts(): string;
|
|
30
77
|
declare function sleep(ms: number): Promise<unknown>;
|
|
31
78
|
declare function ageSeconds(iso: string): number;
|
|
79
|
+
declare function jitter(id: string, salt: string): number;
|
|
80
|
+
/** Spread a base duration across 0.4×–1.6× so a stage's items trickle instead of toggling together. */
|
|
81
|
+
declare function spread(base: number, r: number): number;
|
|
82
|
+
/** Evenly distribute SHOES_PCT across the order sequence (deterministic). */
|
|
83
|
+
declare function hasShoes(i: number): boolean;
|
|
84
|
+
/** Queue wait before this escalation may be claimed. */
|
|
85
|
+
declare function claimWaitFor(esc: {
|
|
86
|
+
id: string;
|
|
87
|
+
role: string;
|
|
88
|
+
}): number;
|
|
89
|
+
/** Hold time after claim before this escalation may be resolved. */
|
|
90
|
+
declare function holdFor(esc: {
|
|
91
|
+
id: string;
|
|
92
|
+
role: string;
|
|
93
|
+
}): number;
|
|
32
94
|
declare function api(method: string, path: string, body?: unknown): Promise<any>;
|
|
33
95
|
declare function login(): Promise<void>;
|
|
96
|
+
declare function ensureSideQuestRoles(): Promise<void>;
|
|
97
|
+
declare function createSideEscalation(role: string, workflowId: string, orderId: string, runId: string, description: string): Promise<boolean>;
|
|
34
98
|
declare function claimBatch(batchTag: string): Promise<number>;
|
|
35
|
-
declare function resolveBatch(batchTag: string): Promise<number>;
|
|
36
|
-
|
|
99
|
+
declare function resolveBatch(batchTag: string, runId: string): Promise<number>;
|
|
100
|
+
interface PlannedOrder {
|
|
101
|
+
index: number;
|
|
102
|
+
wfId: string;
|
|
103
|
+
orderId: string;
|
|
104
|
+
shoes: boolean;
|
|
105
|
+
}
|
|
106
|
+
declare function runOrders(batchTag: string, runId: string, plan: PlannedOrder[], target: {
|
|
107
|
+
value: number;
|
|
108
|
+
}): Promise<string[]>;
|
|
37
109
|
declare function main(): Promise<void>;
|