@hotmeshio/long-tail 0.27.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 (339) 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.js +9 -4
  5. package/build/lib/db/config-lock.d.ts +10 -0
  6. package/build/lib/db/config-lock.js +28 -0
  7. package/build/lib/db/schemas/041_machine_lines.sql +26 -0
  8. package/build/lib/events/browser-view.js +8 -2
  9. package/build/lib/events/publish.d.ts +33 -0
  10. package/build/lib/events/publish.js +52 -1
  11. package/build/lib/machines/line.d.ts +4 -1
  12. package/build/lib/machines/line.js +18 -1
  13. package/build/lib/machines/protocol/codec.d.ts +8 -0
  14. package/build/lib/machines/protocol/codec.js +9 -0
  15. package/build/lib/machines/protocol/constants.d.ts +1 -1
  16. package/build/lib/machines/protocol/constants.js +1 -1
  17. package/build/lib/machines/protocol/contract.js +2 -2
  18. package/build/lib/machines/site/mosquitto-conf.d.ts +5 -4
  19. package/build/lib/machines/site/mosquitto-conf.js +31 -16
  20. package/build/lib/machines/site/site-conf.d.ts +9 -2
  21. package/build/lib/machines/site/site-conf.js +27 -8
  22. package/build/lib/machines/transport/callback-feed.d.ts +1 -0
  23. package/build/lib/machines/transport/callback-feed.js +4 -1
  24. package/build/lib/machines/transport/memory.d.ts +2 -0
  25. package/build/lib/machines/transport/memory.js +6 -0
  26. package/build/lib/machines/transport/mqtt-bus.d.ts +2 -0
  27. package/build/lib/machines/transport/mqtt-bus.js +4 -0
  28. package/build/lib/machines/transport/nats-bus.d.ts +1 -0
  29. package/build/lib/machines/transport/nats-bus.js +3 -0
  30. package/build/lib/machines/transport/nats-feed.d.ts +1 -0
  31. package/build/lib/machines/transport/nats-feed.js +4 -1
  32. package/build/lib/machines/transport/pubsub-feed.d.ts +1 -0
  33. package/build/lib/machines/transport/pubsub-feed.js +4 -1
  34. package/build/lib/machines/transport/stream-bus.d.ts +2 -0
  35. package/build/lib/machines/transport/stream-bus.js +5 -1
  36. package/build/modules/machines.d.ts +8 -0
  37. package/build/modules/machines.js +16 -0
  38. package/build/routes/index.js +2 -0
  39. package/build/routes/machines.d.ts +2 -0
  40. package/build/routes/machines.js +220 -0
  41. package/build/services/machines/commands.d.ts +5 -5
  42. package/build/services/machines/commands.js +3 -2
  43. package/build/services/machines/config.d.ts +2 -1
  44. package/build/services/machines/config.js +1 -1
  45. package/build/services/machines/contracts.d.ts +10 -0
  46. package/build/services/machines/gateway/actions.d.ts +1 -0
  47. package/build/services/machines/gateway/admission.d.ts +15 -3
  48. package/build/services/machines/gateway/admission.js +29 -14
  49. package/build/services/machines/gateway/dispatcher.d.ts +3 -0
  50. package/build/services/machines/gateway/dispatcher.js +12 -4
  51. package/build/services/machines/gateway/executor.d.ts +11 -2
  52. package/build/services/machines/gateway/executor.js +68 -29
  53. package/build/services/machines/gateway/gateway.d.ts +16 -1
  54. package/build/services/machines/gateway/gateway.js +55 -23
  55. package/build/services/machines/gateway/index.d.ts +3 -0
  56. package/build/services/machines/gateway/index.js +3 -0
  57. package/build/services/machines/gateway/inspect.d.ts +17 -0
  58. package/build/services/machines/gateway/inspect.js +68 -0
  59. package/build/services/machines/gateway/log.d.ts +8 -0
  60. package/build/services/machines/gateway/log.js +18 -0
  61. package/build/services/machines/gateway/pacing.js +1 -0
  62. package/build/services/machines/gateway/plan-escalation.js +8 -3
  63. package/build/services/machines/gateway/plan-machine.js +16 -6
  64. package/build/services/machines/gateway/project.d.ts +9 -0
  65. package/build/services/machines/gateway/project.js +55 -0
  66. package/build/services/machines/gateway/receipts.d.ts +3 -0
  67. package/build/services/machines/gateway/receipts.js +3 -1
  68. package/build/services/machines/gateway/reconcile.js +3 -3
  69. package/build/services/machines/gateway/registration.js +1 -1
  70. package/build/services/machines/gateway/reply-waiter.d.ts +6 -3
  71. package/build/services/machines/gateway/reply-waiter.js +37 -16
  72. package/build/services/machines/gateway/state.d.ts +29 -3
  73. package/build/services/machines/gateway/state.js +61 -7
  74. package/build/services/machines/gateway/wire.d.ts +58 -0
  75. package/build/services/machines/gateway/wire.js +171 -0
  76. package/build/services/machines/index.d.ts +3 -0
  77. package/build/services/machines/index.js +2 -0
  78. package/build/services/machines/line-index.d.ts +16 -0
  79. package/build/services/machines/line-index.js +39 -0
  80. package/build/services/machines/registry-sql.d.ts +31 -0
  81. package/build/services/machines/registry-sql.js +110 -0
  82. package/build/services/machines/registry-sync.d.ts +31 -0
  83. package/build/services/machines/registry-sync.js +81 -0
  84. package/build/services/machines/registry.d.ts +77 -0
  85. package/build/services/machines/registry.js +158 -0
  86. package/build/services/machines/rows.js +10 -1
  87. package/build/services/machines/surface.d.ts +45 -5
  88. package/build/services/machines/surface.js +95 -15
  89. package/build/start/apply-report.d.ts +1 -1
  90. package/build/start/apply-report.js +3 -25
  91. package/build/start/index.js +16 -4
  92. package/build/system/index.js +13 -0
  93. package/build/system/mcp-servers/admin/schemas.d.ts +22 -22
  94. package/build/system/mcp-servers/human-queue-schemas.d.ts +7 -7
  95. package/build/system/mcp-servers/machines-schemas.d.ts +35 -0
  96. package/build/system/mcp-servers/machines-schemas.js +35 -0
  97. package/build/system/mcp-servers/machines.d.ts +20 -0
  98. package/build/system/mcp-servers/machines.js +154 -0
  99. package/build/system/seed/tool-manifests-machines.d.ts +2 -0
  100. package/build/system/seed/tool-manifests-machines.js +88 -0
  101. package/build/tsconfig.tsbuildinfo +1 -1
  102. package/build/types/events.d.ts +6 -1
  103. package/build/types/index.d.ts +1 -0
  104. package/build/types/machines-view.d.ts +159 -0
  105. package/build/types/machines-view.js +7 -0
  106. package/build/types/machines.d.ts +4 -0
  107. package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js → AdminDashboard-Bm7VG65H.js} +2 -2
  108. package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js.map → AdminDashboard-Bm7VG65H.js.map} +1 -1
  109. package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js → AgentConfigPage-aJF7Sdbc.js} +6 -6
  110. package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js.map → AgentConfigPage-aJF7Sdbc.js.map} +1 -1
  111. package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js → AgentDetailPage-GwwghhxT.js} +3 -3
  112. package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js.map → AgentDetailPage-GwwghhxT.js.map} +1 -1
  113. package/dashboard/dist/assets/AgentsPage-DVvCzZyg.js +2 -0
  114. package/dashboard/dist/assets/{AgentsPage-C9UuUKhr.js.map → AgentsPage-DVvCzZyg.js.map} +1 -1
  115. package/dashboard/dist/assets/AvailableEscalationsPage-Cxmcji_K.js +2 -0
  116. package/dashboard/dist/assets/{AvailableEscalationsPage-DrvfXz70.js.map → AvailableEscalationsPage-Cxmcji_K.js.map} +1 -1
  117. package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js → BotPicker-CofRxk4L.js} +2 -2
  118. package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js.map → BotPicker-CofRxk4L.js.map} +1 -1
  119. package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js → BulkAssignModal-BARWuz4L.js} +2 -2
  120. package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js.map → BulkAssignModal-BARWuz4L.js.map} +1 -1
  121. package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js → CapabilitiesPage-BJAWVNEx.js} +2 -2
  122. package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js.map → CapabilitiesPage-BJAWVNEx.js.map} +1 -1
  123. package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js → CollapsibleSection-CtgoaG75.js} +2 -2
  124. package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js.map → CollapsibleSection-CtgoaG75.js.map} +1 -1
  125. package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js → ConfirmDeleteModal-BYXXBWs6.js} +2 -2
  126. package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js.map → ConfirmDeleteModal-BYXXBWs6.js.map} +1 -1
  127. package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js → ConnectedAppsPage-D0JkzWa7.js} +2 -2
  128. package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js.map → ConnectedAppsPage-D0JkzWa7.js.map} +1 -1
  129. package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js → CountdownTimer-BcFxdZYN.js} +2 -2
  130. package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js.map → CountdownTimer-BcFxdZYN.js.map} +1 -1
  131. package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js → CredentialsPage-DPSY20rV.js} +2 -2
  132. package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js.map → CredentialsPage-DPSY20rV.js.map} +1 -1
  133. package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js → CronLabel-Dg_Oew_Y.js} +2 -2
  134. package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js.map → CronLabel-Dg_Oew_Y.js.map} +1 -1
  135. package/dashboard/dist/assets/{DropZone-u1JGfR9G.js → DropZone-Cl_Flb16.js} +2 -2
  136. package/dashboard/dist/assets/{DropZone-u1JGfR9G.js.map → DropZone-Cl_Flb16.js.map} +1 -1
  137. package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js → ElapsedCell-Dm3G5fK2.js} +2 -2
  138. package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js.map → ElapsedCell-Dm3G5fK2.js.map} +1 -1
  139. package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js → EntityTimelinePanel-CrEEP04e.js} +2 -2
  140. package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js.map → EntityTimelinePanel-CrEEP04e.js.map} +1 -1
  141. package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js → EscalationListSchemaPage-wOInXcjs.js} +3 -3
  142. package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js.map → EscalationListSchemaPage-wOInXcjs.js.map} +1 -1
  143. package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js → EscalationSchemaPage-CrIj_g9d.js} +3 -3
  144. package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js.map → EscalationSchemaPage-CrIj_g9d.js.map} +1 -1
  145. package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js → EscalationTimeline-CeAsl5IT.js} +2 -2
  146. package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js.map → EscalationTimeline-CeAsl5IT.js.map} +1 -1
  147. package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js → EscalationTitleSelect-D8qpCYiy.js} +2 -2
  148. package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js.map → EscalationTitleSelect-D8qpCYiy.js.map} +1 -1
  149. package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js → EscalationsOverview-CvaqVPsr.js} +2 -2
  150. package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js.map → EscalationsOverview-CvaqVPsr.js.map} +1 -1
  151. package/dashboard/dist/assets/{EventTable-V4RF_n58.js → EventTable-Be0JuEl6.js} +2 -2
  152. package/dashboard/dist/assets/{EventTable-V4RF_n58.js.map → EventTable-Be0JuEl6.js.map} +1 -1
  153. package/dashboard/dist/assets/FilterBar-BVyAjIgv.js +2 -0
  154. package/dashboard/dist/assets/FilterBar-BVyAjIgv.js.map +1 -0
  155. package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js → GraphInvokePage-D_QigJeD.js} +2 -2
  156. package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js.map → GraphInvokePage-D_QigJeD.js.map} +1 -1
  157. package/dashboard/dist/assets/{HomePage-EjcNxlKx.js → HomePage-C1haeuNy.js} +2 -2
  158. package/dashboard/dist/assets/{HomePage-EjcNxlKx.js.map → HomePage-C1haeuNy.js.map} +1 -1
  159. package/dashboard/dist/assets/LinePage-CWD5pv1g.js +5 -0
  160. package/dashboard/dist/assets/LinePage-CWD5pv1g.js.map +1 -0
  161. package/dashboard/dist/assets/LinesPage-NqChsKcO.js +3 -0
  162. package/dashboard/dist/assets/LinesPage-NqChsKcO.js.map +1 -0
  163. package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js → ListToolbar-BZCNrTh6.js} +2 -2
  164. package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js.map → ListToolbar-BZCNrTh6.js.map} +1 -1
  165. package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js → McpOverview-yJTYnh1z.js} +2 -2
  166. package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js.map → McpOverview-yJTYnh1z.js.map} +1 -1
  167. package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js → McpQueryDetailPage-ChuLpJ4u.js} +3 -3
  168. package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js.map → McpQueryDetailPage-ChuLpJ4u.js.map} +1 -1
  169. package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js → McpQueryPage-9S-v9soF.js} +2 -2
  170. package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js.map → McpQueryPage-9S-v9soF.js.map} +1 -1
  171. package/dashboard/dist/assets/McpRunDetailPage-BhrcfxD5.js +2 -0
  172. package/dashboard/dist/assets/{McpRunDetailPage-80fQn9iX.js.map → McpRunDetailPage-BhrcfxD5.js.map} +1 -1
  173. package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js → McpRunsPage-C5_i8_Zx.js} +2 -2
  174. package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js.map → McpRunsPage-C5_i8_Zx.js.map} +1 -1
  175. package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js → NamespacePill-OTZD2hzt.js} +2 -2
  176. package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js.map → NamespacePill-OTZD2hzt.js.map} +1 -1
  177. package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js → OperationsPage-C03CeU5P.js} +2 -2
  178. package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js.map → OperationsPage-C03CeU5P.js.map} +1 -1
  179. package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js → OperatorDashboard-BzC134Jt.js} +2 -2
  180. package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js.map → OperatorDashboard-BzC134Jt.js.map} +1 -1
  181. package/dashboard/dist/assets/{PageHeader-BSWIspNB.js → PageHeader-Hx8APPwE.js} +2 -2
  182. package/dashboard/dist/assets/{PageHeader-BSWIspNB.js.map → PageHeader-Hx8APPwE.js.map} +1 -1
  183. package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js → PageHeaderWithStats-BEQYYBJv.js} +2 -2
  184. package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js.map → PageHeaderWithStats-BEQYYBJv.js.map} +1 -1
  185. package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js → PersonaDetailPage-D0mY9L6j.js} +2 -2
  186. package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js.map → PersonaDetailPage-D0mY9L6j.js.map} +1 -1
  187. package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js → PersonasPage-FFlm5Eug.js} +2 -2
  188. package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js.map → PersonasPage-FFlm5Eug.js.map} +1 -1
  189. package/dashboard/dist/assets/{PortalPage-CucNZn_w.js → PortalPage-Cpc25uO-.js} +2 -2
  190. package/dashboard/dist/assets/{PortalPage-CucNZn_w.js.map → PortalPage-Cpc25uO-.js.map} +1 -1
  191. package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js → ProcessDetailPage-Di2J7KwY.js} +2 -2
  192. package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js.map → ProcessDetailPage-Di2J7KwY.js.map} +1 -1
  193. package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js → ProcessesListPage-BEXwU3Z0.js} +2 -2
  194. package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js.map → ProcessesListPage-BEXwU3Z0.js.map} +1 -1
  195. package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js → ResolverForm-2ks-3jXC.js} +6 -6
  196. package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js.map → ResolverForm-2ks-3jXC.js.map} +1 -1
  197. package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js → RoleDetailPage-DqoOk0xc.js} +3 -3
  198. package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js.map → RoleDetailPage-DqoOk0xc.js.map} +1 -1
  199. package/dashboard/dist/assets/{RolePill-CoETDpjF.js → RolePill-R5_ctGFy.js} +2 -2
  200. package/dashboard/dist/assets/{RolePill-CoETDpjF.js.map → RolePill-R5_ctGFy.js.map} +1 -1
  201. package/dashboard/dist/assets/{RolesPage-DBKxeam4.js → RolesPage-CPmo8Srr.js} +2 -2
  202. package/dashboard/dist/assets/{RolesPage-DBKxeam4.js.map → RolesPage-CPmo8Srr.js.map} +1 -1
  203. package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js → RosterWidget-D2yovCKw.js} +2 -2
  204. package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js.map → RosterWidget-D2yovCKw.js.map} +1 -1
  205. package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js → RunAsSelector-CMv96On6.js} +2 -2
  206. package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js.map → RunAsSelector-CMv96On6.js.map} +1 -1
  207. package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js → ScanCodesPage-CA6cTT-M.js} +2 -2
  208. package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js.map → ScanCodesPage-CA6cTT-M.js.map} +1 -1
  209. package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js → ScanSchemeDetailPage-DnctN5-H.js} +2 -2
  210. package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js.map → ScanSchemeDetailPage-DnctN5-H.js.map} +1 -1
  211. package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js → ScanStationPage-Bk8RwkKL.js} +2 -2
  212. package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js.map → ScanStationPage-Bk8RwkKL.js.map} +1 -1
  213. package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js → ScopeBadge-BXZ084nD.js} +2 -2
  214. package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js.map → ScopeBadge-BXZ084nD.js.map} +1 -1
  215. package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js → StickyPagination-B0FSuUgs.js} +2 -2
  216. package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js.map → StickyPagination-B0FSuUgs.js.map} +1 -1
  217. package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js → StreamMessageDetail-BwZEvMpP.js} +2 -2
  218. package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js.map → StreamMessageDetail-BwZEvMpP.js.map} +1 -1
  219. package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js → SwimlaneTimeline-BDVQEaMw.js} +2 -2
  220. package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js.map → SwimlaneTimeline-BDVQEaMw.js.map} +1 -1
  221. package/dashboard/dist/assets/{TagInput-S7UuVT_M.js → TagInput-DjPUDp2M.js} +2 -2
  222. package/dashboard/dist/assets/{TagInput-S7UuVT_M.js.map → TagInput-DjPUDp2M.js.map} +1 -1
  223. package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js → TaskDetailPage-BOlv3iGB.js} +2 -2
  224. package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js.map → TaskDetailPage-BOlv3iGB.js.map} +1 -1
  225. package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js → TaskQueuePill-D-4Ynf3K.js} +2 -2
  226. package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js.map → TaskQueuePill-D-4Ynf3K.js.map} +1 -1
  227. package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js → TasksListPage-e2teY0bD.js} +2 -2
  228. package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js.map → TasksListPage-e2teY0bD.js.map} +1 -1
  229. package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js → TimeAgo-Cvkpf_b3.js} +2 -2
  230. package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js.map → TimeAgo-Cvkpf_b3.js.map} +1 -1
  231. package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js → TimestampCell-B3btAV0N.js} +2 -2
  232. package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js.map → TimestampCell-B3btAV0N.js.map} +1 -1
  233. package/dashboard/dist/assets/{ToolPill-D40uLM_v.js → ToolPill-GsKQ80CO.js} +2 -2
  234. package/dashboard/dist/assets/{ToolPill-D40uLM_v.js.map → ToolPill-GsKQ80CO.js.map} +1 -1
  235. package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js → ToolTestPanel-B03nebR7.js} +2 -2
  236. package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js.map → ToolTestPanel-B03nebR7.js.map} +1 -1
  237. package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js → TopicDetailPage-DBRWne3O.js} +3 -3
  238. package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js.map → TopicDetailPage-DBRWne3O.js.map} +1 -1
  239. package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js → TopicsPage-CVe2M9HD.js} +2 -2
  240. package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js.map → TopicsPage-CVe2M9HD.js.map} +1 -1
  241. package/dashboard/dist/assets/{UserName-DQFjuoib.js → UserName-B_q_qp6V.js} +2 -2
  242. package/dashboard/dist/assets/{UserName-DQFjuoib.js.map → UserName-B_q_qp6V.js.map} +1 -1
  243. package/dashboard/dist/assets/WorkflowExecutionPage-Bh_dr9tM.js +2 -0
  244. package/dashboard/dist/assets/{WorkflowExecutionPage-Di08wCbs.js.map → WorkflowExecutionPage-Bh_dr9tM.js.map} +1 -1
  245. package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js → WorkflowPill-D7244fKp.js} +2 -2
  246. package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js.map → WorkflowPill-D7244fKp.js.map} +1 -1
  247. package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js → WorkflowsDashboard-DA6Mj7qH.js} +2 -2
  248. package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js.map → WorkflowsDashboard-DA6Mj7qH.js.map} +1 -1
  249. package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js → WorkflowsOverview-B1kBLj-a.js} +2 -2
  250. package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js.map → WorkflowsOverview-B1kBLj-a.js.map} +1 -1
  251. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js → YamlWorkflowDetailPage-6GJM8QIX.js} +8 -8
  252. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js.map → YamlWorkflowDetailPage-6GJM8QIX.js.map} +1 -1
  253. package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js → YamlWorkflowsPage-Bu811C7f.js} +2 -2
  254. package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js.map → YamlWorkflowsPage-Bu811C7f.js.map} +1 -1
  255. package/dashboard/dist/assets/{agents-PuftRTB2.js → agents-MPk_GnYz.js} +2 -2
  256. package/dashboard/dist/assets/{agents-PuftRTB2.js.map → agents-MPk_GnYz.js.map} +1 -1
  257. package/dashboard/dist/assets/{bots-BmEiPAWY.js → bots-2RihE2Tc.js} +2 -2
  258. package/dashboard/dist/assets/{bots-BmEiPAWY.js.map → bots-2RihE2Tc.js.map} +1 -1
  259. package/dashboard/dist/assets/{capabilities-CRii4Soa.js → capabilities-CC4iwJ1P.js} +2 -2
  260. package/dashboard/dist/assets/{capabilities-CRii4Soa.js.map → capabilities-CC4iwJ1P.js.map} +1 -1
  261. package/dashboard/dist/assets/{controlplane-DO_czaYo.js → controlplane-Bmkic8BH.js} +2 -2
  262. package/dashboard/dist/assets/{controlplane-DO_czaYo.js.map → controlplane-Bmkic8BH.js.map} +1 -1
  263. package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js → escalation-columns-B0lhUUrQ.js} +2 -2
  264. package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js.map → escalation-columns-B0lhUUrQ.js.map} +1 -1
  265. package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js → escalation-items-7WFpPo46.js} +2 -2
  266. package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js.map → escalation-items-7WFpPo46.js.map} +1 -1
  267. package/dashboard/dist/assets/index-B9uv-euR.css +1 -0
  268. package/dashboard/dist/assets/{index-DhSCCpqM.js → index-B_XV1rwu.js} +2 -2
  269. package/dashboard/dist/assets/{index-DhSCCpqM.js.map → index-B_XV1rwu.js.map} +1 -1
  270. package/dashboard/dist/assets/{index-Cx8xb-oU.js → index-C2CLfGwL.js} +2 -2
  271. package/dashboard/dist/assets/{index-Cx8xb-oU.js.map → index-C2CLfGwL.js.map} +1 -1
  272. package/dashboard/dist/assets/{index-Cga5IW3D.js → index-C3AeFihz.js} +2 -2
  273. package/dashboard/dist/assets/{index-Cga5IW3D.js.map → index-C3AeFihz.js.map} +1 -1
  274. package/dashboard/dist/assets/{index-DiaRlFYI.js → index-CBri8fYM.js} +2 -2
  275. package/dashboard/dist/assets/{index-DiaRlFYI.js.map → index-CBri8fYM.js.map} +1 -1
  276. package/dashboard/dist/assets/{index-CL_1VpGb.js → index-CRWsB7ZC.js} +2 -2
  277. package/dashboard/dist/assets/{index-CL_1VpGb.js.map → index-CRWsB7ZC.js.map} +1 -1
  278. package/dashboard/dist/assets/{index-XntldBd0.js → index-CTOv3G7a.js} +2 -2
  279. package/dashboard/dist/assets/{index-XntldBd0.js.map → index-CTOv3G7a.js.map} +1 -1
  280. package/dashboard/dist/assets/{index-CfP2nKRc.js → index-CcArGkzI.js} +3 -3
  281. package/dashboard/dist/assets/{index-CfP2nKRc.js.map → index-CcArGkzI.js.map} +1 -1
  282. package/dashboard/dist/assets/{index-Dz6R8-Dw.js → index-CkMHS-hG.js} +25 -25
  283. package/dashboard/dist/assets/index-CkMHS-hG.js.map +1 -0
  284. package/dashboard/dist/assets/index-CmsmwCyv.js +2 -0
  285. package/dashboard/dist/assets/{index-4YaDUcKd.js.map → index-CmsmwCyv.js.map} +1 -1
  286. package/dashboard/dist/assets/{index-2SM2_onB.js → index-CvJsvqIc.js} +2 -2
  287. package/dashboard/dist/assets/{index-2SM2_onB.js.map → index-CvJsvqIc.js.map} +1 -1
  288. package/dashboard/dist/assets/{index-Rwqrflm-.js → index-D-ilRyfy.js} +2 -2
  289. package/dashboard/dist/assets/{index-Rwqrflm-.js.map → index-D-ilRyfy.js.map} +1 -1
  290. package/dashboard/dist/assets/{index-CZ7A3AcD.js → index-DSUtfDXx.js} +2 -2
  291. package/dashboard/dist/assets/{index-CZ7A3AcD.js.map → index-DSUtfDXx.js.map} +1 -1
  292. package/dashboard/dist/assets/{index-jL2K6us4.js → index-Da6ycKyf.js} +2 -2
  293. package/dashboard/dist/assets/{index-jL2K6us4.js.map → index-Da6ycKyf.js.map} +1 -1
  294. package/dashboard/dist/assets/{knowledge-CeUqGPuo.js → knowledge-Bpbg20DC.js} +2 -2
  295. package/dashboard/dist/assets/{knowledge-CeUqGPuo.js.map → knowledge-Bpbg20DC.js.map} +1 -1
  296. package/dashboard/dist/assets/machines-BqOZZU-3.js +2 -0
  297. package/dashboard/dist/assets/machines-BqOZZU-3.js.map +1 -0
  298. package/dashboard/dist/assets/{mcp-Cx96NTeD.js → mcp-CmcUXYce.js} +2 -2
  299. package/dashboard/dist/assets/{mcp-Cx96NTeD.js.map → mcp-CmcUXYce.js.map} +1 -1
  300. package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js → mcp-query-C8buQxN9.js} +2 -2
  301. package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js.map → mcp-query-C8buQxN9.js.map} +1 -1
  302. package/dashboard/dist/assets/{personas--4kjwyOw.js → personas-C2n5oDmY.js} +2 -2
  303. package/dashboard/dist/assets/{personas--4kjwyOw.js.map → personas-C2n5oDmY.js.map} +1 -1
  304. package/dashboard/dist/assets/{pipelines-PgkwvG7f.js → pipelines-RKpSkFz7.js} +2 -2
  305. package/dashboard/dist/assets/{pipelines-PgkwvG7f.js.map → pipelines-RKpSkFz7.js.map} +1 -1
  306. package/dashboard/dist/assets/{tasks-CcYxdBa3.js → tasks-Dab4hExW.js} +2 -2
  307. package/dashboard/dist/assets/{tasks-CcYxdBa3.js.map → tasks-Dab4hExW.js.map} +1 -1
  308. package/dashboard/dist/assets/{topics-_lik7cNY.js → topics-FTMNP7r3.js} +2 -2
  309. package/dashboard/dist/assets/{topics-_lik7cNY.js.map → topics-FTMNP7r3.js.map} +1 -1
  310. package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js → useDebouncedValue-B_1u1YIk.js} +2 -2
  311. package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js.map → useDebouncedValue-B_1u1YIk.js.map} +1 -1
  312. package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js → useNamespace-HUeAI7Qb.js} +2 -2
  313. package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js.map → useNamespace-HUeAI7Qb.js.map} +1 -1
  314. package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js → useYamlActivityEvents-Cax54qHH.js} +2 -2
  315. package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js.map → useYamlActivityEvents-Cax54qHH.js.map} +1 -1
  316. package/dashboard/dist/assets/{validate-FlXCBBT6.js → validate-DxOaV7QS.js} +2 -2
  317. package/dashboard/dist/assets/{validate-FlXCBBT6.js.map → validate-DxOaV7QS.js.map} +1 -1
  318. package/dashboard/dist/assets/{vendor-icons-DUYcKTjP.js → vendor-icons-fxBvvHBi.js} +187 -182
  319. package/dashboard/dist/assets/vendor-icons-fxBvvHBi.js.map +1 -0
  320. package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js → yaml-workflows-BgY1XHJx.js} +2 -2
  321. package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js.map → yaml-workflows-BgY1XHJx.js.map} +1 -1
  322. package/dashboard/dist/index.html +3 -3
  323. package/docs/architecture.md +1 -0
  324. package/docs/code-owned-configuration.md +6 -0
  325. package/docs/dashboard.md +1 -0
  326. package/docs/events.md +34 -1
  327. package/docs/machines.md +93 -16
  328. package/docs/mcp.md +19 -0
  329. package/package.json +1 -1
  330. package/dashboard/dist/assets/AgentsPage-C9UuUKhr.js +0 -2
  331. package/dashboard/dist/assets/AvailableEscalationsPage-DrvfXz70.js +0 -2
  332. package/dashboard/dist/assets/FilterBar-BygWrnB1.js +0 -2
  333. package/dashboard/dist/assets/FilterBar-BygWrnB1.js.map +0 -1
  334. package/dashboard/dist/assets/McpRunDetailPage-80fQn9iX.js +0 -2
  335. package/dashboard/dist/assets/WorkflowExecutionPage-Di08wCbs.js +0 -2
  336. package/dashboard/dist/assets/index-4YaDUcKd.js +0 -2
  337. package/dashboard/dist/assets/index-CnU7Jjz3.css +0 -1
  338. package/dashboard/dist/assets/index-Dz6R8-Dw.js.map +0 -1
  339. package/dashboard/dist/assets/vendor-icons-DUYcKTjP.js.map +0 -1
