@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
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The line registry: every line this deployment controls, in Postgres, so
3
+ * every replica contends for the same lines and the Lines index reads one
4
+ * list. Lines come from code (start({ machines })) and from the API; the
5
+ * configSource rules decide who wins at boot, the version says what changed.
6
+ */
7
+ import { type LineDef } from '../../lib/machines/line';
8
+ import type { LineHealth, LineSource, SiteSummary } from '../../types/machines-view';
9
+ import { LINE_ORDER, LINE_SOURCE } from './registry-sql';
10
+ export { LINE_SOURCE };
11
+ /** A registry row. */
12
+ export interface LineRecord {
13
+ siteId: string;
14
+ lineId: string;
15
+ definition: LineDef;
16
+ source: LineSource;
17
+ version: number;
18
+ enabled: boolean;
19
+ createdAt: string;
20
+ updatedAt: string;
21
+ }
22
+ /** A registry row with its pending rows counted. */
23
+ export interface LineRecordWithHealth extends LineRecord {
24
+ health: LineHealth;
25
+ }
26
+ export interface LineListQuery {
27
+ q?: string;
28
+ site?: string;
29
+ /** One line by id, with `site`. */
30
+ line?: string;
31
+ attention?: boolean;
32
+ sort?: keyof typeof LINE_ORDER;
33
+ limit?: number;
34
+ offset?: number;
35
+ }
36
+ export interface LineListPage {
37
+ lines: LineRecordWithHealth[];
38
+ total: number;
39
+ limit: number;
40
+ offset: number;
41
+ }
42
+ /** What boot did with each code line, and the code lines it no longer declares. */
43
+ export interface LineApplyReport {
44
+ applied: string[];
45
+ unchanged: string[];
46
+ dbOwned: string[];
47
+ orphans: string[];
48
+ }
49
+ /** A write that named a version the row no longer has. */
50
+ export declare class LineVersionConflict extends Error {
51
+ readonly siteId: string;
52
+ readonly lineId: string;
53
+ readonly expected: number;
54
+ constructor(siteId: string, lineId: string, expected: number);
55
+ }
56
+ export declare const DEFAULT_LINE_PAGE = 50;
57
+ export declare const MAX_LINE_PAGE = 200;
58
+ /** The index's search text: everything a person might type to find the line. */
59
+ export declare function searchTextOf(line: LineDef): string;
60
+ /** Declare a line through the API: insert, or replace and advance its version. */
61
+ export declare function declareApiLine(def: LineDef, expectedVersion?: number): Promise<LineRecord>;
62
+ /**
63
+ * Apply one code line. Db-owned: insert if absent, otherwise leave the row
64
+ * and log drift. Code-owned: write when the definition differs, once.
65
+ */
66
+ export declare function applyCodeLine(def: LineDef, codeOwned: boolean): Promise<'applied' | 'unchanged' | 'db-owned'>;
67
+ /** Boot: apply every code line and report, naming code lines the registry still holds that code no longer declares. */
68
+ export declare function applyDeclaredLines(lines: LineDef[], codeOwned: boolean): Promise<LineApplyReport>;
69
+ export declare function getLine(siteId: string, lineId: string): Promise<LineRecord | null>;
70
+ export declare function deleteLine(siteId: string, lineId: string): Promise<LineRecord | null>;
71
+ /** Every enabled line, code and API alike: what a replica contends for. */
72
+ export declare function listEnabledLines(): Promise<LineRecord[]>;
73
+ /** One page of the index, searched and filtered in SQL, with each line's pending rows counted. */
74
+ export declare function listLines(query?: LineListQuery): Promise<LineListPage>;
75
+ /** One line with its pending rows counted, or null. */
76
+ export declare function getLineWithHealth(siteId: string, lineId: string): Promise<LineRecordWithHealth | null>;
77
+ export declare function listSites(): Promise<SiteSummary[]>;
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ /**
3
+ * The line registry: every line this deployment controls, in Postgres, so
4
+ * every replica contends for the same lines and the Lines index reads one
5
+ * list. Lines come from code (start({ machines })) and from the API; the
6
+ * configSource rules decide who wins at boot, the version says what changed.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.MAX_LINE_PAGE = exports.DEFAULT_LINE_PAGE = exports.LineVersionConflict = exports.LINE_SOURCE = void 0;
10
+ exports.searchTextOf = searchTextOf;
11
+ exports.declareApiLine = declareApiLine;
12
+ exports.applyCodeLine = applyCodeLine;
13
+ exports.applyDeclaredLines = applyDeclaredLines;
14
+ exports.getLine = getLine;
15
+ exports.deleteLine = deleteLine;
16
+ exports.listEnabledLines = listEnabledLines;
17
+ exports.listLines = listLines;
18
+ exports.getLineWithHealth = getLineWithHealth;
19
+ exports.listSites = listSites;
20
+ const node_util_1 = require("node:util");
21
+ const db_1 = require("../../lib/db");
22
+ const logger_1 = require("../../lib/logger");
23
+ const line_1 = require("../../lib/machines/line");
24
+ const registry_sql_1 = require("./registry-sql");
25
+ Object.defineProperty(exports, "LINE_SOURCE", { enumerable: true, get: function () { return registry_sql_1.LINE_SOURCE; } });
26
+ /** A write that named a version the row no longer has. */
27
+ class LineVersionConflict extends Error {
28
+ constructor(siteId, lineId, expected) {
29
+ super(`line ${siteId}/${lineId} is not at version ${expected}`);
30
+ this.siteId = siteId;
31
+ this.lineId = lineId;
32
+ this.expected = expected;
33
+ this.name = 'LineVersionConflict';
34
+ }
35
+ }
36
+ exports.LineVersionConflict = LineVersionConflict;
37
+ exports.DEFAULT_LINE_PAGE = 50;
38
+ exports.MAX_LINE_PAGE = 200;
39
+ const LOG = '[lt-machines]';
40
+ /** The index's search text: everything a person might type to find the line. */
41
+ function searchTextOf(line) {
42
+ const words = [line.siteId, line.lineId];
43
+ for (const m of line.machines)
44
+ words.push(m.machineId, m.process, (0, line_1.machineRole)(m), m.address ?? '');
45
+ return [...new Set(words.filter(Boolean).map((w) => w.toLowerCase()))].join(' ');
46
+ }
47
+ function toRecord(row) {
48
+ return {
49
+ siteId: row.site_id, lineId: row.line_id, definition: row.definition, source: row.source,
50
+ version: row.version, enabled: row.enabled,
51
+ createdAt: new Date(row.created_at).toISOString(), updatedAt: new Date(row.updated_at).toISOString(),
52
+ };
53
+ }
54
+ function toHealth(row) {
55
+ const machines = Array.isArray(row.definition?.machines) ? row.definition.machines.length : 0;
56
+ return {
57
+ machines, offline: row.offline, quiet: row.quiet, alarms: row.alarms, people: row.people,
58
+ handoff: row.handoff, command: row.command, attention: row.attention === true,
59
+ };
60
+ }
61
+ function keyOf(siteId, lineId) {
62
+ return `${siteId}/${lineId}`;
63
+ }
64
+ /** A LIKE pattern that matches the text anywhere, with the person's wildcards taken literally. */
65
+ function likePattern(q) {
66
+ return `%${q.trim().toLowerCase().replace(/[\\%_]/g, (c) => `\\${c}`)}%`;
67
+ }
68
+ /** Declare a line through the API: insert, or replace and advance its version. */
69
+ async function declareApiLine(def, expectedVersion) {
70
+ const line = (0, line_1.validateLine)(def);
71
+ const { rows } = await (0, db_1.getPool)().query(registry_sql_1.UPSERT_API_LINE, [
72
+ line.siteId, line.lineId, JSON.stringify(line), searchTextOf(line), expectedVersion ?? null,
73
+ ]);
74
+ if (!rows.length)
75
+ throw new LineVersionConflict(line.siteId, line.lineId, expectedVersion);
76
+ return toRecord(rows[0]);
77
+ }
78
+ /**
79
+ * Apply one code line. Db-owned: insert if absent, otherwise leave the row
80
+ * and log drift. Code-owned: write when the definition differs, once.
81
+ */
82
+ async function applyCodeLine(def, codeOwned) {
83
+ const line = (0, line_1.validateLine)(def);
84
+ const params = [line.siteId, line.lineId, JSON.stringify(line), searchTextOf(line)];
85
+ const { rows } = await (0, db_1.getPool)().query(codeOwned ? registry_sql_1.APPLY_CODE_LINE : registry_sql_1.SEED_CODE_LINE, params);
86
+ if (rows.length)
87
+ return 'applied';
88
+ if (codeOwned)
89
+ return 'unchanged';
90
+ const existing = await getLine(line.siteId, line.lineId);
91
+ if (existing && !(0, node_util_1.isDeepStrictEqual)(existing.definition, line)) {
92
+ logger_1.loggerRegistry.warn(`${LOG} line ${keyOf(line.siteId, line.lineId)} differs from its declaration; the registry row stands (db-owned)`);
93
+ }
94
+ return 'db-owned';
95
+ }
96
+ /** Boot: apply every code line and report, naming code lines the registry still holds that code no longer declares. */
97
+ async function applyDeclaredLines(lines, codeOwned) {
98
+ const report = { applied: [], unchanged: [], dbOwned: [], orphans: [] };
99
+ const declared = new Set();
100
+ for (const line of lines) {
101
+ const key = keyOf(line.siteId, line.lineId);
102
+ declared.add(key);
103
+ const outcome = await applyCodeLine(line, codeOwned);
104
+ if (outcome === 'applied')
105
+ report.applied.push(key);
106
+ else if (outcome === 'unchanged')
107
+ report.unchanged.push(key);
108
+ else
109
+ report.dbOwned.push(key);
110
+ }
111
+ const { rows } = await (0, db_1.getPool)().query(registry_sql_1.LIST_CODE_LINES);
112
+ report.orphans = rows.map((r) => keyOf(r.site_id, r.line_id)).filter((k) => !declared.has(k));
113
+ const counts = `applied ${report.applied.length}, unchanged ${report.unchanged.length}, db-owned ${report.dbOwned.length}`;
114
+ if (report.orphans.length)
115
+ logger_1.loggerRegistry.warn(`${LOG} lines: ${counts}, declared in code before and not now: [${report.orphans.join(', ')}]`);
116
+ else
117
+ logger_1.loggerRegistry.info(`${LOG} lines: ${counts}`);
118
+ return report;
119
+ }
120
+ async function getLine(siteId, lineId) {
121
+ const { rows } = await (0, db_1.getPool)().query(registry_sql_1.GET_LINE, [siteId, lineId]);
122
+ return rows.length ? toRecord(rows[0]) : null;
123
+ }
124
+ async function deleteLine(siteId, lineId) {
125
+ const { rows } = await (0, db_1.getPool)().query(registry_sql_1.DELETE_LINE, [siteId, lineId]);
126
+ return rows.length ? toRecord(rows[0]) : null;
127
+ }
128
+ /** Every enabled line, code and API alike: what a replica contends for. */
129
+ async function listEnabledLines() {
130
+ const { rows } = await (0, db_1.getPool)().query(registry_sql_1.LIST_ENABLED_LINES);
131
+ return rows.map(toRecord);
132
+ }
133
+ /** One page of the index, searched and filtered in SQL, with each line's pending rows counted. */
134
+ async function listLines(query = {}) {
135
+ const limit = Math.min(Math.max(1, Math.floor(query.limit ?? exports.DEFAULT_LINE_PAGE)), exports.MAX_LINE_PAGE);
136
+ const offset = Math.max(0, Math.floor(query.offset ?? 0));
137
+ const order = registry_sql_1.LINE_ORDER[query.sort ?? 'attention'];
138
+ if (!order)
139
+ throw new Error(`sort must be one of ${Object.keys(registry_sql_1.LINE_ORDER).join(', ')}`);
140
+ const { rows } = await (0, db_1.getPool)().query((0, registry_sql_1.listLinesSql)(order), [
141
+ [...registry_sql_1.HEALTH_ROW_TYPES], query.q?.trim() ? likePattern(query.q) : null, query.site || null,
142
+ query.attention ?? null, limit, offset, query.line || null,
143
+ ]);
144
+ return {
145
+ lines: rows.map((r) => ({ ...toRecord(r), health: toHealth(r) })),
146
+ total: rows.length ? Number(rows[0].total) : 0,
147
+ limit, offset,
148
+ };
149
+ }
150
+ /** One line with its pending rows counted, or null. */
151
+ async function getLineWithHealth(siteId, lineId) {
152
+ const page = await listLines({ site: siteId, line: lineId, limit: 1 });
153
+ return page.lines[0] ?? null;
154
+ }
155
+ async function listSites() {
156
+ const { rows } = await (0, db_1.getPool)().query(registry_sql_1.LIST_SITES, [[...registry_sql_1.HEALTH_ROW_TYPES]]);
157
+ return rows.map((r) => ({ siteId: r.site_id, lines: r.lines, attention: r.attention }));
158
+ }
@@ -15,16 +15,39 @@ const str = (v) => (v === undefined || v === null || v === '' ? null : String(v)
15
15
  function paramsOf(v) {
16
16
  return v && typeof v === 'object' && !Array.isArray(v) ? v : undefined;
17
17
  }
18
+ /** Named references with string values; other values are dropped, and an empty set is no refs. */
19
+ function refsOf(v) {
20
+ if (!v || typeof v !== 'object' || Array.isArray(v))
21
+ return undefined;
22
+ const refs = Object.fromEntries(Object.entries(v).filter((e) => typeof e[1] === 'string'));
23
+ return Object.keys(refs).length ? refs : undefined;
24
+ }
18
25
  function artifactOf(v) {
19
- return v && typeof v.url === 'string' && v.url && typeof v.sha256 === 'string' && v.sha256 ? { url: v.url, sha256: v.sha256 } : undefined;
26
+ if (!v || typeof v.url !== 'string' || !v.url || typeof v.sha256 !== 'string' || !v.sha256)
27
+ return undefined;
28
+ return {
29
+ url: v.url, sha256: v.sha256,
30
+ ...(typeof v.id === 'string' && v.id ? { id: v.id } : {}),
31
+ ...(typeof v.contentType === 'string' && v.contentType ? { contentType: v.contentType } : {}),
32
+ ...(Number.isInteger(v.sizeBytes) && v.sizeBytes >= 0 ? { sizeBytes: v.sizeBytes } : {}),
33
+ };
34
+ }
35
+ function artifactsOf(v) {
36
+ const list = Array.isArray(v) ? v.map(artifactOf).filter((a) => !!a) : [];
37
+ return list.length ? list : undefined;
20
38
  }
21
39
  function unitsOf(v) {
22
40
  if (!Array.isArray(v))
23
41
  return [];
24
42
  return v.filter((u) => u && u.unitId).map((u) => {
25
43
  const artifact = artifactOf(u.artifact);
44
+ const artifacts = artifactsOf(u.artifacts);
26
45
  const parameters = paramsOf(u.parameters);
27
- return { unitId: String(u.unitId), carrierId: str(u.carrierId), ...(artifact ? { artifact } : {}), ...(parameters ? { parameters } : {}) };
46
+ const refs = refsOf(u.refs);
47
+ return {
48
+ unitId: String(u.unitId), carrierId: str(u.carrierId),
49
+ ...(artifact ? { artifact } : {}), ...(artifacts ? { artifacts } : {}), ...(parameters ? { parameters } : {}), ...(refs ? { refs } : {}),
50
+ };
28
51
  });
29
52
  }
30
53
  /** Read standard handoff facets; null when the line, job or units are missing. */
@@ -48,6 +71,7 @@ function readHandoffFacets(md = {}) {
48
71
  artifactSha256: str(md.artifactSha256),
49
72
  attempt: Number(md.attempt ?? 1),
50
73
  ...(paramsOf(md.parameters) ? { parameters: paramsOf(md.parameters) } : {}),
74
+ ...(refsOf(md.refs) ? { refs: refsOf(md.refs) } : {}),
51
75
  };
52
76
  }
