@songsid/agend 2.3.5-alpha.4 → 2.3.5-beta.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 (670) hide show
  1. package/README.md +0 -2
  2. package/README.zh-TW.md +0 -2
  3. package/THIRD_PARTY_NOTICES.md +12 -28
  4. package/dist/agent-cli-instructions.md +1 -1
  5. package/dist/agent-credentials.d.ts +24 -0
  6. package/dist/agent-credentials.js +66 -0
  7. package/dist/agent-credentials.js.map +1 -0
  8. package/dist/agent-endpoint.d.ts +4 -6
  9. package/dist/agent-endpoint.js +15 -12
  10. package/dist/agent-endpoint.js.map +1 -1
  11. package/dist/auth-api.d.ts +0 -21
  12. package/dist/auth-api.js +8 -93
  13. package/dist/auth-api.js.map +1 -1
  14. package/dist/authority/session-authorizations.d.ts +30 -4
  15. package/dist/authority/session-authorizations.js +69 -17
  16. package/dist/authority/session-authorizations.js.map +1 -1
  17. package/dist/authority/web-authority.d.ts +2 -12
  18. package/dist/authority/web-authority.js +4 -25
  19. package/dist/authority/web-authority.js.map +1 -1
  20. package/dist/backend/antigravity.js +3 -1
  21. package/dist/backend/antigravity.js.map +1 -1
  22. package/dist/backend/claude-code.d.ts +12 -15
  23. package/dist/backend/claude-code.js +133 -152
  24. package/dist/backend/claude-code.js.map +1 -1
  25. package/dist/backend/codex-metadata.d.ts +14 -0
  26. package/dist/backend/codex-metadata.js +45 -0
  27. package/dist/backend/codex-metadata.js.map +1 -1
  28. package/dist/backend/codex-package.d.ts +2 -5
  29. package/dist/backend/codex-package.js +5 -1
  30. package/dist/backend/codex-package.js.map +1 -1
  31. package/dist/backend/codex-quota-history.d.ts +7 -0
  32. package/dist/backend/codex-quota-history.js +72 -0
  33. package/dist/backend/codex-quota-history.js.map +1 -0
  34. package/dist/backend/codex-session-lookup.d.ts +6 -0
  35. package/dist/backend/codex-session-lookup.js +1 -1
  36. package/dist/backend/codex-session-lookup.js.map +1 -1
  37. package/dist/backend/codex-speed.d.ts +14 -0
  38. package/dist/backend/codex-speed.js +35 -0
  39. package/dist/backend/codex-speed.js.map +1 -0
  40. package/dist/backend/codex.d.ts +116 -136
  41. package/dist/backend/codex.js +912 -942
  42. package/dist/backend/codex.js.map +1 -1
  43. package/dist/backend/grok-weekly-reset.d.ts +24 -0
  44. package/dist/backend/grok-weekly-reset.js +95 -0
  45. package/dist/backend/grok-weekly-reset.js.map +1 -0
  46. package/dist/backend/grok.d.ts +30 -3
  47. package/dist/backend/grok.js +301 -76
  48. package/dist/backend/grok.js.map +1 -1
  49. package/dist/backend/kiro.d.ts +3 -0
  50. package/dist/backend/kiro.js +50 -2
  51. package/dist/backend/kiro.js.map +1 -1
  52. package/dist/backend/muse.js +5 -3
  53. package/dist/backend/muse.js.map +1 -1
  54. package/dist/backend/types.d.ts +15 -8
  55. package/dist/backend/types.js +3 -0
  56. package/dist/backend/types.js.map +1 -1
  57. package/dist/bundled-tmux-guard.d.ts +21 -0
  58. package/dist/bundled-tmux-guard.js +96 -0
  59. package/dist/bundled-tmux-guard.js.map +1 -0
  60. package/dist/cache-ledger.d.ts +95 -0
  61. package/dist/cache-ledger.js +276 -4
  62. package/dist/cache-ledger.js.map +1 -1
  63. package/dist/cache-service.d.ts +5 -0
  64. package/dist/cache-service.js +16 -4
  65. package/dist/cache-service.js.map +1 -1
  66. package/dist/channel/adapters/discord.js +11 -3
  67. package/dist/channel/adapters/discord.js.map +1 -1
  68. package/dist/channel/adapters/telegram.d.ts +51 -0
  69. package/dist/channel/adapters/telegram.js +235 -17
  70. package/dist/channel/adapters/telegram.js.map +1 -1
  71. package/dist/channel/ipc-bridge.d.ts +0 -2
  72. package/dist/channel/mcp-tools.js +3 -3
  73. package/dist/channel/mcp-tools.js.map +1 -1
  74. package/dist/channel/types.d.ts +2 -0
  75. package/dist/classic-channel-manager.d.ts +2 -0
  76. package/dist/classic-channel-manager.js +5 -1
  77. package/dist/classic-channel-manager.js.map +1 -1
  78. package/dist/cli.js +14 -10
  79. package/dist/cli.js.map +1 -1
  80. package/dist/config-validator.js +30 -71
  81. package/dist/config-validator.js.map +1 -1
  82. package/dist/config.js +3 -17
  83. package/dist/config.js.map +1 -1
  84. package/dist/cross-instance-notice.d.ts +10 -0
  85. package/dist/cross-instance-notice.js +67 -5
  86. package/dist/cross-instance-notice.js.map +1 -1
  87. package/dist/daemon.d.ts +70 -68
  88. package/dist/daemon.js +774 -846
  89. package/dist/daemon.js.map +1 -1
  90. package/dist/dashboard-permissions.d.ts +8 -0
  91. package/dist/dashboard-permissions.js +16 -0
  92. package/dist/dashboard-permissions.js.map +1 -1
  93. package/dist/delivery-consumed-watch.d.ts +26 -16
  94. package/dist/delivery-consumed-watch.js +31 -26
  95. package/dist/delivery-consumed-watch.js.map +1 -1
  96. package/dist/delivery-outbox.d.ts +0 -5
  97. package/dist/delivery-outbox.js +4 -32
  98. package/dist/delivery-outbox.js.map +1 -1
  99. package/dist/delivery-reconciliation.d.ts +42 -2
  100. package/dist/delivery-reconciliation.js +164 -2
  101. package/dist/delivery-reconciliation.js.map +1 -1
  102. package/dist/export-import.d.ts +7 -0
  103. package/dist/export-import.js +44 -10
  104. package/dist/export-import.js.map +1 -1
  105. package/dist/fleet-context.d.ts +4 -2
  106. package/dist/fleet-level-config.d.ts +1 -1
  107. package/dist/fleet-level-config.js +0 -2
  108. package/dist/fleet-level-config.js.map +1 -1
  109. package/dist/fleet-manager.d.ts +108 -245
  110. package/dist/fleet-manager.js +656 -2028
  111. package/dist/fleet-manager.js.map +1 -1
  112. package/dist/general-instance.d.ts +0 -7
  113. package/dist/general-instance.js +3 -20
  114. package/dist/general-instance.js.map +1 -1
  115. package/dist/general-knowledge/skills/concepts/SKILL.md +393 -0
  116. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +1 -0
  117. package/dist/general-knowledge/skills/instance-lifecycle/SKILL.md +3 -1
  118. package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +41 -4
  119. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +9 -3
  120. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  121. package/dist/instance-config-impact.js +6 -7
  122. package/dist/instance-config-impact.js.map +1 -1
  123. package/dist/instance-lifecycle.d.ts +19 -23
  124. package/dist/instance-lifecycle.js +216 -383
  125. package/dist/instance-lifecycle.js.map +1 -1
  126. package/dist/instance-topic-delete.d.ts +77 -0
  127. package/dist/instance-topic-delete.js +123 -0
  128. package/dist/instance-topic-delete.js.map +1 -0
  129. package/dist/instructions.d.ts +1 -3
  130. package/dist/instructions.js +1 -7
  131. package/dist/instructions.js.map +1 -1
  132. package/dist/kiro-engine-status.d.ts +11 -0
  133. package/dist/kiro-engine-status.js +6 -0
  134. package/dist/kiro-engine-status.js.map +1 -1
  135. package/dist/locale.js +63 -86
  136. package/dist/locale.js.map +1 -1
  137. package/dist/log-service.d.ts +28 -0
  138. package/dist/log-service.js +29 -0
  139. package/dist/log-service.js.map +1 -1
  140. package/dist/log-steps.d.ts +4 -3
  141. package/dist/log-steps.js +32 -7
  142. package/dist/log-steps.js.map +1 -1
  143. package/dist/logger.d.ts +16 -2
  144. package/dist/logger.js +346 -66
  145. package/dist/logger.js.map +1 -1
  146. package/dist/login-flows.d.ts +7 -0
  147. package/dist/login-flows.js +5 -2
  148. package/dist/login-flows.js.map +1 -1
  149. package/dist/login-manager.js +25 -4
  150. package/dist/login-manager.js.map +1 -1
  151. package/dist/missed-offline.d.ts +25 -0
  152. package/dist/missed-offline.js +79 -0
  153. package/dist/missed-offline.js.map +1 -0
  154. package/dist/muse-usage-relay.d.ts +2 -0
  155. package/dist/muse-usage-relay.js +5 -3
  156. package/dist/muse-usage-relay.js.map +1 -1
  157. package/dist/needs-you-hub.d.ts +6 -3
  158. package/dist/needs-you-hub.js +31 -9
  159. package/dist/needs-you-hub.js.map +1 -1
  160. package/dist/needs-you.d.ts +20 -18
  161. package/dist/needs-you.js +18 -14
  162. package/dist/needs-you.js.map +1 -1
  163. package/dist/office-share-page.js +1 -1
  164. package/dist/office-share-page.js.map +1 -1
  165. package/dist/outbound-handlers.d.ts +2 -16
  166. package/dist/outbound-handlers.js +10 -72
  167. package/dist/outbound-handlers.js.map +1 -1
  168. package/dist/outbound-schemas.d.ts +0 -38
  169. package/dist/outbound-schemas.js +5 -14
  170. package/dist/outbound-schemas.js.map +1 -1
  171. package/dist/pane-quota-history.d.ts +7 -0
  172. package/dist/pane-quota-history.js +47 -0
  173. package/dist/pane-quota-history.js.map +1 -0
  174. package/dist/platform-general.d.ts +46 -0
  175. package/dist/platform-general.js +91 -0
  176. package/dist/platform-general.js.map +1 -0
  177. package/dist/public-web-gateway.js +0 -9
  178. package/dist/public-web-gateway.js.map +1 -1
  179. package/dist/public-web-link.d.ts +0 -11
  180. package/dist/public-web-link.js +0 -13
  181. package/dist/public-web-link.js.map +1 -1
  182. package/dist/queued-handoffs.d.ts +33 -0
  183. package/dist/queued-handoffs.js +75 -0
  184. package/dist/queued-handoffs.js.map +1 -0
  185. package/dist/quickstart-api.js +5 -9
  186. package/dist/quickstart-api.js.map +1 -1
  187. package/dist/quickstart.d.ts +8 -1
  188. package/dist/quickstart.js +42 -4
  189. package/dist/quickstart.js.map +1 -1
  190. package/dist/quota-notice-config.d.ts +22 -0
  191. package/dist/quota-notice-config.js +41 -0
  192. package/dist/quota-notice-config.js.map +1 -0
  193. package/dist/quota-notice.d.ts +7 -0
  194. package/dist/quota-notice.js +40 -0
  195. package/dist/quota-notice.js.map +1 -1
  196. package/dist/reply-buttons-controller.js +10 -6
  197. package/dist/reply-buttons-controller.js.map +1 -1
  198. package/dist/reply-polls.d.ts +2 -2
  199. package/dist/reply-polls.js +3 -3
  200. package/dist/reply-polls.js.map +1 -1
  201. package/dist/scheduler/db.d.ts +2 -1
  202. package/dist/scheduler/db.js +23 -9
  203. package/dist/scheduler/db.js.map +1 -1
  204. package/dist/scheduler/task-board.d.ts +9 -0
  205. package/dist/scheduler/task-board.js +19 -0
  206. package/dist/scheduler/task-board.js.map +1 -1
  207. package/dist/settings-api.d.ts +13 -5
  208. package/dist/settings-api.js +26 -96
  209. package/dist/settings-api.js.map +1 -1
  210. package/dist/settings-baseline.d.ts +0 -1
  211. package/dist/settings-baseline.js +1 -1
  212. package/dist/settings-baseline.js.map +1 -1
  213. package/dist/settings-change.js +23 -28
  214. package/dist/settings-change.js.map +1 -1
  215. package/dist/settings-confirmation.d.ts +1 -16
  216. package/dist/settings-confirmation.js +9 -47
  217. package/dist/settings-confirmation.js.map +1 -1
  218. package/dist/settings-effect.d.ts +0 -4
  219. package/dist/settings-effect.js +1 -58
  220. package/dist/settings-effect.js.map +1 -1
  221. package/dist/settings-http-confirmation.d.ts +0 -4
  222. package/dist/settings-http-confirmation.js +3 -31
  223. package/dist/settings-http-confirmation.js.map +1 -1
  224. package/dist/settings-instance-patch.js +28 -1
  225. package/dist/settings-instance-patch.js.map +1 -1
  226. package/dist/settings-request-capability.d.ts +0 -2
  227. package/dist/settings-request-capability.js +0 -4
  228. package/dist/settings-request-capability.js.map +1 -1
  229. package/dist/settings-transaction.d.ts +0 -4
  230. package/dist/settings-transaction.js +0 -9
  231. package/dist/settings-transaction.js.map +1 -1
  232. package/dist/setup-form.js +3 -6
  233. package/dist/setup-form.js.map +1 -1
  234. package/dist/setup-i18n.js +0 -3
  235. package/dist/setup-i18n.js.map +1 -1
  236. package/dist/task-board-tool.d.ts +11 -0
  237. package/dist/task-board-tool.js +44 -0
  238. package/dist/task-board-tool.js.map +1 -1
  239. package/dist/task-board-waker.d.ts +6 -0
  240. package/dist/task-board-waker.js +4 -0
  241. package/dist/task-board-waker.js.map +1 -1
  242. package/dist/tmux-control.d.ts +1 -2
  243. package/dist/tmux-control.js.map +1 -1
  244. package/dist/tmux-manager.d.ts +1 -2
  245. package/dist/tmux-manager.js.map +1 -1
  246. package/dist/tool-permissions.d.ts +5 -2
  247. package/dist/tool-permissions.js +7 -7
  248. package/dist/tool-permissions.js.map +1 -1
  249. package/dist/tool-progress.d.ts +2 -0
  250. package/dist/tool-progress.js +19 -3
  251. package/dist/tool-progress.js.map +1 -1
  252. package/dist/topic-commands.js +4 -3
  253. package/dist/topic-commands.js.map +1 -1
  254. package/dist/transcript-delta-reader.d.ts +1 -1
  255. package/dist/transcript-delta-reader.js +1 -1
  256. package/dist/transcript-delta-reader.js.map +1 -1
  257. package/dist/transcript-monitor.d.ts +20 -3
  258. package/dist/transcript-monitor.js +92 -24
  259. package/dist/transcript-monitor.js.map +1 -1
  260. package/dist/transcript-sources.d.ts +0 -5
  261. package/dist/transcript-sources.js +79 -8
  262. package/dist/transcript-sources.js.map +1 -1
  263. package/dist/types.d.ts +3 -23
  264. package/dist/ui/app.html +8 -1
  265. package/dist/ui/backend-signin.js +21 -36
  266. package/dist/ui/chat-md-strings.js +9 -0
  267. package/dist/ui/chat-store.js +2 -13
  268. package/dist/ui/chat-strings.js +2 -50
  269. package/dist/ui/chat-thread.js +53 -3
  270. package/dist/ui/fleet-task-card.js +3 -3
  271. package/dist/ui/fleet-task-common.js +10 -0
  272. package/dist/ui/fleet-tasks.js +7 -5
  273. package/dist/ui/fleet-usage.js +90 -27
  274. package/dist/ui/panel-chat.js +37 -66
  275. package/dist/ui/panel-details.js +1 -2
  276. package/dist/ui/panel-fleet.js +88 -107
  277. package/dist/ui/panel-needs.js +21 -163
  278. package/dist/ui/panel-notices.js +4 -3
  279. package/dist/ui/panel-settings.js +149 -239
  280. package/dist/ui/preview-panel.js +84 -6
  281. package/dist/ui/search-dialog.js +3 -2
  282. package/dist/ui/settings-appearance.js +23 -122
  283. package/dist/ui/settings-catalog.js +10 -37
  284. package/dist/ui/settings-codex-copy.js +19 -0
  285. package/dist/ui/settings-confirm.js +1 -3
  286. package/dist/ui/settings-dialogs.js +20 -27
  287. package/dist/ui/settings-guests.js +14 -27
  288. package/dist/ui/settings-model.js +17 -12
  289. package/dist/ui/settings-quota-notice.js +100 -0
  290. package/dist/ui/settings-registry.js +4 -11
  291. package/dist/ui/settings-strings.js +4 -113
  292. package/dist/ui/settings-web-authority.js +13 -15
  293. package/dist/ui/shared/app-i18n.js +2 -2
  294. package/dist/ui/shared/app-needs.js +1 -1
  295. package/dist/ui/shared/app-route.js +2 -6
  296. package/dist/ui/shared/app-shell.js +18 -23
  297. package/dist/ui/shared/app-store.js +2 -3
  298. package/dist/ui/shared/app-stream.js +1 -3
  299. package/dist/ui/shared/app.css +40 -1312
  300. package/dist/ui/shared/app.js +2 -5
  301. package/dist/ui/shared/header-tools.js +4 -6
  302. package/dist/ui/shared/instance-nav.js +7 -34
  303. package/dist/ui/shared/instance-switch.js +3 -4
  304. package/dist/ui/shared/loading.css +37 -0
  305. package/dist/ui/shared/panel-view.js +77 -4
  306. package/dist/ui/shared/signin.js +6 -39
  307. package/dist/ui/shared/tokens.css +0 -1
  308. package/dist/ui/shared/ui-dialog.js +2 -2
  309. package/dist/ui/shared/ui-menu.js +10 -30
  310. package/dist/ui/shared/ui-states.js +14 -3
  311. package/dist/ui/shared/usage-dialog.js +18 -1
  312. package/dist/ui/shared/vendor/vendor.json +2 -19
  313. package/dist/ui/shared/view-history.css +17 -0
  314. package/dist/ui/shared/view-history.js +438 -0
  315. package/dist/ui/shared/view-strings.js +16 -8
  316. package/dist/ui/signin.html +5 -2
  317. package/dist/unattended-install.d.ts +11 -2
  318. package/dist/unattended-install.js +39 -5
  319. package/dist/unattended-install.js.map +1 -1
  320. package/dist/usage/capacity.d.ts +69 -0
  321. package/dist/usage/capacity.js +119 -0
  322. package/dist/usage/capacity.js.map +1 -0
  323. package/dist/usage/i18n-keys.d.ts +1 -1
  324. package/dist/usage/i18n-keys.js +3 -0
  325. package/dist/usage/i18n-keys.js.map +1 -1
  326. package/dist/usage/profile-timeline.d.ts +16 -0
  327. package/dist/usage/profile-timeline.js +58 -0
  328. package/dist/usage/profile-timeline.js.map +1 -0
  329. package/dist/usage/providers.d.ts +5 -0
  330. package/dist/usage/providers.js +5 -0
  331. package/dist/usage/providers.js.map +1 -1
  332. package/dist/usage/quota-history.d.ts +43 -0
  333. package/dist/usage/quota-history.js +168 -0
  334. package/dist/usage/quota-history.js.map +1 -0
  335. package/dist/usage/quota-notices.d.ts +38 -0
  336. package/dist/usage/quota-notices.js +160 -0
  337. package/dist/usage/quota-notices.js.map +1 -0
  338. package/dist/usage/usage-api.d.ts +32 -0
  339. package/dist/usage/usage-api.js +96 -1
  340. package/dist/usage/usage-api.js.map +1 -1
  341. package/dist/usage-report.d.ts +25 -1
  342. package/dist/usage-report.js +55 -4
  343. package/dist/usage-report.js.map +1 -1
  344. package/dist/usage-rollup.d.ts +6 -1
  345. package/dist/usage-rollup.js +16 -4
  346. package/dist/usage-rollup.js.map +1 -1
  347. package/dist/view-api.d.ts +16 -0
  348. package/dist/view-api.js +100 -16
  349. package/dist/view-api.js.map +1 -1
  350. package/dist/view-history.d.ts +84 -0
  351. package/dist/view-history.js +116 -0
  352. package/dist/view-history.js.map +1 -0
  353. package/dist/web-api.d.ts +6 -38
  354. package/dist/web-api.js +20 -255
  355. package/dist/web-api.js.map +1 -1
  356. package/dist/web-chat-history.d.ts +2 -19
  357. package/dist/web-chat-history.js +3 -72
  358. package/dist/web-chat-history.js.map +1 -1
  359. package/dist/web-only-fleet.d.ts +0 -20
  360. package/dist/web-only-fleet.js +0 -21
  361. package/dist/web-only-fleet.js.map +1 -1
  362. package/dist/web-session-authorization.d.ts +13 -2
  363. package/dist/web-session-authorization.js +10 -3
  364. package/dist/web-session-authorization.js.map +1 -1
  365. package/dist/web-session.d.ts +0 -7
  366. package/dist/web-session.js +0 -2
  367. package/dist/web-session.js.map +1 -1
  368. package/dist/web-shell-routes.d.ts +1 -4
  369. package/dist/web-shell-routes.js +2 -7
  370. package/dist/web-shell-routes.js.map +1 -1
  371. package/launcher/private-home.cjs +1 -1
  372. package/package.json +3 -9
  373. package/dist/agent-runtime-api.d.ts +0 -4
  374. package/dist/agent-runtime-api.js +0 -59
  375. package/dist/agent-runtime-api.js.map +0 -1
  376. package/dist/agent-runtime-change.d.ts +0 -74
  377. package/dist/agent-runtime-change.js +0 -102
  378. package/dist/agent-runtime-change.js.map +0 -1
  379. package/dist/backend/grok-model-cache.d.ts +0 -7
  380. package/dist/backend/grok-model-cache.js +0 -65
  381. package/dist/backend/grok-model-cache.js.map +0 -1
  382. package/dist/backend/native-pane.d.ts +0 -9
  383. package/dist/backend/native-pane.js +0 -59
  384. package/dist/backend/native-pane.js.map +0 -1
  385. package/dist/fleet-windows-runtime.d.ts +0 -97
  386. package/dist/fleet-windows-runtime.js +0 -449
  387. package/dist/fleet-windows-runtime.js.map +0 -1
  388. package/dist/general-binding.d.ts +0 -85
  389. package/dist/general-binding.js +0 -298
  390. package/dist/general-binding.js.map +0 -1
  391. package/dist/general-host-owner.d.ts +0 -8
  392. package/dist/general-host-owner.js +0 -26
  393. package/dist/general-host-owner.js.map +0 -1
  394. package/dist/general-role.d.ts +0 -5
  395. package/dist/general-role.js +0 -26
  396. package/dist/general-role.js.map +0 -1
  397. package/dist/local-pane-endpoint.d.ts +0 -46
  398. package/dist/local-pane-endpoint.js +0 -189
  399. package/dist/local-pane-endpoint.js.map +0 -1
  400. package/dist/local-pane-launcher.d.ts +0 -2
  401. package/dist/local-pane-launcher.js +0 -38
  402. package/dist/local-pane-launcher.js.map +0 -1
  403. package/dist/local-pane-stage.ps1 +0 -101
  404. package/dist/model-catalog-defaults.d.ts +0 -14
  405. package/dist/model-catalog-defaults.js +0 -20
  406. package/dist/model-catalog-defaults.js.map +0 -1
  407. package/dist/native-agent-admission.d.ts +0 -7
  408. package/dist/native-agent-admission.js +0 -26
  409. package/dist/native-agent-admission.js.map +0 -1
  410. package/dist/native-daemon-client.d.ts +0 -13
  411. package/dist/native-daemon-client.js +0 -28
  412. package/dist/native-daemon-client.js.map +0 -1
  413. package/dist/native-instance-api.d.ts +0 -14
  414. package/dist/native-instance-api.js +0 -205
  415. package/dist/native-instance-api.js.map +0 -1
  416. package/dist/native-instance-input.d.ts +0 -84
  417. package/dist/native-instance-input.js +0 -54
  418. package/dist/native-instance-input.js.map +0 -1
  419. package/dist/native-instance-registry.d.ts +0 -32
  420. package/dist/native-instance-registry.js +0 -105
  421. package/dist/native-instance-registry.js.map +0 -1
  422. package/dist/native-mcp.d.ts +0 -40
  423. package/dist/native-mcp.js +0 -278
  424. package/dist/native-mcp.js.map +0 -1
  425. package/dist/native-model-catalog.d.ts +0 -5
  426. package/dist/native-model-catalog.js +0 -76
  427. package/dist/native-model-catalog.js.map +0 -1
  428. package/dist/native-pane-crash-budget.d.ts +0 -20
  429. package/dist/native-pane-crash-budget.js +0 -60
  430. package/dist/native-pane-crash-budget.js.map +0 -1
  431. package/dist/native-pane-create.d.ts +0 -26
  432. package/dist/native-pane-create.js +0 -53
  433. package/dist/native-pane-create.js.map +0 -1
  434. package/dist/native-pane-lifecycle.d.ts +0 -65
  435. package/dist/native-pane-lifecycle.js +0 -230
  436. package/dist/native-pane-lifecycle.js.map +0 -1
  437. package/dist/native-pane-manager.d.ts +0 -59
  438. package/dist/native-pane-manager.js +0 -584
  439. package/dist/native-pane-manager.js.map +0 -1
  440. package/dist/native-pane-output-log.d.ts +0 -15
  441. package/dist/native-pane-output-log.js +0 -108
  442. package/dist/native-pane-output-log.js.map +0 -1
  443. package/dist/native-pane-reconciliation.d.ts +0 -4
  444. package/dist/native-pane-reconciliation.js +0 -40
  445. package/dist/native-pane-reconciliation.js.map +0 -1
  446. package/dist/native-pane-recovery.d.ts +0 -12
  447. package/dist/native-pane-recovery.js +0 -10
  448. package/dist/native-pane-recovery.js.map +0 -1
  449. package/dist/native-pane-tools.d.ts +0 -2
  450. package/dist/native-pane-tools.js +0 -14
  451. package/dist/native-pane-tools.js.map +0 -1
  452. package/dist/pane-port.d.ts +0 -118
  453. package/dist/pane-port.js +0 -2
  454. package/dist/pane-port.js.map +0 -1
  455. package/dist/runtime-api.d.ts +0 -8
  456. package/dist/runtime-api.js +0 -171
  457. package/dist/runtime-api.js.map +0 -1
  458. package/dist/runtime-assets/@xterm/addon-serialize/LICENSE +0 -21
  459. package/dist/runtime-assets/@xterm/addon-serialize/lib/addon-serialize.js +0 -2
  460. package/dist/runtime-assets/@xterm/addon-serialize/lib/addon-serialize.mjs +0 -19
  461. package/dist/runtime-assets/@xterm/addon-serialize/package.json +0 -29
  462. package/dist/runtime-assets/@xterm/headless/LICENSE +0 -21
  463. package/dist/runtime-assets/@xterm/headless/lib-headless/xterm-headless.js +0 -2
  464. package/dist/runtime-assets/@xterm/headless/lib-headless/xterm-headless.mjs +0 -46
  465. package/dist/runtime-assets/@xterm/headless/package.json +0 -29
  466. package/dist/runtime-assets/node-pty/CONPTY-LICENSE +0 -21
  467. package/dist/runtime-assets/node-pty/CONPTY-NOTICE.md +0 -503
  468. package/dist/runtime-assets/node-pty/LICENSE +0 -69
  469. package/dist/runtime-assets/node-pty/lib/conpty_console_list_agent.js +0 -16
  470. package/dist/runtime-assets/node-pty/lib/eventEmitter2.js +0 -47
  471. package/dist/runtime-assets/node-pty/lib/index.js +0 -52
  472. package/dist/runtime-assets/node-pty/lib/interfaces.js +0 -7
  473. package/dist/runtime-assets/node-pty/lib/shared/conout.js +0 -11
  474. package/dist/runtime-assets/node-pty/lib/terminal.js +0 -190
  475. package/dist/runtime-assets/node-pty/lib/types.js +0 -7
  476. package/dist/runtime-assets/node-pty/lib/unixTerminal.js +0 -346
  477. package/dist/runtime-assets/node-pty/lib/utils.js +0 -39
  478. package/dist/runtime-assets/node-pty/lib/windowsConoutConnection.js +0 -125
  479. package/dist/runtime-assets/node-pty/lib/windowsPtyAgent.js +0 -320
  480. package/dist/runtime-assets/node-pty/lib/windowsTerminal.js +0 -199
  481. package/dist/runtime-assets/node-pty/lib/worker/conoutSocketWorker.js +0 -22
  482. package/dist/runtime-assets/node-pty/package.json +0 -64
  483. package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
  484. package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
  485. package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
  486. package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
  487. package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
  488. package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
  489. package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty.node +0 -0
  490. package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
  491. package/dist/runtime-build-info.d.ts +0 -9
  492. package/dist/runtime-build-info.js +0 -57
  493. package/dist/runtime-build-info.js.map +0 -1
  494. package/dist/runtime-bundle.d.ts +0 -19
  495. package/dist/runtime-bundle.js +0 -156
  496. package/dist/runtime-bundle.js.map +0 -1
  497. package/dist/runtime-cli.d.ts +0 -7
  498. package/dist/runtime-cli.js +0 -152
  499. package/dist/runtime-cli.js.map +0 -1
  500. package/dist/runtime-client-store.d.ts +0 -68
  501. package/dist/runtime-client-store.js +0 -344
  502. package/dist/runtime-client-store.js.map +0 -1
  503. package/dist/runtime-client.d.ts +0 -112
  504. package/dist/runtime-client.js +0 -736
  505. package/dist/runtime-client.js.map +0 -1
  506. package/dist/runtime-connection.d.ts +0 -22
  507. package/dist/runtime-connection.js +0 -93
  508. package/dist/runtime-connection.js.map +0 -1
  509. package/dist/runtime-coordinator.d.ts +0 -91
  510. package/dist/runtime-coordinator.js +0 -911
  511. package/dist/runtime-coordinator.js.map +0 -1
  512. package/dist/runtime-general-protocol.d.ts +0 -22
  513. package/dist/runtime-general-protocol.js +0 -57
  514. package/dist/runtime-general-protocol.js.map +0 -1
  515. package/dist/runtime-general-workspace.d.ts +0 -17
  516. package/dist/runtime-general-workspace.js +0 -213
  517. package/dist/runtime-general-workspace.js.map +0 -1
  518. package/dist/runtime-pane-assets.d.ts +0 -17
  519. package/dist/runtime-pane-assets.js +0 -23
  520. package/dist/runtime-pane-assets.js.map +0 -1
  521. package/dist/runtime-pane-boot.d.ts +0 -9
  522. package/dist/runtime-pane-boot.js +0 -47
  523. package/dist/runtime-pane-boot.js.map +0 -1
  524. package/dist/runtime-pane-codex-index.d.ts +0 -1
  525. package/dist/runtime-pane-codex-index.js +0 -47
  526. package/dist/runtime-pane-codex-index.js.map +0 -1
  527. package/dist/runtime-pane-config.d.ts +0 -16
  528. package/dist/runtime-pane-config.js +0 -54
  529. package/dist/runtime-pane-config.js.map +0 -1
  530. package/dist/runtime-pane-host.d.ts +0 -44
  531. package/dist/runtime-pane-host.js +0 -424
  532. package/dist/runtime-pane-host.js.map +0 -1
  533. package/dist/runtime-pane-job-owner.d.ts +0 -1
  534. package/dist/runtime-pane-job-owner.js +0 -29
  535. package/dist/runtime-pane-job-owner.js.map +0 -1
  536. package/dist/runtime-pane-job.ps1 +0 -116
  537. package/dist/runtime-pane-link.d.ts +0 -40
  538. package/dist/runtime-pane-link.js +0 -246
  539. package/dist/runtime-pane-link.js.map +0 -1
  540. package/dist/runtime-pane-mcp-protocol.d.ts +0 -32
  541. package/dist/runtime-pane-mcp-protocol.js +0 -39
  542. package/dist/runtime-pane-mcp-protocol.js.map +0 -1
  543. package/dist/runtime-pane-mcp-relay.d.ts +0 -17
  544. package/dist/runtime-pane-mcp-relay.js +0 -70
  545. package/dist/runtime-pane-mcp-relay.js.map +0 -1
  546. package/dist/runtime-pane-mcp.d.ts +0 -51
  547. package/dist/runtime-pane-mcp.js +0 -150
  548. package/dist/runtime-pane-mcp.js.map +0 -1
  549. package/dist/runtime-pane-native.d.ts +0 -45
  550. package/dist/runtime-pane-native.js +0 -65
  551. package/dist/runtime-pane-native.js.map +0 -1
  552. package/dist/runtime-pane-output.d.ts +0 -19
  553. package/dist/runtime-pane-output.js +0 -53
  554. package/dist/runtime-pane-output.js.map +0 -1
  555. package/dist/runtime-pane-port.d.ts +0 -139
  556. package/dist/runtime-pane-port.js +0 -558
  557. package/dist/runtime-pane-port.js.map +0 -1
  558. package/dist/runtime-pane-private.d.ts +0 -14
  559. package/dist/runtime-pane-private.js +0 -51
  560. package/dist/runtime-pane-private.js.map +0 -1
  561. package/dist/runtime-pane-private.ps1 +0 -14
  562. package/dist/runtime-pane-process.d.ts +0 -4
  563. package/dist/runtime-pane-process.js +0 -108
  564. package/dist/runtime-pane-process.js.map +0 -1
  565. package/dist/runtime-pane-protocol.d.ts +0 -172
  566. package/dist/runtime-pane-protocol.js +0 -195
  567. package/dist/runtime-pane-protocol.js.map +0 -1
  568. package/dist/runtime-pane-screen.d.ts +0 -19
  569. package/dist/runtime-pane-screen.js +0 -76
  570. package/dist/runtime-pane-screen.js.map +0 -1
  571. package/dist/runtime-pane-service.d.ts +0 -11
  572. package/dist/runtime-pane-service.js +0 -221
  573. package/dist/runtime-pane-service.js.map +0 -1
  574. package/dist/runtime-pane-stdio-protocol.d.ts +0 -54
  575. package/dist/runtime-pane-stdio-protocol.js +0 -94
  576. package/dist/runtime-pane-stdio-protocol.js.map +0 -1
  577. package/dist/runtime-pane-stdio.d.ts +0 -3
  578. package/dist/runtime-pane-stdio.js +0 -123
  579. package/dist/runtime-pane-stdio.js.map +0 -1
  580. package/dist/runtime-pane-store.d.ts +0 -33
  581. package/dist/runtime-pane-store.js +0 -164
  582. package/dist/runtime-pane-store.js.map +0 -1
  583. package/dist/runtime-pane-transcript-protocol.d.ts +0 -43
  584. package/dist/runtime-pane-transcript-protocol.js +0 -58
  585. package/dist/runtime-pane-transcript-protocol.js.map +0 -1
  586. package/dist/runtime-pane-transcript.d.ts +0 -45
  587. package/dist/runtime-pane-transcript.js +0 -605
  588. package/dist/runtime-pane-transcript.js.map +0 -1
  589. package/dist/runtime-pane-worker.d.ts +0 -1
  590. package/dist/runtime-pane-worker.js +0 -154
  591. package/dist/runtime-pane-worker.js.map +0 -1
  592. package/dist/runtime-protocol.d.ts +0 -162
  593. package/dist/runtime-protocol.js +0 -37
  594. package/dist/runtime-protocol.js.map +0 -1
  595. package/dist/runtime-switches.d.ts +0 -79
  596. package/dist/runtime-switches.js +0 -90
  597. package/dist/runtime-switches.js.map +0 -1
  598. package/dist/runtime-transcript-delta-reader.d.ts +0 -23
  599. package/dist/runtime-transcript-delta-reader.js +0 -74
  600. package/dist/runtime-transcript-delta-reader.js.map +0 -1
  601. package/dist/runtime-transcript-source.d.ts +0 -36
  602. package/dist/runtime-transcript-source.js +0 -189
  603. package/dist/runtime-transcript-source.js.map +0 -1
  604. package/dist/runtime-windows-bridge.d.ts +0 -41
  605. package/dist/runtime-windows-bridge.js +0 -157
  606. package/dist/runtime-windows-bridge.js.map +0 -1
  607. package/dist/settings-route-lifetime.d.ts +0 -14
  608. package/dist/settings-route-lifetime.js +0 -48
  609. package/dist/settings-route-lifetime.js.map +0 -1
  610. package/dist/tmux-pane-host.d.ts +0 -26
  611. package/dist/tmux-pane-host.js +0 -25
  612. package/dist/tmux-pane-host.js.map +0 -1
  613. package/dist/transcript-needles.d.ts +0 -35
  614. package/dist/transcript-needles.js +0 -158
  615. package/dist/transcript-needles.js.map +0 -1
  616. package/dist/transcript-records.d.ts +0 -21
  617. package/dist/transcript-records.js +0 -140
  618. package/dist/transcript-records.js.map +0 -1
  619. package/dist/ui/agent-proposals.js +0 -90
  620. package/dist/ui/agent-runtime-settings.js +0 -67
  621. package/dist/ui/agent-runtime.js +0 -124
  622. package/dist/ui/cli-picker.js +0 -42
  623. package/dist/ui/general-location.js +0 -71
  624. package/dist/ui/native-instance-settings.js +0 -44
  625. package/dist/ui/native-pane-recovery.js +0 -45
  626. package/dist/ui/panel-runtimes.js +0 -334
  627. package/dist/ui/panel-windows-agent.js +0 -86
  628. package/dist/ui/panel-windows-cli.js +0 -179
  629. package/dist/ui/provider-marks.js +0 -83
  630. package/dist/ui/runtime-catalog.js +0 -55
  631. package/dist/ui/settings-agent-filters.js +0 -94
  632. package/dist/ui/settings-layout.js +0 -245
  633. package/dist/ui/settings-outside.js +0 -176
  634. package/dist/ui/settings-shortcuts.js +0 -65
  635. package/dist/ui/shared/machine-name.js +0 -13
  636. package/dist/ui/shared/qrcode.module.js +0 -2237
  637. package/dist/ui/shared/settings-width.js +0 -31
  638. package/dist/ui/shared/vendor/qrcode-generator.LICENSE +0 -27
  639. package/dist/ui/windows-agents-nav.js +0 -2
  640. package/dist/ui/windows-cli-catalog.js +0 -108
  641. package/dist/web-remote-access.d.ts +0 -152
  642. package/dist/web-remote-access.js +0 -368
  643. package/dist/web-remote-access.js.map +0 -1
  644. package/dist/windows-agents.d.ts +0 -126
  645. package/dist/windows-agents.js +0 -490
  646. package/dist/windows-agents.js.map +0 -1
  647. package/dist/windows-cli-api.d.ts +0 -23
  648. package/dist/windows-cli-api.js +0 -159
  649. package/dist/windows-cli-api.js.map +0 -1
  650. package/dist/windows-cli-providers.d.ts +0 -115
  651. package/dist/windows-cli-providers.js +0 -429
  652. package/dist/windows-cli-providers.js.map +0 -1
  653. package/dist/windows-cli-worker.d.ts +0 -59
  654. package/dist/windows-cli-worker.js +0 -479
  655. package/dist/windows-cli-worker.js.map +0 -1
  656. package/dist/windows-cli.d.ts +0 -116
  657. package/dist/windows-cli.js +0 -407
  658. package/dist/windows-cli.js.map +0 -1
  659. package/dist/windows-native-mcp.d.ts +0 -19
  660. package/dist/windows-native-mcp.js +0 -143
  661. package/dist/windows-native-mcp.js.map +0 -1
  662. package/dist/windows-pane-mcp.d.ts +0 -26
  663. package/dist/windows-pane-mcp.js +0 -187
  664. package/dist/windows-pane-mcp.js.map +0 -1
  665. package/templates/runtime-assets/conpty-LICENSE +0 -21
  666. package/templates/runtime-assets/conpty-NOTICE.md +0 -503
  667. package/templates/runtime-assets/local-pane-stage.ps1 +0 -101
  668. package/templates/runtime-assets/runtime-pane-job.ps1 +0 -116
  669. package/templates/runtime-assets/runtime-pane-private.ps1 +0 -14
  670. package/templates/runtime-assets/xterm-LICENSE +0 -21
