@hotmeshio/long-tail 0.10.14 → 0.11.1
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/analytics.d.ts +6 -0
- package/build/api/escalations/analytics.js +123 -0
- package/build/api/escalations/index.d.ts +1 -0
- package/build/api/escalations/index.js +4 -1
- package/build/api/roles.d.ts +4 -0
- package/build/api/roles.js +8 -0
- package/build/api/scan-codes/choice.d.ts +11 -0
- package/build/api/scan-codes/choice.js +136 -0
- package/build/api/scan-codes/context.d.ts +24 -0
- package/build/api/scan-codes/context.js +86 -0
- package/build/api/scan-codes/execute.d.ts +1 -0
- package/build/api/scan-codes/execute.js +49 -244
- package/build/api/scan-codes/identity.d.ts +18 -0
- package/build/api/scan-codes/identity.js +116 -0
- package/build/api/scan-codes/index.d.ts +2 -0
- package/build/api/scan-codes/index.js +6 -1
- package/build/api/scan-codes/locate.d.ts +14 -0
- package/build/api/scan-codes/locate.js +127 -0
- package/build/api/scan-codes/present.d.ts +9 -0
- package/build/api/scan-codes/present.js +59 -0
- package/build/api/scan-codes/verbs.d.ts +15 -0
- package/build/api/scan-codes/verbs.js +205 -0
- package/build/bin/ltc.js +33 -0
- package/build/lib/cli/commands/escalations.d.ts +31 -0
- package/build/lib/cli/commands/escalations.js +88 -0
- package/build/lib/db/schemas/028_role_entity_facet.sql +18 -0
- package/build/lib/db/schemas/029_scan_scheme_kind.sql +31 -0
- package/build/modules/config.d.ts +5 -0
- package/build/modules/config.js +12 -0
- package/build/routes/escalations/acting.d.ts +12 -0
- package/build/routes/escalations/acting.js +25 -0
- package/build/routes/escalations/analytics.d.ts +8 -0
- package/build/routes/escalations/analytics.js +63 -0
- package/build/routes/escalations/index.js +3 -0
- package/build/routes/escalations/resolve.js +8 -1
- package/build/routes/escalations/single.js +13 -4
- package/build/routes/mcp-endpoint.js +4 -1
- package/build/routes/roles.js +1 -1
- package/build/routes/scan-codes.js +28 -2
- package/build/scripts/ortho-populate.js +14 -0
- package/build/scripts/printer-cycle.d.ts +25 -0
- package/build/scripts/printer-cycle.js +169 -0
- package/build/scripts/twin-farm.js +19 -5
- package/build/sdk/index.d.ts +2 -0
- package/build/sdk/index.js +3 -0
- package/build/services/escalation/aggregate-sql.d.ts +36 -0
- package/build/services/escalation/aggregate-sql.js +253 -0
- package/build/services/escalation/aggregate-validate.d.ts +57 -0
- package/build/services/escalation/aggregate-validate.js +224 -0
- package/build/services/escalation/aggregates.d.ts +26 -0
- package/build/services/escalation/aggregates.js +204 -0
- package/build/services/escalation/client.js +57 -21
- package/build/services/escalation/facet-sql.js +27 -0
- package/build/services/escalation/index.d.ts +2 -0
- package/build/services/escalation/index.js +8 -1
- package/build/services/escalation/metrics-cache.d.ts +18 -0
- package/build/services/escalation/metrics-cache.js +47 -1
- package/build/services/escalation/queries.js +2 -0
- package/build/services/iam/acting-identity.d.ts +16 -0
- package/build/services/iam/acting-identity.js +60 -0
- package/build/services/mcp/external-server.js +34 -26
- package/build/services/role/index.js +2 -0
- package/build/services/role/sql.d.ts +10 -2
- package/build/services/role/sql.js +14 -1
- package/build/services/role/types.d.ts +16 -0
- package/build/services/scan-code/read.js +4 -0
- package/build/services/scan-code/sql.d.ts +4 -4
- package/build/services/scan-code/sql.js +14 -8
- package/build/services/scan-code/validate.d.ts +2 -0
- package/build/services/scan-code/validate.js +86 -0
- package/build/services/scan-code/write.d.ts +4 -0
- package/build/services/scan-code/write.js +16 -2
- package/build/services/user/crud.d.ts +6 -0
- package/build/services/user/crud.js +16 -0
- package/build/services/user/index.d.ts +1 -1
- package/build/services/user/index.js +2 -1
- package/build/services/user/sql.d.ts +8 -0
- package/build/services/user/sql.js +9 -1
- package/build/system/index.js +17 -0
- package/build/system/mcp-servers/admin/escalations.js +34 -0
- package/build/system/mcp-servers/admin/index.js +2 -4
- package/build/system/mcp-servers/admin/scan-codes.js +17 -1
- package/build/system/mcp-servers/admin/schemas.d.ts +643 -25
- package/build/system/mcp-servers/admin/schemas.js +127 -19
- package/build/system/mcp-servers/admin/users.js +3 -1
- package/build/system/mcp-servers/human-queue-schemas.d.ts +2 -2
- package/build/system/seed/tool-manifests-admin.d.ts +2473 -1327
- package/build/system/seed/tool-manifests-admin.js +8 -10
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/analytics.d.ts +154 -0
- package/build/types/analytics.js +14 -0
- package/build/types/facets.d.ts +21 -0
- package/build/types/index.d.ts +5 -2
- package/build/types/index.js +5 -1
- package/build/types/scan-choice.d.ts +49 -0
- package/build/types/scan-choice.js +9 -0
- package/build/types/scan-code.d.ts +72 -1
- package/build/types/scan-code.js +30 -1
- package/dashboard/dist/assets/{AdminDashboard-Chg69wlx.js → AdminDashboard-D4ebrcNR.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-Chg69wlx.js.map → AdminDashboard-D4ebrcNR.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-DRTFwbfC.js → AgentConfigPage-DP4KUuCX.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-DRTFwbfC.js.map → AgentConfigPage-DP4KUuCX.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-JKByfFIi.js → AgentDetailPage-ktYiR1kq.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-JKByfFIi.js.map → AgentDetailPage-ktYiR1kq.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-BlgEmKhA.js → AgentsPage-B4iqm4-h.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-BlgEmKhA.js.map → AgentsPage-B4iqm4-h.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-tL3mM1RG.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-tL3mM1RG.js.map +1 -0
- package/dashboard/dist/assets/{BotPicker-CCVcz4Cq.js → BotPicker-CLrJuHnW.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-CCVcz4Cq.js.map → BotPicker-CLrJuHnW.js.map} +1 -1
- package/dashboard/dist/assets/CapabilitiesPage-DG5V0tMT.js +2 -0
- package/dashboard/dist/assets/CapabilitiesPage-DG5V0tMT.js.map +1 -0
- package/dashboard/dist/assets/{CollapsibleSection-8YE965QX.js → CollapsibleSection-CvLHvVfU.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-8YE965QX.js.map → CollapsibleSection-CvLHvVfU.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-Bxvq3D7j.js → CountdownTimer-Co57-iLY.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-Bxvq3D7j.js.map → CountdownTimer-Co57-iLY.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-Bn7_SX6-.js → CredentialsPage-qCJZ3rdi.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-Bn7_SX6-.js.map → CredentialsPage-qCJZ3rdi.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-Bn4mX_Yn.js → CronLabel-C3iKifDN.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-Bn4mX_Yn.js.map → CronLabel-C3iKifDN.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-pMcrFyW6.js → CustomDurationPicker-C-Szl4rU.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-pMcrFyW6.js.map → CustomDurationPicker-C-Szl4rU.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-zCEGjjk-.js → DropZone-BWD9aGOz.js} +2 -2
- package/dashboard/dist/assets/{DropZone-zCEGjjk-.js.map → DropZone-BWD9aGOz.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-BGO7IXEg.js → ElapsedCell-CamZk5o1.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-BGO7IXEg.js.map → ElapsedCell-CamZk5o1.js.map} +1 -1
- package/dashboard/dist/assets/EntityTimelinePanel-CABCW2dS.js +2 -0
- package/dashboard/dist/assets/EntityTimelinePanel-CABCW2dS.js.map +1 -0
- package/dashboard/dist/assets/{EscalationListSchemaPage-CFDxbd50.js → EscalationListSchemaPage-BddDSfjl.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-CFDxbd50.js.map → EscalationListSchemaPage-BddDSfjl.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-DnXPnDkz.js → EscalationSchemaPage-BRyCtw9R.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-DnXPnDkz.js.map → EscalationSchemaPage-BRyCtw9R.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-BZMVXrkK.js → EscalationsOverview-DUWYxJyD.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-BZMVXrkK.js.map → EscalationsOverview-DUWYxJyD.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-Bfi-f8as.js → EventTable-CtVuCgq6.js} +2 -2
- package/dashboard/dist/assets/{EventTable-Bfi-f8as.js.map → EventTable-CtVuCgq6.js.map} +1 -1
- package/dashboard/dist/assets/FilterBar-BYsBgOiE.js +2 -0
- package/dashboard/dist/assets/{FilterBar-Do7yR4xM.js.map → FilterBar-BYsBgOiE.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-d1ie4T7f.js → GraphInvokePage-CA4skPN2.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-d1ie4T7f.js.map → GraphInvokePage-CA4skPN2.js.map} +1 -1
- package/dashboard/dist/assets/HomePage-DwG-AnjQ.js +2 -0
- package/dashboard/dist/assets/{HomePage-BEeodImU.js.map → HomePage-DwG-AnjQ.js.map} +1 -1
- package/dashboard/dist/assets/ListToolbar-D86IN_hQ.js +2 -0
- package/dashboard/dist/assets/{ListToolbar-CLtw-1QN.js.map → ListToolbar-D86IN_hQ.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-DIsy9TB3.js → McpOverview-CoEHGseD.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-DIsy9TB3.js.map → McpOverview-CoEHGseD.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-6PomdsyD.js → McpQueryDetailPage-C9hMgJe1.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-6PomdsyD.js.map → McpQueryDetailPage-C9hMgJe1.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-YMdQCXm9.js → McpQueryPage-B20Zn4QX.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-YMdQCXm9.js.map → McpQueryPage-B20Zn4QX.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-DsD1Gm2o.js → McpRunDetailPage-DDKHf-3R.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-DsD1Gm2o.js.map → McpRunDetailPage-DDKHf-3R.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage--a5Jgb33.js → McpRunsPage-Puyn3iJr.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage--a5Jgb33.js.map → McpRunsPage-Puyn3iJr.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-wV6L4VW1.js → NamespacePill-C09QuOEz.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-wV6L4VW1.js.map → NamespacePill-C09QuOEz.js.map} +1 -1
- package/dashboard/dist/assets/OperationsPage-Bsrt4XTL.js +3 -0
- package/dashboard/dist/assets/OperationsPage-Bsrt4XTL.js.map +1 -0
- package/dashboard/dist/assets/OperatorDashboard-CXBbFLAL.js +2 -0
- package/dashboard/dist/assets/{OperatorDashboard-CkLfbxEh.js.map → OperatorDashboard-CXBbFLAL.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-BtIr6r-8.js → PageHeader-B7YJxa4o.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-BtIr6r-8.js.map → PageHeader-B7YJxa4o.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-C2sGqFQG.js → PageHeaderWithStats-gT-5ovJh.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-C2sGqFQG.js.map → PageHeaderWithStats-gT-5ovJh.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-CCmOgKQb.js → PersonaDetailPage-BN5xNDDX.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-CCmOgKQb.js.map → PersonaDetailPage-BN5xNDDX.js.map} +1 -1
- package/dashboard/dist/assets/PersonasPage-Bdtv6HPZ.js +2 -0
- package/dashboard/dist/assets/PersonasPage-Bdtv6HPZ.js.map +1 -0
- package/dashboard/dist/assets/{ProcessDetailPage-DT9BlJXK.js → ProcessDetailPage-BMg70ZAJ.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-DT9BlJXK.js.map → ProcessDetailPage-BMg70ZAJ.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-DgSGzTDT.js → ProcessesListPage-_KvdxGhL.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-DgSGzTDT.js.map → ProcessesListPage-_KvdxGhL.js.map} +1 -1
- package/dashboard/dist/assets/RoleDetailPage-BM5BXc7j.js +8 -0
- package/dashboard/dist/assets/RoleDetailPage-BM5BXc7j.js.map +1 -0
- package/dashboard/dist/assets/{RolePill-BBYjhAPj.js → RolePill-CtYI1_k1.js} +2 -2
- package/dashboard/dist/assets/{RolePill-BBYjhAPj.js.map → RolePill-CtYI1_k1.js.map} +1 -1
- package/dashboard/dist/assets/RolesPage-Bv23VmUi.js +2 -0
- package/dashboard/dist/assets/RolesPage-Bv23VmUi.js.map +1 -0
- package/dashboard/dist/assets/{RunAsSelector-CateuvcC.js → RunAsSelector-D-Sjr7uB.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-CateuvcC.js.map → RunAsSelector-D-Sjr7uB.js.map} +1 -1
- package/dashboard/dist/assets/ScanCodesPage-s3OEMJno.js +2 -0
- package/dashboard/dist/assets/ScanCodesPage-s3OEMJno.js.map +1 -0
- package/dashboard/dist/assets/ScanSchemeDetailPage-D8WQkZmw.js +2 -0
- package/dashboard/dist/assets/ScanSchemeDetailPage-D8WQkZmw.js.map +1 -0
- package/dashboard/dist/assets/ScanStationPage-CkRQaH5G.js +2 -0
- package/dashboard/dist/assets/ScanStationPage-CkRQaH5G.js.map +1 -0
- package/dashboard/dist/assets/{ScopeBadge-xs2Nhjy4.js → ScopeBadge-B76rOtA0.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-xs2Nhjy4.js.map → ScopeBadge-B76rOtA0.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-Cg-QdYWL.js → StickyPagination-BpTIMOL5.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-Cg-QdYWL.js.map → StickyPagination-BpTIMOL5.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-DEeuh4_-.js → StreamMessageDetail-ChoWrZzO.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-DEeuh4_-.js.map → StreamMessageDetail-ChoWrZzO.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-DMY0jL2F.js → SwimlaneTimeline-nmIqEuEH.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-DMY0jL2F.js.map → SwimlaneTimeline-nmIqEuEH.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-BMmiV-MD.js → TagInput-BQAPOp17.js} +2 -2
- package/dashboard/dist/assets/{TagInput-BMmiV-MD.js.map → TagInput-BQAPOp17.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-CPbkIvfF.js → TaskDetailPage-KajZD2Cp.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-CPbkIvfF.js.map → TaskDetailPage-KajZD2Cp.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-DLgYaw1x.js → TaskQueuePill-C2NImrwl.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-DLgYaw1x.js.map → TaskQueuePill-C2NImrwl.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CtHudKhQ.js → TasksListPage-CiqSfapP.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CtHudKhQ.js.map → TasksListPage-CiqSfapP.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-BdHOizWg.js → TimeAgo-ClauexJj.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-BdHOizWg.js.map → TimeAgo-ClauexJj.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-FVukzKRe.js → TimestampCell-CXmbCnAJ.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-FVukzKRe.js.map → TimestampCell-CXmbCnAJ.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-BvS53hxP.js → ToolPill-FOZm67TS.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-BvS53hxP.js.map → ToolPill-FOZm67TS.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-HN0OCYTL.js → ToolTestPanel-DFUU0zGv.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-HN0OCYTL.js.map → ToolTestPanel-DFUU0zGv.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-DHdSpN61.js → TopicDetailPage-DuN5BrsI.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-DHdSpN61.js.map → TopicDetailPage-DuN5BrsI.js.map} +1 -1
- package/dashboard/dist/assets/TopicsPage-DZ1NQdYG.js +2 -0
- package/dashboard/dist/assets/{TopicsPage-Clr6Tl5P.js.map → TopicsPage-DZ1NQdYG.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-BUVYyIAS.js → UserName-BPHG_MQs.js} +2 -2
- package/dashboard/dist/assets/{UserName-BUVYyIAS.js.map → UserName-BPHG_MQs.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-kncWFfe5.js → WorkflowExecutionPage-D_Z-tIjR.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-kncWFfe5.js.map → WorkflowExecutionPage-D_Z-tIjR.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-BPC_Dc_I.js → WorkflowPill-C5TEWlfO.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-BPC_Dc_I.js.map → WorkflowPill-C5TEWlfO.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-4ypPDGKx.js → WorkflowsDashboard-VMBW1WuR.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-4ypPDGKx.js.map → WorkflowsDashboard-VMBW1WuR.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-CeQlZkkd.js → WorkflowsOverview-CUOXXcpg.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-CeQlZkkd.js.map → WorkflowsOverview-CUOXXcpg.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DLAlEzwT.js → YamlWorkflowDetailPage-CsfzbboC.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DLAlEzwT.js.map → YamlWorkflowDetailPage-CsfzbboC.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-DQhenKFT.js → YamlWorkflowsPage-BpgKLSGT.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-DQhenKFT.js.map → YamlWorkflowsPage-BpgKLSGT.js.map} +1 -1
- package/dashboard/dist/assets/{agents-s3feet3W.js → agents-Cg2FVYQP.js} +2 -2
- package/dashboard/dist/assets/{agents-s3feet3W.js.map → agents-Cg2FVYQP.js.map} +1 -1
- package/dashboard/dist/assets/{bots-CkSd2rn9.js → bots-vtVLRKGt.js} +2 -2
- package/dashboard/dist/assets/{bots-CkSd2rn9.js.map → bots-vtVLRKGt.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-DA_r09tM.js → capabilities-DLsXhwlD.js} +2 -2
- package/dashboard/dist/assets/{capabilities-DA_r09tM.js.map → capabilities-DLsXhwlD.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-C9c25q21.js → controlplane-Js7dxpX4.js} +2 -2
- package/dashboard/dist/assets/{controlplane-C9c25q21.js.map → controlplane-Js7dxpX4.js.map} +1 -1
- package/dashboard/dist/assets/escalation-columns-h0NLAJss.js +2 -0
- package/dashboard/dist/assets/escalation-columns-h0NLAJss.js.map +1 -0
- package/dashboard/dist/assets/index-7c7FEe5S.js +3 -0
- package/dashboard/dist/assets/index-7c7FEe5S.js.map +1 -0
- package/dashboard/dist/assets/{index-WxE3ONia.js → index-BTzhV9ST.js} +2 -2
- package/dashboard/dist/assets/{index-WxE3ONia.js.map → index-BTzhV9ST.js.map} +1 -1
- package/dashboard/dist/assets/{index-BIcYbDVf.js → index-Bcv5k8Dw.js} +2 -2
- package/dashboard/dist/assets/{index-BIcYbDVf.js.map → index-Bcv5k8Dw.js.map} +1 -1
- package/dashboard/dist/assets/{index-BU5FFAJo.js → index-BjfoWzJL.js} +2 -2
- package/dashboard/dist/assets/{index-BU5FFAJo.js.map → index-BjfoWzJL.js.map} +1 -1
- package/dashboard/dist/assets/{index-C-MmR-jf.js → index-BvVJ538E.js} +2 -2
- package/dashboard/dist/assets/{index-C-MmR-jf.js.map → index-BvVJ538E.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cw9poaez.js → index-CSpTj5DB.js} +2 -2
- package/dashboard/dist/assets/{index-Cw9poaez.js.map → index-CSpTj5DB.js.map} +1 -1
- package/dashboard/dist/assets/index-CcjdA7jA.js +65 -0
- package/dashboard/dist/assets/index-CcjdA7jA.js.map +1 -0
- package/dashboard/dist/assets/{index-S13oPvuS.js → index-DQi6CjqF.js} +2 -2
- package/dashboard/dist/assets/{index-S13oPvuS.js.map → index-DQi6CjqF.js.map} +1 -1
- package/dashboard/dist/assets/index-DglcqBHn.js +6 -0
- package/dashboard/dist/assets/index-DglcqBHn.js.map +1 -0
- package/dashboard/dist/assets/{index-DvoMXQqO.js → index-DlO3bCfu.js} +2 -2
- package/dashboard/dist/assets/{index-DvoMXQqO.js.map → index-DlO3bCfu.js.map} +1 -1
- package/dashboard/dist/assets/{index-Bo5TtX9l.js → index-FYQ9yPhO.js} +2 -2
- package/dashboard/dist/assets/{index-Bo5TtX9l.js.map → index-FYQ9yPhO.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cmxzk4ay.js → index-KcaVfpWn.js} +2 -2
- package/dashboard/dist/assets/{index-Cmxzk4ay.js.map → index-KcaVfpWn.js.map} +1 -1
- package/dashboard/dist/assets/index-cFHoANSG.css +1 -0
- package/dashboard/dist/assets/{index--7Vdkzwd.js → index-vAkZ5dZe.js} +2 -2
- package/dashboard/dist/assets/{index--7Vdkzwd.js.map → index-vAkZ5dZe.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-Bpln0zy_.js → knowledge-Bkvl3cIz.js} +2 -2
- package/dashboard/dist/assets/{knowledge-Bpln0zy_.js.map → knowledge-Bkvl3cIz.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-BqDq3RZH.js → mcp-DEtDLeIQ.js} +2 -2
- package/dashboard/dist/assets/{mcp-BqDq3RZH.js.map → mcp-DEtDLeIQ.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-DGue75R6.js → mcp-query-BCRgnt0K.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-DGue75R6.js.map → mcp-query-BCRgnt0K.js.map} +1 -1
- package/dashboard/dist/assets/{personas-B8z_sTiJ.js → personas-CABKq-0L.js} +2 -2
- package/dashboard/dist/assets/{personas-B8z_sTiJ.js.map → personas-CABKq-0L.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-DYgNd9nB.js → pipelines-fuN8dVNl.js} +2 -2
- package/dashboard/dist/assets/{pipelines-DYgNd9nB.js.map → pipelines-fuN8dVNl.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-CJdjjhgO.js → tasks-u3YPNJBo.js} +2 -2
- package/dashboard/dist/assets/{tasks-CJdjjhgO.js.map → tasks-u3YPNJBo.js.map} +1 -1
- package/dashboard/dist/assets/{topics-DPrL8Dtq.js → topics-D37_RAIT.js} +2 -2
- package/dashboard/dist/assets/{topics-DPrL8Dtq.js.map → topics-D37_RAIT.js.map} +1 -1
- package/dashboard/dist/assets/useEventHooks-BbXfrFbq.js +2 -0
- package/dashboard/dist/assets/{useEventHooks-DXCgDgiu.js.map → useEventHooks-BbXfrFbq.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-DnFZfy7N.js → useNamespace-DvuoFTda.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-DnFZfy7N.js.map → useNamespace-DvuoFTda.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-kx5CLENv.js → useYamlActivityEvents-CL-Uf2cb.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-kx5CLENv.js.map → useYamlActivityEvents-CL-Uf2cb.js.map} +1 -1
- package/dashboard/dist/assets/{users-DKng7vAG.js → users-CMxw_HzK.js} +2 -2
- package/dashboard/dist/assets/{users-DKng7vAG.js.map → users-CMxw_HzK.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-CN-bAo9U.js → vendor-icons-Aw7bzBxa.js} +157 -137
- package/dashboard/dist/assets/vendor-icons-Aw7bzBxa.js.map +1 -0
- package/dashboard/dist/assets/{workflows-C4V0rMkM.js → workflows-Bez-o6fu.js} +2 -2
- package/dashboard/dist/assets/{workflows-C4V0rMkM.js.map → workflows-Bez-o6fu.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-D3PAiJ9d.js → yaml-workflows-NrXcLsNm.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-D3PAiJ9d.js.map → yaml-workflows-NrXcLsNm.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/escalations.md +133 -0
- package/docs/api/http/roles.md +6 -0
- package/docs/api/mcp/admin.md +53 -0
- package/docs/api/sdk/escalations.md +58 -0
- package/docs/cli.md +11 -0
- package/docs/dashboard.md +22 -20
- package/docs/data.md +12 -4
- package/docs/escalation-analytics.md +251 -0
- package/docs/hitl/roles.md +1 -1
- package/docs/hitl/x-lt-footer.md +1 -2
- package/docs/hitl-guide.md +3 -3
- package/docs/iam.md +12 -0
- package/docs/operations.md +17 -0
- package/docs/scan-codes.md +112 -0
- package/docs/sdk.md +1 -1
- package/package.json +2 -1
- package/build/system/mcp-servers/admin/ortho.d.ts +0 -10
- package/build/system/mcp-servers/admin/ortho.js +0 -242
- package/dashboard/dist/assets/AvailableEscalationsPage-C_7y692Q.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-C_7y692Q.js.map +0 -1
- package/dashboard/dist/assets/CapabilitiesPage-Czi9jUwD.js +0 -2
- package/dashboard/dist/assets/CapabilitiesPage-Czi9jUwD.js.map +0 -1
- package/dashboard/dist/assets/FilterBar-Do7yR4xM.js +0 -2
- package/dashboard/dist/assets/HomePage-BEeodImU.js +0 -2
- package/dashboard/dist/assets/ListToolbar-CLtw-1QN.js +0 -2
- package/dashboard/dist/assets/OperationsPage-B2v9k3DT.js +0 -2
- package/dashboard/dist/assets/OperationsPage-B2v9k3DT.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-CkLfbxEh.js +0 -2
- package/dashboard/dist/assets/PersonasPage-BJkSuDTN.js +0 -2
- package/dashboard/dist/assets/PersonasPage-BJkSuDTN.js.map +0 -1
- package/dashboard/dist/assets/RoleDetailPage-DMphTvro.js +0 -8
- package/dashboard/dist/assets/RoleDetailPage-DMphTvro.js.map +0 -1
- package/dashboard/dist/assets/RolesPage-gi_kaot1.js +0 -2
- package/dashboard/dist/assets/RolesPage-gi_kaot1.js.map +0 -1
- package/dashboard/dist/assets/ScanCodesPage-CQ8RxMug.js +0 -2
- package/dashboard/dist/assets/ScanCodesPage-CQ8RxMug.js.map +0 -1
- package/dashboard/dist/assets/ScanSchemeDetailPage-puSbuxcV.js +0 -2
- package/dashboard/dist/assets/ScanSchemeDetailPage-puSbuxcV.js.map +0 -1
- package/dashboard/dist/assets/TopicsPage-Clr6Tl5P.js +0 -2
- package/dashboard/dist/assets/escalation-columns-Cp3UrT48.js +0 -2
- package/dashboard/dist/assets/escalation-columns-Cp3UrT48.js.map +0 -1
- package/dashboard/dist/assets/index--DG-qQBT.js +0 -65
- package/dashboard/dist/assets/index--DG-qQBT.js.map +0 -1
- package/dashboard/dist/assets/index-C7ABSOU2.js +0 -6
- package/dashboard/dist/assets/index-C7ABSOU2.js.map +0 -1
- package/dashboard/dist/assets/index-DEbY57_c.js +0 -3
- package/dashboard/dist/assets/index-DEbY57_c.js.map +0 -1
- package/dashboard/dist/assets/index-DnV6LSeY.css +0 -1
- package/dashboard/dist/assets/useEventHooks-DXCgDgiu.js +0 -2
- package/dashboard/dist/assets/vendor-icons-CN-bAo9U.js.map +0 -1
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Escalation Analytics — Instrumenting a Process
|
|
2
|
+
|
|
3
|
+
Every escalation is one interval an entity spends in one state: it opens at
|
|
4
|
+
`created_at` and closes the instant the row leaves the live set. The
|
|
5
|
+
escalation queue is therefore a complete state time-series for every process
|
|
6
|
+
the platform runs, and the analytics surface reads it three ways — the
|
|
7
|
+
aggregate, the categorical slice, and the individual — from vocabulary the
|
|
8
|
+
workflow already writes plus two dials on the role.
|
|
9
|
+
|
|
10
|
+
This page is the whole authoring contract. The worked example is the seeded
|
|
11
|
+
printer scenario (`examples/seed-fleet-sim.ts`), which a fresh install
|
|
12
|
+
produces automatically; every call below runs verbatim against it.
|
|
13
|
+
|
|
14
|
+
## The sixty-second contract
|
|
15
|
+
|
|
16
|
+
**1. The workflow parks every state as an escalation.** `role` is the queue
|
|
17
|
+
that attends the state. `subtype` names the state *within* the role, for
|
|
18
|
+
roles that hold several. `metadata` carries the entity key (stored as a JSON
|
|
19
|
+
string) plus any categorical facts worth slicing by.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// Inside a durable workflow: park the printer in the fleet queue, printing.
|
|
23
|
+
const result = await condition(signalId, {
|
|
24
|
+
activity: ltCreateEscalation,
|
|
25
|
+
config: {
|
|
26
|
+
type: 'fleet',
|
|
27
|
+
subtype: 'printing', // the state, within the printer-fleet role
|
|
28
|
+
role: 'printer-fleet', // the queue that attends it
|
|
29
|
+
metadata: {
|
|
30
|
+
serialNumber: 'PRN-001', // the entity
|
|
31
|
+
model: 'h2s', // categorical facts, sliceable
|
|
32
|
+
pdac: true,
|
|
33
|
+
foaming: false,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**2. Each role declares two dials** (in the role admin page's Pace Board
|
|
40
|
+
section, beside the priority dials, or via `PATCH /api/roles/:role`):
|
|
41
|
+
|
|
42
|
+
| Dial | Meaning |
|
|
43
|
+
|------|---------|
|
|
44
|
+
| **Entity** (`entity_facet`) | The metadata key naming what moves through this role — `serialNumber` here. Roles sharing an entity key form that entity's **system**; the system is derived, never maintained. |
|
|
45
|
+
| **States from** (`entity_state_source`) | How the role names its contribution to the entity's state space. `'role'` (default): being in this queue is one state — a harvest or service bay. `'subtype'`: the role's subtypes are its states — a fleet role whose rows park as `idle` / `printing`. |
|
|
46
|
+
|
|
47
|
+
The printer scenario declares three roles:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
printer-fleet entity_facet: serialNumber states from: subtype (idle, printing)
|
|
51
|
+
printer-harvest entity_facet: serialNumber states from: role
|
|
52
|
+
printer-service entity_facet: serialNumber states from: role
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
That is the entire contract. Everything below is reading it back.
|
|
56
|
+
|
|
57
|
+
## The three questions
|
|
58
|
+
|
|
59
|
+
### Q1 — the fleet: how did all printers spend their time?
|
|
60
|
+
|
|
61
|
+
One call: scope to the entity's system, group by the derived state, measure
|
|
62
|
+
dwell (open-seconds, clipped to the window).
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
ltc esc aggregate-facets --entity serialNumber --group-state \
|
|
66
|
+
--window '{"from":"2026-08-01T00:00:00Z","to":"2026-08-01T12:00:00Z"}'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const { data } = await client.escalations.aggregateByFacets({
|
|
71
|
+
query: { entity: 'serialNumber' },
|
|
72
|
+
groupBy: { state: true },
|
|
73
|
+
measure: { kind: 'dwell', window: { from, to } },
|
|
74
|
+
});
|
|
75
|
+
// → groups: [{ state: 'idle', dwellSeconds, ... }, { state: 'printing', ... },
|
|
76
|
+
// { state: 'printer-harvest', ... }, { state: 'printer-service', ... }]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
curl -s -X POST http://localhost:3000/api/escalations/aggregate-by-facets \
|
|
81
|
+
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
|
|
82
|
+
-d '{"query":{"entity":"serialNumber"},"groupBy":{"state":true},
|
|
83
|
+
"measure":{"kind":"dwell","window":{"from":"2026-08-01T00:00:00Z","to":"2026-08-01T12:00:00Z"}}}'
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Each role contributes states per its dial: the fleet's subtypes (`idle`,
|
|
87
|
+
`printing`) plus the harvest and service roles themselves.
|
|
88
|
+
|
|
89
|
+
**Membership** is the other measure — rows (or, with `distinctBy`, distinct
|
|
90
|
+
entities) open at an instant. Omit `asOf` for now; a past `asOf` reconstructs
|
|
91
|
+
the live set at that moment.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// How many printers are in each state right now?
|
|
95
|
+
await client.escalations.aggregateByFacets({
|
|
96
|
+
query: { entity: 'serialNumber' },
|
|
97
|
+
groupBy: { state: true },
|
|
98
|
+
measure: { kind: 'membership' },
|
|
99
|
+
distinctBy: 'serialNumber',
|
|
100
|
+
});
|
|
101
|
+
// → one group per state, count = printers (not rows)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Q2 — the slice: the same, compared by any facet
|
|
105
|
+
|
|
106
|
+
Q1 plus `groupBy.facets` — each value gets an independent state split, and a
|
|
107
|
+
NULL group key is a real group (rows missing the facet).
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
ltc esc aggregate-facets --entity serialNumber --group-state --group-facets model \
|
|
111
|
+
--window '{"from":"2026-08-01T00:00:00Z","to":"2026-08-01T12:00:00Z"}'
|
|
112
|
+
# → p1s and h2s, each with its own idle/printing/harvest/service dwell
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Filtering works the same way: `--facets '{"pdac":true}'` restricts the whole
|
|
116
|
+
aggregate to the pdac printers.
|
|
117
|
+
|
|
118
|
+
### Q3 — the individual: how did printer X spend its day?
|
|
119
|
+
|
|
120
|
+
The ordered interval sequence across the whole system, durations included.
|
|
121
|
+
Gaps between intervals are untracked time and are preserved — the settle
|
|
122
|
+
latency between queues is a first-class signal.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
ltc esc timeline serialNumber PRN-001 --entity serialNumber
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
const { data } = await client.escalations.timelineByFacet({
|
|
130
|
+
facet: { key: 'serialNumber', value: 'PRN-001' },
|
|
131
|
+
query: { entity: 'serialNumber' },
|
|
132
|
+
});
|
|
133
|
+
// → intervals: [{ role, subtype, startedAt, endedAt, durationSeconds }, ...]
|
|
134
|
+
// open intervals report endedAt: null; gaps appear as time between spans
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
curl -s -X POST http://localhost:3000/api/escalations/timeline-by-facet \
|
|
139
|
+
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
|
|
140
|
+
-d '{"facet":{"key":"serialNumber","value":"PRN-001"},"query":{"entity":"serialNumber"}}'
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Where the answers appear in the dashboard
|
|
144
|
+
|
|
145
|
+
- **Q1** — `/operations`: the view selector offers every entity system beside
|
|
146
|
+
the station view; the system band shows state dwell over the selected
|
|
147
|
+
period with membership-now counts and the distinct-entity headline.
|
|
148
|
+
- **Q2** — the entity view's **Slice by** control: pick any metadata key the
|
|
149
|
+
rows carry and each value renders its own band, side by side.
|
|
150
|
+
- **Q3** — the entity table's timeline action, or the history affordance on
|
|
151
|
+
any metadata value in any escalation list: the full cross-queue journey in
|
|
152
|
+
the side panel, untracked gaps included.
|
|
153
|
+
|
|
154
|
+
Every surface refreshes from escalation events — resolve something and the
|
|
155
|
+
band moves within seconds.
|
|
156
|
+
|
|
157
|
+
## The interval, precisely
|
|
158
|
+
|
|
159
|
+
`[created_at, ended_at)`. `ended_at` derives from the terminal transition:
|
|
160
|
+
`resolved_at` for resolved rows, `updated_at` for cancelled or expired rows
|
|
161
|
+
(both stamped inside their status-guarded transitions), NULL while the row is
|
|
162
|
+
live. The `lt_escalations` view exposes it as a computed column, and a
|
|
163
|
+
partial index on the terminal end instant keeps history scans bounded — one
|
|
164
|
+
index write per row, at its terminal transition.
|
|
165
|
+
|
|
166
|
+
`liveStatuses` (default `['pending']`) declares which statuses count as
|
|
167
|
+
live; everything else is terminal.
|
|
168
|
+
|
|
169
|
+
## Locating one entity among thousands
|
|
170
|
+
|
|
171
|
+
Two filter fields make the individual findable at fleet scale, and both ride
|
|
172
|
+
the scans the aggregate already bounds — no additional indexes:
|
|
173
|
+
|
|
174
|
+
- **`prefix`** — case-insensitive prefix match on facet values
|
|
175
|
+
(`metadata->>key ILIKE 'value%'`, wildcards escaped). Type or scan the
|
|
176
|
+
leading characters of a serial and the entity table narrows:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
ltc esc aggregate-facets --entity serialNumber --group-facets serialNumber \
|
|
180
|
+
--prefix '{"serialNumber":"PRN-00"}' --window '{"from":"...","to":"..."}'
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
- **`anyOf`** — the row carries at least one of the given facet sets
|
|
184
|
+
(`metadata @> ANY(...)`, GIN-served; max 200 entries). Targets an explicit
|
|
185
|
+
entity set — the current table page — in one query:
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{ "anyOf": [{ "serialNumber": "PRN-001" }, { "serialNumber": "PRN-002" }] }
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Result groups page with `orderBy` + `limit`/`offset`; `overflow: true` means
|
|
192
|
+
another page exists. In the dashboard, every entity row is deep-linkable:
|
|
193
|
+
`/operations?lens=serialNumber&entity=PRN-003` opens the fleet view focused
|
|
194
|
+
on that printer with its timeline panel raised, and `&find=PRN-00` restores
|
|
195
|
+
a narrowed table.
|
|
196
|
+
|
|
197
|
+
## Paging a long timeline
|
|
198
|
+
|
|
199
|
+
Timelines order by start instant. The default `asc` reads the journey
|
|
200
|
+
top-down; a long history pages recent-first with `order: 'desc'` and the
|
|
201
|
+
`before` cursor (a strict upper bound on `startedAt`):
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
ltc esc timeline serialNumber PRN-001 --entity serialNumber \
|
|
205
|
+
--order desc --limit 100
|
|
206
|
+
# then, for the next-older page:
|
|
207
|
+
ltc esc timeline serialNumber PRN-001 --entity serialNumber \
|
|
208
|
+
--order desc --limit 100 --before 2026-08-01T09:15:00Z
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The dashboard's timeline panel loads the most recent 100 intervals and
|
|
212
|
+
offers "Load earlier" until the history is exhausted.
|
|
213
|
+
|
|
214
|
+
## Fail-loud validation
|
|
215
|
+
|
|
216
|
+
The filter takes the WHAT of a facet query only — `role`/`roles` (or
|
|
217
|
+
`entity`), `facets`, `block`, `range`, `exists`. Everything that would
|
|
218
|
+
silently change what an aggregate means is rejected with a 400:
|
|
219
|
+
|
|
220
|
+
- `status`, `available`, `jeopardy` on the filter — liveness derives from
|
|
221
|
+
the interval and the measure
|
|
222
|
+
- `orderBy`/`limit`/`offset` on the filter — paging applies to result groups
|
|
223
|
+
- `entity` together with `role`/`roles` — one scoping mechanism at a time
|
|
224
|
+
- an entity key no role declares — the response names the configuration gap
|
|
225
|
+
- `groupBy.state` together with `states[]` — one labeling mechanism
|
|
226
|
+
- a window wider than `LT_ANALYTICS_MAX_WINDOW_DAYS`, a future `asOf`,
|
|
227
|
+
malformed facet keys, unknown statuses
|
|
228
|
+
|
|
229
|
+
Result groups are capped (`LT_ANALYTICS_MAX_GROUPS`); when more exist the
|
|
230
|
+
response carries `overflow: true`.
|
|
231
|
+
|
|
232
|
+
## Access
|
|
233
|
+
|
|
234
|
+
Aggregates and timelines require `read_all` on every role in scope —
|
|
235
|
+
entity-derived roles included. A query with no role scope spans every queue
|
|
236
|
+
and requires a global principal. With the public Pace Board flag on,
|
|
237
|
+
counts-only aggregates (no facet keys among the group keys) are readable by
|
|
238
|
+
any login — the same data class the station metrics expose; facet-keyed
|
|
239
|
+
groupings and timelines always take the full gate. See [iam.md](iam.md).
|
|
240
|
+
|
|
241
|
+
## Reference
|
|
242
|
+
|
|
243
|
+
- HTTP: [api/http/escalations.md](api/http/escalations.md)
|
|
244
|
+
- SDK: `client.escalations.aggregateByFacets` / `timelineByFacet`
|
|
245
|
+
- MCP: `aggregate_by_facets` / `timeline_by_facet` on the admin server
|
|
246
|
+
- CLI: `ltc esc aggregate-facets`, `ltc esc timeline` — [cli.md](cli.md)
|
|
247
|
+
- Config: `LT_ANALYTICS_MAX_GROUPS`, `LT_ANALYTICS_MAX_WINDOW_DAYS`,
|
|
248
|
+
`LT_ANALYTICS_CACHE_TTL_MS`, `LT_ANALYTICS_PAST_CACHE_TTL_MS`,
|
|
249
|
+
`LT_ANALYTICS_CACHE_MAX_ENTRIES`
|
|
250
|
+
|
|
251
|
+
To watch the seeded fleet move live: `npm run printers:cycle`.
|
package/docs/hitl/roles.md
CHANGED
|
@@ -57,7 +57,7 @@ const decision = await conditionLT<{ confirmed: boolean; address: string }>(sign
|
|
|
57
57
|
|
|
58
58
|
## Escalation Chains
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
Chains are role-to-role routing edges, configured via the roles API (`POST /api/roles/escalation-chains`). Each role lists which other roles it can route work to, and the edges scope the programmatic re-routing surfaces — the `escalate_and_wait` MCP tool and the escalate APIs (HTTP, SDK, MCP, CLI). Common shape:
|
|
61
61
|
|
|
62
62
|
```
|
|
63
63
|
Analyst → Senior Analyst → Manager → VP
|
package/docs/hitl/x-lt-footer.md
CHANGED
|
@@ -23,7 +23,6 @@ to render in their place:
|
|
|
23
23
|
| `claim` | Claim | The claim button (unclaimed). |
|
|
24
24
|
| `cancel` | Cancel / Cancel escalation | The cancel control, both states. |
|
|
25
25
|
| `submit` | Submit / Acknowledge | The resolve button (claimed). |
|
|
26
|
-
| `escalate` | Escalate | The escalate tab and button. |
|
|
27
26
|
| `release` | Release | The release tab. |
|
|
28
27
|
|
|
29
28
|
```jsonc
|
|
@@ -34,7 +33,7 @@ to render in their place:
|
|
|
34
33
|
}
|
|
35
34
|
```
|
|
36
35
|
|
|
37
|
-
Only the
|
|
36
|
+
Only the known targets are read; unknown keys and non-string values are
|
|
38
37
|
ignored. Any target the schema omits keeps its default, so a schema overrides
|
|
39
38
|
just the controls it cares about. The pending, triage, and confirmation states
|
|
40
39
|
("Claiming…", "Send to Triage", "Yes, Release") keep their own copy.
|
package/docs/hitl-guide.md
CHANGED
|
@@ -61,12 +61,12 @@ When you author a HITL-backed workflow, the platform handles:
|
|
|
61
61
|
- **Accessible forms** — generated controls carry label association, error announcements, and keyboard-correct locking (see [form.md](hitl/form.md#accessibility))
|
|
62
62
|
- **Side panel** — help, AI analysis, metadata, context, and raw-record views beside the form
|
|
63
63
|
- **Section state persistence** — collapsed sections remembered across navigation
|
|
64
|
-
- **Escalation chains** —
|
|
64
|
+
- **Escalation chains** — role-to-role routing edges that scope programmatic re-routing (API, MCP, CLI)
|
|
65
65
|
- **AI triage** — optional auto-resolution for common patterns
|
|
66
66
|
- **Credential security** — password fields use ephemeral tokens, never stored in plain text
|
|
67
67
|
- **Schema enforcement** — roles with `enforce_schema` validate every resolver payload server-side (dashboard, API, MCP, CLI alike) with the same pass the form runs, rejecting violations as a structured 422 (see [schema-enforcement.md](schema-enforcement.md))
|
|
68
68
|
- **Telemetry** — trace IDs link escalations to OpenTelemetry traces
|
|
69
|
-
- **Bulk operations** — bulk claim, assign,
|
|
69
|
+
- **Bulk operations** — bulk claim, assign, triage, and cancel for queue management
|
|
70
70
|
- **Cancellation** — cancel pending escalations from the API or dashboard
|
|
71
71
|
|
|
72
72
|
You write the workflow and the schema. Everything else is provided.
|
|
@@ -124,7 +124,7 @@ Ordered as a learning path — each file adds one capability to the same form:
|
|
|
124
124
|
| `x-lt-viewport` | schema | Replace the generated form with a custom iframe UI |
|
|
125
125
|
| `x-lt-submit-guard` | schema | Block the resolve while an embedded escalation query returns rows; `autoResolveWhenEmpty` auto-closes the claimed parent once it drains. Enforced isomorphically for `enforce_schema` roles |
|
|
126
126
|
| `x-lt-submit-on-claim` | schema | Claiming also resolves the form's seeded defaults in one gesture |
|
|
127
|
-
| `x-lt-labels` | schema | Per-target labels for the footer controls (`claim`, `cancel`, `submit`, `
|
|
127
|
+
| `x-lt-labels` | schema | Per-target labels for the footer controls (`claim`, `cancel`, `submit`, `release`) |
|
|
128
128
|
| `x-lt-transition` | schema | Pause on a wait screen after resolve and hand off to the born-assigned follow-on |
|
|
129
129
|
| `x-lt-columns` | schema (list) | Column definitions for `facet-table` layout |
|
|
130
130
|
| `x-lt-row-action` | schema (list) | Per-row list action: `claim` / `view`, or `submitOnClaim` to claim, submit, and transition straight from the list |
|
package/docs/iam.md
CHANGED
|
@@ -92,6 +92,12 @@ HTTP surface: `GET/POST /api/personas`, `GET/PATCH/DELETE /api/personas/:key`, `
|
|
|
92
92
|
|
|
93
93
|
Scope folds into the SQL, so it is atomic with no TOCTOU window. Read scope becomes part of the escalation search query — a member sees a row when `role ∈ allRoles OR (role ∈ selfRoles AND assigned_to = me)`. Write scope folds into the atomic resolve-by-metadata query and gates the by-id claim/resolve/cancel paths. `assigned_to` is indexed, so `self` scope scales to large queues.
|
|
94
94
|
|
|
95
|
+
### Analytics gate
|
|
96
|
+
|
|
97
|
+
The escalation analytics surfaces (`aggregate-by-facets`, `timeline-by-facet`) are reads that aggregate other operators' items, and they may span roles — so the gate is `read_all` on **every** role in the query's scope. When the filter uses `entity`, the scope is the derived system: every role declaring that entity facet. A query with no role scope at all is inherently cross-role and requires a global principal (superadmin/admin).
|
|
98
|
+
|
|
99
|
+
While the `features.publicPaceBoard` flag stands (default on), counts-only aggregates — groupings with no `groupBy.facets` keys — are readable by any login: they emit counts and seconds, the same data class station metrics already expose to everyone. Facet-keyed groupings emit facet values (entity ids) as group keys, and a timeline is one entity's movement history — item-level disclosure — so both always take the full `read_all`-per-role gate.
|
|
100
|
+
|
|
95
101
|
## Workflow Types and IAM
|
|
96
102
|
|
|
97
103
|
Long Tail has three workflow types (see the [Workflows Guide](workflows.md#three-workflow-types) for full details). IAM applies to all three:
|
|
@@ -239,6 +245,12 @@ If a token is expired or exhausted, the opaque string passes through unchanged.
|
|
|
239
245
|
|
|
240
246
|
When an activity calls `getCredential('anthropic')` and no credential exists in the cascade (principal → initiator → env var), `MissingCredentialError` is thrown. The interceptor catches this and creates a credential-focused escalation with `category: 'missing_credential'`. The escalation form can include a password field so the human provides the credential ephemerally, without it being stored permanently.
|
|
241
247
|
|
|
248
|
+
### Acting identity (badge grants)
|
|
249
|
+
|
|
250
|
+
The same keystore carries **acting-identity grants** for shared station devices. A device signs in once as a station account — `read_scope: 'all'`, `write_scope: 'none'` on the queues it fronts — so reads are free and every mutation is structurally blocked for the account itself. A badge scan under an identity-kind scan scheme resolves the badge token against a server-side binding (`lt_users.metadata`, e.g. `badge_id`) and mints `eph:v1:acting_identity:<uuid>` under the scheme's TTL/max-uses policy.
|
|
251
|
+
|
|
252
|
+
The grant rides scan requests as `actingToken` and is exchanged server-side before anything reads or writes: the verbs run **as the badged person under their own live RBAC**. The grant confers attribution, never privilege — a badged user without write scope on the queue is still denied. Mutations attribute to the person (`assigned_to`, `resolved_by`) with the device recorded beside them (`scanStation` provenance). A dead grant is a loud `not_primed` outcome, never a silent execution as the device. See [scan-codes.md](scan-codes.md#identity-schemes-and-acting-identity).
|
|
253
|
+
|
|
242
254
|
## Dashboard
|
|
243
255
|
|
|
244
256
|
The dashboard surfaces IAM across four pages:
|
package/docs/operations.md
CHANGED
|
@@ -90,6 +90,23 @@ A 340 px right rail that slides open when a row or chart circle is clicked. Thre
|
|
|
90
90
|
|
|
91
91
|
Close the panel with × or by clicking another row.
|
|
92
92
|
|
|
93
|
+
## Entity lens
|
|
94
|
+
|
|
95
|
+
The board carries one view selector. When any station declares an entity facet, a lens strip appears above the chart: **Stations** (the default station-first board) plus one lens per entity facet the visible roles declare, labeled `by <key>` (e.g. `by serialNumber`). The active lens is deep-linked (`?lens=<key>`). Selecting a lens flips the page from station-first to entity-first: roles sharing the facet form the entity's **system**, and each role contributes states per its `entity_state_source`. Three tiers, aggregate → individual:
|
|
96
|
+
|
|
97
|
+
- **The system band** — how the fleet's time splits across states over the selected period: one stacked dwell band with a per-state legend (duration, percentage, and a `· N now` membership count where entities currently sit), headlined by the distinct-entity count in queue now (e.g. `6 serialNumber in queue now`).
|
|
98
|
+
- **Slice by** — the same band per value of any metadata key, chosen from a select of the known facet keys (e.g. `model` splits the band into `p1s` vs `h2s`). Small-multiple bands, ranked by total dwell, top 8 values.
|
|
99
|
+
- **The entity table** — one row per entity, ranked by tracked time: the entity value, its current state, its own dwell band, its total tracked time, and a timeline action that opens the entity's cross-queue interval timeline in the right panel.
|
|
100
|
+
|
|
101
|
+
The lens is driven by two dials on the role's Pace Board section ([Role Detail](dashboard.md#role-detail)):
|
|
102
|
+
|
|
103
|
+
| Dial | Description |
|
|
104
|
+
|------|-------------|
|
|
105
|
+
| `entity_facet` | The `lt_escalations.metadata` key naming the entity that moves through the role (e.g. `serialNumber`, `orderId`). Roles sharing a key form that entity's system. Blank = the role has no entity notion. |
|
|
106
|
+
| `entity_state_source` | How the role names the entity's state: **Station** (`'role'` — being in this role is one state, e.g. a servicing queue) or **Subtypes** (`'subtype'` — the one role holds several states named by each escalation's subtype, e.g. a fleet role parking `idle` / `printing`). Default `'role'`. |
|
|
107
|
+
|
|
108
|
+
The band tiers are counts-only aggregates, readable by any login while the public board flag stands; the slice and per-entity tiers group by facet values and require full (`read_all`) access to the system's queues. Data comes from `POST /api/escalations/aggregate-by-facets` and `POST /api/escalations/timeline-by-facet` — see [escalation-analytics.md](escalation-analytics.md) for the query contract.
|
|
109
|
+
|
|
93
110
|
## Data source
|
|
94
111
|
|
|
95
112
|
All station metrics come from `GET /api/escalations/station-metrics?period=<period>`. The endpoint runs two queries against `public.hmsh_escalations` joined to `lt_roles` (for the priority dials and `target_per_hour`): a live-counts pass over the pending backlog, and a window-bounded percentile pass over resolved rows (`PERCENTILE_CONT` in Postgres, served by the `idx_hmsh_esc_resolved_cover` index). Updates reach the page as push events — every escalation write invalidates the metrics through the Socket.IO event system.
|
package/docs/scan-codes.md
CHANGED
|
@@ -22,6 +22,9 @@ canonical action surface. A scan is an **ECA rule** over that surface:
|
|
|
22
22
|
- [Schemes](#schemes)
|
|
23
23
|
- [Rules and steps](#rules-and-steps)
|
|
24
24
|
- [Confirmation](#confirmation)
|
|
25
|
+
- [Info-choice screens](#info-choice-screens)
|
|
26
|
+
- [Identity schemes and acting identity](#identity-schemes-and-acting-identity)
|
|
27
|
+
- [Station deployments](#station-deployments)
|
|
25
28
|
- [The fallback screen](#the-fallback-screen)
|
|
26
29
|
- [Executing a scan](#executing-a-scan)
|
|
27
30
|
- [Capture on the dashboard](#capture-on-the-dashboard)
|
|
@@ -122,6 +125,115 @@ rule's prompt ("Cancel this printer's current state and send it home to
|
|
|
122
125
|
servicing?"). Confirming fires the standard per-id endpoint — the same
|
|
123
126
|
guarded call every other surface uses.
|
|
124
127
|
|
|
128
|
+
## Info-choice screens
|
|
129
|
+
|
|
130
|
+
Some objects carry one code for their whole life — an item tag, an order
|
|
131
|
+
label. One code, many possible intents, and the right one depends on where
|
|
132
|
+
the object is in its journey. The `present` verb closes that gap: the step
|
|
133
|
+
locates the row, states its reality, and returns a configured, labeled
|
|
134
|
+
choice set for the human to pick from. Upper half — what is true; lower
|
|
135
|
+
half — what you may do about it.
|
|
136
|
+
|
|
137
|
+
```jsonc
|
|
138
|
+
{
|
|
139
|
+
"query": { "roles": ["printer-fleet", "printer-harvest", "printer-service"] },
|
|
140
|
+
"verb": "present",
|
|
141
|
+
"choices": [
|
|
142
|
+
{ "label": "Claim & Start", "verb": "claim", "requireActingIdentity": true, "code": "CLAIM" },
|
|
143
|
+
{ "label": "Complete", "verb": "resolve", "requireActingIdentity": true,
|
|
144
|
+
"confirm": { "prompt": "Mark this item complete?" },
|
|
145
|
+
"params": { "resolverPayload": { "outcome": "complete" } } },
|
|
146
|
+
{ "label": "View Details", "verb": "show-detail" }
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The scan answers `choices` with the located escalation and the choice list;
|
|
152
|
+
each choice carries `withheld: true` when its identity requirement is
|
|
153
|
+
unsatisfied. Picking one calls `POST /api/scan-codes/execute-choice` with a
|
|
154
|
+
pointer (scheme, category, step index, choice index, escalation id) — and a
|
|
155
|
+
pointer is never authority: the server re-reads live config, re-locates the
|
|
156
|
+
row under the step's query, re-applies the identity gate, and runs the verb
|
|
157
|
+
through the same atomic executors a direct scan uses. A row that moved on
|
|
158
|
+
between render and tap answers `conflict`, exactly as a lost double-scan.
|
|
159
|
+
|
|
160
|
+
A choice's `code` is a short printable token (letters, digits, underscore,
|
|
161
|
+
dash) enabling double-scan selection: scan the object, then scan an action
|
|
162
|
+
card. The station screen matches the second scan against the presented
|
|
163
|
+
choices before treating it as a new code.
|
|
164
|
+
|
|
165
|
+
A claim choice lands on the work: after `claim` or `claim-show-detail`
|
|
166
|
+
executes, the station navigates to the escalation's detail page — the same
|
|
167
|
+
form every operator uses to resolve, reject, or conclude the item.
|
|
168
|
+
|
|
169
|
+
**One scan, one action.** A step with exactly one confirm-less choice can
|
|
170
|
+
set `autoSelectSingle: true`: the scan executes the choice directly instead
|
|
171
|
+
of presenting a one-button screen. The worker scans the item that just
|
|
172
|
+
arrived at their bench and it is theirs, claimed for the configured
|
|
173
|
+
duration, form on screen. An unsatisfied identity requirement never
|
|
174
|
+
auto-fires as the wrong actor — the scan stops over at the badge screen and
|
|
175
|
+
completes on its own once a badge primes.
|
|
176
|
+
|
|
177
|
+
## Identity schemes and acting identity
|
|
178
|
+
|
|
179
|
+
A scheme with `kind: "identity"` is the badge layer. Its `target_facet`
|
|
180
|
+
names the `lt_users.metadata` key the scanned badge token matches (the demo
|
|
181
|
+
binds `badge_id`) — resolution is only ever that metadata equality, so a
|
|
182
|
+
printed username can never impersonate. Identity rules carry no steps;
|
|
183
|
+
their `fallback` is the unknown-badge screen.
|
|
184
|
+
|
|
185
|
+
A matching badge scan answers `identity_primed` with the person's display
|
|
186
|
+
name, an expiry, and an **acting grant** — an ephemeral token
|
|
187
|
+
(`eph:v1:acting_identity:…`) minted through the internal keystore under the
|
|
188
|
+
scheme's policy:
|
|
189
|
+
|
|
190
|
+
| Scheme field | Meaning |
|
|
191
|
+
|---|---|
|
|
192
|
+
| `grant_ttl_seconds` | How long the grant lives (1–86400). |
|
|
193
|
+
| `grant_max_uses` | `0` = TTL-bound; `n` = the grant covers n scan requests (a strict one-scan policy is `1`). |
|
|
194
|
+
|
|
195
|
+
The grant rides subsequent scans as `actingToken`. Verbs then run **as the
|
|
196
|
+
badged person under their own live RBAC** — the grant confers attribution,
|
|
197
|
+
never privilege. A dead grant (expired, exhausted, revoked) is a loud
|
|
198
|
+
`not_primed`, never a silent execution as the device. Scanning the next
|
|
199
|
+
badge replaces the session's grant; passing `previousActingToken` revokes
|
|
200
|
+
the outgoing one immediately.
|
|
201
|
+
|
|
202
|
+
Steps and choices opt in with `requireActingIdentity: true`: the effective
|
|
203
|
+
actor must be a real acting identity — a badge grant, or an authenticated
|
|
204
|
+
user whose own write scope covers the step. When unsatisfied, the outcome
|
|
205
|
+
is `not_primed` with the rule's `notPrimed` screen (a sibling of
|
|
206
|
+
`fallback`): the "scan your badge" message, never a silent or misattributed
|
|
207
|
+
action.
|
|
208
|
+
|
|
209
|
+
## Station deployments
|
|
210
|
+
|
|
211
|
+
A shared floor device (tablet + tethered scanner) signs in once as a
|
|
212
|
+
station account — an ordinary user with `read_scope: 'all'` and
|
|
213
|
+
`write_scope: 'none'` on the queues it fronts. Reads are free: the station
|
|
214
|
+
holds a real seat with a queue view and an audit identity. Every mutation
|
|
215
|
+
takes the badge layer, and `write_scope: 'none'` is the structural
|
|
216
|
+
backstop — even a misconfigured rule cannot mutate as the station, because
|
|
217
|
+
the RBAC write gate denies the account itself.
|
|
218
|
+
|
|
219
|
+
Mutations attribute to the badged person (`assigned_to`, `resolved_by`)
|
|
220
|
+
with the device recorded beside them (`scanStation` in the scan
|
|
221
|
+
provenance) — every action individually owned and geographically placed.
|
|
222
|
+
The dashboard's `/scan/station` route is the full-screen experience: idle
|
|
223
|
+
("scan your badge / scan an item"), the primed chrome with the grant
|
|
224
|
+
countdown, the info-choice screen, and the **badge stop-over** — the one
|
|
225
|
+
identity moment the flow ever surfaces. When an action needs a person and
|
|
226
|
+
none is primed (a withheld choice tapped, an auto-select scan, a grant that
|
|
227
|
+
lapsed mid-flow), the screen becomes a single clear prompt: scan your badge
|
|
228
|
+
to continue. The badge scan primes the session and the pending action
|
|
229
|
+
completes on its own. With a live grant the stop-over never appears — the
|
|
230
|
+
identity layer is invisible when all is well.
|
|
231
|
+
|
|
232
|
+
Badge tokens are printed credentials: seed them as long random strings,
|
|
233
|
+
bind them server-side (`lt_users.metadata`), and treat badge possession
|
|
234
|
+
with the same physical policy as any badge system. Unknown badges answer
|
|
235
|
+
`identity_unknown` and are auditable.
|
|
236
|
+
|
|
125
237
|
## The fallback screen
|
|
126
238
|
|
|
127
239
|
When no step matches, the response carries the rule's `fallback`: markdown
|
package/docs/sdk.md
CHANGED
|
@@ -63,7 +63,7 @@ The client mirrors the REST route structure:
|
|
|
63
63
|
| Namespace | REST equivalent | Key operations |
|
|
64
64
|
|-----------|----------------|----------------|
|
|
65
65
|
| `lt.tasks` | `/api/tasks` | `list`, `get`, `listProcesses`, `getProcess`, `getProcessStats` |
|
|
66
|
-
| `lt.escalations` | `/api/escalations` | `list`, `listAvailable`, `get`, `claim`, `release`, `resolve`, `escalate`, `bulkClaim`, `bulkAssign`, `findByMetadata`, `claimByMetadata`, `resolveByMetadata` |
|
|
66
|
+
| `lt.escalations` | `/api/escalations` | `list`, `listAvailable`, `get`, `claim`, `release`, `resolve`, `escalate`, `bulkClaim`, `bulkAssign`, `findByMetadata`, `claimByMetadata`, `resolveByMetadata`, `aggregateByFacets`, `timelineByFacet` — see the [Escalations SDK reference](api/sdk/escalations.md) |
|
|
67
67
|
| `lt.workflows` | `/api/workflows` | `invoke`, `getStatus`, `getResult`, `terminate`, `listWorkers`, `listDiscovered`, `listConfigs`, `getConfig`, `upsertConfig` |
|
|
68
68
|
| `lt.yamlWorkflows` | `/api/yaml-workflows` | `list`, `get`, `create`, `deploy`, `activate`, `invoke`, `archive` |
|
|
69
69
|
| `lt.users` | `/api/users` | `list`, `get`, `create`, `update`, `delete`, `getRoles`, `addRole`, `removeRole` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hotmeshio/long-tail",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Long Tail Workflows — Durable AI workflows with human-in-the-loop escalation. Powered by PostgreSQL.",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"demo": "bash scripts/demo.sh",
|
|
46
46
|
"ortho:populate": "ts-node scripts/ortho-populate.ts",
|
|
47
47
|
"twin:farm": "ts-node scripts/twin-farm.ts",
|
|
48
|
+
"printers:cycle": "ts-node scripts/printer-cycle.ts",
|
|
48
49
|
"dashboard:install": "cd dashboard && npm install",
|
|
49
50
|
"dashboard:dev": "cd dashboard && npm run dev",
|
|
50
51
|
"dashboard:build": "cd dashboard && npm run build",
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ortho pipeline MCP tools — AI-operable interface for the 8-stage manufacturing workflow.
|
|
3
|
-
*
|
|
4
|
-
* ortho_submit — start a new order through the orthoPipeline workflow
|
|
5
|
-
* ortho_pending — list open stage escalations waiting for completion
|
|
6
|
-
* ortho_complete_stage — claim and resolve one stage escalation (advances the pipeline)
|
|
7
|
-
* ortho_status — get the current status and results for an order workflow
|
|
8
|
-
*/
|
|
9
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
-
export declare function registerOrthoTools(server: McpServer): void;
|