agent-tower 0.7.4 → 0.7.5-beta.5

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 (365) hide show
  1. package/dist/app.d.ts.map +1 -1
  2. package/dist/app.js +6 -1
  3. package/dist/app.js.map +1 -1
  4. package/dist/core/container.d.ts +2 -0
  5. package/dist/core/container.d.ts.map +1 -1
  6. package/dist/core/container.js +25 -0
  7. package/dist/core/container.js.map +1 -1
  8. package/dist/executors/__tests__/base.executor.test.js +19 -0
  9. package/dist/executors/__tests__/base.executor.test.js.map +1 -1
  10. package/dist/executors/__tests__/claude-code-mcp.test.d.ts +2 -0
  11. package/dist/executors/__tests__/claude-code-mcp.test.d.ts.map +1 -0
  12. package/dist/executors/__tests__/claude-code-mcp.test.js +211 -0
  13. package/dist/executors/__tests__/claude-code-mcp.test.js.map +1 -0
  14. package/dist/executors/__tests__/codex-mcp-windows.test.d.ts +2 -0
  15. package/dist/executors/__tests__/codex-mcp-windows.test.d.ts.map +1 -0
  16. package/dist/executors/__tests__/codex-mcp-windows.test.js +128 -0
  17. package/dist/executors/__tests__/codex-mcp-windows.test.js.map +1 -0
  18. package/dist/executors/__tests__/codex.executor.test.js +394 -1
  19. package/dist/executors/__tests__/codex.executor.test.js.map +1 -1
  20. package/dist/executors/base.executor.d.ts.map +1 -1
  21. package/dist/executors/base.executor.js +13 -0
  22. package/dist/executors/base.executor.js.map +1 -1
  23. package/dist/executors/claude-code.executor.d.ts +1 -0
  24. package/dist/executors/claude-code.executor.d.ts.map +1 -1
  25. package/dist/executors/claude-code.executor.js +52 -3
  26. package/dist/executors/claude-code.executor.js.map +1 -1
  27. package/dist/executors/codex.executor.d.ts +6 -6
  28. package/dist/executors/codex.executor.d.ts.map +1 -1
  29. package/dist/executors/codex.executor.js +118 -32
  30. package/dist/executors/codex.executor.js.map +1 -1
  31. package/dist/git/worktree.manager.d.ts.map +1 -1
  32. package/dist/git/worktree.manager.js +5 -2
  33. package/dist/git/worktree.manager.js.map +1 -1
  34. package/dist/mcp/http-client.d.ts +8 -1
  35. package/dist/mcp/http-client.d.ts.map +1 -1
  36. package/dist/mcp/http-client.js +6 -0
  37. package/dist/mcp/http-client.js.map +1 -1
  38. package/dist/mcp/tools/__tests__/workspace-services.test.js +34 -1
  39. package/dist/mcp/tools/__tests__/workspace-services.test.js.map +1 -1
  40. package/dist/mcp/tools/tasks.js +1 -1
  41. package/dist/mcp/tools/tasks.js.map +1 -1
  42. package/dist/mcp/tools/workspace-services.d.ts.map +1 -1
  43. package/dist/mcp/tools/workspace-services.js +39 -2
  44. package/dist/mcp/tools/workspace-services.js.map +1 -1
  45. package/dist/mcp/types.d.ts +20 -0
  46. package/dist/mcp/types.d.ts.map +1 -1
  47. package/dist/mcp/types.js +12 -0
  48. package/dist/mcp/types.js.map +1 -1
  49. package/dist/middleware/__tests__/preview-fallback.test.d.ts +2 -0
  50. package/dist/middleware/__tests__/preview-fallback.test.d.ts.map +1 -0
  51. package/dist/middleware/__tests__/preview-fallback.test.js +93 -0
  52. package/dist/middleware/__tests__/preview-fallback.test.js.map +1 -0
  53. package/dist/middleware/preview-fallback.d.ts +5 -0
  54. package/dist/middleware/preview-fallback.d.ts.map +1 -0
  55. package/dist/middleware/preview-fallback.js +91 -0
  56. package/dist/middleware/preview-fallback.js.map +1 -0
  57. package/dist/output/__tests__/claude-code-parser-continuation.test.d.ts +2 -0
  58. package/dist/output/__tests__/claude-code-parser-continuation.test.d.ts.map +1 -0
  59. package/dist/output/__tests__/claude-code-parser-continuation.test.js +89 -0
  60. package/dist/output/__tests__/claude-code-parser-continuation.test.js.map +1 -0
  61. package/dist/output/__tests__/claude-code-parser-lifecycle.test.js +4 -1
  62. package/dist/output/__tests__/claude-code-parser-lifecycle.test.js.map +1 -1
  63. package/dist/output/claude-code-parser.d.ts +36 -1
  64. package/dist/output/claude-code-parser.d.ts.map +1 -1
  65. package/dist/output/claude-code-parser.js +149 -18
  66. package/dist/output/claude-code-parser.js.map +1 -1
  67. package/dist/output/types.d.ts +2 -0
  68. package/dist/output/types.d.ts.map +1 -1
  69. package/dist/output/types.js.map +1 -1
  70. package/dist/prompts/workspace-background-service-policy.d.ts +6 -2
  71. package/dist/prompts/workspace-background-service-policy.d.ts.map +1 -1
  72. package/dist/prompts/workspace-background-service-policy.js +12 -3
  73. package/dist/prompts/workspace-background-service-policy.js.map +1 -1
  74. package/dist/prompts/workspace-background-service-policy.test.js +11 -0
  75. package/dist/prompts/workspace-background-service-policy.test.js.map +1 -1
  76. package/dist/routes/__tests__/previews.integration.test.js +117 -6
  77. package/dist/routes/__tests__/previews.integration.test.js.map +1 -1
  78. package/dist/routes/__tests__/previews.test.js +223 -194
  79. package/dist/routes/__tests__/previews.test.js.map +1 -1
  80. package/dist/routes/__tests__/task-handoff.test.js +25 -16
  81. package/dist/routes/__tests__/task-handoff.test.js.map +1 -1
  82. package/dist/routes/index.d.ts.map +1 -1
  83. package/dist/routes/index.js +3 -0
  84. package/dist/routes/index.js.map +1 -1
  85. package/dist/routes/previews.d.ts +11 -9
  86. package/dist/routes/previews.d.ts.map +1 -1
  87. package/dist/routes/previews.js +137 -516
  88. package/dist/routes/previews.js.map +1 -1
  89. package/dist/routes/session-wakeups.d.ts +7 -0
  90. package/dist/routes/session-wakeups.d.ts.map +1 -0
  91. package/dist/routes/session-wakeups.js +86 -0
  92. package/dist/routes/session-wakeups.js.map +1 -0
  93. package/dist/routes/tasks.d.ts.map +1 -1
  94. package/dist/routes/tasks.js +3 -1
  95. package/dist/routes/tasks.js.map +1 -1
  96. package/dist/runtime/__tests__/acp-process-manager.test.js +65 -0
  97. package/dist/runtime/__tests__/acp-process-manager.test.js.map +1 -1
  98. package/dist/runtime/__tests__/claude-cli-driver.test.js +96 -2
  99. package/dist/runtime/__tests__/claude-cli-driver.test.js.map +1 -1
  100. package/dist/runtime/__tests__/claude-run-lifecycle.test.d.ts +2 -0
  101. package/dist/runtime/__tests__/claude-run-lifecycle.test.d.ts.map +1 -0
  102. package/dist/runtime/__tests__/claude-run-lifecycle.test.js +88 -0
  103. package/dist/runtime/__tests__/claude-run-lifecycle.test.js.map +1 -0
  104. package/dist/runtime/__tests__/cli-driver-lifecycle.test.js +14 -7
  105. package/dist/runtime/__tests__/cli-driver-lifecycle.test.js.map +1 -1
  106. package/dist/runtime/acp/agents/pi-coding-agent.d.ts.map +1 -1
  107. package/dist/runtime/acp/agents/pi-coding-agent.js +3 -0
  108. package/dist/runtime/acp/agents/pi-coding-agent.js.map +1 -1
  109. package/dist/runtime/claude-run-lifecycle.d.ts +77 -0
  110. package/dist/runtime/claude-run-lifecycle.d.ts.map +1 -0
  111. package/dist/runtime/claude-run-lifecycle.js +147 -0
  112. package/dist/runtime/claude-run-lifecycle.js.map +1 -0
  113. package/dist/runtime/cli-driver.d.ts.map +1 -1
  114. package/dist/runtime/cli-driver.js +89 -3
  115. package/dist/runtime/cli-driver.js.map +1 -1
  116. package/dist/runtime/contracts.d.ts +6 -1
  117. package/dist/runtime/contracts.d.ts.map +1 -1
  118. package/dist/runtime/process-scope/__tests__/process-scope.test.d.ts +2 -0
  119. package/dist/runtime/process-scope/__tests__/process-scope.test.d.ts.map +1 -0
  120. package/dist/runtime/process-scope/__tests__/process-scope.test.js +156 -0
  121. package/dist/runtime/process-scope/__tests__/process-scope.test.js.map +1 -0
  122. package/dist/runtime/process-scope/process-scope.d.ts +46 -0
  123. package/dist/runtime/process-scope/process-scope.d.ts.map +1 -0
  124. package/dist/runtime/process-scope/process-scope.js +68 -0
  125. package/dist/runtime/process-scope/process-scope.js.map +1 -0
  126. package/dist/runtime/process-scope/scope-helper.d.ts +28 -0
  127. package/dist/runtime/process-scope/scope-helper.d.ts.map +1 -0
  128. package/dist/runtime/process-scope/scope-helper.js +78 -0
  129. package/dist/runtime/process-scope/scope-helper.js.map +1 -0
  130. package/dist/runtime/runtime-coordinator.d.ts.map +1 -1
  131. package/dist/runtime/runtime-coordinator.js +6 -0
  132. package/dist/runtime/runtime-coordinator.js.map +1 -1
  133. package/dist/services/__tests__/preview-runtime-manager.test.js +13 -112
  134. package/dist/services/__tests__/preview-runtime-manager.test.js.map +1 -1
  135. package/dist/services/__tests__/preview.service.test.js +13 -14
  136. package/dist/services/__tests__/preview.service.test.js.map +1 -1
  137. package/dist/services/__tests__/session-manager.lifecycle.test.js +147 -1
  138. package/dist/services/__tests__/session-manager.lifecycle.test.js.map +1 -1
  139. package/dist/services/__tests__/session-wakeup.service.test.d.ts +2 -0
  140. package/dist/services/__tests__/session-wakeup.service.test.d.ts.map +1 -0
  141. package/dist/services/__tests__/session-wakeup.service.test.js +173 -0
  142. package/dist/services/__tests__/session-wakeup.service.test.js.map +1 -0
  143. package/dist/services/__tests__/terminal-manager.test.js +129 -51
  144. package/dist/services/__tests__/terminal-manager.test.js.map +1 -1
  145. package/dist/services/__tests__/workspace.service.test.js +31 -0
  146. package/dist/services/__tests__/workspace.service.test.js.map +1 -1
  147. package/dist/services/message-delivery.service.d.ts +3 -2
  148. package/dist/services/message-delivery.service.d.ts.map +1 -1
  149. package/dist/services/message-delivery.service.js +11 -7
  150. package/dist/services/message-delivery.service.js.map +1 -1
  151. package/dist/services/preview-bridge.d.ts +50 -0
  152. package/dist/services/preview-bridge.d.ts.map +1 -0
  153. package/dist/services/preview-bridge.js +537 -0
  154. package/dist/services/preview-bridge.js.map +1 -0
  155. package/dist/services/preview-cookies.d.ts +28 -0
  156. package/dist/services/preview-cookies.d.ts.map +1 -0
  157. package/dist/services/preview-cookies.js +133 -0
  158. package/dist/services/preview-cookies.js.map +1 -0
  159. package/dist/services/preview-proxy.d.ts +71 -0
  160. package/dist/services/preview-proxy.d.ts.map +1 -0
  161. package/dist/services/preview-proxy.js +462 -0
  162. package/dist/services/preview-proxy.js.map +1 -0
  163. package/dist/services/preview-runtime-manager.d.ts +11 -25
  164. package/dist/services/preview-runtime-manager.d.ts.map +1 -1
  165. package/dist/services/preview-runtime-manager.js +46 -363
  166. package/dist/services/preview-runtime-manager.js.map +1 -1
  167. package/dist/services/preview.service.d.ts.map +1 -1
  168. package/dist/services/preview.service.js +11 -9
  169. package/dist/services/preview.service.js.map +1 -1
  170. package/dist/services/project.service.d.ts +13 -13
  171. package/dist/services/session-manager.d.ts +2 -0
  172. package/dist/services/session-manager.d.ts.map +1 -1
  173. package/dist/services/session-manager.js +4 -2
  174. package/dist/services/session-manager.js.map +1 -1
  175. package/dist/services/session-wakeup.service.d.ts +105 -0
  176. package/dist/services/session-wakeup.service.d.ts.map +1 -0
  177. package/dist/services/session-wakeup.service.js +319 -0
  178. package/dist/services/session-wakeup.service.js.map +1 -0
  179. package/dist/services/task-handoff.service.d.ts +3 -2
  180. package/dist/services/task-handoff.service.d.ts.map +1 -1
  181. package/dist/services/task-handoff.service.js +7 -6
  182. package/dist/services/task-handoff.service.js.map +1 -1
  183. package/dist/services/team-room-delivery.d.ts +4 -4
  184. package/dist/services/terminal-manager.d.ts +16 -0
  185. package/dist/services/terminal-manager.d.ts.map +1 -1
  186. package/dist/services/terminal-manager.js +64 -7
  187. package/dist/services/terminal-manager.js.map +1 -1
  188. package/dist/services/workspace-background-service.service.d.ts +15 -1
  189. package/dist/services/workspace-background-service.service.d.ts.map +1 -1
  190. package/dist/services/workspace-background-service.service.js +41 -2
  191. package/dist/services/workspace-background-service.service.js.map +1 -1
  192. package/dist/services/workspace.service.d.ts.map +1 -1
  193. package/dist/services/workspace.service.js +2 -1
  194. package/dist/services/workspace.service.js.map +1 -1
  195. package/dist/utils/database-schema.d.ts.map +1 -1
  196. package/dist/utils/database-schema.js +9 -4
  197. package/dist/utils/database-schema.js.map +1 -1
  198. package/dist/utils/database-schema.test.js +21 -0
  199. package/dist/utils/database-schema.test.js.map +1 -1
  200. package/dist/utils/owned-child-process.d.ts +32 -3
  201. package/dist/utils/owned-child-process.d.ts.map +1 -1
  202. package/dist/utils/owned-child-process.js +138 -1
  203. package/dist/utils/owned-child-process.js.map +1 -1
  204. package/dist/web/assets/{AgentDemoPage-D9bIiALx.js → AgentDemoPage-D6clLNZx.js} +1 -1
  205. package/dist/web/assets/{AgentEnvironmentSettingsPage-BE0RC6fR.js → AgentEnvironmentSettingsPage-O1hlpsgp.js} +1 -1
  206. package/dist/web/assets/AttachmentPreview-hD3g_T_y.js +2 -0
  207. package/dist/web/assets/{BranchSelect-Kv3M1YhZ.js → BranchSelect-BkuXnEG2.js} +1 -1
  208. package/dist/web/assets/{BrandLogo-fR2lCwEo.js → BrandLogo-BSwQa2SF.js} +1 -1
  209. package/dist/web/assets/{ConversationPage-BZiMHI9T.js → ConversationPage-DvWjqFF2.js} +1 -1
  210. package/dist/web/assets/CreateTaskInput-Bric0GeW.js +1 -0
  211. package/dist/web/assets/{DemoPage-DwpThe16.js → DemoPage-Cwy3EmOm.js} +1 -1
  212. package/dist/web/assets/{DesignSystemPage-DH9_cygJ.js → DesignSystemPage-C1HrGwpV.js} +1 -1
  213. package/dist/web/assets/{ExecutionPermissionSelector-C-akTOVg.js → ExecutionPermissionSelector-BgrxbvBB.js} +1 -1
  214. package/dist/web/assets/{GeneralSettingsPage-v2w1eofz.js → GeneralSettingsPage-qdeAdBkW.js} +1 -1
  215. package/dist/web/assets/{LoadingPreviewPage-pgk3PWM9.js → LoadingPreviewPage-qeZ8nuiQ.js} +1 -1
  216. package/dist/web/assets/{McpSettingsPage-w1DOlY5V.js → McpSettingsPage-Bo-auo0X.js} +1 -1
  217. package/dist/web/assets/{MemberAvatar-CJtylxwu.js → MemberAvatar-DBab_9EO.js} +1 -1
  218. package/dist/web/assets/{MobileTaskDetail-D5Czlr2O.js → MobileTaskDetail-Dm64ie99.js} +2 -2
  219. package/dist/web/assets/{NotificationSettingsPage-CkLg4WvT.js → NotificationSettingsPage-BVJpo76k.js} +1 -1
  220. package/dist/web/assets/{ProfileSettingsPage-B3yzbY1V.js → ProfileSettingsPage-CbSRYGcp.js} +1 -1
  221. package/dist/web/assets/{ProjectKanbanPage-CuGSLvrU.js → ProjectKanbanPage-Cp3rdFik.js} +6 -6
  222. package/dist/web/assets/{ProjectSettingsPage-DoklOfna.js → ProjectSettingsPage-DLs5-Gk3.js} +1 -1
  223. package/dist/web/assets/{ProviderSettingsPage-Cm0hbX5n.js → ProviderSettingsPage-BnBcgAMQ.js} +1 -1
  224. package/dist/web/assets/{SettingsMasterDetail-CGCUalkW.js → SettingsMasterDetail-fu-_yejj.js} +1 -1
  225. package/dist/web/assets/{TaskDetail-BiZbuXcE.js → TaskDetail-C2_Fg59e.js} +1 -1
  226. package/dist/web/assets/TaskHandoffPanel-3Y0gcjyN.js +70 -0
  227. package/dist/web/assets/{TeamSettingsPage-CyppRTaY.js → TeamSettingsPage-CAjitaBe.js} +1 -1
  228. package/dist/web/assets/{TranslationSettingsPage-BoQXEZmn.js → TranslationSettingsPage-DKD6Uw2F.js} +1 -1
  229. package/dist/web/assets/{arc-5NPBSbiL.js → arc-BiuUFTzU.js} +1 -1
  230. package/dist/web/assets/{architectureDiagram-3BPJPVTR-CqPT-IsX.js → architectureDiagram-3BPJPVTR-Dcwk905A.js} +1 -1
  231. package/dist/web/assets/{at-sign-Cf39WHCg.js → at-sign-CZAKOH3i.js} +1 -1
  232. package/dist/web/assets/{blockDiagram-GPEHLZMM-BN-1z9KN.js → blockDiagram-GPEHLZMM-Cfc5JDN-.js} +1 -1
  233. package/dist/web/assets/{c4Diagram-AAUBKEIU-CkeLbmQp.js → c4Diagram-AAUBKEIU-B4v5PUdt.js} +1 -1
  234. package/dist/web/assets/channel-DThSYkmR.js +1 -0
  235. package/dist/web/assets/check-C3vuSPKz.js +1 -0
  236. package/dist/web/assets/{chevron-down-Ct7FZbKm.js → chevron-down-CtAk9uZw.js} +1 -1
  237. package/dist/web/assets/{chevron-up-ARFlXMyO.js → chevron-up-DAc3NX1J.js} +1 -1
  238. package/dist/web/assets/{chip-BV_1-tIb.js → chip-CDUNxQW2.js} +1 -1
  239. package/dist/web/assets/{chunk-2J33WTMH-CWR7tRuT.js → chunk-2J33WTMH-BYRdUeyt.js} +1 -1
  240. package/dist/web/assets/{chunk-4BX2VUAB-CAulp4D5.js → chunk-4BX2VUAB-3si_kPmV.js} +1 -1
  241. package/dist/web/assets/{chunk-55IACEB6-DqkKXsbD.js → chunk-55IACEB6-JiMm9u33.js} +1 -1
  242. package/dist/web/assets/{chunk-727SXJPM-B19m45Sq.js → chunk-727SXJPM-CMCFIUyF.js} +1 -1
  243. package/dist/web/assets/{chunk-AQP2D5EJ-CuODwkza.js → chunk-AQP2D5EJ-CzvnZjH5.js} +1 -1
  244. package/dist/web/assets/{chunk-FMBD7UC4-CbUAjtCT.js → chunk-FMBD7UC4-hsabZkPl.js} +1 -1
  245. package/dist/web/assets/{chunk-ND2GUHAM-C54VxArl.js → chunk-ND2GUHAM-D2o-Reeo.js} +1 -1
  246. package/dist/web/assets/{chunk-QZHKN3VN-D54Uw5fD.js → chunk-QZHKN3VN-ASJk-E7d.js} +1 -1
  247. package/dist/web/assets/classDiagram-4FO5ZUOK-CjJqgIpK.js +1 -0
  248. package/dist/web/assets/classDiagram-v2-Q7XG4LA2-CjJqgIpK.js +1 -0
  249. package/dist/web/assets/{code-block-OCS4YCEC-CtAySD1h.js → code-block-OCS4YCEC-5bkFBowa.js} +1 -1
  250. package/dist/web/assets/{confirm-dialog-CCjHVFTv.js → confirm-dialog-Bs80kXB9.js} +1 -1
  251. package/dist/web/assets/{content-DZozZbBD.js → content-DAccroCT.js} +1 -1
  252. package/dist/web/assets/{copy-C-jvx2et.js → copy-D1XK3OqK.js} +1 -1
  253. package/dist/web/assets/{cose-bilkent-S5V4N54A-BaB2EVcU.js → cose-bilkent-S5V4N54A-C52UKnOd.js} +1 -1
  254. package/dist/web/assets/{cssMode-wd7JR1S4.js → cssMode-BFq_c5xU.js} +1 -1
  255. package/dist/web/assets/{dagre-BM42HDAG-C2j1Y8pO.js → dagre-BM42HDAG-CeEute93.js} +1 -1
  256. package/dist/web/assets/{diagram-2AECGRRQ-CF-EvpV9.js → diagram-2AECGRRQ-CEcq4W4S.js} +1 -1
  257. package/dist/web/assets/{diagram-5GNKFQAL-rBNso835.js → diagram-5GNKFQAL-DqQe7Rr7.js} +1 -1
  258. package/dist/web/assets/{diagram-KO2AKTUF-6NW-oos1.js → diagram-KO2AKTUF-C1KVZphS.js} +1 -1
  259. package/dist/web/assets/{diagram-LMA3HP47-DTfRxRLT.js → diagram-LMA3HP47-D1BL7GQh.js} +1 -1
  260. package/dist/web/assets/{diagram-OG6HWLK6-CS4Ae-hD.js → diagram-OG6HWLK6-ngyXooqC.js} +1 -1
  261. package/dist/web/assets/{dialog-DV4wfpNU.js → dialog-XkZ8wMQa.js} +1 -1
  262. package/dist/web/assets/{erDiagram-TEJ5UH35-Dw9QQctN.js → erDiagram-TEJ5UH35-D1zIFVqE.js} +1 -1
  263. package/dist/web/assets/{file-Btui_I8Z.js → file-CXCll7Pm.js} +1 -1
  264. package/dist/web/assets/{flowDiagram-I6XJVG4X-BGZ9q86S.js → flowDiagram-I6XJVG4X-BZu49qcj.js} +1 -1
  265. package/dist/web/assets/{folder-picker-DiR-8Qdl.js → folder-picker-CVkaEJEL.js} +1 -1
  266. package/dist/web/assets/{freemarker2-yVWXzD3l.js → freemarker2-CmhadAeB.js} +1 -1
  267. package/dist/web/assets/{ganttDiagram-6RSMTGT7-CkGun0no.js → ganttDiagram-6RSMTGT7-eJ8yBxfS.js} +1 -1
  268. package/dist/web/assets/{gitGraphDiagram-PVQCEYII-Bz3oiYvi.js → gitGraphDiagram-PVQCEYII-DpeUUyH_.js} +1 -1
  269. package/dist/web/assets/{globe-DAFqpAcW.js → globe-WnxN1JzY.js} +1 -1
  270. package/dist/web/assets/{handlebars-BPf0z6eN.js → handlebars-DtjmH1qR.js} +1 -1
  271. package/dist/web/assets/{html-HCTCjfUg.js → html-DOYAlzlD.js} +1 -1
  272. package/dist/web/assets/{htmlMode-BDkbsknt.js → htmlMode-ORxd7KRN.js} +1 -1
  273. package/dist/web/assets/{index-BMcLxIvZ.js → index-6mINSZng.js} +1 -1
  274. package/dist/web/assets/{index-BPqjxXmH.js → index-BrjvxKaf.js} +1 -1
  275. package/dist/web/assets/{index-B8xoIIa6.js → index-CqIyOiVN.js} +4 -4
  276. package/dist/web/assets/{index-DgUtx9rV.js → index-D9w1zMaz.js} +1 -1
  277. package/dist/web/assets/{index-DkSPjZm4.js → index-DHDgbH3t.js} +1 -1
  278. package/dist/web/assets/{index-BszkzNS4.js → index-Dz9SKopM.js} +13 -13
  279. package/dist/web/assets/{index-GuczxPxb.js → index-eIXz5Hbk.js} +1 -1
  280. package/dist/web/assets/{index-DuM6iAxG.js → index-iOIxdF6J.js} +1 -1
  281. package/dist/web/assets/{index-lZLy5rkr.js → index-wbMiSmsY.js} +1 -1
  282. package/dist/web/assets/{infoDiagram-5YYISTIA-DYFufUYC.js → infoDiagram-5YYISTIA-BiVrC__7.js} +1 -1
  283. package/dist/web/assets/{ishikawaDiagram-YF4QCWOH-IOkrKRwu.js → ishikawaDiagram-YF4QCWOH-B1kPjO1J.js} +1 -1
  284. package/dist/web/assets/javascript-CHlWHrtz.js +1 -0
  285. package/dist/web/assets/{journeyDiagram-JHISSGLW-Btl3yxne.js → journeyDiagram-JHISSGLW-DoTAPPAQ.js} +1 -1
  286. package/dist/web/assets/{jsonMode-DJPdvFcw.js → jsonMode-BkeQ_C6g.js} +1 -1
  287. package/dist/web/assets/{kanban-definition-UN3LZRKU-CDryhPbA.js → kanban-definition-UN3LZRKU-CBRmLcce.js} +1 -1
  288. package/dist/web/assets/{kbd-8RRRm9jd.js → kbd-CTfS0G5-.js} +1 -1
  289. package/dist/web/assets/{key-round-wojrCrDP.js → key-round-B7gTfpDR.js} +1 -1
  290. package/dist/web/assets/{layers-BH_LL4b8.js → layers-DE0xXedq.js} +1 -1
  291. package/dist/web/assets/{linear-BLuwKHze.js → linear-VLiA8Vcw.js} +1 -1
  292. package/dist/web/assets/{link-jWQOSQOQ.js → link-BSE_nRDT.js} +1 -1
  293. package/dist/web/assets/{liquid-1y-xg637.js → liquid-BZeg6p1K.js} +1 -1
  294. package/dist/web/assets/{lspLanguageFeatures-cYkILdCn.js → lspLanguageFeatures-CuFQ2_f9.js} +1 -1
  295. package/dist/web/assets/{mdx-CRg4Q6aP.js → mdx-C7xLyFFX.js} +1 -1
  296. package/dist/web/assets/{menu-CMqbaDni.js → menu-Dp4RDxvP.js} +1 -1
  297. package/dist/web/assets/{mermaid-NOHMQCX5-CYeAhOl-.js → mermaid-NOHMQCX5-C2enCJxR.js} +62 -62
  298. package/dist/web/assets/{message-square-DykJ2lWP.js → message-square-4lyHjyHe.js} +1 -1
  299. package/dist/web/assets/{mindmap-definition-RKZ34NQL-B5wtw1Rv.js → mindmap-definition-RKZ34NQL-C1OOtqma.js} +1 -1
  300. package/dist/web/assets/{modal-BwOwTzij.js → modal-BGglpgrR.js} +1 -1
  301. package/dist/web/assets/{monaco-CcHqpOKe.js → monaco-B-6VmJO0.js} +3 -3
  302. package/dist/web/assets/{nav-row-BmtdNLxR.js → nav-row-DaR8yP7p.js} +1 -1
  303. package/dist/web/assets/{paperclip-C4t49vX2.js → paperclip-DORF2rEM.js} +1 -1
  304. package/dist/web/assets/{pencil-BQ5_raiB.js → pencil-BG033B74.js} +1 -1
  305. package/dist/web/assets/{people-Dr0v8HK0.js → people-1qyKeYq6.js} +1 -1
  306. package/dist/web/assets/{pieDiagram-4H26LBE5-BZ3VoaNI.js → pieDiagram-4H26LBE5-BYYFVqOS.js} +1 -1
  307. package/dist/web/assets/{popover-CTqvKqTR.js → popover-CvjMbMb4.js} +1 -1
  308. package/dist/web/assets/{python-Huq_acyd.js → python-TTfnYnjF.js} +1 -1
  309. package/dist/web/assets/{quadrantDiagram-W4KKPZXB-C6ArHmnG.js → quadrantDiagram-W4KKPZXB-DTllM2j9.js} +1 -1
  310. package/dist/web/assets/{razor-Clc87Ivb.js → razor-BFVXAHVd.js} +1 -1
  311. package/dist/web/assets/{requirementDiagram-4Y6WPE33-DiLzBRQP.js → requirementDiagram-4Y6WPE33-DeJDRYUP.js} +1 -1
  312. package/dist/web/assets/{sankeyDiagram-5OEKKPKP-QlYYd7IZ.js → sankeyDiagram-5OEKKPKP-DzTvEKv8.js} +1 -1
  313. package/dist/web/assets/{search-CMIAPUEt.js → search-DDRcBORc.js} +1 -1
  314. package/dist/web/assets/{select-DqB7YF38.js → select-CXC17bJx.js} +1 -1
  315. package/dist/web/assets/{select-Bg7NI8i0.js → select-CzXL3ZbG.js} +1 -1
  316. package/dist/web/assets/{sequenceDiagram-3UESZ5HK-COKEtqc0.js → sequenceDiagram-3UESZ5HK-CIYrA1ww.js} +1 -1
  317. package/dist/web/assets/{server-D7knl8H9.js → server-KqeWHfgr.js} +1 -1
  318. package/dist/web/assets/{stateDiagram-AJRCARHV-1RZZZdOe.js → stateDiagram-AJRCARHV-Dg_UXkEq.js} +1 -1
  319. package/dist/web/assets/stateDiagram-v2-BHNVJYJU-Lc4r0bC3.js +1 -0
  320. package/dist/web/assets/{textarea-BCY2J2ca.js → textarea-Cmbv5l35.js} +1 -1
  321. package/dist/web/assets/{timeline-definition-PNZ67QCA-IJl1LY6J.js → timeline-definition-PNZ67QCA-CfSPMqxF.js} +1 -1
  322. package/dist/web/assets/{toggles-C4LmZwyo.js → toggles-t5v4QKn6.js} +1 -1
  323. package/dist/web/assets/{tooltip-Cirpotu3.js → tooltip-Cp8tovqH.js} +1 -1
  324. package/dist/web/assets/{track-Cv7h6oaE.js → track-C1rUV49K.js} +1 -1
  325. package/dist/web/assets/{trash-2-BEOQ1ICJ.js → trash-2-Ca2ken6q.js} +1 -1
  326. package/dist/web/assets/{tsMode-CHIbCBQc.js → tsMode-DBbiXlyu.js} +1 -1
  327. package/dist/web/assets/{typescript-CScj0bbb.js → typescript-jv_3P9x_.js} +1 -1
  328. package/dist/web/assets/{upload-tLVD0xMT.js → upload-CgGjN1FH.js} +1 -1
  329. package/dist/web/assets/{use-profiles-TkoP4Yw9.js → use-profiles-BdL-U8GZ.js} +1 -1
  330. package/dist/web/assets/{use-providers-Bz6YNiYj.js → use-providers-B6Mj5qeG.js} +1 -1
  331. package/dist/web/assets/{use-translation-settings-CCpQNS30.js → use-translation-settings-FIP674t9.js} +1 -1
  332. package/dist/web/assets/{useNormalizedLogs-Bstb98cF.js → useNormalizedLogs-FpVMUHeq.js} +1 -1
  333. package/dist/web/assets/useTokenUsage-Ay3Yy0_V.js +1 -0
  334. package/dist/web/assets/{vennDiagram-CIIHVFJN-DzVayy4U.js → vennDiagram-CIIHVFJN-DKREAIRT.js} +1 -1
  335. package/dist/web/assets/{wardley-L42UT6IY-CULSKh55.js → wardley-L42UT6IY-BMpDotAz.js} +1 -1
  336. package/dist/web/assets/{wardleyDiagram-YWT4CUSO-C5_h3lAA.js → wardleyDiagram-YWT4CUSO-DAPccQsF.js} +1 -1
  337. package/dist/web/assets/{xml-XuycSwh6.js → xml-DnxIQwRS.js} +1 -1
  338. package/dist/web/assets/{xychartDiagram-2RQKCTM6-F65naXcR.js → xychartDiagram-2RQKCTM6-o06g8vo8.js} +1 -1
  339. package/dist/web/assets/{yaml-BWm159lw.js → yaml-BV5yQTRd.js} +1 -1
  340. package/dist/web/index.html +1 -1
  341. package/node_modules/@agent-tower/shared/dist/log-adapter.d.ts +4 -0
  342. package/node_modules/@agent-tower/shared/dist/log-adapter.d.ts.map +1 -1
  343. package/node_modules/@agent-tower/shared/dist/log-adapter.js +1 -0
  344. package/node_modules/@agent-tower/shared/dist/log-adapter.js.map +1 -1
  345. package/node_modules/@agent-tower/shared/dist/translation.d.ts +4 -1
  346. package/node_modules/@agent-tower/shared/dist/translation.d.ts.map +1 -1
  347. package/node_modules/@agent-tower/shared/dist/translation.js +4 -1
  348. package/node_modules/@agent-tower/shared/dist/translation.js.map +1 -1
  349. package/node_modules/@agent-tower/shared/dist/types.d.ts +38 -2
  350. package/node_modules/@agent-tower/shared/dist/types.d.ts.map +1 -1
  351. package/node_modules/@agent-tower/shared/dist/types.js.map +1 -1
  352. package/package.json +2 -1
  353. package/prisma/migrations/20261106000000_add_session_wakeups/migration.sql +28 -0
  354. package/prisma/schema.prisma +28 -0
  355. package/scripts/postinstall.js +23 -0
  356. package/dist/web/assets/AttachmentPreview-TPd4gdfb.js +0 -2
  357. package/dist/web/assets/CreateTaskInput-TcZpjBe-.js +0 -1
  358. package/dist/web/assets/TaskHandoffPanel-CJahUKNo.js +0 -70
  359. package/dist/web/assets/channel-CDkuQ_7m.js +0 -1
  360. package/dist/web/assets/check-yNWhPvMH.js +0 -1
  361. package/dist/web/assets/classDiagram-4FO5ZUOK-eHY73FGu.js +0 -1
  362. package/dist/web/assets/classDiagram-v2-Q7XG4LA2-eHY73FGu.js +0 -1
  363. package/dist/web/assets/javascript-DKmxrNeR.js +0 -1
  364. package/dist/web/assets/stateDiagram-v2-BHNVJYJU-CCLmVs34.js +0 -1
  365. package/dist/web/assets/useTokenUsage-D7SEwXb0.js +0 -1
