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
@@ -0,0 +1,128 @@
1
+ import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import * as fs from 'node:fs';
3
+ import * as os from 'node:os';
4
+ import * as path from 'node:path';
5
+ import { buildAgentTowerMcpConfigOverrides, getCodexMcpServerNamesForLaunch, resetCodexMcpServerCache, } from '../codex.executor.js';
6
+ import { ExecutionEnv } from '../execution-env.js';
7
+ const mocks = vi.hoisted(() => ({ execFile: vi.fn() }));
8
+ vi.mock('child_process', async (importOriginal) => ({
9
+ ...await importOriginal(),
10
+ execFile: mocks.execFile,
11
+ }));
12
+ const nativePlatform = process.platform;
13
+ const platformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform');
14
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-mcp-windows-'));
15
+ const workingDir = path.join(tmpDir, 'project with spaces');
16
+ const codexHome = path.join(tmpDir, 'codex-home');
17
+ fs.mkdirSync(path.join(workingDir, '.codex'), { recursive: true });
18
+ fs.mkdirSync(codexHome);
19
+ fs.writeFileSync(path.join(workingDir, '.codex', 'config.toml'), '[mcp_servers.agent-tower]\ncommand="old-tower"');
20
+ beforeEach(() => {
21
+ Object.defineProperty(process, 'platform', { ...platformDescriptor, value: 'win32' });
22
+ resetCodexMcpServerCache();
23
+ mocks.execFile.mockReset();
24
+ mocks.execFile.mockImplementation((_command, _args, _options, callback) => {
25
+ callback(null, JSON.stringify([{ name: 'agent-tower' }, { name: 'project-only' }]));
26
+ });
27
+ });
28
+ afterEach(() => {
29
+ Object.defineProperty(process, 'platform', platformDescriptor);
30
+ resetCodexMcpServerCache();
31
+ });
32
+ afterAll(() => { fs.rmSync(tmpDir, { recursive: true, force: true }); });
33
+ function environment(overrides = {}) {
34
+ return { CODEX_HOME: codexHome, PROVIDER_SENTINEL: 'provider-value', ...overrides };
35
+ }
36
+ describe('Windows Codex MCP launch discovery', () => {
37
+ it.each(['cmd', 'BAT'])('loads project MCPs through a .%s shim with cwd, env and config arguments', async (extension) => {
38
+ const executable = path.join(tmpDir, `npm directory/codex.${extension}`);
39
+ const env = environment({ ComSpec: 'custom-cmd.exe' });
40
+ const overrides = ['--profile', 'work profile', '-c', 'model="test model"'];
41
+ const names = await getCodexMcpServerNamesForLaunch(overrides, undefined, { program: executable, args: overrides }, env, workingDir);
42
+ expect(names).toEqual(new Set(['agent-tower', 'project-only']));
43
+ expect(mocks.execFile).toHaveBeenCalledOnce();
44
+ const [command, args, options] = mocks.execFile.mock.calls[0];
45
+ expect(command).toBe('custom-cmd.exe');
46
+ expect(args.slice(0, 3)).toEqual(['/d', '/s', '/c']);
47
+ expect(args[3]).toContain('codex.' + extension);
48
+ expect(args[3]).toContain('--profile "work profile"');
49
+ expect(args[3]).toContain('-c "model=\\"test model\\""');
50
+ expect(args[3]).toMatch(/ mcp list --json"$/);
51
+ expect(options).toMatchObject({
52
+ cwd: fs.realpathSync(workingDir), env, timeout: 3000, windowsHide: true, windowsVerbatimArguments: true,
53
+ });
54
+ expect(options.shell).not.toBe(true);
55
+ const sessionEnv = ExecutionEnv.default(workingDir).merge({
56
+ AGENT_TOWER_AGENT_CREDENTIAL: 'windows-session-credential',
57
+ AGENT_TOWER_URL: 'http://127.0.0.1:42001',
58
+ AGENT_TOWER_SESSION_ID: 'windows-mcp-session',
59
+ });
60
+ expect(buildAgentTowerMcpConfigOverrides(sessionEnv, names)).toContain('mcp_servers.agent-tower.enabled=false');
61
+ });
62
+ it.each(['ComSpec', 'COMSPEC', undefined])('selects the configured command interpreter (%s)', async (key) => {
63
+ const env = environment(key ? { [key]: 'selected-cmd.exe' } : {});
64
+ await getCodexMcpServerNamesForLaunch([], undefined, { program: path.join(tmpDir, 'codex.cmd'), args: [] }, env, workingDir);
65
+ expect(mocks.execFile.mock.calls[0][0]).toBe(key ? 'selected-cmd.exe' : 'cmd.exe');
66
+ });
67
+ it('resolves an npm shim from a Windows Path variable', async () => {
68
+ const binDir = path.join(tmpDir, 'npm-bin');
69
+ fs.mkdirSync(binDir, { recursive: true });
70
+ fs.writeFileSync(path.join(binDir, 'codex.CMD'), '');
71
+ const env = environment({ Path: binDir, PATHEXT: '.EXE;.CMD;.BAT' });
72
+ await getCodexMcpServerNamesForLaunch([], undefined, { program: 'codex', args: [] }, env, workingDir);
73
+ expect(mocks.execFile.mock.calls[0][0]).toBe('cmd.exe');
74
+ expect(mocks.execFile.mock.calls[0][1][3]).toContain('codex.CMD');
75
+ });
76
+ it('retains a relative custom shim and resolves it from the target workspace', async () => {
77
+ await getCodexMcpServerNamesForLaunch([], undefined, { program: './tools/custom-codex.cmd', args: ['--profile', 'custom'] }, environment(), workingDir);
78
+ const args = mocks.execFile.mock.calls[0][1];
79
+ expect(args[3]).toContain('custom-codex.cmd');
80
+ // cmd quoting escapes Windows path separators; normalize only for this assertion.
81
+ expect(args[3].replace(/\\\\/g, '\\')).toContain(path.join(workingDir, 'tools', 'custom-codex.cmd'));
82
+ expect(args[3]).toContain('--profile custom mcp list --json');
83
+ });
84
+ it('keeps native executables and missing custom commands on the direct path', async () => {
85
+ for (const program of [path.join(tmpDir, 'native codex.exe'), 'custom-missing-codex']) {
86
+ const args = ['-c', 'model="test model"'];
87
+ await getCodexMcpServerNamesForLaunch(args, undefined, { program, args }, environment(), workingDir);
88
+ expect(mocks.execFile).toHaveBeenLastCalledWith(program, [...args, 'mcp', 'list', '--json'], expect.not.objectContaining({ windowsVerbatimArguments: true }), expect.any(Function));
89
+ }
90
+ });
91
+ it('retains the existing global fallback if the command interpreter fails', async () => {
92
+ const configPath = path.join(tmpDir, 'fallback.toml');
93
+ fs.writeFileSync(configPath, '[mcp_servers.global-only]\ncommand="fallback-mcp"');
94
+ mocks.execFile.mockImplementation((_command, _args, _options, callback) => callback(new Error('interpreter failed'), ''));
95
+ const names = await getCodexMcpServerNamesForLaunch([], configPath, { program: path.join(tmpDir, 'codex.cmd'), args: [] }, environment(), workingDir);
96
+ expect(names).toEqual(new Set(['global-only']));
97
+ });
98
+ it('does not wrap a .cmd filename on Unix', async () => {
99
+ Object.defineProperty(process, 'platform', { ...platformDescriptor, value: 'linux' });
100
+ const executable = path.join(tmpDir, 'unix-codex.cmd');
101
+ await getCodexMcpServerNamesForLaunch([], undefined, { program: executable, args: [] }, environment(), workingDir);
102
+ expect(mocks.execFile).toHaveBeenCalledWith(executable, ['mcp', 'list', '--json'], expect.not.objectContaining({ windowsVerbatimArguments: true }), expect.any(Function));
103
+ });
104
+ });
105
+ describe.skipIf(nativePlatform !== 'win32')('native Windows npm shim discovery', () => {
106
+ it.each(['cmd', 'bat'])('round-trips project configuration and arguments through a real .%s shim', async (extension) => {
107
+ const nativeChildProcess = await vi.importActual('child_process');
108
+ mocks.execFile.mockImplementation(nativeChildProcess.execFile);
109
+ const script = path.join(tmpDir, 'native-probe.cjs');
110
+ const captured = path.join(tmpDir, `native-args-${extension}.json`);
111
+ fs.writeFileSync(script, [
112
+ 'const fs = require("node:fs");',
113
+ `fs.writeFileSync(${JSON.stringify(captured)}, JSON.stringify({args: process.argv.slice(2), cwd: process.cwd(), sentinel: process.env.PROVIDER_SENTINEL}));`,
114
+ 'const config = fs.readFileSync(".codex/config.toml", "utf8");',
115
+ 'process.stdout.write(JSON.stringify(config.includes("mcp_servers.agent-tower") ? [{name:"agent-tower"}] : []));',
116
+ ].join('\n'));
117
+ const shim = path.join(tmpDir, `native codex.${extension}`);
118
+ fs.writeFileSync(shim, `@echo off\r\n"${process.execPath}" "${script}" %*\r\n`);
119
+ const args = ['-c', 'model="test model"'];
120
+ const env = environment({ ...process.env, CODEX_HOME: codexHome });
121
+ const names = await getCodexMcpServerNamesForLaunch(args, undefined, { program: shim, args }, env, workingDir);
122
+ expect(names).toEqual(new Set(['agent-tower']));
123
+ expect(JSON.parse(fs.readFileSync(captured, 'utf8'))).toEqual({
124
+ args: [...args, 'mcp', 'list', '--json'], cwd: fs.realpathSync(workingDir), sentinel: 'provider-value',
125
+ });
126
+ });
127
+ });
128
+ //# sourceMappingURL=codex-mcp-windows.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-mcp-windows.test.js","sourceRoot":"","sources":["../../../src/executors/__tests__/codex-mcp-windows.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACnF,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EACL,iCAAiC,EACjC,+BAA+B,EAC/B,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AACxD,EAAE,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,EAAC,cAAc,EAAC,EAAE,CAAC,CAAC;IAChD,GAAG,MAAM,cAAc,EAAuB;IAC9C,QAAQ,EAAE,KAAK,CAAC,QAAQ;CACzB,CAAC,CAAC,CAAC;AAEJ,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC;AACxC,MAAM,kBAAkB,GAAG,MAAM,CAAC,wBAAwB,CAAC,OAAO,EAAE,UAAU,CAAE,CAAC;AACjF,MAAM,MAAM,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC;AAC5E,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;AAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAClD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACnE,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AACxB,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,gDAAgD,CAAC,CAAC;AAEnH,UAAU,CAAC,GAAG,EAAE;IACd,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,GAAG,kBAAkB,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IACtF,wBAAwB,EAAE,CAAC;IAC3B,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;IAC3B,KAAK,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE;QACxE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AACH,SAAS,CAAC,GAAG,EAAE;IACb,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,kBAAkB,CAAC,CAAC;IAC/D,wBAAwB,EAAE,CAAC;AAC7B,CAAC,CAAC,CAAC;AACH,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzE,SAAS,WAAW,CAAC,YAA+B,EAAE;IACpD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,GAAG,SAAS,EAAE,CAAC;AACtF,CAAC;AAED,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,0EAA0E,EAAE,KAAK,EAAC,SAAS,EAAC,EAAE;QACpH,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,uBAAuB,SAAS,EAAE,CAAC,CAAC;QACzE,MAAM,GAAG,GAAG,WAAW,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC;QACvD,MAAM,SAAS,GAAG,CAAC,WAAW,EAAE,cAAc,EAAE,IAAI,EAAE,oBAAoB,CAAC,CAAC;QAE5E,MAAM,KAAK,GAAG,MAAM,+BAA+B,CACjD,SAAS,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,UAAU,CAChF,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,oBAAoB,EAAE,CAAC;QAC9C,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;QAC/D,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QACzD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;QAC9C,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC;YAC5B,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI;SACxG,CAAC,CAAC;QACH,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAErC,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC;YACxD,4BAA4B,EAAE,4BAA4B;YAC1D,eAAe,EAAE,wBAAwB;YACzC,sBAAsB,EAAE,qBAAqB;SAC9C,CAAC,CAAC;QACH,MAAM,CAAC,iCAAiC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,uCAAuC,CAAC,CAAC;IAClH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,iDAAiD,EAAE,KAAK,EAAC,GAAG,EAAC,EAAE;QACxG,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAClE,MAAM,+BAA+B,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;QAC7H,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAC5C,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC;QACrD,MAAM,GAAG,GAAG,WAAW,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC;QAErE,MAAM,+BAA+B,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;QAEtG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,MAAM,+BAA+B,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,0BAA0B,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,EAAE,UAAU,CAAC,CAAC;QACxJ,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;QAC9C,kFAAkF;QAClF,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC;QACrG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;QACvF,KAAK,MAAM,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,sBAAsB,CAAC,EAAE,CAAC;YACtF,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;YAC1C,MAAM,+BAA+B,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,EAAE,UAAU,CAAC,CAAC;YACrG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,wBAAwB,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EACzF,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,wBAAwB,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACrF,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;QACtD,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,mDAAmD,CAAC,CAAC;QAClF,KAAK,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAE1H,MAAM,KAAK,GAAG,MAAM,+BAA+B,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,UAAU,CAAC,CAAC;QACtJ,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,GAAG,kBAAkB,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACtF,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QACvD,MAAM,+BAA+B,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,UAAU,CAAC,CAAC;QACnH,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAC/E,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,wBAAwB,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,MAAM,CAAC,cAAc,KAAK,OAAO,CAAC,CAAC,mCAAmC,EAAE,GAAG,EAAE;IACpF,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,yEAAyE,EAAE,KAAK,EAAC,SAAS,EAAC,EAAE;QACnH,MAAM,kBAAkB,GAAG,MAAM,EAAE,CAAC,YAAY,CAAsB,eAAe,CAAC,CAAC;QACvF,KAAK,CAAC,QAAQ,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,SAAS,OAAO,CAAC,CAAC;QACpE,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE;YACvB,gCAAgC;YAChC,oBAAoB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,gHAAgH;YAC5J,+DAA+D;YAC/D,iHAAiH;SAClH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACd,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,gBAAgB,SAAS,EAAE,CAAC,CAAC;QAC5D,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,iBAAiB,OAAO,CAAC,QAAQ,MAAM,MAAM,UAAU,CAAC,CAAC;QAChF,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;QAE1C,MAAM,GAAG,GAAG,WAAW,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;QACnE,MAAM,KAAK,GAAG,MAAM,+BAA+B,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;QAE/G,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC5D,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,gBAAgB;SACvG,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -2,7 +2,8 @@ import { describe, expect, it, afterAll, afterEach, beforeEach, vi } from 'vites
2
2
  import * as fs from 'fs';
3
3
  import * as os from 'os';
4
4
  import * as path from 'path';
5
- import { buildAgentTowerMcpEnvConfigOverrides, getCodexDeclaredMcpServerNames, queryCodexMcpServerNames, detectDeclaredMcpServers, getCachedCodexMcpServerNames, resetCodexMcpServerCache, waitForCodexMcpServerCacheRefresh, CODEX_HTTP_ONLY_OPENAI_PROVIDER_ID, getCodexPermissionMode, CodexExecutor, } from '../codex.executor.js';
5
+ import { parse as parseToml } from 'smol-toml';
6
+ import { buildAgentTowerMcpConfigOverrides, buildAgentTowerMcpEnvConfigOverrides, getCodexDeclaredMcpServerNames, queryCodexMcpServerNames, detectDeclaredMcpServers, getCachedCodexMcpServerNames, getCodexMcpServerNamesForLaunch, resetCodexMcpServerCache, waitForCodexMcpServerCacheRefresh, CODEX_HTTP_ONLY_OPENAI_PROVIDER_ID, getCodexPermissionMode, CodexExecutor, } from '../codex.executor.js';
6
7
  import { AGENT_SUBPROCESS_BLOCKED_ENV_KEYS, AGENT_TOWER_MCP_IDENTITY_ENV_KEYS, AGENT_TOWER_MCP_SERVICE_ENV_KEYS, ExecutionEnv, } from '../execution-env.js';
7
8
  import { getExecutorByProvider, createExecutorFromProvider } from '../index.js';
8
9
  import { createProvider as createRawProvider, reloadProviders, updateProvider } from '../providers.js';
@@ -637,6 +638,7 @@ function createAsyncProbeCodex(name, stdout, options = {}) {
637
638
  const script = [
638
639
  '#!/bin/sh',
639
640
  `printf '1\\n' >> "${countFile}"`,
641
+ `pwd >> "${path.join(binDir, 'probe-cwds')}"`,
640
642
  `sleep ${delaySeconds}`,
641
643
  'cat <<\'FAKE_EOF\'',
642
644
  stdout,
@@ -653,6 +655,34 @@ function probeCount(binDir) {
653
655
  return 0;
654
656
  return fs.readFileSync(file, 'utf-8').trim().split('\n').filter(Boolean).length;
655
657
  }
658
+ function createWorkspaceProbeCodex(name, options = {}) {
659
+ const binDir = path.join(tmpDir, `workspace-probe-${name}`);
660
+ fs.mkdirSync(binDir, { recursive: true });
661
+ const script = `#!${process.execPath}
662
+ const fs = require('node:fs');
663
+ const path = require('node:path');
664
+ fs.appendFileSync(${JSON.stringify(path.join(binDir, 'probe-count'))}, '1\\n');
665
+ fs.appendFileSync(${JSON.stringify(path.join(binDir, 'probe-cwds'))}, process.cwd() + '\\n');
666
+ setTimeout(() => {
667
+ const files = [path.join(process.env.CODEX_HOME, 'config.toml')];
668
+ if (!${Boolean(options.ignoreProject)}) {
669
+ for (let dir = process.cwd(); ; dir = path.dirname(dir)) {
670
+ files.push(path.join(dir, '.codex', 'config.toml'));
671
+ if (path.dirname(dir) === dir) break;
672
+ }
673
+ }
674
+ const names = new Set();
675
+ for (const file of files) {
676
+ try {
677
+ for (const match of fs.readFileSync(file, 'utf8').matchAll(/^\\[mcp_servers\\.([a-zA-Z0-9_-]+)\\]/gm)) names.add(match[1]);
678
+ } catch {}
679
+ }
680
+ process.stdout.write(JSON.stringify([...names].map(name => ({ name }))));
681
+ }, ${options.delayMs ?? 0});
682
+ `;
683
+ fs.writeFileSync(path.join(binDir, 'codex'), script, { mode: 0o755 });
684
+ return binDir;
685
+ }
656
686
  describe('getCachedCodexMcpServerNames', () => {
657
687
  it('returns fallback names immediately and probes without blocking the event loop', async () => {
658
688
  const binDir = createAsyncProbeCodex('nonblocking', JSON.stringify([{ name: 'agent-tower' }]), { delayMs: 500 });
@@ -724,6 +754,126 @@ describe('getCachedCodexMcpServerNames', () => {
724
754
  await waitForCodexMcpServerCacheRefresh();
725
755
  expect(probeCount(binDir)).toBe(1);
726
756
  });
757
+ it('awaits effective workspace and ancestor declarations on the first launch without blocking the event loop', async () => {
758
+ const binDir = createWorkspaceProbeCodex('workspace-fallback', { delayMs: 100 });
759
+ const home = path.join(tmpDir, 'workspace-fallback-home');
760
+ const project = path.join(tmpDir, 'workspace-fallback-project');
761
+ const workingDir = path.join(project, 'packages', 'app');
762
+ fs.mkdirSync(home, { recursive: true });
763
+ fs.mkdirSync(path.join(project, '.codex'), { recursive: true });
764
+ fs.mkdirSync(path.join(workingDir, '.codex'), { recursive: true });
765
+ fs.writeFileSync(path.join(home, 'config.toml'), '[mcp_servers.global-tool]\ncommand="global-mcp"');
766
+ fs.writeFileSync(path.join(project, '.codex', 'config.toml'), '[mcp_servers.agent-tower]\nurl="https://old.example/mcp"');
767
+ const sessionEnv = ExecutionEnv.default(workingDir).merge({
768
+ AGENT_TOWER_AGENT_CREDENTIAL: 'project-session-credential',
769
+ AGENT_TOWER_URL: 'http://127.0.0.1:42001',
770
+ AGENT_TOWER_SESSION_ID: 'project-fallback-session',
771
+ });
772
+ const generatedName = buildAgentTowerMcpConfigOverrides(sessionEnv, new Set())
773
+ .find(arg => /^mcp_servers\.agent-tower-[a-f0-9]{8}=/.test(arg))
774
+ .split('=')[0].slice('mcp_servers.'.length);
775
+ fs.writeFileSync(path.join(workingDir, '.codex', 'config.toml'), [
776
+ '[mcp_servers.agent-tower-dev]', 'command="old-dev-mcp"',
777
+ `[mcp_servers.${generatedName}]`, 'url="https://old-name.example/mcp"',
778
+ ].join('\n'));
779
+ const environment = { ...process.env, PATH: `${binDir}:${savedPath}`, CODEX_HOME: home };
780
+ const probe = { program: 'codex', args: [] };
781
+ const expected = new Set(['global-tool', 'agent-tower', 'agent-tower-dev', generatedName]);
782
+ let eventLoopAdvanced = false;
783
+ const tick = new Promise(resolve => setTimeout(() => { eventLoopAdvanced = true; resolve(); }, 0));
784
+ const initial = await getCodexMcpServerNamesForLaunch([], undefined, probe, environment, workingDir);
785
+ expect(eventLoopAdvanced).toBe(true);
786
+ await tick;
787
+ expect(initial).toEqual(expected);
788
+ const overrides = buildAgentTowerMcpConfigOverrides(sessionEnv, initial);
789
+ expect(overrides).toContain('mcp_servers.agent-tower.enabled=false');
790
+ expect(overrides).toContain('mcp_servers.agent-tower-dev.enabled=false');
791
+ expect(overrides.some(arg => arg.startsWith(`mcp_servers.${generatedName}-2=`))).toBe(true);
792
+ await waitForCodexMcpServerCacheRefresh();
793
+ expect(getCachedCodexMcpServerNames([], undefined, probe, environment, workingDir)).toEqual(expected);
794
+ expect(fs.readFileSync(path.join(binDir, 'probe-cwds'), 'utf8').trim()).toBe(fs.realpathSync(workingDir));
795
+ });
796
+ it('isolates cached probes for workspaces sharing the same executable and CODEX_HOME', async () => {
797
+ const binDir = createWorkspaceProbeCodex('workspace-isolation');
798
+ const home = path.join(tmpDir, 'workspace-isolation-home');
799
+ fs.mkdirSync(home, { recursive: true });
800
+ const environment = { ...process.env, PATH: `${binDir}:${savedPath}`, CODEX_HOME: home };
801
+ const probe = { program: 'codex', args: [] };
802
+ const workspaces = ['first', 'second'].map(name => {
803
+ const workspace = path.join(tmpDir, `isolated-${name}`);
804
+ fs.mkdirSync(path.join(workspace, '.codex'), { recursive: true });
805
+ fs.writeFileSync(path.join(workspace, '.codex', 'config.toml'), `[mcp_servers.${name}-tool]\ncommand="${name}-mcp"`);
806
+ return workspace;
807
+ });
808
+ const [first, second] = await Promise.all(workspaces.map(workspace => getCodexMcpServerNamesForLaunch([], undefined, probe, environment, workspace)));
809
+ expect(first).toEqual(new Set(['first-tool']));
810
+ expect(second).toEqual(new Set(['second-tool']));
811
+ expect(probeCount(binDir)).toBe(2);
812
+ expect(new Set(fs.readFileSync(path.join(binDir, 'probe-cwds'), 'utf8').trim().split('\n'))).toEqual(new Set(workspaces.map(workspace => fs.realpathSync(workspace))));
813
+ expect(getCachedCodexMcpServerNames([], undefined, probe, environment, workspaces[0])).toEqual(new Set(['first-tool']));
814
+ expect(getCachedCodexMcpServerNames([], undefined, probe, environment, workspaces[1])).toEqual(new Set(['second-tool']));
815
+ });
816
+ it.each(['workspace', 'ancestor'])('invalidates the cache when a %s config is created, changed or removed', async (scope) => {
817
+ const binDir = createWorkspaceProbeCodex(`workspace-config-change-${scope}`);
818
+ const home = path.join(tmpDir, `project-config-change-home-${scope}`);
819
+ const project = path.join(tmpDir, `project-config-change-${scope}`);
820
+ const workingDir = path.join(project, 'nested', 'app');
821
+ fs.mkdirSync(home, { recursive: true });
822
+ fs.mkdirSync(workingDir, { recursive: true });
823
+ const environment = { ...process.env, PATH: `${binDir}:${savedPath}`, CODEX_HOME: home };
824
+ const probe = { program: 'codex', args: [] };
825
+ const configPath = path.join(scope === 'workspace' ? workingDir : project, '.codex', 'config.toml');
826
+ const lookup = () => getCodexMcpServerNamesForLaunch([], undefined, probe, environment, workingDir);
827
+ expect(await lookup()).toEqual(new Set());
828
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
829
+ fs.writeFileSync(configPath, '[mcp_servers.agent-tower]\ncommand="old-mcp"');
830
+ expect(await lookup()).toEqual(new Set(['agent-tower']));
831
+ fs.writeFileSync(configPath, '[mcp_servers.agent-tower-dev]\ncommand="another-mcp"');
832
+ expect(await lookup()).toEqual(new Set(['agent-tower-dev']));
833
+ fs.unlinkSync(configPath);
834
+ expect(await lookup()).toEqual(new Set());
835
+ expect(probeCount(binDir)).toBeGreaterThanOrEqual(3);
836
+ });
837
+ it('does not fabricate disabled aliases from a project ignored by the CLI trust rules', async () => {
838
+ const binDir = createWorkspaceProbeCodex('untrusted-project', { ignoreProject: true });
839
+ const home = path.join(tmpDir, 'untrusted-project-home');
840
+ const workingDir = path.join(tmpDir, 'untrusted-project-workspace');
841
+ fs.mkdirSync(home, { recursive: true });
842
+ fs.mkdirSync(path.join(workingDir, '.codex'), { recursive: true });
843
+ fs.writeFileSync(path.join(workingDir, '.codex', 'config.toml'), '[mcp_servers.agent-tower]\ncommand="ignored-project-mcp"');
844
+ const environment = { ...process.env, PATH: `${binDir}:${savedPath}`, CODEX_HOME: home };
845
+ const names = await getCodexMcpServerNamesForLaunch([], undefined, { program: 'codex', args: [] }, environment, workingDir);
846
+ const sessionEnv = ExecutionEnv.default(workingDir).merge({
847
+ AGENT_TOWER_AGENT_CREDENTIAL: 'untrusted-session-credential',
848
+ AGENT_TOWER_URL: 'http://127.0.0.1:42001',
849
+ AGENT_TOWER_SESSION_ID: 'untrusted-project-session',
850
+ });
851
+ expect(names).toEqual(new Set());
852
+ const overrides = buildAgentTowerMcpConfigOverrides(sessionEnv, names);
853
+ expect(overrides).not.toContain('mcp_servers.agent-tower.enabled=false');
854
+ expect(managedMcpServer(overrides).enabled).toBe(true);
855
+ });
856
+ it('waits for its shared refresh when a launch cache expires', async () => {
857
+ const name = 'launch-expired-cache';
858
+ const binDir = createAsyncProbeCodex(name, '[{"name":"previous-tool"}]');
859
+ const home = path.join(tmpDir, 'launch-expired-home');
860
+ fs.mkdirSync(home, { recursive: true });
861
+ const environment = { ...process.env, PATH: `${binDir}:${savedPath}`, CODEX_HOME: home };
862
+ const probe = { program: 'codex', args: [] };
863
+ const date = vi.spyOn(Date, 'now').mockReturnValue(1_000_000);
864
+ try {
865
+ expect(await getCodexMcpServerNamesForLaunch([], undefined, probe, environment, tmpDir)).toEqual(new Set(['previous-tool']));
866
+ createAsyncProbeCodex(name, '[{"name":"current-tool"}]', { delayMs: 50 });
867
+ date.mockReturnValue(1_030_001);
868
+ const results = await Promise.all(Array.from({ length: 3 }, () => getCodexMcpServerNamesForLaunch([], undefined, probe, environment, tmpDir)));
869
+ expect(results).toEqual(Array.from({ length: 3 }, () => new Set(['current-tool'])));
870
+ expect(probeCount(binDir)).toBe(2);
871
+ }
872
+ finally {
873
+ await waitForCodexMcpServerCacheRefresh();
874
+ date.mockRestore();
875
+ }
876
+ });
727
877
  });
728
878
  // ─── getCodexDeclaredMcpServerNames (config.toml fallback) ───────
729
879
  describe('getCodexDeclaredMcpServerNames', () => {
@@ -1107,4 +1257,247 @@ describe('buildAgentTowerMcpEnvConfigOverrides', () => {
1107
1257
  ]);
1108
1258
  });
1109
1259
  });
1260
+ function managedMcpServer(args) {
1261
+ const assignment = args.find(arg => /^mcp_servers\.agent-tower-[a-f0-9]{8}(?:-\d+)?=/.test(arg));
1262
+ expect(assignment).toBeDefined();
1263
+ const parsed = parseToml(assignment);
1264
+ const name = Object.keys(parsed.mcp_servers)[0];
1265
+ const server = parsed.mcp_servers[name];
1266
+ server.env = {};
1267
+ for (const arg of args.filter(arg => arg.startsWith(`mcp_servers.${name}.env.`))) {
1268
+ const projected = parseToml(arg);
1269
+ Object.assign(server.env, projected.mcp_servers[name].env);
1270
+ }
1271
+ return server;
1272
+ }
1273
+ describe('managed Codex CLI MCP registration', () => {
1274
+ beforeEach(() => {
1275
+ for (const key of [
1276
+ ...AGENT_TOWER_MCP_IDENTITY_ENV_KEYS, ...AGENT_TOWER_MCP_SERVICE_ENV_KEYS,
1277
+ 'AGENT_TOWER_MCP_ENTRY', 'AGENT_TOWER_DESKTOP_RUNTIME_MODE', 'AGENT_TOWER_NODE_RUNTIME',
1278
+ 'AGENT_TOWER_DESKTOP_NODE', 'ELECTRON_RUN_AS_NODE',
1279
+ ])
1280
+ vi.stubEnv(key, undefined);
1281
+ });
1282
+ afterEach(() => { vi.unstubAllEnvs(); });
1283
+ it('registers the source MCP without user configuration and scopes its environment to the current session', () => {
1284
+ vi.stubEnv('AGENT_TOWER_AGENT_CREDENTIAL', 'parent-agent-secret');
1285
+ vi.stubEnv('AGENT_TOWER_INTERNAL_TOKEN', 'parent-internal-secret');
1286
+ vi.stubEnv('AGENT_TOWER_SESSION_ID', 'parent-session');
1287
+ vi.stubEnv('AGENT_TOWER_TEAM_RUN_ID', 'parent-team');
1288
+ const env = ExecutionEnv.default(tmpDir).merge({
1289
+ AGENT_TOWER_AGENT_CREDENTIAL: 'current-agent-credential',
1290
+ AGENT_TOWER_INTERNAL_TOKEN: 'must-not-forward-internal',
1291
+ AGENT_TOWER_URL: 'http://127.0.0.1:42001',
1292
+ AGENT_TOWER_PORT: '42001',
1293
+ AGENT_TOWER_SESSION_ID: 'current-session',
1294
+ AGENT_TOWER_INVOCATION_ID: 'current-invocation',
1295
+ AGENT_TOWER_TEAM_RUN_ID: 'current-team',
1296
+ AGENT_TOWER_MEMBER_ID: 'current-member',
1297
+ OPENAI_API_KEY: 'provider-secret',
1298
+ });
1299
+ const args = buildAgentTowerMcpConfigOverrides(env, new Set());
1300
+ const server = managedMcpServer(args);
1301
+ expect(server).toEqual({
1302
+ command: process.execPath,
1303
+ args: ['--import', expect.stringMatching(/[\\/]tsx[\\/]dist[\\/]loader\.mjs$/), path.resolve('packages/server/src/mcp/index.ts')],
1304
+ enabled: true,
1305
+ env: {
1306
+ AGENT_TOWER_URL: 'http://127.0.0.1:42001',
1307
+ AGENT_TOWER_PORT: '42001',
1308
+ AGENT_TOWER_AGENT_CREDENTIAL: 'current-agent-credential',
1309
+ AGENT_TOWER_SESSION_ID: 'current-session',
1310
+ AGENT_TOWER_INVOCATION_ID: 'current-invocation',
1311
+ AGENT_TOWER_TEAM_RUN_ID: 'current-team',
1312
+ AGENT_TOWER_MEMBER_ID: 'current-member',
1313
+ },
1314
+ });
1315
+ expect(args.join(' ')).not.toMatch(/parent-|must-not-forward-internal|provider-secret/);
1316
+ const registration = args.find(arg => /^mcp_servers\.agent-tower-[a-f0-9]{8}=/.test(arg));
1317
+ expect(registration).not.toContain('current-agent-credential');
1318
+ expect(registration).not.toContain('env');
1319
+ expect(args.some(arg => arg.startsWith('mcp_servers.agent-tower.env.'))).toBe(false);
1320
+ });
1321
+ it('uses a distinct backend and credential for each session without inheriting a previous team identity', () => {
1322
+ vi.stubEnv('AGENT_TOWER_TEAM_RUN_ID', 'stale-parent-team');
1323
+ const first = ExecutionEnv.default(tmpDir).merge({
1324
+ AGENT_TOWER_AGENT_CREDENTIAL: 'first-credential', AGENT_TOWER_PORT: '42001',
1325
+ AGENT_TOWER_SESSION_ID: 'first-session', AGENT_TOWER_TEAM_RUN_ID: 'first-team',
1326
+ });
1327
+ const second = ExecutionEnv.default(tmpDir).merge({
1328
+ AGENT_TOWER_AGENT_CREDENTIAL: 'second-credential', AGENT_TOWER_URL: 'http://127.0.0.1:42002',
1329
+ AGENT_TOWER_SESSION_ID: 'second-session',
1330
+ });
1331
+ const firstServer = managedMcpServer(buildAgentTowerMcpConfigOverrides(first, new Set()));
1332
+ const secondServer = managedMcpServer(buildAgentTowerMcpConfigOverrides(second, new Set()));
1333
+ expect(firstServer.env.AGENT_TOWER_URL).toBe('http://127.0.0.1:42001');
1334
+ expect(firstServer.env.AGENT_TOWER_TEAM_RUN_ID).toBe('first-team');
1335
+ expect(secondServer.env).toEqual({
1336
+ AGENT_TOWER_URL: 'http://127.0.0.1:42002',
1337
+ AGENT_TOWER_AGENT_CREDENTIAL: 'second-credential',
1338
+ AGENT_TOWER_SESSION_ID: 'second-session',
1339
+ });
1340
+ });
1341
+ it.each(['workspace', 'packaged'])('uses the trusted %s runtime entry and keeps its Node environment', mode => {
1342
+ const entry = path.join(tmpDir, `${mode} install`, 'dist', 'mcp', 'index.js');
1343
+ fs.mkdirSync(path.dirname(entry), { recursive: true });
1344
+ fs.writeFileSync(entry, '');
1345
+ vi.stubEnv('AGENT_TOWER_MCP_ENTRY', entry);
1346
+ vi.stubEnv('AGENT_TOWER_DESKTOP_RUNTIME_MODE', mode);
1347
+ vi.stubEnv('AGENT_TOWER_NODE_RUNTIME', 'C:\\Program Files\\Agent Tower\\node.exe');
1348
+ vi.stubEnv('ELECTRON_RUN_AS_NODE', '1');
1349
+ const env = ExecutionEnv.default(tmpDir).merge({
1350
+ AGENT_TOWER_URL: 'http://127.0.0.1:12580',
1351
+ AGENT_TOWER_INTERNAL_TOKEN: 'trusted-internal-token',
1352
+ });
1353
+ const server = managedMcpServer(buildAgentTowerMcpConfigOverrides(env, new Set()));
1354
+ expect(server.command).toBe(mode === 'packaged' ? 'C:\\Program Files\\Agent Tower\\node.exe' : process.execPath);
1355
+ expect(server.args).toEqual([entry]);
1356
+ expect(server.env).toEqual({
1357
+ AGENT_TOWER_URL: 'http://127.0.0.1:12580',
1358
+ AGENT_TOWER_INTERNAL_TOKEN: 'trusted-internal-token',
1359
+ ...(mode === 'packaged' ? { ELECTRON_RUN_AS_NODE: '1' } : {}),
1360
+ });
1361
+ });
1362
+ it('disables declared Tower endpoints without sharing credentials and leaves unrelated MCP servers alone', () => {
1363
+ const env = ExecutionEnv.default(tmpDir).merge({
1364
+ AGENT_TOWER_URL: 'http://127.0.0.1:42001',
1365
+ AGENT_TOWER_AGENT_CREDENTIAL: 'session-credential',
1366
+ AGENT_TOWER_INTERNAL_TOKEN: 'must-not-forward-internal',
1367
+ AGENT_TOWER_SESSION_ID: 'session',
1368
+ });
1369
+ const args = buildAgentTowerMcpConfigOverrides(env, new Set(['agent-tower', 'agent-tower-dev', 'other-server']));
1370
+ expect(managedMcpServer(args).env.AGENT_TOWER_AGENT_CREDENTIAL).toBe('session-credential');
1371
+ expect(args).toContain('mcp_servers.agent-tower.enabled=false');
1372
+ expect(args).toContain('mcp_servers.agent-tower-dev.enabled=false');
1373
+ expect(args.some(arg => /^mcp_servers\.(agent-tower|agent-tower-dev)\.env\./.test(arg))).toBe(false);
1374
+ expect(args.join(' ')).not.toContain('must-not-forward-internal');
1375
+ expect(args.some(arg => arg.includes('other-server'))).toBe(false);
1376
+ });
1377
+ it('does not register MCP from credentials belonging to a parent process', () => {
1378
+ vi.stubEnv('AGENT_TOWER_AGENT_CREDENTIAL', 'parent-agent-secret');
1379
+ vi.stubEnv('AGENT_TOWER_INTERNAL_TOKEN', 'parent-internal-secret');
1380
+ const env = ExecutionEnv.default(tmpDir).set('AGENT_TOWER_SESSION_ID', 'session');
1381
+ expect(buildAgentTowerMcpConfigOverrides(env, new Set())).toEqual([]);
1382
+ expect(buildAgentTowerMcpConfigOverrides(env, new Set(['agent-tower']))).toEqual([
1383
+ '-c', 'mcp_servers.agent-tower.env.AGENT_TOWER_SESSION_ID="session"',
1384
+ ]);
1385
+ });
1386
+ it('chooses an unused managed server name without changing an existing server at the generated name', () => {
1387
+ const env = ExecutionEnv.default(tmpDir).merge({
1388
+ AGENT_TOWER_URL: 'http://127.0.0.1:42001',
1389
+ AGENT_TOWER_AGENT_CREDENTIAL: 'session-credential',
1390
+ AGENT_TOWER_SESSION_ID: 'session-with-existing-server',
1391
+ });
1392
+ const initial = buildAgentTowerMcpConfigOverrides(env, new Set());
1393
+ const assignment = initial.find(arg => /^mcp_servers\.agent-tower-[a-f0-9]{8}=/.test(arg));
1394
+ const existingName = assignment.slice('mcp_servers.'.length, assignment.indexOf('='));
1395
+ const args = buildAgentTowerMcpConfigOverrides(env, new Set([existingName, `${existingName}-2`]));
1396
+ expect(args.some(arg => arg.startsWith(`mcp_servers.${existingName}-3=`))).toBe(true);
1397
+ expect(args.some(arg => arg.startsWith(`mcp_servers.${existingName}.`))).toBe(false);
1398
+ expect(args.some(arg => arg.startsWith(`mcp_servers.${existingName}-2.`))).toBe(false);
1399
+ expect(managedMcpServer(args).env.AGENT_TOWER_AGENT_CREDENTIAL).toBe('session-credential');
1400
+ });
1401
+ it.each(['FULL_ACCESS', 'ASK', 'AUTO_SANDBOX'])('disables project-level Tower aliases on the first new and resumed %s launch', async (executionPermission) => {
1402
+ const home = path.join(tmpDir, `project-launch-home-${executionPermission}`);
1403
+ const workingDir = path.join(tmpDir, `project-launch-workspace-${executionPermission}`);
1404
+ fs.mkdirSync(home, { recursive: true });
1405
+ fs.mkdirSync(path.join(workingDir, '.codex'), { recursive: true });
1406
+ const projectConfig = '[mcp_servers.agent-tower]\nurl="https://old-project.example/mcp"\n[mcp_servers.agent-tower-dev]\ncommand="old-dev-mcp"\n[mcp_servers.project-tool]\ncommand="project-mcp"';
1407
+ const configPath = path.join(workingDir, '.codex', 'config.toml');
1408
+ fs.writeFileSync(configPath, projectConfig);
1409
+ vi.stubEnv('CODEX_HOME', home);
1410
+ const binDir = createWorkspaceProbeCodex(`project-launch-${executionPermission}`, { delayMs: 50 });
1411
+ const executable = path.join(binDir, 'codex');
1412
+ const refresh = vi.spyOn(codexAskCapabilities, 'refreshCodexCliSupport').mockResolvedValue({ supported: true, executable });
1413
+ const support = vi.spyOn(codexAskCapabilities, 'cachedCodexCliSupport').mockReturnValue({ supported: true, executable });
1414
+ const executor = new CodexExecutor({ executionPermission, cmd: { baseCommandOverride: executable } });
1415
+ const stdin = vi.spyOn(executor, 'spawnWithStdin').mockResolvedValue({});
1416
+ const duplex = vi.spyOn(executor, 'spawnWithDuplex').mockResolvedValue({});
1417
+ try {
1418
+ const config = {
1419
+ workingDir, prompt: 'task',
1420
+ env: ExecutionEnv.default(workingDir).merge({
1421
+ AGENT_TOWER_URL: 'http://127.0.0.1:42001',
1422
+ AGENT_TOWER_AGENT_CREDENTIAL: 'project-bound-credential',
1423
+ AGENT_TOWER_SESSION_ID: 'project-launch-session',
1424
+ }),
1425
+ };
1426
+ await executor.spawn(config);
1427
+ await executor.spawnFollowUp(config, 'native-thread');
1428
+ const spawn = executionPermission === 'FULL_ACCESS' ? stdin : duplex;
1429
+ expect(spawn).toHaveBeenCalledTimes(2);
1430
+ for (const [, parts] of spawn.mock.calls) {
1431
+ expect(parts.args).toContain('mcp_servers.agent-tower.enabled=false');
1432
+ expect(parts.args).toContain('mcp_servers.agent-tower-dev.enabled=false');
1433
+ expect(parts.args.some(arg => arg.includes('mcp_servers.project-tool'))).toBe(false);
1434
+ expect(managedMcpServer(parts.args).env.AGENT_TOWER_SESSION_ID).toBe('project-launch-session');
1435
+ }
1436
+ await waitForCodexMcpServerCacheRefresh();
1437
+ expect(fs.readFileSync(path.join(binDir, 'probe-cwds'), 'utf8').trim()).toBe(fs.realpathSync(workingDir));
1438
+ expect(fs.readFileSync(configPath, 'utf8')).toBe(projectConfig);
1439
+ expect(fs.readdirSync(home)).toEqual([]);
1440
+ }
1441
+ finally {
1442
+ await waitForCodexMcpServerCacheRefresh();
1443
+ stdin.mockRestore();
1444
+ duplex.mockRestore();
1445
+ refresh.mockRestore();
1446
+ support.mockRestore();
1447
+ }
1448
+ });
1449
+ it.each(['FULL_ACCESS', 'ASK', 'AUTO_SANDBOX'])('isolates managed MCP from stale user settings on new and resumed %s launches without writing user config', async (executionPermission) => {
1450
+ const home = path.join(tmpDir, `managed-codex-home-${executionPermission}`);
1451
+ fs.mkdirSync(home, { recursive: true });
1452
+ const userConfig = '[mcp_servers.agent-tower]\nurl="https://stale.example/mcp"\nenabled=false\ndisabled_tools=["get_task_handoff"]\n[mcp_servers.other-server]\ncommand="other-mcp"';
1453
+ fs.writeFileSync(path.join(home, 'config.toml'), userConfig);
1454
+ vi.stubEnv('CODEX_HOME', home);
1455
+ const refresh = vi.spyOn(codexAskCapabilities, 'refreshCodexCliSupport').mockResolvedValue({ supported: true, executable: '/verified/codex' });
1456
+ const support = vi.spyOn(codexAskCapabilities, 'cachedCodexCliSupport').mockReturnValue({ supported: true, executable: '/verified/codex' });
1457
+ const executor = new CodexExecutor({
1458
+ executionPermission,
1459
+ settings: userConfig,
1460
+ cmd: { baseCommandOverride: '/verified/codex', env: { AGENT_TOWER_DESKTOP_NODE: '/profile/node' } },
1461
+ });
1462
+ const stdin = vi.spyOn(executor, 'spawnWithStdin').mockResolvedValue({});
1463
+ const duplex = vi.spyOn(executor, 'spawnWithDuplex').mockResolvedValue({});
1464
+ try {
1465
+ const config = {
1466
+ workingDir: tmpDir, prompt: 'task',
1467
+ env: ExecutionEnv.default(tmpDir).merge({
1468
+ AGENT_TOWER_URL: 'http://127.0.0.1:42001',
1469
+ AGENT_TOWER_AGENT_CREDENTIAL: 'bound-session-credential',
1470
+ AGENT_TOWER_SESSION_ID: 'current-session',
1471
+ }),
1472
+ };
1473
+ await executor.spawn(config);
1474
+ await executor.spawnFollowUp(config, 'native-thread');
1475
+ const spawn = executionPermission === 'FULL_ACCESS' ? stdin : duplex;
1476
+ expect(spawn).toHaveBeenCalledTimes(2);
1477
+ const serverNames = new Set(spawn.mock.calls.map(([, parts]) => parts.args.find(arg => /^mcp_servers\.agent-tower-[a-f0-9]{8}(?:-\d+)?=/.test(arg))?.split('=')[0]));
1478
+ expect(serverNames.size).toBe(1);
1479
+ for (const [, parts] of spawn.mock.calls) {
1480
+ const server = managedMcpServer(parts.args);
1481
+ expect(server.command).toBe('/profile/node');
1482
+ expect(server.enabled).toBe(true);
1483
+ expect(server.env.AGENT_TOWER_AGENT_CREDENTIAL).toBe('bound-session-credential');
1484
+ expect(server.env.AGENT_TOWER_SESSION_ID).toBe('current-session');
1485
+ expect(server).not.toHaveProperty('url');
1486
+ expect(server).not.toHaveProperty('disabled_tools');
1487
+ expect(parts.args).toContain('mcp_servers.other-server.command="other-mcp"');
1488
+ expect(parts.args.findIndex(arg => /^mcp_servers\.agent-tower-[a-f0-9]{8}(?:-\d+)?=/.test(arg)))
1489
+ .toBeGreaterThan(parts.args.indexOf('mcp_servers.agent-tower.enabled=false'));
1490
+ }
1491
+ expect(fs.readdirSync(home)).toEqual(['config.toml']);
1492
+ expect(fs.readFileSync(path.join(home, 'config.toml'), 'utf8')).toBe(userConfig);
1493
+ }
1494
+ finally {
1495
+ await waitForCodexMcpServerCacheRefresh();
1496
+ stdin.mockRestore();
1497
+ duplex.mockRestore();
1498
+ refresh.mockRestore();
1499
+ support.mockRestore();
1500
+ }
1501
+ });
1502
+ });
1110
1503
  //# sourceMappingURL=codex.executor.test.js.map