@hotmeshio/long-tail 0.27.0 → 0.28.1

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 (386) hide show
  1. package/README.md +9 -2
  2. package/build/api/files.d.ts +5 -0
  3. package/build/api/files.js +19 -2
  4. package/build/api/knowledge.d.ts +3 -1
  5. package/build/api/settings.d.ts +4 -1
  6. package/build/api/settings.js +7 -1
  7. package/build/index.js +9 -4
  8. package/build/lib/db/config-lock.d.ts +10 -0
  9. package/build/lib/db/config-lock.js +28 -0
  10. package/build/lib/db/schemas/041_machine_lines.sql +26 -0
  11. package/build/lib/db/schemas/042_knowledge_edition_labels.sql +9 -0
  12. package/build/lib/events/browser-view.js +8 -2
  13. package/build/lib/events/publish.d.ts +33 -0
  14. package/build/lib/events/publish.js +52 -1
  15. package/build/lib/machines/line.d.ts +7 -1
  16. package/build/lib/machines/line.js +25 -2
  17. package/build/lib/machines/protocol/codec.d.ts +14 -0
  18. package/build/lib/machines/protocol/codec.js +10 -1
  19. package/build/lib/machines/protocol/constants.d.ts +1 -1
  20. package/build/lib/machines/protocol/constants.js +1 -1
  21. package/build/lib/machines/protocol/contract.d.ts +2 -0
  22. package/build/lib/machines/protocol/contract.js +13 -8
  23. package/build/lib/machines/site/mosquitto-conf.d.ts +9 -4
  24. package/build/lib/machines/site/mosquitto-conf.js +32 -22
  25. package/build/lib/machines/site/site-conf.d.ts +13 -3
  26. package/build/lib/machines/site/site-conf.js +31 -8
  27. package/build/lib/machines/transport/callback-feed.d.ts +1 -0
  28. package/build/lib/machines/transport/callback-feed.js +4 -1
  29. package/build/lib/machines/transport/memory.d.ts +2 -0
  30. package/build/lib/machines/transport/memory.js +6 -0
  31. package/build/lib/machines/transport/mqtt-bus.d.ts +2 -0
  32. package/build/lib/machines/transport/mqtt-bus.js +4 -0
  33. package/build/lib/machines/transport/nats-bus.d.ts +3 -0
  34. package/build/lib/machines/transport/nats-bus.js +3 -0
  35. package/build/lib/machines/transport/nats-feed.d.ts +1 -0
  36. package/build/lib/machines/transport/nats-feed.js +4 -1
  37. package/build/lib/machines/transport/pubsub-feed.d.ts +1 -0
  38. package/build/lib/machines/transport/pubsub-feed.js +4 -1
  39. package/build/lib/machines/transport/stream-bus.d.ts +7 -1
  40. package/build/lib/machines/transport/stream-bus.js +17 -5
  41. package/build/lib/machines/transport/streams.d.ts +10 -2
  42. package/build/lib/machines/transport/streams.js +32 -5
  43. package/build/lib/messaging/memory.js +3 -0
  44. package/build/lib/messaging/nats/streams.d.ts +3 -0
  45. package/build/lib/messaging/nats/streams.js +16 -0
  46. package/build/lib/storage/local.d.ts +2 -0
  47. package/build/lib/storage/local.js +3 -0
  48. package/build/lib/storage/s3.d.ts +3 -2
  49. package/build/lib/storage/s3.js +6 -1
  50. package/build/lib/storage/types.d.ts +7 -1
  51. package/build/modules/machines.d.ts +8 -0
  52. package/build/modules/machines.js +16 -0
  53. package/build/routes/file-browser.js +3 -1
  54. package/build/routes/index.js +2 -0
  55. package/build/routes/knowledge.js +6 -5
  56. package/build/routes/machines.d.ts +2 -0
  57. package/build/routes/machines.js +253 -0
  58. package/build/services/knowledge/index.d.ts +4 -2
  59. package/build/services/knowledge/index.js +8 -2
  60. package/build/services/knowledge/lookup-cache.d.ts +8 -0
  61. package/build/services/knowledge/lookup-cache.js +30 -3
  62. package/build/services/knowledge/lookup-refs.js +1 -1
  63. package/build/services/knowledge/sql.d.ts +4 -2
  64. package/build/services/knowledge/sql.js +8 -3
  65. package/build/services/machines/commands.d.ts +5 -5
  66. package/build/services/machines/commands.js +3 -2
  67. package/build/services/machines/config.d.ts +4 -1
  68. package/build/services/machines/config.js +2 -1
  69. package/build/services/machines/contracts.d.ts +28 -0
  70. package/build/services/machines/contracts.js +15 -1
  71. package/build/services/machines/forms.d.ts +26 -1
  72. package/build/services/machines/forms.js +17 -1
  73. package/build/services/machines/gateway/actions.d.ts +14 -1
  74. package/build/services/machines/gateway/admission.d.ts +30 -4
  75. package/build/services/machines/gateway/admission.js +76 -14
  76. package/build/services/machines/gateway/api-escalations.js +4 -0
  77. package/build/services/machines/gateway/dispatcher.d.ts +12 -4
  78. package/build/services/machines/gateway/dispatcher.js +53 -17
  79. package/build/services/machines/gateway/executor.d.ts +13 -2
  80. package/build/services/machines/gateway/executor.js +84 -29
  81. package/build/services/machines/gateway/gateway.d.ts +21 -1
  82. package/build/services/machines/gateway/gateway.js +65 -25
  83. package/build/services/machines/gateway/index.d.ts +3 -0
  84. package/build/services/machines/gateway/index.js +3 -0
  85. package/build/services/machines/gateway/inspect.d.ts +17 -0
  86. package/build/services/machines/gateway/inspect.js +68 -0
  87. package/build/services/machines/gateway/log.d.ts +10 -0
  88. package/build/services/machines/gateway/log.js +20 -0
  89. package/build/services/machines/gateway/lt-http.js +11 -2
  90. package/build/services/machines/gateway/pacing.js +2 -1
  91. package/build/services/machines/gateway/plan-escalation.js +8 -3
  92. package/build/services/machines/gateway/plan-machine.js +41 -16
  93. package/build/services/machines/gateway/plan-shared.d.ts +5 -3
  94. package/build/services/machines/gateway/plan-shared.js +6 -4
  95. package/build/services/machines/gateway/project.d.ts +9 -0
  96. package/build/services/machines/gateway/project.js +55 -0
  97. package/build/services/machines/gateway/receipts.d.ts +3 -0
  98. package/build/services/machines/gateway/receipts.js +3 -1
  99. package/build/services/machines/gateway/reconcile.js +3 -3
  100. package/build/services/machines/gateway/registration.js +1 -1
  101. package/build/services/machines/gateway/reply-waiter.d.ts +8 -3
  102. package/build/services/machines/gateway/reply-waiter.js +37 -16
  103. package/build/services/machines/gateway/state.d.ts +53 -4
  104. package/build/services/machines/gateway/state.js +128 -13
  105. package/build/services/machines/gateway/wire-window.d.ts +21 -0
  106. package/build/services/machines/gateway/wire-window.js +61 -0
  107. package/build/services/machines/gateway/wire.d.ts +58 -0
  108. package/build/services/machines/gateway/wire.js +172 -0
  109. package/build/services/machines/index.d.ts +3 -0
  110. package/build/services/machines/index.js +2 -0
  111. package/build/services/machines/line-index.d.ts +16 -0
  112. package/build/services/machines/line-index.js +39 -0
  113. package/build/services/machines/registry-sql.d.ts +31 -0
  114. package/build/services/machines/registry-sql.js +110 -0
  115. package/build/services/machines/registry-sync.d.ts +31 -0
  116. package/build/services/machines/registry-sync.js +81 -0
  117. package/build/services/machines/registry.d.ts +77 -0
  118. package/build/services/machines/registry.js +158 -0
  119. package/build/services/machines/roles.d.ts +5 -4
  120. package/build/services/machines/roles.js +13 -4
  121. package/build/services/machines/rows.js +10 -1
  122. package/build/services/machines/select.d.ts +3 -2
  123. package/build/services/machines/select.js +4 -3
  124. package/build/services/machines/surface.d.ts +54 -5
  125. package/build/services/machines/surface.js +113 -17
  126. package/build/start/apply-report.d.ts +1 -1
  127. package/build/start/apply-report.js +3 -25
  128. package/build/start/index.js +16 -4
  129. package/build/system/activities/knowledge.d.ts +4 -0
  130. package/build/system/activities/knowledge.js +15 -0
  131. package/build/system/activities/sql.d.ts +2 -0
  132. package/build/system/activities/sql.js +6 -1
  133. package/build/system/index.js +13 -0
  134. package/build/system/mcp-servers/admin/schemas.d.ts +22 -22
  135. package/build/system/mcp-servers/human-queue-schemas.d.ts +7 -7
  136. package/build/system/mcp-servers/knowledge.js +4 -2
  137. package/build/system/mcp-servers/machines-schemas.d.ts +35 -0
  138. package/build/system/mcp-servers/machines-schemas.js +35 -0
  139. package/build/system/mcp-servers/machines.d.ts +20 -0
  140. package/build/system/mcp-servers/machines.js +154 -0
  141. package/build/system/seed/tool-manifests-machines.d.ts +2 -0
  142. package/build/system/seed/tool-manifests-machines.js +88 -0
  143. package/build/tsconfig.tsbuildinfo +1 -1
  144. package/build/types/escalation.d.ts +9 -6
  145. package/build/types/escalation.js +8 -2
  146. package/build/types/events.d.ts +6 -1
  147. package/build/types/index.d.ts +1 -0
  148. package/build/types/machines-view.d.ts +175 -0
  149. package/build/types/machines-view.js +7 -0
  150. package/build/types/machines.d.ts +5 -0
  151. package/build/types/messaging.d.ts +2 -0
  152. package/build/types/startup.d.ts +2 -0
  153. package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js → AdminDashboard-Bm7VG65H.js} +2 -2
  154. package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js.map → AdminDashboard-Bm7VG65H.js.map} +1 -1
  155. package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js → AgentConfigPage-aJF7Sdbc.js} +6 -6
  156. package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js.map → AgentConfigPage-aJF7Sdbc.js.map} +1 -1
  157. package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js → AgentDetailPage-GwwghhxT.js} +3 -3
  158. package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js.map → AgentDetailPage-GwwghhxT.js.map} +1 -1
  159. package/dashboard/dist/assets/AgentsPage-DVvCzZyg.js +2 -0
  160. package/dashboard/dist/assets/{AgentsPage-C9UuUKhr.js.map → AgentsPage-DVvCzZyg.js.map} +1 -1
  161. package/dashboard/dist/assets/AvailableEscalationsPage-Cxmcji_K.js +2 -0
  162. package/dashboard/dist/assets/{AvailableEscalationsPage-DrvfXz70.js.map → AvailableEscalationsPage-Cxmcji_K.js.map} +1 -1
  163. package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js → BotPicker-CofRxk4L.js} +2 -2
  164. package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js.map → BotPicker-CofRxk4L.js.map} +1 -1
  165. package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js → BulkAssignModal-BARWuz4L.js} +2 -2
  166. package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js.map → BulkAssignModal-BARWuz4L.js.map} +1 -1
  167. package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js → CapabilitiesPage-BJAWVNEx.js} +2 -2
  168. package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js.map → CapabilitiesPage-BJAWVNEx.js.map} +1 -1
  169. package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js → CollapsibleSection-CtgoaG75.js} +2 -2
  170. package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js.map → CollapsibleSection-CtgoaG75.js.map} +1 -1
  171. package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js → ConfirmDeleteModal-BYXXBWs6.js} +2 -2
  172. package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js.map → ConfirmDeleteModal-BYXXBWs6.js.map} +1 -1
  173. package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js → ConnectedAppsPage-D0JkzWa7.js} +2 -2
  174. package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js.map → ConnectedAppsPage-D0JkzWa7.js.map} +1 -1
  175. package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js → CountdownTimer-BcFxdZYN.js} +2 -2
  176. package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js.map → CountdownTimer-BcFxdZYN.js.map} +1 -1
  177. package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js → CredentialsPage-DPSY20rV.js} +2 -2
  178. package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js.map → CredentialsPage-DPSY20rV.js.map} +1 -1
  179. package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js → CronLabel-Dg_Oew_Y.js} +2 -2
  180. package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js.map → CronLabel-Dg_Oew_Y.js.map} +1 -1
  181. package/dashboard/dist/assets/{DropZone-u1JGfR9G.js → DropZone-Cl_Flb16.js} +2 -2
  182. package/dashboard/dist/assets/{DropZone-u1JGfR9G.js.map → DropZone-Cl_Flb16.js.map} +1 -1
  183. package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js → ElapsedCell-Dm3G5fK2.js} +2 -2
  184. package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js.map → ElapsedCell-Dm3G5fK2.js.map} +1 -1
  185. package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js → EntityTimelinePanel-CrEEP04e.js} +2 -2
  186. package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js.map → EntityTimelinePanel-CrEEP04e.js.map} +1 -1
  187. package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js → EscalationListSchemaPage-wOInXcjs.js} +3 -3
  188. package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js.map → EscalationListSchemaPage-wOInXcjs.js.map} +1 -1
  189. package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js → EscalationSchemaPage-CrIj_g9d.js} +3 -3
  190. package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js.map → EscalationSchemaPage-CrIj_g9d.js.map} +1 -1
  191. package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js → EscalationTimeline-CeAsl5IT.js} +2 -2
  192. package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js.map → EscalationTimeline-CeAsl5IT.js.map} +1 -1
  193. package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js → EscalationTitleSelect-D8qpCYiy.js} +2 -2
  194. package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js.map → EscalationTitleSelect-D8qpCYiy.js.map} +1 -1
  195. package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js → EscalationsOverview-CvaqVPsr.js} +2 -2
  196. package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js.map → EscalationsOverview-CvaqVPsr.js.map} +1 -1
  197. package/dashboard/dist/assets/{EventTable-V4RF_n58.js → EventTable-Be0JuEl6.js} +2 -2
  198. package/dashboard/dist/assets/{EventTable-V4RF_n58.js.map → EventTable-Be0JuEl6.js.map} +1 -1
  199. package/dashboard/dist/assets/FilterBar-BVyAjIgv.js +2 -0
  200. package/dashboard/dist/assets/FilterBar-BVyAjIgv.js.map +1 -0
  201. package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js → GraphInvokePage-D_QigJeD.js} +2 -2
  202. package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js.map → GraphInvokePage-D_QigJeD.js.map} +1 -1
  203. package/dashboard/dist/assets/{HomePage-EjcNxlKx.js → HomePage-C1haeuNy.js} +2 -2
  204. package/dashboard/dist/assets/{HomePage-EjcNxlKx.js.map → HomePage-C1haeuNy.js.map} +1 -1
  205. package/dashboard/dist/assets/LinePage-CWD5pv1g.js +5 -0
  206. package/dashboard/dist/assets/LinePage-CWD5pv1g.js.map +1 -0
  207. package/dashboard/dist/assets/LinesPage-NqChsKcO.js +3 -0
  208. package/dashboard/dist/assets/LinesPage-NqChsKcO.js.map +1 -0
  209. package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js → ListToolbar-BZCNrTh6.js} +2 -2
  210. package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js.map → ListToolbar-BZCNrTh6.js.map} +1 -1
  211. package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js → McpOverview-yJTYnh1z.js} +2 -2
  212. package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js.map → McpOverview-yJTYnh1z.js.map} +1 -1
  213. package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js → McpQueryDetailPage-ChuLpJ4u.js} +3 -3
  214. package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js.map → McpQueryDetailPage-ChuLpJ4u.js.map} +1 -1
  215. package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js → McpQueryPage-9S-v9soF.js} +2 -2
  216. package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js.map → McpQueryPage-9S-v9soF.js.map} +1 -1
  217. package/dashboard/dist/assets/McpRunDetailPage-BhrcfxD5.js +2 -0
  218. package/dashboard/dist/assets/{McpRunDetailPage-80fQn9iX.js.map → McpRunDetailPage-BhrcfxD5.js.map} +1 -1
  219. package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js → McpRunsPage-C5_i8_Zx.js} +2 -2
  220. package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js.map → McpRunsPage-C5_i8_Zx.js.map} +1 -1
  221. package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js → NamespacePill-OTZD2hzt.js} +2 -2
  222. package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js.map → NamespacePill-OTZD2hzt.js.map} +1 -1
  223. package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js → OperationsPage-C03CeU5P.js} +2 -2
  224. package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js.map → OperationsPage-C03CeU5P.js.map} +1 -1
  225. package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js → OperatorDashboard-BzC134Jt.js} +2 -2
  226. package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js.map → OperatorDashboard-BzC134Jt.js.map} +1 -1
  227. package/dashboard/dist/assets/{PageHeader-BSWIspNB.js → PageHeader-Hx8APPwE.js} +2 -2
  228. package/dashboard/dist/assets/{PageHeader-BSWIspNB.js.map → PageHeader-Hx8APPwE.js.map} +1 -1
  229. package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js → PageHeaderWithStats-BEQYYBJv.js} +2 -2
  230. package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js.map → PageHeaderWithStats-BEQYYBJv.js.map} +1 -1
  231. package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js → PersonaDetailPage-D0mY9L6j.js} +2 -2
  232. package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js.map → PersonaDetailPage-D0mY9L6j.js.map} +1 -1
  233. package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js → PersonasPage-FFlm5Eug.js} +2 -2
  234. package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js.map → PersonasPage-FFlm5Eug.js.map} +1 -1
  235. package/dashboard/dist/assets/{PortalPage-CucNZn_w.js → PortalPage-Cpc25uO-.js} +2 -2
  236. package/dashboard/dist/assets/{PortalPage-CucNZn_w.js.map → PortalPage-Cpc25uO-.js.map} +1 -1
  237. package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js → ProcessDetailPage-Di2J7KwY.js} +2 -2
  238. package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js.map → ProcessDetailPage-Di2J7KwY.js.map} +1 -1
  239. package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js → ProcessesListPage-BEXwU3Z0.js} +2 -2
  240. package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js.map → ProcessesListPage-BEXwU3Z0.js.map} +1 -1
  241. package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js → ResolverForm-2ks-3jXC.js} +6 -6
  242. package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js.map → ResolverForm-2ks-3jXC.js.map} +1 -1
  243. package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js → RoleDetailPage-DqoOk0xc.js} +3 -3
  244. package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js.map → RoleDetailPage-DqoOk0xc.js.map} +1 -1
  245. package/dashboard/dist/assets/{RolePill-CoETDpjF.js → RolePill-R5_ctGFy.js} +2 -2
  246. package/dashboard/dist/assets/{RolePill-CoETDpjF.js.map → RolePill-R5_ctGFy.js.map} +1 -1
  247. package/dashboard/dist/assets/{RolesPage-DBKxeam4.js → RolesPage-CPmo8Srr.js} +2 -2
  248. package/dashboard/dist/assets/{RolesPage-DBKxeam4.js.map → RolesPage-CPmo8Srr.js.map} +1 -1
  249. package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js → RosterWidget-D2yovCKw.js} +2 -2
  250. package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js.map → RosterWidget-D2yovCKw.js.map} +1 -1
  251. package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js → RunAsSelector-CMv96On6.js} +2 -2
  252. package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js.map → RunAsSelector-CMv96On6.js.map} +1 -1
  253. package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js → ScanCodesPage-CA6cTT-M.js} +2 -2
  254. package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js.map → ScanCodesPage-CA6cTT-M.js.map} +1 -1
  255. package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js → ScanSchemeDetailPage-DnctN5-H.js} +2 -2
  256. package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js.map → ScanSchemeDetailPage-DnctN5-H.js.map} +1 -1
  257. package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js → ScanStationPage-Bk8RwkKL.js} +2 -2
  258. package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js.map → ScanStationPage-Bk8RwkKL.js.map} +1 -1
  259. package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js → ScopeBadge-BXZ084nD.js} +2 -2
  260. package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js.map → ScopeBadge-BXZ084nD.js.map} +1 -1
  261. package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js → StickyPagination-B0FSuUgs.js} +2 -2
  262. package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js.map → StickyPagination-B0FSuUgs.js.map} +1 -1
  263. package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js → StreamMessageDetail-BwZEvMpP.js} +2 -2
  264. package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js.map → StreamMessageDetail-BwZEvMpP.js.map} +1 -1
  265. package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js → SwimlaneTimeline-BDVQEaMw.js} +2 -2
  266. package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js.map → SwimlaneTimeline-BDVQEaMw.js.map} +1 -1
  267. package/dashboard/dist/assets/{TagInput-S7UuVT_M.js → TagInput-DjPUDp2M.js} +2 -2
  268. package/dashboard/dist/assets/{TagInput-S7UuVT_M.js.map → TagInput-DjPUDp2M.js.map} +1 -1
  269. package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js → TaskDetailPage-BOlv3iGB.js} +2 -2
  270. package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js.map → TaskDetailPage-BOlv3iGB.js.map} +1 -1
  271. package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js → TaskQueuePill-D-4Ynf3K.js} +2 -2
  272. package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js.map → TaskQueuePill-D-4Ynf3K.js.map} +1 -1
  273. package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js → TasksListPage-e2teY0bD.js} +2 -2
  274. package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js.map → TasksListPage-e2teY0bD.js.map} +1 -1
  275. package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js → TimeAgo-Cvkpf_b3.js} +2 -2
  276. package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js.map → TimeAgo-Cvkpf_b3.js.map} +1 -1
  277. package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js → TimestampCell-B3btAV0N.js} +2 -2
  278. package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js.map → TimestampCell-B3btAV0N.js.map} +1 -1
  279. package/dashboard/dist/assets/{ToolPill-D40uLM_v.js → ToolPill-GsKQ80CO.js} +2 -2
  280. package/dashboard/dist/assets/{ToolPill-D40uLM_v.js.map → ToolPill-GsKQ80CO.js.map} +1 -1
  281. package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js → ToolTestPanel-B03nebR7.js} +2 -2
  282. package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js.map → ToolTestPanel-B03nebR7.js.map} +1 -1
  283. package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js → TopicDetailPage-DBRWne3O.js} +3 -3
  284. package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js.map → TopicDetailPage-DBRWne3O.js.map} +1 -1
  285. package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js → TopicsPage-CVe2M9HD.js} +2 -2
  286. package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js.map → TopicsPage-CVe2M9HD.js.map} +1 -1
  287. package/dashboard/dist/assets/{UserName-DQFjuoib.js → UserName-B_q_qp6V.js} +2 -2
  288. package/dashboard/dist/assets/{UserName-DQFjuoib.js.map → UserName-B_q_qp6V.js.map} +1 -1
  289. package/dashboard/dist/assets/WorkflowExecutionPage-Bh_dr9tM.js +2 -0
  290. package/dashboard/dist/assets/{WorkflowExecutionPage-Di08wCbs.js.map → WorkflowExecutionPage-Bh_dr9tM.js.map} +1 -1
  291. package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js → WorkflowPill-D7244fKp.js} +2 -2
  292. package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js.map → WorkflowPill-D7244fKp.js.map} +1 -1
  293. package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js → WorkflowsDashboard-DA6Mj7qH.js} +2 -2
  294. package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js.map → WorkflowsDashboard-DA6Mj7qH.js.map} +1 -1
  295. package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js → WorkflowsOverview-B1kBLj-a.js} +2 -2
  296. package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js.map → WorkflowsOverview-B1kBLj-a.js.map} +1 -1
  297. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js → YamlWorkflowDetailPage-6GJM8QIX.js} +8 -8
  298. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js.map → YamlWorkflowDetailPage-6GJM8QIX.js.map} +1 -1
  299. package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js → YamlWorkflowsPage-Bu811C7f.js} +2 -2
  300. package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js.map → YamlWorkflowsPage-Bu811C7f.js.map} +1 -1
  301. package/dashboard/dist/assets/{agents-PuftRTB2.js → agents-MPk_GnYz.js} +2 -2
  302. package/dashboard/dist/assets/{agents-PuftRTB2.js.map → agents-MPk_GnYz.js.map} +1 -1
  303. package/dashboard/dist/assets/{bots-BmEiPAWY.js → bots-2RihE2Tc.js} +2 -2
  304. package/dashboard/dist/assets/{bots-BmEiPAWY.js.map → bots-2RihE2Tc.js.map} +1 -1
  305. package/dashboard/dist/assets/{capabilities-CRii4Soa.js → capabilities-CC4iwJ1P.js} +2 -2
  306. package/dashboard/dist/assets/{capabilities-CRii4Soa.js.map → capabilities-CC4iwJ1P.js.map} +1 -1
  307. package/dashboard/dist/assets/{controlplane-DO_czaYo.js → controlplane-Bmkic8BH.js} +2 -2
  308. package/dashboard/dist/assets/{controlplane-DO_czaYo.js.map → controlplane-Bmkic8BH.js.map} +1 -1
  309. package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js → escalation-columns-B0lhUUrQ.js} +2 -2
  310. package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js.map → escalation-columns-B0lhUUrQ.js.map} +1 -1
  311. package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js → escalation-items-7WFpPo46.js} +2 -2
  312. package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js.map → escalation-items-7WFpPo46.js.map} +1 -1
  313. package/dashboard/dist/assets/index-B9uv-euR.css +1 -0
  314. package/dashboard/dist/assets/{index-DhSCCpqM.js → index-B_XV1rwu.js} +2 -2
  315. package/dashboard/dist/assets/{index-DhSCCpqM.js.map → index-B_XV1rwu.js.map} +1 -1
  316. package/dashboard/dist/assets/{index-Cx8xb-oU.js → index-C2CLfGwL.js} +2 -2
  317. package/dashboard/dist/assets/{index-Cx8xb-oU.js.map → index-C2CLfGwL.js.map} +1 -1
  318. package/dashboard/dist/assets/{index-Cga5IW3D.js → index-C3AeFihz.js} +2 -2
  319. package/dashboard/dist/assets/{index-Cga5IW3D.js.map → index-C3AeFihz.js.map} +1 -1
  320. package/dashboard/dist/assets/{index-DiaRlFYI.js → index-CBri8fYM.js} +2 -2
  321. package/dashboard/dist/assets/{index-DiaRlFYI.js.map → index-CBri8fYM.js.map} +1 -1
  322. package/dashboard/dist/assets/{index-CL_1VpGb.js → index-CRWsB7ZC.js} +2 -2
  323. package/dashboard/dist/assets/{index-CL_1VpGb.js.map → index-CRWsB7ZC.js.map} +1 -1
  324. package/dashboard/dist/assets/{index-XntldBd0.js → index-CTOv3G7a.js} +2 -2
  325. package/dashboard/dist/assets/{index-XntldBd0.js.map → index-CTOv3G7a.js.map} +1 -1
  326. package/dashboard/dist/assets/{index-CfP2nKRc.js → index-CcArGkzI.js} +3 -3
  327. package/dashboard/dist/assets/{index-CfP2nKRc.js.map → index-CcArGkzI.js.map} +1 -1
  328. package/dashboard/dist/assets/{index-Dz6R8-Dw.js → index-CkMHS-hG.js} +25 -25
  329. package/dashboard/dist/assets/index-CkMHS-hG.js.map +1 -0
  330. package/dashboard/dist/assets/index-CmsmwCyv.js +2 -0
  331. package/dashboard/dist/assets/{index-4YaDUcKd.js.map → index-CmsmwCyv.js.map} +1 -1
  332. package/dashboard/dist/assets/{index-2SM2_onB.js → index-CvJsvqIc.js} +2 -2
  333. package/dashboard/dist/assets/{index-2SM2_onB.js.map → index-CvJsvqIc.js.map} +1 -1
  334. package/dashboard/dist/assets/{index-Rwqrflm-.js → index-D-ilRyfy.js} +2 -2
  335. package/dashboard/dist/assets/{index-Rwqrflm-.js.map → index-D-ilRyfy.js.map} +1 -1
  336. package/dashboard/dist/assets/{index-CZ7A3AcD.js → index-DSUtfDXx.js} +2 -2
  337. package/dashboard/dist/assets/{index-CZ7A3AcD.js.map → index-DSUtfDXx.js.map} +1 -1
  338. package/dashboard/dist/assets/{index-jL2K6us4.js → index-Da6ycKyf.js} +2 -2
  339. package/dashboard/dist/assets/{index-jL2K6us4.js.map → index-Da6ycKyf.js.map} +1 -1
  340. package/dashboard/dist/assets/{knowledge-CeUqGPuo.js → knowledge-Bpbg20DC.js} +2 -2
  341. package/dashboard/dist/assets/{knowledge-CeUqGPuo.js.map → knowledge-Bpbg20DC.js.map} +1 -1
  342. package/dashboard/dist/assets/machines-BqOZZU-3.js +2 -0
  343. package/dashboard/dist/assets/machines-BqOZZU-3.js.map +1 -0
  344. package/dashboard/dist/assets/{mcp-Cx96NTeD.js → mcp-CmcUXYce.js} +2 -2
  345. package/dashboard/dist/assets/{mcp-Cx96NTeD.js.map → mcp-CmcUXYce.js.map} +1 -1
  346. package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js → mcp-query-C8buQxN9.js} +2 -2
  347. package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js.map → mcp-query-C8buQxN9.js.map} +1 -1
  348. package/dashboard/dist/assets/{personas--4kjwyOw.js → personas-C2n5oDmY.js} +2 -2
  349. package/dashboard/dist/assets/{personas--4kjwyOw.js.map → personas-C2n5oDmY.js.map} +1 -1
  350. package/dashboard/dist/assets/{pipelines-PgkwvG7f.js → pipelines-RKpSkFz7.js} +2 -2
  351. package/dashboard/dist/assets/{pipelines-PgkwvG7f.js.map → pipelines-RKpSkFz7.js.map} +1 -1
  352. package/dashboard/dist/assets/{tasks-CcYxdBa3.js → tasks-Dab4hExW.js} +2 -2
  353. package/dashboard/dist/assets/{tasks-CcYxdBa3.js.map → tasks-Dab4hExW.js.map} +1 -1
  354. package/dashboard/dist/assets/{topics-_lik7cNY.js → topics-FTMNP7r3.js} +2 -2
  355. package/dashboard/dist/assets/{topics-_lik7cNY.js.map → topics-FTMNP7r3.js.map} +1 -1
  356. package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js → useDebouncedValue-B_1u1YIk.js} +2 -2
  357. package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js.map → useDebouncedValue-B_1u1YIk.js.map} +1 -1
  358. package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js → useNamespace-HUeAI7Qb.js} +2 -2
  359. package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js.map → useNamespace-HUeAI7Qb.js.map} +1 -1
  360. package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js → useYamlActivityEvents-Cax54qHH.js} +2 -2
  361. package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js.map → useYamlActivityEvents-Cax54qHH.js.map} +1 -1
  362. package/dashboard/dist/assets/{validate-FlXCBBT6.js → validate-DxOaV7QS.js} +2 -2
  363. package/dashboard/dist/assets/{validate-FlXCBBT6.js.map → validate-DxOaV7QS.js.map} +1 -1
  364. package/dashboard/dist/assets/{vendor-icons-DUYcKTjP.js → vendor-icons-fxBvvHBi.js} +187 -182
  365. package/dashboard/dist/assets/vendor-icons-fxBvvHBi.js.map +1 -0
  366. package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js → yaml-workflows-BgY1XHJx.js} +2 -2
  367. package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js.map → yaml-workflows-BgY1XHJx.js.map} +1 -1
  368. package/dashboard/dist/index.html +3 -3
  369. package/docs/architecture.md +1 -0
  370. package/docs/code-owned-configuration.md +6 -0
  371. package/docs/dashboard.md +2 -1
  372. package/docs/events.md +34 -1
  373. package/docs/hitl/lookups.md +6 -4
  374. package/docs/machines.md +114 -28
  375. package/docs/mcp.md +19 -0
  376. package/package.json +1 -1
  377. package/dashboard/dist/assets/AgentsPage-C9UuUKhr.js +0 -2
  378. package/dashboard/dist/assets/AvailableEscalationsPage-DrvfXz70.js +0 -2
  379. package/dashboard/dist/assets/FilterBar-BygWrnB1.js +0 -2
  380. package/dashboard/dist/assets/FilterBar-BygWrnB1.js.map +0 -1
  381. package/dashboard/dist/assets/McpRunDetailPage-80fQn9iX.js +0 -2
  382. package/dashboard/dist/assets/WorkflowExecutionPage-Di08wCbs.js +0 -2
  383. package/dashboard/dist/assets/index-4YaDUcKd.js +0 -2
  384. package/dashboard/dist/assets/index-CnU7Jjz3.css +0 -1
  385. package/dashboard/dist/assets/index-Dz6R8-Dw.js.map +0 -1
  386. 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