@@ -1,31 +1,20 @@
1
1
  import { registerApplicationProcessCleanup } from '../runtime/application-process-cleanup.js';
2
2
  import { z } from 'zod';
3
- import http from 'node:http';
4
- import https from 'node:https';
5
3
  import { PreviewService } from '../services/preview.service.js';
6
4
  import { ServiceError } from '../errors.js';
7
5
  import { TunnelService } from '../services/tunnel.service.js';
8
- import { TUNNEL_SESSION_COOKIE_NAME, extractTunnelSessionTokenFromCookieHeader, } from '../utils/tunnel-cookie.js';
9
- import { AccessAuthService, isAccessAuthCookieName, } from '../services/access-auth.service.js';
6
+ import { extractTunnelSessionTokenFromCookieHeader } from '../utils/tunnel-cookie.js';
7
+ import { AccessAuthService } from '../services/access-auth.service.js';
10
8
  import { INTERNAL_API_TOKEN_HEADER, validateInternalApiToken, } from '../utils/internal-api-token.js';
11
- import { buildPreviewPathPrefix, parsePreviewPath, PREVIEW_PREFIX, } from '../utils/preview-path.js';
9
+ import { buildPreviewPathPrefix, parsePreviewPath } from '../utils/preview-path.js';
12
10
  import { addPreviewAccessToken, PreviewRuntimeManager, } from '../services/preview-runtime-manager.js';
