@quenty/studio-bridge 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (689) hide show
  1. package/CHANGELOG.md +12 -44
  2. package/README.md +166 -115
  3. package/dist/src/bridge/bridge-connection-remote.test.d.ts +7 -0
  4. package/dist/src/bridge/bridge-connection-remote.test.d.ts.map +1 -0
  5. package/dist/src/bridge/bridge-connection-remote.test.js +144 -0
  6. package/dist/src/bridge/bridge-connection-remote.test.js.map +1 -0
  7. package/dist/src/bridge/bridge-connection.d.ts +112 -0
  8. package/dist/src/bridge/bridge-connection.d.ts.map +1 -0
  9. package/dist/src/bridge/bridge-connection.js +528 -0
  10. package/dist/src/bridge/bridge-connection.js.map +1 -0
  11. package/dist/src/bridge/bridge-connection.test.d.ts +6 -0
  12. package/dist/src/bridge/bridge-connection.test.d.ts.map +1 -0
  13. package/dist/src/bridge/bridge-connection.test.js +773 -0
  14. package/dist/src/bridge/bridge-connection.test.js.map +1 -0
  15. package/dist/src/bridge/bridge-session.d.ts +38 -0
  16. package/dist/src/bridge/bridge-session.d.ts.map +1 -0
  17. package/dist/src/bridge/bridge-session.js +259 -0
  18. package/dist/src/bridge/bridge-session.js.map +1 -0
  19. package/dist/src/bridge/bridge-session.test.d.ts +6 -0
  20. package/dist/src/bridge/bridge-session.test.d.ts.map +1 -0
  21. package/dist/src/bridge/bridge-session.test.js +264 -0
  22. package/dist/src/bridge/bridge-session.test.js.map +1 -0
  23. package/dist/src/bridge/index.d.ts +13 -0
  24. package/dist/src/bridge/index.d.ts.map +1 -0
  25. package/dist/src/bridge/index.js +13 -0
  26. package/dist/src/bridge/index.js.map +1 -0
  27. package/dist/src/bridge/internal/__tests__/failover-crash.test.d.ts +9 -0
  28. package/dist/src/bridge/internal/__tests__/failover-crash.test.d.ts.map +1 -0
  29. package/dist/src/bridge/internal/__tests__/failover-crash.test.js +159 -0
  30. package/dist/src/bridge/internal/__tests__/failover-crash.test.js.map +1 -0
  31. package/dist/src/bridge/internal/__tests__/failover-graceful.test.d.ts +9 -0
  32. package/dist/src/bridge/internal/__tests__/failover-graceful.test.d.ts.map +1 -0
  33. package/dist/src/bridge/internal/__tests__/failover-graceful.test.js +218 -0
  34. package/dist/src/bridge/internal/__tests__/failover-graceful.test.js.map +1 -0
  35. package/dist/src/bridge/internal/__tests__/failover-inflight.test.d.ts +9 -0
  36. package/dist/src/bridge/internal/__tests__/failover-inflight.test.d.ts.map +1 -0
  37. package/dist/src/bridge/internal/__tests__/failover-inflight.test.js +246 -0
  38. package/dist/src/bridge/internal/__tests__/failover-inflight.test.js.map +1 -0
  39. package/dist/src/bridge/internal/__tests__/host-client-integration.test.d.ts +10 -0
  40. package/dist/src/bridge/internal/__tests__/host-client-integration.test.d.ts.map +1 -0
  41. package/dist/src/bridge/internal/__tests__/host-client-integration.test.js +298 -0
  42. package/dist/src/bridge/internal/__tests__/host-client-integration.test.js.map +1 -0
  43. package/dist/src/bridge/internal/bridge-client.d.ts +70 -0
  44. package/dist/src/bridge/internal/bridge-client.d.ts.map +1 -0
  45. package/dist/src/bridge/internal/bridge-client.js +344 -0
  46. package/dist/src/bridge/internal/bridge-client.js.map +1 -0
  47. package/dist/src/bridge/internal/bridge-client.test.d.ts +7 -0
  48. package/dist/src/bridge/internal/bridge-client.test.d.ts.map +1 -0
  49. package/dist/src/bridge/internal/bridge-client.test.js +301 -0
  50. package/dist/src/bridge/internal/bridge-client.test.js.map +1 -0
  51. package/dist/src/bridge/internal/bridge-host.d.ts +78 -0
  52. package/dist/src/bridge/internal/bridge-host.d.ts.map +1 -0
  53. package/dist/src/bridge/internal/bridge-host.js +383 -0
  54. package/dist/src/bridge/internal/bridge-host.js.map +1 -0
  55. package/dist/src/bridge/internal/bridge-host.test.d.ts +7 -0
  56. package/dist/src/bridge/internal/bridge-host.test.d.ts.map +1 -0
  57. package/dist/src/bridge/internal/bridge-host.test.js +377 -0
  58. package/dist/src/bridge/internal/bridge-host.test.js.map +1 -0
  59. package/dist/src/bridge/internal/environment-detection.d.ts +44 -0
  60. package/dist/src/bridge/internal/environment-detection.d.ts.map +1 -0
  61. package/dist/src/bridge/internal/environment-detection.js +91 -0
  62. package/dist/src/bridge/internal/environment-detection.js.map +1 -0
  63. package/dist/src/bridge/internal/environment-detection.test.d.ts +7 -0
  64. package/dist/src/bridge/internal/environment-detection.test.d.ts.map +1 -0
  65. package/dist/src/bridge/internal/environment-detection.test.js +150 -0
  66. package/dist/src/bridge/internal/environment-detection.test.js.map +1 -0
  67. package/dist/src/bridge/internal/hand-off.d.ts +69 -0
  68. package/dist/src/bridge/internal/hand-off.d.ts.map +1 -0
  69. package/dist/src/bridge/internal/hand-off.js +178 -0
  70. package/dist/src/bridge/internal/hand-off.js.map +1 -0
  71. package/dist/src/bridge/internal/hand-off.test.d.ts +7 -0
  72. package/dist/src/bridge/internal/hand-off.test.d.ts.map +1 -0
  73. package/dist/src/bridge/internal/hand-off.test.js +325 -0
  74. package/dist/src/bridge/internal/hand-off.test.js.map +1 -0
  75. package/dist/src/bridge/internal/health-endpoint.d.ts +32 -0
  76. package/dist/src/bridge/internal/health-endpoint.d.ts.map +1 -0
  77. package/dist/src/bridge/internal/health-endpoint.js +73 -0
  78. package/dist/src/bridge/internal/health-endpoint.js.map +1 -0
  79. package/dist/src/bridge/internal/health-endpoint.test.d.ts +6 -0
  80. package/dist/src/bridge/internal/health-endpoint.test.d.ts.map +1 -0
  81. package/dist/src/bridge/internal/health-endpoint.test.js +122 -0
  82. package/dist/src/bridge/internal/health-endpoint.test.js.map +1 -0
  83. package/dist/src/bridge/internal/host-protocol.d.ts +60 -0
  84. package/dist/src/bridge/internal/host-protocol.d.ts.map +1 -0
  85. package/dist/src/bridge/internal/host-protocol.js +184 -0
  86. package/dist/src/bridge/internal/host-protocol.js.map +1 -0
  87. package/dist/src/bridge/internal/host-protocol.test.d.ts +6 -0
  88. package/dist/src/bridge/internal/host-protocol.test.d.ts.map +1 -0
  89. package/dist/src/bridge/internal/host-protocol.test.js +307 -0
  90. package/dist/src/bridge/internal/host-protocol.test.js.map +1 -0
  91. package/dist/src/bridge/internal/session-tracker.d.ts +67 -0
  92. package/dist/src/bridge/internal/session-tracker.d.ts.map +1 -0
  93. package/dist/src/bridge/internal/session-tracker.js +138 -0
  94. package/dist/src/bridge/internal/session-tracker.js.map +1 -0
  95. package/dist/src/bridge/internal/session-tracker.test.d.ts +6 -0
  96. package/dist/src/bridge/internal/session-tracker.test.d.ts.map +1 -0
  97. package/dist/src/bridge/internal/session-tracker.test.js +342 -0
  98. package/dist/src/bridge/internal/session-tracker.test.js.map +1 -0
  99. package/dist/src/bridge/internal/transport-client.d.ts +43 -0
  100. package/dist/src/bridge/internal/transport-client.d.ts.map +1 -0
  101. package/dist/src/bridge/internal/transport-client.js +146 -0
  102. package/dist/src/bridge/internal/transport-client.js.map +1 -0
  103. package/dist/src/bridge/internal/transport-client.test.d.ts +6 -0
  104. package/dist/src/bridge/internal/transport-client.test.d.ts.map +1 -0
  105. package/dist/src/bridge/internal/transport-client.test.js +176 -0
  106. package/dist/src/bridge/internal/transport-client.test.js.map +1 -0
  107. package/dist/src/bridge/internal/transport-server.d.ts +59 -0
  108. package/dist/src/bridge/internal/transport-server.d.ts.map +1 -0
  109. package/dist/src/bridge/internal/transport-server.js +189 -0
  110. package/dist/src/bridge/internal/transport-server.js.map +1 -0
  111. package/dist/src/bridge/internal/transport-server.test.d.ts +6 -0
  112. package/dist/src/bridge/internal/transport-server.test.d.ts.map +1 -0
  113. package/dist/src/bridge/internal/transport-server.test.js +171 -0
  114. package/dist/src/bridge/internal/transport-server.test.js.map +1 -0
  115. package/dist/src/bridge/types.d.ts +117 -0
  116. package/dist/src/bridge/types.d.ts.map +1 -0
  117. package/dist/src/bridge/types.js +68 -0
  118. package/dist/src/bridge/types.js.map +1 -0
  119. package/dist/src/cli/adapters/cli-command-adapter-handler.test.d.ts +6 -0
  120. package/dist/src/cli/adapters/cli-command-adapter-handler.test.d.ts.map +1 -0
  121. package/dist/src/cli/adapters/cli-command-adapter-handler.test.js +260 -0
  122. package/dist/src/cli/adapters/cli-command-adapter-handler.test.js.map +1 -0
  123. package/dist/src/cli/adapters/cli-command-adapter.d.ts +39 -0
  124. package/dist/src/cli/adapters/cli-command-adapter.d.ts.map +1 -0
  125. package/dist/src/cli/adapters/cli-command-adapter.js +241 -0
  126. package/dist/src/cli/adapters/cli-command-adapter.js.map +1 -0
  127. package/dist/src/cli/adapters/cli-command-adapter.test.d.ts +5 -0
  128. package/dist/src/cli/adapters/cli-command-adapter.test.d.ts.map +1 -0
  129. package/dist/src/cli/adapters/cli-command-adapter.test.js +188 -0
  130. package/dist/src/cli/adapters/cli-command-adapter.test.js.map +1 -0
  131. package/dist/src/cli/adapters/group-builder.d.ts +29 -0
  132. package/dist/src/cli/adapters/group-builder.d.ts.map +1 -0
  133. package/dist/src/cli/adapters/group-builder.js +54 -0
  134. package/dist/src/cli/adapters/group-builder.js.map +1 -0
  135. package/dist/src/cli/adapters/group-builder.test.d.ts +5 -0
  136. package/dist/src/cli/adapters/group-builder.test.d.ts.map +1 -0
  137. package/dist/src/cli/adapters/group-builder.test.js +108 -0
  138. package/dist/src/cli/adapters/group-builder.test.js.map +1 -0
  139. package/dist/src/cli/adapters/help-formatter.d.ts +11 -0
  140. package/dist/src/cli/adapters/help-formatter.d.ts.map +1 -0
  141. package/dist/src/cli/adapters/help-formatter.js +78 -0
  142. package/dist/src/cli/adapters/help-formatter.js.map +1 -0
  143. package/dist/src/cli/adapters/help-formatter.test.d.ts +5 -0
  144. package/dist/src/cli/adapters/help-formatter.test.d.ts.map +1 -0
  145. package/dist/src/cli/adapters/help-formatter.test.js +79 -0
  146. package/dist/src/cli/adapters/help-formatter.test.js.map +1 -0
  147. package/dist/src/cli/adapters/target-resolver.d.ts +54 -0
  148. package/dist/src/cli/adapters/target-resolver.d.ts.map +1 -0
  149. package/dist/src/cli/adapters/target-resolver.js +90 -0
  150. package/dist/src/cli/adapters/target-resolver.js.map +1 -0
  151. package/dist/src/cli/adapters/target-resolver.test.d.ts +5 -0
  152. package/dist/src/cli/adapters/target-resolver.test.d.ts.map +1 -0
  153. package/dist/src/cli/adapters/target-resolver.test.js +169 -0
  154. package/dist/src/cli/adapters/target-resolver.test.js.map +1 -0
  155. package/dist/src/cli/args/global-args.d.ts +2 -0
  156. package/dist/src/cli/args/global-args.d.ts.map +1 -1
  157. package/dist/src/cli/cli.d.ts +6 -3
  158. package/dist/src/cli/cli.d.ts.map +1 -1
  159. package/dist/src/cli/cli.js +82 -20
  160. package/dist/src/cli/cli.js.map +1 -1
  161. package/dist/src/cli/resolve-script-content.d.ts +19 -0
  162. package/dist/src/cli/resolve-script-content.d.ts.map +1 -0
  163. package/dist/src/cli/resolve-script-content.js +22 -0
  164. package/dist/src/cli/resolve-script-content.js.map +1 -0
  165. package/dist/src/cli/resolve-session.d.ts +21 -0
  166. package/dist/src/cli/resolve-session.d.ts.map +1 -0
  167. package/dist/src/cli/resolve-session.js +40 -0
  168. package/dist/src/cli/resolve-session.js.map +1 -0
  169. package/dist/src/cli/resolve-session.test.d.ts +5 -0
  170. package/dist/src/cli/resolve-session.test.d.ts.map +1 -0
  171. package/dist/src/cli/resolve-session.test.js +112 -0
  172. package/dist/src/cli/resolve-session.test.js.map +1 -0
  173. package/dist/src/cli/script-executor.d.ts +1 -0
  174. package/dist/src/cli/script-executor.d.ts.map +1 -1
  175. package/dist/src/cli/script-executor.js +7 -1
  176. package/dist/src/cli/script-executor.js.map +1 -1
  177. package/dist/src/cli/types.d.ts +11 -0
  178. package/dist/src/cli/types.d.ts.map +1 -0
  179. package/dist/src/cli/types.js +5 -0
  180. package/dist/src/cli/types.js.map +1 -0
  181. package/dist/src/commands/connect.d.ts +16 -0
  182. package/dist/src/commands/connect.d.ts.map +1 -0
  183. package/dist/src/commands/connect.js +15 -0
  184. package/dist/src/commands/connect.js.map +1 -0
  185. package/dist/src/commands/connect.test.d.ts +5 -0
  186. package/dist/src/commands/connect.test.d.ts.map +1 -0
  187. package/dist/src/commands/connect.test.js +46 -0
  188. package/dist/src/commands/connect.test.js.map +1 -0
  189. package/dist/src/commands/console/exec/exec.d.ts +43 -0
  190. package/dist/src/commands/console/exec/exec.d.ts.map +1 -0
  191. package/dist/src/commands/console/exec/exec.js +79 -0
  192. package/dist/src/commands/console/exec/exec.js.map +1 -0
  193. package/dist/src/commands/console/exec/exec.test.d.ts +5 -0
  194. package/dist/src/commands/console/exec/exec.test.d.ts.map +1 -0
  195. package/dist/src/commands/console/exec/exec.test.js +191 -0
  196. package/dist/src/commands/console/exec/exec.test.js.map +1 -0
  197. package/dist/src/commands/console/logs/logs.d.ts +23 -0
  198. package/dist/src/commands/console/logs/logs.d.ts.map +1 -0
  199. package/dist/src/commands/console/logs/logs.js +80 -0
  200. package/dist/src/commands/console/logs/logs.js.map +1 -0
  201. package/dist/src/commands/console/logs/logs.test.d.ts +5 -0
  202. package/dist/src/commands/console/logs/logs.test.d.ts.map +1 -0
  203. package/dist/src/commands/console/logs/logs.test.js +111 -0
  204. package/dist/src/commands/console/logs/logs.test.js.map +1 -0
  205. package/dist/src/commands/disconnect.d.ts +9 -0
  206. package/dist/src/commands/disconnect.d.ts.map +1 -0
  207. package/dist/src/commands/disconnect.js +8 -0
  208. package/dist/src/commands/disconnect.js.map +1 -0
  209. package/dist/src/commands/disconnect.test.d.ts +5 -0
  210. package/dist/src/commands/disconnect.test.d.ts.map +1 -0
  211. package/dist/src/commands/disconnect.test.js +17 -0
  212. package/dist/src/commands/disconnect.test.js.map +1 -0
  213. package/dist/src/commands/explorer/query/query.d.ts +31 -0
  214. package/dist/src/commands/explorer/query/query.d.ts.map +1 -0
  215. package/dist/src/commands/explorer/query/query.js +106 -0
  216. package/dist/src/commands/explorer/query/query.js.map +1 -0
  217. package/dist/src/commands/explorer/query/query.test.d.ts +5 -0
  218. package/dist/src/commands/explorer/query/query.test.d.ts.map +1 -0
  219. package/dist/src/commands/explorer/query/query.test.js +228 -0
  220. package/dist/src/commands/explorer/query/query.test.js.map +1 -0
  221. package/dist/src/commands/formatters.test.d.ts +6 -0
  222. package/dist/src/commands/formatters.test.d.ts.map +1 -0
  223. package/dist/src/commands/formatters.test.js +211 -0
  224. package/dist/src/commands/formatters.test.js.map +1 -0
  225. package/dist/src/commands/framework/action-loader.d.ts +25 -0
  226. package/dist/src/commands/framework/action-loader.d.ts.map +1 -0
  227. package/dist/src/commands/framework/action-loader.js +46 -0
  228. package/dist/src/commands/framework/action-loader.js.map +1 -0
  229. package/dist/src/commands/framework/action-loader.test.d.ts +5 -0
  230. package/dist/src/commands/framework/action-loader.test.d.ts.map +1 -0
  231. package/dist/src/commands/framework/action-loader.test.js +89 -0
  232. package/dist/src/commands/framework/action-loader.test.js.map +1 -0
  233. package/dist/src/commands/framework/arg-builder.d.ts +92 -0
  234. package/dist/src/commands/framework/arg-builder.d.ts.map +1 -0
  235. package/dist/src/commands/framework/arg-builder.js +137 -0
  236. package/dist/src/commands/framework/arg-builder.js.map +1 -0
  237. package/dist/src/commands/framework/arg-builder.test.d.ts +5 -0
  238. package/dist/src/commands/framework/arg-builder.test.d.ts.map +1 -0
  239. package/dist/src/commands/framework/arg-builder.test.js +246 -0
  240. package/dist/src/commands/framework/arg-builder.test.js.map +1 -0
  241. package/dist/src/commands/framework/command-registry.d.ts +23 -0
  242. package/dist/src/commands/framework/command-registry.d.ts.map +1 -0
  243. package/dist/src/commands/framework/command-registry.js +42 -0
  244. package/dist/src/commands/framework/command-registry.js.map +1 -0
  245. package/dist/src/commands/framework/command-registry.test.d.ts +5 -0
  246. package/dist/src/commands/framework/command-registry.test.d.ts.map +1 -0
  247. package/dist/src/commands/framework/command-registry.test.js +158 -0
  248. package/dist/src/commands/framework/command-registry.test.js.map +1 -0
  249. package/dist/src/commands/framework/define-command.d.ts +76 -0
  250. package/dist/src/commands/framework/define-command.d.ts.map +1 -0
  251. package/dist/src/commands/framework/define-command.js +28 -0
  252. package/dist/src/commands/framework/define-command.js.map +1 -0
  253. package/dist/src/commands/framework/define-command.test.d.ts +5 -0
  254. package/dist/src/commands/framework/define-command.test.d.ts.map +1 -0
  255. package/dist/src/commands/framework/define-command.test.js +135 -0
  256. package/dist/src/commands/framework/define-command.test.js.map +1 -0
  257. package/dist/src/commands/framework/index.d.ts +8 -0
  258. package/dist/src/commands/framework/index.d.ts.map +1 -0
  259. package/dist/src/commands/framework/index.js +8 -0
  260. package/dist/src/commands/framework/index.js.map +1 -0
  261. package/dist/src/commands/index.d.ts +20 -0
  262. package/dist/src/commands/index.d.ts.map +1 -0
  263. package/dist/src/commands/index.js +20 -0
  264. package/dist/src/commands/index.js.map +1 -0
  265. package/dist/src/commands/linux/inject-credentials/inject-credentials.d.ts +15 -0
  266. package/dist/src/commands/linux/inject-credentials/inject-credentials.d.ts.map +1 -0
  267. package/dist/src/commands/linux/inject-credentials/inject-credentials.js +88 -0
  268. package/dist/src/commands/linux/inject-credentials/inject-credentials.js.map +1 -0
  269. package/dist/src/commands/linux/setup/setup.d.ts +19 -0
  270. package/dist/src/commands/linux/setup/setup.d.ts.map +1 -0
  271. package/dist/src/commands/linux/setup/setup.js +107 -0
  272. package/dist/src/commands/linux/setup/setup.js.map +1 -0
  273. package/dist/src/commands/linux/status/status.d.ts +34 -0
  274. package/dist/src/commands/linux/status/status.d.ts.map +1 -0
  275. package/dist/src/commands/linux/status/status.js +134 -0
  276. package/dist/src/commands/linux/status/status.js.map +1 -0
  277. package/dist/src/commands/plugin/install/install.d.ts +10 -0
  278. package/dist/src/commands/plugin/install/install.d.ts.map +1 -0
  279. package/dist/src/commands/plugin/install/install.js +23 -0
  280. package/dist/src/commands/plugin/install/install.js.map +1 -0
  281. package/dist/src/commands/plugin/uninstall/uninstall.d.ts +9 -0
  282. package/dist/src/commands/plugin/uninstall/uninstall.d.ts.map +1 -0
  283. package/dist/src/commands/plugin/uninstall/uninstall.js +41 -0
  284. package/dist/src/commands/plugin/uninstall/uninstall.js.map +1 -0
  285. package/dist/src/commands/process/close/close.d.ts +22 -0
  286. package/dist/src/commands/process/close/close.d.ts.map +1 -0
  287. package/dist/src/commands/process/close/close.js +34 -0
  288. package/dist/src/commands/process/close/close.js.map +1 -0
  289. package/dist/src/commands/process/format-state.d.ts +7 -0
  290. package/dist/src/commands/process/format-state.d.ts.map +1 -0
  291. package/dist/src/commands/process/format-state.js +19 -0
  292. package/dist/src/commands/process/format-state.js.map +1 -0
  293. package/dist/src/commands/process/info/info.d.ts +17 -0
  294. package/dist/src/commands/process/info/info.d.ts.map +1 -0
  295. package/dist/src/commands/process/info/info.js +38 -0
  296. package/dist/src/commands/process/info/info.js.map +1 -0
  297. package/dist/src/commands/process/info/info.test.d.ts +5 -0
  298. package/dist/src/commands/process/info/info.test.d.ts.map +1 -0
  299. package/dist/src/commands/process/info/info.test.js +58 -0
  300. package/dist/src/commands/process/info/info.test.js.map +1 -0
  301. package/dist/src/commands/process/launch/launch.d.ts +17 -0
  302. package/dist/src/commands/process/launch/launch.d.ts.map +1 -0
  303. package/dist/src/commands/process/launch/launch.js +26 -0
  304. package/dist/src/commands/process/launch/launch.js.map +1 -0
  305. package/dist/src/commands/process/launch/launch.test.d.ts +5 -0
  306. package/dist/src/commands/process/launch/launch.test.d.ts.map +1 -0
  307. package/dist/src/commands/process/launch/launch.test.js +49 -0
  308. package/dist/src/commands/process/launch/launch.test.js.map +1 -0
  309. package/dist/src/commands/process/list/list.d.ts +16 -0
  310. package/dist/src/commands/process/list/list.d.ts.map +1 -0
  311. package/dist/src/commands/process/list/list.js +56 -0
  312. package/dist/src/commands/process/list/list.js.map +1 -0
  313. package/dist/src/commands/process/list/list.test.d.ts +5 -0
  314. package/dist/src/commands/process/list/list.test.d.ts.map +1 -0
  315. package/dist/src/commands/process/list/list.test.js +71 -0
  316. package/dist/src/commands/process/list/list.test.js.map +1 -0
  317. package/dist/src/commands/process/run/run.d.ts +31 -0
  318. package/dist/src/commands/process/run/run.d.ts.map +1 -0
  319. package/dist/src/commands/process/run/run.js +63 -0
  320. package/dist/src/commands/process/run/run.js.map +1 -0
  321. package/dist/src/commands/rgba-to-png.d.ts +17 -0
  322. package/dist/src/commands/rgba-to-png.d.ts.map +1 -0
  323. package/dist/src/commands/rgba-to-png.js +85 -0
  324. package/dist/src/commands/rgba-to-png.js.map +1 -0
  325. package/dist/src/commands/serve/serve.d.ts +17 -0
  326. package/dist/src/commands/serve/serve.d.ts.map +1 -0
  327. package/dist/src/commands/serve/serve.js +128 -0
  328. package/dist/src/commands/serve/serve.js.map +1 -0
  329. package/dist/src/commands/serve/serve.test.d.ts +5 -0
  330. package/dist/src/commands/serve/serve.test.d.ts.map +1 -0
  331. package/dist/src/commands/serve/serve.test.js +100 -0
  332. package/dist/src/commands/serve/serve.test.js.map +1 -0
  333. package/dist/src/commands/viewport/screenshot/screenshot.d.ts +17 -0
  334. package/dist/src/commands/viewport/screenshot/screenshot.d.ts.map +1 -0
  335. package/dist/src/commands/viewport/screenshot/screenshot.js +45 -0
  336. package/dist/src/commands/viewport/screenshot/screenshot.js.map +1 -0
  337. package/dist/src/commands/viewport/screenshot/screenshot.test.d.ts +5 -0
  338. package/dist/src/commands/viewport/screenshot/screenshot.test.d.ts.map +1 -0
  339. package/dist/src/commands/viewport/screenshot/screenshot.test.js +143 -0
  340. package/dist/src/commands/viewport/screenshot/screenshot.test.js.map +1 -0
  341. package/dist/src/docker/docker-delegator.d.ts +30 -0
  342. package/dist/src/docker/docker-delegator.d.ts.map +1 -0
  343. package/dist/src/docker/docker-delegator.js +201 -0
  344. package/dist/src/docker/docker-delegator.js.map +1 -0
  345. package/dist/src/docker/docker-delegator.test.d.ts +2 -0
  346. package/dist/src/docker/docker-delegator.test.d.ts.map +1 -0
  347. package/dist/src/docker/docker-delegator.test.js +132 -0
  348. package/dist/src/docker/docker-delegator.test.js.map +1 -0
  349. package/dist/src/index.d.ts +9 -2
  350. package/dist/src/index.d.ts.map +1 -1
  351. package/dist/src/index.js +6 -1
  352. package/dist/src/index.js.map +1 -1
  353. package/dist/src/index.test.d.ts +2 -0
  354. package/dist/src/index.test.d.ts.map +1 -0
  355. package/dist/src/index.test.js +51 -0
  356. package/dist/src/index.test.js.map +1 -0
  357. package/dist/src/linux/index.d.ts +12 -0
  358. package/dist/src/linux/index.d.ts.map +1 -0
  359. package/dist/src/linux/index.js +11 -0
  360. package/dist/src/linux/index.js.map +1 -0
  361. package/dist/src/linux/linux-config.d.ts +37 -0
  362. package/dist/src/linux/linux-config.d.ts.map +1 -0
  363. package/dist/src/linux/linux-config.js +70 -0
  364. package/dist/src/linux/linux-config.js.map +1 -0
  365. package/dist/src/linux/linux-config.test.d.ts +2 -0
  366. package/dist/src/linux/linux-config.test.d.ts.map +1 -0
  367. package/dist/src/linux/linux-config.test.js +54 -0
  368. package/dist/src/linux/linux-config.test.js.map +1 -0
  369. package/dist/src/linux/linux-credential-writer.d.ts +35 -0
  370. package/dist/src/linux/linux-credential-writer.d.ts.map +1 -0
  371. package/dist/src/linux/linux-credential-writer.js +300 -0
  372. package/dist/src/linux/linux-credential-writer.js.map +1 -0
  373. package/dist/src/linux/linux-display-manager.d.ts +24 -0
  374. package/dist/src/linux/linux-display-manager.d.ts.map +1 -0
  375. package/dist/src/linux/linux-display-manager.js +92 -0
  376. package/dist/src/linux/linux-display-manager.js.map +1 -0
  377. package/dist/src/linux/linux-env-guard.d.ts +13 -0
  378. package/dist/src/linux/linux-env-guard.d.ts.map +1 -0
  379. package/dist/src/linux/linux-env-guard.js +31 -0
  380. package/dist/src/linux/linux-env-guard.js.map +1 -0
  381. package/dist/src/linux/linux-env-guard.test.d.ts +2 -0
  382. package/dist/src/linux/linux-env-guard.test.d.ts.map +1 -0
  383. package/dist/src/linux/linux-env-guard.test.js +48 -0
  384. package/dist/src/linux/linux-env-guard.test.js.map +1 -0
  385. package/dist/src/linux/linux-fflags.d.ts +17 -0
  386. package/dist/src/linux/linux-fflags.d.ts.map +1 -0
  387. package/dist/src/linux/linux-fflags.js +33 -0
  388. package/dist/src/linux/linux-fflags.js.map +1 -0
  389. package/dist/src/linux/linux-fflags.test.d.ts +2 -0
  390. package/dist/src/linux/linux-fflags.test.d.ts.map +1 -0
  391. package/dist/src/linux/linux-fflags.test.js +55 -0
  392. package/dist/src/linux/linux-fflags.test.js.map +1 -0
  393. package/dist/src/linux/linux-prerequisites.d.ts +24 -0
  394. package/dist/src/linux/linux-prerequisites.d.ts.map +1 -0
  395. package/dist/src/linux/linux-prerequisites.js +118 -0
  396. package/dist/src/linux/linux-prerequisites.js.map +1 -0
  397. package/dist/src/linux/linux-shader-patcher.d.ts +17 -0
  398. package/dist/src/linux/linux-shader-patcher.d.ts.map +1 -0
  399. package/dist/src/linux/linux-shader-patcher.js +48 -0
  400. package/dist/src/linux/linux-shader-patcher.js.map +1 -0
  401. package/dist/src/linux/linux-shader-patcher.test.d.ts +2 -0
  402. package/dist/src/linux/linux-shader-patcher.test.d.ts.map +1 -0
  403. package/dist/src/linux/linux-shader-patcher.test.js +55 -0
  404. package/dist/src/linux/linux-shader-patcher.test.js.map +1 -0
  405. package/dist/src/linux/linux-studio-installer.d.ts +10 -0
  406. package/dist/src/linux/linux-studio-installer.d.ts.map +1 -0
  407. package/dist/src/linux/linux-studio-installer.js +79 -0
  408. package/dist/src/linux/linux-studio-installer.js.map +1 -0
  409. package/dist/src/linux/linux-studio-launcher.d.ts +10 -0
  410. package/dist/src/linux/linux-studio-launcher.d.ts.map +1 -0
  411. package/dist/src/linux/linux-studio-launcher.js +73 -0
  412. package/dist/src/linux/linux-studio-launcher.js.map +1 -0
  413. package/dist/src/linux/linux-version-resolver.d.ts +18 -0
  414. package/dist/src/linux/linux-version-resolver.d.ts.map +1 -0
  415. package/dist/src/linux/linux-version-resolver.js +49 -0
  416. package/dist/src/linux/linux-version-resolver.js.map +1 -0
  417. package/dist/src/linux/linux-wine-env.d.ts +11 -0
  418. package/dist/src/linux/linux-wine-env.d.ts.map +1 -0
  419. package/dist/src/linux/linux-wine-env.js +33 -0
  420. package/dist/src/linux/linux-wine-env.js.map +1 -0
  421. package/dist/src/linux/linux-wine-env.test.d.ts +2 -0
  422. package/dist/src/linux/linux-wine-env.test.d.ts.map +1 -0
  423. package/dist/src/linux/linux-wine-env.test.js +47 -0
  424. package/dist/src/linux/linux-wine-env.test.js.map +1 -0
  425. package/dist/src/plugin/persistent-plugin-installer.d.ts +21 -0
  426. package/dist/src/plugin/persistent-plugin-installer.d.ts.map +1 -0
  427. package/dist/src/plugin/persistent-plugin-installer.js +69 -0
  428. package/dist/src/plugin/persistent-plugin-installer.js.map +1 -0
  429. package/dist/src/plugin/persistent-plugin-installer.test.d.ts +5 -0
  430. package/dist/src/plugin/persistent-plugin-installer.test.d.ts.map +1 -0
  431. package/dist/src/plugin/persistent-plugin-installer.test.js +109 -0
  432. package/dist/src/plugin/persistent-plugin-installer.test.js.map +1 -0
  433. package/dist/src/plugin/plugin-discovery.d.ts +7 -0
  434. package/dist/src/plugin/plugin-discovery.d.ts.map +1 -0
  435. package/dist/src/plugin/plugin-discovery.js +18 -0
  436. package/dist/src/plugin/plugin-discovery.js.map +1 -0
  437. package/dist/src/plugin/plugin-discovery.test.d.ts +5 -0
  438. package/dist/src/plugin/plugin-discovery.test.d.ts.map +1 -0
  439. package/dist/src/plugin/plugin-discovery.test.js +55 -0
  440. package/dist/src/plugin/plugin-discovery.test.js.map +1 -0
  441. package/dist/src/plugin/plugin-injector.js +1 -1
  442. package/dist/src/plugin/plugin-injector.js.map +1 -1
  443. package/dist/src/process/studio-process-manager.d.ts +7 -3
  444. package/dist/src/process/studio-process-manager.d.ts.map +1 -1
  445. package/dist/src/process/studio-process-manager.js +38 -11
  446. package/dist/src/process/studio-process-manager.js.map +1 -1
  447. package/dist/src/process/studio-process-manager.test.js +18 -1
  448. package/dist/src/process/studio-process-manager.test.js.map +1 -1
  449. package/dist/src/server/action-dispatcher.d.ts +35 -0
  450. package/dist/src/server/action-dispatcher.d.ts.map +1 -0
  451. package/dist/src/server/action-dispatcher.js +67 -0
  452. package/dist/src/server/action-dispatcher.js.map +1 -0
  453. package/dist/src/server/action-dispatcher.test.d.ts +6 -0
  454. package/dist/src/server/action-dispatcher.test.d.ts.map +1 -0
  455. package/dist/src/server/action-dispatcher.test.js +173 -0
  456. package/dist/src/server/action-dispatcher.test.js.map +1 -0
  457. package/dist/src/server/index.d.ts +1 -1
  458. package/dist/src/server/index.d.ts.map +1 -1
  459. package/dist/src/server/pending-request-map.d.ts +33 -0
  460. package/dist/src/server/pending-request-map.d.ts.map +1 -0
  461. package/dist/src/server/pending-request-map.js +69 -0
  462. package/dist/src/server/pending-request-map.js.map +1 -0
  463. package/dist/src/server/pending-request-map.test.d.ts +2 -0
  464. package/dist/src/server/pending-request-map.test.d.ts.map +1 -0
  465. package/dist/src/server/pending-request-map.test.js +192 -0
  466. package/dist/src/server/pending-request-map.test.js.map +1 -0
  467. package/dist/src/server/plugin-detection.test.d.ts +7 -0
  468. package/dist/src/server/plugin-detection.test.d.ts.map +1 -0
  469. package/dist/src/server/plugin-detection.test.js +154 -0
  470. package/dist/src/server/plugin-detection.test.js.map +1 -0
  471. package/dist/src/server/studio-bridge-server.d.ts +44 -7
  472. package/dist/src/server/studio-bridge-server.d.ts.map +1 -1
  473. package/dist/src/server/studio-bridge-server.js +341 -91
  474. package/dist/src/server/studio-bridge-server.js.map +1 -1
  475. package/dist/src/server/studio-bridge-server.test.js +231 -207
  476. package/dist/src/server/studio-bridge-server.test.js.map +1 -1
  477. package/dist/src/server/web-socket-protocol-basic.test.d.ts +2 -0
  478. package/dist/src/server/web-socket-protocol-basic.test.d.ts.map +1 -0
  479. package/dist/src/server/web-socket-protocol-basic.test.js +98 -0
  480. package/dist/src/server/web-socket-protocol-basic.test.js.map +1 -0
  481. package/dist/src/server/web-socket-protocol.d.ts +218 -20
  482. package/dist/src/server/web-socket-protocol.d.ts.map +1 -1
  483. package/dist/src/server/web-socket-protocol.js +346 -20
  484. package/dist/src/server/web-socket-protocol.js.map +1 -1
  485. package/dist/src/server/web-socket-protocol.test.js +572 -146
  486. package/dist/src/server/web-socket-protocol.test.js.map +1 -1
  487. package/dist/src/test/e2e/hand-off.test.d.ts +9 -0
  488. package/dist/src/test/e2e/hand-off.test.d.ts.map +1 -0
  489. package/dist/src/test/e2e/hand-off.test.js +274 -0
  490. package/dist/src/test/e2e/hand-off.test.js.map +1 -0
  491. package/dist/src/test/e2e/persistent-session.test.d.ts +11 -0
  492. package/dist/src/test/e2e/persistent-session.test.d.ts.map +1 -0
  493. package/dist/src/test/e2e/persistent-session.test.js +367 -0
  494. package/dist/src/test/e2e/persistent-session.test.js.map +1 -0
  495. package/dist/src/test/e2e/split-server.test.d.ts +14 -0
  496. package/dist/src/test/e2e/split-server.test.d.ts.map +1 -0
  497. package/dist/src/test/e2e/split-server.test.js +230 -0
  498. package/dist/src/test/e2e/split-server.test.js.map +1 -0
  499. package/dist/src/test/helpers/mock-plugin-client.d.ts +69 -0
  500. package/dist/src/test/helpers/mock-plugin-client.d.ts.map +1 -0
  501. package/dist/src/test/helpers/mock-plugin-client.js +213 -0
  502. package/dist/src/test/helpers/mock-plugin-client.js.map +1 -0
  503. package/dist/tsconfig.tsbuildinfo +1 -1
  504. package/docker/.dockerignore +2 -0
  505. package/docker/Dockerfile +113 -0
  506. package/docker/docker-compose.yml +20 -0
  507. package/docker/entrypoint.sh +19 -0
  508. package/package.json +8 -6
  509. package/src/bridge/bridge-connection-remote.test.ts +189 -0
  510. package/src/bridge/bridge-connection.test.ts +1076 -0
  511. package/src/bridge/bridge-connection.ts +718 -0
  512. package/src/bridge/bridge-session.test.ts +336 -0
  513. package/src/bridge/bridge-session.ts +365 -0
  514. package/src/bridge/index.ts +42 -0
  515. package/src/bridge/internal/__tests__/failover-crash.test.ts +191 -0
  516. package/src/bridge/internal/__tests__/failover-graceful.test.ts +268 -0
  517. package/src/bridge/internal/__tests__/failover-inflight.test.ts +329 -0
  518. package/src/bridge/internal/__tests__/host-client-integration.test.ts +387 -0
  519. package/src/bridge/internal/bridge-client.test.ts +399 -0
  520. package/src/bridge/internal/bridge-client.ts +434 -0
  521. package/src/bridge/internal/bridge-host.test.ts +501 -0
  522. package/src/bridge/internal/bridge-host.ts +531 -0
  523. package/src/bridge/internal/environment-detection.test.ts +180 -0
  524. package/src/bridge/internal/environment-detection.ts +119 -0
  525. package/src/bridge/internal/hand-off.test.ts +408 -0
  526. package/src/bridge/internal/hand-off.ts +275 -0
  527. package/src/bridge/internal/health-endpoint.test.ts +147 -0
  528. package/src/bridge/internal/health-endpoint.ts +100 -0
  529. package/src/bridge/internal/host-protocol.test.ts +415 -0
  530. package/src/bridge/internal/host-protocol.ts +255 -0
  531. package/src/bridge/internal/session-tracker.test.ts +535 -0
  532. package/src/bridge/internal/session-tracker.ts +198 -0
  533. package/src/bridge/internal/transport-client.test.ts +241 -0
  534. package/src/bridge/internal/transport-client.ts +194 -0
  535. package/src/bridge/internal/transport-server.test.ts +220 -0
  536. package/src/bridge/internal/transport-server.ts +242 -0
  537. package/src/bridge/types.ts +161 -0
  538. package/src/cli/adapters/cli-command-adapter-handler.test.ts +318 -0
  539. package/src/cli/adapters/cli-command-adapter.test.ts +221 -0
  540. package/src/cli/adapters/cli-command-adapter.ts +342 -0
  541. package/src/cli/adapters/group-builder.test.ts +146 -0
  542. package/src/cli/adapters/group-builder.ts +81 -0
  543. package/src/cli/adapters/help-formatter.test.ts +97 -0
  544. package/src/cli/adapters/help-formatter.ts +86 -0
  545. package/src/cli/adapters/target-resolver.test.ts +222 -0
  546. package/src/cli/adapters/target-resolver.ts +144 -0
  547. package/src/cli/args/global-args.ts +2 -0
  548. package/src/cli/cli.ts +100 -21
  549. package/src/cli/resolve-script-content.ts +36 -0
  550. package/src/cli/resolve-session.test.ts +141 -0
  551. package/src/cli/resolve-session.ts +66 -0
  552. package/src/cli/script-executor.ts +22 -4
  553. package/src/cli/types.ts +11 -0
  554. package/src/commands/connect.test.ts +61 -0
  555. package/src/commands/connect.ts +32 -0
  556. package/src/commands/console/exec/exec.test.ts +258 -0
  557. package/src/commands/console/exec/exec.ts +130 -0
  558. package/src/commands/console/exec/execute.luau +202 -0
  559. package/src/commands/console/logs/logs.test.ts +138 -0
  560. package/src/commands/console/logs/logs.ts +115 -0
  561. package/src/commands/console/logs/query-logs.luau +76 -0
  562. package/src/commands/disconnect.test.ts +21 -0
  563. package/src/commands/disconnect.ts +12 -0
  564. package/src/commands/explorer/query/query-data-model.luau +206 -0
  565. package/src/commands/explorer/query/query.test.ts +297 -0
  566. package/src/commands/explorer/query/query.ts +157 -0
  567. package/src/commands/formatters.test.ts +237 -0
  568. package/src/commands/framework/action-loader.test.ts +118 -0
  569. package/src/commands/framework/action-loader.ts +65 -0
  570. package/src/commands/framework/arg-builder.test.ts +298 -0
  571. package/src/commands/framework/arg-builder.ts +203 -0
  572. package/src/commands/framework/command-registry.test.ts +204 -0
  573. package/src/commands/framework/command-registry.ts +51 -0
  574. package/src/commands/framework/define-command.test.ts +161 -0
  575. package/src/commands/framework/define-command.ts +114 -0
  576. package/src/commands/framework/index.ts +33 -0
  577. package/src/commands/index.ts +72 -0
  578. package/src/commands/linux/inject-credentials/inject-credentials.ts +118 -0
  579. package/src/commands/linux/setup/setup.ts +145 -0
  580. package/src/commands/linux/status/status.ts +180 -0
  581. package/src/commands/plugin/install/install.ts +31 -0
  582. package/src/commands/plugin/uninstall/uninstall.ts +54 -0
  583. package/src/commands/process/close/close.ts +52 -0
  584. package/src/commands/process/format-state.ts +21 -0
  585. package/src/commands/process/info/info.test.ts +76 -0
  586. package/src/commands/process/info/info.ts +54 -0
  587. package/src/commands/process/info/query-state.luau +48 -0
  588. package/src/commands/process/launch/launch.test.ts +65 -0
  589. package/src/commands/process/launch/launch.ts +45 -0
  590. package/src/commands/process/list/list.test.ts +82 -0
  591. package/src/commands/process/list/list.ts +75 -0
  592. package/src/commands/process/run/run.ts +98 -0
  593. package/src/commands/rgba-to-png.ts +98 -0
  594. package/src/commands/serve/serve.test.ts +139 -0
  595. package/src/commands/serve/serve.ts +161 -0
  596. package/src/commands/viewport/screenshot/capture-screenshot.luau +247 -0
  597. package/src/commands/viewport/screenshot/screenshot.test.ts +181 -0
  598. package/src/commands/viewport/screenshot/screenshot.ts +71 -0
  599. package/src/docker/docker-delegator.test.ts +159 -0
  600. package/src/docker/docker-delegator.ts +240 -0
  601. package/src/index.test.ts +58 -0
  602. package/src/index.ts +104 -3
  603. package/src/linux/README.md +130 -0
  604. package/src/linux/index.ts +25 -0
  605. package/src/linux/linux-config.test.ts +66 -0
  606. package/src/linux/linux-config.ts +102 -0
  607. package/src/linux/linux-credential-writer.ts +421 -0
  608. package/src/linux/linux-display-manager.ts +106 -0
  609. package/src/linux/linux-env-guard.test.ts +62 -0
  610. package/src/linux/linux-env-guard.ts +38 -0
  611. package/src/linux/linux-fflags.test.ts +78 -0
  612. package/src/linux/linux-fflags.ts +48 -0
  613. package/src/linux/linux-prerequisites.ts +152 -0
  614. package/src/linux/linux-shader-patcher.test.ts +76 -0
  615. package/src/linux/linux-shader-patcher.ts +56 -0
  616. package/src/linux/linux-studio-installer.ts +113 -0
  617. package/src/linux/linux-studio-launcher.ts +90 -0
  618. package/src/linux/linux-version-resolver.ts +74 -0
  619. package/src/linux/linux-wine-env.test.ts +56 -0
  620. package/src/linux/linux-wine-env.ts +38 -0
  621. package/src/linux/write-cred.c +48 -0
  622. package/src/plugin/persistent-plugin-installer.test.ts +168 -0
  623. package/src/plugin/persistent-plugin-installer.ts +90 -0
  624. package/src/plugin/plugin-discovery.test.ts +70 -0
  625. package/src/plugin/plugin-discovery.ts +21 -0
  626. package/src/plugin/plugin-injector.ts +1 -1
  627. package/src/process/studio-process-manager.test.ts +22 -1
  628. package/src/process/studio-process-manager.ts +57 -18
  629. package/src/server/action-dispatcher.test.ts +240 -0
  630. package/src/server/action-dispatcher.ts +89 -0
  631. package/src/server/index.ts +0 -3
  632. package/src/server/pending-request-map.test.ts +261 -0
  633. package/src/server/pending-request-map.ts +87 -0
  634. package/src/server/plugin-detection.test.ts +195 -0
  635. package/src/server/studio-bridge-server.test.ts +321 -283
  636. package/src/server/studio-bridge-server.ts +469 -111
  637. package/src/server/web-socket-protocol-basic.test.ts +131 -0
  638. package/src/server/web-socket-protocol.test.ts +658 -159
  639. package/src/server/web-socket-protocol.ts +668 -58
  640. package/src/test/e2e/hand-off.test.ts +338 -0
  641. package/src/test/e2e/persistent-session.test.ts +442 -0
  642. package/src/test/e2e/split-server.test.ts +290 -0
  643. package/src/test/helpers/mock-plugin-client.ts +276 -0
  644. package/templates/studio-bridge-plugin/src/Shared/ActionRouter.luau +245 -0
  645. package/templates/studio-bridge-plugin/src/Shared/DiscoveryStateMachine.luau +203 -0
  646. package/templates/studio-bridge-plugin/src/Shared/MessageBuffer.luau +144 -0
  647. package/templates/studio-bridge-plugin/src/Shared/Protocol.luau +132 -0
  648. package/templates/studio-bridge-plugin/src/StudioBridgePlugin.server.lua +364 -133
  649. package/templates/studio-bridge-plugin/src/Vendor/png.luau +1247 -0
  650. package/templates/studio-bridge-plugin-test/test/actions.test.luau +580 -0
  651. package/templates/studio-bridge-plugin-test/test/discovery.test.luau +622 -0
  652. package/templates/studio-bridge-plugin-test/test/execute-handler.test.luau +406 -0
  653. package/templates/studio-bridge-plugin-test/test/hash-lifecycle.test.luau +814 -0
  654. package/templates/studio-bridge-plugin-test/test/integration.test.luau +1020 -0
  655. package/templates/studio-bridge-plugin-test/test/new-actions.test.luau +339 -0
  656. package/templates/studio-bridge-plugin-test/test/plugin-entry.test.luau +493 -0
  657. package/templates/studio-bridge-plugin-test/test/protocol.test.luau +506 -0
  658. package/templates/studio-bridge-plugin-test/test/roblox-mocks.luau +108 -0
  659. package/templates/studio-bridge-plugin-test/test/test-runner.luau +112 -0
  660. package/dist/src/cli/commands/exec-command.d.ts +0 -15
  661. package/dist/src/cli/commands/exec-command.d.ts.map +0 -1
  662. package/dist/src/cli/commands/exec-command.js +0 -35
  663. package/dist/src/cli/commands/exec-command.js.map +0 -1
  664. package/dist/src/cli/commands/run-command.d.ts +0 -15
  665. package/dist/src/cli/commands/run-command.d.ts.map +0 -1
  666. package/dist/src/cli/commands/run-command.js +0 -47
  667. package/dist/src/cli/commands/run-command.js.map +0 -1
  668. package/dist/src/cli/commands/terminal/terminal-command.d.ts +0 -17
  669. package/dist/src/cli/commands/terminal/terminal-command.d.ts.map +0 -1
  670. package/dist/src/cli/commands/terminal/terminal-command.js +0 -41
  671. package/dist/src/cli/commands/terminal/terminal-command.js.map +0 -1
  672. package/dist/src/cli/commands/terminal/terminal-editor.d.ts +0 -43
  673. package/dist/src/cli/commands/terminal/terminal-editor.d.ts.map +0 -1
  674. package/dist/src/cli/commands/terminal/terminal-editor.js +0 -430
  675. package/dist/src/cli/commands/terminal/terminal-editor.js.map +0 -1
  676. package/dist/src/cli/commands/terminal/terminal-mode.d.ts +0 -13
  677. package/dist/src/cli/commands/terminal/terminal-mode.d.ts.map +0 -1
  678. package/dist/src/cli/commands/terminal/terminal-mode.js +0 -141
  679. package/dist/src/cli/commands/terminal/terminal-mode.js.map +0 -1
  680. package/dist/src/server/web-socket-protocol.smoke.test.d.ts +0 -6
  681. package/dist/src/server/web-socket-protocol.smoke.test.d.ts.map +0 -1
  682. package/dist/src/server/web-socket-protocol.smoke.test.js +0 -196
  683. package/dist/src/server/web-socket-protocol.smoke.test.js.map +0 -1
  684. package/src/cli/commands/exec-command.ts +0 -48
  685. package/src/cli/commands/run-command.ts +0 -63
  686. package/src/cli/commands/terminal/terminal-command.ts +0 -54
  687. package/src/cli/commands/terminal/terminal-editor.ts +0 -500
  688. package/src/cli/commands/terminal/terminal-mode.ts +0 -184
  689. package/src/server/web-socket-protocol.smoke.test.ts +0 -255