53
77
  exports.standardRows = {
@@ -6,12 +6,19 @@
6
6
  import { type MachineLineConfig } from './config';
7
7
  import { type LineDef } from '../../lib/machines/line';
8
8
  import { type LineCodec } from '../../lib/machines/protocol';
9
+ import { messagingRegistry } from '../../lib/messaging';
9
10
  import type { CallbackEventAdapter } from '../../lib/events/callback';
10
11
  import type { EscalationFeed, MachineBus, MachineLink } from '../../lib/machines/transport/delivery';
11
12
  /** The codec for a line when the host supplies none: the line protocol under MACHINE_TOPIC_ROOT. */
12
13
  export declare function defaultCodec(config: MachineLineConfig, line?: LineDef): LineCodec;
13
- /** The gateway's view of every machine on the line. */
14
- export declare function createMachineBus(config: MachineLineConfig, line: LineDef, codec?: LineCodec): MachineBus;
14
+ /** What the stream bus needs from Long Tail's messaging; the registry by default. */
15
+ export type LineMessaging = Pick<typeof messagingRegistry, 'streams' | 'pubsub'>;
16
+ /**
17
+ * The gateway's view of every machine on the line. With `nats`, events are read
18
+ * from Long Tail's messaging streams; MACHINE_SITE_NATS_URL instead names a NATS
19
+ * server of the site's own, which the bus connects to itself.
20
+ */
21
+ export declare function createMachineBus(config: MachineLineConfig, line: LineDef, codec?: LineCodec, messaging?: LineMessaging): MachineBus;
15
22
  /** Long Tail's escalation events for the gateway; `in-process` needs the running instance's callback adapter. */
16
23
  export declare function createEscalationFeed(config: MachineLineConfig, line: LineDef, callbacks?: CallbackEventAdapter): EscalationFeed;
17
24
  /** One MQTT link per simulated machine; machines speak MQTT in every networked mode. */
@@ -15,8 +15,11 @@ const protocol_1 = require("../../lib/machines/protocol");
15
15
  const mqtt_bus_1 = require("../../lib/machines/transport/mqtt-bus");
16
16
  const mqtt_link_1 = require("../../lib/machines/transport/mqtt-link");
17
17
  const nats_bus_1 = require("../../lib/machines/transport/nats-bus");
18
+ const stream_bus_1 = require("../../lib/machines/transport/stream-bus");
18
19
  const callback_feed_1 = require("../../lib/machines/transport/callback-feed");
19
20
  const nats_feed_1 = require("../../lib/machines/transport/nats-feed");
21
+ const pubsub_feed_1 = require("../../lib/machines/transport/pubsub-feed");
22
+ const messaging_1 = require("../../lib/messaging");
20
23
  const IN_PROCESS_ONLY = 'lives inside one process; build MemoryMachineBus and MemoryEscalationFeed directly';
21
24
  function mqttOf(config) {
22
25
  if (!config.mqtt)
@@ -27,14 +30,20 @@ function mqttOf(config) {
27
30
  function defaultCodec(config, line) {
28
31
  return (0, protocol_1.genericCodec)({ root: config.topicRoot, line });
29
32
  }
30
- /** The gateway's view of every machine on the line. */
31
- function createMachineBus(config, line, codec = defaultCodec(config, line)) {
33
+ /**
34
+ * The gateway's view of every machine on the line. With `nats`, events are read
35
+ * from Long Tail's messaging streams; MACHINE_SITE_NATS_URL instead names a NATS
36
+ * server of the site's own, which the bus connects to itself.
37
+ */
38
+ function createMachineBus(config, line, codec = defaultCodec(config, line), messaging = messaging_1.messagingRegistry) {
32
39
  switch (config.transport) {
33
- case config_1.MACHINE_TRANSPORT.NATS:
34
- return new nats_bus_1.NatsMachineBus({
35
- natsUrl: config.siteNatsUrl, user: config.siteNatsUser, password: config.siteNatsPassword,
36
- mqtt: mqttOf(config), controllerId: (0, line_1.controllerId)(line), siteId: line.siteId, lineId: line.lineId, codec,
37
- });
40
+ case config_1.MACHINE_TRANSPORT.NATS: {
41
+ const where = { mqtt: mqttOf(config), controllerId: (0, line_1.controllerId)(line), siteId: line.siteId, lineId: line.lineId, codec };
42
+ if (config.siteNatsUrl) {
43
+ return new nats_bus_1.NatsMachineBus({ natsUrl: config.siteNatsUrl, user: config.siteNatsUser, password: config.siteNatsPassword, ...where });
44
+ }
45
+ return new stream_bus_1.StreamMachineBus({ streams: messaging.streams, pubsub: messaging.pubsub, ...where });
46
+ }
38
47
  case config_1.MACHINE_TRANSPORT.MQTT:
39
48
  return new mqtt_bus_1.MqttMachineBus(mqttOf(config), (0, line_1.controllerId)(line), (0, protocol_1.lineFilter)(codec.root, line.siteId, line.lineId));
40
49
  default:
@@ -49,6 +58,10 @@ function createEscalationFeed(config, line, callbacks) {
49
58
  throw new Error('MACHINE_ESCALATION_FEED=in-process runs inside start({ machines })');
50
59
  return new callback_feed_1.CallbackEscalationFeed(callbacks);
51
60
  case config_1.ESCALATION_FEED.CORE:
61
+ if (messaging_1.messagingRegistry.hasProvider)
62
+ return new pubsub_feed_1.PubSubEscalationFeed(messaging_1.messagingRegistry.pubsub);
63
+ if (!config.ltNatsUrl)
64
+ throw new Error('MACHINE_ESCALATION_FEED=core needs Long Tail messaging (LT_MESSAGING=nats) or NATS_URL');
52
65
  return new nats_feed_1.CoreEscalationFeed({ natsUrl: config.ltNatsUrl, token: config.ltNatsToken });
53
66
  default:
54
67
  throw new Error(`MACHINE_ESCALATION_FEED=${config.feed} ${IN_PROCESS_ONLY}`);
@@ -3,13 +3,17 @@
3
3
  * controls, one replica leads (an advisory lock), makes sure the line's bot
4
4
  * accounts exist, and runs the gateway: escalation events in, machine
5
5
  * messages in, verbs performed in process as each machine. Workflows never
6
- * see any of it; their rows are resolved the way a form resolves them.
6
+ * see any of it; their rows are resolved the way a form resolves them. The
7
+ * surface also describes its lines for the dashboard: every replica lists
8
+ * them, and the leader of a line projects it.
7
9
  */
8
10
  import type { CallbackEventAdapter } from '../../lib/events/callback';
9
- import type { LineDef } from '../../lib/machines/line';
11
+ import { type LineDef } from '../../lib/machines/line';
12
+ import { type LineCodec } from '../../lib/machines/protocol';
13
+ import type { InboundMessage } from '../../lib/machines/transport';
14
+ import type { InspectResult, LineSummary, LineView } from '../../types/machines-view';
10
15
  import { type MachineLineConfig } from './config';
11
16
  import { type GatewayLog } from './gateway/log';
12
- import type { LineCodec } from '../../lib/machines/protocol';
13
17
  import type { HandoffRowAdapter } from './rows';
14
18
  type Env = Record<string, string | undefined>;
15
19
  export interface MachineSurfaceOptions {
@@ -21,13 +25,49 @@ export interface MachineSurfaceOptions {
21
25
  codec?: LineCodec;
22
26
  rows?: HandoffRowAdapter;
23
27
  }
28
+ /** A message to dry-run against a line. */
29
+ export type WireProbe = Pick<InboundMessage, 'topic' | 'payload' | 'retained'>;
30
+ /** What settings and the API read of the surface. */
31
+ export interface LineSurface {
32
+ /** Every declared line, on every replica. */
33
+ describeLines(): LineSummary[];
34
+ /** The line as its leader sees it; null when this replica is not leading it, or the line is not declared. */
35
+ describeLine(siteId: string, lineId: string): LineView | null;
36
+ /** A dry run of one message; null when this replica is not leading the line. */
37
+ inspect(siteId: string, lineId: string, probe: WireProbe): InspectResult | null;
38
+ /** The declared line, or undefined. */
39
+ findLine(siteId: string, lineId: string): LineDef | undefined;
40
+ /** The ops a machine-command row on this line may ask for. */
41
+ commandOps(siteId: string, lineId: string): string[];
42
+ /** Run a line on this replica: started, replaced when its definition changed, or unchanged. */
43
+ declare(line: LineDef): Promise<DeclareOutcome>;
44
+ /** Stop running a line on this replica; false when it was not running. */
45
+ retire(siteId: string, lineId: string): Promise<boolean>;
46
+ }
47
+ export type DeclareOutcome = 'started' | 'replaced' | 'unchanged';
24
48
  /** Inside Long Tail the gateway reads escalation events in process. */
25
49
  export declare function surfaceConfig(env: Env): MachineLineConfig;
26
- export declare class MachineSurface {
50
+ /** The line as every replica can describe it: its machines, roles, declared addresses and the codec's own ops. */
51
+ export declare function summarizeLine(line: LineDef, codec: Pick<LineCodec, 'rowOps'>): LineSummary;
52
+ /** The ops a machine-command row may ask for: the control ops, a snapshot, and the codec's own. */
53
+ export declare function commandOpsOf(codec: Pick<LineCodec, 'rowOps'>): string[];
54
+ export declare class MachineSurface implements LineSurface {
55
+ private readonly config;
56
+ private readonly opts;
57
+ private readonly log;
27
58
  private readonly runs;
28
59
  private constructor();
29
- /** Validate the configuration, then contend for every line in the background. */
60
+ /** Validate the configuration, then contend for every line in the background. The registry may add lines later. */
30
61
  static start(opts: MachineSurfaceOptions): MachineSurface;
31
62
  stop(): Promise<void>;
63
+ declare(line: LineDef): Promise<DeclareOutcome>;
64
+ retire(siteId: string, lineId: string): Promise<boolean>;
65
+ describeLines(): LineSummary[];
66
+ describeLine(siteId: string, lineId: string): LineView | null;
67
+ inspect(siteId: string, lineId: string, probe: WireProbe): InspectResult | null;
68
+ findLine(siteId: string, lineId: string): LineDef | undefined;
69
+ commandOps(siteId: string, lineId: string): string[];
70
+ private begin;
71
+ private run;
32
72
  }
33
73
  export {};
@@ -4,11 +4,18 @@
4
4
  * controls, one replica leads (an advisory lock), makes sure the line's bot
5
5
  * accounts exist, and runs the gateway: escalation events in, machine
6
6
  * messages in, verbs performed in process as each machine. Workflows never
7
- * see any of it; their rows are resolved the way a form resolves them.
7
+ * see any of it; their rows are resolved the way a form resolves them. The
8
+ * surface also describes its lines for the dashboard: every replica lists
9
+ * them, and the leader of a line projects it.
8
10
  */
9
11
  Object.defineProperty(exports, "__esModule", { value: true });
10
12
  exports.MachineSurface = void 0;
11
13
  exports.surfaceConfig = surfaceConfig;
14
+ exports.summarizeLine = summarizeLine;
15
+ exports.commandOpsOf = commandOpsOf;
16
+ const node_util_1 = require("node:util");
17
+ const line_1 = require("../../lib/machines/line");
18
+ const protocol_1 = require("../../lib/machines/protocol");
12
19
  const config_1 = require("./config");
13
20
  const api_escalations_1 = require("./gateway/api-escalations");
14
21
  const gateway_1 = require("./gateway/gateway");
@@ -24,38 +31,70 @@ function surfaceConfig(env) {
24
31
  }
25
32
  return (0, config_1.loadMachineLineConfig)({ ...env, MACHINE_ESCALATION_FEED: env.MACHINE_ESCALATION_FEED ?? config_1.ESCALATION_FEED.IN_PROCESS });
26
33
  }
34
+ /** The line as every replica can describe it: its machines, roles, declared addresses and the codec's own ops. */
35
+ function summarizeLine(line, codec) {
36
+ const rowOps = (0, protocol_1.declaredRowOps)(codec);
37
+ return {
38
+ siteId: line.siteId, lineId: line.lineId,
39
+ machines: line.machines.map((m) => {
40
+ const learned = (0, line_1.learnsAddress)(line, m.machineId);
41
+ return {
42
+ machineId: m.machineId, process: m.process, role: (0, line_1.machineRole)(m),
43
+ address: learned ? null : m.address ?? m.machineId, addressing: learned ? 'learned' : 'declared',
44
+ ...(rowOps.length ? { rowOps } : {}),
45
+ };
46
+ }),
47
+ };
48
+ }
49
+ /** The ops a machine-command row may ask for: the control ops, a snapshot, and the codec's own. */
50
+ function commandOpsOf(codec) {
51
+ return [...new Set([...protocol_1.CONTROL_OPS, protocol_1.OP.SNAPSHOT, ...(0, protocol_1.declaredRowOps)(codec)])];
52
+ }
27
53
  class LineRun {
28
54
  constructor(line, config, opts, log) {
29
55
  this.line = line;
30
56
  this.config = config;
31
57
  this.opts = opts;
32
58
  this.log = log;
59
+ this.ready = false;
60
+ this.stopped = false;
33
61
  this.leadership = new leadership_1.LineLeadership(`lt-machine-line:${line.siteId}/${line.lineId}`);
62
+ this.codec = opts.codec ?? (0, select_1.defaultCodec)(config, line);
34
63
  }
35
64
  start() {
36
65
  const where = { site: this.line.siteId, line: this.line.lineId };
37
66
  this.log.info(log_1.GATEWAY_LOG.STANDBY, where);
38
- this.leadership.run(() => this.lead(), async (err) => {
67
+ this.leadership.run(() => (this.leading = this.lead()), async (err) => {
39
68
  this.log.warn(log_1.GATEWAY_LOG.LEADERSHIP_LOST, { ...where, error: err.message });
69
+ this.ready = false;
40
70
  await this.gateway?.stop();
41
71
  this.gateway = undefined;
42
72
  }).catch((err) => this.log.error(log_1.GATEWAY_LOG.START_FAILED, { ...where, error: err.message }));
43
73
  }
74
+ /** A gateway still starting finishes first, so none is left running after stop. */
44
75
  async stop() {
76
+ this.stopped = true;
77
+ this.ready = false;
78
+ await this.leading?.catch(() => undefined);
45
79
  await this.gateway?.stop();
46
80
  await this.leadership.stop();
47
81
  }
82
+ /** The gateway, once it leads the line. */
83
+ leader() {
84
+ return this.ready ? this.gateway : undefined;
85
+ }
48
86
  async lead() {
49
87
  // 1. Identities, 2. gateway on the line's bus and feed, 3. reconcile and consume (gateway.start)
50
88
  const ids = await (0, identities_1.ensureLineBots)(this.line);
89
+ if (this.stopped)
90
+ return;
51
91
  const userFor = (as) => {
52
92
  const id = ids.get(as);
53
93
  if (!id)
54
94
  throw new Error(`no bot for "${as}" on ${this.line.siteId}/${this.line.lineId}`);
55
95
  return id;
56
96
  };
57
- const { config, line } = this;
58
- const codec = this.opts.codec ?? (0, select_1.defaultCodec)(config, line);
97
+ const { config, line, codec } = this;
59
98
  this.gateway = new gateway_1.MachineGateway({
60
99
  bus: (0, select_1.createMachineBus)(config, line, codec),
61
100
  codec,
@@ -68,31 +107,78 @@ class LineRun {
68
107
  settings: {
69
108
  topicRoot: config.topicRoot, replyTimeoutMs: config.replyTimeoutMs, dispatchAttempts: config.dispatchAttempts,
70
109
  offlineDebounceMs: config.offlineDebounceMs, dispatchTtlMs: config.dispatchTtlMs, quietMs: config.quietMs,
71
- receiptDelayMs: config.receiptDelayMs,
110
+ receiptDelayMs: config.receiptDelayMs, lifecycle: config.lifecycle, progressStep: config.progressStep, wireTelemetry: config.wireTelemetry,
72
111
  },
73
112
  });
74
113
  await this.gateway.start();
114
+ this.ready = true;
75
115
  this.log.info(log_1.GATEWAY_LOG.LEADING, { site: line.siteId, line: line.lineId });
76
116
  }
77
117
  }
78
118
  class MachineSurface {
79
- constructor(runs) {
80
- this.runs = runs;
119
+ constructor(config, opts, log) {
120
+ this.config = config;
121
+ this.opts = opts;
122
+ this.log = log;
123
+ this.runs = new Map();
81
124
  }
82
- /** Validate the configuration, then contend for every line in the background. */
125
+ /** Validate the configuration, then contend for every line in the background. The registry may add lines later. */
83
126
  static start(opts) {
84
- if (!opts.lines.length)
85
- throw new Error('start({ machines }) needs at least one line');
86
127
  const config = surfaceConfig(opts.env ?? process.env);
87
- const log = opts.log ?? log_1.consoleLog;
88
- const runs = opts.lines.map((line) => new LineRun(line, config, opts, log));
89
- for (const run of runs)
90
- run.start();
91
- return new MachineSurface(runs);
128
+ const surface = new MachineSurface(config, opts, opts.log ?? log_1.consoleLog);
129
+ for (const line of opts.lines)
130
+ surface.begin(line);
131
+ return surface;
92
132
  }
93
133
  async stop() {
94
- for (const run of this.runs)
134
+ for (const run of this.runs.values())
95
135
  await run.stop();
136
+ this.runs.clear();
137
+ }
138
+ async declare(line) {
139
+ const current = this.run(line.siteId, line.lineId);
140
+ if (current && (0, node_util_1.isDeepStrictEqual)(current.line, line))
141
+ return 'unchanged';
142
+ if (current)
143
+ await current.stop();
144
+ this.begin(line);
145
+ return current ? 'replaced' : 'started';
146
+ }
147
+ async retire(siteId, lineId) {
148
+ const current = this.run(siteId, lineId);
149
+ if (!current)
150
+ return false;
151
+ this.runs.delete(keyOf(siteId, lineId));
152
+ await current.stop();
153
+ return true;
154
+ }
155
+ describeLines() {
156
+ return [...this.runs.values()].map((run) => summarizeLine(run.line, run.codec));
157
+ }
158
+ describeLine(siteId, lineId) {
159
+ const gateway = this.run(siteId, lineId)?.leader();
160
+ return gateway ? gateway.state.project(this.findLine(siteId, lineId)) : null;
161
+ }
162
+ inspect(siteId, lineId, probe) {
163
+ return this.run(siteId, lineId)?.leader()?.inspect(probe) ?? null;
164
+ }
165
+ findLine(siteId, lineId) {
166
+ return this.run(siteId, lineId)?.line;
167
+ }
168
+ commandOps(siteId, lineId) {
169
+ const run = this.run(siteId, lineId);
170
+ return run ? commandOpsOf(run.codec) : [];
171
+ }
172
+ begin(line) {
173
+ const run = new LineRun(line, this.config, this.opts, (0, log_1.composeLogs)(this.log, (0, log_1.eventsLog)(line)));
174
+ this.runs.set(keyOf(line.siteId, line.lineId), run);
175
+ run.start();
176
+ }
177
+ run(siteId, lineId) {
178
+ return this.runs.get(keyOf(siteId, lineId));
96
179
  }
97
180
  }
98
181
  exports.MachineSurface = MachineSurface;
182
+ function keyOf(siteId, lineId) {
183
+ return `${siteId}/${lineId}`;
184
+ }
@@ -26,6 +26,7 @@ export interface FakeRow {
26
26
  resolved_by?: string;
27
27
  envelope?: string;
28
28
  escalation_payload?: string;
29
+ created_at?: string;
29
30
  }
30
31
  export interface Call {
31
32
  verb: string;
@@ -43,7 +43,7 @@ class FakeLongTail {
43
43
  });
44
44
  }
45
45
  add(input) {
46
- const row = { ...input, id: `e${++this.seq}`, status: 'pending', items: [] };
46
+ const row = { ...input, id: `e${++this.seq}`, status: 'pending', items: [], created_at: new Date().toISOString() };
47
47
  this.rows.set(row.id, row);
48
48
  this.emit(row, 'created');
49
49
  return row;
@@ -132,7 +132,7 @@ class FakeLongTail {
132
132
  return null;
133
133
  return {
134
134
  id: row.id, type: row.type, subtype: row.subtype, role: row.role, status: row.status,
135
- assigned_to: row.assigned_to ?? null, resolved_by: row.resolved_by ?? null, metadata: { ...row.metadata },
135
+ assigned_to: row.assigned_to ?? null, resolved_by: row.resolved_by ?? null, metadata: { ...row.metadata }, created_at: row.created_at ?? null,
136
136
  // Stored serialized, as Long Tail returns it.
137
137
  resolver_payload: row.resolver_payload ? JSON.stringify(row.resolver_payload) : null,
138
138
  };
@@ -140,7 +140,10 @@ class FakeLongTail {
140
140
  async listOpen(query) {
141
141
  return [...this.rows.values()]
142
142
  .filter((r) => r.status === 'pending' && (!query.type || r.type === query.type) && (!query.role || r.role === query.role))
143
- .map((r) => ({ id: r.id, type: r.type, subtype: r.subtype, role: r.role, status: r.status, assigned_to: r.assigned_to ?? null, metadata: r.metadata }));
143
+ .map((r) => ({
144
+ id: r.id, type: r.type, subtype: r.subtype, role: r.role, status: r.status, assigned_to: r.assigned_to ?? null, metadata: r.metadata,
145
+ created_at: r.created_at ?? null,
146
+ }));
144
147
  }
145
148
  ofType(type) {
146
149
  return [...this.rows.values()].filter((r) => r.type === type);