@hotmeshio/long-tail 0.26.0 → 0.28.0
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/settings.d.ts +4 -1
- package/build/api/settings.js +7 -1
- package/build/index.d.ts +4 -0
- package/build/index.js +35 -8
- 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/events/browser-view.js +8 -2
- package/build/lib/events/nats.d.ts +11 -0
- package/build/lib/events/nats.js +33 -2
- package/build/lib/events/publish.d.ts +33 -0
- package/build/lib/events/publish.js +52 -1
- package/build/lib/machines/index.d.ts +1 -0
- package/build/lib/machines/index.js +1 -0
- package/build/lib/machines/line.d.ts +4 -1
- package/build/lib/machines/line.js +18 -1
- package/build/lib/machines/protocol/codec.d.ts +24 -0
- package/build/lib/machines/protocol/codec.js +10 -0
- 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.js +12 -3
- package/build/lib/machines/site/edge-account.d.ts +11 -0
- package/build/lib/machines/site/edge-account.js +24 -0
- package/build/lib/machines/site/mosquitto-conf.d.ts +5 -4
- package/build/lib/machines/site/mosquitto-conf.js +31 -16
- package/build/lib/machines/site/site-conf.d.ts +16 -6
- package/build/lib/machines/site/site-conf.js +39 -13
- 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/delivery.d.ts +3 -4
- package/build/lib/machines/transport/delivery.js +3 -8
- package/build/lib/machines/transport/index.d.ts +2 -0
- package/build/lib/machines/transport/index.js +2 -0
- 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 +8 -13
- package/build/lib/machines/transport/nats-bus.js +26 -43
- package/build/lib/machines/transport/nats-feed.d.ts +1 -0
- package/build/lib/machines/transport/nats-feed.js +6 -3
- package/build/lib/machines/transport/pubsub-feed.d.ts +18 -0
- package/build/lib/machines/transport/pubsub-feed.js +42 -0
- package/build/lib/machines/transport/stream-bus.d.ts +42 -0
- package/build/lib/machines/transport/stream-bus.js +61 -0
- package/build/lib/machines/transport/streams.d.ts +10 -14
- package/build/lib/machines/transport/streams.js +18 -61
- package/build/lib/messaging/config.d.ts +25 -0
- package/build/lib/messaging/config.js +55 -0
- package/build/lib/messaging/constants.d.ts +26 -0
- package/build/lib/messaging/constants.js +26 -0
- package/build/lib/messaging/index.d.ts +24 -0
- package/build/lib/messaging/index.js +65 -0
- package/build/lib/messaging/memory.d.ts +16 -0
- package/build/lib/messaging/memory.js +147 -0
- package/build/lib/messaging/nats/permissions.d.ts +13 -0
- package/build/lib/messaging/nats/permissions.js +22 -0
- package/build/lib/messaging/nats/provider.d.ts +30 -0
- package/build/lib/messaging/nats/provider.js +77 -0
- package/build/lib/messaging/nats/render-conf.d.ts +68 -0
- package/build/lib/messaging/nats/render-conf.js +58 -0
- package/build/lib/messaging/nats/streams.d.ts +26 -0
- package/build/lib/messaging/nats/streams.js +97 -0
- package/build/lib/messaging/subjects.d.ts +8 -0
- package/build/lib/messaging/subjects.js +25 -0
- package/build/modules/machines.d.ts +8 -0
- package/build/modules/machines.js +16 -0
- package/build/routes/index.js +2 -0
- package/build/routes/machines.d.ts +2 -0
- package/build/routes/machines.js +220 -0
- package/build/scripts/bambu-boat.d.ts +17 -0
- package/build/scripts/bambu-boat.js +134 -0
- package/build/scripts/bambu-print.d.ts +18 -0
- package/build/scripts/bambu-print.js +114 -0
- package/build/services/machines/commands.d.ts +5 -5
- package/build/services/machines/commands.js +3 -2
- package/build/services/machines/config.d.ts +8 -1
- package/build/services/machines/config.js +17 -7
- package/build/services/machines/contracts.d.ts +29 -2
- package/build/services/machines/contracts.js +12 -3
- package/build/services/machines/gateway/actions.d.ts +2 -1
- package/build/services/machines/gateway/admission.d.ts +15 -3
- package/build/services/machines/gateway/admission.js +29 -14
- package/build/services/machines/gateway/dispatcher.d.ts +19 -3
- package/build/services/machines/gateway/dispatcher.js +61 -13
- package/build/services/machines/gateway/executor.d.ts +18 -4
- package/build/services/machines/gateway/executor.js +99 -34
- package/build/services/machines/gateway/gateway.d.ts +22 -1
- package/build/services/machines/gateway/gateway.js +83 -28
- 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/lifecycle.d.ts +21 -0
- package/build/services/machines/gateway/lifecycle.js +89 -0
- package/build/services/machines/gateway/log.d.ts +8 -0
- package/build/services/machines/gateway/log.js +18 -0
- package/build/services/machines/gateway/pacing.d.ts +14 -0
- package/build/services/machines/gateway/pacing.js +27 -2
- package/build/services/machines/gateway/plan-escalation.js +21 -7
- package/build/services/machines/gateway/plan-machine.d.ts +5 -4
- package/build/services/machines/gateway/plan-machine.js +70 -19
- 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.d.ts +2 -0
- package/build/services/machines/gateway/reconcile.js +16 -3
- package/build/services/machines/gateway/registration.js +1 -1
- package/build/services/machines/gateway/reply-waiter.d.ts +6 -3
- package/build/services/machines/gateway/reply-waiter.js +37 -16
- package/build/services/machines/gateway/state.d.ts +50 -4
- package/build/services/machines/gateway/state.js +77 -10
- package/build/services/machines/gateway/wire.d.ts +58 -0
- package/build/services/machines/gateway/wire.js +171 -0
- package/build/services/machines/index.d.ts +3 -0
- package/build/services/machines/index.js +2 -0
- package/build/services/machines/leadership.d.ts +17 -4
- package/build/services/machines/leadership.js +43 -18
- 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/rows.js +26 -2
- package/build/services/machines/select.d.ts +9 -2
- package/build/services/machines/select.js +20 -7
- package/build/services/machines/surface.d.ts +45 -5
- package/build/services/machines/surface.js +102 -16
- package/build/services/machines/testing/fake-long-tail.d.ts +1 -0
- package/build/services/machines/testing/fake-long-tail.js +6 -3
- package/build/start/adapters.js +11 -2
- package/build/start/apply-report.d.ts +1 -1
- package/build/start/apply-report.js +3 -25
- package/build/start/index.js +23 -5
- 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/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/events.d.ts +6 -1
- package/build/types/index.d.ts +2 -0
- package/build/types/machines-view.d.ts +159 -0
- package/build/types/machines-view.js +7 -0
- package/build/types/machines.d.ts +6 -1
- package/build/types/messaging.d.ts +72 -0
- package/build/types/messaging.js +11 -0
- package/build/types/startup.d.ts +26 -1
- 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 +1 -0
- package/docs/events.md +83 -4
- package/docs/machines.md +129 -23
- package/docs/mcp.md +19 -0
- package/package.json +3 -1
- package/build/lib/machines/transport/nats-durable.d.ts +0 -11
- package/build/lib/machines/transport/nats-durable.js +0 -28
- package/dashboard/dist/assets/AgentsPage-C9UuUKhr.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-DrvfXz70.js +0 -2
- package/dashboard/dist/assets/FilterBar-BygWrnB1.js +0 -2
- package/dashboard/dist/assets/FilterBar-BygWrnB1.js.map +0 -1
- package/dashboard/dist/assets/McpRunDetailPage-80fQn9iX.js +0 -2
- package/dashboard/dist/assets/WorkflowExecutionPage-Di08wCbs.js +0 -2
- package/dashboard/dist/assets/index-4YaDUcKd.js +0 -2
- package/dashboard/dist/assets/index-CnU7Jjz3.css +0 -1
- package/dashboard/dist/assets/index-Dz6R8-Dw.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-DUYcKTjP.js.map +0 -1
|
@@ -0,0 +1,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
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job lifecycle on the row. A machine's started and progress events, and the
|
|
3
|
+
* alarms that stop it, are noted as items on the open row that holds the job:
|
|
4
|
+
* the accepted dispatch into the machine until its units arrive, then the
|
|
5
|
+
* handoff out of it. Progress is noted only when it crosses a step, or reaches
|
|
6
|
+
* a named stage it has not reached before, so a row carries a handful of items
|
|
7
|
+
* while the stream keeps every report.
|
|
8
|
+
*
|
|
9
|
+
* Off unless the line turns it on (MACHINE_LIFECYCLE=on). A row parked with a
|
|
10
|
+
* limit on its items gets no notes, so they never use a slot its units need.
|
|
11
|
+
*/
|
|
12
|
+
import type { Action } from './actions';
|
|
13
|
+
import { type AlarmTrack, type GatewayState } from './state';
|
|
14
|
+
/** The progress step `percent` has reached; null below the first step, at 100, or when steps are off. */
|
|
15
|
+
export declare function progressStepOf(percent: unknown, step: number): number | null;
|
|
16
|
+
/** A started or progress event, noted on the row that holds the job. */
|
|
17
|
+
export declare function noteJobEvent(state: GatewayState, m: string, b: Record<string, any>, at: string | undefined): Action[];
|
|
18
|
+
/** Rows a stopping alarm pauses: those running or leaving with its job, or every row the machine holds. */
|
|
19
|
+
export declare function notePause(state: GatewayState, track: AlarmTrack, b: Record<string, any>): Action[];
|
|
20
|
+
/** The machine cleared an alarm: the rows it paused, still open, note the resume. */
|
|
21
|
+
export declare function noteResume(state: GatewayState, track: AlarmTrack, b: Record<string, any>): Action[];
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Job lifecycle on the row. A machine's started and progress events, and the
|
|
4
|
+
* alarms that stop it, are noted as items on the open row that holds the job:
|
|
5
|
+
* the accepted dispatch into the machine until its units arrive, then the
|
|
6
|
+
* handoff out of it. Progress is noted only when it crosses a step, or reaches
|
|
7
|
+
* a named stage it has not reached before, so a row carries a handful of items
|
|
8
|
+
* while the stream keeps every report.
|
|
9
|
+
*
|
|
10
|
+
* Off unless the line turns it on (MACHINE_LIFECYCLE=on). A row parked with a
|
|
11
|
+
* limit on its items gets no notes, so they never use a slot its units need.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.progressStepOf = progressStepOf;
|
|
15
|
+
exports.noteJobEvent = noteJobEvent;
|
|
16
|
+
exports.notePause = notePause;
|
|
17
|
+
exports.noteResume = noteResume;
|
|
18
|
+
const contracts_1 = require("../contracts");
|
|
19
|
+
const protocol_1 = require("../../../lib/machines/protocol");
|
|
20
|
+
const jobs_1 = require("./jobs");
|
|
21
|
+
const state_1 = require("./state");
|
|
22
|
+
const owns = (jobId, reported) => !jobId || typeof reported !== 'string' || (0, jobs_1.jobOwns)(jobId, reported);
|
|
23
|
+
const runningAt = (r, m, jobId) => r.toMachine === m && r.dispatch === state_1.DISPATCH_STATE.ACCEPTED && owns(r.jobId, jobId);
|
|
24
|
+
const leavingFrom = (r, m, jobId) => r.fromMachine === m && !!r.senderJobId && owns(r.senderJobId, jobId);
|
|
25
|
+
/** The open row holding `unitId` at `m`: its accepted dispatch, else the handoff out of `m`. */
|
|
26
|
+
function holderRow(state, m, unitId, jobId) {
|
|
27
|
+
return state.openFor(unitId, (r) => runningAt(r, m, jobId)) ?? state.openFor(unitId, (r) => leavingFrom(r, m, jobId));
|
|
28
|
+
}
|
|
29
|
+
/** The progress step `percent` has reached; null below the first step, at 100, or when steps are off. */
|
|
30
|
+
function progressStepOf(percent, step) {
|
|
31
|
+
if (step <= 0 || typeof percent !== 'number' || !Number.isFinite(percent))
|
|
32
|
+
return null;
|
|
33
|
+
const reached = Math.floor(percent / step) * step;
|
|
34
|
+
return reached > 0 && reached < 100 ? reached : null;
|
|
35
|
+
}
|
|
36
|
+
/** An item the row does not hold yet, added as the machine. */
|
|
37
|
+
function note(row, m, itemKey, payload, metadata) {
|
|
38
|
+
if (row.capped || row.noted?.includes(itemKey))
|
|
39
|
+
return [];
|
|
40
|
+
row.noted = [...(row.noted ?? []), itemKey];
|
|
41
|
+
return [{ kind: 'accumulate', as: m, rowId: row.id, itemKey, payload, ...(metadata ? { metadata } : {}) }];
|
|
42
|
+
}
|
|
43
|
+
/** A started or progress event, noted on the row that holds the job. */
|
|
44
|
+
function noteJobEvent(state, m, b, at) {
|
|
45
|
+
const unitId = b.unitId;
|
|
46
|
+
if (!state.lifecycle || typeof unitId !== 'string')
|
|
47
|
+
return [];
|
|
48
|
+
const row = holderRow(state, m, unitId, b.jobId);
|
|
49
|
+
if (!row)
|
|
50
|
+
return [];
|
|
51
|
+
const when = at ?? new Date().toISOString();
|
|
52
|
+
if (b.event === protocol_1.JOB_EVENT.STARTED) {
|
|
53
|
+
return note(row, m, contracts_1.itemKeys.started(unitId), { unitId, jobId: b.jobId ?? null, at: when });
|
|
54
|
+
}
|
|
55
|
+
const step = progressStepOf(b.percent, state.progressStep);
|
|
56
|
+
const stage = typeof b.stage === 'string' && b.stage ? b.stage : null;
|
|
57
|
+
if (step === null && stage === null)
|
|
58
|
+
return [];
|
|
59
|
+
const progress = {
|
|
60
|
+
...(typeof b.percent === 'number' ? { percent: b.percent } : {}), remainingSec: b.remainingSec ?? null, ...(stage ? { stage } : {}), at: when,
|
|
61
|
+
...(b.detail && typeof b.detail === 'object' ? { detail: b.detail } : {}),
|
|
62
|
+
};
|
|
63
|
+
const facet = { [contracts_1.LIFECYCLE_FACET.PROGRESS]: progress };
|
|
64
|
+
const job = { unitId, jobId: b.jobId ?? null };
|
|
65
|
+
return [
|
|
66
|
+
...(step === null ? [] : note(row, m, contracts_1.itemKeys.progress(unitId, step), { ...job, step, ...progress }, facet)),
|
|
67
|
+
...(stage === null ? [] : note(row, m, contracts_1.itemKeys.stage(unitId, stage), { ...job, ...progress }, facet)),
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
/** Rows a stopping alarm pauses: those running or leaving with its job, or every row the machine holds. */
|
|
71
|
+
function notePause(state, track, b) {
|
|
72
|
+
if (!state.lifecycle)
|
|
73
|
+
return [];
|
|
74
|
+
const m = track.machineId;
|
|
75
|
+
const jobId = typeof b.jobId === 'string' ? b.jobId : undefined;
|
|
76
|
+
const rows = state.open().filter((r) => runningAt(r, m, jobId) || leavingFrom(r, m, jobId));
|
|
77
|
+
track.noted = rows.map((r) => r.id);
|
|
78
|
+
const payload = { alarmId: track.alarmId, code: b.code ?? null, level: b.level ?? null, text: b.text ?? null, raisedAt: b.raisedAt ?? null };
|
|
79
|
+
return rows.flatMap((r) => note(r, m, contracts_1.itemKeys.paused(track.alarmId, String(b.raisedAt ?? '')), payload));
|
|
80
|
+
}
|
|
81
|
+
/** The machine cleared an alarm: the rows it paused, still open, note the resume. */
|
|
82
|
+
function noteResume(state, track, b) {
|
|
83
|
+
const key = contracts_1.itemKeys.resumed(track.alarmId, String(track.raisedAt ?? ''));
|
|
84
|
+
const payload = { alarmId: track.alarmId, clearedAt: b.clearedAt ?? new Date().toISOString(), clearedBy: b.clearedBy ?? null };
|
|
85
|
+
return (track.noted ?? [])
|
|
86
|
+
.map((id) => state.get(id))
|
|
87
|
+
.filter((r) => !!r && !r.ended)
|
|
88
|
+
.flatMap((r) => note(r, track.machineId, key, payload));
|
|
89
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
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";
|
|
@@ -39,3 +40,10 @@ export interface GatewayLog {
|
|
|
39
40
|
}
|
|
40
41
|
export declare const consoleLog: GatewayLog;
|
|
41
42
|
export declare const silentLog: GatewayLog;
|
|
43
|
+
/** Each entry published as `machine.log.<site>.<line>.<event>` with its context, for the line's dashboard view. */
|
|
44
|
+
export declare function eventsLog(line: {
|
|
45
|
+
siteId: string;
|
|
46
|
+
lineId: string;
|
|
47
|
+
}, publish?: typeof publishMachineLogEvent): GatewayLog;
|
|
48
|
+
/** Every entry goes to each log in turn. */
|
|
49
|
+
export declare function composeLogs(...logs: GatewayLog[]): GatewayLog;
|
|
@@ -1,6 +1,9 @@
|
|
|
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',
|
|
@@ -40,3 +43,18 @@ exports.consoleLog = {
|
|
|
40
43
|
error: (event, context) => console.error(JSON.stringify({ level: 'error', event, ...context })),
|
|
41
44
|
};
|
|
42
45
|
exports.silentLog = { info: () => undefined, warn: () => undefined, error: () => undefined };
|
|
46
|
+
/** Each entry published as `machine.log.<site>.<line>.<event>` with its context, for the line's dashboard view. */
|
|
47
|
+
function eventsLog(line, publish = publish_1.publishMachineLogEvent) {
|
|
48
|
+
const emit = (level) => (event, context) => {
|
|
49
|
+
publish({ siteId: line.siteId, lineId: line.lineId, level, event, context }).catch(() => undefined);
|
|
50
|
+
};
|
|
51
|
+
return { info: emit('info'), warn: emit('warn'), error: emit('error') };
|
|
52
|
+
}
|
|
53
|
+
/** Every entry goes to each log in turn. */
|
|
54
|
+
function composeLogs(...logs) {
|
|
55
|
+
const each = (level) => (event, context) => {
|
|
56
|
+
for (const log of logs)
|
|
57
|
+
log[level](event, context);
|
|
58
|
+
};
|
|
59
|
+
return { info: each('info'), warn: each('warn'), error: each('error') };
|
|
60
|
+
}
|
|
@@ -11,6 +11,20 @@ import { type Action } from './actions';
|
|
|
11
11
|
import { type GatewayState, type HandoffRow } from './state';
|
|
12
12
|
/** Dispatch arguments for a handoff row. */
|
|
13
13
|
export declare function dispatchArgs(row: HandoffRow, expiresAt: number): Record<string, any>;
|
|
14
|
+
/**
|
|
15
|
+
* The validity round a dispatch belongs to. Rounds of one validity period count
|
|
16
|
+
* from when the dispatch became due, and a round begins only when the one
|
|
17
|
+
* before it has expired, so a machine never holds two valid commands for one
|
|
18
|
+
* row. Within a round a dispatch sent again, by a retry, a restarted machine or
|
|
19
|
+
* a restarted gateway, is the same command with the same arguments; a new round
|
|
20
|
+
* is a new command, never an old one with changed arguments.
|
|
21
|
+
*/
|
|
22
|
+
export declare function dispatchWindow(dueAt: number, now: number, ttlMs: number): {
|
|
23
|
+
round: number;
|
|
24
|
+
expiresAt: number;
|
|
25
|
+
};
|
|
26
|
+
/** The later of a row's due time and an arrival's time; an unreadable time leaves it as it was. */
|
|
27
|
+
export declare function latestArrival(dueAt: number | undefined, at: unknown): number | undefined;
|
|
14
28
|
export declare function dispatchAction(row: HandoffRow, machineId: string, dispatchTtlMs: number): Action;
|
|
15
29
|
/** A machine on a version the line does not allow is refused before any dispatch. */
|
|
16
30
|
export declare function softwareRefusal(state: GatewayState, line: LineDef, machineId: string): string | null;
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.dispatchArgs = dispatchArgs;
|
|
12
|
+
exports.dispatchWindow = dispatchWindow;
|
|
13
|
+
exports.latestArrival = latestArrival;
|
|
12
14
|
exports.dispatchAction = dispatchAction;
|
|
13
15
|
exports.softwareRefusal = softwareRefusal;
|
|
14
16
|
exports.artifactRefusal = artifactRefusal;
|
|
@@ -37,11 +39,34 @@ function dispatchArgs(row, expiresAt) {
|
|
|
37
39
|
expiresAt: (0, protocol_1.isoTs)(expiresAt),
|
|
38
40
|
...(row.artifactUrl ? { artifact: { url: row.artifactUrl, sha256: row.artifactSha256 } } : {}),
|
|
39
41
|
...(row.parameters ? { parameters: row.parameters } : {}),
|
|
42
|
+
...(row.refs ? { refs: row.refs } : {}),
|
|
40
43
|
};
|
|
41
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* The validity round a dispatch belongs to. Rounds of one validity period count
|
|
47
|
+
* from when the dispatch became due, and a round begins only when the one
|
|
48
|
+
* before it has expired, so a machine never holds two valid commands for one
|
|
49
|
+
* row. Within a round a dispatch sent again, by a retry, a restarted machine or
|
|
50
|
+
* a restarted gateway, is the same command with the same arguments; a new round
|
|
51
|
+
* is a new command, never an old one with changed arguments.
|
|
52
|
+
*/
|
|
53
|
+
function dispatchWindow(dueAt, now, ttlMs) {
|
|
54
|
+
const round = Math.max(1, Math.floor((now - dueAt) / ttlMs) + 1);
|
|
55
|
+
return { round, expiresAt: dueAt + round * ttlMs };
|
|
56
|
+
}
|
|
57
|
+
/** The later of a row's due time and an arrival's time; an unreadable time leaves it as it was. */
|
|
58
|
+
function latestArrival(dueAt, at) {
|
|
59
|
+
const t = typeof at === 'string' ? Date.parse(at) : NaN;
|
|
60
|
+
if (!Number.isFinite(t))
|
|
61
|
+
return dueAt;
|
|
62
|
+
return dueAt === undefined ? t : Math.max(dueAt, t);
|
|
63
|
+
}
|
|
42
64
|
function dispatchAction(row, machineId, dispatchTtlMs) {
|
|
65
|
+
const now = Date.now();
|
|
66
|
+
row.createdAt ??= now;
|
|
67
|
+
const { round, expiresAt } = dispatchWindow(row.dueAt ?? row.createdAt, now, dispatchTtlMs);
|
|
43
68
|
return {
|
|
44
|
-
kind: 'dispatch', rowId: row.id, machineId, cmdId: (0, contracts_1.dispatchCommandId)(row.id), args: dispatchArgs(row,
|
|
69
|
+
kind: 'dispatch', rowId: row.id, machineId, cmdId: (0, contracts_1.dispatchCommandId)(row.id, round), args: dispatchArgs(row, expiresAt),
|
|
45
70
|
...(row.dispatch === state_1.DISPATCH_STATE.ARRIVING ? { receivedOnAccept: true } : {}),
|
|
46
71
|
};
|
|
47
72
|
}
|
|
@@ -57,7 +82,7 @@ function softwareRefusal(state, line, machineId) {
|
|
|
57
82
|
function artifactRefusal(line, row) {
|
|
58
83
|
if (!(0, line_1.machineById)(line, row.toMachine).requireArtifact || (row.artifactUrl && row.artifactSha256))
|
|
59
84
|
return null;
|
|
60
|
-
if (row.units.every((u) => u.artifact))
|
|
85
|
+
if (row.units.every((u) => u.artifact || u.artifacts?.length))
|
|
61
86
|
return null;
|
|
62
87
|
return `${row.toMachine} requires an artifact (url and sha256), for the job or for every unit; the row has none`;
|
|
63
88
|
}
|
|
@@ -29,9 +29,17 @@ const VERB = { CREATED: 'created', CLAIMED: 'claimed', RESOLVED: 'resolved', CAN
|
|
|
29
29
|
const STATUS_FOR_VERB = {
|
|
30
30
|
[VERB.CREATED]: 'pending', [VERB.CLAIMED]: 'pending', [VERB.RESOLVED]: 'resolved', [VERB.CANCELLED]: 'cancelled', [VERB.EXPIRED]: 'expired',
|
|
31
31
|
};
|
|
32
|
+
/** The metadata key an accumulator row parked with an item limit carries. */
|
|
33
|
+
const ACCUMULATE_MAX = 'accumulate_max';
|
|
32
34
|
const LINE_ROW_TYPES = [contracts_1.ROW_TYPE.ALARM, contracts_1.ROW_TYPE.MACHINE_OFFLINE, contracts_1.ROW_TYPE.MACHINE_QUIET, contracts_1.ROW_TYPE.MACHINE_COMMAND, contracts_1.ROW_TYPE.MACHINE_REGISTRATION];
|
|
33
|
-
function handoffRow(id, role, facets,
|
|
34
|
-
|
|
35
|
+
function handoffRow(id, role, facets, data) {
|
|
36
|
+
const metadata = data?.metadata;
|
|
37
|
+
const capped = metadata?.[ACCUMULATE_MAX] != null;
|
|
38
|
+
const createdAt = data?.created_at ? new Date(data.created_at).getTime() : NaN;
|
|
39
|
+
return {
|
|
40
|
+
...facets, id, role, dispatch: state_1.DISPATCH_STATE.NONE, trace: (0, trace_1.readTrace)(metadata),
|
|
41
|
+
...(capped ? { capped } : {}), ...(Number.isFinite(createdAt) ? { createdAt } : {}),
|
|
42
|
+
};
|
|
35
43
|
}
|
|
36
44
|
/** Rows for another line belong to that line's gateway. */
|
|
37
45
|
function onThisLine(line, at) {
|
|
@@ -85,8 +93,9 @@ function commandRefusal(state, line, c, role) {
|
|
|
85
93
|
const own = (0, line_1.machineRole)((0, line_1.machineById)(line, c.machineId));
|
|
86
94
|
if (role !== own)
|
|
87
95
|
return `commands for ${c.machineId} are parked on ${own}, not ${role}`;
|
|
88
|
-
|
|
89
|
-
|
|
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(', ')}`;
|
|
90
99
|
if (c.op === protocol_1.OP.CANCEL && typeof c.args.jobId !== 'string')
|
|
91
100
|
return `${protocol_1.OP.CANCEL} needs args.jobId, the job to withdraw or stop`;
|
|
92
101
|
if (!(0, registration_1.reachable)(state, line, c.machineId))
|
|
@@ -102,13 +111,18 @@ function planCommandRow(state, line, event) {
|
|
|
102
111
|
if (event.verb !== VERB.CREATED && event.verb !== VERB.CLAIMED)
|
|
103
112
|
return [];
|
|
104
113
|
const c = (0, commands_1.readCommandFacets)(event.data?.metadata);
|
|
105
|
-
if (!c || !state.trackCommand(id))
|
|
114
|
+
if (!c || !state.trackCommand(id, c.machineId))
|
|
106
115
|
return [];
|
|
107
116
|
const refusal = commandRefusal(state, line, c, event.role);
|
|
108
117
|
if (refusal) {
|
|
109
118
|
return [{ kind: 'resolve', as: actions_1.CONTROLLER, rowId: id, payload: { accepted: false, machineId: c.machineId, op: c.op, status: contracts_1.COMMAND_STATUS.UNSUPPORTED, reason: refusal } }];
|
|
110
119
|
}
|
|
111
|
-
|
|
120
|
+
const createdAt = event.data?.created_at ? new Date(event.data.created_at).getTime() : NaN;
|
|
121
|
+
return [{ kind: 'control', rowId: id, machineId: c.machineId, op: c.op, args: c.args, ...(Number.isFinite(createdAt) ? { createdAt } : {}) }];
|
|
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];
|
|
112
126
|
}
|
|
113
127
|
function onLine(line, machineId) {
|
|
114
128
|
return !!machineId && line.machines.some((m) => m.machineId === machineId);
|
|
@@ -122,7 +136,7 @@ function planHandoff(state, line, event, facets, dispatchTtlMs) {
|
|
|
122
136
|
if (event.verb === VERB.CREATED || event.verb === VERB.CLAIMED) {
|
|
123
137
|
if (state.isClosed(id) || !facets)
|
|
124
138
|
return [];
|
|
125
|
-
state.index(handoffRow(id, event.role, facets, event.data
|
|
139
|
+
state.index(handoffRow(id, event.role, facets, event.data));
|
|
126
140
|
const row = state.get(id);
|
|
127
141
|
// The units now wait on the sender as this row's sender job, when the sender holds them under it.
|
|
128
142
|
if (row.fromMachine)
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
* Machine messages to gateway actions: the escalation verbs a person would
|
|
3
3
|
* perform, performed for the machine. Each unit's arrival and the sender's
|
|
4
4
|
* finished record accumulate on the handoff row, and the last expected item
|
|
5
|
-
* resolves it. A failure on either side resolves it with an error.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* resolves it. A failure on either side resolves it with an error. A job's
|
|
6
|
+
* start, its progress steps, and the alarms that pause it are noted on the row
|
|
7
|
+
* that holds it (lifecycle.ts). Alarms that stop work and machines that go
|
|
8
|
+
* dark or quiet become rows for people. A restarted machine gets back the
|
|
9
|
+
* dispatches it lost. Everything else stays in the stream.
|
|
9
10
|
*
|
|
10
11
|
* A message whose row does not exist yet is nak'd and arrives again; one whose
|
|
11
12
|
* row already closed is acked, so a replay never resolves anything twice.
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
* Machine messages to gateway actions: the escalation verbs a person would
|
|
4
4
|
* perform, performed for the machine. Each unit's arrival and the sender's
|
|
5
5
|
* finished record accumulate on the handoff row, and the last expected item
|
|
6
|
-
* resolves it. A failure on either side resolves it with an error.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* resolves it. A failure on either side resolves it with an error. A job's
|
|
7
|
+
* start, its progress steps, and the alarms that pause it are noted on the row
|
|
8
|
+
* that holds it (lifecycle.ts). Alarms that stop work and machines that go
|
|
9
|
+
* dark or quiet become rows for people. A restarted machine gets back the
|
|
10
|
+
* dispatches it lost. Everything else stays in the stream.
|
|
10
11
|
*
|
|
11
12
|
* A message whose row does not exist yet is nak'd and arrives again; one whose
|
|
12
13
|
* row already closed is acked, so a replay never resolves anything twice.
|
|
@@ -21,6 +22,7 @@ const actions_1 = require("./actions");
|
|
|
21
22
|
const pacing_1 = require("./pacing");
|
|
22
23
|
const plan_shared_1 = require("./plan-shared");
|
|
23
24
|
const jobs_1 = require("./jobs");
|
|
25
|
+
const lifecycle_1 = require("./lifecycle");
|
|
24
26
|
const trace_1 = require("./trace");
|
|
25
27
|
const state_1 = require("./state");
|
|
26
28
|
const ack = (actions = []) => ({ actions, disposition: transport_1.DISPOSITION.ACK });
|
|
@@ -34,7 +36,7 @@ function planMachineMessage(state, parsed, env, dispatchTtlMs) {
|
|
|
34
36
|
function planByKind(state, m, parsed, env, b, ttl) {
|
|
35
37
|
switch (parsed.kind) {
|
|
36
38
|
case protocol_1.MESSAGE_KIND.REPLY:
|
|
37
|
-
return ack([{ kind: 'settleReply', cmdId: b.cmdId, status: b.status, reason: b.reason }]);
|
|
39
|
+
return ack([{ kind: 'settleReply', cmdId: b.cmdId, status: b.status, reason: b.reason, ...(typeof b.code === 'string' ? { code: b.code } : {}) }]);
|
|
38
40
|
case protocol_1.MESSAGE_KIND.JOB:
|
|
39
41
|
return planJob(state, m, b, env?.at, ttl);
|
|
40
42
|
case protocol_1.MESSAGE_KIND.ALARM:
|
|
@@ -68,12 +70,29 @@ function ownsJob(jobId, reported) {
|
|
|
68
70
|
return (0, jobs_1.jobOwns)(jobId, reported);
|
|
69
71
|
}
|
|
70
72
|
/** Keep the receiver's arrival event for the unit, to go out with its dispatch. */
|
|
71
|
-
function withArrival(row, unitId, b) {
|
|
73
|
+
function withArrival(row, unitId, b, at) {
|
|
72
74
|
row.arrivals = { ...row.arrivals, [unitId]: b };
|
|
75
|
+
row.dueAt = (0, pacing_1.latestArrival)(row.dueAt, at);
|
|
73
76
|
return row;
|
|
74
77
|
}
|
|
78
|
+
/** The unit an open handoff into `m` carries on `carrierId`, for a scan that read only the carrier. */
|
|
79
|
+
function unitOnCarrier(state, m, carrierId) {
|
|
80
|
+
if (typeof carrierId !== 'string')
|
|
81
|
+
return undefined;
|
|
82
|
+
for (const r of state.open()) {
|
|
83
|
+
if (r.toMachine !== m)
|
|
84
|
+
continue;
|
|
85
|
+
const unit = r.units.find((u) => u.carrierId === carrierId);
|
|
86
|
+
if (unit)
|
|
87
|
+
return unit.unitId;
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
75
91
|
function planJob(state, m, b, at, ttl) {
|
|
76
|
-
const unitId = b.unitId;
|
|
92
|
+
const unitId = typeof b.unitId === 'string' ? b.unitId : unitOnCarrier(state, m, b.carrierId);
|
|
93
|
+
// A carrier no open handoff here carries yet: its row may still be on the way.
|
|
94
|
+
if (unitId === undefined)
|
|
95
|
+
return nak;
|
|
77
96
|
// An event from an earlier attempt's job never touches a later attempt's row.
|
|
78
97
|
const toHere = (r) => r.toMachine === m && ownsJob(r.jobId, b.jobId);
|
|
79
98
|
const fromHere = (r) => r.fromMachine === m && ownsJob(r.senderJobId, b.jobId);
|
|
@@ -95,13 +114,14 @@ function planJob(state, m, b, at, ttl) {
|
|
|
95
114
|
if (row.fromMachine)
|
|
96
115
|
state.letGo(row.fromMachine, unitId);
|
|
97
116
|
const units = row.units.map((u) => u.unitId);
|
|
117
|
+
const arrivedAt = at ?? new Date().toISOString();
|
|
98
118
|
const complete = row.dispatch === state_1.DISPATCH_STATE.ARRIVING
|
|
99
|
-
? { keys: units.map(contracts_1.itemKeys.arrived), then: [(0, pacing_1.dispatchAction)(withArrival(row, unitId, b), m, ttl)] }
|
|
119
|
+
? { keys: units.map(contracts_1.itemKeys.arrived), then: [(0, pacing_1.dispatchAction)(withArrival(row, unitId, b, arrivedAt), m, ttl)] }
|
|
100
120
|
: { keys: units.map(contracts_1.itemKeys.arrived), payload: { received: true, receiver: m, units } };
|
|
101
121
|
return ack([...early, {
|
|
102
122
|
kind: 'accumulate', as: m, rowId: row.id, itemKey: contracts_1.itemKeys.arrived(unitId),
|
|
103
123
|
payload: {
|
|
104
|
-
unitId, carrierId: b.carrierId ?? null, from: b.peer ?? null, at:
|
|
124
|
+
unitId, carrierId: b.carrierId ?? null, from: b.peer ?? null, at: arrivedAt,
|
|
105
125
|
...(row.dispatch === state_1.DISPATCH_STATE.ARRIVING ? { arrival: b } : {}),
|
|
106
126
|
},
|
|
107
127
|
complete,
|
|
@@ -119,7 +139,8 @@ function planJob(state, m, b, at, ttl) {
|
|
|
119
139
|
if (b.result === protocol_1.JOB_RESULT.OK)
|
|
120
140
|
return ack([released]);
|
|
121
141
|
return ack([released, ...(0, plan_shared_1.failHandoff)(state, row, m, {
|
|
122
|
-
received: false, unitId, errorCode: contracts_1.HANDOFF_ERROR.SENDER_REJECTED,
|
|
142
|
+
received: false, unitId, errorCode: contracts_1.HANDOFF_ERROR.SENDER_REJECTED, result: b.result, reason: b.reason ?? null,
|
|
143
|
+
detail: `${m} finished ${unitId}: ${b.result}${b.reason ? ` (${b.reason})` : ''}`,
|
|
123
144
|
})]);
|
|
124
145
|
}
|
|
125
146
|
if (b.event === protocol_1.JOB_EVENT.TRANSFER_FAILED) {
|
|
@@ -140,6 +161,8 @@ function planJob(state, m, b, at, ttl) {
|
|
|
140
161
|
return ack();
|
|
141
162
|
return ack((0, plan_shared_1.failHandoff)(state, row, m, { received: false, unitId, errorCode: contracts_1.HANDOFF_ERROR.WITHDRAWN, detail: `${m} gave up ${b.jobId}` }));
|
|
142
163
|
}
|
|
164
|
+
if (b.event === protocol_1.JOB_EVENT.STARTED || b.event === protocol_1.JOB_EVENT.PROGRESS)
|
|
165
|
+
return ack((0, lifecycle_1.noteJobEvent)(state, m, b, at));
|
|
143
166
|
return ack();
|
|
144
167
|
}
|
|
145
168
|
function releasedAction(row, m, b) {
|
|
@@ -160,9 +183,10 @@ function planAlarm(state, parsed, alarmId, env) {
|
|
|
160
183
|
if (!env || b.active === false) {
|
|
161
184
|
const track = state.alarms.get(key);
|
|
162
185
|
state.alarms.delete(key);
|
|
186
|
+
const resumed = track ? (0, lifecycle_1.noteResume)(state, track, b) : [];
|
|
163
187
|
if (!track?.rowId || !track.open)
|
|
164
|
-
return ack();
|
|
165
|
-
return ack([{
|
|
188
|
+
return ack(resumed);
|
|
189
|
+
return ack([...resumed, {
|
|
166
190
|
kind: 'resolve', as: actions_1.CONTROLLER, rowId: track.rowId,
|
|
167
191
|
payload: { decision: contracts_1.DECISION.CLEARED, clearedBy: b.clearedBy ?? null, note: `cleared at ${m}${b.clearedBy ? ` by ${b.clearedBy}` : ''}` },
|
|
168
192
|
}]);
|
|
@@ -175,8 +199,9 @@ function planAlarm(state, parsed, alarmId, env) {
|
|
|
175
199
|
const superseded = known?.rowId && known.open
|
|
176
200
|
? [{ kind: 'resolve', as: actions_1.CONTROLLER, rowId: known.rowId, payload: { decision: contracts_1.DECISION.CLEARED, note: `${m} raised ${alarmId} again; this one ended` } }]
|
|
177
201
|
: [];
|
|
178
|
-
|
|
179
|
-
|
|
202
|
+
const track = { machineId: m, alarmId, raisedAt: b.raisedAt, level: b.level, open: true };
|
|
203
|
+
state.alarms.set(key, track);
|
|
204
|
+
return ack([...superseded, ...(0, lifecycle_1.notePause)(state, track, b), {
|
|
180
205
|
kind: 'createAlarmRow', machineId: m, alarmId,
|
|
181
206
|
row: {
|
|
182
207
|
type: contracts_1.ROW_TYPE.ALARM, subtype: b.level, role: contracts_1.LINE_ROLE.OPERATOR, priority: b.level === protocol_1.LEVEL.EMERGENCY ? 1 : 2,
|
|
@@ -198,10 +223,12 @@ function catalogEnvelope(catalog) {
|
|
|
198
223
|
}
|
|
199
224
|
function planPresence(state, m, b) {
|
|
200
225
|
const link = state.link(m);
|
|
226
|
+
const session = typeof b.sessionId === 'string' ? b.sessionId : undefined;
|
|
201
227
|
if (b.online !== true) {
|
|
202
228
|
if (link.online)
|
|
203
229
|
link.since = Date.now();
|
|
204
230
|
link.online = false;
|
|
231
|
+
link.reason = typeof b.reason === 'string' ? b.reason : undefined;
|
|
205
232
|
if (link.rowId || link.watching)
|
|
206
233
|
return ack();
|
|
207
234
|
link.watching = true;
|
|
@@ -210,12 +237,17 @@ function planPresence(state, m, b) {
|
|
|
210
237
|
if (b.software)
|
|
211
238
|
link.software = b.software;
|
|
212
239
|
const wasOffline = !link.online;
|
|
240
|
+
// A new session while online: the machine reconnected before its offline presence was heard.
|
|
241
|
+
const reconnected = !!session && !!link.sessionId && session !== link.sessionId;
|
|
213
242
|
link.online = true;
|
|
214
243
|
link.watching = false;
|
|
244
|
+
link.reason = undefined;
|
|
245
|
+
if (session)
|
|
246
|
+
link.sessionId = session;
|
|
215
247
|
const actions = [];
|
|
216
248
|
// Back from a drop: ask for the full state rather than wait for the next heartbeat.
|
|
217
|
-
if (wasOffline)
|
|
218
|
-
actions.push({ kind: 'command', machineId: m, op: protocol_1.OP.SNAPSHOT, cmdId: `${m}:resync:${link.since}`, args: {} });
|
|
249
|
+
if (wasOffline || reconnected)
|
|
250
|
+
actions.push({ kind: 'command', machineId: m, op: protocol_1.OP.SNAPSHOT, cmdId: `${m}:resync:${session ?? link.since}`, args: {} });
|
|
219
251
|
if (link.rowId) {
|
|
220
252
|
actions.push({ kind: 'resolve', as: actions_1.CONTROLLER, rowId: link.rowId, payload: { decision: contracts_1.DECISION.RESTORED, note: `${m} back online` } });
|
|
221
253
|
link.rowId = undefined;
|
|
@@ -228,15 +260,34 @@ function planSnapshot(state, m, b, ttl) {
|
|
|
228
260
|
if (b.software)
|
|
229
261
|
link.software = b.software;
|
|
230
262
|
const jobIds = Array.isArray(b.jobs) ? b.jobs.map((j) => j?.jobId).filter((id) => typeof id === 'string') : [];
|
|
231
|
-
if (Array.isArray(b.jobs))
|
|
263
|
+
if (Array.isArray(b.jobs)) {
|
|
232
264
|
state.keepHeld(m, new Set(jobIds));
|
|
265
|
+
link.jobs = b.jobs;
|
|
266
|
+
}
|
|
267
|
+
const fresh = !state.retainedAlarms && !state.readingRetained && Array.isArray(b.alarms);
|
|
268
|
+
const cleared = fresh ? alarmsNoLongerListed(state, m, b.alarms) : [];
|
|
233
269
|
const answer = { kind: 'settleSnapshot', machineId: m, jobIds };
|
|
234
270
|
const previous = link.bootId;
|
|
235
271
|
link.bootId = b.bootId;
|
|
236
272
|
if (!previous || previous === b.bootId)
|
|
237
|
-
return ack([answer]);
|
|
273
|
+
return ack([...cleared, answer]);
|
|
238
274
|
const held = new Set(jobIds);
|
|
239
275
|
const missing = (r) => (0, jobs_1.dispatchJobs)(r.jobId, r.units, state.unitsPerDispatch).some((j) => !held.has(j.jobId));
|
|
240
276
|
const lost = state.open().filter((r) => r.toMachine === m && r.dispatch === state_1.DISPATCH_STATE.ACCEPTED && missing(r));
|
|
241
|
-
return ack([answer, ...lost.map((r) => (0, pacing_1.dispatchAction)(r, m, ttl))]);
|
|
277
|
+
return ack([...cleared, answer, ...lost.map((r) => (0, pacing_1.dispatchAction)(r, m, ttl))]);
|
|
278
|
+
}
|
|
279
|
+
/** Alarm rows for `m` whose alarm its snapshot no longer lists: they cleared at the machine. */
|
|
280
|
+
function alarmsNoLongerListed(state, m, listed) {
|
|
281
|
+
const active = new Set(listed.filter((id) => typeof id === 'string'));
|
|
282
|
+
const actions = [];
|
|
283
|
+
for (const [key, track] of [...state.alarms.entries()]) {
|
|
284
|
+
if (track.machineId !== m || active.has(track.alarmId))
|
|
285
|
+
continue;
|
|
286
|
+
state.alarms.delete(key);
|
|
287
|
+
actions.push(...(0, lifecycle_1.noteResume)(state, track, {}));
|
|
288
|
+
if (track.open && track.rowId) {
|
|
289
|
+
actions.push({ kind: 'resolve', as: actions_1.CONTROLLER, rowId: track.rowId, payload: { decision: contracts_1.DECISION.CLEARED, note: `cleared at ${m}; its snapshot no longer lists it` } });
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return actions;
|
|
242
293
|
}
|
|
@@ -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;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The line as its leader sees it, for the dashboard: each machine's link,
|
|
4
|
+
* held units, open rows and alarms from the gateway state, and the claims
|
|
5
|
+
* waiting for a person. Pure: reads the state and the line, changes nothing.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.projectLine = projectLine;
|
|
9
|
+
const line_1 = require("../../../lib/machines/line");
|
|
10
|
+
const protocol_1 = require("../../../lib/machines/protocol");
|
|
11
|
+
const at = (ms) => (ms ? (0, protocol_1.isoTs)(ms) : null);
|
|
12
|
+
function addressOf(state, line, def) {
|
|
13
|
+
if ((0, line_1.learnsAddress)(line, def.machineId))
|
|
14
|
+
return state.learnedAddress(def.machineId) ?? null;
|
|
15
|
+
return def.address ?? def.machineId;
|
|
16
|
+
}
|
|
17
|
+
function alarmsOf(state, machineId) {
|
|
18
|
+
return [...state.alarms.values()]
|
|
19
|
+
.filter((track) => track.machineId === machineId)
|
|
20
|
+
.map((track) => ({ alarmId: track.alarmId, level: track.level ?? '', raisedAt: track.raisedAt ?? '', rowId: track.rowId ?? null }));
|
|
21
|
+
}
|
|
22
|
+
/** The handoff that brought a unit into a machine: open first, then the recently closed one. */
|
|
23
|
+
function rowCarrying(state, machineId, unitId) {
|
|
24
|
+
const into = (r) => r.toMachine === machineId;
|
|
25
|
+
return state.openFor(unitId, into) ?? state.closedFor(unitId, into);
|
|
26
|
+
}
|
|
27
|
+
function machineView(state, line, def) {
|
|
28
|
+
const m = def.machineId;
|
|
29
|
+
const link = state.links.get(m);
|
|
30
|
+
const open = state.open();
|
|
31
|
+
return {
|
|
32
|
+
machineId: m, process: def.process, role: (0, line_1.machineRole)(def), address: addressOf(state, line, def),
|
|
33
|
+
online: link ? link.online : null, since: at(link?.since), lastSeen: at(link?.lastSeen),
|
|
34
|
+
software: link?.software ?? null, bootId: link?.bootId ?? null, sessionId: link?.sessionId ?? null,
|
|
35
|
+
heldUnits: state.heldUnitsAt(m).map(({ unitId }) => {
|
|
36
|
+
const row = rowCarrying(state, m, unitId);
|
|
37
|
+
return { unitId, carrierId: row?.units.find((u) => u.unitId === unitId)?.carrierId ?? null, rowId: row?.id ?? '' };
|
|
38
|
+
}),
|
|
39
|
+
rows: {
|
|
40
|
+
handoff: open.filter((r) => r.toMachine === m).length,
|
|
41
|
+
command: state.openCommandsFor(m),
|
|
42
|
+
alarm: [...state.alarms.values()].filter((t) => t.machineId === m && t.open && !!t.rowId).length,
|
|
43
|
+
offlineRowId: link?.rowId ?? null, quietRowId: link?.quietRowId ?? null,
|
|
44
|
+
},
|
|
45
|
+
alarms: alarmsOf(state, m),
|
|
46
|
+
jobs: link?.jobs ?? [],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function projectLine(state, line) {
|
|
50
|
+
return {
|
|
51
|
+
siteId: line.siteId, lineId: line.lineId, leading: true, takenAt: at(state.takenAt),
|
|
52
|
+
machines: line.machines.map((def) => machineView(state, line, def)),
|
|
53
|
+
contested: state.contested(),
|
|
54
|
+
};
|
|
55
|
+
}
|