11
+ import { classifyPreviewRequest, previewServiceWorkerSegment, proxyPreviewHttpRequest, proxyPreviewWebSocket, shouldServeBootstrap, writeBootstrapPage, writeServiceWorkerScript, writeUpgradeError, } from '../services/preview-proxy.js';
13
12
  import { isTunnelRequest } from '../middleware/tunnel-auth.js';
14
- export const PREVIEW_SANDBOX_CSP = [
15
- 'sandbox',
16
- 'allow-scripts',
17
- 'allow-same-origin',
18
- 'allow-forms',
19
- 'allow-popups',
20
- 'allow-popups-to-escape-sandbox',
21
- 'allow-modals',
22
- 'allow-downloads',
23
- 'allow-pointer-lock',
24
- 'allow-presentation',
25
- 'allow-top-navigation-by-user-activation',
26
- ].join(' ');
27
- const PREVIEW_CORS_ALLOW_METHODS = 'GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS';
28
- const PREVIEW_CORS_DEFAULT_ALLOW_HEADERS = 'Content-Type, Accept, Authorization, X-Requested-With';
13
+ export { PREVIEW_SANDBOX_CSP } from '../services/preview-proxy.js';
14
+ /** Session id returned for the same-origin proxy; it needs no lease or heartbeat. */
15
+ export const SAME_ORIGIN_PREVIEW_SESSION_ID = 'same-origin';
16
+ const SAME_ORIGIN_SESSION_TTL_MS = 24 * 60 * 60 * 1000;
17
+ const PROXY_BODY_LIMIT_BYTES = 256 * 1024 * 1024;
29
18
  const configSchema = z.object({
30
19
  target: z.string().nullable(),
31
20
  });
