@hotmeshio/long-tail 0.27.0 → 0.28.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/README.md +9 -2
- package/build/api/files.d.ts +5 -0
- package/build/api/files.js +19 -2
- package/build/api/knowledge.d.ts +3 -1
- package/build/api/settings.d.ts +4 -1
- package/build/api/settings.js +7 -1
- package/build/index.js +9 -4
- package/build/lib/db/config-lock.d.ts +10 -0
- package/build/lib/db/config-lock.js +28 -0
- package/build/lib/db/schemas/041_machine_lines.sql +26 -0
- package/build/lib/db/schemas/042_knowledge_edition_labels.sql +9 -0
- package/build/lib/events/browser-view.js +8 -2
- package/build/lib/events/publish.d.ts +33 -0
- package/build/lib/events/publish.js +52 -1
- package/build/lib/machines/line.d.ts +7 -1
- package/build/lib/machines/line.js +25 -2
- package/build/lib/machines/protocol/codec.d.ts +14 -0
- package/build/lib/machines/protocol/codec.js +10 -1
- package/build/lib/machines/protocol/constants.d.ts +1 -1
- package/build/lib/machines/protocol/constants.js +1 -1
- package/build/lib/machines/protocol/contract.d.ts +2 -0
- package/build/lib/machines/protocol/contract.js +13 -8
- package/build/lib/machines/site/mosquitto-conf.d.ts +9 -4
- package/build/lib/machines/site/mosquitto-conf.js +32 -22
- package/build/lib/machines/site/site-conf.d.ts +13 -3
- package/build/lib/machines/site/site-conf.js +31 -8
- package/build/lib/machines/transport/callback-feed.d.ts +1 -0
- package/build/lib/machines/transport/callback-feed.js +4 -1
- package/build/lib/machines/transport/memory.d.ts +2 -0
- package/build/lib/machines/transport/memory.js +6 -0
- package/build/lib/machines/transport/mqtt-bus.d.ts +2 -0
- package/build/lib/machines/transport/mqtt-bus.js +4 -0
- package/build/lib/machines/transport/nats-bus.d.ts +3 -0
- package/build/lib/machines/transport/nats-bus.js +3 -0
- package/build/lib/machines/transport/nats-feed.d.ts +1 -0
- package/build/lib/machines/transport/nats-feed.js +4 -1
- package/build/lib/machines/transport/pubsub-feed.d.ts +1 -0
- package/build/lib/machines/transport/pubsub-feed.js +4 -1
- package/build/lib/machines/transport/stream-bus.d.ts +7 -1
- package/build/lib/machines/transport/stream-bus.js +17 -5
- package/build/lib/machines/transport/streams.d.ts +10 -2
- package/build/lib/machines/transport/streams.js +32 -5
- package/build/lib/messaging/memory.js +3 -0
- package/build/lib/messaging/nats/streams.d.ts +3 -0
- package/build/lib/messaging/nats/streams.js +16 -0
- package/build/lib/storage/local.d.ts +2 -0
- package/build/lib/storage/local.js +3 -0
- package/build/lib/storage/s3.d.ts +3 -2
- package/build/lib/storage/s3.js +6 -1
- package/build/lib/storage/types.d.ts +7 -1
- package/build/modules/machines.d.ts +8 -0
- package/build/modules/machines.js +16 -0
- package/build/routes/file-browser.js +3 -1
- package/build/routes/index.js +2 -0
- package/build/routes/knowledge.js +6 -5
- package/build/routes/machines.d.ts +2 -0
- package/build/routes/machines.js +253 -0
- package/build/services/knowledge/index.d.ts +4 -2
- package/build/services/knowledge/index.js +8 -2
- package/build/services/knowledge/lookup-cache.d.ts +8 -0
- package/build/services/knowledge/lookup-cache.js +30 -3
- package/build/services/knowledge/lookup-refs.js +1 -1
- package/build/services/knowledge/sql.d.ts +4 -2
- package/build/services/knowledge/sql.js +8 -3
- package/build/services/machines/commands.d.ts +5 -5
- package/build/services/machines/commands.js +3 -2
- package/build/services/machines/config.d.ts +4 -1
- package/build/services/machines/config.js +2 -1
- package/build/services/machines/contracts.d.ts +28 -0
- package/build/services/machines/contracts.js +15 -1
- package/build/services/machines/forms.d.ts +26 -1
- package/build/services/machines/forms.js +17 -1
- package/build/services/machines/gateway/actions.d.ts +14 -1
- package/build/services/machines/gateway/admission.d.ts +30 -4
- package/build/services/machines/gateway/admission.js +76 -14
- package/build/services/machines/gateway/api-escalations.js +4 -0
- package/build/services/machines/gateway/dispatcher.d.ts +12 -4
- package/build/services/machines/gateway/dispatcher.js +53 -17
- package/build/services/machines/gateway/executor.d.ts +13 -2
- package/build/services/machines/gateway/executor.js +84 -29
- package/build/services/machines/gateway/gateway.d.ts +21 -1
- package/build/services/machines/gateway/gateway.js +65 -25
- package/build/services/machines/gateway/index.d.ts +3 -0
- package/build/services/machines/gateway/index.js +3 -0
- package/build/services/machines/gateway/inspect.d.ts +17 -0
- package/build/services/machines/gateway/inspect.js +68 -0
- package/build/services/machines/gateway/log.d.ts +10 -0
- package/build/services/machines/gateway/log.js +20 -0
- package/build/services/machines/gateway/lt-http.js +11 -2
- package/build/services/machines/gateway/pacing.js +2 -1
- package/build/services/machines/gateway/plan-escalation.js +8 -3
- package/build/services/machines/gateway/plan-machine.js +41 -16
- package/build/services/machines/gateway/plan-shared.d.ts +5 -3
- package/build/services/machines/gateway/plan-shared.js +6 -4
- package/build/services/machines/gateway/project.d.ts +9 -0
- package/build/services/machines/gateway/project.js +55 -0
- package/build/services/machines/gateway/receipts.d.ts +3 -0
- package/build/services/machines/gateway/receipts.js +3 -1
- package/build/services/machines/gateway/reconcile.js +3 -3
- package/build/services/machines/gateway/registration.js +1 -1
- package/build/services/machines/gateway/reply-waiter.d.ts +8 -3
- package/build/services/machines/gateway/reply-waiter.js +37 -16
- package/build/services/machines/gateway/state.d.ts +53 -4
- package/build/services/machines/gateway/state.js +128 -13
- package/build/services/machines/gateway/wire-window.d.ts +21 -0
- package/build/services/machines/gateway/wire-window.js +61 -0
- package/build/services/machines/gateway/wire.d.ts +58 -0
- package/build/services/machines/gateway/wire.js +172 -0
- package/build/services/machines/index.d.ts +3 -0
- package/build/services/machines/index.js +2 -0
- package/build/services/machines/line-index.d.ts +16 -0
- package/build/services/machines/line-index.js +39 -0
- package/build/services/machines/registry-sql.d.ts +31 -0
- package/build/services/machines/registry-sql.js +110 -0
- package/build/services/machines/registry-sync.d.ts +31 -0
- package/build/services/machines/registry-sync.js +81 -0
- package/build/services/machines/registry.d.ts +77 -0
- package/build/services/machines/registry.js +158 -0
- package/build/services/machines/roles.d.ts +5 -4
- package/build/services/machines/roles.js +13 -4
- package/build/services/machines/rows.js +10 -1
- package/build/services/machines/select.d.ts +3 -2
- package/build/services/machines/select.js +4 -3
- package/build/services/machines/surface.d.ts +54 -5
- package/build/services/machines/surface.js +113 -17
- package/build/start/apply-report.d.ts +1 -1
- package/build/start/apply-report.js +3 -25
- package/build/start/index.js +16 -4
- package/build/system/activities/knowledge.d.ts +4 -0
- package/build/system/activities/knowledge.js +15 -0
- package/build/system/activities/sql.d.ts +2 -0
- package/build/system/activities/sql.js +6 -1
- package/build/system/index.js +13 -0
- package/build/system/mcp-servers/admin/schemas.d.ts +22 -22
- package/build/system/mcp-servers/human-queue-schemas.d.ts +7 -7
- package/build/system/mcp-servers/knowledge.js +4 -2
- package/build/system/mcp-servers/machines-schemas.d.ts +35 -0
- package/build/system/mcp-servers/machines-schemas.js +35 -0
- package/build/system/mcp-servers/machines.d.ts +20 -0
- package/build/system/mcp-servers/machines.js +154 -0
- package/build/system/seed/tool-manifests-machines.d.ts +2 -0
- package/build/system/seed/tool-manifests-machines.js +88 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/escalation.d.ts +9 -6
- package/build/types/escalation.js +8 -2
- package/build/types/events.d.ts +6 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/machines-view.d.ts +175 -0
- package/build/types/machines-view.js +7 -0
- package/build/types/machines.d.ts +5 -0
- package/build/types/messaging.d.ts +2 -0
- package/build/types/startup.d.ts +2 -0
- package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js → AdminDashboard-Bm7VG65H.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js.map → AdminDashboard-Bm7VG65H.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js → AgentConfigPage-aJF7Sdbc.js} +6 -6
- package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js.map → AgentConfigPage-aJF7Sdbc.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js → AgentDetailPage-GwwghhxT.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js.map → AgentDetailPage-GwwghhxT.js.map} +1 -1
- package/dashboard/dist/assets/AgentsPage-DVvCzZyg.js +2 -0
- package/dashboard/dist/assets/{AgentsPage-C9UuUKhr.js.map → AgentsPage-DVvCzZyg.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-Cxmcji_K.js +2 -0
- package/dashboard/dist/assets/{AvailableEscalationsPage-DrvfXz70.js.map → AvailableEscalationsPage-Cxmcji_K.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js → BotPicker-CofRxk4L.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js.map → BotPicker-CofRxk4L.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js → BulkAssignModal-BARWuz4L.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js.map → BulkAssignModal-BARWuz4L.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js → CapabilitiesPage-BJAWVNEx.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js.map → CapabilitiesPage-BJAWVNEx.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js → CollapsibleSection-CtgoaG75.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js.map → CollapsibleSection-CtgoaG75.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js → ConfirmDeleteModal-BYXXBWs6.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js.map → ConfirmDeleteModal-BYXXBWs6.js.map} +1 -1
- package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js → ConnectedAppsPage-D0JkzWa7.js} +2 -2
- package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js.map → ConnectedAppsPage-D0JkzWa7.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js → CountdownTimer-BcFxdZYN.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js.map → CountdownTimer-BcFxdZYN.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js → CredentialsPage-DPSY20rV.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js.map → CredentialsPage-DPSY20rV.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js → CronLabel-Dg_Oew_Y.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js.map → CronLabel-Dg_Oew_Y.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-u1JGfR9G.js → DropZone-Cl_Flb16.js} +2 -2
- package/dashboard/dist/assets/{DropZone-u1JGfR9G.js.map → DropZone-Cl_Flb16.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js → ElapsedCell-Dm3G5fK2.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js.map → ElapsedCell-Dm3G5fK2.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js → EntityTimelinePanel-CrEEP04e.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js.map → EntityTimelinePanel-CrEEP04e.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js → EscalationListSchemaPage-wOInXcjs.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js.map → EscalationListSchemaPage-wOInXcjs.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js → EscalationSchemaPage-CrIj_g9d.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js.map → EscalationSchemaPage-CrIj_g9d.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js → EscalationTimeline-CeAsl5IT.js} +2 -2
- package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js.map → EscalationTimeline-CeAsl5IT.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js → EscalationTitleSelect-D8qpCYiy.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js.map → EscalationTitleSelect-D8qpCYiy.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js → EscalationsOverview-CvaqVPsr.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js.map → EscalationsOverview-CvaqVPsr.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-V4RF_n58.js → EventTable-Be0JuEl6.js} +2 -2
- package/dashboard/dist/assets/{EventTable-V4RF_n58.js.map → EventTable-Be0JuEl6.js.map} +1 -1
- package/dashboard/dist/assets/FilterBar-BVyAjIgv.js +2 -0
- package/dashboard/dist/assets/FilterBar-BVyAjIgv.js.map +1 -0
- package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js → GraphInvokePage-D_QigJeD.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js.map → GraphInvokePage-D_QigJeD.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-EjcNxlKx.js → HomePage-C1haeuNy.js} +2 -2
- package/dashboard/dist/assets/{HomePage-EjcNxlKx.js.map → HomePage-C1haeuNy.js.map} +1 -1
- package/dashboard/dist/assets/LinePage-CWD5pv1g.js +5 -0
- package/dashboard/dist/assets/LinePage-CWD5pv1g.js.map +1 -0
- package/dashboard/dist/assets/LinesPage-NqChsKcO.js +3 -0
- package/dashboard/dist/assets/LinesPage-NqChsKcO.js.map +1 -0
- package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js → ListToolbar-BZCNrTh6.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js.map → ListToolbar-BZCNrTh6.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js → McpOverview-yJTYnh1z.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js.map → McpOverview-yJTYnh1z.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js → McpQueryDetailPage-ChuLpJ4u.js} +3 -3
- package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js.map → McpQueryDetailPage-ChuLpJ4u.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js → McpQueryPage-9S-v9soF.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js.map → McpQueryPage-9S-v9soF.js.map} +1 -1
- package/dashboard/dist/assets/McpRunDetailPage-BhrcfxD5.js +2 -0
- package/dashboard/dist/assets/{McpRunDetailPage-80fQn9iX.js.map → McpRunDetailPage-BhrcfxD5.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js → McpRunsPage-C5_i8_Zx.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js.map → McpRunsPage-C5_i8_Zx.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js → NamespacePill-OTZD2hzt.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js.map → NamespacePill-OTZD2hzt.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js → OperationsPage-C03CeU5P.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js.map → OperationsPage-C03CeU5P.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js → OperatorDashboard-BzC134Jt.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js.map → OperatorDashboard-BzC134Jt.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-BSWIspNB.js → PageHeader-Hx8APPwE.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-BSWIspNB.js.map → PageHeader-Hx8APPwE.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js → PageHeaderWithStats-BEQYYBJv.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js.map → PageHeaderWithStats-BEQYYBJv.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js → PersonaDetailPage-D0mY9L6j.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js.map → PersonaDetailPage-D0mY9L6j.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js → PersonasPage-FFlm5Eug.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js.map → PersonasPage-FFlm5Eug.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-CucNZn_w.js → PortalPage-Cpc25uO-.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-CucNZn_w.js.map → PortalPage-Cpc25uO-.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js → ProcessDetailPage-Di2J7KwY.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js.map → ProcessDetailPage-Di2J7KwY.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js → ProcessesListPage-BEXwU3Z0.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js.map → ProcessesListPage-BEXwU3Z0.js.map} +1 -1
- package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js → ResolverForm-2ks-3jXC.js} +6 -6
- package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js.map → ResolverForm-2ks-3jXC.js.map} +1 -1
- package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js → RoleDetailPage-DqoOk0xc.js} +3 -3
- package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js.map → RoleDetailPage-DqoOk0xc.js.map} +1 -1
- package/dashboard/dist/assets/{RolePill-CoETDpjF.js → RolePill-R5_ctGFy.js} +2 -2
- package/dashboard/dist/assets/{RolePill-CoETDpjF.js.map → RolePill-R5_ctGFy.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-DBKxeam4.js → RolesPage-CPmo8Srr.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-DBKxeam4.js.map → RolesPage-CPmo8Srr.js.map} +1 -1
- package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js → RosterWidget-D2yovCKw.js} +2 -2
- package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js.map → RosterWidget-D2yovCKw.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js → RunAsSelector-CMv96On6.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js.map → RunAsSelector-CMv96On6.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js → ScanCodesPage-CA6cTT-M.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js.map → ScanCodesPage-CA6cTT-M.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js → ScanSchemeDetailPage-DnctN5-H.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js.map → ScanSchemeDetailPage-DnctN5-H.js.map} +1 -1
- package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js → ScanStationPage-Bk8RwkKL.js} +2 -2
- package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js.map → ScanStationPage-Bk8RwkKL.js.map} +1 -1
- package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js → ScopeBadge-BXZ084nD.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js.map → ScopeBadge-BXZ084nD.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js → StickyPagination-B0FSuUgs.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js.map → StickyPagination-B0FSuUgs.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js → StreamMessageDetail-BwZEvMpP.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js.map → StreamMessageDetail-BwZEvMpP.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js → SwimlaneTimeline-BDVQEaMw.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js.map → SwimlaneTimeline-BDVQEaMw.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-S7UuVT_M.js → TagInput-DjPUDp2M.js} +2 -2
- package/dashboard/dist/assets/{TagInput-S7UuVT_M.js.map → TagInput-DjPUDp2M.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js → TaskDetailPage-BOlv3iGB.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js.map → TaskDetailPage-BOlv3iGB.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js → TaskQueuePill-D-4Ynf3K.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js.map → TaskQueuePill-D-4Ynf3K.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js → TasksListPage-e2teY0bD.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js.map → TasksListPage-e2teY0bD.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js → TimeAgo-Cvkpf_b3.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js.map → TimeAgo-Cvkpf_b3.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js → TimestampCell-B3btAV0N.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js.map → TimestampCell-B3btAV0N.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-D40uLM_v.js → ToolPill-GsKQ80CO.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-D40uLM_v.js.map → ToolPill-GsKQ80CO.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js → ToolTestPanel-B03nebR7.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js.map → ToolTestPanel-B03nebR7.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js → TopicDetailPage-DBRWne3O.js} +3 -3
- package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js.map → TopicDetailPage-DBRWne3O.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js → TopicsPage-CVe2M9HD.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js.map → TopicsPage-CVe2M9HD.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-DQFjuoib.js → UserName-B_q_qp6V.js} +2 -2
- package/dashboard/dist/assets/{UserName-DQFjuoib.js.map → UserName-B_q_qp6V.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-Bh_dr9tM.js +2 -0
- package/dashboard/dist/assets/{WorkflowExecutionPage-Di08wCbs.js.map → WorkflowExecutionPage-Bh_dr9tM.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js → WorkflowPill-D7244fKp.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js.map → WorkflowPill-D7244fKp.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js → WorkflowsDashboard-DA6Mj7qH.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js.map → WorkflowsDashboard-DA6Mj7qH.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js → WorkflowsOverview-B1kBLj-a.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js.map → WorkflowsOverview-B1kBLj-a.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js → YamlWorkflowDetailPage-6GJM8QIX.js} +8 -8
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js.map → YamlWorkflowDetailPage-6GJM8QIX.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js → YamlWorkflowsPage-Bu811C7f.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js.map → YamlWorkflowsPage-Bu811C7f.js.map} +1 -1
- package/dashboard/dist/assets/{agents-PuftRTB2.js → agents-MPk_GnYz.js} +2 -2
- package/dashboard/dist/assets/{agents-PuftRTB2.js.map → agents-MPk_GnYz.js.map} +1 -1
- package/dashboard/dist/assets/{bots-BmEiPAWY.js → bots-2RihE2Tc.js} +2 -2
- package/dashboard/dist/assets/{bots-BmEiPAWY.js.map → bots-2RihE2Tc.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-CRii4Soa.js → capabilities-CC4iwJ1P.js} +2 -2
- package/dashboard/dist/assets/{capabilities-CRii4Soa.js.map → capabilities-CC4iwJ1P.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DO_czaYo.js → controlplane-Bmkic8BH.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DO_czaYo.js.map → controlplane-Bmkic8BH.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js → escalation-columns-B0lhUUrQ.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js.map → escalation-columns-B0lhUUrQ.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js → escalation-items-7WFpPo46.js} +2 -2
- package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js.map → escalation-items-7WFpPo46.js.map} +1 -1
- package/dashboard/dist/assets/index-B9uv-euR.css +1 -0
- package/dashboard/dist/assets/{index-DhSCCpqM.js → index-B_XV1rwu.js} +2 -2
- package/dashboard/dist/assets/{index-DhSCCpqM.js.map → index-B_XV1rwu.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cx8xb-oU.js → index-C2CLfGwL.js} +2 -2
- package/dashboard/dist/assets/{index-Cx8xb-oU.js.map → index-C2CLfGwL.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cga5IW3D.js → index-C3AeFihz.js} +2 -2
- package/dashboard/dist/assets/{index-Cga5IW3D.js.map → index-C3AeFihz.js.map} +1 -1
- package/dashboard/dist/assets/{index-DiaRlFYI.js → index-CBri8fYM.js} +2 -2
- package/dashboard/dist/assets/{index-DiaRlFYI.js.map → index-CBri8fYM.js.map} +1 -1
- package/dashboard/dist/assets/{index-CL_1VpGb.js → index-CRWsB7ZC.js} +2 -2
- package/dashboard/dist/assets/{index-CL_1VpGb.js.map → index-CRWsB7ZC.js.map} +1 -1
- package/dashboard/dist/assets/{index-XntldBd0.js → index-CTOv3G7a.js} +2 -2
- package/dashboard/dist/assets/{index-XntldBd0.js.map → index-CTOv3G7a.js.map} +1 -1
- package/dashboard/dist/assets/{index-CfP2nKRc.js → index-CcArGkzI.js} +3 -3
- package/dashboard/dist/assets/{index-CfP2nKRc.js.map → index-CcArGkzI.js.map} +1 -1
- package/dashboard/dist/assets/{index-Dz6R8-Dw.js → index-CkMHS-hG.js} +25 -25
- package/dashboard/dist/assets/index-CkMHS-hG.js.map +1 -0
- package/dashboard/dist/assets/index-CmsmwCyv.js +2 -0
- package/dashboard/dist/assets/{index-4YaDUcKd.js.map → index-CmsmwCyv.js.map} +1 -1
- package/dashboard/dist/assets/{index-2SM2_onB.js → index-CvJsvqIc.js} +2 -2
- package/dashboard/dist/assets/{index-2SM2_onB.js.map → index-CvJsvqIc.js.map} +1 -1
- package/dashboard/dist/assets/{index-Rwqrflm-.js → index-D-ilRyfy.js} +2 -2
- package/dashboard/dist/assets/{index-Rwqrflm-.js.map → index-D-ilRyfy.js.map} +1 -1
- package/dashboard/dist/assets/{index-CZ7A3AcD.js → index-DSUtfDXx.js} +2 -2
- package/dashboard/dist/assets/{index-CZ7A3AcD.js.map → index-DSUtfDXx.js.map} +1 -1
- package/dashboard/dist/assets/{index-jL2K6us4.js → index-Da6ycKyf.js} +2 -2
- package/dashboard/dist/assets/{index-jL2K6us4.js.map → index-Da6ycKyf.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-CeUqGPuo.js → knowledge-Bpbg20DC.js} +2 -2
- package/dashboard/dist/assets/{knowledge-CeUqGPuo.js.map → knowledge-Bpbg20DC.js.map} +1 -1
- package/dashboard/dist/assets/machines-BqOZZU-3.js +2 -0
- package/dashboard/dist/assets/machines-BqOZZU-3.js.map +1 -0
- package/dashboard/dist/assets/{mcp-Cx96NTeD.js → mcp-CmcUXYce.js} +2 -2
- package/dashboard/dist/assets/{mcp-Cx96NTeD.js.map → mcp-CmcUXYce.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js → mcp-query-C8buQxN9.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js.map → mcp-query-C8buQxN9.js.map} +1 -1
- package/dashboard/dist/assets/{personas--4kjwyOw.js → personas-C2n5oDmY.js} +2 -2
- package/dashboard/dist/assets/{personas--4kjwyOw.js.map → personas-C2n5oDmY.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-PgkwvG7f.js → pipelines-RKpSkFz7.js} +2 -2
- package/dashboard/dist/assets/{pipelines-PgkwvG7f.js.map → pipelines-RKpSkFz7.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-CcYxdBa3.js → tasks-Dab4hExW.js} +2 -2
- package/dashboard/dist/assets/{tasks-CcYxdBa3.js.map → tasks-Dab4hExW.js.map} +1 -1
- package/dashboard/dist/assets/{topics-_lik7cNY.js → topics-FTMNP7r3.js} +2 -2
- package/dashboard/dist/assets/{topics-_lik7cNY.js.map → topics-FTMNP7r3.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js → useDebouncedValue-B_1u1YIk.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js.map → useDebouncedValue-B_1u1YIk.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js → useNamespace-HUeAI7Qb.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js.map → useNamespace-HUeAI7Qb.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js → useYamlActivityEvents-Cax54qHH.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js.map → useYamlActivityEvents-Cax54qHH.js.map} +1 -1
- package/dashboard/dist/assets/{validate-FlXCBBT6.js → validate-DxOaV7QS.js} +2 -2
- package/dashboard/dist/assets/{validate-FlXCBBT6.js.map → validate-DxOaV7QS.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-DUYcKTjP.js → vendor-icons-fxBvvHBi.js} +187 -182
- package/dashboard/dist/assets/vendor-icons-fxBvvHBi.js.map +1 -0
- package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js → yaml-workflows-BgY1XHJx.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js.map → yaml-workflows-BgY1XHJx.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/architecture.md +1 -0
- package/docs/code-owned-configuration.md +6 -0
- package/docs/dashboard.md +2 -1
- package/docs/events.md +34 -1
- package/docs/hitl/lookups.md +6 -4
- package/docs/machines.md +114 -28
- package/docs/mcp.md +19 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/AgentsPage-C9UuUKhr.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-DrvfXz70.js +0 -2
- package/dashboard/dist/assets/FilterBar-BygWrnB1.js +0 -2
- package/dashboard/dist/assets/FilterBar-BygWrnB1.js.map +0 -1
- package/dashboard/dist/assets/McpRunDetailPage-80fQn9iX.js +0 -2
- package/dashboard/dist/assets/WorkflowExecutionPage-Di08wCbs.js +0 -2
- package/dashboard/dist/assets/index-4YaDUcKd.js +0 -2
- package/dashboard/dist/assets/index-CnU7Jjz3.css +0 -1
- package/dashboard/dist/assets/index-Dz6R8-Dw.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-DUYcKTjP.js.map +0 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The last wire events of a line, kept by its leader so a client reads the
|
|
4
|
+
* tape over HTTP instead of the event stream. A ring of a fixed size; reads
|
|
5
|
+
* are newest first and may narrow by machine, direction, kind and time.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.WireWindow = exports.MAX_WIRE_PAGE = exports.DEFAULT_WIRE_WINDOW = void 0;
|
|
9
|
+
exports.isWireDirection = isWireDirection;
|
|
10
|
+
exports.isWireKind = isWireKind;
|
|
11
|
+
exports.DEFAULT_WIRE_WINDOW = 500;
|
|
12
|
+
exports.MAX_WIRE_PAGE = 500;
|
|
13
|
+
class WireWindow {
|
|
14
|
+
constructor(size = exports.DEFAULT_WIRE_WINDOW) {
|
|
15
|
+
this.size = size;
|
|
16
|
+
this.events = [];
|
|
17
|
+
this.head = 0;
|
|
18
|
+
this.count = 0;
|
|
19
|
+
if (!Number.isInteger(size) || size < 1)
|
|
20
|
+
throw new Error(`a wire window keeps at least one event (got ${size})`);
|
|
21
|
+
}
|
|
22
|
+
push(event) {
|
|
23
|
+
this.events[this.head] = event;
|
|
24
|
+
this.head = (this.head + 1) % this.size;
|
|
25
|
+
if (this.count < this.size)
|
|
26
|
+
this.count += 1;
|
|
27
|
+
}
|
|
28
|
+
/** Newest first, narrowed by the query, at most `limit` (the window's size when absent). */
|
|
29
|
+
read(query = {}) {
|
|
30
|
+
const limit = Math.min(Math.max(1, query.limit ?? this.size), exports.MAX_WIRE_PAGE);
|
|
31
|
+
const out = [];
|
|
32
|
+
for (let i = 1; i <= this.count && out.length < limit; i++) {
|
|
33
|
+
const event = this.events[(this.head - i + this.size) % this.size];
|
|
34
|
+
if (matches(event, query))
|
|
35
|
+
out.push(event);
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
get length() {
|
|
40
|
+
return this.count;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.WireWindow = WireWindow;
|
|
44
|
+
function matches(event, q) {
|
|
45
|
+
if (q.machine && event.machineId !== q.machine)
|
|
46
|
+
return false;
|
|
47
|
+
if (q.direction && event.direction !== q.direction)
|
|
48
|
+
return false;
|
|
49
|
+
if (q.kind && event.kind !== q.kind)
|
|
50
|
+
return false;
|
|
51
|
+
if (q.since && event.at <= q.since)
|
|
52
|
+
return false;
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
function isWireDirection(v) {
|
|
56
|
+
return v === 'in' || v === 'out';
|
|
57
|
+
}
|
|
58
|
+
const KINDS = ['presence', 'snapshot', 'job', 'alarm', 'telemetry', 'report', 'cmd', 'reply', 'receipt', 'unknown'];
|
|
59
|
+
function isWireKind(v) {
|
|
60
|
+
return typeof v === 'string' && KINDS.includes(v);
|
|
61
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire record. Every message a gateway reads, and every command,
|
|
3
|
+
* snapshot request and receipt it sends, becomes one WireEvent for the
|
|
4
|
+
* line's view: what was on the wire, how the codec read it, and what the
|
|
5
|
+
* gateway did about it. Telemetry is left out unless the line asks for it.
|
|
6
|
+
*/
|
|
7
|
+
import { type Inspection, type MachineCommand, type MachineIdent, type WireMessage } from '../../../lib/machines/protocol';
|
|
8
|
+
import { type InboundMessage } from '../../../lib/machines/transport';
|
|
9
|
+
import type { WireAction, WireEvent } from '../../../types/machines-view';
|
|
10
|
+
import type { Action } from './actions';
|
|
11
|
+
import type { Applied } from './admission';
|
|
12
|
+
export type WireSink = (event: WireEvent) => void;
|
|
13
|
+
export declare const WIRE_EVENT_TYPE = "machine.wire";
|
|
14
|
+
export declare const WIRE_DIRECTION: {
|
|
15
|
+
readonly IN: "in";
|
|
16
|
+
readonly OUT: "out";
|
|
17
|
+
};
|
|
18
|
+
export interface WireOptions {
|
|
19
|
+
/** Publish telemetry messages too. */
|
|
20
|
+
telemetry?: boolean;
|
|
21
|
+
}
|
|
22
|
+
interface WireLine {
|
|
23
|
+
siteId: string;
|
|
24
|
+
lineId: string;
|
|
25
|
+
}
|
|
26
|
+
/** The sender a message was read as, when it differs from the topic's. */
|
|
27
|
+
export interface WireSender {
|
|
28
|
+
machineId: string | null;
|
|
29
|
+
address: string | null;
|
|
30
|
+
}
|
|
31
|
+
export declare class WireRecorder {
|
|
32
|
+
private readonly line;
|
|
33
|
+
private readonly sink;
|
|
34
|
+
private readonly opts;
|
|
35
|
+
constructor(line: WireLine, sink: WireSink, opts?: WireOptions);
|
|
36
|
+
/** A decoded inbound message and what the gateway did with it. */
|
|
37
|
+
inbound(msg: InboundMessage, seen: Inspection, applied: Applied, deliveries: number, sender?: WireSender): void;
|
|
38
|
+
/** A message the codec could not read, or one that is not a machine's. */
|
|
39
|
+
unreadable(msg: InboundMessage, detail: string, verb?: WireAction['verb']): void;
|
|
40
|
+
/** A command the gateway sent, as the codec put it on the wire. */
|
|
41
|
+
command(ident: MachineIdent, command: MachineCommand, wire: WireMessage): void;
|
|
42
|
+
/** A receipt confirming the messages the gateway is done with. */
|
|
43
|
+
receipt(ident: MachineIdent, ids: string[], wire: WireMessage): void;
|
|
44
|
+
private outbound;
|
|
45
|
+
}
|
|
46
|
+
/** The event name within the kind: job event, alarm action, command op, reply status. */
|
|
47
|
+
export declare function eventOf(seen: Inspection): string | null;
|
|
48
|
+
/** One line from the kind, the event and the ids the body names. */
|
|
49
|
+
export declare function summarize(seen: Inspection): string;
|
|
50
|
+
/** The record of an inbound message before the gateway's actions are known. */
|
|
51
|
+
export declare function describeInbound(line: WireLine, msg: InboundMessage, seen: Inspection, sender?: WireSender): Omit<WireEvent, 'actions'>;
|
|
52
|
+
/** What handling a message came to, as actions; a message with none is acknowledged, or waits for its row. */
|
|
53
|
+
export declare function appliedActions(applied: Applied, deliveries: number, maxDeliveries?: number): WireAction[];
|
|
54
|
+
/** A message no row has claimed after this many deliveries is not racing its row. */
|
|
55
|
+
export declare const MAX_DELIVERIES = 30;
|
|
56
|
+
/** A planner action as the wire would record it, before it runs; a dry run shows these. */
|
|
57
|
+
export declare function plannedAction(a: Action): WireAction;
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The wire record. Every message a gateway reads, and every command,
|
|
4
|
+
* snapshot request and receipt it sends, becomes one WireEvent for the
|
|
5
|
+
* line's view: what was on the wire, how the codec read it, and what the
|
|
6
|
+
* gateway did about it. Telemetry is left out unless the line asks for it.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.MAX_DELIVERIES = exports.WireRecorder = exports.WIRE_DIRECTION = exports.WIRE_EVENT_TYPE = void 0;
|
|
10
|
+
exports.eventOf = eventOf;
|
|
11
|
+
exports.summarize = summarize;
|
|
12
|
+
exports.describeInbound = describeInbound;
|
|
13
|
+
exports.appliedActions = appliedActions;
|
|
14
|
+
exports.plannedAction = plannedAction;
|
|
15
|
+
const protocol_1 = require("../../../lib/machines/protocol");
|
|
16
|
+
const transport_1 = require("../../../lib/machines/transport");
|
|
17
|
+
exports.WIRE_EVENT_TYPE = 'machine.wire';
|
|
18
|
+
exports.WIRE_DIRECTION = { IN: 'in', OUT: 'out' };
|
|
19
|
+
const RECEIPT_CHANNEL = 'receipt';
|
|
20
|
+
const ALARM_EVENT = { RAISED: 'raised', ACKED: 'acked', CLEARED: 'cleared' };
|
|
21
|
+
const PRESENCE_EVENT = { ONLINE: 'online', OFFLINE: 'offline' };
|
|
22
|
+
class WireRecorder {
|
|
23
|
+
constructor(line, sink, opts = {}) {
|
|
24
|
+
this.line = line;
|
|
25
|
+
this.sink = sink;
|
|
26
|
+
this.opts = opts;
|
|
27
|
+
}
|
|
28
|
+
/** A decoded inbound message and what the gateway did with it. */
|
|
29
|
+
inbound(msg, seen, applied, deliveries, sender) {
|
|
30
|
+
if (seen.parsed?.kind === protocol_1.MESSAGE_KIND.TELEMETRY && !this.opts.telemetry)
|
|
31
|
+
return;
|
|
32
|
+
this.sink({ ...describeInbound(this.line, msg, seen, sender), actions: appliedActions(applied, deliveries) });
|
|
33
|
+
}
|
|
34
|
+
/** A message the codec could not read, or one that is not a machine's. */
|
|
35
|
+
unreadable(msg, detail, verb = 'unreadable') {
|
|
36
|
+
this.sink({
|
|
37
|
+
...describeInbound(this.line, msg, { parsed: null, body: null, violations: [] }),
|
|
38
|
+
summary: detail, actions: [{ verb, detail }],
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/** A command the gateway sent, as the codec put it on the wire. */
|
|
42
|
+
command(ident, command, wire) {
|
|
43
|
+
const jobId = typeof command.args.jobId === 'string' ? ` ${command.args.jobId}` : '';
|
|
44
|
+
this.sink(this.outbound(ident, wire, protocol_1.MESSAGE_KIND.CMD, protocol_1.CHANNEL.CMD, command.op, `cmd ${command.op}${jobId} ${command.cmdId}`));
|
|
45
|
+
}
|
|
46
|
+
/** A receipt confirming the messages the gateway is done with. */
|
|
47
|
+
receipt(ident, ids, wire) {
|
|
48
|
+
this.sink(this.outbound(ident, wire, 'receipt', RECEIPT_CHANNEL, null, `receipt for ${ids.length} message${ids.length === 1 ? '' : 's'}`));
|
|
49
|
+
}
|
|
50
|
+
outbound(ident, wire, kind, channel, event, summary) {
|
|
51
|
+
const body = parseJson(wire.payload);
|
|
52
|
+
return {
|
|
53
|
+
type: exports.WIRE_EVENT_TYPE, siteId: this.line.siteId, lineId: this.line.lineId, machineId: ident.machineId, address: (0, protocol_1.addressOf)(ident),
|
|
54
|
+
direction: exports.WIRE_DIRECTION.OUT, channel, topic: wire.topic, id: typeof body?.id === 'string' ? body.id : null,
|
|
55
|
+
at: typeof body?.at === 'string' ? body.at : (0, protocol_1.isoTs)(), retained: false, kind, event, summary, violations: [], actions: [], payload: body ?? wire.payload,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.WireRecorder = WireRecorder;
|
|
60
|
+
function parseJson(payload) {
|
|
61
|
+
try {
|
|
62
|
+
const parsed = JSON.parse(payload);
|
|
63
|
+
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** The line-protocol channel a decoded message belongs to. */
|
|
70
|
+
function channelOf(seen) {
|
|
71
|
+
const parsed = seen.parsed;
|
|
72
|
+
if (!parsed)
|
|
73
|
+
return '';
|
|
74
|
+
switch (parsed.kind) {
|
|
75
|
+
case protocol_1.MESSAGE_KIND.ALARM: return `${protocol_1.CHANNEL.ALARM}/${parsed.key ?? ''}`;
|
|
76
|
+
case protocol_1.MESSAGE_KIND.REPORT: return `${protocol_1.CHANNEL.REPORT}/${parsed.key ?? ''}`;
|
|
77
|
+
case protocol_1.MESSAGE_KIND.REPLY: return protocol_1.CHANNEL.REPLY;
|
|
78
|
+
default: return parsed.kind;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** The event name within the kind: job event, alarm action, command op, reply status. */
|
|
82
|
+
function eventOf(seen) {
|
|
83
|
+
const parsed = seen.parsed;
|
|
84
|
+
const b = seen.body?.body ?? {};
|
|
85
|
+
if (!parsed)
|
|
86
|
+
return null;
|
|
87
|
+
switch (parsed.kind) {
|
|
88
|
+
case protocol_1.MESSAGE_KIND.JOB: return typeof b.event === 'string' ? b.event : null;
|
|
89
|
+
case protocol_1.MESSAGE_KIND.ALARM: return !seen.body || b.active === false ? ALARM_EVENT.CLEARED : b.ackedBy ? ALARM_EVENT.ACKED : ALARM_EVENT.RAISED;
|
|
90
|
+
case protocol_1.MESSAGE_KIND.CMD: return typeof b.op === 'string' ? b.op : null;
|
|
91
|
+
case protocol_1.MESSAGE_KIND.REPLY: return typeof b.status === 'string' ? b.status : null;
|
|
92
|
+
case protocol_1.MESSAGE_KIND.PRESENCE: return b.online === true ? PRESENCE_EVENT.ONLINE : PRESENCE_EVENT.OFFLINE;
|
|
93
|
+
case protocol_1.MESSAGE_KIND.SNAPSHOT: return typeof b.mode === 'string' ? b.mode : null;
|
|
94
|
+
case protocol_1.MESSAGE_KIND.REPORT: return parsed.key ?? null;
|
|
95
|
+
default: return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const count = (n, word) => `${n} ${word}${n === 1 ? '' : 's'}`;
|
|
99
|
+
/** One line from the kind, the event and the ids the body names. */
|
|
100
|
+
function summarize(seen) {
|
|
101
|
+
const parsed = seen.parsed;
|
|
102
|
+
if (!parsed)
|
|
103
|
+
return 'not a machine message';
|
|
104
|
+
const b = seen.body?.body ?? {};
|
|
105
|
+
const event = eventOf(seen);
|
|
106
|
+
switch (parsed.kind) {
|
|
107
|
+
case protocol_1.MESSAGE_KIND.PRESENCE:
|
|
108
|
+
return ['presence', event, b.software, b.reason ? `(${b.reason})` : null].filter(Boolean).join(' ');
|
|
109
|
+
case protocol_1.MESSAGE_KIND.SNAPSHOT:
|
|
110
|
+
return ['snapshot', event, count(Array.isArray(b.jobs) ? b.jobs.length : 0, 'job'), Array.isArray(b.alarms) && b.alarms.length ? count(b.alarms.length, 'alarm') : null].filter(Boolean).join(' ');
|
|
111
|
+
case protocol_1.MESSAGE_KIND.JOB:
|
|
112
|
+
return ['job', event, b.unitId ?? (b.carrierId ? `carrier ${b.carrierId}` : null), b.jobId ? `(${b.jobId})` : null, b.result, b.failure].filter(Boolean).join(' ');
|
|
113
|
+
case protocol_1.MESSAGE_KIND.ALARM:
|
|
114
|
+
return ['alarm', event, parsed.key ?? b.alarmId, b.level, b.text ? `: ${b.text}` : null].filter(Boolean).join(' ');
|
|
115
|
+
case protocol_1.MESSAGE_KIND.TELEMETRY:
|
|
116
|
+
return `telemetry ${count(Object.keys(b.readings ?? {}).length, 'reading')}`;
|
|
117
|
+
case protocol_1.MESSAGE_KIND.CMD:
|
|
118
|
+
return ['cmd', event, b.args?.jobId, b.cmdId].filter(Boolean).join(' ');
|
|
119
|
+
case protocol_1.MESSAGE_KIND.REPLY:
|
|
120
|
+
return ['reply', event, b.cmdId, b.reason ? `: ${b.reason}` : null].filter(Boolean).join(' ');
|
|
121
|
+
case protocol_1.MESSAGE_KIND.REPORT:
|
|
122
|
+
return `report ${parsed.key ?? ''}`.trim();
|
|
123
|
+
default:
|
|
124
|
+
return parsed.kind;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/** The record of an inbound message before the gateway's actions are known. */
|
|
128
|
+
function describeInbound(line, msg, seen, sender) {
|
|
129
|
+
const ident = seen.parsed?.ident;
|
|
130
|
+
return {
|
|
131
|
+
type: exports.WIRE_EVENT_TYPE, siteId: line.siteId, lineId: line.lineId,
|
|
132
|
+
machineId: sender ? sender.machineId : ident?.machineId ?? null,
|
|
133
|
+
address: sender ? sender.address : ident ? (0, protocol_1.addressOf)(ident) : null,
|
|
134
|
+
direction: exports.WIRE_DIRECTION.IN, channel: channelOf(seen), topic: msg.topic,
|
|
135
|
+
id: seen.body?.id ?? null, at: seen.body?.at ?? (0, protocol_1.isoTs)(), retained: msg.retained === true,
|
|
136
|
+
kind: seen.parsed?.kind ?? 'unknown', event: eventOf(seen), summary: summarize(seen),
|
|
137
|
+
violations: seen.violations, payload: seen.body ?? msg.payload,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/** What handling a message came to, as actions; a message with none is acknowledged, or waits for its row. */
|
|
141
|
+
function appliedActions(applied, deliveries, maxDeliveries = exports.MAX_DELIVERIES) {
|
|
142
|
+
if (applied.actions.length)
|
|
143
|
+
return applied.actions;
|
|
144
|
+
if (applied.disposition !== transport_1.DISPOSITION.NAK)
|
|
145
|
+
return [{ verb: 'ack' }];
|
|
146
|
+
if (applied.failed)
|
|
147
|
+
return [{ verb: 'none', detail: 'a verb failed; the message is delivered again' }];
|
|
148
|
+
if (deliveries >= maxDeliveries)
|
|
149
|
+
return [{ verb: 'unmatched', detail: `no row after ${deliveries} deliveries` }];
|
|
150
|
+
return [{ verb: 'none', detail: `waiting for its row (delivery ${deliveries})` }];
|
|
151
|
+
}
|
|
152
|
+
/** A message no row has claimed after this many deliveries is not racing its row. */
|
|
153
|
+
exports.MAX_DELIVERIES = 30;
|
|
154
|
+
/** A planner action as the wire would record it, before it runs; a dry run shows these. */
|
|
155
|
+
function plannedAction(a) {
|
|
156
|
+
switch (a.kind) {
|
|
157
|
+
case 'dispatch': return { verb: 'none', detail: `dispatch ${a.args.jobId ?? a.cmdId} to ${a.machineId}` };
|
|
158
|
+
case 'command': return { verb: 'none', detail: `${a.op} to ${a.machineId}` };
|
|
159
|
+
case 'control': return { verb: 'none', rowId: a.rowId, detail: `${a.op} to ${a.machineId}` };
|
|
160
|
+
case 'claim': return { verb: 'claim', rowId: a.rowId };
|
|
161
|
+
case 'accumulate': return { verb: 'accumulate', rowId: a.rowId, itemKey: a.itemKey };
|
|
162
|
+
case 'resolve': return { verb: 'resolve', rowId: a.rowId };
|
|
163
|
+
case 'createAlarmRow': return { verb: 'create-row', detail: `${a.row.type} for ${a.machineId}` };
|
|
164
|
+
case 'createRow': return { verb: 'create-row', detail: a.row.type };
|
|
165
|
+
case 'watchOffline': return { verb: 'none', detail: `watching ${a.machineId} for an offline row` };
|
|
166
|
+
case 'settleReply': return { verb: 'ack', detail: `${a.status} ${a.cmdId}` };
|
|
167
|
+
case 'settleSnapshot': return { verb: 'ack', detail: `${a.machineId} holds ${count(a.jobIds.length, 'job')}` };
|
|
168
|
+
case 'unrecoverable': return { verb: 'none', detail: `${a.machineId} lost ${a.jobs.join(', ')}; nothing remembered to send again` };
|
|
169
|
+
case 'bindAddress': return { verb: 'ack', detail: `bind ${a.machineId} to ${a.address}` };
|
|
170
|
+
case 'refuseBinding': return { verb: 'refuse', detail: a.reason };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -7,5 +7,8 @@ export * from './gateway';
|
|
|
7
7
|
export * from './roles';
|
|
8
8
|
export * from './identities';
|
|
9
9
|
export * from './surface';
|
|
10
|
+
export * from './registry';
|
|
11
|
+
export * from './registry-sync';
|
|
10
12
|
export * from './rows';
|
|
11
13
|
export * from '../../lib/machines';
|
|
14
|
+
export type * from '../../types/machines-view';
|
|
@@ -23,5 +23,7 @@ __exportStar(require("./gateway"), exports);
|
|
|
23
23
|
__exportStar(require("./roles"), exports);
|
|
24
24
|
__exportStar(require("./identities"), exports);
|
|
25
25
|
__exportStar(require("./surface"), exports);
|
|
26
|
+
__exportStar(require("./registry"), exports);
|
|
27
|
+
__exportStar(require("./registry-sync"), exports);
|
|
26
28
|
__exportStar(require("./rows"), exports);
|
|
27
29
|
__exportStar(require("../../lib/machines"), exports);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The lines index as the API and the MCP server present it: a registry row
|
|
3
|
+
* joined with what the running surface knows about the line.
|
|
4
|
+
*/
|
|
5
|
+
import type { LineDef } from '../../lib/machines/line';
|
|
6
|
+
import type { LineHealth, LineIndexRow, LineSummary } from '../../types/machines-view';
|
|
7
|
+
import type { LineRecordWithHealth } from './registry';
|
|
8
|
+
import { type LineSurface } from './surface';
|
|
9
|
+
/** The line as every replica describes it: the surface's own summary when it runs the line, else the stored definition. */
|
|
10
|
+
export declare function lineSummaryOf(surface: LineSurface, siteId: string, lineId: string, stored: LineDef): LineSummary;
|
|
11
|
+
/** A registry row as the index shows it. */
|
|
12
|
+
export declare function toLineIndexRow(surface: LineSurface, record: LineRecordWithHealth): LineIndexRow;
|
|
13
|
+
/** Health for a line no pending row names yet. */
|
|
14
|
+
export declare function emptyLineHealth(machines: number): LineHealth;
|
|
15
|
+
/** The raw wire payload as a string: an object is serialized, text passes through. */
|
|
16
|
+
export declare function wirePayloadOf(body: unknown): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The lines index as the API and the MCP server present it: a registry row
|
|
4
|
+
* joined with what the running surface knows about the line.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.lineSummaryOf = lineSummaryOf;
|
|
8
|
+
exports.toLineIndexRow = toLineIndexRow;
|
|
9
|
+
exports.emptyLineHealth = emptyLineHealth;
|
|
10
|
+
exports.wirePayloadOf = wirePayloadOf;
|
|
11
|
+
const surface_1 = require("./surface");
|
|
12
|
+
/** The line as every replica describes it: the surface's own summary when it runs the line, else the stored definition. */
|
|
13
|
+
function lineSummaryOf(surface, siteId, lineId, stored) {
|
|
14
|
+
const running = surface.findLine(siteId, lineId)
|
|
15
|
+
? surface.describeLines().find((l) => l.siteId === siteId && l.lineId === lineId)
|
|
16
|
+
: undefined;
|
|
17
|
+
return running ?? (0, surface_1.summarizeLine)(stored, {});
|
|
18
|
+
}
|
|
19
|
+
/** A registry row as the index shows it. */
|
|
20
|
+
function toLineIndexRow(surface, record) {
|
|
21
|
+
return {
|
|
22
|
+
...lineSummaryOf(surface, record.siteId, record.lineId, record.definition),
|
|
23
|
+
source: record.source, version: record.version, enabled: record.enabled, updatedAt: record.updatedAt,
|
|
24
|
+
leading: surface.describeLine(record.siteId, record.lineId) !== null,
|
|
25
|
+
health: record.health,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Health for a line no pending row names yet. */
|
|
29
|
+
function emptyLineHealth(machines) {
|
|
30
|
+
return { machines, offline: 0, quiet: 0, alarms: 0, people: 0, handoff: 0, command: 0, attention: false };
|
|
31
|
+
}
|
|
32
|
+
/** The raw wire payload as a string: an object is serialized, text passes through. */
|
|
33
|
+
function wirePayloadOf(body) {
|
|
34
|
+
if (typeof body === 'string')
|
|
35
|
+
return body;
|
|
36
|
+
if (body === undefined || body === null)
|
|
37
|
+
return '';
|
|
38
|
+
return JSON.stringify(body);
|
|
39
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The line registry's statements. Every write is one statement: the
|
|
3
|
+
* version advances in the same UPDATE that changes the row, and a version
|
|
4
|
+
* check rides the WHERE so a stale writer gets zero rows back.
|
|
5
|
+
*/
|
|
6
|
+
export declare const LINE_SOURCE: {
|
|
7
|
+
readonly CODE: "code";
|
|
8
|
+
readonly API: "api";
|
|
9
|
+
};
|
|
10
|
+
/** An API write: insert, or replace and advance the version; $5 non-null requires that version. */
|
|
11
|
+
export declare const UPSERT_API_LINE: string;
|
|
12
|
+
/** A db-owned code line: first writer wins, an existing row is left as it is. */
|
|
13
|
+
export declare const SEED_CODE_LINE: string;
|
|
14
|
+
/** A code-owned code line: written only when the definition or the owner differs, one version per change. */
|
|
15
|
+
export declare const APPLY_CODE_LINE: string;
|
|
16
|
+
export declare const GET_LINE = "SELECT site_id, line_id, definition, source, version, enabled, search_text, created_at, updated_at FROM lt_machine_lines WHERE site_id = $1 AND line_id = $2";
|
|
17
|
+
export declare const DELETE_LINE = "DELETE FROM lt_machine_lines WHERE site_id = $1 AND line_id = $2 RETURNING site_id, line_id, definition, source, version, enabled, search_text, created_at, updated_at";
|
|
18
|
+
export declare const LIST_ENABLED_LINES = "SELECT site_id, line_id, definition, source, version, enabled, search_text, created_at, updated_at FROM lt_machine_lines WHERE enabled ORDER BY site_id, line_id";
|
|
19
|
+
export declare const LIST_CODE_LINES: string;
|
|
20
|
+
/** The kinds of pending rows the index counts, in the order the health CTE projects them. */
|
|
21
|
+
export declare const HEALTH_ROW_TYPES: readonly ["machine-offline", "machine-quiet", "line-alarm", "handoff-error", "contract-violation", "machine-registration", "handoff", "machine-command"];
|
|
22
|
+
/** The index's order, by name; attention first within each. */
|
|
23
|
+
export declare const LINE_ORDER: Record<string, string>;
|
|
24
|
+
/**
|
|
25
|
+
* One page of the index: $1 row types, $2 search pattern or null, $3 site
|
|
26
|
+
* or null, $4 attention or null, $5 limit, $6 offset, $7 line or null. The
|
|
27
|
+
* total rides every row as a window count.
|
|
28
|
+
*/
|
|
29
|
+
export declare function listLinesSql(order: string): string;
|
|
30
|
+
/** Every site, with its lines and how many need attention: $1 row types. */
|
|
31
|
+
export declare const LIST_SITES: string;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The line registry's statements. Every write is one statement: the
|
|
4
|
+
* version advances in the same UPDATE that changes the row, and a version
|
|
5
|
+
* check rides the WHERE so a stale writer gets zero rows back.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.LIST_SITES = exports.LINE_ORDER = exports.HEALTH_ROW_TYPES = exports.LIST_CODE_LINES = exports.LIST_ENABLED_LINES = exports.DELETE_LINE = exports.GET_LINE = exports.APPLY_CODE_LINE = exports.SEED_CODE_LINE = exports.UPSERT_API_LINE = exports.LINE_SOURCE = void 0;
|
|
9
|
+
exports.listLinesSql = listLinesSql;
|
|
10
|
+
const contracts_1 = require("./contracts");
|
|
11
|
+
exports.LINE_SOURCE = { CODE: 'code', API: 'api' };
|
|
12
|
+
const COLUMNS = 'site_id, line_id, definition, source, version, enabled, search_text, created_at, updated_at';
|
|
13
|
+
/** An API write: insert, or replace and advance the version; $5 non-null requires that version. */
|
|
14
|
+
exports.UPSERT_API_LINE = `
|
|
15
|
+
INSERT INTO lt_machine_lines (site_id, line_id, definition, source, search_text)
|
|
16
|
+
VALUES ($1, $2, $3::jsonb, '${exports.LINE_SOURCE.API}', $4)
|
|
17
|
+
ON CONFLICT (site_id, line_id) DO UPDATE
|
|
18
|
+
SET definition = EXCLUDED.definition,
|
|
19
|
+
source = '${exports.LINE_SOURCE.API}',
|
|
20
|
+
search_text = EXCLUDED.search_text,
|
|
21
|
+
enabled = true,
|
|
22
|
+
version = lt_machine_lines.version + 1,
|
|
23
|
+
updated_at = NOW()
|
|
24
|
+
WHERE $5::int IS NULL OR lt_machine_lines.version = $5::int
|
|
25
|
+
RETURNING ${COLUMNS}`;
|
|
26
|
+
/** A db-owned code line: first writer wins, an existing row is left as it is. */
|
|
27
|
+
exports.SEED_CODE_LINE = `
|
|
28
|
+
INSERT INTO lt_machine_lines (site_id, line_id, definition, source, search_text)
|
|
29
|
+
VALUES ($1, $2, $3::jsonb, '${exports.LINE_SOURCE.CODE}', $4)
|
|
30
|
+
ON CONFLICT (site_id, line_id) DO NOTHING
|
|
31
|
+
RETURNING ${COLUMNS}`;
|
|
32
|
+
/** A code-owned code line: written only when the definition or the owner differs, one version per change. */
|
|
33
|
+
exports.APPLY_CODE_LINE = `
|
|
34
|
+
INSERT INTO lt_machine_lines (site_id, line_id, definition, source, search_text)
|
|
35
|
+
VALUES ($1, $2, $3::jsonb, '${exports.LINE_SOURCE.CODE}', $4)
|
|
36
|
+
ON CONFLICT (site_id, line_id) DO UPDATE
|
|
37
|
+
SET definition = EXCLUDED.definition,
|
|
38
|
+
source = '${exports.LINE_SOURCE.CODE}',
|
|
39
|
+
search_text = EXCLUDED.search_text,
|
|
40
|
+
enabled = true,
|
|
41
|
+
version = lt_machine_lines.version + 1,
|
|
42
|
+
updated_at = NOW()
|
|
43
|
+
WHERE lt_machine_lines.definition IS DISTINCT FROM EXCLUDED.definition
|
|
44
|
+
OR lt_machine_lines.source <> '${exports.LINE_SOURCE.CODE}'
|
|
45
|
+
OR NOT lt_machine_lines.enabled
|
|
46
|
+
RETURNING ${COLUMNS}`;
|
|
47
|
+
exports.GET_LINE = `SELECT ${COLUMNS} FROM lt_machine_lines WHERE site_id = $1 AND line_id = $2`;
|
|
48
|
+
exports.DELETE_LINE = `DELETE FROM lt_machine_lines WHERE site_id = $1 AND line_id = $2 RETURNING ${COLUMNS}`;
|
|
49
|
+
exports.LIST_ENABLED_LINES = `SELECT ${COLUMNS} FROM lt_machine_lines WHERE enabled ORDER BY site_id, line_id`;
|
|
50
|
+
exports.LIST_CODE_LINES = `SELECT site_id, line_id FROM lt_machine_lines WHERE source = '${exports.LINE_SOURCE.CODE}'`;
|
|
51
|
+
/** The kinds of pending rows the index counts, in the order the health CTE projects them. */
|
|
52
|
+
exports.HEALTH_ROW_TYPES = [
|
|
53
|
+
contracts_1.ROW_TYPE.MACHINE_OFFLINE, contracts_1.ROW_TYPE.MACHINE_QUIET, contracts_1.ROW_TYPE.ALARM,
|
|
54
|
+
contracts_1.ROW_TYPE.HANDOFF_ERROR, contracts_1.ROW_TYPE.CONTRACT_VIOLATION, contracts_1.ROW_TYPE.MACHINE_REGISTRATION,
|
|
55
|
+
contracts_1.ROW_TYPE.HANDOFF, contracts_1.ROW_TYPE.MACHINE_COMMAND,
|
|
56
|
+
];
|
|
57
|
+
const PENDING = 'pending';
|
|
58
|
+
/** Pending rows per line, counted by kind: $1 is the list of row types. */
|
|
59
|
+
const HEALTH_CTE = `
|
|
60
|
+
health AS (
|
|
61
|
+
SELECT metadata->>'siteId' AS site_id, metadata->>'lineId' AS line_id,
|
|
62
|
+
COUNT(*) FILTER (WHERE type = '${contracts_1.ROW_TYPE.MACHINE_OFFLINE}')::int AS offline,
|
|
63
|
+
COUNT(*) FILTER (WHERE type = '${contracts_1.ROW_TYPE.MACHINE_QUIET}')::int AS quiet,
|
|
64
|
+
COUNT(*) FILTER (WHERE type = '${contracts_1.ROW_TYPE.ALARM}')::int AS alarms,
|
|
65
|
+
COUNT(*) FILTER (WHERE type IN ('${contracts_1.ROW_TYPE.HANDOFF_ERROR}', '${contracts_1.ROW_TYPE.CONTRACT_VIOLATION}', '${contracts_1.ROW_TYPE.MACHINE_REGISTRATION}'))::int AS people,
|
|
66
|
+
COUNT(*) FILTER (WHERE type = '${contracts_1.ROW_TYPE.HANDOFF}')::int AS handoff,
|
|
67
|
+
COUNT(*) FILTER (WHERE type = '${contracts_1.ROW_TYPE.MACHINE_COMMAND}')::int AS command
|
|
68
|
+
FROM public.lt_escalations
|
|
69
|
+
WHERE status = '${PENDING}' AND type = ANY($1::text[]) AND metadata ? 'siteId' AND metadata ? 'lineId'
|
|
70
|
+
GROUP BY 1, 2
|
|
71
|
+
),
|
|
72
|
+
lines AS (
|
|
73
|
+
SELECT l.${COLUMNS.split(', ').join(', l.')},
|
|
74
|
+
COALESCE(h.offline, 0) AS offline, COALESCE(h.quiet, 0) AS quiet, COALESCE(h.alarms, 0) AS alarms,
|
|
75
|
+
COALESCE(h.people, 0) AS people, COALESCE(h.handoff, 0) AS handoff, COALESCE(h.command, 0) AS command,
|
|
76
|
+
(COALESCE(h.offline, 0) + COALESCE(h.alarms, 0) + COALESCE(h.people, 0)) > 0 AS attention
|
|
77
|
+
FROM lt_machine_lines l
|
|
78
|
+
LEFT JOIN health h ON h.site_id = l.site_id AND h.line_id = l.line_id
|
|
79
|
+
WHERE l.enabled
|
|
80
|
+
)`;
|
|
81
|
+
/** The index's order, by name; attention first within each. */
|
|
82
|
+
exports.LINE_ORDER = {
|
|
83
|
+
attention: 'attention DESC, (offline + alarms + people) DESC, site_id, line_id',
|
|
84
|
+
site: 'site_id, line_id',
|
|
85
|
+
updated: 'updated_at DESC, site_id, line_id',
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* One page of the index: $1 row types, $2 search pattern or null, $3 site
|
|
89
|
+
* or null, $4 attention or null, $5 limit, $6 offset, $7 line or null. The
|
|
90
|
+
* total rides every row as a window count.
|
|
91
|
+
*/
|
|
92
|
+
function listLinesSql(order) {
|
|
93
|
+
return `
|
|
94
|
+
WITH ${HEALTH_CTE}
|
|
95
|
+
SELECT *, COUNT(*) OVER() AS total
|
|
96
|
+
FROM lines
|
|
97
|
+
WHERE ($2::text IS NULL OR search_text ILIKE $2 ESCAPE '\\')
|
|
98
|
+
AND ($3::text IS NULL OR site_id = $3)
|
|
99
|
+
AND ($4::boolean IS NULL OR attention = $4)
|
|
100
|
+
AND ($7::text IS NULL OR line_id = $7)
|
|
101
|
+
ORDER BY ${order}
|
|
102
|
+
LIMIT $5 OFFSET $6`;
|
|
103
|
+
}
|
|
104
|
+
/** Every site, with its lines and how many need attention: $1 row types. */
|
|
105
|
+
exports.LIST_SITES = `
|
|
106
|
+
WITH ${HEALTH_CTE}
|
|
107
|
+
SELECT site_id, COUNT(*)::int AS lines, COUNT(*) FILTER (WHERE attention)::int AS attention
|
|
108
|
+
FROM lines
|
|
109
|
+
GROUP BY site_id
|
|
110
|
+
ORDER BY site_id`;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps the running surface in step with the line registry. A declaration
|
|
3
|
+
* through the API writes the registry, applies the line's roles, runs the
|
|
4
|
+
* line on this replica and tells every other replica, which reads the row
|
|
5
|
+
* again and follows. Boot applies the code lines the same way, then starts
|
|
6
|
+
* the surface with everything the registry holds.
|
|
7
|
+
*/
|
|
8
|
+
import type { CallbackEventAdapter } from '../../lib/events/callback';
|
|
9
|
+
import type { LineDef } from '../../lib/machines/line';
|
|
10
|
+
import { type LineApplyReport, type LineRecord } from './registry';
|
|
11
|
+
import type { LineSurface } from './surface';
|
|
12
|
+
export declare const LINE_ACTION: {
|
|
13
|
+
readonly DECLARED: "declared";
|
|
14
|
+
readonly RETIRED: "retired";
|
|
15
|
+
};
|
|
16
|
+
/** Declare a line through the API on this replica, then tell the others. */
|
|
17
|
+
export declare function declareLine(surface: LineSurface, def: LineDef, expectedVersion?: number): Promise<LineRecord>;
|
|
18
|
+
/** Retire a line on this replica and in the registry, then tell the others. Roles and bot accounts stay. */
|
|
19
|
+
export declare function retireLine(surface: LineSurface, siteId: string, lineId: string): Promise<LineRecord | null>;
|
|
20
|
+
/** Boot: apply code lines under the configSource rules, then every enabled line the registry holds. */
|
|
21
|
+
export declare function syncDeclaredLines(lines: LineDef[], codeOwned: boolean): Promise<{
|
|
22
|
+
report: LineApplyReport;
|
|
23
|
+
lines: LineDef[];
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* Follow registry changes other replicas publish. The event only names the
|
|
27
|
+
* line: the registry row is read again and decides, so a stray or stale
|
|
28
|
+
* event cannot stop a line the registry still holds. The surface ignores a
|
|
29
|
+
* line it already runs unchanged.
|
|
30
|
+
*/
|
|
31
|
+
export declare function watchLineRegistry(surface: LineSurface, callbacks: CallbackEventAdapter): () => void;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Keeps the running surface in step with the line registry. A declaration
|
|
4
|
+
* through the API writes the registry, applies the line's roles, runs the
|
|
5
|
+
* line on this replica and tells every other replica, which reads the row
|
|
6
|
+
* again and follows. Boot applies the code lines the same way, then starts
|
|
7
|
+
* the surface with everything the registry holds.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.LINE_ACTION = void 0;
|
|
11
|
+
exports.declareLine = declareLine;
|
|
12
|
+
exports.retireLine = retireLine;
|
|
13
|
+
exports.syncDeclaredLines = syncDeclaredLines;
|
|
14
|
+
exports.watchLineRegistry = watchLineRegistry;
|
|
15
|
+
const publish_1 = require("../../lib/events/publish");
|
|
16
|
+
const config_lock_1 = require("../../lib/db/config-lock");
|
|
17
|
+
const logger_1 = require("../../lib/logger");
|
|
18
|
+
const topics_1 = require("../../lib/machines/protocol/topics");
|
|
19
|
+
const seed_1 = require("../role/seed");
|
|
20
|
+
const registry_1 = require("./registry");
|
|
21
|
+
const roles_1 = require("./roles");
|
|
22
|
+
const LINE_EVENTS = 'machine.line.>';
|
|
23
|
+
const LOG = '[lt-machines]';
|
|
24
|
+
exports.LINE_ACTION = { DECLARED: 'declared', RETIRED: 'retired' };
|
|
25
|
+
/** The line's station, exit and operator roles, where the host declared none. */
|
|
26
|
+
async function applyLineRoles(line) {
|
|
27
|
+
await (0, config_lock_1.withConfigLock)(async () => {
|
|
28
|
+
for (const cfg of (0, roles_1.machineRoleConfigs)(line))
|
|
29
|
+
await (0, seed_1.applyRoleConfig)(cfg, false);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** Declare a line through the API on this replica, then tell the others. */
|
|
33
|
+
async function declareLine(surface, def, expectedVersion) {
|
|
34
|
+
const record = await (0, registry_1.declareApiLine)(def, expectedVersion);
|
|
35
|
+
await applyLineRoles(record.definition);
|
|
36
|
+
await surface.declare(record.definition);
|
|
37
|
+
await (0, publish_1.publishMachineLineEvent)({ siteId: record.siteId, lineId: record.lineId, source: record.source, version: record.version, action: exports.LINE_ACTION.DECLARED });
|
|
38
|
+
return record;
|
|
39
|
+
}
|
|
40
|
+
/** Retire a line on this replica and in the registry, then tell the others. Roles and bot accounts stay. */
|
|
41
|
+
async function retireLine(surface, siteId, lineId) {
|
|
42
|
+
const record = await (0, registry_1.deleteLine)(siteId, lineId);
|
|
43
|
+
if (!record)
|
|
44
|
+
return null;
|
|
45
|
+
await surface.retire(siteId, lineId);
|
|
46
|
+
await (0, publish_1.publishMachineLineEvent)({ siteId, lineId, source: record.source, version: record.version, action: exports.LINE_ACTION.RETIRED });
|
|
47
|
+
return record;
|
|
48
|
+
}
|
|
49
|
+
/** Boot: apply code lines under the configSource rules, then every enabled line the registry holds. */
|
|
50
|
+
async function syncDeclaredLines(lines, codeOwned) {
|
|
51
|
+
const report = await (0, config_lock_1.withConfigLock)(() => (0, registry_1.applyDeclaredLines)(lines, codeOwned));
|
|
52
|
+
const enabled = await (0, registry_1.listEnabledLines)();
|
|
53
|
+
return { report, lines: enabled.map((r) => r.definition) };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Follow registry changes other replicas publish. The event only names the
|
|
57
|
+
* line: the registry row is read again and decides, so a stray or stale
|
|
58
|
+
* event cannot stop a line the registry still holds. The surface ignores a
|
|
59
|
+
* line it already runs unchanged.
|
|
60
|
+
*/
|
|
61
|
+
function watchLineRegistry(surface, callbacks) {
|
|
62
|
+
return callbacks.on(LINE_EVENTS, (event) => {
|
|
63
|
+
const data = (event.data ?? {});
|
|
64
|
+
if (!(0, topics_1.isTopicLevel)(data.siteId) || !(0, topics_1.isTopicLevel)(data.lineId))
|
|
65
|
+
return;
|
|
66
|
+
const { siteId, lineId } = data;
|
|
67
|
+
void follow(surface, siteId, lineId).catch((err) => {
|
|
68
|
+
logger_1.loggerRegistry.warn(`${LOG} following ${siteId}/${lineId} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async function follow(surface, siteId, lineId) {
|
|
73
|
+
const record = await (0, registry_1.getLine)(siteId, lineId);
|
|
74
|
+
if (!record || !record.enabled) {
|
|
75
|
+
await surface.retire(siteId, lineId);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const outcome = await surface.declare(record.definition);
|
|
79
|
+
if (outcome !== 'unchanged')
|
|
80
|
+
logger_1.loggerRegistry.info(`${LOG} line ${siteId}/${lineId} ${outcome} from the registry (v${record.version})`);
|
|
81
|
+
}
|