@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.
Files changed (392) hide show
  1. package/README.md +9 -2
  2. package/build/api/settings.d.ts +4 -1
  3. package/build/api/settings.js +7 -1
  4. package/build/index.d.ts +4 -0
  5. package/build/index.js +35 -8
  6. package/build/lib/db/config-lock.d.ts +10 -0
  7. package/build/lib/db/config-lock.js +28 -0
  8. package/build/lib/db/schemas/041_machine_lines.sql +26 -0
  9. package/build/lib/events/browser-view.js +8 -2
  10. package/build/lib/events/nats.d.ts +11 -0
  11. package/build/lib/events/nats.js +33 -2
  12. package/build/lib/events/publish.d.ts +33 -0
  13. package/build/lib/events/publish.js +52 -1
  14. package/build/lib/machines/index.d.ts +1 -0
  15. package/build/lib/machines/index.js +1 -0
  16. package/build/lib/machines/line.d.ts +4 -1
  17. package/build/lib/machines/line.js +18 -1
  18. package/build/lib/machines/protocol/codec.d.ts +24 -0
  19. package/build/lib/machines/protocol/codec.js +10 -0
  20. package/build/lib/machines/protocol/constants.d.ts +1 -1
  21. package/build/lib/machines/protocol/constants.js +1 -1
  22. package/build/lib/machines/protocol/contract.js +12 -3
  23. package/build/lib/machines/site/edge-account.d.ts +11 -0
  24. package/build/lib/machines/site/edge-account.js +24 -0
  25. package/build/lib/machines/site/mosquitto-conf.d.ts +5 -4
  26. package/build/lib/machines/site/mosquitto-conf.js +31 -16
  27. package/build/lib/machines/site/site-conf.d.ts +16 -6
  28. package/build/lib/machines/site/site-conf.js +39 -13
  29. package/build/lib/machines/transport/callback-feed.d.ts +1 -0
  30. package/build/lib/machines/transport/callback-feed.js +4 -1
  31. package/build/lib/machines/transport/delivery.d.ts +3 -4
  32. package/build/lib/machines/transport/delivery.js +3 -8
  33. package/build/lib/machines/transport/index.d.ts +2 -0
  34. package/build/lib/machines/transport/index.js +2 -0
  35. package/build/lib/machines/transport/memory.d.ts +2 -0
  36. package/build/lib/machines/transport/memory.js +6 -0
  37. package/build/lib/machines/transport/mqtt-bus.d.ts +2 -0
  38. package/build/lib/machines/transport/mqtt-bus.js +4 -0
  39. package/build/lib/machines/transport/nats-bus.d.ts +8 -13
  40. package/build/lib/machines/transport/nats-bus.js +26 -43
  41. package/build/lib/machines/transport/nats-feed.d.ts +1 -0
  42. package/build/lib/machines/transport/nats-feed.js +6 -3
  43. package/build/lib/machines/transport/pubsub-feed.d.ts +18 -0
  44. package/build/lib/machines/transport/pubsub-feed.js +42 -0
  45. package/build/lib/machines/transport/stream-bus.d.ts +42 -0
  46. package/build/lib/machines/transport/stream-bus.js +61 -0
  47. package/build/lib/machines/transport/streams.d.ts +10 -14
  48. package/build/lib/machines/transport/streams.js +18 -61
  49. package/build/lib/messaging/config.d.ts +25 -0
  50. package/build/lib/messaging/config.js +55 -0
  51. package/build/lib/messaging/constants.d.ts +26 -0
  52. package/build/lib/messaging/constants.js +26 -0
  53. package/build/lib/messaging/index.d.ts +24 -0
  54. package/build/lib/messaging/index.js +65 -0
  55. package/build/lib/messaging/memory.d.ts +16 -0
  56. package/build/lib/messaging/memory.js +147 -0
  57. package/build/lib/messaging/nats/permissions.d.ts +13 -0
  58. package/build/lib/messaging/nats/permissions.js +22 -0
  59. package/build/lib/messaging/nats/provider.d.ts +30 -0
  60. package/build/lib/messaging/nats/provider.js +77 -0
  61. package/build/lib/messaging/nats/render-conf.d.ts +68 -0
  62. package/build/lib/messaging/nats/render-conf.js +58 -0
  63. package/build/lib/messaging/nats/streams.d.ts +26 -0
  64. package/build/lib/messaging/nats/streams.js +97 -0
  65. package/build/lib/messaging/subjects.d.ts +8 -0
  66. package/build/lib/messaging/subjects.js +25 -0
  67. package/build/modules/machines.d.ts +8 -0
  68. package/build/modules/machines.js +16 -0
  69. package/build/routes/index.js +2 -0
  70. package/build/routes/machines.d.ts +2 -0
  71. package/build/routes/machines.js +220 -0
  72. package/build/scripts/bambu-boat.d.ts +17 -0
  73. package/build/scripts/bambu-boat.js +134 -0
  74. package/build/scripts/bambu-print.d.ts +18 -0
  75. package/build/scripts/bambu-print.js +114 -0
  76. package/build/services/machines/commands.d.ts +5 -5
  77. package/build/services/machines/commands.js +3 -2
  78. package/build/services/machines/config.d.ts +8 -1
  79. package/build/services/machines/config.js +17 -7
  80. package/build/services/machines/contracts.d.ts +29 -2
  81. package/build/services/machines/contracts.js +12 -3
  82. package/build/services/machines/gateway/actions.d.ts +2 -1
  83. package/build/services/machines/gateway/admission.d.ts +15 -3
  84. package/build/services/machines/gateway/admission.js +29 -14
  85. package/build/services/machines/gateway/dispatcher.d.ts +19 -3
  86. package/build/services/machines/gateway/dispatcher.js +61 -13
  87. package/build/services/machines/gateway/executor.d.ts +18 -4
  88. package/build/services/machines/gateway/executor.js +99 -34
  89. package/build/services/machines/gateway/gateway.d.ts +22 -1
  90. package/build/services/machines/gateway/gateway.js +83 -28
  91. package/build/services/machines/gateway/index.d.ts +3 -0
  92. package/build/services/machines/gateway/index.js +3 -0
  93. package/build/services/machines/gateway/inspect.d.ts +17 -0
  94. package/build/services/machines/gateway/inspect.js +68 -0
  95. package/build/services/machines/gateway/lifecycle.d.ts +21 -0
  96. package/build/services/machines/gateway/lifecycle.js +89 -0
  97. package/build/services/machines/gateway/log.d.ts +8 -0
  98. package/build/services/machines/gateway/log.js +18 -0
  99. package/build/services/machines/gateway/pacing.d.ts +14 -0
  100. package/build/services/machines/gateway/pacing.js +27 -2
  101. package/build/services/machines/gateway/plan-escalation.js +21 -7
  102. package/build/services/machines/gateway/plan-machine.d.ts +5 -4
  103. package/build/services/machines/gateway/plan-machine.js +70 -19
  104. package/build/services/machines/gateway/project.d.ts +9 -0
  105. package/build/services/machines/gateway/project.js +55 -0
  106. package/build/services/machines/gateway/receipts.d.ts +3 -0
  107. package/build/services/machines/gateway/receipts.js +3 -1
  108. package/build/services/machines/gateway/reconcile.d.ts +2 -0
  109. package/build/services/machines/gateway/reconcile.js +16 -3
  110. package/build/services/machines/gateway/registration.js +1 -1
  111. package/build/services/machines/gateway/reply-waiter.d.ts +6 -3
  112. package/build/services/machines/gateway/reply-waiter.js +37 -16
  113. package/build/services/machines/gateway/state.d.ts +50 -4
  114. package/build/services/machines/gateway/state.js +77 -10
  115. package/build/services/machines/gateway/wire.d.ts +58 -0
  116. package/build/services/machines/gateway/wire.js +171 -0
  117. package/build/services/machines/index.d.ts +3 -0
  118. package/build/services/machines/index.js +2 -0
  119. package/build/services/machines/leadership.d.ts +17 -4
  120. package/build/services/machines/leadership.js +43 -18
  121. package/build/services/machines/line-index.d.ts +16 -0
  122. package/build/services/machines/line-index.js +39 -0
  123. package/build/services/machines/registry-sql.d.ts +31 -0
  124. package/build/services/machines/registry-sql.js +110 -0
  125. package/build/services/machines/registry-sync.d.ts +31 -0
  126. package/build/services/machines/registry-sync.js +81 -0
  127. package/build/services/machines/registry.d.ts +77 -0
  128. package/build/services/machines/registry.js +158 -0
  129. package/build/services/machines/rows.js +26 -2
  130. package/build/services/machines/select.d.ts +9 -2
  131. package/build/services/machines/select.js +20 -7
  132. package/build/services/machines/surface.d.ts +45 -5
  133. package/build/services/machines/surface.js +102 -16
  134. package/build/services/machines/testing/fake-long-tail.d.ts +1 -0
  135. package/build/services/machines/testing/fake-long-tail.js +6 -3
  136. package/build/start/adapters.js +11 -2
  137. package/build/start/apply-report.d.ts +1 -1
  138. package/build/start/apply-report.js +3 -25
  139. package/build/start/index.js +23 -5
  140. package/build/system/index.js +13 -0
  141. package/build/system/mcp-servers/admin/schemas.d.ts +22 -22
  142. package/build/system/mcp-servers/human-queue-schemas.d.ts +7 -7
  143. package/build/system/mcp-servers/machines-schemas.d.ts +35 -0
  144. package/build/system/mcp-servers/machines-schemas.js +35 -0
  145. package/build/system/mcp-servers/machines.d.ts +20 -0
  146. package/build/system/mcp-servers/machines.js +154 -0
  147. package/build/system/seed/tool-manifests-machines.d.ts +2 -0
  148. package/build/system/seed/tool-manifests-machines.js +88 -0
  149. package/build/tsconfig.tsbuildinfo +1 -1
  150. package/build/types/events.d.ts +6 -1
  151. package/build/types/index.d.ts +2 -0
  152. package/build/types/machines-view.d.ts +159 -0
  153. package/build/types/machines-view.js +7 -0
  154. package/build/types/machines.d.ts +6 -1
  155. package/build/types/messaging.d.ts +72 -0
  156. package/build/types/messaging.js +11 -0
  157. package/build/types/startup.d.ts +26 -1
  158. package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js → AdminDashboard-Bm7VG65H.js} +2 -2
  159. package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js.map → AdminDashboard-Bm7VG65H.js.map} +1 -1
  160. package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js → AgentConfigPage-aJF7Sdbc.js} +6 -6
  161. package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js.map → AgentConfigPage-aJF7Sdbc.js.map} +1 -1
  162. package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js → AgentDetailPage-GwwghhxT.js} +3 -3
  163. package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js.map → AgentDetailPage-GwwghhxT.js.map} +1 -1
  164. package/dashboard/dist/assets/AgentsPage-DVvCzZyg.js +2 -0
  165. package/dashboard/dist/assets/{AgentsPage-C9UuUKhr.js.map → AgentsPage-DVvCzZyg.js.map} +1 -1
  166. package/dashboard/dist/assets/AvailableEscalationsPage-Cxmcji_K.js +2 -0
  167. package/dashboard/dist/assets/{AvailableEscalationsPage-DrvfXz70.js.map → AvailableEscalationsPage-Cxmcji_K.js.map} +1 -1
  168. package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js → BotPicker-CofRxk4L.js} +2 -2
  169. package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js.map → BotPicker-CofRxk4L.js.map} +1 -1
  170. package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js → BulkAssignModal-BARWuz4L.js} +2 -2
  171. package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js.map → BulkAssignModal-BARWuz4L.js.map} +1 -1
  172. package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js → CapabilitiesPage-BJAWVNEx.js} +2 -2
  173. package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js.map → CapabilitiesPage-BJAWVNEx.js.map} +1 -1
  174. package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js → CollapsibleSection-CtgoaG75.js} +2 -2
  175. package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js.map → CollapsibleSection-CtgoaG75.js.map} +1 -1
  176. package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js → ConfirmDeleteModal-BYXXBWs6.js} +2 -2
  177. package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js.map → ConfirmDeleteModal-BYXXBWs6.js.map} +1 -1
  178. package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js → ConnectedAppsPage-D0JkzWa7.js} +2 -2
  179. package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js.map → ConnectedAppsPage-D0JkzWa7.js.map} +1 -1
  180. package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js → CountdownTimer-BcFxdZYN.js} +2 -2
  181. package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js.map → CountdownTimer-BcFxdZYN.js.map} +1 -1
  182. package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js → CredentialsPage-DPSY20rV.js} +2 -2
  183. package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js.map → CredentialsPage-DPSY20rV.js.map} +1 -1
  184. package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js → CronLabel-Dg_Oew_Y.js} +2 -2
  185. package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js.map → CronLabel-Dg_Oew_Y.js.map} +1 -1
  186. package/dashboard/dist/assets/{DropZone-u1JGfR9G.js → DropZone-Cl_Flb16.js} +2 -2
  187. package/dashboard/dist/assets/{DropZone-u1JGfR9G.js.map → DropZone-Cl_Flb16.js.map} +1 -1
  188. package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js → ElapsedCell-Dm3G5fK2.js} +2 -2
  189. package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js.map → ElapsedCell-Dm3G5fK2.js.map} +1 -1
  190. package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js → EntityTimelinePanel-CrEEP04e.js} +2 -2
  191. package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js.map → EntityTimelinePanel-CrEEP04e.js.map} +1 -1
  192. package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js → EscalationListSchemaPage-wOInXcjs.js} +3 -3
  193. package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js.map → EscalationListSchemaPage-wOInXcjs.js.map} +1 -1
  194. package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js → EscalationSchemaPage-CrIj_g9d.js} +3 -3
  195. package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js.map → EscalationSchemaPage-CrIj_g9d.js.map} +1 -1
  196. package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js → EscalationTimeline-CeAsl5IT.js} +2 -2
  197. package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js.map → EscalationTimeline-CeAsl5IT.js.map} +1 -1
  198. package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js → EscalationTitleSelect-D8qpCYiy.js} +2 -2
  199. package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js.map → EscalationTitleSelect-D8qpCYiy.js.map} +1 -1
  200. package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js → EscalationsOverview-CvaqVPsr.js} +2 -2
  201. package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js.map → EscalationsOverview-CvaqVPsr.js.map} +1 -1
  202. package/dashboard/dist/assets/{EventTable-V4RF_n58.js → EventTable-Be0JuEl6.js} +2 -2
  203. package/dashboard/dist/assets/{EventTable-V4RF_n58.js.map → EventTable-Be0JuEl6.js.map} +1 -1
  204. package/dashboard/dist/assets/FilterBar-BVyAjIgv.js +2 -0
  205. package/dashboard/dist/assets/FilterBar-BVyAjIgv.js.map +1 -0
  206. package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js → GraphInvokePage-D_QigJeD.js} +2 -2
  207. package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js.map → GraphInvokePage-D_QigJeD.js.map} +1 -1
  208. package/dashboard/dist/assets/{HomePage-EjcNxlKx.js → HomePage-C1haeuNy.js} +2 -2
  209. package/dashboard/dist/assets/{HomePage-EjcNxlKx.js.map → HomePage-C1haeuNy.js.map} +1 -1
  210. package/dashboard/dist/assets/LinePage-CWD5pv1g.js +5 -0
  211. package/dashboard/dist/assets/LinePage-CWD5pv1g.js.map +1 -0
  212. package/dashboard/dist/assets/LinesPage-NqChsKcO.js +3 -0
  213. package/dashboard/dist/assets/LinesPage-NqChsKcO.js.map +1 -0
  214. package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js → ListToolbar-BZCNrTh6.js} +2 -2
  215. package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js.map → ListToolbar-BZCNrTh6.js.map} +1 -1
  216. package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js → McpOverview-yJTYnh1z.js} +2 -2
  217. package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js.map → McpOverview-yJTYnh1z.js.map} +1 -1
  218. package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js → McpQueryDetailPage-ChuLpJ4u.js} +3 -3
  219. package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js.map → McpQueryDetailPage-ChuLpJ4u.js.map} +1 -1
  220. package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js → McpQueryPage-9S-v9soF.js} +2 -2
  221. package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js.map → McpQueryPage-9S-v9soF.js.map} +1 -1
  222. package/dashboard/dist/assets/McpRunDetailPage-BhrcfxD5.js +2 -0
  223. package/dashboard/dist/assets/{McpRunDetailPage-80fQn9iX.js.map → McpRunDetailPage-BhrcfxD5.js.map} +1 -1
  224. package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js → McpRunsPage-C5_i8_Zx.js} +2 -2
  225. package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js.map → McpRunsPage-C5_i8_Zx.js.map} +1 -1
  226. package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js → NamespacePill-OTZD2hzt.js} +2 -2
  227. package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js.map → NamespacePill-OTZD2hzt.js.map} +1 -1
  228. package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js → OperationsPage-C03CeU5P.js} +2 -2
  229. package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js.map → OperationsPage-C03CeU5P.js.map} +1 -1
  230. package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js → OperatorDashboard-BzC134Jt.js} +2 -2
  231. package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js.map → OperatorDashboard-BzC134Jt.js.map} +1 -1
  232. package/dashboard/dist/assets/{PageHeader-BSWIspNB.js → PageHeader-Hx8APPwE.js} +2 -2
  233. package/dashboard/dist/assets/{PageHeader-BSWIspNB.js.map → PageHeader-Hx8APPwE.js.map} +1 -1
  234. package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js → PageHeaderWithStats-BEQYYBJv.js} +2 -2
  235. package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js.map → PageHeaderWithStats-BEQYYBJv.js.map} +1 -1
  236. package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js → PersonaDetailPage-D0mY9L6j.js} +2 -2
  237. package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js.map → PersonaDetailPage-D0mY9L6j.js.map} +1 -1
  238. package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js → PersonasPage-FFlm5Eug.js} +2 -2
  239. package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js.map → PersonasPage-FFlm5Eug.js.map} +1 -1
  240. package/dashboard/dist/assets/{PortalPage-CucNZn_w.js → PortalPage-Cpc25uO-.js} +2 -2
  241. package/dashboard/dist/assets/{PortalPage-CucNZn_w.js.map → PortalPage-Cpc25uO-.js.map} +1 -1
  242. package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js → ProcessDetailPage-Di2J7KwY.js} +2 -2
  243. package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js.map → ProcessDetailPage-Di2J7KwY.js.map} +1 -1
  244. package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js → ProcessesListPage-BEXwU3Z0.js} +2 -2
  245. package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js.map → ProcessesListPage-BEXwU3Z0.js.map} +1 -1
  246. package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js → ResolverForm-2ks-3jXC.js} +6 -6
  247. package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js.map → ResolverForm-2ks-3jXC.js.map} +1 -1
  248. package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js → RoleDetailPage-DqoOk0xc.js} +3 -3
  249. package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js.map → RoleDetailPage-DqoOk0xc.js.map} +1 -1
  250. package/dashboard/dist/assets/{RolePill-CoETDpjF.js → RolePill-R5_ctGFy.js} +2 -2
  251. package/dashboard/dist/assets/{RolePill-CoETDpjF.js.map → RolePill-R5_ctGFy.js.map} +1 -1
  252. package/dashboard/dist/assets/{RolesPage-DBKxeam4.js → RolesPage-CPmo8Srr.js} +2 -2
  253. package/dashboard/dist/assets/{RolesPage-DBKxeam4.js.map → RolesPage-CPmo8Srr.js.map} +1 -1
  254. package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js → RosterWidget-D2yovCKw.js} +2 -2
  255. package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js.map → RosterWidget-D2yovCKw.js.map} +1 -1
  256. package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js → RunAsSelector-CMv96On6.js} +2 -2
  257. package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js.map → RunAsSelector-CMv96On6.js.map} +1 -1
  258. package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js → ScanCodesPage-CA6cTT-M.js} +2 -2
  259. package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js.map → ScanCodesPage-CA6cTT-M.js.map} +1 -1
  260. package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js → ScanSchemeDetailPage-DnctN5-H.js} +2 -2
  261. package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js.map → ScanSchemeDetailPage-DnctN5-H.js.map} +1 -1
  262. package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js → ScanStationPage-Bk8RwkKL.js} +2 -2
  263. package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js.map → ScanStationPage-Bk8RwkKL.js.map} +1 -1
  264. package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js → ScopeBadge-BXZ084nD.js} +2 -2
  265. package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js.map → ScopeBadge-BXZ084nD.js.map} +1 -1
  266. package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js → StickyPagination-B0FSuUgs.js} +2 -2
  267. package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js.map → StickyPagination-B0FSuUgs.js.map} +1 -1
  268. package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js → StreamMessageDetail-BwZEvMpP.js} +2 -2
  269. package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js.map → StreamMessageDetail-BwZEvMpP.js.map} +1 -1
  270. package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js → SwimlaneTimeline-BDVQEaMw.js} +2 -2
  271. package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js.map → SwimlaneTimeline-BDVQEaMw.js.map} +1 -1
  272. package/dashboard/dist/assets/{TagInput-S7UuVT_M.js → TagInput-DjPUDp2M.js} +2 -2
  273. package/dashboard/dist/assets/{TagInput-S7UuVT_M.js.map → TagInput-DjPUDp2M.js.map} +1 -1
  274. package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js → TaskDetailPage-BOlv3iGB.js} +2 -2
  275. package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js.map → TaskDetailPage-BOlv3iGB.js.map} +1 -1
  276. package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js → TaskQueuePill-D-4Ynf3K.js} +2 -2
  277. package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js.map → TaskQueuePill-D-4Ynf3K.js.map} +1 -1
  278. package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js → TasksListPage-e2teY0bD.js} +2 -2
  279. package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js.map → TasksListPage-e2teY0bD.js.map} +1 -1
  280. package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js → TimeAgo-Cvkpf_b3.js} +2 -2
  281. package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js.map → TimeAgo-Cvkpf_b3.js.map} +1 -1
  282. package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js → TimestampCell-B3btAV0N.js} +2 -2
  283. package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js.map → TimestampCell-B3btAV0N.js.map} +1 -1
  284. package/dashboard/dist/assets/{ToolPill-D40uLM_v.js → ToolPill-GsKQ80CO.js} +2 -2
  285. package/dashboard/dist/assets/{ToolPill-D40uLM_v.js.map → ToolPill-GsKQ80CO.js.map} +1 -1
  286. package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js → ToolTestPanel-B03nebR7.js} +2 -2
  287. package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js.map → ToolTestPanel-B03nebR7.js.map} +1 -1
  288. package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js → TopicDetailPage-DBRWne3O.js} +3 -3
  289. package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js.map → TopicDetailPage-DBRWne3O.js.map} +1 -1
  290. package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js → TopicsPage-CVe2M9HD.js} +2 -2
  291. package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js.map → TopicsPage-CVe2M9HD.js.map} +1 -1
  292. package/dashboard/dist/assets/{UserName-DQFjuoib.js → UserName-B_q_qp6V.js} +2 -2
  293. package/dashboard/dist/assets/{UserName-DQFjuoib.js.map → UserName-B_q_qp6V.js.map} +1 -1
  294. package/dashboard/dist/assets/WorkflowExecutionPage-Bh_dr9tM.js +2 -0
  295. package/dashboard/dist/assets/{WorkflowExecutionPage-Di08wCbs.js.map → WorkflowExecutionPage-Bh_dr9tM.js.map} +1 -1
  296. package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js → WorkflowPill-D7244fKp.js} +2 -2
  297. package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js.map → WorkflowPill-D7244fKp.js.map} +1 -1
  298. package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js → WorkflowsDashboard-DA6Mj7qH.js} +2 -2
  299. package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js.map → WorkflowsDashboard-DA6Mj7qH.js.map} +1 -1
  300. package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js → WorkflowsOverview-B1kBLj-a.js} +2 -2
  301. package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js.map → WorkflowsOverview-B1kBLj-a.js.map} +1 -1
  302. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js → YamlWorkflowDetailPage-6GJM8QIX.js} +8 -8
  303. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js.map → YamlWorkflowDetailPage-6GJM8QIX.js.map} +1 -1
  304. package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js → YamlWorkflowsPage-Bu811C7f.js} +2 -2
  305. package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js.map → YamlWorkflowsPage-Bu811C7f.js.map} +1 -1
  306. package/dashboard/dist/assets/{agents-PuftRTB2.js → agents-MPk_GnYz.js} +2 -2
  307. package/dashboard/dist/assets/{agents-PuftRTB2.js.map → agents-MPk_GnYz.js.map} +1 -1
  308. package/dashboard/dist/assets/{bots-BmEiPAWY.js → bots-2RihE2Tc.js} +2 -2
  309. package/dashboard/dist/assets/{bots-BmEiPAWY.js.map → bots-2RihE2Tc.js.map} +1 -1
  310. package/dashboard/dist/assets/{capabilities-CRii4Soa.js → capabilities-CC4iwJ1P.js} +2 -2
  311. package/dashboard/dist/assets/{capabilities-CRii4Soa.js.map → capabilities-CC4iwJ1P.js.map} +1 -1
  312. package/dashboard/dist/assets/{controlplane-DO_czaYo.js → controlplane-Bmkic8BH.js} +2 -2
  313. package/dashboard/dist/assets/{controlplane-DO_czaYo.js.map → controlplane-Bmkic8BH.js.map} +1 -1
  314. package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js → escalation-columns-B0lhUUrQ.js} +2 -2
  315. package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js.map → escalation-columns-B0lhUUrQ.js.map} +1 -1
  316. package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js → escalation-items-7WFpPo46.js} +2 -2
  317. package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js.map → escalation-items-7WFpPo46.js.map} +1 -1
  318. package/dashboard/dist/assets/index-B9uv-euR.css +1 -0
  319. package/dashboard/dist/assets/{index-DhSCCpqM.js → index-B_XV1rwu.js} +2 -2
  320. package/dashboard/dist/assets/{index-DhSCCpqM.js.map → index-B_XV1rwu.js.map} +1 -1
  321. package/dashboard/dist/assets/{index-Cx8xb-oU.js → index-C2CLfGwL.js} +2 -2
  322. package/dashboard/dist/assets/{index-Cx8xb-oU.js.map → index-C2CLfGwL.js.map} +1 -1
  323. package/dashboard/dist/assets/{index-Cga5IW3D.js → index-C3AeFihz.js} +2 -2
  324. package/dashboard/dist/assets/{index-Cga5IW3D.js.map → index-C3AeFihz.js.map} +1 -1
  325. package/dashboard/dist/assets/{index-DiaRlFYI.js → index-CBri8fYM.js} +2 -2
  326. package/dashboard/dist/assets/{index-DiaRlFYI.js.map → index-CBri8fYM.js.map} +1 -1
  327. package/dashboard/dist/assets/{index-CL_1VpGb.js → index-CRWsB7ZC.js} +2 -2
  328. package/dashboard/dist/assets/{index-CL_1VpGb.js.map → index-CRWsB7ZC.js.map} +1 -1
  329. package/dashboard/dist/assets/{index-XntldBd0.js → index-CTOv3G7a.js} +2 -2
  330. package/dashboard/dist/assets/{index-XntldBd0.js.map → index-CTOv3G7a.js.map} +1 -1
  331. package/dashboard/dist/assets/{index-CfP2nKRc.js → index-CcArGkzI.js} +3 -3
  332. package/dashboard/dist/assets/{index-CfP2nKRc.js.map → index-CcArGkzI.js.map} +1 -1
  333. package/dashboard/dist/assets/{index-Dz6R8-Dw.js → index-CkMHS-hG.js} +25 -25
  334. package/dashboard/dist/assets/index-CkMHS-hG.js.map +1 -0
  335. package/dashboard/dist/assets/index-CmsmwCyv.js +2 -0
  336. package/dashboard/dist/assets/{index-4YaDUcKd.js.map → index-CmsmwCyv.js.map} +1 -1
  337. package/dashboard/dist/assets/{index-2SM2_onB.js → index-CvJsvqIc.js} +2 -2
  338. package/dashboard/dist/assets/{index-2SM2_onB.js.map → index-CvJsvqIc.js.map} +1 -1
  339. package/dashboard/dist/assets/{index-Rwqrflm-.js → index-D-ilRyfy.js} +2 -2
  340. package/dashboard/dist/assets/{index-Rwqrflm-.js.map → index-D-ilRyfy.js.map} +1 -1
  341. package/dashboard/dist/assets/{index-CZ7A3AcD.js → index-DSUtfDXx.js} +2 -2
  342. package/dashboard/dist/assets/{index-CZ7A3AcD.js.map → index-DSUtfDXx.js.map} +1 -1
  343. package/dashboard/dist/assets/{index-jL2K6us4.js → index-Da6ycKyf.js} +2 -2
  344. package/dashboard/dist/assets/{index-jL2K6us4.js.map → index-Da6ycKyf.js.map} +1 -1
  345. package/dashboard/dist/assets/{knowledge-CeUqGPuo.js → knowledge-Bpbg20DC.js} +2 -2
  346. package/dashboard/dist/assets/{knowledge-CeUqGPuo.js.map → knowledge-Bpbg20DC.js.map} +1 -1
  347. package/dashboard/dist/assets/machines-BqOZZU-3.js +2 -0
  348. package/dashboard/dist/assets/machines-BqOZZU-3.js.map +1 -0
  349. package/dashboard/dist/assets/{mcp-Cx96NTeD.js → mcp-CmcUXYce.js} +2 -2
  350. package/dashboard/dist/assets/{mcp-Cx96NTeD.js.map → mcp-CmcUXYce.js.map} +1 -1
  351. package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js → mcp-query-C8buQxN9.js} +2 -2
  352. package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js.map → mcp-query-C8buQxN9.js.map} +1 -1
  353. package/dashboard/dist/assets/{personas--4kjwyOw.js → personas-C2n5oDmY.js} +2 -2
  354. package/dashboard/dist/assets/{personas--4kjwyOw.js.map → personas-C2n5oDmY.js.map} +1 -1
  355. package/dashboard/dist/assets/{pipelines-PgkwvG7f.js → pipelines-RKpSkFz7.js} +2 -2
  356. package/dashboard/dist/assets/{pipelines-PgkwvG7f.js.map → pipelines-RKpSkFz7.js.map} +1 -1
  357. package/dashboard/dist/assets/{tasks-CcYxdBa3.js → tasks-Dab4hExW.js} +2 -2
  358. package/dashboard/dist/assets/{tasks-CcYxdBa3.js.map → tasks-Dab4hExW.js.map} +1 -1
  359. package/dashboard/dist/assets/{topics-_lik7cNY.js → topics-FTMNP7r3.js} +2 -2
  360. package/dashboard/dist/assets/{topics-_lik7cNY.js.map → topics-FTMNP7r3.js.map} +1 -1
  361. package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js → useDebouncedValue-B_1u1YIk.js} +2 -2
  362. package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js.map → useDebouncedValue-B_1u1YIk.js.map} +1 -1
  363. package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js → useNamespace-HUeAI7Qb.js} +2 -2
  364. package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js.map → useNamespace-HUeAI7Qb.js.map} +1 -1
  365. package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js → useYamlActivityEvents-Cax54qHH.js} +2 -2
  366. package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js.map → useYamlActivityEvents-Cax54qHH.js.map} +1 -1
  367. package/dashboard/dist/assets/{validate-FlXCBBT6.js → validate-DxOaV7QS.js} +2 -2
  368. package/dashboard/dist/assets/{validate-FlXCBBT6.js.map → validate-DxOaV7QS.js.map} +1 -1
  369. package/dashboard/dist/assets/{vendor-icons-DUYcKTjP.js → vendor-icons-fxBvvHBi.js} +187 -182
  370. package/dashboard/dist/assets/vendor-icons-fxBvvHBi.js.map +1 -0
  371. package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js → yaml-workflows-BgY1XHJx.js} +2 -2
  372. package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js.map → yaml-workflows-BgY1XHJx.js.map} +1 -1
  373. package/dashboard/dist/index.html +3 -3
  374. package/docs/architecture.md +1 -0
  375. package/docs/code-owned-configuration.md +6 -0
  376. package/docs/dashboard.md +1 -0
  377. package/docs/events.md +83 -4
  378. package/docs/machines.md +129 -23
  379. package/docs/mcp.md +19 -0
  380. package/package.json +3 -1
  381. package/build/lib/machines/transport/nats-durable.d.ts +0 -11
  382. package/build/lib/machines/transport/nats-durable.js +0 -28
  383. package/dashboard/dist/assets/AgentsPage-C9UuUKhr.js +0 -2
  384. package/dashboard/dist/assets/AvailableEscalationsPage-DrvfXz70.js +0 -2
  385. package/dashboard/dist/assets/FilterBar-BygWrnB1.js +0 -2
  386. package/dashboard/dist/assets/FilterBar-BygWrnB1.js.map +0 -1
  387. package/dashboard/dist/assets/McpRunDetailPage-80fQn9iX.js +0 -2
  388. package/dashboard/dist/assets/WorkflowExecutionPage-Di08wCbs.js +0 -2
  389. package/dashboard/dist/assets/index-4YaDUcKd.js +0 -2
  390. package/dashboard/dist/assets/index-CnU7Jjz3.css +0 -1
  391. package/dashboard/dist/assets/index-Dz6R8-Dw.js.map +0 -1
  392. 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 ?? 'line/v1',
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
- config.siteNatsUrl = required(env, 'MACHINE_SITE_NATS_URL', transport);
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
- export declare const dispatchCommandId: (escalationId: string) => string;
192
- export declare const controlCommandId: (escalationId: string) => string;
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
- const dispatchCommandId = (escalationId) => `${escalationId}:dispatch`;
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
- const controlCommandId = (escalationId) => `${escalationId}:command`;
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<void>;
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<Inspection | Applied>;
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
- if (sender.status === registration_1.SENDER.UNKNOWN && ctx.state.firstHeardStranger(sender.address))
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
- ctx.log.error(log_1.GATEWAY_LOG.VERB_FAILED, { topic, error: err.message });
43
- return { disposition: transport_1.DISPOSITION.NAK, failed: true };
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
- ctx.log.error(log_1.GATEWAY_LOG.VERB_FAILED, { topic: msg.topic, error: err.message });
64
- return { disposition: transport_1.DISPOSITION.NAK, failed: true };
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
- /** False when the codec has no message for the command. */
44
- publish(machineId: string, op: string, cmdId: string, args: Record<string, any>): Promise<boolean>;
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>): Promise<CommandReply | null>;
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
- /** False when the codec has no message for the command. */
37
- async publish(machineId, op, cmdId, args) {
38
- const wires = this.d.codec.encode((0, registration_1.identFor)(this.d.state, this.d.line, machineId), { cmdId, op, args });
39
- for (const wire of wires)
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 expiresAt = Date.now() + this.d.replyTimeoutMs * this.d.dispatchAttempts;
73
- const reply = await this.ask(a.machineId, a.op, a.cmdId, { ...a.args, expiresAt: (0, protocol_1.isoTs)(expiresAt) });
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 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 })));
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 { GatewayState } from './state';
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<void>;
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
- /** A dispatch's second reply: ready, or a failure to prepare that ends the handoff. */
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;