@@ -1,911 +0,0 @@
1
- /** Durable machine registration and outbound-client transport; never starts a remote shell. */
2
- import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
3
- import { existsSync, lstatSync, mkdirSync, readFileSync } from "node:fs";
4
- import { join } from "node:path";
5
- import { WebSocket, WebSocketServer } from "ws";
6
- import { readBoundedWebBody } from "./web-body.js";
7
- import { atomicWriteFileSync } from "./atomic-write.js";
8
- import { validateNativeTask } from "./windows-cli-worker.js";
9
- import { inventoryProbed } from "./windows-cli.js";
10
- import { isNativeProviderId } from "./windows-cli-providers.js";
11
- import { validatePaneMcpBody } from "./runtime-pane-mcp-protocol.js";
12
- import { validateRuntimePaneRequest, validateRuntimePaneSnapshot, validateRuntimePaneShutdown } from "./runtime-pane-protocol.js";
13
- import { RUNTIME_CLAIM_PATH, RUNTIME_CONNECT_PATH, RUNTIME_MAX_FRAME_BYTES, RUNTIME_PAIR_PATH, RUNTIME_ROTATE_PATH, runtimeFingerprintFromHash, parseRuntimeInfo, RUNTIME_PROTOCOL_VERSION } from "./runtime-protocol.js";
14
- const PAIR_TTL = 10 * 60_000;
15
- const MAX_STORE_BYTES = 64 * 1024 * 1024;
16
- const UUID = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
17
- const secret = () => randomBytes(32).toString("hex");
18
- const hash = (value) => createHash("sha256").update(value).digest("hex");
19
- const equal = (value, digest) => /^[a-f0-9]{64}$/i.test(digest) && timingSafeEqual(Buffer.from(hash(value), "hex"), Buffer.from(digest, "hex"));
20
- const record = (v) => !!v && typeof v === "object" && !Array.isArray(v);
21
- /** A deliberate validation failure whose static message is safe to show the runtime; every other error (I/O, internal) is not. */
22
- class RuntimeProtocolError extends Error {
23
- }
24
- const text = (v, max) => typeof v === "string" && v.length > 0 && v.length <= max && !/[\0\r\n]/.test(v);
25
- const terminal = (task) => !!task.finishedAt && ["completed", "failed", "cancelled"].includes(task.status);
26
- const loopback = (address) => address === "127.0.0.1" || address === "::1" || address === "::ffff:127.0.0.1";
27
- function privateTransport(req) {
28
- return req.headers.origin === undefined && req.headers.cookie === undefined
29
- && (loopback(req.socket.remoteAddress) || req.socket.encrypted === true);
30
- }
31
- function stable(value, depth = 0) {
32
- if (depth > 64)
33
- throw Error("Runtime request is too deeply nested");
34
- if (Array.isArray(value))
35
- return `[${value.map(value => stable(value, depth + 1)).join(",")}]`;
36
- if (record(value))
37
- return `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${stable(value[key], depth + 1)}`).join(",")}}`;
38
- return JSON.stringify(value) ?? "null";
39
- }
40
- function inventory(value) {
41
- if (!record(value) || typeof value.home !== "string" || value.home.length > 1024 || !Array.isArray(value.clis) || value.clis.length > 16)
42
- throw new RuntimeProtocolError("Invalid runtime inventory");
43
- const seen = new Set();
44
- for (const row of value.clis) {
45
- if (!record(row) || !isNativeProviderId(row.id) || seen.has(row.id) || !record(row.supports)
46
- || typeof row.runnable !== "boolean" || typeof row.readOnlySupport !== "boolean"
47
- || ![true, false, null].includes(row.authenticated)
48
- || !(row.path === null || text(row.path, 2048)) || !(row.version === null || text(row.version, 256))
49
- || typeof row.permissionNote !== "string" || row.permissionNote.length > 2048
50
- || !Array.isArray(row.models) || row.models.length > 256)
51
- throw new RuntimeProtocolError("Invalid runtime CLI inventory");
52
- for (const model of row.models)
53
- if (!record(model) || !text(model.id, 256) || model.name !== undefined && !text(model.name, 256)
54
- || model.description !== undefined && (typeof model.description !== "string" || model.description.length > 2048))
55
- throw new RuntimeProtocolError("Invalid runtime model inventory");
56
- if (Object.values(row.supports).some(v => typeof v !== "boolean"))
57
- throw new RuntimeProtocolError("Invalid runtime capabilities");
58
- seen.add(row.id);
59
- }
60
- if (Buffer.byteLength(JSON.stringify(value)) > RUNTIME_MAX_FRAME_BYTES / 2)
61
- throw new RuntimeProtocolError("Runtime inventory is too large");
62
- return structuredClone(value);
63
- }
64
- function machineView(machine) {
65
- return { ...structuredClone(machine), runtimeCompatibility: machine.runtimeInfo
66
- ? machine.runtimeInfo.protocolVersions.includes(RUNTIME_PROTOCOL_VERSION) ? "compatible" : "incompatible"
67
- : machine.bootId ? "legacy" : "unknown" };
68
- }
69
- /**
70
- * M-2239 P2-1 (#2936 review): the journal is compacted, never just capped. A settled command (failed, or accepted with a
71
- * terminal, process-confirmed outcome) older than COMMAND_KEEP_MS, or the oldest settled ones beyond COMMAND_SOFT_CAP,
72
- * become tombstones; pending and uncertain commands are never compacted. Tombstones are evicted only beyond
73
- * TOMBSTONE_CAP and only when older than TOMBSTONE_KEEP_MS — a replayed id is refused for at least that long.
74
- */
75
- const COMMAND_HARD_CAP = 4096, COMMAND_SOFT_CAP = 2048, COMMAND_KEEP_MS = 7 * 24 * 3_600_000;
76
- const TOMBSTONE_CAP = 65_536, TOMBSTONE_KEEP_MS = 30 * 24 * 3_600_000;
77
- /**
78
- * alpha.2 polish: what an interrupted command becomes. A probe only reads the runner's CLI inventory — nothing to reconcile
79
- * if its answer was lost — so it settles as failed (compacted like any settled command); every other operation stays
80
- * uncertain (never compacted, never sent again). The automatic probe on connect must not leave a trail in the journal.
81
- */
82
- const interrupted = (command) => command.operation === "probe" ? "failed" : "uncertain";
83
- export class RuntimeCoordinator {
84
- options;
85
- paneEpoch = randomUUID();
86
- path;
87
- state;
88
- server = new WebSocketServer({ noServer: true, maxPayload: RUNTIME_MAX_FRAME_BYTES, perMessageDeflate: false });
89
- connections = new Map();
90
- pending = new Map();
91
- paneToolPending = new Set();
92
- panePending = new Map();
93
- listeners = new Set();
94
- limits = new Map();
95
- heartbeat;
96
- closed = false;
97
- constructor(home, options = {}) {
98
- this.options = options;
99
- mkdirSync(home, { recursive: true, mode: 0o700 });
100
- this.path = join(home, "runtime-machines.json");
101
- if (existsSync(this.path)) {
102
- const stat = lstatSync(this.path);
103
- if (!stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_STORE_BYTES)
104
- throw Error("Invalid runtime machine store file");
105
- }
106
- this.state = existsSync(this.path) ? JSON.parse(readFileSync(this.path, "utf8")) : { version: 1, machines: [], pairings: [], commands: [] };
107
- if (this.state.version !== 1 || !Array.isArray(this.state.machines) || !Array.isArray(this.state.pairings) || !Array.isArray(this.state.commands)
108
- || this.state.tombstones !== undefined && !Array.isArray(this.state.tombstones))
109
- throw Error("Invalid runtime machine store");
110
- this.state.tombstones ??= [];
111
- if (this.state.machines.length > 256 || this.state.pairings.length > 16 || this.state.commands.length > COMMAND_HARD_CAP || this.state.tombstones.length > TOMBSTONE_CAP
112
- || this.state.tombstones.some(row => !record(row) || !text(row.id, 128) || !UUID.test(String(row.machineId)) || !/^[a-f0-9]{64}$/.test(row.digest) || !Number.isFinite(row.at))
113
- || this.state.machines.some(row => !record(row) || !record(row.machine) || !UUID.test(String(row.machine.id)) || !text(row.machine.name, 100)
114
- || row.machine.platform !== "win32" || !["pending", "offline", "online", "revoked"].includes(String(row.machine.status))
115
- || !Number.isSafeInteger(row.machine.generation) || row.machine.generation < 0
116
- || row.machine.pairingFingerprint !== undefined && (typeof row.machine.pairingFingerprint !== "string" || !/^[A-F0-9]{4}(?:-[A-F0-9]{4}){2}$/.test(row.machine.pairingFingerprint))
117
- || row.credentialHash !== undefined && !/^[a-f0-9]{64}$/.test(row.credentialHash)
118
- || row.claimHash !== undefined && !/^[a-f0-9]{64}$/.test(row.claimHash))
119
- || new Set(this.state.machines.map(row => row.machine.id)).size !== this.state.machines.length
120
- || this.state.pairings.some(row => !record(row) || !UUID.test(String(row.id)) || !/^[a-f0-9]{64}$/.test(row.codeHash) || !Number.isFinite(row.expiresAt))
121
- || this.state.commands.some(row => !record(row) || !text(row.id, 128) || !UUID.test(String(row.machineId)) || !/^[a-f0-9]{64}$/.test(row.digest)
122
- || !["probe", "workspace", "run", "cancel", "reconcile", "recover"].includes(row.operation)
123
- || !["pending", "accepted", "failed", "uncertain"].includes(row.state) || !Number.isSafeInteger(row.seq) || row.seq < 0))
124
- throw Error("Malformed runtime machine store");
125
- // A coordinator restart never grants execution authority or redelivers an in-flight command.
126
- for (const row of this.state.machines) {
127
- if (row.machine.status === "online")
128
- row.machine.status = "offline";
129
- if (row.claimHash)
130
- row.machine.pairingFingerprint = runtimeFingerprintFromHash(row.claimHash);
131
- }
132
- for (const command of this.state.commands)
133
- if (command.state === "pending")
134
- command.state = interrupted(command);
135
- for (const row of this.state.machines)
136
- if (row.machine.runtimeInfo !== undefined)
137
- row.machine.runtimeInfo = parseRuntimeInfo(row.machine.runtimeInfo);
138
- this.save();
139
- this.heartbeat = setInterval(() => {
140
- for (const connection of this.connections.values()) {
141
- if (!connection.alive) {
142
- connection.ws.terminate();
143
- continue;
144
- }
145
- connection.alive = false;
146
- connection.ws.ping();
147
- }
148
- }, 15_000);
149
- this.heartbeat.unref();
150
- }
151
- now() { return this.options.now?.() ?? Date.now(); }
152
- save() {
153
- const value = JSON.stringify(this.state);
154
- if (Buffer.byteLength(value) > MAX_STORE_BYTES)
155
- throw Error("Runtime machine journal limit reached");
156
- for (let attempt = 0;; attempt++) {
157
- try {
158
- atomicWriteFileSync(this.path, value, { mode: 0o600 });
159
- return;
160
- }
161
- catch (error) {
162
- // Windows scanners can briefly hold a destination open; retain atomic replacement and a bounded retry.
163
- if (process.platform !== "win32" || attempt >= 4 || !["EPERM", "EACCES", "EBUSY"].includes(error.code ?? ""))
164
- throw error;
165
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10 * (attempt + 1));
166
- }
167
- }
168
- }
169
- emit(event) {
170
- try {
171
- this.options.changed?.(event);
172
- }
173
- catch { /* UI observers cannot change the durable verdict. */ }
174
- for (const listener of this.listeners) {
175
- try {
176
- listener(structuredClone(event));
177
- }
178
- catch { /* Observer isolation. */ }
179
- }
180
- }
181
- entry(id) { const row = this.state.machines.find(v => v.machine.id === id); if (!row)
182
- throw Error("Runtime machine not found"); return row; }
183
- listMachines() { return this.state.machines.map(row => machineView(row.machine)); }
184
- machine(id) { const row = this.state.machines.find(v => v.machine.id === id); return row ? machineView(row.machine) : null; }
185
- subscribe(listener) { this.listeners.add(listener); return () => this.listeners.delete(listener); }
186
- createPairing() {
187
- this.state.pairings = this.state.pairings.filter(row => row.expiresAt > this.now());
188
- if (this.state.pairings.length >= 16)
189
- throw Error("Too many pending runtime pairing codes");
190
- const code = randomBytes(6).toString("hex").toUpperCase(), pairingId = randomUUID(), expiresAt = this.now() + PAIR_TTL;
191
- this.state.pairings.push({ id: pairingId, codeHash: hash(code), expiresAt });
192
- this.save();
193
- return { pairingId, code: code.match(/.{4}/g).join("-"), expiresAt };
194
- }
195
- pair(input) {
196
- if (!record(input) || Object.keys(input).some(k => !["code", "name", "platform", "hostname"].includes(k))
197
- || !text(input.code, 32) || !text(input.name, 100) || !input.name.trim() || input.platform !== "win32"
198
- || input.hostname !== undefined && !text(input.hostname, 255))
199
- throw Error("Invalid runtime pairing request");
200
- if (this.state.machines.length >= 256 || this.state.machines.filter(row => row.machine.status !== "revoked").length >= 64)
201
- throw Error("Runtime machine limit reached");
202
- const code = input.code.replaceAll("-", "").toUpperCase();
203
- const pairing = this.state.pairings.find(row => row.expiresAt > this.now() && equal(code, row.codeHash));
204
- if (!pairing)
205
- throw Error("Pairing code is invalid, used or expired");
206
- const machineId = randomUUID(), claimSecret = secret();
207
- this.state.pairings = this.state.pairings.filter(row => row !== pairing);
208
- this.state.machines.push({ machine: { id: machineId, name: input.name.trim(), platform: "win32", ...(input.hostname ? { hostname: input.hostname } : {}), status: "pending", createdAt: this.now(), generation: 0, pairingFingerprint: runtimeFingerprintFromHash(hash(claimSecret)) }, claimHash: hash(claimSecret), claimExpiresAt: pairing.expiresAt });
209
- this.save();
210
- this.emit({ type: "machine", machineId });
211
- return { machineId, claimSecret, status: "pending", expiresAt: pairing.expiresAt };
212
- }
213
- claim(input) {
214
- if (!record(input) || Object.keys(input).some(k => !["machineId", "claimSecret"].includes(k)) || !text(input.machineId, 64) || !text(input.claimSecret, 128))
215
- throw Error("Invalid runtime claim");
216
- const row = this.state.machines.find(row => row.machine.id === input.machineId);
217
- if (!row?.claimHash || !row.claimExpiresAt || row.claimExpiresAt <= this.now() || !equal(input.claimSecret, row.claimHash) || row.machine.status === "revoked")
218
- throw Error("Runtime claim is invalid or expired");
219
- if (!row.machine.approvedAt)
220
- return { status: "pending" };
221
- const credential = secret();
222
- row.credentialHash = hash(credential);
223
- delete row.claimHash;
224
- delete row.claimExpiresAt;
225
- this.save();
226
- return { machineId: row.machine.id, credential, status: "approved" };
227
- }
228
- approve(id, fingerprint) {
229
- const row = this.entry(id);
230
- if (row.machine.status !== "pending" || !row.claimExpiresAt || row.claimExpiresAt <= this.now())
231
- throw Error("Runtime pairing is no longer pending");
232
- if (!fingerprint || fingerprint !== row.machine.pairingFingerprint)
233
- throw Error("Compare the pairing fingerprint shown by this Runtime before approving");
234
- row.machine.approvedAt = this.now();
235
- row.machine.status = "offline";
236
- this.save();
237
- this.emit({ type: "machine", machineId: id });
238
- return structuredClone(row.machine);
239
- }
240
- rename(id, name) {
241
- if (!text(name, 100) || !name.trim())
242
- throw Error("Invalid runtime machine name");
243
- const row = this.entry(id);
244
- row.machine.name = name.trim();
245
- this.save();
246
- this.emit({ type: "machine", machineId: id });
247
- return structuredClone(row.machine);
248
- }
249
- revoke(id) {
250
- const row = this.entry(id);
251
- row.machine.status = "revoked";
252
- delete row.credentialHash;
253
- delete row.claimHash;
254
- delete row.claimExpiresAt;
255
- this.save();
256
- const connection = this.connections.get(id);
257
- if (connection) {
258
- this.connections.delete(id);
259
- this.rejectPending(connection, "Runtime machine was revoked");
260
- this.options.warn?.({ machineId: id, code: 1008, reason: "Machine revoked" }, "Runtime connection closed because the machine was revoked");
261
- connection.ws.close(1008, "Machine revoked");
262
- }
263
- this.emit({ type: "machine", machineId: id });
264
- return structuredClone(row.machine);
265
- }
266
- credentialOwner(auth) {
267
- if (typeof auth !== "string" || !/^Bearer [a-f0-9]{64}$/i.test(auth))
268
- return;
269
- return this.state.machines.find(row => row.credentialHash && row.machine.status !== "revoked" && row.machine.approvedAt && equal(auth.slice(7), row.credentialHash));
270
- }
271
- /** Valid capabilities never share the invalid-traffic bucket of a loopback proxy. Forwarding headers are untrusted. */
272
- rate(key, limit) {
273
- const now = this.now();
274
- for (const [id, value] of this.limits)
275
- if (value.until <= now)
276
- this.limits.delete(id);
277
- if (!this.limits.has(key) && this.limits.size >= 512) {
278
- const invalid = [...this.limits.keys()].find(id => id.startsWith("invalid:"));
279
- if (!invalid || key.startsWith("invalid:"))
280
- return false;
281
- this.limits.delete(invalid);
282
- }
283
- const old = this.limits.get(key), row = old && old.until > now ? old : { count: 0, until: now + 60_000 };
284
- this.limits.set(key, row);
285
- return ++row.count <= limit;
286
- }
287
- requestRateKey(path, input, req) {
288
- if (path === RUNTIME_ROTATE_PATH) {
289
- const row = this.credentialOwner(req.headers.authorization);
290
- if (row)
291
- return `rotate:${row.machine.id}`;
292
- }
293
- else if (record(input)) {
294
- if (path === RUNTIME_PAIR_PATH && text(input.code, 32)) {
295
- const code = input.code.replaceAll("-", "").toUpperCase();
296
- const row = this.state.pairings.find(row => row.expiresAt > this.now() && equal(code, row.codeHash));
297
- if (row)
298
- return `pair:${row.id}`;
299
- }
300
- if (path === RUNTIME_CLAIM_PATH && text(input.claimSecret, 128)) {
301
- const row = this.state.machines.find(row => row.machine.id === input.machineId && row.claimHash && row.claimExpiresAt > this.now()
302
- && row.machine.status !== "revoked" && equal(input.claimSecret, row.claimHash));
303
- if (row)
304
- return `claim:${row.machine.id}`;
305
- }
306
- }
307
- return `invalid:${req.socket.remoteAddress ?? "unknown"}`;
308
- }
309
- rotateCredential(auth, input) {
310
- const row = this.credentialOwner(auth);
311
- if (!row || !record(input) || Object.keys(input).some(key => !["machineId", "credential"].includes(key))
312
- || input.machineId !== row.machine.id || typeof input.credential !== "string" || !/^[a-f0-9]{64}$/.test(input.credential))
313
- throw Error("Invalid runtime credential rotation");
314
- if (!equal(input.credential, row.credentialHash)) {
315
- const before = { credentialHash: row.credentialHash, status: row.machine.status };
316
- row.credentialHash = hash(input.credential);
317
- row.machine.status = "offline";
318
- try {
319
- this.save();
320
- }
321
- catch (error) {
322
- row.credentialHash = before.credentialHash;
323
- row.machine.status = before.status;
324
- throw error;
325
- }
326
- const connection = this.connections.get(row.machine.id);
327
- if (connection) {
328
- this.connections.delete(row.machine.id);
329
- this.rejectPending(connection, "Runtime credential rotated; reconnect to reconcile");
330
- connection.ws.close(1012, "Credential rotated");
331
- }
332
- this.emit({ type: "machine", machineId: row.machine.id });
333
- }
334
- return { machineId: row.machine.id, status: "rotated" };
335
- }
336
- handlePublicRequest(req, res, url) {
337
- if (![RUNTIME_PAIR_PATH, RUNTIME_CLAIM_PATH, RUNTIME_ROTATE_PATH].includes(url.pathname))
338
- return false;
339
- const answer = (status, body) => { if (!res.destroyed && !res.writableEnded) {
340
- res.writeHead(status, { "Content-Type": "application/json", "Cache-Control": "no-store" });
341
- res.end(JSON.stringify(body));
342
- } };
343
- if (this.closed || req.method !== "POST" || url.search || !privateTransport(req)) {
344
- answer(403, { error: "Runtime pairing requires a protected non-browser connection" });
345
- return true;
346
- }
347
- let charged = false;
348
- void readBoundedWebBody(req, 4096).then(bytes => {
349
- const value = JSON.parse(bytes.toString("utf8"));
350
- if (this.closed) {
351
- answer(403, { error: "Runtime coordinator is closed" });
352
- return;
353
- }
354
- const key = this.requestRateKey(url.pathname, value, req);
355
- charged = true;
356
- if (!this.rate(key, key.startsWith("claim:") ? 120 : 30)) {
357
- answer(429, { error: "Too many runtime pairing requests" });
358
- return;
359
- }
360
- if (url.pathname === RUNTIME_ROTATE_PATH) {
361
- if (!this.credentialOwner(req.headers.authorization)) {
362
- answer(401, { error: "Runtime credential was refused" });
363
- return;
364
- }
365
- answer(200, this.rotateCredential(req.headers.authorization, value));
366
- return;
367
- }
368
- if (url.pathname === RUNTIME_PAIR_PATH)
369
- answer(201, this.pair(value));
370
- else {
371
- const result = this.claim(value);
372
- answer(result.status === "pending" ? 202 : 200, result);
373
- }
374
- }).catch(() => {
375
- const allowed = charged || this.rate(`invalid:${req.socket.remoteAddress ?? "unknown"}`, 30);
376
- answer(allowed ? 400 : 429, { error: "Runtime pairing request is invalid, expired or already used" });
377
- });
378
- return true;
379
- }
380
- handleUpgrade(req, socket, head) {
381
- let url;
382
- try {
383
- url = new URL(req.url ?? "", "http://localhost");
384
- }
385
- catch {
386
- return false;
387
- }
388
- if (url.pathname !== RUNTIME_CONNECT_PATH)
389
- return false;
390
- const refuse = () => { socket.end("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\nContent-Length: 0\r\n\r\n"); };
391
- const auth = req.headers.authorization;
392
- if (this.closed || req.method !== "GET" || url.search || !privateTransport(req) || typeof auth !== "string" || !/^Bearer [a-f0-9]{64}$/i.test(auth)) {
393
- refuse();
394
- return true;
395
- }
396
- const row = this.credentialOwner(auth);
397
- if (!row) {
398
- refuse();
399
- return true;
400
- }
401
- this.server.handleUpgrade(req, socket, head, ws => this.attach(ws, row));
402
- return true;
403
- }
404
- current(connection) { return !this.closed && this.connections.get(connection.machineId) === connection && this.entry(connection.machineId).machine.status !== "revoked"; }
405
- attach(ws, row) {
406
- const old = this.connections.get(row.machine.id);
407
- if (old) {
408
- this.rejectPending(old, "Runtime connection was replaced; execution must be reconciled");
409
- this.options.warn?.({ machineId: row.machine.id, code: 1008, reason: "Connection replaced" }, "Runtime connection closed because the same machine credential connected again");
410
- old.ws.close(1008, "Connection replaced");
411
- }
412
- row.machine.generation++;
413
- row.machine.status = "offline";
414
- this.save();
415
- const connection = { ws, machineId: row.machine.id, generation: row.machine.generation, ready: false, alive: true, helloTimer: setTimeout(() => ws.close(1008, "Runtime hello required"), 10_000) };
416
- connection.helloTimer.unref();
417
- this.connections.set(row.machine.id, connection);
418
- ws.on("pong", () => { connection.alive = true; if (this.current(connection))
419
- row.machine.lastSeenAt = this.now(); });
420
- ws.on("message", (data, binary) => {
421
- if (binary) {
422
- ws.close(1008, "Runtime requires JSON text frames");
423
- return;
424
- }
425
- void this.message(connection, data).catch(error => {
426
- // The cause (a static validation message) goes to the log and, trimmed, to the runtime so its terminal can show it.
427
- const reason = error instanceof RuntimeProtocolError ? `Invalid runtime message: ${error.message}`.replace(/[^ -~]/g, "?").slice(0, 120) : "Invalid runtime message";
428
- this.options.warn?.({ machineId: connection.machineId, code: 1008, reason, detail: error instanceof Error ? error.message : String(error) }, "Runtime connection closed because of an invalid runtime message");
429
- ws.close(1008, reason);
430
- });
431
- });
432
- ws.on("error", () => { });
433
- ws.on("close", () => {
434
- clearTimeout(connection.helloTimer);
435
- if (this.connections.get(row.machine.id) !== connection)
436
- return;
437
- this.connections.delete(row.machine.id);
438
- this.rejectPending(connection, "Runtime disconnected; reconcile before retrying");
439
- if (row.machine.status !== "revoked")
440
- row.machine.status = "offline";
441
- this.save();
442
- this.emit({ type: "machine", machineId: row.machine.id });
443
- });
444
- }
445
- send(connection, value) {
446
- if (!this.current(connection) || connection.ws.readyState !== WebSocket.OPEN)
447
- throw Error("Runtime machine is offline");
448
- const frame = JSON.stringify(value);
449
- if (Buffer.byteLength(frame) > RUNTIME_MAX_FRAME_BYTES)
450
- throw Error("Runtime response exceeds the frame limit");
451
- if (connection.ws.bufferedAmount > RUNTIME_MAX_FRAME_BYTES * 2) {
452
- connection.ws.close(1013, "Runtime backpressure");
453
- throw Error("Runtime connection is too slow");
454
- }
455
- connection.ws.send(frame);
456
- }
457
- rejectPending(connection, reason) {
458
- for (const [id, pending] of this.panePending)
459
- if (pending.machineId === connection.machineId && pending.generation === connection.generation) {
460
- this.panePending.delete(id);
461
- clearTimeout(pending.timer);
462
- pending.reject(Error(reason));
463
- }
464
- let changed = false;
465
- for (const [id, pending] of this.pending)
466
- if (pending.machineId === connection.machineId && pending.generation === connection.generation) {
467
- this.pending.delete(id);
468
- clearTimeout(pending.timer);
469
- const command = this.state.commands.find(row => row.id === id);
470
- if (command?.state === "pending") {
471
- command.state = interrupted(command);
472
- command.error = reason;
473
- changed = true;
474
- }
475
- pending.reject(Error(reason));
476
- }
477
- if (changed)
478
- this.save();
479
- }
480
- validateTask(command, value) {
481
- if (command.operation !== "run" || !record(command.payload) || !record(command.payload.task) || !record(value))
482
- throw new RuntimeProtocolError("Unexpected runtime task");
483
- const input = command.payload.task;
484
- if (value.id !== input.requestId || value.cli !== input.cli || value.cwd !== input.cwd || value.sandbox !== input.sandbox || (value.model ?? "") !== (input.model ?? "")
485
- || !["starting", "running", "cancelling", "completed", "failed", "cancelled"].includes(String(value.status))
486
- || typeof value.startedAt !== "number" || !Number.isFinite(value.startedAt) || typeof value.output !== "string" || value.output.length > 64 * 1024
487
- || value.finishedAt !== undefined && (typeof value.finishedAt !== "number" || !Number.isFinite(value.finishedAt))
488
- || ["completed", "failed", "cancelled"].includes(String(value.status)) && (typeof value.finishedAt !== "number" || typeof value.outcomeConfirmed !== "boolean")
489
- || value.error !== undefined && (typeof value.error !== "string" || value.error.length > 8192)
490
- || value.threadId !== undefined && !text(value.threadId, 256)
491
- || value.threadId !== undefined && command.payload.resumeSessionId !== undefined && value.threadId !== command.payload.resumeSessionId
492
- || value.outcomeConfirmed !== undefined && typeof value.outcomeConfirmed !== "boolean")
493
- throw new RuntimeProtocolError("Invalid runtime task snapshot");
494
- return { id: value.id, cli: value.cli, cwd: value.cwd, sandbox: value.sandbox, ...(value.model ? { model: value.model } : {}),
495
- status: value.status, startedAt: value.startedAt, output: value.output,
496
- ...(value.finishedAt !== undefined ? { finishedAt: value.finishedAt } : {}), ...(value.error ? { error: value.error } : {}), ...(value.threadId ? { threadId: value.threadId } : {}), ...(value.outcomeConfirmed !== undefined ? { outcomeConfirmed: value.outcomeConfirmed } : {}) };
497
- }
498
- async message(connection, raw) {
499
- if (!this.current(connection))
500
- return;
501
- const value = JSON.parse(raw.toString());
502
- if (!record(value) || value.v !== 1 || !text(value.type, 32))
503
- throw new RuntimeProtocolError("Invalid runtime frame");
504
- const row = this.entry(connection.machineId);
505
- connection.alive = true;
506
- if (!connection.ready) {
507
- if (value.type !== "hello" || !text(value.bootId, 128))
508
- throw new RuntimeProtocolError("Runtime hello required");
509
- const runtimeInfo = parseRuntimeInfo(value.runtimeInfo);
510
- connection.ready = true;
511
- connection.bootId = value.bootId;
512
- clearTimeout(connection.helloTimer);
513
- row.machine.bootId = value.bootId;
514
- row.machine.status = "online";
515
- row.machine.lastSeenAt = this.now();
516
- if (runtimeInfo)
517
- row.machine.runtimeInfo = runtimeInfo;
518
- else
519
- delete row.machine.runtimeInfo;
520
- if (value.paneProtocol === 1)
521
- row.machine.paneProtocol = 1;
522
- else
523
- delete row.machine.paneProtocol;
524
- if (value.inventory !== undefined) {
525
- row.machine.inventory = inventory(value.inventory);
526
- row.machine.inventoryUpdatedAt = this.now();
527
- }
528
- this.save();
529
- this.send(connection, { v: 1, type: "welcome", machineId: connection.machineId, generation: connection.generation });
530
- this.emit({ type: "machine", machineId: connection.machineId });
531
- // alpha.2 polish (dev-claude's no-chat e2e): a runner that brings no CLI inventory (just paired, nothing detected
532
- // yet) is asked for its own report now — its detection runs on that PC, never on this fleet's loop — so the first
533
- // approval of an agent's request there is not refused for "no available CLI" until someone presses Refresh.
534
- // (#3004 rig: the runner's hello may carry a placeholder — `probedAt: null`, no CLIs — which is no report either.)
535
- // (#3005 rig recheck: `force` — without it the runner answers with its cached inventory, on a fresh profile the same
536
- // placeholder; Refresh sends force, and so does this: detection runs on that PC.)
537
- if (!inventoryProbed(row.machine.inventory))
538
- void this.call(connection.machineId, "probe", { force: true }).catch(() => { });
539
- return;
540
- }
541
- row.machine.lastSeenAt = this.now();
542
- if (value.type === "pane.tool.request") {
543
- if (row.machine.paneProtocol !== 1 || Object.keys(value).some(key => !["v", "type", "id", "body"].includes(key)) || !UUID.test(String(value.id)))
544
- throw new RuntimeProtocolError("Invalid pane MCP transport request");
545
- const body = validatePaneMcpBody(value.body), id = value.id;
546
- const key = `${connection.machineId}:${connection.generation}:${id}`;
547
- if (this.paneToolPending.size >= 128 || this.paneToolPending.has(key))
548
- throw new RuntimeProtocolError("Pane MCP transport backlog or duplicate request");
549
- let active = true;
550
- const current = () => active && !this.closed && this.current(connection) && connection.ready && connection.ws.readyState === WebSocket.OPEN;
551
- this.paneToolPending.add(key);
552
- let timer;
553
- try {
554
- if (!current() || !this.options.handlePaneMcp)
555
- throw new RuntimeProtocolError("Pane MCP scope unavailable");
556
- const result = await Promise.race([this.options.handlePaneMcp(connection.machineId, body, current), new Promise((_resolve, reject) => {
557
- timer = setTimeout(() => { active = false; reject(Error("Pane MCP deadline")); }, 80_000);
558
- timer.unref();
559
- })]);
560
- if (current())
561
- this.send(connection, { v: 1, type: "pane.tool.result", id, ok: true, result });
562
- }
563
- catch {
564
- if (current())
565
- this.send(connection, { v: 1, type: "pane.tool.result", id, ok: false });
566
- }
567
- finally {
568
- active = false;
569
- clearTimeout(timer);
570
- this.paneToolPending.delete(key);
571
- }
572
- return;
573
- }
574
- if (value.type === "pane.output") {
575
- if (row.machine.paneProtocol !== 1)
576
- throw new RuntimeProtocolError("Pane protocol was not negotiated");
577
- const snapshot = validateRuntimePaneSnapshot(value.snapshot);
578
- this.emit({ type: "pane", machineId: connection.machineId, pane: snapshot });
579
- return;
580
- }
581
- if (value.type === "pane.response") {
582
- if (row.machine.paneProtocol !== 1 || !UUID.test(String(value.id)) || typeof value.ok !== "boolean")
583
- throw new RuntimeProtocolError("Invalid pane transport response");
584
- const pending = this.panePending.get(value.id);
585
- if (!pending)
586
- return; // A late reply proves nothing and never replays a command.
587
- if (pending.machineId !== connection.machineId || pending.generation !== connection.generation)
588
- throw new RuntimeProtocolError("Pane response belongs to another connection");
589
- this.panePending.delete(value.id);
590
- clearTimeout(pending.timer);
591
- if (value.ok)
592
- pending.resolve(value.result);
593
- else
594
- pending.reject(Error(typeof value.error === "string" ? value.error.slice(0, 1000) : "Pane operation failed"));
595
- return;
596
- }
597
- if (value.type === "inventory") {
598
- row.machine.inventory = inventory(value.inventory);
599
- row.machine.inventoryUpdatedAt = this.now();
600
- this.save();
601
- this.emit({ type: "machine", machineId: connection.machineId });
602
- return;
603
- }
604
- if (value.type === "task") {
605
- if (!record(value.task) || !Number.isSafeInteger(value.seq) || value.seq < 1)
606
- throw new RuntimeProtocolError("Invalid runtime task event");
607
- const taskValue = value.task;
608
- const command = this.state.commands.find(command => command.id === taskValue.id && command.machineId === connection.machineId && command.operation === "run");
609
- if (!command) {
610
- // #2945 review: a reconnecting runtime republishes what it retained; a run already settled and compacted here
611
- // is acknowledged by its tombstone and changes nothing. An unknown id, or another machine's, still closes.
612
- if (this.tombstoned(connection.machineId, taskValue.id))
613
- return;
614
- throw new RuntimeProtocolError("Runtime task does not belong to this machine");
615
- }
616
- const task = this.validateTask(command, value.task);
617
- if (value.seq <= command.seq)
618
- return;
619
- if (command.task && terminal(command.task) && !terminal(task))
620
- throw new RuntimeProtocolError("Runtime task cannot restart");
621
- command.seq = value.seq;
622
- command.task = task;
623
- command.state = "accepted";
624
- this.save();
625
- this.emit({ type: "task", machineId: connection.machineId, task });
626
- return;
627
- }
628
- if (value.type === "response") {
629
- if (!text(value.id, 128) || typeof value.ok !== "boolean")
630
- throw new RuntimeProtocolError("Invalid runtime response");
631
- const pending = this.pending.get(value.id), command = this.state.commands.find(command => command.id === value.id);
632
- if (!command || command.machineId !== connection.machineId) {
633
- if (!command && this.tombstoned(connection.machineId, value.id))
634
- return;
635
- throw new RuntimeProtocolError("Runtime response does not belong to this machine");
636
- }
637
- if (!pending || pending.generation !== connection.generation)
638
- return;
639
- this.pending.delete(value.id);
640
- clearTimeout(pending.timer);
641
- try {
642
- if (!value.ok) {
643
- command.state = "failed";
644
- command.error = typeof value.error === "string" ? value.error.slice(0, 1024) : "Runtime request failed";
645
- this.save();
646
- pending.reject(Error(command.error));
647
- return;
648
- }
649
- let result = value.result;
650
- if (command.operation === "probe") {
651
- result = inventory(result);
652
- row.machine.inventory = result;
653
- row.machine.inventoryUpdatedAt = this.now();
654
- }
655
- if (command.operation === "run") {
656
- const task = this.validateTask(command, result);
657
- if (!command.task || !terminal(command.task))
658
- command.task = task;
659
- result = command.task;
660
- }
661
- command.state = "accepted";
662
- command.result = result;
663
- this.save();
664
- if (command.task)
665
- this.emit({ type: "task", machineId: connection.machineId, task: command.task });
666
- else if (command.operation === "probe")
667
- this.emit({ type: "machine", machineId: connection.machineId });
668
- pending.resolve(structuredClone(result));
669
- }
670
- catch (error) {
671
- command.state = "uncertain";
672
- this.save();
673
- pending.reject(error instanceof Error ? error : Error("Invalid runtime response"));
674
- throw error;
675
- }
676
- return;
677
- }
678
- if (value.type === "tool.call") {
679
- if (!text(value.id, 128) || !text(value.runId, 128))
680
- throw new RuntimeProtocolError("Invalid runtime tool call");
681
- const command = this.state.commands.find(command => command.id === value.runId && command.machineId === connection.machineId && command.operation === "run");
682
- try {
683
- if (!command || !record(command.payload) || !record(command.payload.mcp) || command.task && terminal(command.task) || !this.options.handleMcp)
684
- throw new RuntimeProtocolError("Runtime tool call has no active turn");
685
- const body = value.body;
686
- if (!record(body) || Object.keys(body).some(key => !["op", "method", "params", "callId"].includes(key))
687
- || body.op !== "native-mcp" || !record(body.params) || Buffer.byteLength(JSON.stringify(body)) > 64 * 1024)
688
- throw new RuntimeProtocolError("Invalid runtime MCP request");
689
- if (body.method === "tools/list") {
690
- if (Object.keys(body.params).length || body.callId !== undefined)
691
- throw new RuntimeProtocolError("Invalid runtime MCP listing");
692
- }
693
- else if (body.method === "tools/call") {
694
- if (!text(body.callId, 128) || !/^[A-Za-z0-9._:-]+$/.test(body.callId)
695
- || Object.keys(body.params).some(key => !["name", "arguments"].includes(key)) || typeof body.params.name !== "string"
696
- || !Array.isArray(command.payload.mcp.tools) || !command.payload.mcp.tools.includes(body.params.name)
697
- || body.params.arguments !== undefined && !record(body.params.arguments))
698
- throw new RuntimeProtocolError("Runtime MCP tool is outside this turn");
699
- stable(body.params);
700
- }
701
- else
702
- throw new RuntimeProtocolError("Invalid runtime MCP operation");
703
- const result = await this.options.handleMcp(connection.machineId, value.runId, body);
704
- if (!this.current(connection))
705
- return;
706
- this.send(connection, { v: 1, type: "tool.result", id: value.id, ok: true, result });
707
- }
708
- catch {
709
- if (this.current(connection))
710
- this.send(connection, { v: 1, type: "tool.result", id: value.id, ok: false, error: "Runtime tool call was refused or its turn expired" });
711
- }
712
- return;
713
- }
714
- throw new RuntimeProtocolError("Unknown runtime message");
715
- }
716
- tombstoned(machineId, id) {
717
- return typeof id === "string" && this.state.tombstones.some(row => row.id === id && row.machineId === machineId);
718
- }
719
- /** M-2239 P2-1: settled commands to tombstones (see COMMAND_KEEP_MS); never a pending, uncertain or unconfirmed one. */
720
- compact() {
721
- const now = this.now();
722
- const settled = (command) => !this.pending.has(command.id) && (command.state === "failed"
723
- || command.state === "accepted" && (command.operation !== "run" || !!command.task && terminal(command.task) && command.task.outcomeConfirmed === true));
724
- const drop = new Set(this.state.commands.filter(command => settled(command) && now - command.createdAt > COMMAND_KEEP_MS));
725
- const excess = this.state.commands.length - drop.size - COMMAND_SOFT_CAP;
726
- if (excess > 0)
727
- for (const command of this.state.commands.filter(command => settled(command) && !drop.has(command)).sort((a, b) => a.createdAt - b.createdAt).slice(0, excess))
728
- drop.add(command);
729
- if (!drop.size)
730
- return;
731
- // Room for new tombstones without passing TOMBSTONE_CAP (what the constructor reads back, #2945 review): old ones
732
- // past TOMBSTONE_KEEP_MS give way, oldest first; a younger one never does. Commands beyond that room stay as they
733
- // are — still refused by id from the journal — until room frees up.
734
- const tombstones = this.state.tombstones;
735
- const evictable = tombstones.filter(row => now - row.at > TOMBSTONE_KEEP_MS).sort((a, b) => a.at - b.at);
736
- const room = TOMBSTONE_CAP - tombstones.length + evictable.length;
737
- const moved = [...drop].sort((a, b) => a.createdAt - b.createdAt).slice(0, Math.max(0, room));
738
- if (!moved.length)
739
- return;
740
- const gone = new Set(evictable.slice(0, Math.max(0, tombstones.length + moved.length - TOMBSTONE_CAP)));
741
- const movedSet = new Set(moved);
742
- this.state.tombstones = [...tombstones.filter(row => !gone.has(row)),
743
- ...moved.map(command => ({ id: command.id, machineId: command.machineId, digest: command.digest, at: now }))];
744
- this.state.commands = this.state.commands.filter(command => !movedSet.has(command));
745
- this.save();
746
- }
747
- task(id) { const task = this.state.commands.find(command => command.id === id && command.operation === "run")?.task; return task ? structuredClone(task) : null; }
748
- tasks() { return this.state.commands.flatMap(command => command.operation === "run" && command.task ? [{ machineId: command.machineId, task: structuredClone(command.task) }] : []); }
749
- /** Include journaled sends whose acknowledgement is still missing, so reopening diagnostics cannot hide an uncertain run. */
750
- diagnosticTasks(machineId) {
751
- return this.state.commands.flatMap(command => {
752
- if (command.operation !== "run" || command.machineId !== machineId)
753
- return [];
754
- if (command.task)
755
- return [structuredClone(command.task)];
756
- let input;
757
- try {
758
- input = validateNativeTask(command.payload.task);
759
- }
760
- catch {
761
- return [];
762
- }
763
- const uncertain = command.state === "uncertain", rejected = command.state === "failed";
764
- return [{ id: command.id, cli: input.cli, cwd: input.cwd, sandbox: input.sandbox, ...(input.model ? { model: input.model } : {}),
765
- startedAt: command.createdAt, status: uncertain || rejected ? "failed" : "starting", output: "",
766
- ...(rejected ? { outcomeConfirmed: true, error: command.error || "Runtime request failed" } : {}),
767
- ...(uncertain ? { outcomeConfirmed: false, error: "Remote execution outcome is unconfirmed. Reconnect this runtime to reconcile before sending another task." } : {}) }];
768
- }).sort((a, b) => b.startedAt - a.startedAt).slice(0, 20);
769
- }
770
- hasActiveTask(machineId) { return this.state.commands.some(command => command.machineId === machineId && command.operation === "run" && command.state !== "failed" && (!command.task || !terminal(command.task) || command.task.outcomeConfirmed === false)); }
771
- paneTransportEpoch(machineId) {
772
- const connection = this.connections.get(machineId);
773
- return connection?.ready && connection.ws.readyState === WebSocket.OPEN && this.current(connection) ? `${this.paneEpoch}:${machineId}:${connection.generation}` : null;
774
- }
775
- /** Pane input replay/sequence authority lives in its pane ledger; reads never fill the exec-task journal. */
776
- async callPane(machineId, raw, maxAgents = 4) {
777
- const request = validateRuntimePaneRequest(raw);
778
- if (!Number.isInteger(maxAgents) || maxAgents < 1 || maxAgents > 16)
779
- throw Error("Invalid machine pane limit");
780
- const machine = this.entry(machineId).machine, connection = this.connections.get(machineId);
781
- if (this.closed || machine.status !== "online" || machine.paneProtocol !== 1 || !connection?.ready || !this.current(connection))
782
- throw Error("Pane runtime is offline or unsupported");
783
- if (this.panePending.size >= 64)
784
- throw Error("Pane transport capacity reached");
785
- const id = randomUUID();
786
- return new Promise((resolve, reject) => {
787
- const timer = setTimeout(() => { this.panePending.delete(id); reject(Error("Pane response timed out; reconcile before another input")); }, this.options.requestTimeoutMs ?? 30_000);
788
- timer.unref();
789
- this.panePending.set(id, { machineId, generation: connection.generation, resolve, reject, timer });
790
- try {
791
- this.send(connection, { v: 1, type: "pane.request", id, maxAgents, request });
792
- }
793
- catch (error) {
794
- this.panePending.delete(id);
795
- clearTimeout(timer);
796
- reject(error);
797
- }
798
- });
799
- }
800
- /** Explicit switch-off only, after owned pane closes. A normal hub close/restart never shuts its hosts down. */
801
- async shutdownPaneHosts() {
802
- const machines = this.listMachines().filter(machine => machine.status === "online" && machine.paneProtocol === 1);
803
- const outcomes = await Promise.allSettled(machines.map(async (machine) => {
804
- const raw = await this.callPane(machine.id, { action: "list" });
805
- if (!raw || typeof raw.hostBootId !== "string" || !/^[a-f0-9-]{36}$/i.test(raw.hostBootId) || !Array.isArray(raw.panes) || raw.panes.length > 4096)
806
- throw Error("Pane shutdown inventory is unconfirmed");
807
- if (raw.panes.map(validateRuntimePaneSnapshot).some(pane => pane.state !== "exited"))
808
- throw Error("Pane shutdown still has live or unconfirmed work");
809
- validateRuntimePaneShutdown(await this.callPane(machine.id, { action: "shutdown", hostBootId: raw.hostBootId }), raw.hostBootId);
810
- }));
811
- if (outcomes.some(result => result.status === "rejected"))
812
- throw Error("One or more pane hosts could not confirm empty shutdown; retained work stays reserved");
813
- }
814
- async call(machineId, operation, payload) {
815
- if (this.closed || !["probe", "workspace", "run", "cancel", "reconcile", "recover"].includes(operation))
816
- throw Error("Unsupported runtime operation");
817
- const machine = this.entry(machineId).machine;
818
- const connection = this.connections.get(machineId);
819
- if (machine.status !== "online" || !connection?.ready || !this.current(connection))
820
- throw Error("Runtime machine is offline");
821
- let id = randomUUID(), normalized = payload;
822
- if (operation === "run") {
823
- if (!record(payload) || Object.keys(payload).some(k => !["task", "resumeSessionId", "context", "mcp"].includes(k)))
824
- throw Error("Invalid runtime run payload");
825
- const task = validateNativeTask(payload.task);
826
- if (payload.resumeSessionId !== undefined && !text(payload.resumeSessionId, 256) || payload.context !== undefined && (typeof payload.context !== "string" || payload.context.length > 2000 || payload.context.includes("\0")))
827
- throw Error("Invalid runtime turn context");
828
- if (payload.mcp !== undefined && (!record(payload.mcp) || Object.keys(payload.mcp).some(k => k !== "tools") || !Array.isArray(payload.mcp.tools) || !payload.mcp.tools.length || payload.mcp.tools.length > 128 || payload.mcp.tools.some(v => typeof v !== "string" || !/^[a-z][a-z0-9_]{0,63}$/.test(v))))
829
- throw Error("Invalid runtime tool scope");
830
- normalized = { ...payload, task };
831
- id = task.requestId;
832
- }
833
- if (operation === "recover") {
834
- if (!record(payload) || Object.keys(payload).some(key => !["runId", "confirmedStopped"].includes(key))
835
- || !text(payload.runId, 80) || payload.confirmedStopped !== true)
836
- throw Error("Runtime recovery requires explicit stopped-process confirmation");
837
- const original = this.state.commands.find(command => command.id === payload.runId && command.machineId === machineId && command.operation === "run");
838
- if (!original)
839
- throw Error("Runtime recovery does not belong to this machine");
840
- // A runtime that never received the original request can still save a no-execution tombstone after manual
841
- // confirmation. The original is server-owned; callers cannot replace it with another task or tool scope.
842
- normalized = { runId: payload.runId, confirmedStopped: true, original: structuredClone(original.payload) };
843
- }
844
- const digest = hash(stable({ operation, payload: normalized }));
845
- if (Buffer.byteLength(JSON.stringify(normalized)) > RUNTIME_MAX_FRAME_BYTES / 2)
846
- throw Error("Runtime command payload is too large");
847
- const existing = this.state.commands.find(command => command.id === id);
848
- if (existing) {
849
- if (existing.machineId !== machineId || existing.digest !== digest)
850
- throw Error("Runtime task ID belongs to a different request or machine");
851
- if (existing.task)
852
- return structuredClone(existing.task);
853
- throw Error("Runtime command is already recorded; reconcile it before retrying");
854
- }
855
- const tombstone = this.state.tombstones.find(row => row.id === id);
856
- if (tombstone) {
857
- if (tombstone.machineId !== machineId || tombstone.digest !== digest)
858
- throw Error("Runtime task ID belongs to a different request or machine");
859
- throw Error("Runtime command already ran and its record was compacted; do not retry it");
860
- }
861
- if (operation === "run" && this.hasActiveTask(machineId))
862
- throw Error("Runtime machine is busy or has an unconfirmed task");
863
- this.compact();
864
- if (this.state.commands.length >= COMMAND_HARD_CAP)
865
- throw Error("Runtime command journal limit reached: too many unsettled commands; reconcile them");
866
- const command = { id, machineId, operation, digest, payload: normalized, createdAt: this.now(), state: "pending", seq: 0 };
867
- // Journal is committed before the first byte reaches the execution computer. Never auto-send it again.
868
- this.state.commands.push(command);
869
- this.save();
870
- return new Promise((resolve, reject) => {
871
- const timer = setTimeout(() => {
872
- this.pending.delete(id);
873
- command.state = interrupted(command);
874
- command.error = command.state === "failed" ? "Runtime inventory request timed out" : "Runtime acknowledgment timed out; reconcile before retrying";
875
- this.save();
876
- reject(Error(command.error));
877
- }, this.options.requestTimeoutMs ?? (operation === "probe" ? 90_000 : 30_000));
878
- timer.unref();
879
- this.pending.set(id, { machineId, generation: connection.generation, resolve, reject, timer });
880
- try {
881
- this.send(connection, { v: 1, type: "request", id, operation, payload: normalized });
882
- }
883
- catch (error) {
884
- this.pending.delete(id);
885
- clearTimeout(timer);
886
- command.state = interrupted(command);
887
- this.save();
888
- reject(error);
889
- }
890
- });
891
- }
892
- close() {
893
- if (this.closed)
894
- return;
895
- this.closed = true;
896
- clearInterval(this.heartbeat);
897
- for (const connection of this.connections.values()) {
898
- clearTimeout(connection.helloTimer);
899
- this.rejectPending(connection, "Runtime coordinator stopped; reconcile before retrying");
900
- connection.ws.terminate();
901
- }
902
- this.connections.clear();
903
- for (const row of this.state.machines)
904
- if (row.machine.status === "online")
905
- row.machine.status = "offline";
906
- this.save();
907
- this.server.close();
908
- this.listeners.clear();
909
- }
910
- }
911
- //# sourceMappingURL=runtime-coordinator.js.map