@@ -0,0 +1,1020 @@
1
+ --[[
2
+ Integration tests for Phase 0.5 plugin modules.
3
+
4
+ Tests that Protocol, ActionRouter, MessageBuffer, and DiscoveryStateMachine
5
+ compose correctly as an integrated system. Each test exercises multiple modules
6
+ together, validating the full data flow rather than individual module behavior.
7
+ ]]
8
+
9
+ local ActionRouter = require("../../studio-bridge-plugin/src/Shared/ActionRouter")
10
+ local DiscoveryStateMachine = require("../../studio-bridge-plugin/src/Shared/DiscoveryStateMachine")
11
+ local MessageBuffer = require("../../studio-bridge-plugin/src/Shared/MessageBuffer")
12
+ local Protocol = require("../../studio-bridge-plugin/src/Shared/Protocol")
13
+
14
+ -- ---------------------------------------------------------------------------
15
+ -- Test helpers
16
+ -- ---------------------------------------------------------------------------
17
+
18
+ local function assertEqual(actual: any, expected: any, label: string?)
19
+ if actual ~= expected then
20
+ error(
21
+ string.format(
22
+ "%sexpected %s, got %s",
23
+ if label then label .. ": " else "",
24
+ tostring(expected),
25
+ tostring(actual)
26
+ )
27
+ )
28
+ end
29
+ end
30
+
31
+ local function assertNil(value: any, label: string?)
32
+ if value ~= nil then
33
+ error(string.format("%sexpected nil, got %s", if label then label .. ": " else "", tostring(value)))
34
+ end
35
+ end
36
+
37
+ local function assertNotNil(value: any, label: string?)
38
+ if value == nil then
39
+ error(string.format("%sexpected non-nil value", if label then label .. ": " else ""))
40
+ end
41
+ end
42
+
43
+ local function assertTrue(value: any, label: string?)
44
+ if not value then
45
+ error(string.format("%sexpected truthy value, got %s", if label then label .. ": " else "", tostring(value)))
46
+ end
47
+ end
48
+
49
+ local function assertContains(str: string, substring: string, label: string?)
50
+ if not string.find(str, substring, 1, true) then
51
+ error(
52
+ string.format(
53
+ "%sexpected string to contain '%s', got '%s'",
54
+ if label then label .. ": " else "",
55
+ substring,
56
+ str
57
+ )
58
+ )
59
+ end
60
+ end
61
+
62
+ -- ---------------------------------------------------------------------------
63
+ -- Tests
64
+ -- ---------------------------------------------------------------------------
65
+
66
+ local tests = {}
67
+
68
+ -- ===========================================================================
69
+ -- 1. Protocol + ActionRouter: encode request, decode, dispatch, encode response
70
+ -- ===========================================================================
71
+
72
+ table.insert(tests, {
73
+ name = "Protocol + ActionRouter: queryState round-trip through dispatch",
74
+ fn = function()
75
+ -- Set up a router with a queryState handler
76
+ local router = ActionRouter.new()
77
+ router:setResponseType("queryState", "stateResult")
78
+ router:register("queryState", function(_payload, _requestId, _sessionId)
79
+ return { state = "Edit", placeId = 12345, placeName = "TestPlace", gameId = 67890 }
80
+ end)
81
+
82
+ -- Encode a queryState request using Protocol
83
+ local encoded = Protocol.encode({
84
+ type = "queryState",
85
+ sessionId = "int-sess-001",
86
+ requestId = "int-req-001",
87
+ payload = {},
88
+ })
89
+
90
+ -- Decode it back
91
+ local decoded, decodeErr = Protocol.decode(encoded)
92
+ assertNil(decodeErr, "decode error")
93
+ assertNotNil(decoded, "decoded message")
94
+ assertEqual(decoded.type, "queryState")
95
+ assertEqual(decoded.sessionId, "int-sess-001")
96
+ assertEqual(decoded.requestId, "int-req-001")
97
+
98
+ -- Dispatch through ActionRouter
99
+ local response = router:dispatch(decoded)
100
+ assertNotNil(response, "dispatch response")
101
+ assertEqual(response.type, "stateResult")
102
+ assertEqual(response.sessionId, "int-sess-001")
103
+ assertEqual(response.requestId, "int-req-001")
104
+ assertEqual(response.payload.state, "Edit")
105
+ assertEqual(response.payload.placeId, 12345)
106
+
107
+ -- Encode the response back through Protocol
108
+ local responseEncoded = Protocol.encode({
109
+ type = response.type,
110
+ sessionId = response.sessionId,
111
+ requestId = response.requestId,
112
+ payload = response.payload,
113
+ })
114
+
115
+ -- Decode the response to verify it round-trips cleanly
116
+ local responseParsed, respErr = Protocol.decode(responseEncoded)
117
+ assertNil(respErr, "response decode error")
118
+ assertNotNil(responseParsed, "response parsed")
119
+ assertEqual(responseParsed.type, "stateResult")
120
+ assertEqual(responseParsed.payload.state, "Edit")
121
+ assertEqual(responseParsed.payload.placeName, "TestPlace")
122
+ end,
123
+ })
124
+
125
+ -- ===========================================================================
126
+ -- 2. Protocol + ActionRouter: execute action with scriptComplete response
127
+ -- ===========================================================================
128
+
129
+ table.insert(tests, {
130
+ name = "Protocol + ActionRouter: execute round-trip produces scriptComplete",
131
+ fn = function()
132
+ local router = ActionRouter.new()
133
+ local capturedScript = nil
134
+
135
+ router:setResponseType("execute", "scriptComplete")
136
+ router:register("execute", function(payload, _requestId, _sessionId)
137
+ capturedScript = payload.script
138
+ return { success = true }
139
+ end)
140
+
141
+ -- Simulate server sending an execute message
142
+ local executeMsg = Protocol.encode({
143
+ type = "execute",
144
+ sessionId = "exec-sess",
145
+ requestId = "exec-req-001",
146
+ payload = { script = "print('hello world')" },
147
+ })
148
+
149
+ -- Decode and dispatch
150
+ local decoded, err = Protocol.decode(executeMsg)
151
+ assertNil(err, "decode error")
152
+ local response = router:dispatch(decoded)
153
+
154
+ -- Verify handler received the script
155
+ assertEqual(capturedScript, "print('hello world')", "handler received script")
156
+
157
+ -- Verify response is scriptComplete
158
+ assertNotNil(response, "response")
159
+ assertEqual(response.type, "scriptComplete")
160
+ assertEqual(response.payload.success, true)
161
+ assertEqual(response.requestId, "exec-req-001")
162
+
163
+ -- Re-encode and verify the scriptComplete round-trips
164
+ local responseJson = Protocol.encode({
165
+ type = response.type,
166
+ sessionId = response.sessionId,
167
+ requestId = response.requestId,
168
+ payload = response.payload,
169
+ })
170
+ local reparsed, rerr = Protocol.decode(responseJson)
171
+ assertNil(rerr, "re-decode error")
172
+ assertEqual(reparsed.type, "scriptComplete")
173
+ assertEqual(reparsed.payload.success, true)
174
+ end,
175
+ })
176
+
177
+ -- ===========================================================================
178
+ -- 3. ActionRouter + MessageBuffer: queryLogs reads from buffer
179
+ -- ===========================================================================
180
+
181
+ table.insert(tests, {
182
+ name = "ActionRouter + MessageBuffer: queryLogs handler reads from buffer",
183
+ fn = function()
184
+ local buffer = MessageBuffer.new(100)
185
+ local router = ActionRouter.new()
186
+
187
+ -- Register a queryLogs handler that reads from the buffer
188
+ router:setResponseType("queryLogs", "logsResult")
189
+ router:register("queryLogs", function(payload, _requestId, _sessionId)
190
+ local direction = payload.direction or "tail"
191
+ local count = payload.count or 50
192
+ return buffer:get(direction, count)
193
+ end)
194
+
195
+ -- Push log entries
196
+ buffer:push({ level = "Print", body = "Starting up...", timestamp = 1000 })
197
+ buffer:push({ level = "Warning", body = "Low memory", timestamp = 2000 })
198
+ buffer:push({ level = "Error", body = "Connection failed", timestamp = 3000 })
199
+ buffer:push({ level = "Print", body = "Retrying...", timestamp = 4000 })
200
+ buffer:push({ level = "Print", body = "Connected!", timestamp = 5000 })
201
+
202
+ -- Dispatch a queryLogs request for tail 3
203
+ local response = router:dispatch({
204
+ type = "queryLogs",
205
+ sessionId = "logs-sess",
206
+ requestId = "logs-req-001",
207
+ payload = { direction = "tail", count = 3 },
208
+ })
209
+
210
+ assertNotNil(response, "response")
211
+ assertEqual(response.type, "logsResult")
212
+ assertEqual(#response.payload.entries, 3)
213
+ assertEqual(response.payload.entries[1].body, "Connection failed")
214
+ assertEqual(response.payload.entries[2].body, "Retrying...")
215
+ assertEqual(response.payload.entries[3].body, "Connected!")
216
+ assertEqual(response.payload.total, 5)
217
+ assertEqual(response.payload.bufferCapacity, 100)
218
+
219
+ -- Now request head 2
220
+ local headResponse = router:dispatch({
221
+ type = "queryLogs",
222
+ sessionId = "logs-sess",
223
+ requestId = "logs-req-002",
224
+ payload = { direction = "head", count = 2 },
225
+ })
226
+
227
+ assertNotNil(headResponse, "head response")
228
+ assertEqual(#headResponse.payload.entries, 2)
229
+ assertEqual(headResponse.payload.entries[1].body, "Starting up...")
230
+ assertEqual(headResponse.payload.entries[2].body, "Low memory")
231
+ end,
232
+ })
233
+
234
+ -- ===========================================================================
235
+ -- 4. Protocol + ActionRouter + MessageBuffer: queryLogs wire round-trip
236
+ -- ===========================================================================
237
+
238
+ table.insert(tests, {
239
+ name = "Protocol + ActionRouter + MessageBuffer: queryLogs full wire round-trip",
240
+ fn = function()
241
+ local buffer = MessageBuffer.new(50)
242
+ local router = ActionRouter.new()
243
+
244
+ router:setResponseType("queryLogs", "logsResult")
245
+ router:register("queryLogs", function(payload, _requestId, _sessionId)
246
+ return buffer:get(payload.direction, payload.count)
247
+ end)
248
+
249
+ -- Push entries
250
+ for i = 1, 10 do
251
+ buffer:push({
252
+ level = if i % 3 == 0 then "Warning" else "Print",
253
+ body = "log entry " .. tostring(i),
254
+ timestamp = i * 1000,
255
+ })
256
+ end
257
+
258
+ -- Encode queryLogs request
259
+ local requestJson = Protocol.encode({
260
+ type = "queryLogs",
261
+ sessionId = "wire-sess",
262
+ requestId = "wire-req-001",
263
+ payload = { direction = "tail", count = 5 },
264
+ })
265
+
266
+ -- Decode request
267
+ local request, decErr = Protocol.decode(requestJson)
268
+ assertNil(decErr, "decode error")
269
+
270
+ -- Dispatch
271
+ local response = router:dispatch(request)
272
+ assertNotNil(response, "response")
273
+
274
+ -- Encode response
275
+ local responseJson = Protocol.encode({
276
+ type = response.type,
277
+ sessionId = response.sessionId,
278
+ requestId = response.requestId,
279
+ payload = response.payload,
280
+ })
281
+
282
+ -- Decode response
283
+ local responseParsed, respErr = Protocol.decode(responseJson)
284
+ assertNil(respErr, "response decode error")
285
+ assertEqual(responseParsed.type, "logsResult")
286
+ assertEqual(#responseParsed.payload.entries, 5)
287
+ assertEqual(responseParsed.payload.entries[5].body, "log entry 10")
288
+ assertEqual(responseParsed.payload.total, 10)
289
+ assertEqual(responseParsed.payload.bufferCapacity, 50)
290
+ end,
291
+ })
292
+
293
+ -- ===========================================================================
294
+ -- 5. DiscoveryStateMachine + Protocol: health check and connection lifecycle
295
+ -- ===========================================================================
296
+
297
+ table.insert(tests, {
298
+ name = "DiscoveryStateMachine + Protocol: full discovery to connected lifecycle",
299
+ fn = function()
300
+ local stateTransitions: { { old: string, new: string } } = {}
301
+ local connectedConnection = nil
302
+ local disconnectedReason = nil
303
+ local targetPort = 38745
304
+
305
+ local sm = DiscoveryStateMachine.new({
306
+ portRange = { min = 38740, max = 38759 },
307
+ pollIntervalSec = 1,
308
+ }, {
309
+ scanPortsAsync = function(ports: { number }, _timeoutSec: number): (number?, string?)
310
+ -- Simulate: only the target port responds. The health body is
311
+ -- opaque to DiscoveryStateMachine, so a stub JSON suffices.
312
+ for _, port in ports do
313
+ if port == targetPort then
314
+ return port, '{"status":"ok"}'
315
+ end
316
+ end
317
+ return nil, nil
318
+ end,
319
+ connectWebSocket = function(url: string)
320
+ -- Simulate: WebSocket connection succeeds for the target port
321
+ if string.find(url, tostring(targetPort)) then
322
+ return true, { id = "mock-connection" }
323
+ end
324
+ return false, nil
325
+ end,
326
+ onStateChange = function(oldState: string, newState: string)
327
+ table.insert(stateTransitions, { old = oldState, new = newState })
328
+ end,
329
+ onConnected = function(connection: any)
330
+ connectedConnection = connection
331
+ end,
332
+ onDisconnected = function(reason: string?)
333
+ disconnectedReason = reason
334
+ end,
335
+ })
336
+
337
+ -- Start the state machine
338
+ assertEqual(sm:getState(), "idle")
339
+ sm:start()
340
+ assertEqual(sm:getState(), "searching")
341
+
342
+ -- First poll triggers immediate scan (nextPollAt was set to 0)
343
+ sm:pollAsync()
344
+
345
+ -- State machine should have found the port and connected
346
+ assertEqual(sm:getState(), "connected")
347
+ assertNotNil(connectedConnection, "connection object")
348
+ assertEqual(connectedConnection.id, "mock-connection")
349
+
350
+ -- Verify state transitions: idle -> searching -> connecting -> connected
351
+ assertTrue(#stateTransitions >= 3, "at least 3 transitions")
352
+ assertEqual(stateTransitions[1].old, "idle")
353
+ assertEqual(stateTransitions[1].new, "searching")
354
+ assertEqual(stateTransitions[2].old, "searching")
355
+ assertEqual(stateTransitions[2].new, "connecting")
356
+ assertEqual(stateTransitions[3].old, "connecting")
357
+ assertEqual(stateTransitions[3].new, "connected")
358
+ end,
359
+ })
360
+
361
+ -- ===========================================================================
362
+ -- 6. DiscoveryStateMachine: disconnect triggers immediate search and recovers
363
+ -- ===========================================================================
364
+
365
+ table.insert(tests, {
366
+ name = "DiscoveryStateMachine: disconnect searches immediately and reconnects when server returns",
367
+ fn = function()
368
+ local currentState = "idle"
369
+ local connectAttempts = 0
370
+ local scanAttempts = 0
371
+ local serverUp = true
372
+
373
+ local sm = DiscoveryStateMachine.new({
374
+ portRange = { min = 38740, max = 38740 }, -- single port
375
+ pollIntervalSec = 0.1,
376
+ }, {
377
+ scanPortsAsync = function(ports: { number }, _timeoutSec: number): (number?, string?)
378
+ scanAttempts = scanAttempts + 1
379
+ if serverUp then
380
+ return ports[1], "ok"
381
+ end
382
+ return nil, nil
383
+ end,
384
+ connectWebSocket = function(_url: string)
385
+ connectAttempts = connectAttempts + 1
386
+ if serverUp then
387
+ return true, { id = "conn" }
388
+ end
389
+ return false, nil
390
+ end,
391
+ onStateChange = function(_old: string, new: string)
392
+ currentState = new
393
+ end,
394
+ onConnected = function(_conn: any) end,
395
+ onDisconnected = function(_reason: string?) end,
396
+ })
397
+
398
+ -- Start and connect
399
+ sm:start()
400
+ sm:pollAsync()
401
+ assertEqual(currentState, "connected", "initial connection")
402
+
403
+ -- Simulate disconnect with server down
404
+ serverUp = false
405
+ sm:onDisconnect("connection lost")
406
+ -- Transitions straight to searching (no backoff)
407
+ assertEqual(currentState, "searching", "searching immediately after disconnect")
408
+
409
+ -- First poll triggers scan (primed), server still down -> stays searching
410
+ sm:pollAsync()
411
+ assertEqual(currentState, "searching", "stays searching when server is down")
412
+
413
+ -- Next poll should not scan yet (nextPollAt is in the future)
414
+ sm:pollAsync()
415
+ assertEqual(currentState, "searching", "still searching, waiting for poll interval")
416
+
417
+ -- Bring server back up and force next poll by setting _nextPollAt to 0
418
+ serverUp = true
419
+ sm._nextPollAt = 0
420
+
421
+ -- Next poll triggers scan -> server responds -> connects
422
+ sm:pollAsync()
423
+ assertEqual(currentState, "connected", "reconnected after server came back")
424
+ end,
425
+ })
426
+
427
+ -- ===========================================================================
428
+ -- 7. Full message lifecycle: register -> execute -> output -> scriptComplete
429
+ -- ===========================================================================
430
+
431
+ table.insert(tests, {
432
+ name = "Full lifecycle: register -> execute -> output -> scriptComplete",
433
+ fn = function()
434
+ local sessionId = "lifecycle-sess-001"
435
+ local router = ActionRouter.new()
436
+ local outputBuffer = MessageBuffer.new(100)
437
+
438
+ -- Set up execute handler that simulates script execution
439
+ router:setResponseType("execute", "scriptComplete")
440
+ router:register("execute", function(payload, _requestId, _sessionId)
441
+ -- Simulate: script produces output and completes
442
+ outputBuffer:push({
443
+ level = "Print",
444
+ body = "Script output: " .. payload.script,
445
+ timestamp = 5000,
446
+ })
447
+ return { success = true }
448
+ end)
449
+
450
+ -- Step 1: Plugin sends register
451
+ local registerMsg = Protocol.encode({
452
+ type = "register",
453
+ sessionId = sessionId,
454
+ payload = {
455
+ pluginVersion = "1.0.0",
456
+ instanceId = "inst-abc",
457
+ placeName = "TestPlace",
458
+ state = "Edit",
459
+ capabilities = { "execute", "queryState", "queryLogs" },
460
+ },
461
+ })
462
+
463
+ local registerDecoded, regErr = Protocol.decode(registerMsg)
464
+ assertNil(regErr, "register decode error")
465
+ assertEqual(registerDecoded.type, "register")
466
+ assertEqual(registerDecoded.payload.pluginVersion, "1.0.0")
467
+
468
+ -- Step 2: Server sends execute
469
+ local executeMsg = Protocol.encode({
470
+ type = "execute",
471
+ sessionId = sessionId,
472
+ requestId = "req-exec-001",
473
+ payload = { script = "print('hello')" },
474
+ })
475
+
476
+ local executeDecoded, execErr = Protocol.decode(executeMsg)
477
+ assertNil(execErr, "execute decode error")
478
+
479
+ -- Step 4: Plugin dispatches execute through ActionRouter
480
+ local scriptCompleteResponse = router:dispatch(executeDecoded)
481
+ assertNotNil(scriptCompleteResponse, "scriptComplete response")
482
+ assertEqual(scriptCompleteResponse.type, "scriptComplete")
483
+ assertEqual(scriptCompleteResponse.payload.success, true)
484
+ assertEqual(scriptCompleteResponse.requestId, "req-exec-001")
485
+
486
+ -- Step 5: Verify output was buffered
487
+ assertEqual(outputBuffer:size(), 1, "one output entry")
488
+ local logs = outputBuffer:get("tail", 1)
489
+ assertContains(logs.entries[1].body, "print('hello')")
490
+
491
+ -- Step 6: Encode the scriptComplete response (script output rides
492
+ -- inside the scriptComplete payload — there is no separate "output"
493
+ -- protocol message).
494
+ local _ = sessionId -- suppress unused-warning when output step is gone
495
+ local completeMsg = Protocol.encode({
496
+ type = scriptCompleteResponse.type,
497
+ sessionId = scriptCompleteResponse.sessionId,
498
+ requestId = scriptCompleteResponse.requestId,
499
+ payload = scriptCompleteResponse.payload,
500
+ })
501
+
502
+ local completeParsed, compErr = Protocol.decode(completeMsg)
503
+ assertNil(compErr, "scriptComplete decode error")
504
+ assertEqual(completeParsed.type, "scriptComplete")
505
+ assertEqual(completeParsed.payload.success, true)
506
+ end,
507
+ })
508
+
509
+ -- ===========================================================================
510
+ -- 8. ActionRouter error dispatch round-trips through Protocol
511
+ -- ===========================================================================
512
+
513
+ table.insert(tests, {
514
+ name = "Protocol + ActionRouter: error response round-trips through Protocol",
515
+ fn = function()
516
+ local router = ActionRouter.new()
517
+
518
+ -- No handler registered: should produce UNKNOWN_REQUEST error
519
+ local unknownRequest = Protocol.encode({
520
+ type = "captureScreenshot",
521
+ sessionId = "err-sess",
522
+ requestId = "err-req-001",
523
+ payload = {},
524
+ })
525
+
526
+ local decoded, err = Protocol.decode(unknownRequest)
527
+ assertNil(err, "decode error")
528
+
529
+ local errorResponse = router:dispatch(decoded)
530
+ assertNotNil(errorResponse, "error response")
531
+ assertEqual(errorResponse.type, "error")
532
+ assertEqual(errorResponse.payload.code, "UNKNOWN_REQUEST")
533
+
534
+ -- Encode the error response and verify it round-trips
535
+ local errorJson = Protocol.encode({
536
+ type = errorResponse.type,
537
+ sessionId = errorResponse.sessionId,
538
+ requestId = errorResponse.requestId,
539
+ payload = errorResponse.payload,
540
+ })
541
+
542
+ local errorParsed, errParseErr = Protocol.decode(errorJson)
543
+ assertNil(errParseErr, "error parse error")
544
+ assertEqual(errorParsed.type, "error")
545
+ assertEqual(errorParsed.payload.code, "UNKNOWN_REQUEST")
546
+ assertContains(errorParsed.payload.message, "captureScreenshot")
547
+ end,
548
+ })
549
+
550
+ -- ===========================================================================
551
+ -- 9. ActionRouter + MessageBuffer: buffer overflow during queryLogs
552
+ -- ===========================================================================
553
+
554
+ table.insert(tests, {
555
+ name = "ActionRouter + MessageBuffer: queryLogs with buffer overflow returns newest",
556
+ fn = function()
557
+ local buffer = MessageBuffer.new(5) -- small capacity
558
+ local router = ActionRouter.new()
559
+
560
+ router:setResponseType("queryLogs", "logsResult")
561
+ router:register("queryLogs", function(payload, _requestId, _sessionId)
562
+ return buffer:get(payload.direction, payload.count)
563
+ end)
564
+
565
+ -- Push more entries than capacity
566
+ for i = 1, 20 do
567
+ buffer:push({
568
+ level = if i % 2 == 0 then "Warning" else "Print",
569
+ body = "overflow-" .. tostring(i),
570
+ timestamp = i * 100,
571
+ })
572
+ end
573
+
574
+ -- Query tail 3 via dispatch
575
+ local response = router:dispatch({
576
+ type = "queryLogs",
577
+ sessionId = "overflow-sess",
578
+ requestId = "overflow-req",
579
+ payload = { direction = "tail", count = 3 },
580
+ })
581
+
582
+ assertNotNil(response, "response")
583
+ assertEqual(response.type, "logsResult")
584
+ assertEqual(#response.payload.entries, 3)
585
+ -- Should be the last 3 of the most recent 5 (16..20)
586
+ assertEqual(response.payload.entries[1].body, "overflow-18")
587
+ assertEqual(response.payload.entries[2].body, "overflow-19")
588
+ assertEqual(response.payload.entries[3].body, "overflow-20")
589
+ assertEqual(response.payload.total, 5, "total reflects buffer count (capped at capacity)")
590
+ assertEqual(response.payload.bufferCapacity, 5)
591
+ end,
592
+ })
593
+
594
+ -- ===========================================================================
595
+ -- 10. Multiple actions dispatched concurrently through Protocol
596
+ -- ===========================================================================
597
+
598
+ table.insert(tests, {
599
+ name = "Protocol + ActionRouter: multiple concurrent requests maintain isolation",
600
+ fn = function()
601
+ local buffer = MessageBuffer.new(100)
602
+ local router = ActionRouter.new()
603
+
604
+ -- Register multiple handlers
605
+ router:setResponseType("queryState", "stateResult")
606
+ router:setResponseType("execute", "scriptComplete")
607
+ router:setResponseType("queryLogs", "logsResult")
608
+ router:register("queryState", function(_payload, _requestId, _sessionId)
609
+ return { state = "Play", placeId = 111, placeName = "GamePlace", gameId = 222 }
610
+ end)
611
+
612
+ router:register("queryLogs", function(payload, _requestId, _sessionId)
613
+ return buffer:get(payload.direction, payload.count)
614
+ end)
615
+
616
+ router:register("execute", function(payload, _requestId, _sessionId)
617
+ return { success = true }
618
+ end)
619
+
620
+ -- Push some logs
621
+ buffer:push({ level = "Print", body = "test log", timestamp = 1000 })
622
+
623
+ -- Encode three requests with different requestIds
624
+ local requests = {
625
+ Protocol.encode({
626
+ type = "queryState",
627
+ sessionId = "multi-sess",
628
+ requestId = "multi-req-001",
629
+ payload = {},
630
+ }),
631
+ Protocol.encode({
632
+ type = "execute",
633
+ sessionId = "multi-sess",
634
+ requestId = "multi-req-002",
635
+ payload = { script = "game:GetService('Workspace')" },
636
+ }),
637
+ Protocol.encode({
638
+ type = "queryLogs",
639
+ sessionId = "multi-sess",
640
+ requestId = "multi-req-003",
641
+ payload = { direction = "tail", count = 10 },
642
+ }),
643
+ }
644
+
645
+ -- Decode and dispatch all three
646
+ local responses = {}
647
+ for _, reqJson in requests do
648
+ local decoded, err = Protocol.decode(reqJson)
649
+ assertNil(err, "decode error")
650
+ local resp = router:dispatch(decoded)
651
+ assertNotNil(resp, "response")
652
+ table.insert(responses, resp)
653
+ end
654
+
655
+ -- Verify each response has correct type and requestId
656
+ assertEqual(responses[1].type, "stateResult")
657
+ assertEqual(responses[1].requestId, "multi-req-001")
658
+ assertEqual(responses[1].payload.state, "Play")
659
+
660
+ assertEqual(responses[2].type, "scriptComplete")
661
+ assertEqual(responses[2].requestId, "multi-req-002")
662
+ assertEqual(responses[2].payload.success, true)
663
+
664
+ assertEqual(responses[3].type, "logsResult")
665
+ assertEqual(responses[3].requestId, "multi-req-003")
666
+ assertEqual(#responses[3].payload.entries, 1)
667
+ assertEqual(responses[3].payload.entries[1].body, "test log")
668
+
669
+ -- All share the same sessionId
670
+ for _, resp in responses do
671
+ assertEqual(resp.sessionId, "multi-sess")
672
+ end
673
+ end,
674
+ })
675
+
676
+ -- ===========================================================================
677
+ -- 11. DiscoveryStateMachine + Protocol: stop during connection cleans up
678
+ -- ===========================================================================
679
+
680
+ table.insert(tests, {
681
+ name = "DiscoveryStateMachine: stop during connected state fires onDisconnected",
682
+ fn = function()
683
+ local disconnectReason: string? = nil
684
+ local wasConnected = false
685
+
686
+ local sm = DiscoveryStateMachine.new({
687
+ portRange = { min = 38740, max = 38740 },
688
+ pollIntervalSec = 0.1,
689
+ }, {
690
+ scanPortsAsync = function(ports: { number }, _timeoutSec: number): (number?, string?)
691
+ return ports[1], "ok"
692
+ end,
693
+ connectWebSocket = function(_url: string)
694
+ return true, { id = "conn-stop-test" }
695
+ end,
696
+ onStateChange = function(_old: string, _new: string) end,
697
+ onConnected = function(_conn: any)
698
+ wasConnected = true
699
+ end,
700
+ onDisconnected = function(reason: string?)
701
+ disconnectReason = reason
702
+ end,
703
+ })
704
+
705
+ -- Connect
706
+ sm:start()
707
+ sm:pollAsync()
708
+ assertTrue(wasConnected, "should be connected")
709
+ assertEqual(sm:getState(), "connected")
710
+
711
+ -- Stop while connected
712
+ sm:stop()
713
+ assertEqual(sm:getState(), "idle")
714
+ assertEqual(disconnectReason, "stopped", "disconnect reason should be 'stopped'")
715
+ end,
716
+ })
717
+
718
+ -- ===========================================================================
719
+ -- 12. Protocol + ActionRouter: handler error produces encodable error message
720
+ -- ===========================================================================
721
+
722
+ table.insert(tests, {
723
+ name = "Protocol + ActionRouter: handler error encodes as valid Protocol error",
724
+ fn = function()
725
+ local router = ActionRouter.new()
726
+ router:register("queryDataModel", function(_payload, _requestId, _sessionId)
727
+ error("Instance not found: game.Workspace.Missing")
728
+ end)
729
+
730
+ -- Encode request
731
+ local requestJson = Protocol.encode({
732
+ type = "queryDataModel",
733
+ sessionId = "err-handler-sess",
734
+ requestId = "err-handler-req",
735
+ payload = { path = "game.Workspace.Missing", depth = 0 },
736
+ })
737
+
738
+ -- Decode and dispatch
739
+ local decoded, decErr = Protocol.decode(requestJson)
740
+ assertNil(decErr, "decode error")
741
+
742
+ local errorResponse = router:dispatch(decoded)
743
+ assertNotNil(errorResponse, "error response")
744
+ assertEqual(errorResponse.type, "error")
745
+ assertEqual(errorResponse.payload.code, "INTERNAL_ERROR")
746
+
747
+ -- Encode the error through Protocol
748
+ local errorJson = Protocol.encode({
749
+ type = errorResponse.type,
750
+ sessionId = errorResponse.sessionId,
751
+ requestId = errorResponse.requestId,
752
+ payload = errorResponse.payload,
753
+ })
754
+
755
+ -- Verify it decodes cleanly
756
+ local errorParsed, parseErr = Protocol.decode(errorJson)
757
+ assertNil(parseErr, "error decode error")
758
+ assertEqual(errorParsed.type, "error")
759
+ assertEqual(errorParsed.payload.code, "INTERNAL_ERROR")
760
+ assertContains(errorParsed.payload.message, "Instance not found")
761
+ assertEqual(errorParsed.sessionId, "err-handler-sess")
762
+ assertEqual(errorParsed.requestId, "err-handler-req")
763
+ end,
764
+ })
765
+
766
+ -- ===========================================================================
767
+ -- 13. Full system: discovery -> register -> queryLogs with buffered data
768
+ -- ===========================================================================
769
+
770
+ table.insert(tests, {
771
+ name = "Full system: discovery + register + queryLogs with populated buffer",
772
+ fn = function()
773
+ -- Set up the message buffer and router as if a plugin were running
774
+ local buffer = MessageBuffer.new(100)
775
+ local router = ActionRouter.new()
776
+ local discoveredPort: number? = nil
777
+
778
+ router:setResponseType("queryLogs", "logsResult")
779
+ router:register("queryLogs", function(payload, _requestId, _sessionId)
780
+ return buffer:get(payload.direction or "tail", payload.count or 50)
781
+ end)
782
+
783
+ -- Pre-populate the buffer (simulating logs accumulated during startup)
784
+ buffer:push({ level = "Print", body = "[StudioBridge] Plugin loaded", timestamp = 100 })
785
+ buffer:push({ level = "Print", body = "[StudioBridge] Searching for server...", timestamp = 200 })
786
+ buffer:push({ level = "Print", body = "[StudioBridge] Connected to port 38742", timestamp = 500 })
787
+
788
+ -- Discovery finds the server on port 38742
789
+ local sm = DiscoveryStateMachine.new({
790
+ portRange = { min = 38740, max = 38750 },
791
+ pollIntervalSec = 0.5,
792
+ }, {
793
+ scanPortsAsync = function(ports: { number }, _timeoutSec: number): (number?, string?)
794
+ for _, port in ports do
795
+ if port == 38742 then
796
+ return port, '{"status":"ok"}'
797
+ end
798
+ end
799
+ return nil, nil
800
+ end,
801
+ connectWebSocket = function(url: string)
802
+ if string.find(url, "38742") then
803
+ discoveredPort = 38742
804
+ return true, { id = "ws-conn" }
805
+ end
806
+ return false, nil
807
+ end,
808
+ onStateChange = function(_old: string, _new: string) end,
809
+ onConnected = function(_conn: any) end,
810
+ onDisconnected = function(_reason: string?) end,
811
+ })
812
+
813
+ sm:start()
814
+ sm:pollAsync()
815
+ assertEqual(sm:getState(), "connected")
816
+ assertEqual(discoveredPort, 38742)
817
+
818
+ -- Now simulate the register handshake via Protocol
819
+ local registerJson = Protocol.encode({
820
+ type = "register",
821
+ sessionId = "full-sys-sess",
822
+ payload = {
823
+ pluginVersion = "1.0.0",
824
+ instanceId = "inst-full",
825
+ placeName = "FullTestPlace",
826
+ state = "Edit",
827
+ capabilities = { "execute", "queryLogs" },
828
+ },
829
+ })
830
+
831
+ local registerDecoded, regErr = Protocol.decode(registerJson)
832
+ assertNil(regErr, "register decode error")
833
+ assertEqual(registerDecoded.type, "register")
834
+
835
+ -- Server sends queryLogs
836
+ local queryLogsJson = Protocol.encode({
837
+ type = "queryLogs",
838
+ sessionId = "full-sys-sess",
839
+ requestId = "ql-001",
840
+ payload = { direction = "tail", count = 2 },
841
+ })
842
+
843
+ local queryDecoded, qlErr = Protocol.decode(queryLogsJson)
844
+ assertNil(qlErr, "queryLogs decode error")
845
+
846
+ -- Plugin dispatches through router
847
+ local logsResponse = router:dispatch(queryDecoded)
848
+ assertNotNil(logsResponse, "logs response")
849
+ assertEqual(logsResponse.type, "logsResult")
850
+ assertEqual(#logsResponse.payload.entries, 2)
851
+ -- Last 2 entries
852
+ assertContains(logsResponse.payload.entries[1].body, "Searching for server")
853
+ assertContains(logsResponse.payload.entries[2].body, "Connected to port 38742")
854
+ assertEqual(logsResponse.payload.total, 3)
855
+ end,
856
+ })
857
+
858
+ -- ===========================================================================
859
+ -- 14. Protocol preserves register payload fields across encode/decode
860
+ -- ===========================================================================
861
+
862
+ table.insert(tests, {
863
+ name = "Protocol: register preserves payload fields across encode/decode",
864
+ fn = function()
865
+ local capabilities =
866
+ { "execute", "queryState", "captureScreenshot", "queryDataModel", "queryLogs", "subscribe", "heartbeat" }
867
+
868
+ local registerJson = Protocol.encode({
869
+ type = "register",
870
+ sessionId = "register-test-sess",
871
+ payload = {
872
+ pluginVersion = "1.2.3",
873
+ instanceId = "inst-x",
874
+ placeName = "TestPlace",
875
+ state = "Edit",
876
+ capabilities = capabilities,
877
+ },
878
+ })
879
+
880
+ local registerParsed, regErr = Protocol.decode(registerJson)
881
+ assertNil(regErr, "register error")
882
+ assertEqual(registerParsed.payload.pluginVersion, "1.2.3")
883
+ assertEqual(registerParsed.payload.instanceId, "inst-x")
884
+ assertEqual(#registerParsed.payload.capabilities, 7)
885
+ end,
886
+ })
887
+
888
+ -- ===========================================================================
889
+ -- 15. DiscoveryStateMachine: all ports fail, stays searching
890
+ -- ===========================================================================
891
+
892
+ table.insert(tests, {
893
+ name = "DiscoveryStateMachine: all ports fail stays in searching state",
894
+ fn = function()
895
+ local currentState = "idle"
896
+ local sm = DiscoveryStateMachine.new({
897
+ portRange = { min = 38740, max = 38742 }, -- 3 ports
898
+ pollIntervalSec = 0.5,
899
+ }, {
900
+ scanPortsAsync = function(_ports: { number }, _timeoutSec: number): (number?, string?)
901
+ return nil, nil -- all ports fail
902
+ end,
903
+ connectWebSocket = function(_url: string)
904
+ return false, nil
905
+ end,
906
+ onStateChange = function(_old: string, new: string)
907
+ currentState = new
908
+ end,
909
+ onConnected = function(_conn: any) end,
910
+ onDisconnected = function(_reason: string?) end,
911
+ })
912
+
913
+ sm:start()
914
+ assertEqual(currentState, "searching")
915
+
916
+ -- Poll to trigger scan
917
+ sm:pollAsync()
918
+ -- All ports failed, should stay in searching
919
+ assertEqual(currentState, "searching")
920
+
921
+ -- Next poll should skip (nextPollAt is in the future), then force it
922
+ sm._nextPollAt = 0
923
+ sm:pollAsync()
924
+ assertEqual(currentState, "searching", "still searching after second scan")
925
+ end,
926
+ })
927
+
928
+ -- ===========================================================================
929
+ -- 16. ActionRouter + Protocol: subscribe/unsubscribe flow
930
+ -- ===========================================================================
931
+
932
+ table.insert(tests, {
933
+ name = "Protocol + ActionRouter: subscribe and unsubscribe flow",
934
+ fn = function()
935
+ local router = ActionRouter.new()
936
+ local activeSubscriptions: { string } = {}
937
+
938
+ router:setResponseType("subscribe", "subscribeResult")
939
+ router:setResponseType("unsubscribe", "unsubscribeResult")
940
+ router:register("subscribe", function(payload, _requestId, _sessionId)
941
+ for _, event in payload.events do
942
+ table.insert(activeSubscriptions, event)
943
+ end
944
+ return { events = payload.events }
945
+ end)
946
+
947
+ router:register("unsubscribe", function(payload, _requestId, _sessionId)
948
+ local remaining = {}
949
+ for _, sub in activeSubscriptions do
950
+ local found = false
951
+ for _, unsub in payload.events do
952
+ if sub == unsub then
953
+ found = true
954
+ break
955
+ end
956
+ end
957
+ if not found then
958
+ table.insert(remaining, sub)
959
+ end
960
+ end
961
+ activeSubscriptions = remaining
962
+ return { events = payload.events }
963
+ end)
964
+
965
+ -- Subscribe via Protocol-encoded message
966
+ local subJson = Protocol.encode({
967
+ type = "subscribe",
968
+ sessionId = "sub-sess",
969
+ requestId = "sub-req-001",
970
+ payload = { events = { "stateChange", "logPush" } },
971
+ })
972
+
973
+ local subDecoded, subErr = Protocol.decode(subJson)
974
+ assertNil(subErr, "subscribe decode error")
975
+ local subResponse = router:dispatch(subDecoded)
976
+
977
+ assertNotNil(subResponse, "subscribe response")
978
+ assertEqual(subResponse.type, "subscribeResult")
979
+ assertEqual(#activeSubscriptions, 2)
980
+
981
+ -- Encode the subscribeResult and verify round-trip
982
+ local subResultJson = Protocol.encode({
983
+ type = subResponse.type,
984
+ sessionId = subResponse.sessionId,
985
+ requestId = subResponse.requestId,
986
+ payload = subResponse.payload,
987
+ })
988
+ local subResultParsed, srErr = Protocol.decode(subResultJson)
989
+ assertNil(srErr, "subscribeResult decode error")
990
+ assertEqual(subResultParsed.type, "subscribeResult")
991
+
992
+ -- Unsubscribe from stateChange
993
+ local unsubJson = Protocol.encode({
994
+ type = "unsubscribe",
995
+ sessionId = "sub-sess",
996
+ requestId = "sub-req-002",
997
+ payload = { events = { "stateChange" } },
998
+ })
999
+
1000
+ local unsubDecoded, unsubErr = Protocol.decode(unsubJson)
1001
+ assertNil(unsubErr, "unsubscribe decode error")
1002
+ local unsubResponse = router:dispatch(unsubDecoded)
1003
+
1004
+ assertNotNil(unsubResponse, "unsubscribe response")
1005
+ assertEqual(unsubResponse.type, "unsubscribeResult")
1006
+ assertEqual(#activeSubscriptions, 1)
1007
+
1008
+ -- Verify remaining subscription is logPush (not stateChange)
1009
+ local found = false
1010
+ for _, sub in activeSubscriptions do
1011
+ if sub == "logPush" then
1012
+ found = true
1013
+ end
1014
+ assertTrue(sub ~= "stateChange", "stateChange should be removed")
1015
+ end
1016
+ assertTrue(found, "logPush should still be subscribed")
1017
+ end,
1018
+ })
1019
+
1020
+ return tests