@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
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
* an unknown or incomplete selection throws; nothing falls back silently.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.ESCALATION_FEED = exports.MACHINE_TRANSPORT = void 0;
|
|
7
|
+
exports.DEFAULT_TOPIC_ROOT = exports.ESCALATION_FEED = exports.MACHINE_TRANSPORT = void 0;
|
|
8
8
|
exports.loadMachineLineConfig = loadMachineLineConfig;
|
|
9
9
|
const protocol_1 = require("../../lib/machines/protocol");
|
|
10
10
|
exports.MACHINE_TRANSPORT = { MEMORY: 'memory', NATS: 'nats', MQTT: 'mqtt' };
|
|
11
11
|
exports.ESCALATION_FEED = { MEMORY: 'memory', CORE: 'core', IN_PROCESS: 'in-process' };
|
|
12
|
+
/** The generic line protocol's topic root when MACHINE_TOPIC_ROOT is unset. */
|
|
13
|
+
exports.DEFAULT_TOPIC_ROOT = 'line/v1';
|
|
14
|
+
const SWITCH = { ON: 'on', OFF: 'off' };
|
|
12
15
|
function oneOf(name, value, allowed) {
|
|
13
16
|
if (!allowed.includes(value)) {
|
|
14
17
|
throw new Error(`${name}="${value}" is not one of ${allowed.join(', ')}`);
|
|
@@ -24,6 +27,12 @@ function int(env, name, fallback) {
|
|
|
24
27
|
throw new Error(`${name}="${raw}" must be a non-negative integer`);
|
|
25
28
|
return n;
|
|
26
29
|
}
|
|
30
|
+
function percentStep(env, name, fallback) {
|
|
31
|
+
const n = int(env, name, fallback);
|
|
32
|
+
if (n > 100)
|
|
33
|
+
throw new Error(`${name}="${n}" must be at most 100`);
|
|
34
|
+
return n;
|
|
35
|
+
}
|
|
27
36
|
function required(env, name, mode) {
|
|
28
37
|
const value = env[name];
|
|
29
38
|
if (!value)
|
|
@@ -55,19 +64,22 @@ function loadMachineLineConfig(env = process.env) {
|
|
|
55
64
|
const config = {
|
|
56
65
|
transport,
|
|
57
66
|
feed,
|
|
58
|
-
topicRoot: env.MACHINE_TOPIC_ROOT ??
|
|
67
|
+
topicRoot: env.MACHINE_TOPIC_ROOT ?? exports.DEFAULT_TOPIC_ROOT,
|
|
59
68
|
lineConfigPath: env.MACHINE_LINE_CONFIG || undefined,
|
|
60
69
|
replyTimeoutMs: int(env, 'MACHINE_REPLY_TIMEOUT_MS', protocol_1.REPLY_DEADLINE_MS),
|
|
61
70
|
dispatchAttempts: Math.max(1, int(env, 'MACHINE_DISPATCH_ATTEMPTS', 3)),
|
|
62
|
-
handoffTimeout: env.MACHINE_HANDOFF_TIMEOUT ?? '10m',
|
|
63
71
|
offlineDebounceMs: int(env, 'MACHINE_OFFLINE_DEBOUNCE_MS', 15_000),
|
|
64
72
|
quietMs: int(env, 'MACHINE_QUIET_MS', 90_000),
|
|
65
73
|
dispatchTtlMs: int(env, 'MACHINE_DISPATCH_TTL_MS', 600_000),
|
|
66
74
|
receiptDelayMs: int(env, 'MACHINE_RECEIPT_DELAY_MS', 250),
|
|
75
|
+
lifecycle: oneOf('MACHINE_LIFECYCLE', env.MACHINE_LIFECYCLE || SWITCH.OFF, Object.values(SWITCH)) === SWITCH.ON,
|
|
76
|
+
progressStep: percentStep(env, 'MACHINE_PROGRESS_STEP', 25),
|
|
77
|
+
wireTelemetry: oneOf('MACHINE_WIRE_TELEMETRY', env.MACHINE_WIRE_TELEMETRY || SWITCH.OFF, Object.values(SWITCH)) === SWITCH.ON,
|
|
67
78
|
ltBaseUrl: env.LT_BASE_URL ?? 'http://localhost:3000',
|
|
68
79
|
};
|
|
69
80
|
if (transport === exports.MACHINE_TRANSPORT.NATS) {
|
|
70
|
-
|
|
81
|
+
// A site NATS of its own; without one, the streams are Long Tail's messaging.
|
|
82
|
+
config.siteNatsUrl = env.MACHINE_SITE_NATS_URL || undefined;
|
|
71
83
|
config.siteNatsUser = env.MACHINE_SITE_NATS_USER;
|
|
72
84
|
config.siteNatsPassword = env.MACHINE_SITE_NATS_PASSWORD;
|
|
73
85
|
config.mqtt = mqttEndpoint(env, transport, 5);
|
|
@@ -75,10 +87,8 @@ function loadMachineLineConfig(env = process.env) {
|
|
|
75
87
|
if (transport === exports.MACHINE_TRANSPORT.MQTT)
|
|
76
88
|
config.mqtt = mqttEndpoint(env, transport, 5);
|
|
77
89
|
if (feed === exports.ESCALATION_FEED.CORE) {
|
|
78
|
-
config.ltNatsUrl = env.NATS_URL;
|
|
90
|
+
config.ltNatsUrl = env.NATS_URL || undefined;
|
|
79
91
|
config.ltNatsToken = env.NATS_TOKEN;
|
|
80
|
-
if (!config.ltNatsUrl)
|
|
81
|
-
throw new Error('MACHINE_ESCALATION_FEED=core needs NATS_URL (Long Tail NATS)');
|
|
82
92
|
}
|
|
83
93
|
return config;
|
|
84
94
|
}
|
|
@@ -29,14 +29,22 @@ export declare const LINE_ROLE: {
|
|
|
29
29
|
export interface ArtifactRef {
|
|
30
30
|
url: string;
|
|
31
31
|
sha256: string;
|
|
32
|
+
/** The host's id for the file. */
|
|
33
|
+
id?: string;
|
|
34
|
+
contentType?: string;
|
|
35
|
+
sizeBytes?: number;
|
|
32
36
|
}
|
|
33
37
|
export interface HandoffUnit {
|
|
34
38
|
unitId: string;
|
|
35
39
|
carrierId: string | null;
|
|
36
40
|
/** This unit's own file, when each unit has one (a per-unit model or toolpath). */
|
|
37
41
|
artifact?: ArtifactRef;
|
|
42
|
+
/** This unit's files, when it has several. */
|
|
43
|
+
artifacts?: ArtifactRef[];
|
|
38
44
|
/** Parameters for this unit alone, sent to the machine as given. */
|
|
39
45
|
parameters?: Record<string, unknown>;
|
|
46
|
+
/** The host's references for this unit, by name; sent to the machine as given and searchable on the row. */
|
|
47
|
+
refs?: Record<string, string>;
|
|
40
48
|
}
|
|
41
49
|
/** Metadata on a handoff row. Everything a dispatch needs rides here. */
|
|
42
50
|
export interface HandoffFacets {
|
|
@@ -60,6 +68,8 @@ export interface HandoffFacets {
|
|
|
60
68
|
attempt: number;
|
|
61
69
|
/** Parameters for the job, sent to the machine as given; what they mean is between the host and its codec. */
|
|
62
70
|
parameters?: Record<string, unknown>;
|
|
71
|
+
/** The host's references for the job, by name (an order, a batch, a ticket); sent to the machine as given and searchable on the row. */
|
|
72
|
+
refs?: Record<string, string>;
|
|
63
73
|
}
|
|
64
74
|
/**
|
|
65
75
|
* Items a handoff row accumulates, one per unit: the sender's finished-job
|
|
@@ -69,6 +79,11 @@ export interface HandoffFacets {
|
|
|
69
79
|
export declare const itemKeys: {
|
|
70
80
|
released: (unitId: string) => string;
|
|
71
81
|
arrived: (unitId: string) => string;
|
|
82
|
+
started: (unitId: string) => string;
|
|
83
|
+
progress: (unitId: string, step: number) => string;
|
|
84
|
+
stage: (unitId: string, stage: string) => string;
|
|
85
|
+
paused: (alarmId: string, raisedAt: string) => string;
|
|
86
|
+
resumed: (alarmId: string, raisedAt: string) => string;
|
|
72
87
|
};
|
|
73
88
|
/** The unit an arrival item names; null for any other item. */
|
|
74
89
|
export declare function arrivedUnit(itemKey: string): string | null;
|
|
@@ -125,6 +140,10 @@ export declare const TRACE_FACET: {
|
|
|
125
140
|
readonly TRACE: "trace";
|
|
126
141
|
readonly LOTS: "lots";
|
|
127
142
|
};
|
|
143
|
+
/** The facet a row holding a job carries while it runs: its latest noted progress. */
|
|
144
|
+
export declare const LIFECYCLE_FACET: {
|
|
145
|
+
readonly PROGRESS: "progress";
|
|
146
|
+
};
|
|
128
147
|
/** What resolves a handoff row, from a machine or from a person's form. */
|
|
129
148
|
export interface HandoffResolution {
|
|
130
149
|
received: boolean;
|
|
@@ -136,8 +155,12 @@ export interface HandoffResolution {
|
|
|
136
155
|
/** The machine that reported the error, when it is not the one resolving. */
|
|
137
156
|
reportedBy?: string;
|
|
138
157
|
errorCode?: HandoffErrorCode;
|
|
158
|
+
/** On `sender-rejected`, how the sender finished the unit: reject, hold, scrap or rework. */
|
|
159
|
+
result?: string;
|
|
139
160
|
reason?: string | null;
|
|
140
161
|
detail?: string;
|
|
162
|
+
/** The machine's structured code for a refusal or failure, when its reply carried one. */
|
|
163
|
+
code?: string;
|
|
141
164
|
}
|
|
142
165
|
/** Decisions on line-operator rows: failed handoffs, alarms, dark machines, contested registrations. */
|
|
143
166
|
export declare const DECISION: {
|
|
@@ -187,7 +210,11 @@ export interface CommandResolution {
|
|
|
187
210
|
op: string;
|
|
188
211
|
status: CommandStatus;
|
|
189
212
|
reason?: string;
|
|
213
|
+
/** The machine's structured code for the outcome, when its reply carried one. */
|
|
214
|
+
code?: string;
|
|
190
215
|
}
|
|
191
|
-
|
|
192
|
-
export declare const
|
|
216
|
+
/** A row's dispatch command in its validity round; a later round is a new command (gateway/pacing.ts dispatchWindow). */
|
|
217
|
+
export declare const dispatchCommandId: (escalationId: string, round?: number) => string;
|
|
218
|
+
/** A command row's command in its validity round; a later round is a new command (gateway/pacing.ts dispatchWindow). */
|
|
219
|
+
export declare const controlCommandId: (escalationId: string, round?: number) => string;
|
|
193
220
|
export declare const cancelCommandId: (escalationId: string) => string;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* protocol that resolves it differs.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.cancelCommandId = exports.controlCommandId = exports.dispatchCommandId = exports.COMMAND_STATUS = exports.signalKeys = exports.DECISION = exports.TRACE_FACET = exports.HANDOFF_ERROR = exports.itemKeys = exports.LINE_ROLE = exports.ROW_TYPE = void 0;
|
|
9
|
+
exports.cancelCommandId = exports.controlCommandId = exports.dispatchCommandId = exports.COMMAND_STATUS = exports.signalKeys = exports.DECISION = exports.LIFECYCLE_FACET = exports.TRACE_FACET = exports.HANDOFF_ERROR = exports.itemKeys = exports.LINE_ROLE = exports.ROW_TYPE = void 0;
|
|
10
10
|
exports.arrivedUnit = arrivedUnit;
|
|
11
11
|
exports.handoffProgress = handoffProgress;
|
|
12
12
|
exports.handoffDecisions = handoffDecisions;
|
|
@@ -43,6 +43,11 @@ const ARRIVED_PREFIX = 'arrived:';
|
|
|
43
43
|
exports.itemKeys = {
|
|
44
44
|
released: (unitId) => `${RELEASED_PREFIX}${unitId}`,
|
|
45
45
|
arrived: (unitId) => `${ARRIVED_PREFIX}${unitId}`,
|
|
46
|
+
started: (unitId) => `started:${unitId}`,
|
|
47
|
+
progress: (unitId, step) => `progress:${unitId}:${step}`,
|
|
48
|
+
stage: (unitId, stage) => `stage:${unitId}:${stage}`,
|
|
49
|
+
paused: (alarmId, raisedAt) => `paused:${alarmId}:${raisedAt}`,
|
|
50
|
+
resumed: (alarmId, raisedAt) => `resumed:${alarmId}:${raisedAt}`,
|
|
46
51
|
};
|
|
47
52
|
/** The unit an arrival item names; null for any other item. */
|
|
48
53
|
function arrivedUnit(itemKey) {
|
|
@@ -78,6 +83,8 @@ exports.HANDOFF_ERROR = {
|
|
|
78
83
|
* containment-searchable, e.g. `{ lots: ['LOT-7'] }`.
|
|
79
84
|
*/
|
|
80
85
|
exports.TRACE_FACET = { TRACE: 'trace', LOTS: 'lots' };
|
|
86
|
+
/** The facet a row holding a job carries while it runs: its latest noted progress. */
|
|
87
|
+
exports.LIFECYCLE_FACET = { PROGRESS: 'progress' };
|
|
81
88
|
/** Decisions on line-operator rows: failed handoffs, alarms, dark machines, contested registrations. */
|
|
82
89
|
exports.DECISION = {
|
|
83
90
|
RETRY: 'retry',
|
|
@@ -107,9 +114,11 @@ exports.signalKeys = {
|
|
|
107
114
|
jobStop: (jobKey, step, attempt) => `job-stop-${jobKey}-s${step}-a${attempt}`,
|
|
108
115
|
};
|
|
109
116
|
exports.COMMAND_STATUS = { ...protocol_1.REPLY_STATUS, NO_REPLY: 'no-reply', UNSUPPORTED: 'unsupported' };
|
|
110
|
-
|
|
117
|
+
/** A row's dispatch command in its validity round; a later round is a new command (gateway/pacing.ts dispatchWindow). */
|
|
118
|
+
const dispatchCommandId = (escalationId, round = 1) => (round > 1 ? `${escalationId}:dispatch:r${round}` : `${escalationId}:dispatch`);
|
|
111
119
|
exports.dispatchCommandId = dispatchCommandId;
|
|
112
|
-
|
|
120
|
+
/** A command row's command in its validity round; a later round is a new command (gateway/pacing.ts dispatchWindow). */
|
|
121
|
+
const controlCommandId = (escalationId, round = 1) => (round > 1 ? `${escalationId}:command:r${round}` : `${escalationId}:command`);
|
|
113
122
|
exports.controlCommandId = controlCommandId;
|
|
114
123
|
const cancelCommandId = (escalationId) => `${escalationId}:cancel`;
|
|
115
124
|
exports.cancelCommandId = cancelCommandId;
|
|
@@ -39,8 +39,8 @@ export type Action =
|
|
|
39
39
|
rowId: string;
|
|
40
40
|
machineId: string;
|
|
41
41
|
op: string;
|
|
42
|
-
cmdId: string;
|
|
43
42
|
args: Record<string, any>;
|
|
43
|
+
createdAt?: number;
|
|
44
44
|
} | {
|
|
45
45
|
kind: 'claim';
|
|
46
46
|
as: Actor;
|
|
@@ -78,6 +78,7 @@ export type Action =
|
|
|
78
78
|
cmdId: string;
|
|
79
79
|
status: string;
|
|
80
80
|
reason: string;
|
|
81
|
+
code?: string;
|
|
81
82
|
}
|
|
82
83
|
/** A machine reported the jobs it holds: answers a status query in flight. */
|
|
83
84
|
| {
|
|
@@ -7,19 +7,31 @@
|
|
|
7
7
|
import { type LineDef } from '../../../lib/machines/line';
|
|
8
8
|
import type { Inspection } from '../../../lib/machines/protocol';
|
|
9
9
|
import { type Disposition, type InboundMessage } from '../../../lib/machines/transport';
|
|
10
|
+
import type { WireAction } from '../../../types/machines-view';
|
|
10
11
|
import type { Action } from './actions';
|
|
11
12
|
import { type GatewayLog } from './log';
|
|
12
13
|
import type { GatewayState } from './state';
|
|
13
|
-
/** What handling one decoded message came to. */
|
|
14
|
+
/** What handling one decoded message came to, with what the gateway did for the wire record. */
|
|
14
15
|
export interface Applied {
|
|
15
16
|
disposition: Disposition;
|
|
16
17
|
failed: boolean;
|
|
18
|
+
actions: WireAction[];
|
|
19
|
+
/** The address the message came from, when it was not admitted as a station's. */
|
|
20
|
+
sender?: {
|
|
21
|
+
machineId: string | null;
|
|
22
|
+
address: string | null;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** A message admitted as a station's, with what admitting it did (a binding, say). */
|
|
26
|
+
export interface Admitted {
|
|
27
|
+
seen: Inspection;
|
|
28
|
+
actions: WireAction[];
|
|
17
29
|
}
|
|
18
30
|
export interface AdmissionContext {
|
|
19
31
|
state: GatewayState;
|
|
20
32
|
line: LineDef;
|
|
21
33
|
executor: {
|
|
22
|
-
apply(actions: Action[]): Promise<
|
|
34
|
+
apply(actions: Action[]): Promise<WireAction[]>;
|
|
23
35
|
};
|
|
24
36
|
log: GatewayLog;
|
|
25
37
|
/** Send waiting handoffs that may now go out. */
|
|
@@ -30,6 +42,6 @@ export interface AdmissionContext {
|
|
|
30
42
|
* bound and its waiting work goes out; a contested claim raises one row for a
|
|
31
43
|
* person; either of those, and an address no station claims, is not acted on.
|
|
32
44
|
*/
|
|
33
|
-
export declare function admitSender(ctx: AdmissionContext, topic: string, raw: Inspection): Promise<
|
|
45
|
+
export declare function admitSender(ctx: AdmissionContext, topic: string, raw: Inspection): Promise<Admitted | Applied>;
|
|
34
46
|
/** Under a strict codec a broken message is not acted on: a person sees it on a row, once. */
|
|
35
47
|
export declare function holdViolation(ctx: AdmissionContext, msg: InboundMessage, seen: Inspection): Promise<Applied>;
|
|
@@ -11,8 +11,12 @@ exports.holdViolation = holdViolation;
|
|
|
11
11
|
const contracts_1 = require("../contracts");
|
|
12
12
|
const line_1 = require("../../../lib/machines/line");
|
|
13
13
|
const transport_1 = require("../../../lib/machines/transport");
|
|
14
|
+
const dispatcher_1 = require("./dispatcher");
|
|
14
15
|
const log_1 = require("./log");
|
|
15
16
|
const registration_1 = require("./registration");
|
|
17
|
+
function from(sender) {
|
|
18
|
+
return { machineId: sender.machineId ?? null, address: sender.address };
|
|
19
|
+
}
|
|
16
20
|
/**
|
|
17
21
|
* The station a message is from (registration.ts). A newly claimed station is
|
|
18
22
|
* bound and its waiting work goes out; a contested claim raises one row for a
|
|
@@ -20,47 +24,58 @@ const registration_1 = require("./registration");
|
|
|
20
24
|
*/
|
|
21
25
|
async function admitSender(ctx, topic, raw) {
|
|
22
26
|
const sender = (0, registration_1.resolveSender)(ctx.state, ctx.line, raw);
|
|
27
|
+
const actions = [];
|
|
23
28
|
try {
|
|
24
29
|
if (sender.status === registration_1.SENDER.BOUND) {
|
|
25
|
-
await ctx.executor.apply([{ kind: 'bindAddress', machineId: sender.machineId, address: sender.address }]);
|
|
30
|
+
actions.push(...await ctx.executor.apply([{ kind: 'bindAddress', machineId: sender.machineId, address: sender.address }]));
|
|
26
31
|
await ctx.pace();
|
|
27
32
|
}
|
|
28
33
|
if (sender.seen)
|
|
29
|
-
return sender.seen;
|
|
34
|
+
return { seen: sender.seen, actions };
|
|
30
35
|
if (sender.status === registration_1.SENDER.CONTESTED)
|
|
31
36
|
ctx.state.hearClaim(sender.address, sender.machineId);
|
|
32
37
|
if (sender.status === registration_1.SENDER.CONTESTED && !ctx.state.claimRaised(sender.address, sender.machineId)) {
|
|
33
|
-
await ctx.executor.apply([{ kind: 'createRow', row: (0, registration_1.registrationRow)(ctx.state, ctx.line, sender.address, sender.machineId) }]);
|
|
34
|
-
ctx.state.raiseClaim(sender.address, sender.machineId);
|
|
38
|
+
const [made] = await ctx.executor.apply([{ kind: 'createRow', row: (0, registration_1.registrationRow)(ctx.state, ctx.line, sender.address, sender.machineId) }]);
|
|
39
|
+
ctx.state.raiseClaim(sender.address, sender.machineId, made?.rowId);
|
|
35
40
|
ctx.log.warn(log_1.GATEWAY_LOG.ADDRESS_CONTESTED, { topic, address: sender.address, machine: sender.machineId });
|
|
41
|
+
actions.push({ ...made, detail: `${sender.address} says it is ${sender.machineId}; a person decides` });
|
|
42
|
+
}
|
|
43
|
+
else if (sender.status === registration_1.SENDER.CONTESTED) {
|
|
44
|
+
actions.push({ verb: 'none', detail: `${sender.address} says it is ${sender.machineId}; waiting for a person` });
|
|
45
|
+
}
|
|
46
|
+
if (sender.status === registration_1.SENDER.UNKNOWN) {
|
|
47
|
+
if (ctx.state.firstHeardStranger(sender.address))
|
|
48
|
+
ctx.log.warn(log_1.GATEWAY_LOG.ADDRESS_UNKNOWN, { topic, address: sender.address });
|
|
49
|
+
actions.push({ verb: 'none', detail: `${sender.address} claims no station on this line` });
|
|
36
50
|
}
|
|
37
|
-
|
|
38
|
-
ctx.log.warn(log_1.GATEWAY_LOG.ADDRESS_UNKNOWN, { topic, address: sender.address });
|
|
39
|
-
return { disposition: transport_1.DISPOSITION.ACK, failed: false };
|
|
51
|
+
return { disposition: transport_1.DISPOSITION.ACK, failed: false, actions, sender: from(sender) };
|
|
40
52
|
}
|
|
41
53
|
catch (err) {
|
|
42
|
-
|
|
43
|
-
|
|
54
|
+
if (!(err instanceof dispatcher_1.GatewayStopped))
|
|
55
|
+
ctx.log.error(log_1.GATEWAY_LOG.VERB_FAILED, { topic, error: err.message });
|
|
56
|
+
return { disposition: transport_1.DISPOSITION.NAK, failed: true, actions, sender: from(sender) };
|
|
44
57
|
}
|
|
45
58
|
}
|
|
46
59
|
/** Under a strict codec a broken message is not acted on: a person sees it on a row, once. */
|
|
47
60
|
async function holdViolation(ctx, msg, seen) {
|
|
48
61
|
const { ident, kind } = seen.parsed;
|
|
49
62
|
const key = seen.receiptId ?? seen.body?.id ?? `${msg.topic}:${msg.payload}`;
|
|
63
|
+
const detail = seen.violations.join('; ');
|
|
50
64
|
if (ctx.state.violationRaised(key))
|
|
51
|
-
return { disposition: transport_1.DISPOSITION.ACK, failed: false };
|
|
65
|
+
return { disposition: transport_1.DISPOSITION.ACK, failed: false, actions: [{ verb: 'hold', detail: `${detail} (already shown to a person)` }] };
|
|
52
66
|
try {
|
|
53
|
-
await ctx.executor.apply([{ kind: 'createRow', row: {
|
|
67
|
+
const [made] = await ctx.executor.apply([{ kind: 'createRow', row: {
|
|
54
68
|
type: contracts_1.ROW_TYPE.CONTRACT_VIOLATION, role: (0, line_1.operatorRole)(ctx.line), priority: 2,
|
|
55
69
|
description: `${ident.machineId} sent a ${kind} message that breaks the contract: ${seen.violations.join('; ')}`,
|
|
56
70
|
metadata: { siteId: ident.siteId, lineId: ident.lineId, machineId: ident.machineId, kind, topic: msg.topic, messageId: seen.body?.id ?? null, violations: seen.violations },
|
|
57
71
|
escalation_payload: msg.payload,
|
|
58
72
|
} }]);
|
|
59
73
|
ctx.state.raiseViolation(key);
|
|
60
|
-
return { disposition: transport_1.DISPOSITION.ACK, failed: false };
|
|
74
|
+
return { disposition: transport_1.DISPOSITION.ACK, failed: false, actions: [{ verb: 'hold', rowId: made?.rowId, detail }] };
|
|
61
75
|
}
|
|
62
76
|
catch (err) {
|
|
63
|
-
|
|
64
|
-
|
|
77
|
+
if (!(err instanceof dispatcher_1.GatewayStopped))
|
|
78
|
+
ctx.log.error(log_1.GATEWAY_LOG.VERB_FAILED, { topic: msg.topic, error: err.message });
|
|
79
|
+
return { disposition: transport_1.DISPOSITION.NAK, failed: true, actions: [] };
|
|
65
80
|
}
|
|
66
81
|
}
|
|
@@ -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';
|
|
@@ -37,18 +40,31 @@ type CommandAction = Extract<Action, {
|
|
|
37
40
|
type ControlAction = Extract<Action, {
|
|
38
41
|
kind: 'control';
|
|
39
42
|
}>;
|
|
43
|
+
/** Ends a dispatch or command still running when the gateway stops; the next leader takes it up from the row. */
|
|
44
|
+
export declare class GatewayStopped extends Error {
|
|
45
|
+
constructor();
|
|
46
|
+
}
|
|
40
47
|
export declare class Dispatcher {
|
|
41
48
|
private readonly d;
|
|
49
|
+
private readonly sent;
|
|
50
|
+
private readonly stopping;
|
|
42
51
|
constructor(d: DispatcherDeps);
|
|
43
|
-
/**
|
|
44
|
-
|
|
52
|
+
/** Work still running sends nothing more and changes no row. */
|
|
53
|
+
stop(): void;
|
|
54
|
+
private live;
|
|
55
|
+
/** This send's attempt number, and whether the machine may have the command already. */
|
|
56
|
+
private countSend;
|
|
57
|
+
/** False when the codec has no message for the command. `since` is when the command's row was created. */
|
|
58
|
+
publish(machineId: string, op: string, cmdId: string, args: Record<string, any>, since?: number): Promise<boolean>;
|
|
45
59
|
/** Publish and wait for the reply, asking again with the same id; null when none came. */
|
|
46
|
-
ask(machineId: string, op: string, cmdId: string, args: Record<string, any
|
|
60
|
+
ask(machineId: string, op: string, cmdId: string, args: Record<string, any>, since?: number): Promise<CommandReply | null>;
|
|
47
61
|
command(a: CommandAction): Promise<void>;
|
|
48
62
|
/**
|
|
49
63
|
* A machine-command row: send it, then resolve the row with the reply, as the
|
|
50
64
|
* machine that gave it. The command expires when the asking ends, so one that
|
|
51
65
|
* reaches a machine after its row resolved no-reply is refused, never run.
|
|
66
|
+
* Rounds of the asking count from the row's creation, so the command sent
|
|
67
|
+
* again by a new gateway is the same command with the same arguments.
|
|
52
68
|
*/
|
|
53
69
|
control(a: ControlAction): Promise<void>;
|
|
54
70
|
dispatch(a: DispatchAction): Promise<void>;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* codec has no message for is unsupported: nothing is sent or awaited.
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.Dispatcher = void 0;
|
|
14
|
+
exports.Dispatcher = exports.GatewayStopped = void 0;
|
|
15
15
|
const promises_1 = require("timers/promises");
|
|
16
16
|
const contracts_1 = require("../contracts");
|
|
17
17
|
const registration_1 = require("./registration");
|
|
@@ -19,6 +19,7 @@ const protocol_1 = require("../../../lib/machines/protocol");
|
|
|
19
19
|
const actions_1 = require("./actions");
|
|
20
20
|
const escalations_1 = require("./escalations");
|
|
21
21
|
const jobs_1 = require("./jobs");
|
|
22
|
+
const pacing_1 = require("./pacing");
|
|
22
23
|
const log_1 = require("./log");
|
|
23
24
|
const state_1 = require("./state");
|
|
24
25
|
/** A reply the machine sent, as opposed to none or an unsupported command. */
|
|
@@ -29,25 +30,64 @@ function fromMachine(reply) {
|
|
|
29
30
|
function took(reply) {
|
|
30
31
|
return reply?.status === protocol_1.REPLY_STATUS.ACCEPTED || reply?.status === protocol_1.REPLY_STATUS.COMPLETED;
|
|
31
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
|
+
}
|
|
37
|
+
/** Most command ids whose sends are counted; the oldest are forgotten first. */
|
|
38
|
+
const SENT_REMEMBERED = 10_000;
|
|
39
|
+
/** Ends a dispatch or command still running when the gateway stops; the next leader takes it up from the row. */
|
|
40
|
+
class GatewayStopped extends Error {
|
|
41
|
+
constructor() {
|
|
42
|
+
super('the gateway stopped');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.GatewayStopped = GatewayStopped;
|
|
32
46
|
class Dispatcher {
|
|
33
47
|
constructor(d) {
|
|
34
48
|
this.d = d;
|
|
49
|
+
this.sent = new Map();
|
|
50
|
+
this.stopping = new AbortController();
|
|
51
|
+
}
|
|
52
|
+
/** Work still running sends nothing more and changes no row. */
|
|
53
|
+
stop() {
|
|
54
|
+
this.stopping.abort();
|
|
35
55
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
56
|
+
live() {
|
|
57
|
+
if (this.stopping.signal.aborted)
|
|
58
|
+
throw new GatewayStopped();
|
|
59
|
+
}
|
|
60
|
+
/** This send's attempt number, and whether the machine may have the command already. */
|
|
61
|
+
countSend(cmdId, since) {
|
|
62
|
+
const attempt = (this.sent.get(cmdId) ?? 0) + 1;
|
|
63
|
+
this.sent.delete(cmdId);
|
|
64
|
+
this.sent.set(cmdId, attempt);
|
|
65
|
+
if (this.sent.size > SENT_REMEMBERED)
|
|
66
|
+
this.sent.delete(this.sent.keys().next().value);
|
|
67
|
+
return { attempt, retry: attempt > 1 || (since !== undefined && since < this.d.state.takenAt) };
|
|
68
|
+
}
|
|
69
|
+
/** False when the codec has no message for the command. `since` is when the command's row was created. */
|
|
70
|
+
async publish(machineId, op, cmdId, args, since) {
|
|
71
|
+
this.live();
|
|
72
|
+
const ident = (0, registration_1.identFor)(this.d.state, this.d.line, machineId);
|
|
73
|
+
const command = { cmdId, op, args, ...this.countSend(cmdId, since) };
|
|
74
|
+
const wires = this.d.codec.encode(ident, command);
|
|
75
|
+
for (const wire of wires) {
|
|
40
76
|
await this.d.bus.publish(wire.topic, wire.payload);
|
|
77
|
+
this.d.wire?.command(ident, command, wire);
|
|
78
|
+
}
|
|
41
79
|
return wires.length > 0;
|
|
42
80
|
}
|
|
43
81
|
/** Publish and wait for the reply, asking again with the same id; null when none came. */
|
|
44
|
-
async ask(machineId, op, cmdId, args) {
|
|
82
|
+
async ask(machineId, op, cmdId, args, since) {
|
|
45
83
|
for (let attempt = 1; attempt <= this.d.dispatchAttempts; attempt++) {
|
|
84
|
+
this.live();
|
|
46
85
|
const waiting = this.d.replies.wait(cmdId, this.d.replyTimeoutMs);
|
|
47
|
-
if (!await this.publish(machineId, op, cmdId, args)) {
|
|
86
|
+
if (!await this.publish(machineId, op, cmdId, args, since)) {
|
|
48
87
|
this.d.replies.settle({ cmdId, status: contracts_1.COMMAND_STATUS.UNSUPPORTED, reason: `the line's codec has no ${op} command` });
|
|
49
88
|
}
|
|
50
89
|
const reply = await waiting;
|
|
90
|
+
this.live();
|
|
51
91
|
if (reply)
|
|
52
92
|
return reply;
|
|
53
93
|
}
|
|
@@ -67,15 +107,19 @@ class Dispatcher {
|
|
|
67
107
|
* A machine-command row: send it, then resolve the row with the reply, as the
|
|
68
108
|
* machine that gave it. The command expires when the asking ends, so one that
|
|
69
109
|
* reaches a machine after its row resolved no-reply is refused, never run.
|
|
110
|
+
* Rounds of the asking count from the row's creation, so the command sent
|
|
111
|
+
* again by a new gateway is the same command with the same arguments.
|
|
70
112
|
*/
|
|
71
113
|
async control(a) {
|
|
72
|
-
const
|
|
73
|
-
const
|
|
114
|
+
const now = Date.now();
|
|
115
|
+
const { round, expiresAt } = (0, pacing_1.dispatchWindow)(a.createdAt ?? now, now, this.d.replyTimeoutMs * this.d.dispatchAttempts);
|
|
116
|
+
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);
|
|
74
117
|
// Timers may fire a little early; the command must have expired before the row says no-reply.
|
|
75
118
|
if (!reply && Date.now() <= expiresAt)
|
|
76
|
-
await (0, promises_1.setTimeout)(expiresAt - Date.now() + 1);
|
|
119
|
+
await (0, promises_1.setTimeout)(expiresAt - Date.now() + 1, undefined, { signal: this.stopping.signal }).catch(() => undefined);
|
|
120
|
+
this.live();
|
|
77
121
|
const outcome = reply
|
|
78
|
-
? { accepted: reply.status === protocol_1.REPLY_STATUS.ACCEPTED, machineId: a.machineId, op: a.op, status: reply.status, reason: reply.reason }
|
|
122
|
+
? { accepted: reply.status === protocol_1.REPLY_STATUS.ACCEPTED, machineId: a.machineId, op: a.op, status: reply.status, reason: reply.reason, ...withCode(reply) }
|
|
79
123
|
: { accepted: false, machineId: a.machineId, op: a.op, status: contracts_1.COMMAND_STATUS.NO_REPLY, reason: `no reply after ${this.d.dispatchAttempts} attempts` };
|
|
80
124
|
const context = { row: a.rowId, machine: a.machineId, op: a.op, status: outcome.status, reason: outcome.reason };
|
|
81
125
|
if (outcome.accepted)
|
|
@@ -97,10 +141,12 @@ class Dispatcher {
|
|
|
97
141
|
// Known before any reply, so a failure that follows an acceptance finds its row.
|
|
98
142
|
for (const job of jobs)
|
|
99
143
|
state.rememberDispatch(`${a.cmdId}${job.suffix}`, a.rowId);
|
|
100
|
-
const
|
|
144
|
+
const since = state.get(a.rowId)?.createdAt;
|
|
145
|
+
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)));
|
|
101
146
|
const refused = replies.find((r) => r && !took(r));
|
|
102
147
|
const silent = jobs.filter((_, i) => !replies[i]);
|
|
103
148
|
const held = !refused && silent.length ? await this.heldJobs(a.machineId, a.cmdId) : null;
|
|
149
|
+
this.live();
|
|
104
150
|
const reconciled = !!held && silent.every((j) => held.has(j.jobId));
|
|
105
151
|
const row = state.get(a.rowId);
|
|
106
152
|
if (!refused && (!silent.length || reconciled)) {
|
|
@@ -120,7 +166,7 @@ class Dispatcher {
|
|
|
120
166
|
row.dispatch = state_1.DISPATCH_STATE.REFUSED;
|
|
121
167
|
const unanswered = `${a.machineId} sent no reply after ${this.d.dispatchAttempts} attempts`;
|
|
122
168
|
const resolution = refused
|
|
123
|
-
? { received: false, errorCode: contracts_1.HANDOFF_ERROR.DISPATCH_REFUSED, detail: `${a.machineId} ${refused.status}: ${refused.reason}
|
|
169
|
+
? { received: false, errorCode: contracts_1.HANDOFF_ERROR.DISPATCH_REFUSED, detail: `${a.machineId} ${refused.status}: ${refused.reason}`, ...withCode(refused) }
|
|
124
170
|
: { received: false, errorCode: contracts_1.HANDOFF_ERROR.NO_REPLY, detail: held ? `${unanswered} and does not hold the job` : `${unanswered}; its state is unknown` };
|
|
125
171
|
log.warn(log_1.GATEWAY_LOG.DISPATCH_REFUSED, { row: a.rowId, machine: a.machineId, ...resolution });
|
|
126
172
|
const ended = await lt.resolve(fromMachine(refused ?? null) ? a.machineId : actions_1.CONTROLLER, a.rowId, resolution);
|
|
@@ -132,12 +178,14 @@ class Dispatcher {
|
|
|
132
178
|
}
|
|
133
179
|
/** The units were already at the machine: its acceptance completes the handoff. */
|
|
134
180
|
async received(a) {
|
|
181
|
+
this.live();
|
|
135
182
|
const units = a.args.units.map((u) => u.unitId);
|
|
136
183
|
this.check(a.rowId, 'resolve', await this.d.lt.resolve(a.machineId, a.rowId, { received: true, receiver: a.machineId, units }));
|
|
137
184
|
this.d.state.close(a.rowId);
|
|
138
185
|
}
|
|
139
186
|
/** Ask a silent machine what it holds; null when it cannot say or does not answer in time. */
|
|
140
187
|
async heldJobs(machineId, cmdId) {
|
|
188
|
+
this.live();
|
|
141
189
|
const waiting = this.d.replies.waitSnapshot(machineId, this.d.replyTimeoutMs);
|
|
142
190
|
if (!await this.publish(machineId, protocol_1.OP.SNAPSHOT, `${cmdId}:status`, {}))
|
|
143
191
|
this.d.replies.settleSnapshot(machineId, null);
|
|
@@ -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
|
-
import type
|
|
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,22 +29,33 @@ 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
|
+
/**
|
|
54
|
+
* A dispatch's second reply: ready, or a failure to prepare that ends the
|
|
55
|
+
* handoff. When the handoff into the machine has already ended, as one
|
|
56
|
+
* dispatched on arrival does at acceptance, the failure ends the handoff
|
|
57
|
+
* carrying the units out of it.
|
|
58
|
+
*/
|
|
45
59
|
private lateReply;
|
|
46
60
|
/** Add the item; when the row then holds every key the action waits for, resolve it. */
|
|
47
61
|
private accumulate;
|