+ }
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * The roles a line needs, as code-owned role declarations: one station role
3
3
  * per process (a machine resolves the handoffs into it), the exit role (a
4
- * person receives finished units) and the operator role (a person decides
5
- * failed handoffs and closes alarm and machine rows). Each role owns its
6
- * form; only the operator role enforces it on the server, because handoff
7
- * rows also collect machine records the gateway already validates.
4
+ * person receives finished units), the operator role (a person decides
5
+ * failed handoffs and closes alarm and machine rows) and the quality role
6
+ * (a person decides units finished on hold). Each role owns its form; the
7
+ * operator and quality roles enforce it on the server, since handoff rows
8
+ * also collect machine records the gateway already validates.
8
9
  */
9
10
  import type { LTRoleConfig } from '../../types/startup';
10
11
  import { type LineDef } from '../../lib/machines/line';
@@ -2,10 +2,11 @@
2
2
  /**
3
3
  * The roles a line needs, as code-owned role declarations: one station role
4
4
  * per process (a machine resolves the handoffs into it), the exit role (a
5
- * person receives finished units) and the operator role (a person decides
6
- * failed handoffs and closes alarm and machine rows). Each role owns its
7
- * form; only the operator role enforces it on the server, because handoff
8
- * rows also collect machine records the gateway already validates.
5
+ * person receives finished units), the operator role (a person decides
6
+ * failed handoffs and closes alarm and machine rows) and the quality role
7
+ * (a person decides units finished on hold). Each role owns its form; the
8
+ * operator and quality roles enforce it on the server, since handoff rows
9
+ * also collect machine records the gateway already validates.
9
10
  */