@@ -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';
@@ -30,6 +30,10 @@ function fromMachine(reply) {
30
30
  function took(reply) {
31
31
  return reply?.status === protocol_1.REPLY_STATUS.ACCEPTED || reply?.status === protocol_1.REPLY_STATUS.COMPLETED;
32
32
  }
33
+ /** The reply's structured code for a resolution, when it carried one. */
34
+ function withCode(reply) {
35
+ return reply.code ? { code: reply.code } : {};
36
+ }
33
37
  /** Most command ids whose sends are counted; the oldest are forgotten first. */
34
38
  const SENT_REMEMBERED = 10_000;
35
39
  /** Ends a dispatch or command still running when the gateway stops; the next leader takes it up from the row. */
@@ -65,9 +69,13 @@ class Dispatcher {
65
69
  /** False when the codec has no message for the command. `since` is when the command's row was created. */
66
70
  async publish(machineId, op, cmdId, args, since) {
67
71
  this.live();
68
- const wires = this.d.codec.encode((0, registration_1.identFor)(this.d.state, this.d.line, machineId), { cmdId, op, args, ...this.countSend(cmdId, since) });
69
- for (const wire of wires)
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) {
70
76
  await this.d.bus.publish(wire.topic, wire.payload);
77
+ this.d.wire?.command(ident, command, wire);
78
+ }
71
79
  return wires.length > 0;
72
80
  }
73
81
  /** Publish and wait for the reply, asking again with the same id; null when none came. */
@@ -111,7 +119,7 @@ class Dispatcher {
111
119
  await (0, promises_1.setTimeout)(expiresAt - Date.now() + 1, undefined, { signal: this.stopping.signal }).catch(() => undefined);
112
120
  this.live();
113
121
  const outcome = reply
114
- ? { 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) }
115
123
  : { accepted: false, machineId: a.machineId, op: a.op, status: contracts_1.COMMAND_STATUS.NO_REPLY, reason: `no reply after ${this.d.dispatchAttempts} attempts` };
116
124
  const context = { row: a.rowId, machine: a.machineId, op: a.op, status: outcome.status, reason: outcome.reason };
117
125
  if (outcome.accepted)
@@ -158,7 +166,7 @@ class Dispatcher {
158
166
  row.dispatch = state_1.DISPATCH_STATE.REFUSED;
159
167
  const unanswered = `${a.machineId} sent no reply after ${this.d.dispatchAttempts} attempts`;
160
168
  const resolution = refused
161
- ? { 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) }
162
170
  : { received: false, errorCode: contracts_1.HANDOFF_ERROR.NO_REPLY, detail: held ? `${unanswered} and does not hold the job` : `${unanswered}; its state is unknown` };
163
171
  log.warn(log_1.GATEWAY_LOG.DISPATCH_REFUSED, { row: a.rowId, machine: a.machineId, ...resolution });
164
172
  const ended = await lt.resolve(fromMachine(refused ?? null) ? a.machineId : actions_1.CONTROLLER, a.rowId, resolution);
@@ -2,17 +2,20 @@
2
2
  * Runs the planner's actions: escalation verbs through LineEscalations,
3
3
  * dispatches and commands through the Dispatcher, alarm and machine rows,
4
4
  * and the offline debounce. A verb that fails for real throws, so the message that
5
- * caused it is delivered again.
5
+ * caused it is delivered again. What ran comes back as wire actions, for the
6
+ * record of the message that caused it.
6
7
  */
7
8
  import { type LineDef } from '../../../lib/machines/line';
8
9
  import { type LineCodec } from '../../../lib/machines/protocol';
9
10
  import type { MachineBus } from '../../../lib/machines/transport';
11
+ import type { WireAction } from '../../../types/machines-view';
10
12
  import { type Action } from './actions';
11
13
  import type { AddressBook } from './address-book';
12
14
  import { type LineEscalations } from './escalations';
13
15
  import { type GatewayLog } from './log';
14
16
  import type { ReplyWaiter } from './reply-waiter';
15
17
  import { type GatewayState } from './state';
18
+ import { type WireRecorder } from './wire';
16
19
  export interface ExecutorDeps {
17
20
  bus: MachineBus;
18
21
  lt: LineEscalations;
@@ -26,19 +29,25 @@ export interface ExecutorDeps {
26
29
  log: GatewayLog;
27
30
  /** Where learned addresses are kept (registration.ts). */
28
31
  addresses: AddressBook;
32
+ /** Records each command sent, for the line's wire view. */
33
+ wire?: Pick<WireRecorder, 'command'>;
29
34
  }
30
35
  export declare class Executor {
31
36
  private readonly d;
32
37
  private inflight;
33
38
  private quietPending;
34
39
  private timers;
40
+ private stopped;
35
41
  private readonly dispatcher;
36
42
  constructor(d: ExecutorDeps);
37
43
  /** Dispatches and commands run detached so one slow reply never holds up the feed. */
38
- apply(actions: Action[]): Promise<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
53
  /**
@@ -3,7 +3,8 @@
3
3
  * Runs the planner's actions: escalation verbs through LineEscalations,
4
4
  * dispatches and commands through the Dispatcher, alarm and machine rows,
5
5
  * and the offline debounce. A verb that fails for real throws, so the message that
6
- * caused it is delivered again.
6
+ * caused it is delivered again. What ran comes back as wire actions, for the
7
+ * record of the message that caused it.
7
8
  */
8
9
  Object.defineProperty(exports, "__esModule", { value: true });
9
10
  exports.Executor = void 0;
@@ -16,18 +17,28 @@ const log_1 = require("./log");
16
17
  const dispatcher_1 = require("./dispatcher");
17
18
  const plan_shared_1 = require("./plan-shared");
18
19
  const state_1 = require("./state");
20
+ const wire_1 = require("./wire");
19
21
  const NOT_FOUND = 404;
20
22
  const CONFLICT = 409;
23
+ /** A verb's outcome as the wire records it: done, already done, or refused by Long Tail. */
24
+ function outcomeOf(verb, rowId, result) {
25
+ const refused = result.outcome === escalations_1.VERB_OUTCOME.INVALID || result.status === NOT_FOUND || result.status === CONFLICT;
26
+ if (refused)
27
+ return { verb: 'refuse', rowId, detail: `${verb}: ${result.detail ?? result.outcome}` };
28
+ return { verb, rowId, ...(result.outcome === escalations_1.VERB_OUTCOME.ALREADY ? { detail: result.detail ?? 'already ended' } : {}) };
29
+ }
21
30
  class Executor {
22
31
  constructor(d) {
23
32
  this.d = d;
24
33
  this.inflight = new Set();
25
34
  this.quietPending = new Set();
26
35
  this.timers = new Set();
36
+ this.stopped = false;
27
37
  this.dispatcher = new dispatcher_1.Dispatcher(d);
28
38
  }
29
39
  /** Dispatches and commands run detached so one slow reply never holds up the feed. */
30
40
  async apply(actions) {
41
+ const done = [];
31
42
  for (const action of actions) {
32
43
  if (action.kind === 'dispatch')
33
44
  this.track(this.dispatcher.dispatch(action));
@@ -35,22 +46,33 @@ class Executor {
35
46
  this.track(this.dispatcher.command(action));
36
47
  else if (action.kind === 'control')
37
48
  this.track(this.dispatcher.control(action));
38
- else
39
- await this.run(action);
49
+ else {
50
+ done.push(...await this.run(action));
51
+ continue;
52
+ }
53
+ done.push((0, wire_1.plannedAction)(action));
40
54
  }
55
+ return done;
41
56
  }
42
57
  /** Resolves when every detached dispatch has finished. */
43
58
  async idle() {
44
59
  while (this.inflight.size)
45
60
  await Promise.all([...this.inflight]);
46
61
  }
62
+ /** Work still running sends nothing more and raises no row; the next leader takes it up from the message or the row. */
47
63
  stop() {
64
+ this.stopped = true;
48
65
  for (const t of this.timers)
49
66
  clearTimeout(t);
50
67
  this.timers.clear();
51
68
  this.dispatcher.stop();
52
69
  this.d.replies.cancelAll();
53
70
  }
71
+ /** A row raised after stop() would be raised again by the next leader, so the message is nak'd instead. */
72
+ live() {
73
+ if (this.stopped)
74
+ throw new dispatcher_1.GatewayStopped();
75
+ }
54
76
  track(work) {
55
77
  const tracked = work.catch((err) => {
56
78
  if (!(err instanceof dispatcher_1.GatewayStopped))
@@ -62,37 +84,45 @@ class Executor {
62
84
  async run(a) {
63
85
  const { lt, state, replies } = this.d;
64
86
  switch (a.kind) {
65
- case 'claim':
66
- return this.check(a, await lt.claim(a.as, a.rowId));
87
+ case 'claim': {
88
+ const result = await lt.claim(a.as, a.rowId);
89
+ this.check(a, result);
90
+ return [outcomeOf('claim', a.rowId, result)];
91
+ }
67
92
  case 'accumulate':
68
93
  return this.accumulate(a);
69
- case 'resolve':
70
- this.check(a, await lt.resolve(a.as, a.rowId, a.payload));
94
+ case 'resolve': {
95
+ const result = await lt.resolve(a.as, a.rowId, a.payload);
96
+ this.check(a, result);
71
97
  state.close(a.rowId);
72
- return;
98
+ return [outcomeOf('resolve', a.rowId, result)];
99
+ }
73
100
  case 'createAlarmRow':
74
- return this.createAlarmRow(a);
101
+ return [{ verb: 'create-row', rowId: await this.createAlarmRow(a), detail: `${a.row.type} ${a.alarmId} at ${a.machineId}` }];
75
102
  case 'createRow': {
103
+ this.live();
76
104
  const { id } = await lt.create(actions_1.CONTROLLER, a.row);
77
105
  this.d.log.info(log_1.GATEWAY_LOG.VIOLATION_ROW, { row: id, type: a.row.type });
78
- return;
106
+ return [{ verb: 'create-row', rowId: id, detail: a.row.type }];
79
107
  }
80
108
  case 'watchOffline':
81
- return this.watchOffline(a.machineId);
109
+ this.watchOffline(a.machineId);
110
+ return [(0, wire_1.plannedAction)(a)];
82
111
  case 'settleReply':
83
- if (!replies.settle({ cmdId: a.cmdId, status: a.status, reason: a.reason }))
84
- await this.lateReply(a);
85
- return;
112
+ if (replies.settle({ cmdId: a.cmdId, status: a.status, reason: a.reason, ...(a.code ? { code: a.code } : {}) }))
113
+ return [(0, wire_1.plannedAction)(a)];
114
+ return [{ verb: 'ack', detail: `late ${a.status} ${a.cmdId}` }, ...await this.lateReply(a)];
86
115
  case 'settleSnapshot':
87
116
  replies.settleSnapshot(a.machineId, new Set(a.jobIds));
88
- return;
117
+ return [(0, wire_1.plannedAction)(a)];
89
118
  case 'bindAddress':
90
119
  await this.d.addresses.bind(a.machineId, a.address);
91
120
  state.bindAddress(a.machineId, a.address);
92
121
  this.d.log.info(log_1.GATEWAY_LOG.ADDRESS_BOUND, { machine: a.machineId, address: a.address, ...(a.by ? { approvedBy: a.by } : {}) });
93
- return;
122
+ return [{ verb: 'ack', detail: `bound ${a.machineId} to ${a.address}` }];
94
123
  case 'refuseBinding':
95
124
  this.d.log.warn(log_1.GATEWAY_LOG.ADDRESS_REFUSED, { machine: a.machineId, address: a.address, reason: a.reason });
125
+ return [(0, wire_1.plannedAction)(a)];
96
126
  }
97
127
  }
98
128
  /**
@@ -106,18 +136,20 @@ class Executor {
106
136
  const into = state.rowForDispatch(a.cmdId);
107
137
  const m = into?.toMachine;
108
138
  if (!into || !m)
109
- return;
139
+ return [];
110
140
  const context = { row: into.id, machine: m, cmdId: a.cmdId, reason: a.reason };
111
- if (a.status === protocol_1.REPLY_STATUS.COMPLETED)
112
- return log.info(log_1.GATEWAY_LOG.DISPATCH_READY, context);
141
+ if (a.status === protocol_1.REPLY_STATUS.COMPLETED) {
142
+ log.info(log_1.GATEWAY_LOG.DISPATCH_READY, context);
143
+ return [];
144
+ }
113
145
  if (a.status !== protocol_1.REPLY_STATUS.FAILED)
114
- return;
146
+ return [];
115
147
  const row = into.ended ? onwardRow(state, into, m) : into;
116
148
  log.warn(log_1.GATEWAY_LOG.DISPATCH_FAILED, { ...context, ...(into.ended ? { onward: row?.id ?? null } : {}) });
117
149
  if (!row)
118
- return;
119
- await this.apply((0, plan_shared_1.failHandoff)(state, row, m, {
120
- received: false, errorCode: contracts_1.HANDOFF_ERROR.DISPATCH_FAILED, detail: `${m} could not prepare the job: ${a.reason}`,
150
+ return [];
151
+ return this.apply((0, plan_shared_1.failHandoff)(state, row, m, {
152
+ received: false, errorCode: contracts_1.HANDOFF_ERROR.DISPATCH_FAILED, detail: `${m} could not prepare the job: ${a.reason}`, ...(a.code ? { code: a.code } : {}),
121
153
  }));
122
154
  }
123
155
  /** Add the item; when the row then holds every key the action waits for, resolve it. */
@@ -125,15 +157,18 @@ class Executor {
125
157
  const { lt, state } = this.d;
126
158
  const result = await lt.accumulate(a.as, a.rowId, a.itemKey, a.payload, a.metadata);
127
159
  this.check(a, result);
160
+ const added = { ...outcomeOf('accumulate', a.rowId, result), itemKey: a.itemKey };
128
161
  if (!a.complete || result.outcome === escalations_1.VERB_OUTCOME.INVALID)
129
- return;
162
+ return [added];
130
163
  const held = new Set(result.itemKeys ?? await lt.itemKeys(a.rowId));
131
164
  if (!a.complete.keys.every((k) => held.has(k)))
132
- return;
165
+ return [added];
133
166
  if (a.complete.then)
134
- return this.apply(a.complete.then);
135
- this.check(a, await lt.resolve(a.as, a.rowId, a.complete.payload ?? {}));
167
+ return [added, ...await this.apply(a.complete.then)];
168
+ const resolved = await lt.resolve(a.as, a.rowId, a.complete.payload ?? {});
169
+ this.check(a, resolved);
136
170
  state.close(a.rowId);
171
+ return [added, outcomeOf('resolve', a.rowId, resolved)];
137
172
  }
138
173
  check(a, result) {
139
174
  const rowId = a.rowId;
@@ -148,17 +183,19 @@ class Executor {
148
183
  }
149
184
  }
150
185
  async createAlarmRow(a) {
186
+ this.live();
151
187
  const { id } = await this.d.lt.create(actions_1.CONTROLLER, { ...a.row, role: (0, line_1.operatorRole)(this.d.line) });
152
188
  this.d.log.info(log_1.GATEWAY_LOG.ALARM_ROW, { row: id, machine: a.machineId, alarm: a.alarmId });
153
189
  const track = this.d.state.alarms.get(this.d.state.alarmKey(a.machineId, a.alarmId));
154
190
  const raisedAt = a.row.metadata?.raisedAt;
155
191
  if (track && (!track.raisedAt || !raisedAt || track.raisedAt === raisedAt)) {
156
192
  track.rowId = id;
157
- return;
193
+ return id;
158
194
  }
159
195
  // Cleared at the machine, or raised again, while the row was being created.
160
196
  const note = track ? `${a.machineId} raised ${a.alarmId} again; this one ended` : `cleared at ${a.machineId}`;
161
197
  await this.d.lt.resolve(actions_1.CONTROLLER, id, { decision: contracts_1.DECISION.CLEARED, note });
198
+ return id;
162
199
  }
163
200
  /** Raise a quiet row for each connected machine silent longer than `quietMs`. */
164
201
  checkQuiet(machineIds, quietMs) {
@@ -172,6 +209,7 @@ class Executor {
172
209
  }
173
210
  }
174
211
  async raiseQuiet(machineId, silentMs) {
212
+ this.live();
175
213
  const { id } = await this.d.lt.create(actions_1.CONTROLLER, {
176
214
  type: contracts_1.ROW_TYPE.MACHINE_QUIET, role: (0, line_1.operatorRole)(this.d.line), priority: 2,
177
215
  description: `${machineId} is connected but has sent nothing for ${Math.round(silentMs / 1000)} s`,
@@ -194,11 +232,12 @@ class Executor {
194
232
  link.watching = false;
195
233
  if (link.online || link.rowId)
196
234
  return;
235
+ this.live();
197
236
  const since = new Date(link.since).toISOString();
198
237
  const { id } = await this.d.lt.create(actions_1.CONTROLLER, {
199
238
  type: contracts_1.ROW_TYPE.MACHINE_OFFLINE, role: (0, line_1.operatorRole)(this.d.line), priority: 2,
200
239
  description: `${machineId} has been offline since ${since}`,
201
- metadata: { siteId: this.d.line.siteId, lineId: this.d.line.lineId, machineId, offlineSince: since },
240
+ metadata: { siteId: this.d.line.siteId, lineId: this.d.line.lineId, machineId, offlineSince: since, ...(link.reason ? { reason: link.reason } : {}) },
202
241
  });
203
242
  this.d.log.info(log_1.GATEWAY_LOG.OFFLINE_ROW, { row: id, machine: machineId });
204
243
  if (!link.online)
@@ -3,15 +3,18 @@
3
3
  * reads escalation events (a new handoff row means "dispatch"), reads every
4
4
  * machine message on the line (a receipt means "resolve"), and performs the
5
5
  * verbs a person would, as the machine. Neither side knows about the other.
6
+ * Every message read or sent is recorded on the wire (wire.ts).
6
7
  */
7
8
  import { type HandoffRowAdapter } from '../rows';
8
9
  import { type AddressBook } from './address-book';
9
10
  import type { LineDef } from '../../../lib/machines/line';
10
11
  import { type LineCodec } from '../../../lib/machines/protocol';
11
- import { type EscalationFeed, type MachineBus } from '../../../lib/machines/transport';
12
+ import { type EscalationFeed, type InboundMessage, type MachineBus } from '../../../lib/machines/transport';
13
+ import type { InspectResult } from '../../../types/machines-view';
12
14
  import type { LineEscalations } from './escalations';
13
15
  import { type GatewayLog } from './log';
14
16
  import { GatewayState } from './state';
17
+ import { type WireSink } from './wire';
15
18
  export interface GatewaySettings {
16
19
  topicRoot: string;
17
20
  replyTimeoutMs: number;
@@ -27,6 +30,8 @@ export interface GatewaySettings {
27
30
  lifecycle?: boolean;
28
31
  /** With lifecycle notes, progress is noted each time it crosses this many percent; 0 notes none. */
29
32
  progressStep?: number;
33
+ /** Record telemetry messages on the wire too; off unless set. */
34
+ wireTelemetry?: boolean;
30
35
  }
31
36
  export interface GatewayDeps {
32
37
  bus: MachineBus;
@@ -41,6 +46,8 @@ export interface GatewayDeps {
41
46
  codec?: LineCodec;
42
47
  /** Where a line that learns addresses keeps them; in memory by default. */
43
48
  addresses?: AddressBook;
49
+ /** Where wire records go; Long Tail's events by default. */
50
+ wire?: WireSink;
44
51
  }
45
52
  export declare class MachineGateway {
46
53
  private readonly deps;
@@ -52,14 +59,22 @@ export declare class MachineGateway {
52
59
  private readonly log;
53
60
  private readonly addresses;
54
61
  private readonly admission;
62
+ private readonly wire;
55
63
  private quietTimer?;
56
64
  constructor(deps: GatewayDeps);
57
65
  start(): Promise<void>;
66
+ /**
67
+ * Hand the line over cleanly: nothing new is raised or sent, a message
68
+ * still being handled is nak'd for the next leader if it would make a row,
69
+ * receipts for what was applied go out, then the sessions close.
70
+ */
58
71
  stop(): Promise<void>;
59
72
  /** Machines that report only changes are asked for their full state once the gateway listens. */
60
73
  private askEveryMachine;
61
74
  /** Resolves when no dispatch is in flight (tests). */
62
75
  idle(): Promise<void>;
76
+ /** A dry run of one message on a copy of the state: nothing is applied (inspect.ts). */
77
+ inspect(msg: Pick<InboundMessage, 'topic' | 'payload' | 'retained'>): InspectResult;
63
78
  /**
64
79
  * On taking the line: open handoff and command rows (a dispatch or command
65
80
  * interrupted by a restart is sent again with the same cmdId), the gateway's