@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
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* reads escalation events (a new handoff row means "dispatch"), reads every
|
|
5
5
|
* machine message on the line (a receipt means "resolve"), and performs the
|
|
6
6
|
* verbs a person would, as the machine. Neither side knows about the other.
|
|
7
|
+
* Every message read or sent is recorded on the wire (wire.ts).
|
|
7
8
|
*/
|
|
8
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
10
|
exports.MachineGateway = void 0;
|
|
@@ -15,14 +16,19 @@ const address_book_1 = require("./address-book");
|
|
|
15
16
|
const admission_1 = require("./admission");
|
|
16
17
|
const protocol_1 = require("../../../lib/machines/protocol");
|
|
17
18
|
const transport_1 = require("../../../lib/machines/transport");
|
|
19
|
+
const publish_1 = require("../../../lib/events/publish");
|
|
18
20
|
const reply_waiter_1 = require("./reply-waiter");
|
|
19
21
|
const executor_1 = require("./executor");
|
|
22
|
+
const dispatcher_1 = require("./dispatcher");
|
|
23
|
+
const inspect_1 = require("./inspect");
|
|
20
24
|
const log_1 = require("./log");
|
|
21
25
|
const plan_escalation_1 = require("./plan-escalation");
|
|
22
26
|
const pacing_1 = require("./pacing");
|
|
23
27
|
const plan_machine_1 = require("./plan-machine");
|
|
24
28
|
const state_1 = require("./state");
|
|
25
29
|
const receipts_1 = require("./receipts");
|
|
30
|
+
const wire_1 = require("./wire");
|
|
31
|
+
const wire_window_1 = require("./wire-window");
|
|
26
32
|
class MachineGateway {
|
|
27
33
|
constructor(deps) {
|
|
28
34
|
this.deps = deps;
|
|
@@ -32,18 +38,22 @@ class MachineGateway {
|
|
|
32
38
|
this.codec = deps.codec ?? (0, protocol_1.genericCodec)({ root: deps.settings.topicRoot, line: deps.line });
|
|
33
39
|
this.state.unitsPerDispatch = this.codec.unitsPerDispatch;
|
|
34
40
|
this.state.dispatchOnArrival = this.codec.dispatchOn === protocol_1.DISPATCH_ON.ARRIVAL;
|
|
41
|
+
this.state.rowOps = (0, protocol_1.declaredRowOps)(this.codec);
|
|
35
42
|
this.state.lifecycle = deps.settings.lifecycle === true;
|
|
36
43
|
this.state.retainedAlarms = this.codec.retainedAlarms === true;
|
|
37
44
|
this.state.progressStep = deps.settings.progressStep ?? this.state.progressStep;
|
|
38
45
|
this.addresses = deps.addresses ?? new address_book_1.MemoryAddressBook();
|
|
46
|
+
this.window = new wire_window_1.WireWindow(deps.settings.wireWindow);
|
|
47
|
+
const sink = deps.wire ?? publish_1.publishMachineWireEvent;
|
|
48
|
+
this.wire = new wire_1.WireRecorder(deps.line, (event) => { this.window.push(event); sink(event); }, { telemetry: deps.settings.wireTelemetry === true });
|
|
39
49
|
this.executor = new executor_1.Executor({
|
|
40
|
-
addresses: this.addresses,
|
|
50
|
+
addresses: this.addresses, wire: this.wire,
|
|
41
51
|
bus: deps.bus, lt: deps.lt, replies: new reply_waiter_1.ReplyWaiter(), state: this.state, line: deps.line,
|
|
42
52
|
codec: this.codec, replyTimeoutMs: deps.settings.replyTimeoutMs,
|
|
43
53
|
dispatchAttempts: deps.settings.dispatchAttempts, offlineDebounceMs: deps.settings.offlineDebounceMs, log: this.log,
|
|
44
54
|
});
|
|
45
|
-
this.admission = { state: this.state, line: deps.line, executor: this.executor, log: this.log, pace: () => this.pace() };
|
|
46
|
-
this.receipts = new receipts_1.ReceiptBatcher({ bus: deps.bus, codec: this.codec, delayMs: deps.settings.receiptDelayMs ?? DEFAULT_RECEIPT_DELAY_MS, log: this.log });
|
|
55
|
+
this.admission = { state: this.state, line: deps.line, executor: this.executor, log: this.log, pace: () => this.pace(), openRows: (q) => deps.lt.listOpen(q) };
|
|
56
|
+
this.receipts = new receipts_1.ReceiptBatcher({ bus: deps.bus, codec: this.codec, delayMs: deps.settings.receiptDelayMs ?? DEFAULT_RECEIPT_DELAY_MS, log: this.log, wire: this.wire });
|
|
47
57
|
}
|
|
48
58
|
async start() {
|
|
49
59
|
await this.deps.bus.connect();
|
|
@@ -61,10 +71,17 @@ class MachineGateway {
|
|
|
61
71
|
}
|
|
62
72
|
this.log.info(log_1.GATEWAY_LOG.STARTED, { site: this.deps.line.siteId, line: this.deps.line.lineId });
|
|
63
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Hand the line over cleanly: nothing new is raised or sent, a message
|
|
76
|
+
* still being handled is nak'd for the next leader if it would make a row,
|
|
77
|
+
* receipts for what was applied go out, then the sessions close.
|
|
78
|
+
*/
|
|
64
79
|
async stop() {
|
|
65
80
|
if (this.quietTimer)
|
|
66
81
|
clearInterval(this.quietTimer);
|
|
67
82
|
this.executor.stop();
|
|
83
|
+
await this.deps.feed.unsubscribe();
|
|
84
|
+
await this.deps.bus.unsubscribe();
|
|
68
85
|
await this.executor.idle();
|
|
69
86
|
await this.receipts.flush();
|
|
70
87
|
await this.deps.feed.close();
|
|
@@ -81,6 +98,10 @@ class MachineGateway {
|
|
|
81
98
|
idle() {
|
|
82
99
|
return this.executor.idle();
|
|
83
100
|
}
|
|
101
|
+
/** A dry run of one message on a copy of the state: nothing is applied (inspect.ts). */
|
|
102
|
+
inspect(msg) {
|
|
103
|
+
return (0, inspect_1.dryRun)({ state: this.state, line: this.deps.line, codec: this.codec, dispatchTtlMs: this.deps.settings.dispatchTtlMs }, { ...msg, deliveries: 1 });
|
|
104
|
+
}
|
|
84
105
|
/**
|
|
85
106
|
* On taking the line: open handoff and command rows (a dispatch or command
|
|
86
107
|
* interrupted by a restart is sent again with the same cmdId), the gateway's
|
|
@@ -138,16 +159,21 @@ class MachineGateway {
|
|
|
138
159
|
const active = new Set();
|
|
139
160
|
this.state.readingRetained = true;
|
|
140
161
|
try {
|
|
141
|
-
for (const
|
|
142
|
-
|
|
162
|
+
for (const read of await this.deps.bus.retained((0, protocol_1.lineFilter)(this.codec.root, line.siteId, line.lineId))) {
|
|
163
|
+
const msg = { ...read, retained: true };
|
|
164
|
+
for (const raw of this.decode(msg)) {
|
|
143
165
|
if (!raw.parsed)
|
|
144
166
|
continue;
|
|
145
|
-
const
|
|
146
|
-
if (!('
|
|
167
|
+
const admitted = await (0, admission_1.admitSender)(this.admission, msg.topic, raw);
|
|
168
|
+
if (!('seen' in admitted)) {
|
|
169
|
+
this.wire.inbound(msg, raw, admitted, 1, admitted.sender);
|
|
147
170
|
continue;
|
|
171
|
+
}
|
|
172
|
+
const { seen } = admitted;
|
|
148
173
|
if (seen.parsed.kind === protocol_1.MESSAGE_KIND.ALARM && seen.body?.body?.active)
|
|
149
174
|
active.add(this.state.alarmKey(seen.parsed.ident.machineId, seen.parsed.key));
|
|
150
|
-
await this.applyMachine(msg.topic, seen.parsed, seen.body);
|
|
175
|
+
const applied = await this.applyMachine(msg.topic, seen.parsed, seen.body);
|
|
176
|
+
this.wire.inbound(msg, seen, { ...applied, actions: [...admitted.actions, ...applied.actions] }, 1);
|
|
151
177
|
}
|
|
152
178
|
}
|
|
153
179
|
}
|
|
@@ -170,7 +196,8 @@ class MachineGateway {
|
|
|
170
196
|
return transport_1.DISPOSITION.ACK;
|
|
171
197
|
}
|
|
172
198
|
catch (err) {
|
|
173
|
-
|
|
199
|
+
if (!(err instanceof dispatcher_1.GatewayStopped))
|
|
200
|
+
this.log.error(log_1.GATEWAY_LOG.VERB_FAILED, { event: event.type, error: err.message });
|
|
174
201
|
return transport_1.DISPOSITION.NAK;
|
|
175
202
|
}
|
|
176
203
|
}
|
|
@@ -188,31 +215,39 @@ class MachineGateway {
|
|
|
188
215
|
return { ...event, role: row.role, data: row };
|
|
189
216
|
}
|
|
190
217
|
async onMachine(msg) {
|
|
191
|
-
const decoded = this.decode(msg
|
|
218
|
+
const decoded = this.decode(msg);
|
|
192
219
|
const acted = [];
|
|
193
220
|
let outcome = transport_1.DISPOSITION.TERM;
|
|
194
221
|
let failed = false;
|
|
195
222
|
for (const raw of decoded) {
|
|
196
223
|
if (!raw.parsed)
|
|
197
224
|
continue;
|
|
198
|
-
const
|
|
199
|
-
if (!('
|
|
200
|
-
failed ||=
|
|
201
|
-
outcome = worse(outcome,
|
|
225
|
+
const admitted = await (0, admission_1.admitSender)(this.admission, msg.topic, raw);
|
|
226
|
+
if (!('seen' in admitted)) {
|
|
227
|
+
failed ||= admitted.failed;
|
|
228
|
+
outcome = worse(outcome, admitted.disposition);
|
|
229
|
+
this.wire.inbound(msg, raw, admitted, msg.deliveries, admitted.sender);
|
|
202
230
|
continue;
|
|
203
231
|
}
|
|
232
|
+
const { seen } = admitted;
|
|
204
233
|
acted.push(seen);
|
|
205
234
|
if (seen.violations.length && msg.deliveries === 1) {
|
|
206
235
|
this.log.warn(log_1.GATEWAY_LOG.CONTRACT_VIOLATION, { topic: msg.topic, violations: seen.violations });
|
|
207
236
|
}
|
|
208
|
-
|
|
237
|
+
let applied = seen.violations.length && this.codec.strict
|
|
209
238
|
? await (0, admission_1.holdViolation)(this.admission, msg, seen)
|
|
210
239
|
: await this.applyMachine(msg.topic, seen.parsed, seen.body);
|
|
240
|
+
// An arrival still waiting for its row after every delivery is shown to a person instead; one that read no id at once.
|
|
241
|
+
const waited = msg.deliveries >= wire_1.MAX_DELIVERIES || (0, admission_1.isUnreadableArrival)(seen);
|
|
242
|
+
if (applied.disposition === transport_1.DISPOSITION.NAK && !applied.failed && waited && (0, admission_1.isArrival)(seen)) {
|
|
243
|
+
applied = await (0, admission_1.holdArrival)(this.admission, msg, seen);
|
|
244
|
+
}
|
|
211
245
|
failed ||= applied.failed;
|
|
212
246
|
outcome = worse(outcome, applied.disposition);
|
|
247
|
+
this.wire.inbound(msg, seen, { ...applied, actions: [...admitted.actions, ...applied.actions] }, msg.deliveries);
|
|
213
248
|
}
|
|
214
249
|
// No row has claimed it after this many tries, so it is not racing its row: stop. A failed verb always retries.
|
|
215
|
-
if (outcome === transport_1.DISPOSITION.NAK && !failed && msg.deliveries >= MAX_DELIVERIES) {
|
|
250
|
+
if (outcome === transport_1.DISPOSITION.NAK && !failed && msg.deliveries >= wire_1.MAX_DELIVERIES) {
|
|
216
251
|
this.log.warn(log_1.GATEWAY_LOG.UNMATCHED, { topic: msg.topic, deliveries: msg.deliveries });
|
|
217
252
|
outcome = transport_1.DISPOSITION.TERM;
|
|
218
253
|
}
|
|
@@ -221,14 +256,19 @@ class MachineGateway {
|
|
|
221
256
|
return outcome;
|
|
222
257
|
}
|
|
223
258
|
/** A message the codec cannot read is not retried: it is logged and has no effect. */
|
|
224
|
-
decode(
|
|
259
|
+
decode(msg) {
|
|
260
|
+
let decoded;
|
|
225
261
|
try {
|
|
226
|
-
|
|
262
|
+
decoded = this.codec.decode(msg.topic, msg.payload, msg.retained);
|
|
227
263
|
}
|
|
228
264
|
catch (err) {
|
|
229
|
-
this.log.warn(log_1.GATEWAY_LOG.UNREADABLE, { topic, error: err.message });
|
|
265
|
+
this.log.warn(log_1.GATEWAY_LOG.UNREADABLE, { topic: msg.topic, error: err.message });
|
|
266
|
+
this.wire.unreadable(msg, err.message);
|
|
230
267
|
return [];
|
|
231
268
|
}
|
|
269
|
+
if (!decoded.length)
|
|
270
|
+
this.wire.unreadable(msg, 'not a machine message', 'none');
|
|
271
|
+
return decoded;
|
|
232
272
|
}
|
|
233
273
|
/** Done with the message: confirm each id its codec asked to confirm. */
|
|
234
274
|
confirm(decoded) {
|
|
@@ -247,21 +287,21 @@ class MachineGateway {
|
|
|
247
287
|
}
|
|
248
288
|
catch (err) {
|
|
249
289
|
this.log.warn(log_1.GATEWAY_LOG.UNREADABLE, { topic, error: err.message });
|
|
250
|
-
return { disposition: transport_1.DISPOSITION.TERM, failed: false };
|
|
290
|
+
return { disposition: transport_1.DISPOSITION.TERM, failed: false, actions: [{ verb: 'unreadable', detail: err.message }] };
|
|
251
291
|
}
|
|
252
292
|
try {
|
|
253
|
-
await this.executor.apply(plan.actions);
|
|
293
|
+
const actions = await this.executor.apply(plan.actions);
|
|
254
294
|
await this.pace();
|
|
255
|
-
return { disposition: plan.disposition, failed: false };
|
|
295
|
+
return { disposition: plan.disposition, failed: false, actions };
|
|
256
296
|
}
|
|
257
297
|
catch (err) {
|
|
258
|
-
|
|
259
|
-
|
|
298
|
+
if (!(err instanceof dispatcher_1.GatewayStopped))
|
|
299
|
+
this.log.error(log_1.GATEWAY_LOG.VERB_FAILED, { topic, error: err.message });
|
|
300
|
+
return { disposition: transport_1.DISPOSITION.NAK, failed: true, actions: [] };
|
|
260
301
|
}
|
|
261
302
|
}
|
|
262
303
|
}
|
|
263
304
|
exports.MachineGateway = MachineGateway;
|
|
264
|
-
const MAX_DELIVERIES = 30;
|
|
265
305
|
const DEFAULT_RECEIPT_DELAY_MS = 250;
|
|
266
306
|
const RANK = { [transport_1.DISPOSITION.TERM]: 0, [transport_1.DISPOSITION.ACK]: 1, [transport_1.DISPOSITION.NAK]: 2 };
|
|
267
307
|
/** One wire message may decode to several; any that must be retried retries the message. */
|
|
@@ -24,3 +24,6 @@ __exportStar(require("./provision"), exports);
|
|
|
24
24
|
__exportStar(require("./state"), exports);
|
|
25
25
|
__exportStar(require("./address-book"), exports);
|
|
26
26
|
__exportStar(require("./registration"), exports);
|
|
27
|
+
__exportStar(require("./wire"), exports);
|
|
28
|
+
__exportStar(require("./project"), exports);
|
|
29
|
+
__exportStar(require("./inspect"), exports);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A dry run of one wire message: what the codec reads and what the gateway
|
|
3
|
+
* would do, planned on a copy of the state so the line is untouched and no
|
|
4
|
+
* row is created or changed.
|
|
5
|
+
*/
|
|
6
|
+
import type { LineDef } from '../../../lib/machines/line';
|
|
7
|
+
import type { LineCodec } from '../../../lib/machines/protocol';
|
|
8
|
+
import type { InboundMessage } from '../../../lib/machines/transport';
|
|
9
|
+
import type { InspectResult } from '../../../types/machines-view';
|
|
10
|
+
import type { GatewayState } from './state';
|
|
11
|
+
export interface DryRunContext {
|
|
12
|
+
state: GatewayState;
|
|
13
|
+
line: LineDef;
|
|
14
|
+
codec: LineCodec;
|
|
15
|
+
dispatchTtlMs: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function dryRun(ctx: DryRunContext, msg: InboundMessage): InspectResult;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* A dry run of one wire message: what the codec reads and what the gateway
|
|
4
|
+
* would do, planned on a copy of the state so the line is untouched and no
|
|
5
|
+
* row is created or changed.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.dryRun = dryRun;
|
|
9
|
+
const plan_machine_1 = require("./plan-machine");
|
|
10
|
+
const registration_1 = require("./registration");
|
|
11
|
+
const wire_1 = require("./wire");
|
|
12
|
+
/** What admitting the sender would do, or null when the message would be acted on. */
|
|
13
|
+
function admission(state, line, raw) {
|
|
14
|
+
const sender = (0, registration_1.resolveSender)(state, line, raw);
|
|
15
|
+
if (sender.status === registration_1.SENDER.BOUND)
|
|
16
|
+
return { seen: sender.seen, actions: [{ verb: 'ack', detail: `bind ${sender.machineId} to ${sender.address}` }] };
|
|
17
|
+
if (sender.seen)
|
|
18
|
+
return { seen: sender.seen, actions: [] };
|
|
19
|
+
if (sender.status === registration_1.SENDER.UNKNOWN)
|
|
20
|
+
return { seen: null, actions: [{ verb: 'none', detail: `${sender.address} claims no station on this line` }] };
|
|
21
|
+
const raised = state.claimRaised(sender.address, sender.machineId);
|
|
22
|
+
return {
|
|
23
|
+
seen: null,
|
|
24
|
+
actions: [raised
|
|
25
|
+
? { verb: 'none', detail: `${sender.address} says it is ${sender.machineId}; waiting for a person` }
|
|
26
|
+
: { verb: 'create-row', detail: `${sender.address} says it is ${sender.machineId}; a person decides` }],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function planOne(ctx, state, raw) {
|
|
30
|
+
const admitted = admission(state, ctx.line, raw);
|
|
31
|
+
if (!admitted.seen)
|
|
32
|
+
return admitted.actions;
|
|
33
|
+
if (raw.violations.length && ctx.codec.strict)
|
|
34
|
+
return [...admitted.actions, { verb: 'hold', detail: raw.violations.join('; ') }];
|
|
35
|
+
try {
|
|
36
|
+
const plan = (0, plan_machine_1.planMachineMessage)(state, admitted.seen.parsed, admitted.seen.body, ctx.dispatchTtlMs);
|
|
37
|
+
const actions = [...admitted.actions, ...plan.actions.map(wire_1.plannedAction)];
|
|
38
|
+
return (0, wire_1.appliedActions)({ disposition: plan.disposition, failed: false, actions }, 1);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
return [...admitted.actions, { verb: 'unreadable', detail: err.message }];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function dryRun(ctx, msg) {
|
|
45
|
+
let decoded;
|
|
46
|
+
try {
|
|
47
|
+
decoded = ctx.codec.decode(msg.topic, msg.payload, msg.retained);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
return { kind: null, event: null, summary: err.message, inspections: [], violations: [], actions: [{ verb: 'unreadable', detail: err.message }] };
|
|
51
|
+
}
|
|
52
|
+
if (!decoded.length) {
|
|
53
|
+
return { kind: null, event: null, summary: 'not a machine message', inspections: [], violations: [], actions: [{ verb: 'none', detail: 'not a machine message' }] };
|
|
54
|
+
}
|
|
55
|
+
const state = ctx.state.clone();
|
|
56
|
+
const actions = [];
|
|
57
|
+
const violations = [];
|
|
58
|
+
for (const raw of decoded) {
|
|
59
|
+
violations.push(...raw.violations);
|
|
60
|
+
if (raw.parsed)
|
|
61
|
+
actions.push(...planOne(ctx, state, raw));
|
|
62
|
+
}
|
|
63
|
+
const [first] = decoded;
|
|
64
|
+
return {
|
|
65
|
+
kind: first.parsed?.kind ?? null, event: (0, wire_1.eventOf)(first), summary: (0, wire_1.summarize)(first),
|
|
66
|
+
inspections: decoded, violations, actions: actions.length ? actions : [{ verb: 'unreadable', detail: 'unknown topic' }],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { publishMachineLogEvent } from '../../../lib/events/publish';
|
|
1
2
|
export declare const GATEWAY_LOG: {
|
|
2
3
|
readonly STARTED: "machine_gateway.started";
|
|
3
4
|
readonly RECONCILED: "machine_gateway.reconciled";
|
|
4
5
|
readonly DISPATCHED: "machine_gateway.dispatch.accepted";
|
|
5
6
|
readonly DISPATCH_REFUSED: "machine_gateway.dispatch.refused";
|
|
6
7
|
readonly DISPATCH_READY: "machine_gateway.dispatch.ready";
|
|
8
|
+
readonly DISPATCH_PREPARING: "machine_gateway.dispatch.preparing";
|
|
7
9
|
readonly DISPATCH_FAILED: "machine_gateway.dispatch.failed";
|
|
8
10
|
readonly DISPATCH_RECONCILED: "machine_gateway.dispatch.reconciled";
|
|
11
|
+
readonly DISPATCH_UNRECOVERABLE: "machine_gateway.dispatch.unrecoverable";
|
|
9
12
|
readonly VERB_INVALID: "machine_gateway.verb.invalid";
|
|
10
13
|
readonly VERB_FAILED: "machine_gateway.verb.failed";
|
|
11
14
|
readonly ROW_NOT_VISIBLE: "machine_gateway.verb.row_not_visible";
|
|
@@ -39,3 +42,10 @@ export interface GatewayLog {
|
|
|
39
42
|
}
|
|
40
43
|
export declare const consoleLog: GatewayLog;
|
|
41
44
|
export declare const silentLog: GatewayLog;
|
|
45
|
+
/** Each entry published as `machine.log.<site>.<line>.<event>` with its context, for the line's dashboard view. */
|
|
46
|
+
export declare function eventsLog(line: {
|
|
47
|
+
siteId: string;
|
|
48
|
+
lineId: string;
|
|
49
|
+
}, publish?: typeof publishMachineLogEvent): GatewayLog;
|
|
50
|
+
/** Every entry goes to each log in turn. */
|
|
51
|
+
export declare function composeLogs(...logs: GatewayLog[]): GatewayLog;
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.silentLog = exports.consoleLog = exports.GATEWAY_LOG = void 0;
|
|
4
|
+
exports.eventsLog = eventsLog;
|
|
5
|
+
exports.composeLogs = composeLogs;
|
|
6
|
+
const publish_1 = require("../../../lib/events/publish");
|
|
4
7
|
exports.GATEWAY_LOG = {
|
|
5
8
|
STARTED: 'machine_gateway.started',
|
|
6
9
|
RECONCILED: 'machine_gateway.reconciled',
|
|
7
10
|
DISPATCHED: 'machine_gateway.dispatch.accepted',
|
|
8
11
|
DISPATCH_REFUSED: 'machine_gateway.dispatch.refused',
|
|
9
12
|
DISPATCH_READY: 'machine_gateway.dispatch.ready',
|
|
13
|
+
DISPATCH_PREPARING: 'machine_gateway.dispatch.preparing',
|
|
10
14
|
DISPATCH_FAILED: 'machine_gateway.dispatch.failed',
|
|
11
15
|
DISPATCH_RECONCILED: 'machine_gateway.dispatch.reconciled',
|
|
16
|
+
DISPATCH_UNRECOVERABLE: 'machine_gateway.dispatch.unrecoverable',
|
|
12
17
|
VERB_INVALID: 'machine_gateway.verb.invalid',
|
|
13
18
|
VERB_FAILED: 'machine_gateway.verb.failed',
|
|
14
19
|
ROW_NOT_VISIBLE: 'machine_gateway.verb.row_not_visible',
|
|
@@ -40,3 +45,18 @@ exports.consoleLog = {
|
|
|
40
45
|
error: (event, context) => console.error(JSON.stringify({ level: 'error', event, ...context })),
|
|
41
46
|
};
|
|
42
47
|
exports.silentLog = { info: () => undefined, warn: () => undefined, error: () => undefined };
|
|
48
|
+
/** Each entry published as `machine.log.<site>.<line>.<event>` with its context, for the line's dashboard view. */
|
|
49
|
+
function eventsLog(line, publish = publish_1.publishMachineLogEvent) {
|
|
50
|
+
const emit = (level) => (event, context) => {
|
|
51
|
+
publish({ siteId: line.siteId, lineId: line.lineId, level, event, context }).catch(() => undefined);
|
|
52
|
+
};
|
|
53
|
+
return { info: emit('info'), warn: emit('warn'), error: emit('error') };
|
|
54
|
+
}
|
|
55
|
+
/** Every entry goes to each log in turn. */
|
|
56
|
+
function composeLogs(...logs) {
|
|
57
|
+
const each = (level) => (event, context) => {
|
|
58
|
+
for (const log of logs)
|
|
59
|
+
log[level](event, context);
|
|
60
|
+
};
|
|
61
|
+
return { info: each('info'), warn: each('warn'), error: each('error') };
|
|
62
|
+
}
|
|
@@ -56,6 +56,8 @@ class LtHttp {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
exports.LtHttp = LtHttp;
|
|
59
|
+
/** A row that was never given items (one parked by hand) answers 400; it holds none. */
|
|
60
|
+
const NO_ITEMS_STATUS = 400;
|
|
59
61
|
/** Escalation verbs over HTTP, each run with the bearer token of the actor it runs as. */
|
|
60
62
|
class HttpLineEscalations {
|
|
61
63
|
constructor(http, tokenFor, claimMinutes = 24 * 60) {
|
|
@@ -80,8 +82,15 @@ class HttpLineEscalations {
|
|
|
80
82
|
return (await this.items(id)).map((i) => i.itemKey);
|
|
81
83
|
}
|
|
82
84
|
async items(id) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
try {
|
|
86
|
+
const view = await this.http.request('GET', `/escalations/${id}/items`, this.tokenFor(actions_1.CONTROLLER));
|
|
87
|
+
return view.items.map((i) => ({ itemKey: i.itemKey, payload: i.payload ?? {} }));
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
if (err instanceof LtHttpError && err.status === NO_ITEMS_STATUS)
|
|
91
|
+
return [];
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
85
94
|
}
|
|
86
95
|
async get(id) {
|
|
87
96
|
if (!(0, uuid_1.isUuid)(id))
|
|
@@ -39,6 +39,7 @@ function dispatchArgs(row, expiresAt) {
|
|
|
39
39
|
expiresAt: (0, protocol_1.isoTs)(expiresAt),
|
|
40
40
|
...(row.artifactUrl ? { artifact: { url: row.artifactUrl, sha256: row.artifactSha256 } } : {}),
|
|
41
41
|
...(row.parameters ? { parameters: row.parameters } : {}),
|
|
42
|
+
...(row.refs ? { refs: row.refs } : {}),
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
45
|
/**
|
|
@@ -65,7 +66,7 @@ function dispatchAction(row, machineId, dispatchTtlMs) {
|
|
|
65
66
|
row.createdAt ??= now;
|
|
66
67
|
const { round, expiresAt } = dispatchWindow(row.dueAt ?? row.createdAt, now, dispatchTtlMs);
|
|
67
68
|
return {
|
|
68
|
-
kind: 'dispatch', rowId: row.id, machineId, cmdId: (0, contracts_1.dispatchCommandId)(row.id, round), args: dispatchArgs(row, expiresAt),
|
|
69
|
+
kind: 'dispatch', rowId: row.id, machineId, cmdId: (0, contracts_1.dispatchCommandId)(row.id, round), args: dispatchArgs(row, expiresAt), issuedAt: expiresAt - dispatchTtlMs,
|
|
69
70
|
...(row.dispatch === state_1.DISPATCH_STATE.ARRIVING ? { receivedOnAccept: true } : {}),
|
|
70
71
|
};
|
|
71
72
|
}
|
|
@@ -93,8 +93,9 @@ function commandRefusal(state, line, c, role) {
|
|
|
93
93
|
const own = (0, line_1.machineRole)((0, line_1.machineById)(line, c.machineId));
|
|
94
94
|
if (role !== own)
|
|
95
95
|
return `commands for ${c.machineId} are parked on ${own}, not ${role}`;
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
const allowed = rowOps(state);
|
|
97
|
+
if (!allowed.includes(c.op))
|
|
98
|
+
return `${c.op} is not a command a row may ask for; one of ${allowed.join(', ')}`;
|
|
98
99
|
if (c.op === protocol_1.OP.CANCEL && typeof c.args.jobId !== 'string')
|
|
99
100
|
return `${protocol_1.OP.CANCEL} needs args.jobId, the job to withdraw or stop`;
|
|
100
101
|
if (!(0, registration_1.reachable)(state, line, c.machineId))
|
|
@@ -110,7 +111,7 @@ function planCommandRow(state, line, event) {
|
|
|
110
111
|
if (event.verb !== VERB.CREATED && event.verb !== VERB.CLAIMED)
|
|
111
112
|
return [];
|
|
112
113
|
const c = (0, commands_1.readCommandFacets)(event.data?.metadata);
|
|
113
|
-
if (!c || !state.trackCommand(id))
|
|
114
|
+
if (!c || !state.trackCommand(id, c.machineId))
|
|
114
115
|
return [];
|
|
115
116
|
const refusal = commandRefusal(state, line, c, event.role);
|
|
116
117
|
if (refusal) {
|
|
@@ -119,6 +120,10 @@ function planCommandRow(state, line, event) {
|
|
|
119
120
|
const createdAt = event.data?.created_at ? new Date(event.data.created_at).getTime() : NaN;
|
|
120
121
|
return [{ kind: 'control', rowId: id, machineId: c.machineId, op: c.op, args: c.args, ...(Number.isFinite(createdAt) ? { createdAt } : {}) }];
|
|
121
122
|
}
|
|
123
|
+
/** The ops a machine-command row may ask for: the control ops, a snapshot, and the codec's own. */
|
|
124
|
+
function rowOps(state) {
|
|
125
|
+
return [...protocol_1.CONTROL_OPS, protocol_1.OP.SNAPSHOT, ...state.rowOps];
|
|
126
|
+
}
|
|
122
127
|
function onLine(line, machineId) {
|
|
123
128
|
return !!machineId && line.machines.some((m) => m.machineId === machineId);
|
|
124
129
|
}
|
|
@@ -36,7 +36,10 @@ function planMachineMessage(state, parsed, env, dispatchTtlMs) {
|
|
|
36
36
|
function planByKind(state, m, parsed, env, b, ttl) {
|
|
37
37
|
switch (parsed.kind) {
|
|
38
38
|
case protocol_1.MESSAGE_KIND.REPLY:
|
|
39
|
-
return ack([{
|
|
39
|
+
return ack([{
|
|
40
|
+
kind: 'settleReply', cmdId: b.cmdId, status: b.status, reason: b.reason,
|
|
41
|
+
...(typeof b.code === 'string' ? { code: b.code } : {}), ...(b.preparing === true ? { preparing: true } : {}),
|
|
42
|
+
}]);
|
|
40
43
|
case protocol_1.MESSAGE_KIND.JOB:
|
|
41
44
|
return planJob(state, m, b, env?.at, ttl);
|
|
42
45
|
case protocol_1.MESSAGE_KIND.ALARM:
|
|
@@ -139,7 +142,8 @@ function planJob(state, m, b, at, ttl) {
|
|
|
139
142
|
if (b.result === protocol_1.JOB_RESULT.OK)
|
|
140
143
|
return ack([released]);
|
|
141
144
|
return ack([released, ...(0, plan_shared_1.failHandoff)(state, row, m, {
|
|
142
|
-
received: false, unitId, errorCode: contracts_1.HANDOFF_ERROR.SENDER_REJECTED,
|
|
145
|
+
received: false, unitId, errorCode: contracts_1.HANDOFF_ERROR.SENDER_REJECTED, result: b.result, reason: b.reason ?? null,
|
|
146
|
+
detail: `${m} finished ${unitId}: ${b.result}${b.reason ? ` (${b.reason})` : ''}`,
|
|
143
147
|
})]);
|
|
144
148
|
}
|
|
145
149
|
if (b.event === protocol_1.JOB_EVENT.TRANSFER_FAILED) {
|
|
@@ -190,7 +194,9 @@ function planAlarm(state, parsed, alarmId, env) {
|
|
|
190
194
|
payload: { decision: contracts_1.DECISION.CLEARED, clearedBy: b.clearedBy ?? null, note: `cleared at ${m}${b.clearedBy ? ` by ${b.clearedBy}` : ''}` },
|
|
191
195
|
}]);
|
|
192
196
|
}
|
|
193
|
-
|
|
197
|
+
// A stopping level needs a person; so does any alarm the machine flags, at the level it said.
|
|
198
|
+
const stopping = protocol_1.STOPPING_LEVELS.includes(b.level);
|
|
199
|
+
if (!stopping && b.needsPerson !== true)
|
|
194
200
|
return ack();
|
|
195
201
|
const known = state.alarms.get(key);
|
|
196
202
|
if (known && (!known.raisedAt || !b.raisedAt || known.raisedAt === b.raisedAt))
|
|
@@ -198,9 +204,9 @@ function planAlarm(state, parsed, alarmId, env) {
|
|
|
198
204
|
const superseded = known?.rowId && known.open
|
|
199
205
|
? [{ kind: 'resolve', as: actions_1.CONTROLLER, rowId: known.rowId, payload: { decision: contracts_1.DECISION.CLEARED, note: `${m} raised ${alarmId} again; this one ended` } }]
|
|
200
206
|
: [];
|
|
201
|
-
const track = { machineId: m, alarmId, raisedAt: b.raisedAt, open: true };
|
|
207
|
+
const track = { machineId: m, alarmId, raisedAt: b.raisedAt, level: b.level, open: true };
|
|
202
208
|
state.alarms.set(key, track);
|
|
203
|
-
return ack([...superseded, ...(0, lifecycle_1.notePause)(state, track, b), {
|
|
209
|
+
return ack([...superseded, ...(stopping ? (0, lifecycle_1.notePause)(state, track, b) : []), {
|
|
204
210
|
kind: 'createAlarmRow', machineId: m, alarmId,
|
|
205
211
|
row: {
|
|
206
212
|
type: contracts_1.ROW_TYPE.ALARM, subtype: b.level, role: contracts_1.LINE_ROLE.OPERATOR, priority: b.level === protocol_1.LEVEL.EMERGENCY ? 1 : 2,
|
|
@@ -222,10 +228,12 @@ function catalogEnvelope(catalog) {
|
|
|
222
228
|
}
|
|
223
229
|
function planPresence(state, m, b) {
|
|
224
230
|
const link = state.link(m);
|
|
231
|
+
const session = typeof b.sessionId === 'string' ? b.sessionId : undefined;
|
|
225
232
|
if (b.online !== true) {
|
|
226
233
|
if (link.online)
|
|
227
234
|
link.since = Date.now();
|
|
228
235
|
link.online = false;
|
|
236
|
+
link.reason = typeof b.reason === 'string' ? b.reason : undefined;
|
|
229
237
|
if (link.rowId || link.watching)
|
|
230
238
|
return ack();
|
|
231
239
|
link.watching = true;
|
|
@@ -234,37 +242,54 @@ function planPresence(state, m, b) {
|
|
|
234
242
|
if (b.software)
|
|
235
243
|
link.software = b.software;
|
|
236
244
|
const wasOffline = !link.online;
|
|
245
|
+
// A new session while online: the machine reconnected before its offline presence was heard.
|
|
246
|
+
const reconnected = !!session && !!link.sessionId && session !== link.sessionId;
|
|
237
247
|
link.online = true;
|
|
238
248
|
link.watching = false;
|
|
249
|
+
link.reason = undefined;
|
|
250
|
+
if (session)
|
|
251
|
+
link.sessionId = session;
|
|
239
252
|
const actions = [];
|
|
240
253
|
// Back from a drop: ask for the full state rather than wait for the next heartbeat.
|
|
241
|
-
if (wasOffline)
|
|
242
|
-
actions.push({ kind: 'command', machineId: m, op: protocol_1.OP.SNAPSHOT, cmdId: `${m}:resync:${link.since}`, args: {} });
|
|
254
|
+
if (wasOffline || reconnected)
|
|
255
|
+
actions.push({ kind: 'command', machineId: m, op: protocol_1.OP.SNAPSHOT, cmdId: `${m}:resync:${session ?? link.since}`, args: {} });
|
|
243
256
|
if (link.rowId) {
|
|
244
257
|
actions.push({ kind: 'resolve', as: actions_1.CONTROLLER, rowId: link.rowId, payload: { decision: contracts_1.DECISION.RESTORED, note: `${m} back online` } });
|
|
245
258
|
link.rowId = undefined;
|
|
246
259
|
}
|
|
247
260
|
return ack(actions);
|
|
248
261
|
}
|
|
249
|
-
/**
|
|
262
|
+
/**
|
|
263
|
+
* A new boot id means the machine restarted and lost its queue: send its open
|
|
264
|
+
* dispatches again, and the jobs it had ready for units it still holds, from
|
|
265
|
+
* the rows that sent them. A lost job nothing is remembered for is logged.
|
|
266
|
+
*/
|
|
250
267
|
function planSnapshot(state, m, b, ttl) {
|
|
251
268
|
const link = state.link(m);
|
|
252
269
|
if (b.software)
|
|
253
270
|
link.software = b.software;
|
|
254
271
|
const jobIds = Array.isArray(b.jobs) ? b.jobs.map((j) => j?.jobId).filter((id) => typeof id === 'string') : [];
|
|
255
|
-
|
|
256
|
-
|
|
272
|
+
// A snapshot without a boot id says nothing about restarts.
|
|
273
|
+
const rebooted = typeof b.bootId === 'string' && !!link.bootId && link.bootId !== b.bootId;
|
|
274
|
+
const held = new Set(jobIds);
|
|
275
|
+
const lost = rebooted ? state.lostAfterReboot(m, held) : { resend: [], unknown: [] };
|
|
276
|
+
if (Array.isArray(b.jobs)) {
|
|
277
|
+
state.keepHeld(m, new Set([...jobIds, ...lost.resend.map((l) => l.jobId)]));
|
|
278
|
+
link.jobs = b.jobs;
|
|
279
|
+
}
|
|
280
|
+
if (typeof b.bootId === 'string')
|
|
281
|
+
link.bootId = b.bootId;
|
|
257
282
|
const fresh = !state.retainedAlarms && !state.readingRetained && Array.isArray(b.alarms);
|
|
258
283
|
const cleared = fresh ? alarmsNoLongerListed(state, m, b.alarms) : [];
|
|
259
284
|
const answer = { kind: 'settleSnapshot', machineId: m, jobIds };
|
|
260
|
-
|
|
261
|
-
link.bootId = b.bootId;
|
|
262
|
-
if (!previous || previous === b.bootId)
|
|
285
|
+
if (!rebooted)
|
|
263
286
|
return ack([...cleared, answer]);
|
|
264
|
-
const held = new Set(jobIds);
|
|
265
287
|
const missing = (r) => (0, jobs_1.dispatchJobs)(r.jobId, r.units, state.unitsPerDispatch).some((j) => !held.has(j.jobId));
|
|
266
|
-
const
|
|
267
|
-
|
|
288
|
+
const open = state.open().filter((r) => r.toMachine === m && r.dispatch === state_1.DISPATCH_STATE.ACCEPTED && missing(r));
|
|
289
|
+
const rows = new Map(lost.resend.map((l) => [l.row.id, l.row]));
|
|
290
|
+
const again = [...rows.values()].map((r) => ({ ...(0, pacing_1.dispatchAction)(r, m, ttl), ended: true }));
|
|
291
|
+
const unknown = lost.unknown.length ? [{ kind: 'unrecoverable', machineId: m, jobs: lost.unknown }] : [];
|
|
292
|
+
return ack([...cleared, answer, ...open.map((r) => (0, pacing_1.dispatchAction)(r, m, ttl)), ...again, ...unknown]);
|
|
268
293
|
}
|
|
269
294
|
/** Alarm rows for `m` whose alarm its snapshot no longer lists: they cleared at the machine. */
|
|
270
295
|
function alarmsNoLongerListed(state, m, listed) {
|
|
@@ -5,9 +5,11 @@ import { type GatewayState, type HandoffRow } from './state';
|
|
|
5
5
|
/** A cancel for each job a handoff's units became at `machineId`, or for those `keep` leaves out. */
|
|
6
6
|
export declare function cancelJobs(state: GatewayState, row: HandoffRow, machineId: string, jobId: string, tag?: string, keep?: (job: DispatchJob) => boolean): Action[];
|
|
7
7
|
/**
|
|
8
|
-
* Withdraw a dispatch that may still sit in the receiver's queue
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Withdraw a dispatch that may still sit in the receiver's queue: one sent or
|
|
9
|
+
* accepted. A job that never went out (the row waiting for room, or for its
|
|
10
|
+
* units to arrive) leaves the receiver nothing to withdraw. A job some of whose
|
|
11
|
+
* units already reached the receiver is under way: it stays, and what happens
|
|
12
|
+
* to it is the workflow's next decision (a machine-command row).
|
|
11
13
|
*/
|
|
12
14
|
export declare function cancelDispatch(state: GatewayState, row: HandoffRow): Action[];
|
|
13
15
|
/**
|
|
@@ -14,13 +14,15 @@ function cancelJobs(state, row, machineId, jobId, tag = '', keep = () => false)
|
|
|
14
14
|
}));
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* Withdraw a dispatch that may still sit in the receiver's queue
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* Withdraw a dispatch that may still sit in the receiver's queue: one sent or
|
|
18
|
+
* accepted. A job that never went out (the row waiting for room, or for its
|
|
19
|
+
* units to arrive) leaves the receiver nothing to withdraw. A job some of whose
|
|
20
|
+
* units already reached the receiver is under way: it stays, and what happens
|
|
21
|
+
* to it is the workflow's next decision (a machine-command row).
|
|
20
22
|
*/
|
|
21
23
|
function cancelDispatch(state, row) {
|
|
22
24
|
const to = row.toMachine;
|
|
23
|
-
if (!to || row.dispatch
|
|
25
|
+
if (!to || (row.dispatch !== state_1.DISPATCH_STATE.PENDING && row.dispatch !== state_1.DISPATCH_STATE.ACCEPTED))
|
|
24
26
|
return [];
|
|
25
27
|
return cancelJobs(state, row, to, row.jobId, '', (job) => job.units.some((u) => state.heldJob(to, u.unitId) === job.jobId));
|
|
26
28
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The line as its leader sees it, for the dashboard: each machine's link,
|
|
3
|
+
* held units, open rows and alarms from the gateway state, and the claims
|
|
4
|
+
* waiting for a person. Pure: reads the state and the line, changes nothing.
|
|
5
|
+
*/
|
|
6
|
+
import { type LineDef } from '../../../lib/machines/line';
|
|
7
|
+
import type { LineView } from '../../../types/machines-view';
|
|
8
|
+
import type { GatewayState } from './state';
|
|
9
|
+
export declare function projectLine(state: GatewayState, line: LineDef): LineView;
|