10
11
  Object.defineProperty(exports, "__esModule", { value: true });
11
12
  exports.machineRoleConfigs = machineRoleConfigs;
@@ -44,6 +45,14 @@ function machineRoleConfigs(line) {
44
45
  enforce_schema: true,
45
46
  ...BOARD,
46
47
  },
48
+ {
49
+ role: (0, line_1.qualityRole)(line),
50
+ title: 'Line quality',
51
+ description: 'Units a machine finished on hold: release, rework or scrap.',
52
+ form_schema: forms_1.QUALITY_FORM_SCHEMA,
53
+ enforce_schema: true,
54
+ ...BOARD,
55
+ },
47
56
  ];
48
57
  }
49
58
  /** The host's declarations first; line roles only where the host declared none. */
@@ -15,6 +15,13 @@ 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
26
  if (!v || typeof v.url !== 'string' || !v.url || typeof v.sha256 !== 'string' || !v.sha256)
20
27
  return undefined;
@@ -36,9 +43,10 @@ function unitsOf(v) {
36
43
  const artifact = artifactOf(u.artifact);
37
44
  const artifacts = artifactsOf(u.artifacts);
38
45
  const parameters = paramsOf(u.parameters);
46
+ const refs = refsOf(u.refs);
39
47
  return {
40
48
  unitId: String(u.unitId), carrierId: str(u.carrierId),
41
- ...(artifact ? { artifact } : {}), ...(artifacts ? { artifacts } : {}), ...(parameters ? { parameters } : {}),
49
+ ...(artifact ? { artifact } : {}), ...(artifacts ? { artifacts } : {}), ...(parameters ? { parameters } : {}), ...(refs ? { refs } : {}),
42
50
  };
43
51
  });