@@ -47,305 +36,25 @@ function errorResponse(error, reply) {
47
36
  reply.log.error(error);
48
37
  return reply.code(500).send({ error: 'Internal server error', code: 'INTERNAL_ERROR' });
49
38
  }
50
- function joinTargetPath(target, suffix, search) {
51
- const normalizedSuffix = suffix.startsWith('/') ? suffix : `/${suffix}`;
52
- const base = target.basePath || '';
53
- const path = `${base}${normalizedSuffix}`.replace(/\/{2,}/g, '/');
54
- return `${path || '/'}${search}`;
39
+ /**
40
+ * Docker and other deployments whose dynamic gateway port is not reachable by
41
+ * browsers force the same-origin proxy. `AGENT_TOWER_PREVIEW_FORCE_TUNNEL` is
42
+ * the previous name of the same switch and is still honoured.
43
+ */
44
+ export function forceSameOriginPreview(env = process.env) {
45
+ return env.AGENT_TOWER_PREVIEW_FORCE_SAME_ORIGIN === 'true'
46
+ || env.AGENT_TOWER_PREVIEW_FORCE_TUNNEL === 'true';
55
47
  }
56
- function filterCookieHeader(cookieHeader) {
57
- if (!cookieHeader)
58
- return undefined;
59
- const cookies = cookieHeader
60
- .split(';')
61
- .map((part) => part.trim())
62
- .filter(Boolean)
63
- .filter((part) => {
64
- const [name] = part.split('=');
65
- return name
66
- && name !== TUNNEL_SESSION_COOKIE_NAME
67
- && !isAccessAuthCookieName(name);
68
- });
69
- return cookies.length > 0 ? cookies.join('; ') : undefined;
70
- }
71
- export function proxyRequestHeaders(headers, targetUrl, targetPath = '/') {
72
- const next = { ...headers };
73
- delete next.host;
74
- delete next.connection;
75
- delete next['content-length'];
76
- delete next['accept-encoding'];
77
- const cookie = filterCookieHeader(headers.cookie);
78
- if (cookie)
79
- next.cookie = cookie;
80
- else
81
- delete next.cookie;
82
- next.host = targetUrl.host;
83
- next['accept-encoding'] = 'identity';
84
- next['x-forwarded-host'] = targetUrl.host;
85
- next['x-forwarded-proto'] = targetUrl.protocol.slice(0, -1);
86
- if (headers.origin) {
87
- next.origin = targetUrl.origin;
88
- }
89
- if (headers.referer) {
90
- next.referer = new URL(targetPath, targetUrl).toString();
91
- }
92
- else {
93
- delete next.referer;
94
- }
95
- return next;
96
- }
97
- function firstHeaderValue(value) {
98
- return Array.isArray(value) ? value[0] : value;
99
- }
100
- function normalizeRequestedHeaders(value) {
101
- if (!value)
102
- return PREVIEW_CORS_DEFAULT_ALLOW_HEADERS;
103
- const headers = value
104
- .split(',')
105
- .map((item) => item.trim())
106
- .filter(Boolean);
107
- return headers.length > 0 ? headers.join(', ') : PREVIEW_CORS_DEFAULT_ALLOW_HEADERS;
108
- }
109
- export function previewCorsHeaders(requestHeaders) {
48
+ export function sameOriginPreviewSession(workspaceId, target, now = Date.now()) {
110
49
  return {
111
- 'access-control-allow-origin': '*',
112
- 'access-control-allow-methods': PREVIEW_CORS_ALLOW_METHODS,
113
- 'access-control-allow-headers': normalizeRequestedHeaders(firstHeaderValue(requestHeaders?.['access-control-request-headers'])),
114
- 'access-control-max-age': '600',
115
- 'vary': 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers',
50
+ id: SAME_ORIGIN_PREVIEW_SESSION_ID,
51
+ target: target.target,
52
+ mode: 'remote',
53
+ kind: 'same-origin',
54
+ viewUrl: `${buildPreviewPathPrefix(workspaceId)}/`,
55
+ expiresAt: new Date(now + SAME_ORIGIN_SESSION_TTL_MS).toISOString(),
116
56
  };
117
57
  }
118
- export function rewriteLocationHeader(value, workspaceId, target, previewToken) {
119
- const prefix = buildPreviewPathPrefix(workspaceId, previewToken);
120
- try {
121
- const location = new URL(value, target.origin);
122
- if (location.origin !== target.origin)
123
- return value;
124
- if (isSameOrChildPath(location.pathname, prefix)) {
125
- return `${location.pathname}${location.search}${location.hash}`;
126
- }
127
- const basePath = target.basePath;
128
- const isUnderBasePath = basePath
129
- ? location.pathname === basePath || location.pathname.startsWith(`${basePath}/`)
130
- : true;
131
- const path = isUnderBasePath
132
- ? location.pathname.slice(target.basePath.length || 0) || '/'
133
- : location.pathname;
134
- return `${prefix}${path}${location.search}${location.hash}`;
135
- }
136
- catch {
137
- if (isSameOrChildPath(getPathname(value), prefix))
138
- return value;
139
- if (value.startsWith('/'))
140
- return `${prefix}${value}`;
141
- return value;
142
- }
143
- }
144
- export function rewriteSetCookieHeader(value, workspaceId, previewToken) {
145
- const prefix = `${buildPreviewPathPrefix(workspaceId, previewToken)}/`;
146
- const withoutDomain = value.replace(/;\s*domain=[^;]*/gi, '');
147
- if (/;\s*path=/i.test(withoutDomain)) {
148
- return withoutDomain.replace(/;\s*path=([^;]*)/i, `; Path=${prefix}`);
149
- }
150
- return `${withoutDomain}; Path=${prefix}`;
151
- }
152
- export function proxyResponseHeaders(headers, workspaceId, target, requestHeaders, previewToken) {
153
- const next = {};
154
- for (const [key, value] of Object.entries(headers)) {
155
- const lower = key.toLowerCase();
156
- if (lower === 'connection'
157
- || lower === 'content-length'
158
- || lower === 'content-encoding'
159
- || lower === 'transfer-encoding'
160
- || lower === 'x-frame-options') {
161
- continue;
162
- }
163
- if (lower === 'content-security-policy') {
164
- continue;
165
- }
166
- if (lower.startsWith('access-control-')) {
167
- continue;
168
- }
169
- if (lower === 'location' && typeof value === 'string') {
170
- next[key] = rewriteLocationHeader(value, workspaceId, target, previewToken);
171
- continue;
172
- }
173
- if (lower === 'set-cookie') {
174
- const cookies = Array.isArray(value) ? value : typeof value === 'string' ? [value] : [];
175
- next[key] = cookies.map((cookie) => rewriteSetCookieHeader(cookie, workspaceId, previewToken));
176
- continue;
177
- }
178
- if (value !== undefined)
179
- next[key] = value;
180
- }
181
- next['content-security-policy'] = PREVIEW_SANDBOX_CSP;
182
- Object.assign(next, previewCorsHeaders(requestHeaders));
183
- next['cross-origin-resource-policy'] = 'cross-origin';
184
- return next;
185
- }
186
- function isRewritableContent(contentType) {
187
- const value = Array.isArray(contentType) ? contentType.join(';') : contentType ?? '';
188
- const lower = value.toLowerCase();
189
- return lower.includes('text/html')
190
- || lower.includes('text/css')
191
- || lower.includes('javascript')
192
- || lower.includes('application/ecmascript');
193
- }
194
- function isSameOrChildPath(pathname, basePath) {
195
- return pathname === basePath || pathname.startsWith(`${basePath}/`);
196
- }
197
- function getPathname(value) {
198
- const end = value.search(/[?#]/);
199
- return end === -1 ? value : value.slice(0, end);
200
- }
201
- function hasStaticFileExtension(pathname) {
202
- const segment = pathname.split('/').pop() ?? '';
203
- return /\.(?:avif|bmp|css|eot|gif|html?|ico|jpe?g|js|json|map|mjs|png|svg|ttf|txt|wasm|webp|woff2?)$/i.test(segment);
204
- }
205
- function shouldRewriteJavaScriptPath(value, prefix) {
206
- if (!value.startsWith('/') || value.startsWith('//') || value === '/')
207
- return false;
208
- const pathname = getPathname(value);
209
- if (isSameOrChildPath(pathname, prefix) || pathname.startsWith(`${PREVIEW_PREFIX}/`))
210
- return false;
211
- if (isSameOrChildPath(pathname, '/api')
212
- || isSameOrChildPath(pathname, '/socket.io')
213
- || isSameOrChildPath(pathname, '/ws')) {
214
- return true;
215
- }
216
- if (isSameOrChildPath(pathname, '/assets'))
217
- return true;
218
- return hasStaticFileExtension(pathname);
219
- }
220
- function rewriteJavaScriptPathLiterals(body, prefix) {
221
- return body.replace(/(["'`])\/(?!\/)([^"'`\r\n]*)\1/g, (match, quote, rest) => {
222
- const value = `/${rest}`;
223
- if (!shouldRewriteJavaScriptPath(value, prefix))
224
- return match;
225
- return `${quote}${prefix}${value}${quote}`;
226
- });
227
- }
228
- function rewriteJavaScriptRouterBasenameDefaults(body, prefix) {
229
- return body
230
- .replace(/(\bbasename\s*:\s*[A-Za-z_$][\w$]*\s*=\s*)(["'`])\/\2/g, (_match, before, quote) => `${before}${quote}${prefix}${quote}`)
231
- .replace(/(\bbasename\s*=\s*)(["'`])\/\2/g, (_match, before, quote) => `${before}${quote}${prefix}${quote}`)
232
- .replace(/(\bbasename\s*:\s*)(["'`])\/\2/g, (_match, before, quote) => `${before}${quote}${prefix}${quote}`)
233
- .replace(/(\b[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)?\.basename\s*\|\|\s*)(["'`])\/\2/g, (_match, before, quote) => `${before}${quote}${prefix}${quote}`)
234
- .replace(/(\b[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)?\.basename\s*\?\?\s*)(["'`])\/\2/g, (_match, before, quote) => `${before}${quote}${prefix}${quote}`);
235
- }
236
- function injectPreviewRuntimeBridge(body, prefix, target) {
237
- const script = `<script data-agent-tower-preview-bridge>(() => {
238
- const prefix = ${JSON.stringify(prefix)};
239
- const targetOrigin = ${JSON.stringify(target.origin)};
240
- const targetBasePath = ${JSON.stringify(target.basePath)};
241
- const loopbackHosts = new Set(['localhost', '127.0.0.1', '::1', '[::1]', '0.0.0.0']);
242
- const normalizeProtocol = (protocol) => protocol === 'ws:' ? 'http:' : protocol === 'wss:' ? 'https:' : protocol;
243
- const normalizeHost = (hostname) => loopbackHosts.has(hostname.toLowerCase()) ? 'loopback' : hostname.toLowerCase();
244
- const effectivePort = (url) => url.port || (normalizeProtocol(url.protocol) === 'https:' ? '443' : '80');
245
- const sameEndpoint = (left, right) => normalizeProtocol(left.protocol) === normalizeProtocol(right.protocol)
246
- && normalizeHost(left.hostname) === normalizeHost(right.hostname)
247
- && effectivePort(left) === effectivePort(right);
248
- const isPrefixed = (pathname) => pathname === prefix || pathname.startsWith(prefix + '/');
249
- const rewrite = (value) => {
250
- if (value === undefined || value === null) return value;
251
- const raw = value instanceof URL ? value.toString() : String(value);
252
- let url;
253
- try {
254
- url = new URL(raw, window.location.href);
255
- } catch {
256
- return value;
257
- }
258
- if (isPrefixed(url.pathname)) return raw;
259
-
260
- const browserUrl = new URL(window.location.href);
261
- const localTarget = new URL(targetOrigin);
262
- const isRootRelative = raw.startsWith('/') && !raw.startsWith('//');
263
- const isBrowserEndpoint = sameEndpoint(url, browserUrl);
264
- const isTargetEndpoint = sameEndpoint(url, localTarget);
265
- if (!isRootRelative && !isTargetEndpoint) return value;
266
- if (isBrowserEndpoint && !isRootRelative) return value;
267
-
268
- let pathname = url.pathname;
269
- if (isTargetEndpoint && targetBasePath) {
270
- const underBasePath = pathname === targetBasePath || pathname.startsWith(targetBasePath + '/');
271
- if (underBasePath) pathname = pathname.slice(targetBasePath.length) || '/';
272
- }
273
- const protocol = url.protocol === 'ws:' || url.protocol === 'wss:'
274
- ? (window.location.protocol === 'https:' ? 'wss:' : 'ws:')
275
- : window.location.protocol;
276
- return protocol + '//' + window.location.host + prefix + pathname + url.search + url.hash;
277
- };
278
-
279
- const nativePushState = History.prototype.pushState;
280
- const nativeReplaceState = History.prototype.replaceState;
281
- History.prototype.pushState = function(state, unused, url) {
282
- return nativePushState.call(this, state, unused, url == null ? url : rewrite(url));
283
- };
284
- History.prototype.replaceState = function(state, unused, url) {
285
- return nativeReplaceState.call(this, state, unused, url == null ? url : rewrite(url));
286
- };
287
-
288
- const nativeFetch = window.fetch.bind(window);
289
- window.fetch = (input, init) => {
290
- if (typeof input === 'string' || input instanceof URL) return nativeFetch(rewrite(input), init);
291
- if (input instanceof Request) return nativeFetch(new Request(rewrite(input.url), input), init);
292
- return nativeFetch(input, init);
293
- };
294
-
295
- const nativeXhrOpen = XMLHttpRequest.prototype.open;
296
- XMLHttpRequest.prototype.open = function(method, url, ...rest) {
297
- return nativeXhrOpen.call(this, method, rewrite(url), ...rest);
298
- };
299
-
300
- const NativeWebSocket = window.WebSocket;
301
- function PreviewWebSocket(url, protocols) {
302
- const nextUrl = rewrite(url);
303
- return protocols === undefined ? new NativeWebSocket(nextUrl) : new NativeWebSocket(nextUrl, protocols);
304
- }
305
- PreviewWebSocket.prototype = NativeWebSocket.prototype;
306
- Object.setPrototypeOf(PreviewWebSocket, NativeWebSocket);
307
- window.WebSocket = PreviewWebSocket;
308
-
309
- const NativeEventSource = window.EventSource;
310
- if (NativeEventSource) {
311
- function PreviewEventSource(url, options) {
312
- return new NativeEventSource(rewrite(url), options);
313
- }
314
- PreviewEventSource.prototype = NativeEventSource.prototype;
315
- Object.setPrototypeOf(PreviewEventSource, NativeEventSource);
316
- window.EventSource = PreviewEventSource;
317
- }
318
- })();</script>`;
319
- const head = /<head(?:\s[^>]*)?>/i;
320
- if (head.test(body))
321
- return body.replace(head, (match) => `${match}${script}`);
322
- return `${script}${body}`;
323
- }
324
- export function rewritePreviewBody(body, workspaceId, contentType, previewToken, target) {
325
- const prefix = buildPreviewPathPrefix(workspaceId, previewToken);
326
- const value = Array.isArray(contentType) ? contentType.join(';') : contentType ?? '';
327
- const lower = value.toLowerCase();
328
- let next = body;
329
- if (lower.includes('text/html')) {
330
- next = next
331
- .replace(/(\s(?:src|href|action|poster|data|content)=["'])\/(?!\/|view\/)([^"']*)/gi, `$1${prefix}/$2`)
332
- .replace(/(\s(?:srcset)=["'])([^"']*)(["'])/gi, (_match, before, srcset, after) => {
333
- const rewritten = srcset.replace(/(^|,\s*)\/(?!\/|view\/)([^\s,]+)/g, `$1${prefix}/$2`);
334
- return `${before}${rewritten}${after}`;
335
- });
336
- }
337
- if (lower.includes('text/css') || lower.includes('text/html')) {
338
- next = next.replace(/url\((['"]?)\/(?!\/|view\/)([^)'"]+)\1\)/g, `url($1${prefix}/$2$1)`);
339
- }
340
- if (lower.includes('javascript') || lower.includes('ecmascript') || lower.includes('text/html')) {
341
- next = rewriteJavaScriptRouterBasenameDefaults(next, prefix);
342
- next = rewriteJavaScriptPathLiterals(next, prefix);
343
- }
344
- if (lower.includes('text/html') && target) {
345
- next = injectPreviewRuntimeBridge(next, prefix, target);
346
- }
347
- return next;
348
- }
349
58
  function requestBodyBuffer(request) {
350
59
  const method = request.method.toUpperCase();
351
60
  if (method === 'GET' || method === 'HEAD')
@@ -359,180 +68,49 @@ function requestBodyBuffer(request) {
359
68
  return Buffer.from(body);
360
69
  return Buffer.from(JSON.stringify(body));
361
70
  }
362
- async function proxyHttpRequest(request, response, workspaceId, target, previewToken) {
363
- const parsed = parsePreviewPath(request.raw.url ?? '');
364
- if (!parsed) {
365
- response.writeHead(404);
366
- response.end('Preview route not found');
367
- return;
71
+ async function authorizeWebSocketUpgrade(req, socket, workspaceId, previewToken) {
72
+ const isTunnel = Boolean(req.headers['cf-connecting-ip'] || req.headers['cf-ray']);
73
+ if (isTunnel && TunnelService.isRunning()) {
74
+ const token = extractTunnelSessionTokenFromCookieHeader(req.headers.cookie);
75
+ if (!token || !TunnelService.validateToken(token)) {
76
+ writeUpgradeError(socket, 401, 'Unauthorized');
77
+ return false;
78
+ }
368
79
  }
369
- const targetUrl = new URL(target.origin);
370
- const targetPath = joinTargetPath(target, parsed.suffix, parsed.search);
371
- const body = requestBodyBuffer(request);
372
- const headers = proxyRequestHeaders(request.headers, targetUrl, targetPath);
373
- if (body)
374
- headers['content-length'] = Buffer.byteLength(body);
375
- const options = {
376
- protocol: targetUrl.protocol,
377
- hostname: targetUrl.hostname,
378
- port: targetUrl.port,
379
- method: request.method,
380
- path: targetPath,
381
- headers,
382
- rejectUnauthorized: false,
383
- };
384
- const transport = targetUrl.protocol === 'https:' ? https : http;
385
- await new Promise((resolve) => {
386
- const proxyReq = transport.request(options, (proxyRes) => {
387
- const headers = proxyResponseHeaders(proxyRes.headers, workspaceId, target, request.headers, previewToken);
388
- response.statusCode = proxyRes.statusCode ?? 502;
389
- for (const [key, value] of Object.entries(headers)) {
390
- if (value !== undefined)
391
- response.setHeader(key, value);
392
- }
393
- if (!isRewritableContent(proxyRes.headers['content-type'])) {
394
- proxyRes.pipe(response);
395
- proxyRes.on('end', resolve);
396
- proxyRes.on('error', () => {
397
- if (!response.headersSent)
398
- response.writeHead(502);
399
- response.end('Preview proxy response failed');
400
- resolve();
401
- });
402
- return;
403
- }
404
- const chunks = [];
405
- proxyRes.on('data', (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
406
- proxyRes.on('end', () => {
407
- const text = Buffer.concat(chunks).toString('utf8');
408
- response.end(rewritePreviewBody(text, workspaceId, proxyRes.headers['content-type'], previewToken, target));
409
- resolve();
410
- });
411
- proxyRes.on('error', () => {
412
- if (!response.headersSent)
413
- response.writeHead(502);
414
- response.end('Preview proxy response failed');
415
- resolve();
416
- });
417
- });
418
- proxyReq.on('error', (err) => {
419
- if (!response.headersSent) {
420
- response.writeHead(502, { 'content-type': 'application/json' });
421
- }
422
- response.end(JSON.stringify({ error: err.message, code: 'PREVIEW_PROXY_ERROR' }));
423
- resolve();
424
- });
425
- proxyReq.end(body ?? undefined);
426
- });
427
- }
428
- function writeUpgradeError(socket, statusCode, message) {
429
- if (socket.destroyed)
430
- return;
431
- socket.write(`HTTP/1.1 ${statusCode} ${message}\r\nConnection: close\r\n\r\n`);
432
- socket.destroy();
433
- }
434
- function proxyWebSocketRequest(req, socket, head, workspaceId, target) {
435
- const parsed = parsePreviewPath(req.url ?? '');
436
- if (!parsed) {
437
- writeUpgradeError(socket, 404, 'Not Found');
438
- return;
80
+ const internalToken = req.headers[INTERNAL_API_TOKEN_HEADER];
81
+ const normalizedInternalToken = Array.isArray(internalToken) ? internalToken[0] : internalToken;
82
+ if (internalToken !== undefined) {
83
+ if (!validateInternalApiToken(normalizedInternalToken)) {
84
+ writeUpgradeError(socket, 401, 'Invalid Internal Token');
85
+ return false;
86
+ }
87
+ return true;
439
88
  }
440
- socket.on('error', () => {
441
- if (!socket.destroyed)
442
- socket.destroy();
443
- });
444
- const targetUrl = new URL(target.origin);
445
- const targetPath = joinTargetPath(target, parsed.suffix, parsed.search);
446
- const headers = proxyRequestHeaders(req.headers, targetUrl, targetPath);
447
- headers.connection = 'Upgrade';
448
- headers.upgrade = 'websocket';
449
- const options = {
450
- protocol: targetUrl.protocol,
451
- hostname: targetUrl.hostname,
452
- port: targetUrl.port,
453
- method: 'GET',
454
- path: targetPath,
455
- headers,
456
- rejectUnauthorized: false,
457
- };
458
- const transport = targetUrl.protocol === 'https:' ? https : http;
459
- const proxyReq = transport.request(options);
460
- proxyReq.on('upgrade', (proxyRes, proxySocket, proxyHead) => {
461
- const closeClient = () => {
462
- if (!socket.destroyed)
463
- socket.destroy();
464
- };
465
- const closeTarget = () => {
466
- if (!proxySocket.destroyed)
467
- proxySocket.destroy();
468
- };
469
- socket.once('close', closeTarget);
470
- socket.once('error', closeTarget);
471
- proxySocket.once('close', closeClient);
472
- proxySocket.once('error', closeClient);
473
- const headerLines = [
474
- `HTTP/1.1 ${proxyRes.statusCode} ${proxyRes.statusMessage}`,
475
- ...Object.entries(proxyRes.headers).flatMap(([key, value]) => {
476
- if (Array.isArray(value))
477
- return value.map((item) => `${key}: ${item}`);
478
- return value === undefined ? [] : [`${key}: ${value}`];
479
- }),
480
- '',
481
- '',
482
- ];
483
- socket.write(headerLines.join('\r\n'));
484
- if (proxyHead.length > 0)
485
- socket.write(proxyHead);
486
- if (head.length > 0)
487
- proxySocket.write(head);
488
- proxySocket.pipe(socket);
489
- socket.pipe(proxySocket);
490
- });
491
- proxyReq.on('response', (res) => {
492
- writeUpgradeError(socket, res.statusCode ?? 502, res.statusMessage ?? 'Bad Gateway');
493
- });
494
- proxyReq.on('error', () => {
495
- writeUpgradeError(socket, 502, 'Bad Gateway');
496
- });
497
- proxyReq.end();
89
+ if (previewToken && await AccessAuthService.validatePreviewAccessToken(previewToken, workspaceId)) {
90
+ return true;
91
+ }
92
+ const accessToken = AccessAuthService.extractCookieFromHeader(req.headers.cookie);
93
+ if (!await AccessAuthService.validateSessionToken(accessToken)) {
94
+ writeUpgradeError(socket, 401, 'Unauthorized');
95
+ return false;
96
+ }
97
+ return true;
498
98
  }
499
99
  function registerPreviewWebSocketProxy(app, previewService) {
500
- app.server.on('upgrade', async (req, socket, head) => {
100
+ app.server.on('upgrade', (req, socket, head) => {
501
101
  const parsed = parsePreviewPath(req.url ?? '');
502
102
  if (!parsed)
503
103
  return;
504
- const isTunnel = Boolean(req.headers['cf-connecting-ip'] || req.headers['cf-ray']);
505
- if (isTunnel && TunnelService.isRunning()) {
506
- const token = extractTunnelSessionTokenFromCookieHeader(req.headers.cookie);
507
- if (!token || !TunnelService.validateToken(token)) {
508
- writeUpgradeError(socket, 401, 'Unauthorized');
509
- return;
510
- }
511
- }
512
- const internalToken = req.headers[INTERNAL_API_TOKEN_HEADER];
513
- const normalizedInternalToken = Array.isArray(internalToken) ? internalToken[0] : internalToken;
514
- if (internalToken !== undefined) {
515
- if (!validateInternalApiToken(normalizedInternalToken)) {
516
- writeUpgradeError(socket, 401, 'Invalid Internal Token');
104
+ void (async () => {
105
+ if (!await authorizeWebSocketUpgrade(req, socket, parsed.workspaceId, parsed.previewToken))
517
106
  return;
518
- }
519
- }
520
- else if (!parsed.previewToken || !await AccessAuthService.validatePreviewAccessToken(parsed.previewToken, parsed.workspaceId)) {
521
- const accessToken = AccessAuthService.extractCookieFromHeader(req.headers.cookie);
522
- if (!await AccessAuthService.validateSessionToken(accessToken)) {
523
- writeUpgradeError(socket, 401, 'Unauthorized');
524
- return;
525
- }
526
- }
527
- previewService.getTarget(parsed.workspaceId)
528
- .then((target) => {
107
+ const target = await previewService.getTarget(parsed.workspaceId);
529
108
  if (!target) {
530
109
  writeUpgradeError(socket, 404, 'Not Found');
531
110
  return;
532
111
  }
533
- proxyWebSocketRequest(req, socket, head, parsed.workspaceId, target);
534
- })
535
- .catch(() => {
112
+ proxyPreviewWebSocket(req, socket, head, { workspaceId: parsed.workspaceId, target, previewToken: parsed.previewToken }, parsed.suffix, parsed.search);
113
+ })().catch(() => {
536
114
  writeUpgradeError(socket, 502, 'Bad Gateway');
537
115
  });
538
116
  });
@@ -546,12 +124,13 @@ export async function previewRoutes(app) {
546
124
  };
547
125
  const unregisterCleanup = registerApplicationProcessCleanup(cleanupPreview);
548
126
  registerPreviewWebSocketProxy(app, previewService);
549
- const sessionResponse = async (session) => {
127
+ const gatewaySessionResponse = async (session) => {
550
128
  const accessToken = await AccessAuthService.createPreviewAccessToken(session.workspaceId);
551
129
  return {
552
130
  id: session.id,
553
131
  target: session.target,
554
- mode: session.mode,
132
+ mode: 'local',
133
+ kind: 'gateway',
555
134
  viewUrl: addPreviewAccessToken(session.viewBaseUrl, accessToken),
556
135
  expiresAt: session.expiresAt,
557
136
  };
@@ -590,10 +169,15 @@ export async function previewRoutes(app) {
590
169
  code: 'PREVIEW_NOT_CONFIGURED',
591
170
  });
592
171
  }
593
- const forceRemote = process.env.AGENT_TOWER_PREVIEW_FORCE_TUNNEL === 'true';
594
- const mode = isTunnelRequest(request) || forceRemote ? 'remote' : body.mode;
595
- const session = await previewRuntimeManager.acquire(request.params.workspaceId, target, mode, body.localHostname);
596
- return sessionResponse(session);
172
+ // Browsers that can only reach Agent Tower itself (tunnel, HTTPS reverse
173
+ // proxy, Docker) use the same-origin proxy; everything else gets a
174
+ // dedicated gateway origin on the Agent Tower host.
175
+ const sameOrigin = body.mode === 'remote' || isTunnelRequest(request) || forceSameOriginPreview();
176
+ if (sameOrigin) {
177
+ return sameOriginPreviewSession(request.params.workspaceId, target);
178
+ }
179
+ const session = await previewRuntimeManager.acquire(request.params.workspaceId, target, body.localHostname);
180
+ return await gatewaySessionResponse(session);
597
181
  }
598
182
  catch (err) {
599
183
  return errorResponse(err, reply);
@@ -601,6 +185,16 @@ export async function previewRoutes(app) {
601
185
  });
602
186
  app.post('/api/previews/:workspaceId/sessions/:sessionId/heartbeat', async (request, reply) => {
603
187
  try {
188
+ if (request.params.sessionId === SAME_ORIGIN_PREVIEW_SESSION_ID) {
189
+ const target = await previewService.getTarget(request.params.workspaceId);
190
+ if (!target) {
191
+ return reply.code(404).send({
192
+ error: 'Preview target is not configured',
193
+ code: 'PREVIEW_NOT_CONFIGURED',
194
+ });
195
+ }
196
+ return sameOriginPreviewSession(request.params.workspaceId, target);
197
+ }
604
198
  const session = await previewRuntimeManager.heartbeat(request.params.workspaceId, request.params.sessionId);
605
199
  if (!session) {
606
200
  return reply.code(404).send({
@@ -608,49 +202,76 @@ export async function previewRoutes(app) {
608
202
  code: 'PREVIEW_SESSION_EXPIRED',
609
203
  });
610
204
  }
611
- return sessionResponse(session);
205
+ return await gatewaySessionResponse(session);
612
206
  }
613
207
  catch (err) {
614
208
  return errorResponse(err, reply);
615
209
  }
616
210
  });
617
211
  app.delete('/api/previews/:workspaceId/sessions/:sessionId', async (request, reply) => {
618
- previewRuntimeManager.release(request.params.workspaceId, request.params.sessionId);
212
+ if (request.params.sessionId !== SAME_ORIGIN_PREVIEW_SESSION_ID) {
213
+ previewRuntimeManager.release(request.params.workspaceId, request.params.sessionId);
214
+ }
619
215
  return reply.code(204).send();
620
216
  });
621
- const handler = async (request, reply) => {
622
- const parsed = parsePreviewPath(request.raw.url ?? '');
623
- if (!parsed)
624
- return reply.code(404).send({ error: 'Preview route not found', code: 'NOT_FOUND' });
625
- try {
626
- if (request.method.toUpperCase() === 'OPTIONS' && request.headers['access-control-request-method']) {
627
- return reply
628
- .code(204)
629
- .headers(previewCorsHeaders(request.headers))
630
- .send();
217
+ // The proxy must forward request bodies of any content type untouched.
218
+ await app.register(async (proxyApp) => {
219
+ proxyApp.removeAllContentTypeParsers();
220
+ proxyApp.addContentTypeParser('*', { parseAs: 'buffer', bodyLimit: PROXY_BODY_LIMIT_BYTES }, (_request, body, done) => {
221
+ done(null, body);
222
+ });
223
+ const handler = async (request, reply) => {
224
+ const parsed = parsePreviewPath(request.raw.url ?? '');
225
+ if (!parsed)
226
+ return reply.code(404).send({ error: 'Preview route not found', code: 'NOT_FOUND' });
227
+ try {
228
+ const target = await previewService.getTarget(parsed.workspaceId);
229
+ if (!target) {
230
+ return reply.code(404).send({ error: 'Preview target is not configured', code: 'PREVIEW_NOT_CONFIGURED' });
231
+ }
232
+ const scope = {
233
+ workspaceId: parsed.workspaceId,
234
+ target,
235
+ previewToken: parsed.previewToken,
236
+ };
237
+ const context = classifyPreviewRequest(request.method, request.headers, parsed.search);
238
+ reply.hijack();
239
+ if (request.method.toUpperCase() === 'GET' && previewServiceWorkerSegment(parsed.suffix)) {
240
+ writeServiceWorkerScript(reply.raw);
241
+ return;
242
+ }
243
+ if (shouldServeBootstrap(context, request.method)) {
244
+ writeBootstrapPage(reply.raw, scope);
245
+ return;
246
+ }
247
+ await proxyPreviewHttpRequest({
248
+ request: request.raw,
249
+ response: reply.raw,
250
+ scope,
251
+ suffix: parsed.suffix,
252
+ search: parsed.search,
253
+ context,
254
+ body: requestBodyBuffer(request),
255
+ });
631
256
  }
632
- const target = await previewService.getTarget(parsed.workspaceId);
633
- if (!target) {
634
- return reply.code(404).send({ error: 'Preview target is not configured', code: 'PREVIEW_NOT_CONFIGURED' });
257
+ catch (err) {
258
+ if (!reply.sent)
259
+ return errorResponse(err, reply);
260
+ reply.raw.end();
635
261
  }
636
- reply.hijack();
637
- await proxyHttpRequest(request, reply.raw, parsed.workspaceId, target, parsed.previewToken);
638
- }
639
- catch (err) {
640
- if (!reply.sent)
641
- return errorResponse(err, reply);
642
- reply.raw.end();
643
- }
644
- };
645
- app.route({
646
- method: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'],
647
- url: '/view/:workspaceId',
648
- handler,
649
- });
650
- app.route({
651
- method: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'],
652
- url: '/view/:workspaceId/*',
653
- handler,
262
+ };
263
+ proxyApp.route({
264
+ method: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'],
265
+ url: '/view/:workspaceId',
266
+ bodyLimit: PROXY_BODY_LIMIT_BYTES,
267
+ handler,
268
+ });
269
+ proxyApp.route({
270
+ method: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'],
271
+ url: '/view/:workspaceId/*',
272
+ bodyLimit: PROXY_BODY_LIMIT_BYTES,
273
+ handler,
274
+ });
654
275
  });
655
276
  }
656
277
  //# sourceMappingURL=previews.js.map