@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
|
@@ -17,6 +17,7 @@ import { type LineEscalations } from './escalations';
|
|
|
17
17
|
import { type GatewayLog } from './log';
|
|
18
18
|
import type { CommandReply, ReplyWaiter } from './reply-waiter';
|
|
19
19
|
import { type GatewayState } from './state';
|
|
20
|
+
import type { WireRecorder } from './wire';
|
|
20
21
|
export interface DispatcherDeps {
|
|
21
22
|
bus: MachineBus;
|
|
22
23
|
codec: LineCodec;
|
|
@@ -27,6 +28,8 @@ export interface DispatcherDeps {
|
|
|
27
28
|
replyTimeoutMs: number;
|
|
28
29
|
dispatchAttempts: number;
|
|
29
30
|
log: GatewayLog;
|
|
31
|
+
/** Records each command the gateway sends, for the line's wire view. */
|
|
32
|
+
wire?: Pick<WireRecorder, 'command'>;
|
|
30
33
|
}
|
|
31
34
|
type DispatchAction = Extract<Action, {
|
|
32
35
|
kind: 'dispatch';
|
|
@@ -49,12 +52,15 @@ export declare class Dispatcher {
|
|
|
49
52
|
/** Work still running sends nothing more and changes no row. */
|
|
50
53
|
stop(): void;
|
|
51
54
|
private live;
|
|
52
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* This send's attempt number, whether the machine may have the command already, and when it was
|
|
57
|
+
* issued: the time given (a round's start, the same for every gateway), else the first send's.
|
|
58
|
+
*/
|
|
53
59
|
private countSend;
|
|
54
60
|
/** False when the codec has no message for the command. `since` is when the command's row was created. */
|
|
55
|
-
publish(machineId: string, op: string, cmdId: string, args: Record<string, any>, since?: number): Promise<boolean>;
|
|
61
|
+
publish(machineId: string, op: string, cmdId: string, args: Record<string, any>, since?: number, issuedAt?: number): Promise<boolean>;
|
|
56
62
|
/** Publish and wait for the reply, asking again with the same id; null when none came. */
|
|
57
|
-
ask(machineId: string, op: string, cmdId: string, args: Record<string, any>, since?: number): Promise<CommandReply | null>;
|
|
63
|
+
ask(machineId: string, op: string, cmdId: string, args: Record<string, any>, since?: number, issuedAt?: number): Promise<CommandReply | null>;
|
|
58
64
|
command(a: CommandAction): Promise<void>;
|
|
59
65
|
/**
|
|
60
66
|
* A machine-command row: send it, then resolve the row with the reply, as the
|
|
@@ -65,7 +71,9 @@ export declare class Dispatcher {
|
|
|
65
71
|
*/
|
|
66
72
|
control(a: ControlAction): Promise<void>;
|
|
67
73
|
dispatch(a: DispatchAction): Promise<void>;
|
|
68
|
-
/**
|
|
74
|
+
/** A job sent again after the machine restarted, for a row that already ended: the reply is only logged. */
|
|
75
|
+
private resent;
|
|
76
|
+
/** The units were already at the machine: a job it has taken and is ready for completes the handoff. */
|
|
69
77
|
private received;
|
|
70
78
|
/** Ask a silent machine what it holds; null when it cannot say or does not answer in time. */
|
|
71
79
|
private heldJobs;
|
|
@@ -30,6 +30,10 @@ function fromMachine(reply) {
|
|
|
30
30
|
function took(reply) {
|
|
31
31
|
return reply?.status === protocol_1.REPLY_STATUS.ACCEPTED || reply?.status === protocol_1.REPLY_STATUS.COMPLETED;
|
|
32
32
|
}
|
|
33
|
+
/** The reply's structured code for a resolution, when it carried one. */
|
|
34
|
+
function withCode(reply) {
|
|
35
|
+
return reply.code ? { code: reply.code } : {};
|
|
36
|
+
}
|
|
33
37
|
/** Most command ids whose sends are counted; the oldest are forgotten first. */
|
|
34
38
|
const SENT_REMEMBERED = 10_000;
|
|
35
39
|
/** Ends a dispatch or command still running when the gateway stops; the next leader takes it up from the row. */
|
|
@@ -53,29 +57,38 @@ class Dispatcher {
|
|
|
53
57
|
if (this.stopping.signal.aborted)
|
|
54
58
|
throw new GatewayStopped();
|
|
55
59
|
}
|
|
56
|
-
/**
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
/**
|
|
61
|
+
* This send's attempt number, whether the machine may have the command already, and when it was
|
|
62
|
+
* issued: the time given (a round's start, the same for every gateway), else the first send's.
|
|
63
|
+
*/
|
|
64
|
+
countSend(cmdId, since, issuedAt) {
|
|
65
|
+
const before = this.sent.get(cmdId);
|
|
66
|
+
const record = { attempt: (before?.attempt ?? 0) + 1, issuedAt: issuedAt ?? before?.issuedAt ?? Date.now() };
|
|
59
67
|
this.sent.delete(cmdId);
|
|
60
|
-
this.sent.set(cmdId,
|
|
68
|
+
this.sent.set(cmdId, record);
|
|
61
69
|
if (this.sent.size > SENT_REMEMBERED)
|
|
62
70
|
this.sent.delete(this.sent.keys().next().value);
|
|
63
|
-
|
|
71
|
+
const retry = record.attempt > 1 || (since !== undefined && since < this.d.state.takenAt);
|
|
72
|
+
return { attempt: record.attempt, retry, issuedAt: (0, protocol_1.isoTs)(record.issuedAt) };
|
|
64
73
|
}
|
|
65
74
|
/** False when the codec has no message for the command. `since` is when the command's row was created. */
|
|
66
|
-
async publish(machineId, op, cmdId, args, since) {
|
|
75
|
+
async publish(machineId, op, cmdId, args, since, issuedAt) {
|
|
67
76
|
this.live();
|
|
68
|
-
const
|
|
69
|
-
|
|
77
|
+
const ident = (0, registration_1.identFor)(this.d.state, this.d.line, machineId);
|
|
78
|
+
const command = { cmdId, op, args, ...this.countSend(cmdId, since, issuedAt) };
|
|
79
|
+
const wires = this.d.codec.encode(ident, command);
|
|
80
|
+
for (const wire of wires) {
|
|
70
81
|
await this.d.bus.publish(wire.topic, wire.payload);
|
|
82
|
+
this.d.wire?.command(ident, command, wire);
|
|
83
|
+
}
|
|
71
84
|
return wires.length > 0;
|
|
72
85
|
}
|
|
73
86
|
/** Publish and wait for the reply, asking again with the same id; null when none came. */
|
|
74
|
-
async ask(machineId, op, cmdId, args, since) {
|
|
87
|
+
async ask(machineId, op, cmdId, args, since, issuedAt) {
|
|
75
88
|
for (let attempt = 1; attempt <= this.d.dispatchAttempts; attempt++) {
|
|
76
89
|
this.live();
|
|
77
90
|
const waiting = this.d.replies.wait(cmdId, this.d.replyTimeoutMs);
|
|
78
|
-
if (!await this.publish(machineId, op, cmdId, args, since)) {
|
|
91
|
+
if (!await this.publish(machineId, op, cmdId, args, since, issuedAt)) {
|
|
79
92
|
this.d.replies.settle({ cmdId, status: contracts_1.COMMAND_STATUS.UNSUPPORTED, reason: `the line's codec has no ${op} command` });
|
|
80
93
|
}
|
|
81
94
|
const reply = await waiting;
|
|
@@ -104,14 +117,15 @@ class Dispatcher {
|
|
|
104
117
|
*/
|
|
105
118
|
async control(a) {
|
|
106
119
|
const now = Date.now();
|
|
107
|
-
const
|
|
108
|
-
const
|
|
120
|
+
const ttlMs = this.d.replyTimeoutMs * this.d.dispatchAttempts;
|
|
121
|
+
const { round, expiresAt } = (0, pacing_1.dispatchWindow)(a.createdAt ?? now, now, ttlMs);
|
|
122
|
+
const reply = await this.ask(a.machineId, a.op, (0, contracts_1.controlCommandId)(a.rowId, round), { ...a.args, expiresAt: (0, protocol_1.isoTs)(expiresAt) }, a.createdAt, expiresAt - ttlMs);
|
|
109
123
|
// Timers may fire a little early; the command must have expired before the row says no-reply.
|
|
110
124
|
if (!reply && Date.now() <= expiresAt)
|
|
111
125
|
await (0, promises_1.setTimeout)(expiresAt - Date.now() + 1, undefined, { signal: this.stopping.signal }).catch(() => undefined);
|
|
112
126
|
this.live();
|
|
113
127
|
const outcome = reply
|
|
114
|
-
? { accepted: reply.status === protocol_1.REPLY_STATUS.ACCEPTED, machineId: a.machineId, op: a.op, status: reply.status, reason: reply.reason }
|
|
128
|
+
? { accepted: reply.status === protocol_1.REPLY_STATUS.ACCEPTED, machineId: a.machineId, op: a.op, status: reply.status, reason: reply.reason, ...withCode(reply) }
|
|
115
129
|
: { accepted: false, machineId: a.machineId, op: a.op, status: contracts_1.COMMAND_STATUS.NO_REPLY, reason: `no reply after ${this.d.dispatchAttempts} attempts` };
|
|
116
130
|
const context = { row: a.rowId, machine: a.machineId, op: a.op, status: outcome.status, reason: outcome.reason };
|
|
117
131
|
if (outcome.accepted)
|
|
@@ -134,22 +148,36 @@ class Dispatcher {
|
|
|
134
148
|
for (const job of jobs)
|
|
135
149
|
state.rememberDispatch(`${a.cmdId}${job.suffix}`, a.rowId);
|
|
136
150
|
const since = state.get(a.rowId)?.createdAt;
|
|
137
|
-
const replies = await Promise.all(jobs.map((job) => this.ask(a.machineId, protocol_1.OP.DISPATCH, `${a.cmdId}${job.suffix}`, { ...a.args, jobId: job.jobId, units: job.units }, since)));
|
|
151
|
+
const replies = await Promise.all(jobs.map((job) => this.ask(a.machineId, protocol_1.OP.DISPATCH, `${a.cmdId}${job.suffix}`, { ...a.args, jobId: job.jobId, units: job.units }, since, a.issuedAt)));
|
|
138
152
|
const refused = replies.find((r) => r && !took(r));
|
|
139
153
|
const silent = jobs.filter((_, i) => !replies[i]);
|
|
140
154
|
const held = !refused && silent.length ? await this.heldJobs(a.machineId, a.cmdId) : null;
|
|
141
155
|
this.live();
|
|
142
156
|
const reconciled = !!held && silent.every((j) => held.has(j.jobId));
|
|
157
|
+
if (a.ended) {
|
|
158
|
+
this.resent(a, jobs, refused ?? null, !refused && (!silent.length || reconciled));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
143
161
|
const row = state.get(a.rowId);
|
|
144
162
|
if (!refused && (!silent.length || reconciled)) {
|
|
145
163
|
if (row)
|
|
146
164
|
row.dispatch = state_1.DISPATCH_STATE.ACCEPTED;
|
|
165
|
+
for (const job of jobs)
|
|
166
|
+
state.rememberSent(a.machineId, job.jobId, a.rowId);
|
|
147
167
|
if (reconciled)
|
|
148
168
|
log.info(log_1.GATEWAY_LOG.DISPATCH_RECONCILED, { row: a.rowId, machine: a.machineId, jobs: silent.map((j) => j.jobId) });
|
|
149
169
|
log.info(log_1.GATEWAY_LOG.DISPATCHED, { row: a.rowId, machine: a.machineId, reason: replies.map((r) => r?.reason ?? 'held').join('; ') });
|
|
150
170
|
this.check(a.rowId, 'claim', await lt.claim(a.machineId, a.rowId));
|
|
151
|
-
if (a.receivedOnAccept)
|
|
171
|
+
if (!a.receivedOnAccept)
|
|
172
|
+
return;
|
|
173
|
+
const preparing = jobs.filter((job, i) => replies[i]?.status === protocol_1.REPLY_STATUS.ACCEPTED && replies[i]?.preparing).map((job) => `${a.cmdId}${job.suffix}`);
|
|
174
|
+
if (!preparing.length) {
|
|
152
175
|
await this.received(a);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (row)
|
|
179
|
+
row.awaitingReady = new Set(preparing);
|
|
180
|
+
log.info(log_1.GATEWAY_LOG.DISPATCH_PREPARING, { row: a.rowId, machine: a.machineId, jobs: preparing });
|
|
153
181
|
return;
|
|
154
182
|
}
|
|
155
183
|
// The handoff may have ended meanwhile: a machine that ran the job anyway reports the arrival.
|
|
@@ -158,7 +186,7 @@ class Dispatcher {
|
|
|
158
186
|
row.dispatch = state_1.DISPATCH_STATE.REFUSED;
|
|
159
187
|
const unanswered = `${a.machineId} sent no reply after ${this.d.dispatchAttempts} attempts`;
|
|
160
188
|
const resolution = refused
|
|
161
|
-
? { received: false, errorCode: contracts_1.HANDOFF_ERROR.DISPATCH_REFUSED, detail: `${a.machineId} ${refused.status}: ${refused.reason}
|
|
189
|
+
? { received: false, errorCode: contracts_1.HANDOFF_ERROR.DISPATCH_REFUSED, detail: `${a.machineId} ${refused.status}: ${refused.reason}`, ...withCode(refused) }
|
|
162
190
|
: { received: false, errorCode: contracts_1.HANDOFF_ERROR.NO_REPLY, detail: held ? `${unanswered} and does not hold the job` : `${unanswered}; its state is unknown` };
|
|
163
191
|
log.warn(log_1.GATEWAY_LOG.DISPATCH_REFUSED, { row: a.rowId, machine: a.machineId, ...resolution });
|
|
164
192
|
const ended = await lt.resolve(fromMachine(refused ?? null) ? a.machineId : actions_1.CONTROLLER, a.rowId, resolution);
|
|
@@ -168,7 +196,15 @@ class Dispatcher {
|
|
|
168
196
|
return;
|
|
169
197
|
await this.withdraw(a, jobs.filter((_, i) => !replies[i] || took(replies[i])));
|
|
170
198
|
}
|
|
171
|
-
/**
|
|
199
|
+
/** A job sent again after the machine restarted, for a row that already ended: the reply is only logged. */
|
|
200
|
+
resent(a, jobs, refused, taken) {
|
|
201
|
+
const context = { row: a.rowId, machine: a.machineId, jobs: jobs.map((j) => j.jobId), resent: true };
|
|
202
|
+
if (taken)
|
|
203
|
+
this.d.log.info(log_1.GATEWAY_LOG.DISPATCHED, { ...context, reason: 'sent again after a restart' });
|
|
204
|
+
else
|
|
205
|
+
this.d.log.warn(log_1.GATEWAY_LOG.DISPATCH_REFUSED, { ...context, reason: refused ? `${refused.status}: ${refused.reason}` : 'no reply' });
|
|
206
|
+
}
|
|
207
|
+
/** The units were already at the machine: a job it has taken and is ready for completes the handoff. */
|
|
172
208
|
async received(a) {
|
|
173
209
|
this.live();
|
|
174
210
|
const units = a.args.units.map((u) => u.unitId);
|
|
@@ -2,17 +2,20 @@
|
|
|
2
2
|
* Runs the planner's actions: escalation verbs through LineEscalations,
|
|
3
3
|
* dispatches and commands through the Dispatcher, alarm and machine rows,
|
|
4
4
|
* and the offline debounce. A verb that fails for real throws, so the message that
|
|
5
|
-
* caused it is delivered again.
|
|
5
|
+
* caused it is delivered again. What ran comes back as wire actions, for the
|
|
6
|
+
* record of the message that caused it.
|
|
6
7
|
*/
|
|
7
8
|
import { type LineDef } from '../../../lib/machines/line';
|
|
8
9
|
import { type LineCodec } from '../../../lib/machines/protocol';
|
|
9
10
|
import type { MachineBus } from '../../../lib/machines/transport';
|
|
11
|
+
import type { WireAction } from '../../../types/machines-view';
|
|
10
12
|
import { type Action } from './actions';
|
|
11
13
|
import type { AddressBook } from './address-book';
|
|
12
14
|
import { type LineEscalations } from './escalations';
|
|
13
15
|
import { type GatewayLog } from './log';
|
|
14
16
|
import type { ReplyWaiter } from './reply-waiter';
|
|
15
17
|
import { type GatewayState } from './state';
|
|
18
|
+
import { type WireRecorder } from './wire';
|
|
16
19
|
export interface ExecutorDeps {
|
|
17
20
|
bus: MachineBus;
|
|
18
21
|
lt: LineEscalations;
|
|
@@ -26,19 +29,25 @@ export interface ExecutorDeps {
|
|
|
26
29
|
log: GatewayLog;
|
|
27
30
|
/** Where learned addresses are kept (registration.ts). */
|
|
28
31
|
addresses: AddressBook;
|
|
32
|
+
/** Records each command sent, for the line's wire view. */
|
|
33
|
+
wire?: Pick<WireRecorder, 'command'>;
|
|
29
34
|
}
|
|
30
35
|
export declare class Executor {
|
|
31
36
|
private readonly d;
|
|
32
37
|
private inflight;
|
|
33
38
|
private quietPending;
|
|
34
39
|
private timers;
|
|
40
|
+
private stopped;
|
|
35
41
|
private readonly dispatcher;
|
|
36
42
|
constructor(d: ExecutorDeps);
|
|
37
43
|
/** Dispatches and commands run detached so one slow reply never holds up the feed. */
|
|
38
|
-
apply(actions: Action[]): Promise<
|
|
44
|
+
apply(actions: Action[]): Promise<WireAction[]>;
|
|
39
45
|
/** Resolves when every detached dispatch has finished. */
|
|
40
46
|
idle(): Promise<void>;
|
|
47
|
+
/** Work still running sends nothing more and raises no row; the next leader takes it up from the message or the row. */
|
|
41
48
|
stop(): void;
|
|
49
|
+
/** A row raised after stop() would be raised again by the next leader, so the message is nak'd instead. */
|
|
50
|
+
private live;
|
|
42
51
|
private track;
|
|
43
52
|
private run;
|
|
44
53
|
/**
|
|
@@ -48,6 +57,8 @@ export declare class Executor {
|
|
|
48
57
|
* carrying the units out of it.
|
|
49
58
|
*/
|
|
50
59
|
private lateReply;
|
|
60
|
+
/** On arrival dispatch, a row that waited for the machine to prepare is received once every job it sent is ready. */
|
|
61
|
+
private readyForArrival;
|
|
51
62
|
/** Add the item; when the row then holds every key the action waits for, resolve it. */
|
|
52
63
|
private accumulate;
|
|
53
64
|
private check;
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* Runs the planner's actions: escalation verbs through LineEscalations,
|
|
4
4
|
* dispatches and commands through the Dispatcher, alarm and machine rows,
|
|
5
5
|
* and the offline debounce. A verb that fails for real throws, so the message that
|
|
6
|
-
* caused it is delivered again.
|
|
6
|
+
* caused it is delivered again. What ran comes back as wire actions, for the
|
|
7
|
+
* record of the message that caused it.
|
|
7
8
|
*/
|
|
8
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
10
|
exports.Executor = void 0;
|
|
@@ -16,18 +17,28 @@ const log_1 = require("./log");
|
|
|
16
17
|
const dispatcher_1 = require("./dispatcher");
|
|
17
18
|
const plan_shared_1 = require("./plan-shared");
|
|
18
19
|
const state_1 = require("./state");
|
|
20
|
+
const wire_1 = require("./wire");
|
|
19
21
|
const NOT_FOUND = 404;
|
|
20
22
|
const CONFLICT = 409;
|
|
23
|
+
/** A verb's outcome as the wire records it: done, already done, or refused by Long Tail. */
|
|
24
|
+
function outcomeOf(verb, rowId, result) {
|
|
25
|
+
const refused = result.outcome === escalations_1.VERB_OUTCOME.INVALID || result.status === NOT_FOUND || result.status === CONFLICT;
|
|
26
|
+
if (refused)
|
|
27
|
+
return { verb: 'refuse', rowId, detail: `${verb}: ${result.detail ?? result.outcome}` };
|
|
28
|
+
return { verb, rowId, ...(result.outcome === escalations_1.VERB_OUTCOME.ALREADY ? { detail: result.detail ?? 'already ended' } : {}) };
|
|
29
|
+
}
|
|
21
30
|
class Executor {
|
|
22
31
|
constructor(d) {
|
|
23
32
|
this.d = d;
|
|
24
33
|
this.inflight = new Set();
|
|
25
34
|
this.quietPending = new Set();
|
|
26
35
|
this.timers = new Set();
|
|
36
|
+
this.stopped = false;
|
|
27
37
|
this.dispatcher = new dispatcher_1.Dispatcher(d);
|
|
28
38
|
}
|
|
29
39
|
/** Dispatches and commands run detached so one slow reply never holds up the feed. */
|
|
30
40
|
async apply(actions) {
|
|
41
|
+
const done = [];
|
|
31
42
|
for (const action of actions) {
|
|
32
43
|
if (action.kind === 'dispatch')
|
|
33
44
|
this.track(this.dispatcher.dispatch(action));
|
|
@@ -35,22 +46,33 @@ class Executor {
|
|
|
35
46
|
this.track(this.dispatcher.command(action));
|
|
36
47
|
else if (action.kind === 'control')
|
|
37
48
|
this.track(this.dispatcher.control(action));
|
|
38
|
-
else
|
|
39
|
-
await this.run(action);
|
|
49
|
+
else {
|
|
50
|
+
done.push(...await this.run(action));
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
done.push((0, wire_1.plannedAction)(action));
|
|
40
54
|
}
|
|
55
|
+
return done;
|
|
41
56
|
}
|
|
42
57
|
/** Resolves when every detached dispatch has finished. */
|
|
43
58
|
async idle() {
|
|
44
59
|
while (this.inflight.size)
|
|
45
60
|
await Promise.all([...this.inflight]);
|
|
46
61
|
}
|
|
62
|
+
/** Work still running sends nothing more and raises no row; the next leader takes it up from the message or the row. */
|
|
47
63
|
stop() {
|
|
64
|
+
this.stopped = true;
|
|
48
65
|
for (const t of this.timers)
|
|
49
66
|
clearTimeout(t);
|
|
50
67
|
this.timers.clear();
|
|
51
68
|
this.dispatcher.stop();
|
|
52
69
|
this.d.replies.cancelAll();
|
|
53
70
|
}
|
|
71
|
+
/** A row raised after stop() would be raised again by the next leader, so the message is nak'd instead. */
|
|
72
|
+
live() {
|
|
73
|
+
if (this.stopped)
|
|
74
|
+
throw new dispatcher_1.GatewayStopped();
|
|
75
|
+
}
|
|
54
76
|
track(work) {
|
|
55
77
|
const tracked = work.catch((err) => {
|
|
56
78
|
if (!(err instanceof dispatcher_1.GatewayStopped))
|
|
@@ -62,37 +84,48 @@ class Executor {
|
|
|
62
84
|
async run(a) {
|
|
63
85
|
const { lt, state, replies } = this.d;
|
|
64
86
|
switch (a.kind) {
|
|
65
|
-
case 'claim':
|
|
66
|
-
|
|
87
|
+
case 'claim': {
|
|
88
|
+
const result = await lt.claim(a.as, a.rowId);
|
|
89
|
+
this.check(a, result);
|
|
90
|
+
return [outcomeOf('claim', a.rowId, result)];
|
|
91
|
+
}
|
|
67
92
|
case 'accumulate':
|
|
68
93
|
return this.accumulate(a);
|
|
69
|
-
case 'resolve':
|
|
70
|
-
|
|
94
|
+
case 'resolve': {
|
|
95
|
+
const result = await lt.resolve(a.as, a.rowId, a.payload);
|
|
96
|
+
this.check(a, result);
|
|
71
97
|
state.close(a.rowId);
|
|
72
|
-
return;
|
|
98
|
+
return [outcomeOf('resolve', a.rowId, result)];
|
|
99
|
+
}
|
|
73
100
|
case 'createAlarmRow':
|
|
74
|
-
return this.createAlarmRow(a);
|
|
101
|
+
return [{ verb: 'create-row', rowId: await this.createAlarmRow(a), detail: `${a.row.type} ${a.alarmId} at ${a.machineId}` }];
|
|
75
102
|
case 'createRow': {
|
|
103
|
+
this.live();
|
|
76
104
|
const { id } = await lt.create(actions_1.CONTROLLER, a.row);
|
|
77
105
|
this.d.log.info(log_1.GATEWAY_LOG.VIOLATION_ROW, { row: id, type: a.row.type });
|
|
78
|
-
return;
|
|
106
|
+
return [{ verb: 'create-row', rowId: id, detail: a.row.type }];
|
|
79
107
|
}
|
|
80
108
|
case 'watchOffline':
|
|
81
|
-
|
|
109
|
+
this.watchOffline(a.machineId);
|
|
110
|
+
return [(0, wire_1.plannedAction)(a)];
|
|
82
111
|
case 'settleReply':
|
|
83
|
-
if (
|
|
84
|
-
|
|
85
|
-
return;
|
|
112
|
+
if (replies.settle({ cmdId: a.cmdId, status: a.status, reason: a.reason, ...(a.code ? { code: a.code } : {}), ...(a.preparing ? { preparing: true } : {}) }))
|
|
113
|
+
return [(0, wire_1.plannedAction)(a)];
|
|
114
|
+
return [{ verb: 'ack', detail: `late ${a.status} ${a.cmdId}` }, ...await this.lateReply(a)];
|
|
86
115
|
case 'settleSnapshot':
|
|
87
116
|
replies.settleSnapshot(a.machineId, new Set(a.jobIds));
|
|
88
|
-
return;
|
|
117
|
+
return [(0, wire_1.plannedAction)(a)];
|
|
89
118
|
case 'bindAddress':
|
|
90
119
|
await this.d.addresses.bind(a.machineId, a.address);
|
|
91
120
|
state.bindAddress(a.machineId, a.address);
|
|
92
121
|
this.d.log.info(log_1.GATEWAY_LOG.ADDRESS_BOUND, { machine: a.machineId, address: a.address, ...(a.by ? { approvedBy: a.by } : {}) });
|
|
93
|
-
return;
|
|
122
|
+
return [{ verb: 'ack', detail: `bound ${a.machineId} to ${a.address}` }];
|
|
94
123
|
case 'refuseBinding':
|
|
95
124
|
this.d.log.warn(log_1.GATEWAY_LOG.ADDRESS_REFUSED, { machine: a.machineId, address: a.address, reason: a.reason });
|
|
125
|
+
return [(0, wire_1.plannedAction)(a)];
|
|
126
|
+
case 'unrecoverable':
|
|
127
|
+
this.d.log.warn(log_1.GATEWAY_LOG.DISPATCH_UNRECOVERABLE, { machine: a.machineId, jobs: a.jobs });
|
|
128
|
+
return [(0, wire_1.plannedAction)(a)];
|
|
96
129
|
}
|
|
97
130
|
}
|
|
98
131
|
/**
|
|
@@ -106,34 +139,52 @@ class Executor {
|
|
|
106
139
|
const into = state.rowForDispatch(a.cmdId);
|
|
107
140
|
const m = into?.toMachine;
|
|
108
141
|
if (!into || !m)
|
|
109
|
-
return;
|
|
142
|
+
return [];
|
|
110
143
|
const context = { row: into.id, machine: m, cmdId: a.cmdId, reason: a.reason };
|
|
111
|
-
if (a.status === protocol_1.REPLY_STATUS.COMPLETED)
|
|
112
|
-
|
|
144
|
+
if (a.status === protocol_1.REPLY_STATUS.COMPLETED) {
|
|
145
|
+
log.info(log_1.GATEWAY_LOG.DISPATCH_READY, context);
|
|
146
|
+
return this.readyForArrival(into, m, a.cmdId);
|
|
147
|
+
}
|
|
113
148
|
if (a.status !== protocol_1.REPLY_STATUS.FAILED)
|
|
114
|
-
return;
|
|
149
|
+
return [];
|
|
115
150
|
const row = into.ended ? onwardRow(state, into, m) : into;
|
|
116
151
|
log.warn(log_1.GATEWAY_LOG.DISPATCH_FAILED, { ...context, ...(into.ended ? { onward: row?.id ?? null } : {}) });
|
|
117
152
|
if (!row)
|
|
118
|
-
return;
|
|
119
|
-
|
|
120
|
-
received: false, errorCode: contracts_1.HANDOFF_ERROR.DISPATCH_FAILED, detail: `${m} could not prepare the job: ${a.reason}`,
|
|
153
|
+
return [];
|
|
154
|
+
return this.apply((0, plan_shared_1.failHandoff)(state, row, m, {
|
|
155
|
+
received: false, errorCode: contracts_1.HANDOFF_ERROR.DISPATCH_FAILED, detail: `${m} could not prepare the job: ${a.reason}`, ...(a.code ? { code: a.code } : {}),
|
|
121
156
|
}));
|
|
122
157
|
}
|
|
158
|
+
/** On arrival dispatch, a row that waited for the machine to prepare is received once every job it sent is ready. */
|
|
159
|
+
async readyForArrival(into, m, cmdId) {
|
|
160
|
+
const { lt, state } = this.d;
|
|
161
|
+
if (into.ended || !into.awaitingReady?.has(cmdId))
|
|
162
|
+
return [];
|
|
163
|
+
into.awaitingReady.delete(cmdId);
|
|
164
|
+
if (into.awaitingReady.size)
|
|
165
|
+
return [];
|
|
166
|
+
const units = into.units.map((u) => u.unitId);
|
|
167
|
+
const resolved = await lt.resolve(m, into.id, { received: true, receiver: m, units });
|
|
168
|
+
state.close(into.id);
|
|
169
|
+
return [outcomeOf('resolve', into.id, resolved)];
|
|
170
|
+
}
|
|
123
171
|
/** Add the item; when the row then holds every key the action waits for, resolve it. */
|
|
124
172
|
async accumulate(a) {
|
|
125
173
|
const { lt, state } = this.d;
|
|
126
174
|
const result = await lt.accumulate(a.as, a.rowId, a.itemKey, a.payload, a.metadata);
|
|
127
175
|
this.check(a, result);
|
|
176
|
+
const added = { ...outcomeOf('accumulate', a.rowId, result), itemKey: a.itemKey };
|
|
128
177
|
if (!a.complete || result.outcome === escalations_1.VERB_OUTCOME.INVALID)
|
|
129
|
-
return;
|
|
178
|
+
return [added];
|
|
130
179
|
const held = new Set(result.itemKeys ?? await lt.itemKeys(a.rowId));
|
|
131
180
|
if (!a.complete.keys.every((k) => held.has(k)))
|
|
132
|
-
return;
|
|
181
|
+
return [added];
|
|
133
182
|
if (a.complete.then)
|
|
134
|
-
return this.apply(a.complete.then);
|
|
135
|
-
|
|
183
|
+
return [added, ...await this.apply(a.complete.then)];
|
|
184
|
+
const resolved = await lt.resolve(a.as, a.rowId, a.complete.payload ?? {});
|
|
185
|
+
this.check(a, resolved);
|
|
136
186
|
state.close(a.rowId);
|
|
187
|
+
return [added, outcomeOf('resolve', a.rowId, resolved)];
|
|
137
188
|
}
|
|
138
189
|
check(a, result) {
|
|
139
190
|
const rowId = a.rowId;
|
|
@@ -148,17 +199,19 @@ class Executor {
|
|
|
148
199
|
}
|
|
149
200
|
}
|
|
150
201
|
async createAlarmRow(a) {
|
|
202
|
+
this.live();
|
|
151
203
|
const { id } = await this.d.lt.create(actions_1.CONTROLLER, { ...a.row, role: (0, line_1.operatorRole)(this.d.line) });
|
|
152
204
|
this.d.log.info(log_1.GATEWAY_LOG.ALARM_ROW, { row: id, machine: a.machineId, alarm: a.alarmId });
|
|
153
205
|
const track = this.d.state.alarms.get(this.d.state.alarmKey(a.machineId, a.alarmId));
|
|
154
206
|
const raisedAt = a.row.metadata?.raisedAt;
|
|
155
207
|
if (track && (!track.raisedAt || !raisedAt || track.raisedAt === raisedAt)) {
|
|
156
208
|
track.rowId = id;
|
|
157
|
-
return;
|
|
209
|
+
return id;
|
|
158
210
|
}
|
|
159
211
|
// Cleared at the machine, or raised again, while the row was being created.
|
|
160
212
|
const note = track ? `${a.machineId} raised ${a.alarmId} again; this one ended` : `cleared at ${a.machineId}`;
|
|
161
213
|
await this.d.lt.resolve(actions_1.CONTROLLER, id, { decision: contracts_1.DECISION.CLEARED, note });
|
|
214
|
+
return id;
|
|
162
215
|
}
|
|
163
216
|
/** Raise a quiet row for each connected machine silent longer than `quietMs`. */
|
|
164
217
|
checkQuiet(machineIds, quietMs) {
|
|
@@ -172,6 +225,7 @@ class Executor {
|
|
|
172
225
|
}
|
|
173
226
|
}
|
|
174
227
|
async raiseQuiet(machineId, silentMs) {
|
|
228
|
+
this.live();
|
|
175
229
|
const { id } = await this.d.lt.create(actions_1.CONTROLLER, {
|
|
176
230
|
type: contracts_1.ROW_TYPE.MACHINE_QUIET, role: (0, line_1.operatorRole)(this.d.line), priority: 2,
|
|
177
231
|
description: `${machineId} is connected but has sent nothing for ${Math.round(silentMs / 1000)} s`,
|
|
@@ -194,11 +248,12 @@ class Executor {
|
|
|
194
248
|
link.watching = false;
|
|
195
249
|
if (link.online || link.rowId)
|
|
196
250
|
return;
|
|
251
|
+
this.live();
|
|
197
252
|
const since = new Date(link.since).toISOString();
|
|
198
253
|
const { id } = await this.d.lt.create(actions_1.CONTROLLER, {
|
|
199
254
|
type: contracts_1.ROW_TYPE.MACHINE_OFFLINE, role: (0, line_1.operatorRole)(this.d.line), priority: 2,
|
|
200
255
|
description: `${machineId} has been offline since ${since}`,
|
|
201
|
-
metadata: { siteId: this.d.line.siteId, lineId: this.d.line.lineId, machineId, offlineSince: since },
|
|
256
|
+
metadata: { siteId: this.d.line.siteId, lineId: this.d.line.lineId, machineId, offlineSince: since, ...(link.reason ? { reason: link.reason } : {}) },
|
|
202
257
|
});
|
|
203
258
|
this.d.log.info(log_1.GATEWAY_LOG.OFFLINE_ROW, { row: id, machine: machineId });
|
|
204
259
|
if (!link.online)
|
|
@@ -3,15 +3,19 @@
|
|
|
3
3
|
* reads escalation events (a new handoff row means "dispatch"), reads every
|
|
4
4
|
* machine message on the line (a receipt means "resolve"), and performs the
|
|
5
5
|
* verbs a person would, as the machine. Neither side knows about the other.
|
|
6
|
+
* Every message read or sent is recorded on the wire (wire.ts).
|
|
6
7
|
*/
|
|
7
8
|
import { type HandoffRowAdapter } from '../rows';
|
|
8
9
|
import { type AddressBook } from './address-book';
|
|
9
10
|
import type { LineDef } from '../../../lib/machines/line';
|
|
10
11
|
import { type LineCodec } from '../../../lib/machines/protocol';
|
|
11
|
-
import { type EscalationFeed, type MachineBus } from '../../../lib/machines/transport';
|
|
12
|
+
import { type EscalationFeed, type InboundMessage, type MachineBus } from '../../../lib/machines/transport';
|
|
13
|
+
import type { InspectResult } from '../../../types/machines-view';
|
|
12
14
|
import type { LineEscalations } from './escalations';
|
|
13
15
|
import { type GatewayLog } from './log';
|
|
14
16
|
import { GatewayState } from './state';
|
|
17
|
+
import { type WireSink } from './wire';
|
|
18
|
+
import { WireWindow } from './wire-window';
|
|
15
19
|
export interface GatewaySettings {
|
|
16
20
|
topicRoot: string;
|
|
17
21
|
replyTimeoutMs: number;
|
|
@@ -27,6 +31,10 @@ export interface GatewaySettings {
|
|
|
27
31
|
lifecycle?: boolean;
|
|
28
32
|
/** With lifecycle notes, progress is noted each time it crosses this many percent; 0 notes none. */
|
|
29
33
|
progressStep?: number;
|
|
34
|
+
/** Record telemetry messages on the wire too; off unless set. */
|
|
35
|
+
wireTelemetry?: boolean;
|
|
36
|
+
/** How many of the latest wire events the gateway keeps for reading over HTTP; 500 by default. */
|
|
37
|
+
wireWindow?: number;
|
|
30
38
|
}
|
|
31
39
|
export interface GatewayDeps {
|
|
32
40
|
bus: MachineBus;
|
|
@@ -41,6 +49,8 @@ export interface GatewayDeps {
|
|
|
41
49
|
codec?: LineCodec;
|
|
42
50
|
/** Where a line that learns addresses keeps them; in memory by default. */
|
|
43
51
|
addresses?: AddressBook;
|
|
52
|
+
/** Where wire records go; Long Tail's events by default. */
|
|
53
|
+
wire?: WireSink;
|
|
44
54
|
}
|
|
45
55
|
export declare class MachineGateway {
|
|
46
56
|
private readonly deps;
|
|
@@ -52,14 +62,24 @@ export declare class MachineGateway {
|
|
|
52
62
|
private readonly log;
|
|
53
63
|
private readonly addresses;
|
|
54
64
|
private readonly admission;
|
|
65
|
+
private readonly wire;
|
|
66
|
+
/** The line's last wire events, newest first on read. */
|
|
67
|
+
readonly window: WireWindow;
|
|
55
68
|
private quietTimer?;
|
|
56
69
|
constructor(deps: GatewayDeps);
|
|
57
70
|
start(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Hand the line over cleanly: nothing new is raised or sent, a message
|
|
73
|
+
* still being handled is nak'd for the next leader if it would make a row,
|
|
74
|
+
* receipts for what was applied go out, then the sessions close.
|
|
75
|
+
*/
|
|
58
76
|
stop(): Promise<void>;
|
|
59
77
|
/** Machines that report only changes are asked for their full state once the gateway listens. */
|
|
60
78
|
private askEveryMachine;
|
|
61
79
|
/** Resolves when no dispatch is in flight (tests). */
|
|
62
80
|
idle(): Promise<void>;
|
|
81
|
+
/** A dry run of one message on a copy of the state: nothing is applied (inspect.ts). */
|
|
82
|
+
inspect(msg: Pick<InboundMessage, 'topic' | 'payload' | 'retained'>): InspectResult;
|
|
63
83
|
/**
|
|
64
84
|
* On taking the line: open handoff and command rows (a dispatch or command
|
|
65
85
|
* interrupted by a restart is sent again with the same cmdId), the gateway's
|