44
52
  }
@@ -63,6 +71,7 @@ function readHandoffFacets(md = {}) {
63
71
  artifactSha256: str(md.artifactSha256),
64
72
  attempt: Number(md.attempt ?? 1),
65
73
  ...(paramsOf(md.parameters) ? { parameters: paramsOf(md.parameters) } : {}),
74
+ ...(refsOf(md.refs) ? { refs: refsOf(md.refs) } : {}),
66
75
  };
67
76
  }
68
77
  exports.standardRows = {
@@ -16,9 +16,10 @@ export type LineMessaging = Pick<typeof messagingRegistry, 'streams' | 'pubsub'>
16
16
  /**
17
17
  * The gateway's view of every machine on the line. With `nats`, events are read
18
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.
19
+ * server of the site's own, which the bus connects to itself. `siteCodecs` are
20
+ * the codecs of every line on the site, so the streams keep all their subjects.
20
21
  */
21
- export declare function createMachineBus(config: MachineLineConfig, line: LineDef, codec?: LineCodec, messaging?: LineMessaging): MachineBus;
22
+ export declare function createMachineBus(config: MachineLineConfig, line: LineDef, codec?: LineCodec, messaging?: LineMessaging, siteCodecs?: LineCodec[]): MachineBus;
22
23
  /** Long Tail's escalation events for the gateway; `in-process` needs the running instance's callback adapter. */
23
24
  export declare function createEscalationFeed(config: MachineLineConfig, line: LineDef, callbacks?: CallbackEventAdapter): EscalationFeed;
24
25
  /** One MQTT link per simulated machine; machines speak MQTT in every networked mode. */
@@ -33,12 +33,13 @@ function defaultCodec(config, line) {
33
33
  /**
34
34
  * The gateway's view of every machine on the line. With `nats`, events are read
35
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.
36
+ * server of the site's own, which the bus connects to itself. `siteCodecs` are
37
+ * the codecs of every line on the site, so the streams keep all their subjects.
37
38
  */
38
- function createMachineBus(config, line, codec = defaultCodec(config, line), messaging = messaging_1.messagingRegistry) {
39
+ function createMachineBus(config, line, codec = defaultCodec(config, line), messaging = messaging_1.messagingRegistry, siteCodecs = []) {
39
40
  switch (config.transport) {
40
41
  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
+ const where = { mqtt: mqttOf(config), controllerId: (0, line_1.controllerId)(line), siteId: line.siteId, lineId: line.lineId, codec, siteCodecs };
42
43
  if (config.siteNatsUrl) {
43
44
  return new nats_bus_1.NatsMachineBus({ natsUrl: config.siteNatsUrl, user: config.siteNatsUser, password: config.siteNatsPassword, ...where });
44
45
  }
@@ -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, WireEvent, WireWindowQuery } 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 {
@@ -19,15 +23,60 @@ export interface MachineSurfaceOptions {
19
23
  callbacks?: CallbackEventAdapter;
20
24
  log?: GatewayLog;
21
25
  codec?: LineCodec;
26
+ /** A codec for one line, keyed `<siteId>/<lineId>`; every other line uses `codec`. */
27
+ codecs?: Record<string, LineCodec>;
22
28
  rows?: HandoffRowAdapter;
23
29
  }
30
+ /** The codec a line runs on: its own, the surface's, or the generic line protocol. */
31
+ export declare function codecFor(opts: Pick<MachineSurfaceOptions, 'codec' | 'codecs'>, config: MachineLineConfig, line: LineDef): LineCodec;
32
+ /** A message to dry-run against a line. */
33
+ export type WireProbe = Pick<InboundMessage, 'topic' | 'payload' | 'retained'>;
34
+ /** What settings and the API read of the surface. */
35
+ export interface LineSurface {
36
+ /** Every declared line, on every replica. */
37
+ describeLines(): LineSummary[];
38
+ /** The line as its leader sees it; null when this replica is not leading it, or the line is not declared. */
39
+ describeLine(siteId: string, lineId: string): LineView | null;
40
+ /** A dry run of one message; null when this replica is not leading the line. */
41
+ inspect(siteId: string, lineId: string, probe: WireProbe): InspectResult | null;
42
+ /** The leader's last wire events, newest first; null when this replica is not leading the line. */
43
+ wire(siteId: string, lineId: string, query?: WireWindowQuery): WireEvent[] | null;
44
+ /** The declared line, or undefined. */
45
+ findLine(siteId: string, lineId: string): LineDef | undefined;
46
+ /** The ops a machine-command row on this line may ask for. */
47
+ commandOps(siteId: string, lineId: string): string[];
48
+ /** Run a line on this replica: started, replaced when its definition changed, or unchanged. */
49
+ declare(line: LineDef): Promise<DeclareOutcome>;
50
+ /** Stop running a line on this replica; false when it was not running. */
51
+ retire(siteId: string, lineId: string): Promise<boolean>;
52
+ }
53
+ export type DeclareOutcome = 'started' | 'replaced' | 'unchanged';
24
54
  /** Inside Long Tail the gateway reads escalation events in process. */
25
55
  export declare function surfaceConfig(env: Env): MachineLineConfig;
26
- export declare class MachineSurface {
56
+ /** The line as every replica can describe it: its machines, roles, declared addresses and the codec's own ops. */
57
+ export declare function summarizeLine(line: LineDef, codec: Pick<LineCodec, 'rowOps'>): LineSummary;
58
+ /** The ops a machine-command row may ask for: the control ops, a snapshot, and the codec's own. */
59
+ export declare function commandOpsOf(codec: Pick<LineCodec, 'rowOps'>): string[];
60
+ export declare class MachineSurface implements LineSurface {
61
+ private readonly config;
62
+ private readonly opts;
63
+ private readonly log;
27
64
  private readonly runs;
28
65
  private constructor();
29
- /** Validate the configuration, then contend for every line in the background. */
66
+ /** Validate the configuration, then contend for every line in the background. The registry may add lines later. */
30
67
  static start(opts: MachineSurfaceOptions): MachineSurface;
31
68
  stop(): Promise<void>;
69
+ declare(line: LineDef): Promise<DeclareOutcome>;
70
+ retire(siteId: string, lineId: string): Promise<boolean>;
71
+ describeLines(): LineSummary[];
72
+ describeLine(siteId: string, lineId: string): LineView | null;
73
+ inspect(siteId: string, lineId: string, probe: WireProbe): InspectResult | null;
74
+ wire(siteId: string, lineId: string, query?: WireWindowQuery): WireEvent[] | null;
75
+ findLine(siteId: string, lineId: string): LineDef | undefined;
76
+ commandOps(siteId: string, lineId: string): string[];
77
+ /** The codecs every line on a site runs, so one site's streams keep all their subjects. */
78
+ codecsOnSite(siteId: string): LineCodec[];
79
+ private begin;
80
+ private run;
32
81
  }
33
82
  export {};
@@ -4,11 +4,19 @@
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;
13
+ exports.codecFor = codecFor;
11
14
  exports.surfaceConfig = surfaceConfig;
15
+ exports.summarizeLine = summarizeLine;
16
+ exports.commandOpsOf = commandOpsOf;
17
+ const node_util_1 = require("node:util");
18
+ const line_1 = require("../../lib/machines/line");
19
+ const protocol_1 = require("../../lib/machines/protocol");
12
20
  const config_1 = require("./config");
13
21
  const api_escalations_1 = require("./gateway/api-escalations");
14
22
  const gateway_1 = require("./gateway/gateway");
@@ -16,6 +24,10 @@ const log_1 = require("./gateway/log");
16
24
  const identities_1 = require("./identities");
17
25
  const leadership_1 = require("./leadership");
18
26
  const select_1 = require("./select");
27
+ /** The codec a line runs on: its own, the surface's, or the generic line protocol. */
28
+ function codecFor(opts, config, line) {
29
+ return opts.codecs?.[keyOf(line.siteId, line.lineId)] ?? opts.codec ?? (0, select_1.defaultCodec)(config, line);
30
+ }
19
31
  /** Inside Long Tail the gateway reads escalation events in process. */
20
32
  function surfaceConfig(env) {
21
33
  const transport = env.MACHINE_TRANSPORT;
@@ -24,20 +36,45 @@ function surfaceConfig(env) {
24
36
  }
25
37
  return (0, config_1.loadMachineLineConfig)({ ...env, MACHINE_ESCALATION_FEED: env.MACHINE_ESCALATION_FEED ?? config_1.ESCALATION_FEED.IN_PROCESS });
26
38
  }
39
+ /** The line as every replica can describe it: its machines, roles, declared addresses and the codec's own ops. */
40
+ function summarizeLine(line, codec) {
41
+ const rowOps = (0, protocol_1.declaredRowOps)(codec);
42
+ return {
43
+ siteId: line.siteId, lineId: line.lineId,
44
+ machines: line.machines.map((m) => {
45
+ const learned = (0, line_1.learnsAddress)(line, m.machineId);
46
+ return {
47
+ machineId: m.machineId, process: m.process, role: (0, line_1.machineRole)(m),
48
+ address: learned ? null : m.address ?? m.machineId, addressing: learned ? 'learned' : 'declared',
49
+ ...(rowOps.length ? { rowOps } : {}),
50
+ };
51
+ }),
52
+ };
53
+ }
54
+ /** The ops a machine-command row may ask for: the control ops, a snapshot, and the codec's own. */
55
+ function commandOpsOf(codec) {
56
+ return [...new Set([...protocol_1.CONTROL_OPS, protocol_1.OP.SNAPSHOT, ...(0, protocol_1.declaredRowOps)(codec)])];
57
+ }
27
58
  class LineRun {
28
- constructor(line, config, opts, log) {
59
+ constructor(line, config, opts, log,
60
+ /** The codecs of every line on this line's site, read when the gateway starts. */
61
+ siteCodecs = () => []) {
29
62
  this.line = line;
30
63
  this.config = config;
31
64
  this.opts = opts;
32
65
  this.log = log;
66
+ this.siteCodecs = siteCodecs;
67
+ this.ready = false;
33
68
  this.stopped = false;
34
69
  this.leadership = new leadership_1.LineLeadership(`lt-machine-line:${line.siteId}/${line.lineId}`);
70
+ this.codec = codecFor(opts, config, line);
35
71
  }
36
72
  start() {
37
73
  const where = { site: this.line.siteId, line: this.line.lineId };
38
74
  this.log.info(log_1.GATEWAY_LOG.STANDBY, where);
39
75
  this.leadership.run(() => (this.leading = this.lead()), async (err) => {
40
76
  this.log.warn(log_1.GATEWAY_LOG.LEADERSHIP_LOST, { ...where, error: err.message });
77
+ this.ready = false;
41
78
  await this.gateway?.stop();
42
79
  this.gateway = undefined;
43
80
  }).catch((err) => this.log.error(log_1.GATEWAY_LOG.START_FAILED, { ...where, error: err.message }));
@@ -45,10 +82,15 @@ class LineRun {
45
82
  /** A gateway still starting finishes first, so none is left running after stop. */
46
83
  async stop() {
47
84
  this.stopped = true;
85
+ this.ready = false;
48
86
  await this.leading?.catch(() => undefined);
49
87
  await this.gateway?.stop();
50
88
  await this.leadership.stop();
51
89
  }
90
+ /** The gateway, once it leads the line. */
91
+ leader() {
92
+ return this.ready ? this.gateway : undefined;
93
+ }
52
94
  async lead() {
53
95
  // 1. Identities, 2. gateway on the line's bus and feed, 3. reconcile and consume (gateway.start)
54
96
  const ids = await (0, identities_1.ensureLineBots)(this.line);
@@ -60,10 +102,9 @@ class LineRun {
60
102
  throw new Error(`no bot for "${as}" on ${this.line.siteId}/${this.line.lineId}`);
61
103
  return id;
62
104
  };
63
- const { config, line } = this;
64
- const codec = this.opts.codec ?? (0, select_1.defaultCodec)(config, line);
105
+ const { config, line, codec } = this;
65
106
  this.gateway = new gateway_1.MachineGateway({
66
- bus: (0, select_1.createMachineBus)(config, line, codec),
107
+ bus: (0, select_1.createMachineBus)(config, line, codec, undefined, this.siteCodecs()),
67
108
  codec,
68
109
  rows: this.opts.rows,
69
110
  feed: (0, select_1.createEscalationFeed)(config, line, this.opts.callbacks),
@@ -74,31 +115,86 @@ class LineRun {
74
115
  settings: {
75
116
  topicRoot: config.topicRoot, replyTimeoutMs: config.replyTimeoutMs, dispatchAttempts: config.dispatchAttempts,
76
117
  offlineDebounceMs: config.offlineDebounceMs, dispatchTtlMs: config.dispatchTtlMs, quietMs: config.quietMs,
77
- receiptDelayMs: config.receiptDelayMs, lifecycle: config.lifecycle, progressStep: config.progressStep,
118
+ receiptDelayMs: config.receiptDelayMs, lifecycle: config.lifecycle, progressStep: config.progressStep, wireTelemetry: config.wireTelemetry,
119
+ wireWindow: config.wireWindow,
78
120
  },
79
121
  });
80
122
  await this.gateway.start();
123
+ this.ready = true;
81
124
  this.log.info(log_1.GATEWAY_LOG.LEADING, { site: line.siteId, line: line.lineId });
82
125
  }
83
126
  }
84
127
  class MachineSurface {
85
- constructor(runs) {
86
- this.runs = runs;
128
+ constructor(config, opts, log) {
129
+ this.config = config;
130
+ this.opts = opts;
131
+ this.log = log;
132
+ this.runs = new Map();
87
133
  }
88
- /** Validate the configuration, then contend for every line in the background. */
134
+ /** Validate the configuration, then contend for every line in the background. The registry may add lines later. */
89
135
  static start(opts) {
90
- if (!opts.lines.length)
91
- throw new Error('start({ machines }) needs at least one line');
92
136
  const config = surfaceConfig(opts.env ?? process.env);
93
- const log = opts.log ?? log_1.consoleLog;
94
- const runs = opts.lines.map((line) => new LineRun(line, config, opts, log));
95
- for (const run of runs)
96
- run.start();
97
- return new MachineSurface(runs);
137
+ const surface = new MachineSurface(config, opts, opts.log ?? log_1.consoleLog);
138
+ for (const line of opts.lines)
139
+ surface.begin(line);
140
+ return surface;
98
141
  }
99
142
  async stop() {
100
- for (const run of this.runs)
143
+ for (const run of this.runs.values())
101
144
  await run.stop();
145
+ this.runs.clear();
146
+ }
147
+ async declare(line) {
148
+ const current = this.run(line.siteId, line.lineId);
149
+ if (current && (0, node_util_1.isDeepStrictEqual)(current.line, line))
150
+ return 'unchanged';
151
+ if (current)
152
+ await current.stop();
153
+ this.begin(line);
154
+ return current ? 'replaced' : 'started';
155
+ }
156
+ async retire(siteId, lineId) {
157
+ const current = this.run(siteId, lineId);
158
+ if (!current)
159
+ return false;
160
+ this.runs.delete(keyOf(siteId, lineId));
161
+ await current.stop();
162
+ return true;
163
+ }
164
+ describeLines() {
165
+ return [...this.runs.values()].map((run) => summarizeLine(run.line, run.codec));
166
+ }
167
+ describeLine(siteId, lineId) {
168
+ const gateway = this.run(siteId, lineId)?.leader();
169
+ return gateway ? gateway.state.project(this.findLine(siteId, lineId)) : null;
170
+ }
171
+ inspect(siteId, lineId, probe) {
172
+ return this.run(siteId, lineId)?.leader()?.inspect(probe) ?? null;
173
+ }
174
+ wire(siteId, lineId, query = {}) {
175
+ return this.run(siteId, lineId)?.leader()?.window.read(query) ?? null;
176
+ }
177
+ findLine(siteId, lineId) {
178
+ return this.run(siteId, lineId)?.line;
179
+ }
180
+ commandOps(siteId, lineId) {
181
+ const run = this.run(siteId, lineId);
182
+ return run ? commandOpsOf(run.codec) : [];
183
+ }
184
+ /** The codecs every line on a site runs, so one site's streams keep all their subjects. */
185
+ codecsOnSite(siteId) {
186
+ return [...new Set([...this.runs.values()].filter((run) => run.line.siteId === siteId).map((run) => run.codec))];
187
+ }
188
+ begin(line) {
189
+ const run = new LineRun(line, this.config, this.opts, (0, log_1.composeLogs)(this.log, (0, log_1.eventsLog)(line)), () => this.codecsOnSite(line.siteId));
190
+ this.runs.set(keyOf(line.siteId, line.lineId), run);
191
+ run.start();
192
+ }
193
+ run(siteId, lineId) {
194
+ return this.runs.get(keyOf(siteId, lineId));
102
195
  }
103
196
  }
104
197
  exports.MachineSurface = MachineSurface;
198
+ function keyOf(siteId, lineId) {
199
+ return `${siteId}/${lineId}`;
200
+ }
@@ -18,7 +18,7 @@ export interface SurfaceReport {
18
18
  export declare function newSurfaceReport(): SurfaceReport;
19
19
  /** Record one entry's outcome on the surface report. */
20
20
  export declare function recordOutcome(report: SurfaceReport, name: string, outcome: ApplyOutcome): void;
21
- export declare function withConfigLock<T>(fn: () => Promise<T>): Promise<T>;
21
+ export { withConfigLock } from '../lib/db/config-lock';
22
22
  /**
23
23
  * One boot line per surface. Warn level when orphans exist so operators see
24
24
  * "declared set no longer matches the DB" without grepping.