@0xmaxma/claude-gateway 2.0.6 → 2.0.7

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 (364) hide show
  1. package/README.md +14 -1
  2. package/dist/agent/builtin-commands.js +5 -5
  3. package/dist/agent/builtin-commands.js.map +1 -1
  4. package/dist/agent/command-help.d.ts +9 -0
  5. package/dist/agent/command-help.d.ts.map +1 -0
  6. package/dist/agent/command-help.js +50 -0
  7. package/dist/agent/command-help.js.map +1 -0
  8. package/dist/agent/dreaming/index.d.ts +6 -3
  9. package/dist/agent/dreaming/index.d.ts.map +1 -1
  10. package/dist/agent/dreaming/index.js +21 -1
  11. package/dist/agent/dreaming/index.js.map +1 -1
  12. package/dist/agent/knowledge/reflection.d.ts +7 -4
  13. package/dist/agent/knowledge/reflection.d.ts.map +1 -1
  14. package/dist/agent/knowledge/reflection.js +19 -1
  15. package/dist/agent/knowledge/reflection.js.map +1 -1
  16. package/dist/agent/runner.d.ts +37 -3
  17. package/dist/agent/runner.d.ts.map +1 -1
  18. package/dist/agent/runner.js +164 -47
  19. package/dist/agent/runner.js.map +1 -1
  20. package/dist/agent/session-confirmations.d.ts +12 -0
  21. package/dist/agent/session-confirmations.d.ts.map +1 -0
  22. package/dist/agent/session-confirmations.js +43 -0
  23. package/dist/agent/session-confirmations.js.map +1 -0
  24. package/dist/agent/session-status.d.ts +7 -0
  25. package/dist/agent/session-status.d.ts.map +1 -0
  26. package/dist/agent/session-status.js +16 -0
  27. package/dist/agent/session-status.js.map +1 -0
  28. package/dist/agent/skill-learning/index.d.ts +5 -1
  29. package/dist/agent/skill-learning/index.d.ts.map +1 -1
  30. package/dist/agent/skill-learning/index.js +23 -1
  31. package/dist/agent/skill-learning/index.js.map +1 -1
  32. package/dist/agent/skill-learning/notifier.d.ts +2 -1
  33. package/dist/agent/skill-learning/notifier.d.ts.map +1 -1
  34. package/dist/agent/skill-learning/notifier.js +1 -0
  35. package/dist/agent/skill-learning/notifier.js.map +1 -1
  36. package/dist/api/apps-router.d.ts.map +1 -1
  37. package/dist/api/apps-router.js +1 -3
  38. package/dist/api/apps-router.js.map +1 -1
  39. package/dist/api/cron-router.d.ts +1 -1
  40. package/dist/api/cron-router.d.ts.map +1 -1
  41. package/dist/api/cron-router.js +4 -4
  42. package/dist/api/cron-router.js.map +1 -1
  43. package/dist/api/dashboard-processes.d.ts +86 -0
  44. package/dist/api/dashboard-processes.d.ts.map +1 -0
  45. package/dist/api/dashboard-processes.js +155 -0
  46. package/dist/api/dashboard-processes.js.map +1 -0
  47. package/dist/api/dashboard-sessions.d.ts +15 -0
  48. package/dist/api/dashboard-sessions.d.ts.map +1 -0
  49. package/dist/api/dashboard-sessions.js +66 -0
  50. package/dist/api/dashboard-sessions.js.map +1 -0
  51. package/dist/api/gateway-router.d.ts +3 -4
  52. package/dist/api/gateway-router.d.ts.map +1 -1
  53. package/dist/api/gateway-router.js +77 -56
  54. package/dist/api/gateway-router.js.map +1 -1
  55. package/dist/api/oauth-connectors-router.d.ts +1 -1
  56. package/dist/api/oauth-connectors-router.d.ts.map +1 -1
  57. package/dist/api/oauth-connectors-router.js +11 -21
  58. package/dist/api/oauth-connectors-router.js.map +1 -1
  59. package/dist/api/router.d.ts +1 -1
  60. package/dist/api/router.d.ts.map +1 -1
  61. package/dist/api/router.js +3 -9
  62. package/dist/api/router.js.map +1 -1
  63. package/dist/api/share-router.d.ts +1 -1
  64. package/dist/api/share-router.d.ts.map +1 -1
  65. package/dist/api/share-router.js +1 -1
  66. package/dist/api/share-router.js.map +1 -1
  67. package/dist/api/slack-webhook-router.js +1 -1
  68. package/dist/api/slack-webhook-router.js.map +1 -1
  69. package/dist/api/voice-router.d.ts +1 -0
  70. package/dist/api/voice-router.d.ts.map +1 -1
  71. package/dist/api/voice-router.js +7 -0
  72. package/dist/api/voice-router.js.map +1 -1
  73. package/dist/apps/agent-container-migration.d.ts +2 -0
  74. package/dist/apps/agent-container-migration.d.ts.map +1 -1
  75. package/dist/apps/agent-container-migration.js +59 -2
  76. package/dist/apps/agent-container-migration.js.map +1 -1
  77. package/dist/apps/agent-manager.d.ts +4 -2
  78. package/dist/apps/agent-manager.d.ts.map +1 -1
  79. package/dist/apps/agent-manager.js +39 -3
  80. package/dist/apps/agent-manager.js.map +1 -1
  81. package/dist/apps/installer.d.ts +4 -3
  82. package/dist/apps/installer.d.ts.map +1 -1
  83. package/dist/apps/installer.js +8 -4
  84. package/dist/apps/installer.js.map +1 -1
  85. package/dist/build-provenance.json +8 -0
  86. package/dist/cli/args.js +1 -1
  87. package/dist/cli/args.js.map +1 -1
  88. package/dist/cli/commands/app.d.ts.map +1 -1
  89. package/dist/cli/commands/app.js +39 -3
  90. package/dist/cli/commands/app.js.map +1 -1
  91. package/dist/cli/commands/doctor.d.ts.map +1 -1
  92. package/dist/cli/commands/doctor.js +6 -2
  93. package/dist/cli/commands/doctor.js.map +1 -1
  94. package/dist/cli/commands/safemode.d.ts +2 -0
  95. package/dist/cli/commands/safemode.d.ts.map +1 -0
  96. package/dist/cli/commands/safemode.js +279 -0
  97. package/dist/cli/commands/safemode.js.map +1 -0
  98. package/dist/cli/dependencies.d.ts +2 -0
  99. package/dist/cli/dependencies.d.ts.map +1 -1
  100. package/dist/cli/dependencies.js +81 -0
  101. package/dist/cli/dependencies.js.map +1 -1
  102. package/dist/cli/index.d.ts.map +1 -1
  103. package/dist/cli/index.js +11 -1
  104. package/dist/cli/index.js.map +1 -1
  105. package/dist/cli/manager.d.ts.map +1 -1
  106. package/dist/cli/manager.js +4 -1
  107. package/dist/cli/manager.js.map +1 -1
  108. package/dist/config/agent-lifecycle.d.ts +26 -0
  109. package/dist/config/agent-lifecycle.d.ts.map +1 -0
  110. package/dist/config/agent-lifecycle.js +63 -0
  111. package/dist/config/agent-lifecycle.js.map +1 -0
  112. package/dist/config/loader.d.ts.map +1 -1
  113. package/dist/config/loader.js +11 -0
  114. package/dist/config/loader.js.map +1 -1
  115. package/dist/config/reload-policy.d.ts +9 -0
  116. package/dist/config/reload-policy.d.ts.map +1 -0
  117. package/dist/config/reload-policy.js +62 -0
  118. package/dist/config/reload-policy.js.map +1 -0
  119. package/dist/config/watcher.d.ts +3 -2
  120. package/dist/config/watcher.d.ts.map +1 -1
  121. package/dist/config/watcher.js +34 -51
  122. package/dist/config/watcher.js.map +1 -1
  123. package/dist/cron/tool-schemas.d.ts +296 -0
  124. package/dist/cron/tool-schemas.d.ts.map +1 -0
  125. package/dist/cron/tool-schemas.js +122 -0
  126. package/dist/cron/tool-schemas.js.map +1 -0
  127. package/dist/index.js +141 -158
  128. package/dist/index.js.map +1 -1
  129. package/dist/orchestration/agent-tool-schemas.js +4 -4
  130. package/dist/orchestration/agent-tool-schemas.js.map +1 -1
  131. package/dist/orchestration/background-work.d.ts +9 -0
  132. package/dist/orchestration/background-work.d.ts.map +1 -0
  133. package/dist/orchestration/background-work.js +49 -0
  134. package/dist/orchestration/background-work.js.map +1 -0
  135. package/dist/orchestration/bridge.d.ts +6 -15
  136. package/dist/orchestration/bridge.d.ts.map +1 -1
  137. package/dist/orchestration/bridge.js +67 -32
  138. package/dist/orchestration/bridge.js.map +1 -1
  139. package/dist/orchestration/capabilities.d.ts.map +1 -1
  140. package/dist/orchestration/capabilities.js +18 -10
  141. package/dist/orchestration/capabilities.js.map +1 -1
  142. package/dist/orchestration/capacity.d.ts +3 -2
  143. package/dist/orchestration/capacity.d.ts.map +1 -1
  144. package/dist/orchestration/capacity.js +7 -0
  145. package/dist/orchestration/capacity.js.map +1 -1
  146. package/dist/orchestration/channel-controls.d.ts.map +1 -1
  147. package/dist/orchestration/channel-controls.js +3 -2
  148. package/dist/orchestration/channel-controls.js.map +1 -1
  149. package/dist/orchestration/cli-skills.d.ts +5 -0
  150. package/dist/orchestration/cli-skills.d.ts.map +1 -1
  151. package/dist/orchestration/container-tool-schemas.d.ts +37 -0
  152. package/dist/orchestration/container-tool-schemas.d.ts.map +1 -0
  153. package/dist/orchestration/container-tool-schemas.js +27 -0
  154. package/dist/orchestration/container-tool-schemas.js.map +1 -0
  155. package/dist/orchestration/container.d.ts.map +1 -1
  156. package/dist/orchestration/container.js +7 -0
  157. package/dist/orchestration/container.js.map +1 -1
  158. package/dist/orchestration/dashboard-reader-worker.js +7 -7
  159. package/dist/orchestration/dashboard-reader-worker.js.map +1 -1
  160. package/dist/orchestration/decision-context.js +1 -1
  161. package/dist/orchestration/decision-context.js.map +1 -1
  162. package/dist/orchestration/gateway-tasks/controller.d.ts +29 -0
  163. package/dist/orchestration/gateway-tasks/controller.d.ts.map +1 -0
  164. package/dist/orchestration/gateway-tasks/controller.js +139 -0
  165. package/dist/orchestration/gateway-tasks/controller.js.map +1 -0
  166. package/dist/orchestration/gateway-tasks/safemode.d.ts +19 -0
  167. package/dist/orchestration/gateway-tasks/safemode.d.ts.map +1 -0
  168. package/dist/orchestration/gateway-tasks/safemode.js +128 -0
  169. package/dist/orchestration/gateway-tasks/safemode.js.map +1 -0
  170. package/dist/orchestration/process-turn.d.ts +11 -2
  171. package/dist/orchestration/process-turn.d.ts.map +1 -1
  172. package/dist/orchestration/process-turn.js +47 -7
  173. package/dist/orchestration/process-turn.js.map +1 -1
  174. package/dist/orchestration/recovery.d.ts.map +1 -1
  175. package/dist/orchestration/recovery.js +4 -2
  176. package/dist/orchestration/recovery.js.map +1 -1
  177. package/dist/orchestration/runtime.d.ts +10 -0
  178. package/dist/orchestration/runtime.d.ts.map +1 -1
  179. package/dist/orchestration/runtime.js +31 -4
  180. package/dist/orchestration/runtime.js.map +1 -1
  181. package/dist/orchestration/skills.d.ts +2 -0
  182. package/dist/orchestration/skills.d.ts.map +1 -1
  183. package/dist/orchestration/skills.js +4 -3
  184. package/dist/orchestration/skills.js.map +1 -1
  185. package/dist/orchestration/task-controls.d.ts +12 -0
  186. package/dist/orchestration/task-controls.d.ts.map +1 -1
  187. package/dist/orchestration/task-controls.js +3 -1
  188. package/dist/orchestration/task-controls.js.map +1 -1
  189. package/dist/orchestration/tasks/driver.d.ts.map +1 -1
  190. package/dist/orchestration/tasks/driver.js +99 -12
  191. package/dist/orchestration/tasks/driver.js.map +1 -1
  192. package/dist/orchestration/tasks/pool.d.ts +2 -0
  193. package/dist/orchestration/tasks/pool.d.ts.map +1 -1
  194. package/dist/orchestration/tasks/pool.js +4 -0
  195. package/dist/orchestration/tasks/pool.js.map +1 -1
  196. package/dist/orchestration/tasks/scheduler.d.ts.map +1 -1
  197. package/dist/orchestration/tasks/scheduler.js +4 -0
  198. package/dist/orchestration/tasks/scheduler.js.map +1 -1
  199. package/dist/orchestration/tasks/service.d.ts +4 -0
  200. package/dist/orchestration/tasks/service.d.ts.map +1 -1
  201. package/dist/orchestration/tasks/service.js +38 -8
  202. package/dist/orchestration/tasks/service.js.map +1 -1
  203. package/dist/orchestration/token-ledger.d.ts +1 -0
  204. package/dist/orchestration/token-ledger.d.ts.map +1 -1
  205. package/dist/orchestration/token-ledger.js +6 -2
  206. package/dist/orchestration/token-ledger.js.map +1 -1
  207. package/dist/orchestration/token-usage.d.ts +3 -0
  208. package/dist/orchestration/token-usage.d.ts.map +1 -1
  209. package/dist/orchestration/token-usage.js +12 -3
  210. package/dist/orchestration/token-usage.js.map +1 -1
  211. package/dist/orchestration/types.d.ts +19 -1
  212. package/dist/orchestration/types.d.ts.map +1 -1
  213. package/dist/orchestration/types.js.map +1 -1
  214. package/dist/orchestration/worker-crons.d.ts +5 -0
  215. package/dist/orchestration/worker-crons.d.ts.map +1 -0
  216. package/dist/orchestration/worker-crons.js +84 -0
  217. package/dist/orchestration/worker-crons.js.map +1 -0
  218. package/dist/orchestration/worker-harness.d.ts +15 -0
  219. package/dist/orchestration/worker-harness.d.ts.map +1 -0
  220. package/dist/orchestration/worker-harness.js +72 -0
  221. package/dist/orchestration/worker-harness.js.map +1 -0
  222. package/dist/safemode/config.d.ts +7 -0
  223. package/dist/safemode/config.d.ts.map +1 -0
  224. package/dist/safemode/config.js +67 -0
  225. package/dist/safemode/config.js.map +1 -0
  226. package/dist/safemode/context.d.ts +7 -0
  227. package/dist/safemode/context.d.ts.map +1 -0
  228. package/dist/safemode/context.js +397 -0
  229. package/dist/safemode/context.js.map +1 -0
  230. package/dist/safemode/external-owners.d.ts +19 -0
  231. package/dist/safemode/external-owners.d.ts.map +1 -0
  232. package/dist/safemode/external-owners.js +229 -0
  233. package/dist/safemode/external-owners.js.map +1 -0
  234. package/dist/safemode/native.d.ts +38 -0
  235. package/dist/safemode/native.d.ts.map +1 -0
  236. package/dist/safemode/native.js +220 -0
  237. package/dist/safemode/native.js.map +1 -0
  238. package/dist/safemode/params.d.ts +10 -0
  239. package/dist/safemode/params.d.ts.map +1 -0
  240. package/dist/safemode/params.js +86 -0
  241. package/dist/safemode/params.js.map +1 -0
  242. package/dist/safemode/provenance.d.ts +45 -0
  243. package/dist/safemode/provenance.d.ts.map +1 -0
  244. package/dist/safemode/provenance.js +153 -0
  245. package/dist/safemode/provenance.js.map +1 -0
  246. package/dist/safemode/runner.d.ts +17 -0
  247. package/dist/safemode/runner.d.ts.map +1 -0
  248. package/dist/safemode/runner.js +398 -0
  249. package/dist/safemode/runner.js.map +1 -0
  250. package/dist/safemode/store.d.ts +56 -0
  251. package/dist/safemode/store.d.ts.map +1 -0
  252. package/dist/safemode/store.js +451 -0
  253. package/dist/safemode/store.js.map +1 -0
  254. package/dist/session/codex-auth.d.ts +37 -0
  255. package/dist/session/codex-auth.d.ts.map +1 -0
  256. package/dist/session/codex-auth.js +266 -0
  257. package/dist/session/codex-auth.js.map +1 -0
  258. package/dist/session/codex-container-runtime.d.ts +15 -0
  259. package/dist/session/codex-container-runtime.d.ts.map +1 -0
  260. package/dist/session/codex-container-runtime.js +85 -0
  261. package/dist/session/codex-container-runtime.js.map +1 -0
  262. package/dist/session/codex-context-defaults.json +5 -0
  263. package/dist/session/codex-context.d.ts +13 -0
  264. package/dist/session/codex-context.d.ts.map +1 -0
  265. package/dist/session/codex-context.js +27 -0
  266. package/dist/session/codex-context.js.map +1 -0
  267. package/dist/session/codex-extension-discovery.d.ts +21 -0
  268. package/dist/session/codex-extension-discovery.d.ts.map +1 -0
  269. package/dist/session/codex-extension-discovery.js +132 -0
  270. package/dist/session/codex-extension-discovery.js.map +1 -0
  271. package/dist/session/codex-native-mcp-client.d.ts +37 -0
  272. package/dist/session/codex-native-mcp-client.d.ts.map +1 -0
  273. package/dist/session/codex-native-mcp-client.js +164 -0
  274. package/dist/session/codex-native-mcp-client.js.map +1 -0
  275. package/dist/session/codex-policy.d.ts +6 -0
  276. package/dist/session/codex-policy.d.ts.map +1 -0
  277. package/dist/session/codex-policy.js +17 -0
  278. package/dist/session/codex-policy.js.map +1 -0
  279. package/dist/session/codex-process.d.ts +114 -0
  280. package/dist/session/codex-process.d.ts.map +1 -0
  281. package/dist/session/codex-process.js +759 -0
  282. package/dist/session/codex-process.js.map +1 -0
  283. package/dist/session/codex-runtime.d.ts +20 -0
  284. package/dist/session/codex-runtime.d.ts.map +1 -0
  285. package/dist/session/codex-runtime.js +182 -0
  286. package/dist/session/codex-runtime.js.map +1 -0
  287. package/dist/session/codex-tool-capture.d.ts +35 -0
  288. package/dist/session/codex-tool-capture.d.ts.map +1 -0
  289. package/dist/session/codex-tool-capture.js +178 -0
  290. package/dist/session/codex-tool-capture.js.map +1 -0
  291. package/dist/session/container-connectors.d.ts +10 -0
  292. package/dist/session/container-connectors.d.ts.map +1 -0
  293. package/dist/session/container-connectors.js +41 -0
  294. package/dist/session/container-connectors.js.map +1 -0
  295. package/dist/session/container-extensions.d.ts +4 -0
  296. package/dist/session/container-extensions.d.ts.map +1 -0
  297. package/dist/session/container-extensions.js +45 -0
  298. package/dist/session/container-extensions.js.map +1 -0
  299. package/dist/session/managed-connectors.d.ts +16 -0
  300. package/dist/session/managed-connectors.d.ts.map +1 -0
  301. package/dist/session/managed-connectors.js +25 -0
  302. package/dist/session/managed-connectors.js.map +1 -0
  303. package/dist/session/process-diagnostics.d.ts +14 -0
  304. package/dist/session/process-diagnostics.d.ts.map +1 -0
  305. package/dist/session/process-diagnostics.js +39 -0
  306. package/dist/session/process-diagnostics.js.map +1 -0
  307. package/dist/session/process.d.ts +4 -0
  308. package/dist/session/process.d.ts.map +1 -1
  309. package/dist/session/process.js +21 -16
  310. package/dist/session/process.js.map +1 -1
  311. package/dist/session/request-tool-capture.d.ts +1 -1
  312. package/dist/session/request-tool-capture.d.ts.map +1 -1
  313. package/dist/session/runtime-profile.d.ts +8 -0
  314. package/dist/session/runtime-profile.d.ts.map +1 -1
  315. package/dist/session/runtime-profile.js +3 -2
  316. package/dist/session/runtime-profile.js.map +1 -1
  317. package/dist/session/worker-environment.d.ts +5 -0
  318. package/dist/session/worker-environment.d.ts.map +1 -0
  319. package/dist/session/worker-environment.js +27 -0
  320. package/dist/session/worker-environment.js.map +1 -0
  321. package/dist/session/worker-extensions.d.ts +20 -0
  322. package/dist/session/worker-extensions.d.ts.map +1 -0
  323. package/dist/session/worker-extensions.js +322 -0
  324. package/dist/session/worker-extensions.js.map +1 -0
  325. package/dist/skills/loader.d.ts +2 -0
  326. package/dist/skills/loader.d.ts.map +1 -1
  327. package/dist/skills/loader.js.map +1 -1
  328. package/dist/types.d.ts +30 -0
  329. package/dist/types.d.ts.map +1 -1
  330. package/dist/ui/codex-context.d.ts +4 -0
  331. package/dist/ui/codex-context.d.ts.map +1 -0
  332. package/dist/ui/codex-context.js +15 -0
  333. package/dist/ui/codex-context.js.map +1 -0
  334. package/dist/ui/dashboard-client.d.ts.map +1 -1
  335. package/dist/ui/dashboard-client.js +14 -11
  336. package/dist/ui/dashboard-client.js.map +1 -1
  337. package/dist/ui/dashboard-presentation.d.ts +1 -1
  338. package/dist/ui/dashboard-presentation.d.ts.map +1 -1
  339. package/dist/ui/dashboard-presentation.js +2 -2
  340. package/dist/ui/dashboard-presentation.js.map +1 -1
  341. package/dist/ui/token-report.d.ts +3 -0
  342. package/dist/ui/token-report.d.ts.map +1 -1
  343. package/dist/ui/token-report.js +22 -10
  344. package/dist/ui/token-report.js.map +1 -1
  345. package/dist/ui/web-ui.d.ts.map +1 -1
  346. package/dist/ui/web-ui.js +53 -132
  347. package/dist/ui/web-ui.js.map +1 -1
  348. package/mcp/capability-catalog.ts +2 -0
  349. package/mcp/extension-catalog.ts +18 -0
  350. package/mcp/lazy-connector.ts +4 -2
  351. package/mcp/lazy-tools.test.ts +29 -0
  352. package/mcp/modules.ts +1 -0
  353. package/mcp/server.ts +2 -2
  354. package/mcp/tools/cron/module.ts +8 -114
  355. package/mcp/tools/discord/commands.ts +4 -1
  356. package/mcp/tools/safemode/module.test.ts +29 -0
  357. package/mcp/tools/telegram/receiver-server.ts +2 -22
  358. package/mcp/tools/telegram/task-detail.ts +2 -1
  359. package/package.json +3 -2
  360. package/scripts/orchestration/audit-codex-context.cjs +83 -0
  361. package/scripts/orchestration/benchmark-worker-harnesses.cjs +112 -0
  362. package/scripts/orchestration/smoke-codex-extensions.ts +29 -0
  363. package/scripts/orchestration/smoke-codex-worker.cjs +166 -0
  364. package/scripts/orchestration/smoke-safemode-codex.cjs +66 -0
@@ -0,0 +1,759 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CodexProcess = void 0;
4
+ exports.cleanupCodexSessions = cleanupCodexSessions;
5
+ const codex_context_1 = require("./codex-context");
6
+ const worker_environment_1 = require("./worker-environment");
7
+ const codex_tool_capture_1 = require("./codex-tool-capture");
8
+ const codex_auth_1 = require("./codex-auth");
9
+ const codex_policy_1 = require("./codex-policy");
10
+ const codex_runtime_1 = require("./codex-runtime");
11
+ const codex_container_runtime_1 = require("./codex-container-runtime");
12
+ const managed_connectors_1 = require("./managed-connectors");
13
+ const worker_extensions_1 = require("./worker-extensions");
14
+ const container_connectors_1 = require("./container-connectors");
15
+ const events_1 = require("events");
16
+ const child_process_1 = require("child_process");
17
+ const crypto_1 = require("crypto");
18
+ const promises_1 = require("fs/promises");
19
+ const path_1 = require("path");
20
+ const os_1 = require("os");
21
+ const container_1 = require("../orchestration/container");
22
+ const process_supervisor_1 = require("../orchestration/process-supervisor");
23
+ const quote = (value) => JSON.stringify(value);
24
+ const MAX_LINE = 4 * 1024 * 1024;
25
+ const threadPattern = /^[a-f0-9-]{36}$/i;
26
+ function sessionRoot(stateDirectory, workspace, sessionId) {
27
+ return (0, path_1.join)(stateDirectory, 'codex', (0, crypto_1.createHash)('sha256').update(workspace + '\0' + sessionId).digest('hex'));
28
+ }
29
+ function ownedHome(root, home, container) {
30
+ if (typeof home !== 'string')
31
+ return false;
32
+ const prefix = container ? (0, os_1.homedir)() + '/.gateway-codex-' : root + '/attempt-';
33
+ return home.startsWith(prefix) && threadPattern.test(home.slice(prefix.length));
34
+ }
35
+ const cleanupRuns = new Map();
36
+ const cleanupCursors = new Map();
37
+ /** Lazy bounded reclamation after the worker pool has expired or replaced logical slots.
38
+ * A durable lease also fences uncertain processes after a gateway crash. Such leases
39
+ * are intentionally retained until process reconciliation can prove they stopped. */
40
+ function cleanupCodexSessions(options) {
41
+ const directory = (0, path_1.join)(options.stateDirectory, 'codex');
42
+ const running = cleanupRuns.get(directory);
43
+ if (running)
44
+ return running;
45
+ const run = (async () => {
46
+ let names;
47
+ try {
48
+ names = (await (0, promises_1.readdir)(directory, { withFileTypes: true })).filter(entry => entry.isDirectory() && /^[a-f0-9]{64}$/.test(entry.name)).map(entry => entry.name).sort();
49
+ }
50
+ catch (error) {
51
+ if (error.code === 'ENOENT')
52
+ return 0;
53
+ throw error;
54
+ }
55
+ const previous = cleanupCursors.get(directory) ?? '';
56
+ const start = Math.max(0, names.findIndex(name => name > previous));
57
+ const batch = [...names.slice(start), ...names.slice(0, start)].slice(0, Math.max(1, Math.min(options.limit ?? 32, 128)));
58
+ const retained = new Set(options.retainedSessionIds);
59
+ let removed = 0;
60
+ for (const name of batch) {
61
+ cleanupCursors.set(directory, name);
62
+ const root = (0, path_1.join)(directory, name), lease = (0, path_1.join)(root, '.active');
63
+ let locked = false;
64
+ try {
65
+ const file = (0, path_1.join)(root, 'homes.json');
66
+ if (!(await (0, promises_1.lstat)(file)).isFile())
67
+ continue;
68
+ const homes = JSON.parse(await (0, promises_1.readFile)(file, 'utf8'));
69
+ if (typeof homes.sessionId !== 'string' || typeof homes.workspace !== 'string' || homes.container !== options.agent.container || root !== sessionRoot(options.stateDirectory, homes.workspace, homes.sessionId) || retained.has(homes.sessionId) || !Array.isArray(homes.homes) || !homes.homes.every(home => ownedHome(root, home, homes.container)))
70
+ continue;
71
+ await (0, promises_1.mkdir)(lease, { mode: 0o700 });
72
+ locked = true;
73
+ // Host deletion cannot establish containment inside an app-agent namespace.
74
+ if (homes.container) {
75
+ for (const home of homes.homes)
76
+ await (0, container_1.containerNode)(homes.container, "require('fs').rmSync(process.argv[1],{recursive:true,force:true})", [home]);
77
+ }
78
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
79
+ locked = false;
80
+ removed++;
81
+ }
82
+ catch (error) {
83
+ // Missing metadata, existing leases, malformed bindings and offline containers
84
+ // are preserved. Cleanup must not turn a new task into a failure.
85
+ }
86
+ finally {
87
+ if (locked)
88
+ await (0, promises_1.rm)(lease, { recursive: true, force: true }).catch(() => { });
89
+ }
90
+ }
91
+ return removed;
92
+ })().finally(() => { cleanupRuns.delete(directory); });
93
+ cleanupRuns.set(directory, run);
94
+ return run;
95
+ }
96
+ /** A bounded native Codex app-server session. Only native Codex provider/auth is selected; user executable configuration is not inherited. */
97
+ class CodexProcess extends events_1.EventEmitter {
98
+ get managedProcessId() { return this.group; }
99
+ constructor(options) {
100
+ super();
101
+ this.options = options;
102
+ this.spawnedAt = Date.now();
103
+ this.managedGroupStopped = false;
104
+ this.executable = '';
105
+ this.cancelled = false;
106
+ this.terminal = false;
107
+ this.exited = false;
108
+ this.home = '';
109
+ this.buffer = '';
110
+ this.stderr = '';
111
+ this.traceState = { files: {}, pending: [], calls: {} };
112
+ this.traceSchemas = new Map();
113
+ this.lastError = '';
114
+ this.finalText = '';
115
+ this.tools = new Set();
116
+ this.completedTools = new Set();
117
+ this.sequence = 0;
118
+ this.requests = new Map();
119
+ this.turnEnded = false;
120
+ this.identity = '';
121
+ this.refreshingAuth = false;
122
+ this.homePersisted = false;
123
+ this.leaseOwned = false;
124
+ this.connectorPaths = new Set();
125
+ this.approvedMcp = {};
126
+ this.runtimeProfile = options.profile;
127
+ this.root = sessionRoot(options.stateDirectory, options.agent.workspace, options.sessionId);
128
+ this.mapping = (0, path_1.join)(this.root, 'thread.json');
129
+ }
130
+ start() {
131
+ return this.preparing ?? (this.preparing = this.prepare().catch(async (error) => {
132
+ // Preparation cannot spawn a worker; reclaim its partial home even when a
133
+ // caller never reaches the normal stop lifecycle. Preserve the original error.
134
+ await this.cleanupHomes().catch(() => { });
135
+ throw error;
136
+ }));
137
+ }
138
+ async prepare() {
139
+ const { agent, profile, config } = this.options;
140
+ if (this.cancelled)
141
+ throw new Error('Codex process cancelled before startup');
142
+ if (profile.role !== 'worker')
143
+ throw new Error('Codex harness supports workers only');
144
+ (0, container_1.assertContainerBinding)(agent, profile);
145
+ if (agent.type === 'app-agent' && profile.hostExecution)
146
+ throw new Error('Container roles cannot use host execution');
147
+ if (profile.workerTools && (!profile.workerTools.includes('Bash') || !profile.workerTools.includes('Edit')))
148
+ throw new Error('Codex cannot enforce this restricted native tool profile');
149
+ const runtime = (0, codex_runtime_1.resolveCodexRuntime)(config.bin, agent.workspace);
150
+ this.executable = agent.type === 'app-agent' ? runtime.containerExecutable : runtime.executable;
151
+ if (agent.type === 'app-agent') {
152
+ this.containerId = await (0, codex_container_runtime_1.inspectSelectedCodexRuntime)(agent, runtime);
153
+ this.nativeSha256 = runtime.nativeSha256;
154
+ }
155
+ this.authExecutable = runtime.executable;
156
+ this.credentials = await (0, codex_auth_1.resolveCodexCredentials)({ ...config, bin: runtime.executable, allowDockerHost: agent.type === 'app-agent' });
157
+ const key = 'GATEWAY_CODEX_API_KEY';
158
+ this.identity = this.credentials.fingerprint;
159
+ await (0, promises_1.mkdir)(this.root, { recursive: true, mode: 0o700 });
160
+ await (0, promises_1.mkdir)((0, path_1.join)(this.root, '.active'), { mode: 0o700 });
161
+ this.leaseOwned = true;
162
+ try {
163
+ this.saved = JSON.parse(await (0, promises_1.readFile)(this.mapping, 'utf8'));
164
+ }
165
+ catch (error) {
166
+ if (error.code !== 'ENOENT')
167
+ throw error;
168
+ }
169
+ if (this.saved && (!threadPattern.test(this.saved.threadId) || this.saved.identity !== this.identity || this.saved.container !== agent.container ||
170
+ !ownedHome(this.root, this.saved.home, agent.container)))
171
+ throw new Error('Invalid persisted Codex thread binding');
172
+ await this.recordHomes();
173
+ let mcp;
174
+ let extensionInstructions = '';
175
+ if (agent.type === 'app-agent') {
176
+ this.containerAttempt = await (0, container_1.prepareContainerProfile)(agent, profile);
177
+ const mountedHash = await (0, container_1.containerNode)(agent.container, "const fs=require('fs'),crypto=require('crypto');process.stdout.write(crypto.createHash('sha256').update(fs.readFileSync(process.argv[1])).digest('hex'));", [this.executable]);
178
+ if (!this.nativeSha256 || mountedHash.trim() !== this.nativeSha256)
179
+ throw new Error(`CODEX_CONTAINER_RUNTIME_STALE: the mounted executable differs from the host. ${codex_container_runtime_1.CODEX_RUNTIME_MAINTENANCE}`);
180
+ if (this.saved) {
181
+ // Native homes live in the container writable layer. A recreated container
182
+ // cannot resume them even though its name and the host pool slot survive.
183
+ // Legacy records have no Docker ID: retain them only if their transcript exists.
184
+ const sameContainer = !this.saved.containerId || this.saved.containerId === this.containerId;
185
+ const transcriptExists = sameContainer && await (0, container_1.containerNode)(agent.container, "const fs=require('fs');try{process.stdout.write(fs.statSync(process.argv[1]+'/sessions').isDirectory()?'yes':'no');}catch(e){if(e.code!=='ENOENT')throw e;process.stdout.write('no');}", [this.saved.home]) === 'yes';
186
+ if (!transcriptExists) {
187
+ this.saved = undefined;
188
+ this.output({ type: 'system', subtype: 'native_session_reset', reason: 'container_session_unavailable' });
189
+ }
190
+ }
191
+ // Existing app-agent images create the installer's home but may have no passwd entry for its numeric UID.
192
+ const containerHome = (0, os_1.homedir)();
193
+ if (!/^\/(?:home\/[^/]+|root)$/.test(containerHome))
194
+ throw new Error('Container requires a writable non-temporary home for Codex');
195
+ this.home = containerHome + '/.gateway-codex-' + (0, crypto_1.randomUUID)();
196
+ await this.recordHomes();
197
+ mcp = JSON.parse(await (0, container_1.containerNode)(agent.container, "process.stdout.write(require('fs').readFileSync(process.argv[1],'utf8'))", [this.containerAttempt.config]));
198
+ if (profile.connectorsAllowed !== false) {
199
+ const extensions = await (0, worker_extensions_1.discoverWorkerExtensions)(agent, this.options.gateway);
200
+ mcp.mcpServers = { ...await (0, container_connectors_1.prepareContainerConnectors)(agent, this.containerAttempt.directory, extensions.servers), ...mcp.mcpServers };
201
+ extensionInstructions = [
202
+ 'Installed container extension skills: read the selected file and follow relative resources. Nested slash skill names mean read that skill, not invoke a host CLI. All commands and MCP servers execute inside this container. Use task_request_input for user questions.',
203
+ ...extensions.skills.map(skill => JSON.stringify({ name: skill.name, aliases: skill.aliases, description: skill.description, path: skill.filePath, pluginRoot: skill.resourceRoot })),
204
+ ...extensions.notices,
205
+ ].join('\n');
206
+ }
207
+ }
208
+ else {
209
+ this.home = (0, path_1.join)(this.root, 'attempt-' + (0, crypto_1.randomUUID)());
210
+ await this.recordHomes();
211
+ await (0, promises_1.mkdir)(this.home, { mode: 0o700 });
212
+ mcp = JSON.parse(await (0, promises_1.readFile)(profile.mcpConfigPath, 'utf8'));
213
+ const extensions = profile.hostExecution && profile.connectorsAllowed !== false ? await (0, worker_extensions_1.discoverWorkerExtensions)(agent, this.options.gateway) : { skills: [], servers: {}, notices: [] };
214
+ extensionInstructions = extensions.skills.length || extensions.notices.length ? [
215
+ 'Installed extension skills: read the selected SKILL.md, then follow its instructions and relative references. A slash skill invocation means read and execute that workflow; do not try to call Claude Code or its Skill tool. For nested skill invocations, resolve the name in this catalog and read that file. Plugin-relative paths resolve from the listed plugin root. Use native shell/file tools for equivalent operations; use task_request_input for questions requiring the user. A skill never grants extra permissions.',
216
+ ...extensions.skills.map(skill => JSON.stringify({ name: skill.name, aliases: skill.aliases, description: skill.description, path: skill.filePath, pluginRoot: skill.resourceRoot, source: skill.source })),
217
+ ...extensions.notices,
218
+ ].join('\n') : '';
219
+ const { servers } = (0, managed_connectors_1.prepareManagedConnectors)(agent, this.options.gateway, profile, this.connectorPaths, extensions.servers);
220
+ mcp.mcpServers = { ...servers, ...mcp.mcpServers };
221
+ }
222
+ this.approvedMcp = mcp.mcpServers ?? {};
223
+ this.contextMeasurement = (0, codex_context_1.codexContextPolicy)(config.model, config.contextWindow);
224
+ const commandEnvironment = (0, worker_environment_1.workerEnvironment)(agent, this.options.gateway);
225
+ const lines = [
226
+ `model = ${quote(config.model)}`, `model_provider = ${quote(this.credentials.chatgpt ? 'openai' : 'gateway')}`, 'approval_policy = "never"',
227
+ `sandbox_mode = ${quote(profile.hostExecution || agent.type === 'app-agent' ? 'danger-full-access' : 'workspace-write')}`,
228
+ 'web_search = "disabled"', 'project_doc_fallback_filenames = ["CLAUDE.md"]',
229
+ ...(this.contextMeasurement.configured !== null ? [`model_context_window = ${this.contextMeasurement.configured}`] : []),
230
+ `developer_instructions = ${quote([profile.context, profile.overlay, extensionInstructions, profile.skillPluginDir || profile.containerSkill ? `Task skill resources: ${this.containerAttempt ? this.containerAttempt.directory + '/skill-plugin' : profile.skillPluginDir}. Read the assigned SKILL.md (or RESOURCE_ROOT.txt) and resolve its plugin-relative references from its resource root.` : undefined].filter(Boolean).join('\n\n'))}`,
231
+ ...(config.reasoningEffort ? [`model_reasoning_effort = ${quote(config.reasoningEffort)}`] : []),
232
+ ...(this.credentials.chatgpt ? ['cli_auth_credentials_store = "ephemeral"'] : ['[model_providers.gateway]', 'name = "Gateway Responses"', 'wire_api = "responses"', `base_url = ${quote(this.credentials.baseUrl)}`, `env_key = ${quote(key)}`]),
233
+ '[features]', 'multi_agent = false',
234
+ `[projects.${quote(agent.type === 'app-agent' ? '/workspace' : agent.workspace)}]`, 'trust_level = "untrusted"',
235
+ ];
236
+ if (Object.keys(commandEnvironment).length) {
237
+ lines.push('[shell_environment_policy.set]', ...Object.entries(commandEnvironment).map(([name, value]) => quote(name) + ' = ' + quote(value)));
238
+ }
239
+ for (const [name, server] of Object.entries(mcp.mcpServers ?? {})) {
240
+ lines.push(`[mcp_servers.${quote(name)}]`, `required = ${name === 'gateway'}`);
241
+ if (typeof server.command === 'string') {
242
+ if (!Array.isArray(server.args) || server.args.some((v) => typeof v !== 'string'))
243
+ throw new Error('Codex MCP requires string arguments');
244
+ lines.push(`command = ${quote(server.command)}`, `args = ${JSON.stringify(server.args)}`);
245
+ if (server.cwd)
246
+ lines.push(`cwd = ${quote(server.cwd)}`);
247
+ }
248
+ else if (typeof server.url === 'string' && server.type !== 'sse') {
249
+ lines.push(`url = ${quote(server.url)}`);
250
+ }
251
+ else
252
+ throw new Error('CODEX_MCP_TRANSPORT_UNAVAILABLE: this container MCP transport requires a compatible local adapter.');
253
+ for (const field of ['enabled_tools', 'disabled_tools'])
254
+ if (Array.isArray(server[field]))
255
+ lines.push(`${field} = ${JSON.stringify(server[field])}`);
256
+ if (server.headers) {
257
+ lines.push(`[mcp_servers.${quote(name)}.http_headers]`);
258
+ for (const [key, value] of Object.entries(server.headers)) {
259
+ if (typeof value !== 'string')
260
+ throw new Error('Invalid MCP header');
261
+ lines.push(`${quote(key)} = ${quote(value)}`);
262
+ }
263
+ }
264
+ if (server.env) {
265
+ lines.push(`[mcp_servers.${quote(name)}.env]`);
266
+ for (const [k, v] of Object.entries(server.env)) {
267
+ if (typeof v !== 'string')
268
+ throw new Error('Invalid MCP environment');
269
+ lines.push(`${quote(k)} = ${quote(v)}`);
270
+ }
271
+ }
272
+ }
273
+ const configText = lines.join('\n') + '\n';
274
+ if (agent.type === 'app-agent') {
275
+ await (0, container_1.containerNode)(agent.container, `const fs=require('fs'),path=require('path');let s='';process.stdin.on('data',b=>s+=b);process.stdin.on('end',()=>{const p=JSON.parse(s);fs.mkdirSync(p.home,{mode:448});if(p.previous)fs.cpSync(p.previous+'/sessions',p.home+'/sessions',{recursive:true});fs.writeFileSync(p.home+'/config.toml',p.config,{mode:384});});`, [], JSON.stringify({ home: this.home, previous: this.saved?.home, config: configText }));
276
+ }
277
+ else {
278
+ if (this.saved)
279
+ await (0, promises_1.cp)((0, path_1.join)(this.saved.home, 'sessions'), (0, path_1.join)(this.home, 'sessions'), { recursive: true });
280
+ await (0, promises_1.writeFile)((0, path_1.join)(this.home, 'config.toml'), configText, { mode: 0o600 });
281
+ }
282
+ if (this.cancelled)
283
+ throw new Error('Codex process cancelled during startup');
284
+ }
285
+ async recordHomes() {
286
+ const agent = this.options.agent;
287
+ await (0, promises_1.writeFile)((0, path_1.join)(this.root, 'homes.json'), JSON.stringify({ sessionId: this.options.sessionId, workspace: agent.workspace, container: agent.container, homes: [this.saved?.home, this.home].filter(Boolean) }), { mode: 0o600 });
288
+ }
289
+ sendMessage(prompt, images = []) {
290
+ if (this.launching)
291
+ throw new Error('Codex process accepts one turn');
292
+ this.launching = this.launch(prompt, images).catch(error => { this.emit('startup-error', error); });
293
+ }
294
+ async launch(prompt, images) {
295
+ await this.start();
296
+ const { agent, config, profile } = this.options;
297
+ const input = [{ type: 'text', text: prompt, text_elements: [] }];
298
+ for (const [index, image] of images.entries()) {
299
+ const filename = this.home + `/input-${index}.${image.source.media_type.split('/')[1]}`;
300
+ if (agent.type === 'app-agent')
301
+ await (0, container_1.containerNode)(agent.container, "require('fs').writeFileSync(process.argv[1],Buffer.from(process.argv[2],'base64'),{mode:384})", [filename, image.source.data]);
302
+ else
303
+ await (0, promises_1.writeFile)(filename, Buffer.from(image.source.data, 'base64'), { mode: 0o600 });
304
+ input.push({ type: 'localImage', path: filename });
305
+ }
306
+ if (this.cancelled)
307
+ return;
308
+ const args = [...(0, codex_policy_1.codexPolicyArgs)(), 'app-server', '--listen', 'stdio://'];
309
+ const key = 'GATEWAY_CODEX_API_KEY';
310
+ const env = profile.hostExecution ? { ...process.env } : Object.fromEntries(['PATH', 'HOME', 'LANG', 'TMPDIR', 'SSL_CERT_FILE', 'SSL_CERT_DIR'].flatMap(k => process.env[k] === undefined ? [] : [[k, process.env[k]]]));
311
+ for (const k of Object.keys(env))
312
+ if (/^(ANTHROPIC_|CLAUDE_|CODEX_|OPENAI_)/.test(k))
313
+ delete env[k];
314
+ Object.assign(env, (0, worker_environment_1.workerEnvironment)(agent, this.options.gateway));
315
+ env.CODEX_HOME = this.home;
316
+ env.CODEX_ROLLOUT_TRACE_ROOT = this.home + '/gateway-trace';
317
+ if (agent.type === 'app-agent')
318
+ await (0, container_1.containerNode)(agent.container, "require('fs').mkdirSync(process.argv[1],{recursive:true,mode:448})", [env.CODEX_ROLLOUT_TRACE_ROOT]);
319
+ else
320
+ await (0, promises_1.mkdir)(env.CODEX_ROLLOUT_TRACE_ROOT, { recursive: true, mode: 0o700 });
321
+ if (this.credentials.chatgpt)
322
+ delete env[key];
323
+ else
324
+ env[key] = this.credentials.key;
325
+ const bin = this.executable;
326
+ const child = this.child = agent.type === 'app-agent'
327
+ ? (0, child_process_1.spawn)('docker', ['exec', '-i', '--workdir', '/workspace', '--user', String((0, os_1.userInfo)().uid), '-e', 'CODEX_HOME', '-e', 'CODEX_ROLLOUT_TRACE_ROOT', '-e', `HOME=${(0, os_1.homedir)()}`, '-e', key, ...Object.keys((0, worker_environment_1.workerEnvironment)(agent, this.options.gateway)).flatMap(name => ['-e', name]), agent.container, 'node', '-e', container_1.CONTAINER_SUPERVISOR, this.containerAttempt.directory, bin, ...args], { env, stdio: 'pipe', detached: true })
328
+ : (0, child_process_1.spawn)(bin, args, { cwd: agent.workspace, env, stdio: 'pipe', detached: true });
329
+ this.group = child.pid;
330
+ this.traceTimer = setInterval(() => { void this.captureTrace(); }, agent.type === 'app-agent' ? 2000 : 500);
331
+ this.traceTimer.unref();
332
+ child.stdout.setEncoding('utf8');
333
+ child.stderr.setEncoding('utf8');
334
+ child.stdout.on('data', (chunk) => this.consume(chunk));
335
+ child.stderr.on('data', (chunk) => { this.stderr = (this.stderr + chunk).slice(-16384); });
336
+ child.stdin.on('error', error => { if (!this.cancelled && !this.terminal)
337
+ this.fail(error.message); });
338
+ child.on('error', error => { this.rejectRequests(error); this.emit('startup-error', error); });
339
+ child.on('close', async (code, signal) => {
340
+ this.exited = true;
341
+ this.rejectRequests(new Error(this.stderr.trim() || 'Codex app-server exited'));
342
+ if (this.buffer.trim())
343
+ this.consume('\n');
344
+ await this.completion;
345
+ if (!this.terminal && !this.cancelled)
346
+ this.fail(this.lastError || this.stderr.trim() || `Codex exited without a completed turn (${code ?? signal})`);
347
+ this.emit('exit', code, signal);
348
+ });
349
+ await this.request('initialize', { clientInfo: { name: 'claude_gateway', version: '1.0.0' }, capabilities: { experimentalApi: true } });
350
+ this.write({ method: 'initialized', params: {} });
351
+ await this.validateConfiguration();
352
+ if (this.credentials.chatgpt) {
353
+ try {
354
+ await this.request('account/login/start', { type: 'chatgptAuthTokens', ...this.credentials.chatgpt });
355
+ }
356
+ catch {
357
+ throw new Error('CODEX_AUTH_REQUIRED: Codex rejected the native ChatGPT access credential. Check codex login status or update Codex.');
358
+ }
359
+ }
360
+ const parameters = { model: config.model, modelProvider: this.credentials.chatgpt ? 'openai' : 'gateway', cwd: agent.type === 'app-agent' ? '/workspace' : agent.workspace, approvalPolicy: 'never', sandbox: profile.hostExecution || agent.type === 'app-agent' ? 'danger-full-access' : 'workspace-write' };
361
+ const response = await this.request(this.saved ? 'thread/resume' : 'thread/start', { ...parameters, ...(this.saved ? { threadId: this.saved.threadId } : {}) });
362
+ if (!threadPattern.test(response.thread?.id) || (this.saved && response.thread.id !== this.saved.threadId))
363
+ throw new Error('Codex thread identity mismatch');
364
+ this.threadId = response.thread.id;
365
+ await this.persist();
366
+ this.output({ type: 'system', subtype: 'native_init', model: config.model, contextWindow: this.contextMeasurement });
367
+ await this.beginTurn(input);
368
+ }
369
+ output(event) { this.emit('output', JSON.stringify(event)); }
370
+ fail(message) { if (this.terminal)
371
+ return; this.terminal = true; this.output({ type: 'result', is_error: true, result: message }); }
372
+ consume(chunk) {
373
+ this.buffer += chunk;
374
+ if (Buffer.byteLength(this.buffer) > MAX_LINE) {
375
+ this.fail('Codex output exceeded the bounded JSON buffer');
376
+ void this.stop();
377
+ return;
378
+ }
379
+ let newline;
380
+ while ((newline = this.buffer.indexOf('\n')) >= 0) {
381
+ const line = this.buffer.slice(0, newline);
382
+ this.buffer = this.buffer.slice(newline + 1);
383
+ if (!line.trim())
384
+ continue;
385
+ try {
386
+ this.event(JSON.parse(line));
387
+ }
388
+ catch (error) {
389
+ this.fail(`Invalid Codex event: ${error.message}`);
390
+ void this.stop();
391
+ return;
392
+ }
393
+ }
394
+ }
395
+ async validateConfiguration() {
396
+ const reply = await this.request('config/read', { cwd: this.options.agent.type === 'app-agent' ? '/workspace' : this.options.agent.workspace, includeLayers: true });
397
+ const effective = reply.config;
398
+ if (!effective || !Array.isArray(reply.layers))
399
+ throw new Error('Codex did not provide effective configuration');
400
+ if (reply.layers.some((layer) => layer.name?.type === 'project' && !layer.disabledReason))
401
+ throw new Error('Codex project executable configuration is not permitted');
402
+ const requestedWindow = this.contextMeasurement?.configured;
403
+ if (requestedWindow != null && effective.model_context_window !== requestedWindow)
404
+ throw new Error('Codex context window configuration mismatch');
405
+ const requestedEnvironment = (0, worker_environment_1.workerEnvironment)(this.options.agent, this.options.gateway);
406
+ if (Object.entries(requestedEnvironment).some(([key, value]) => effective.shell_environment_policy?.set?.[key] !== value))
407
+ throw new Error('Codex worker environment configuration mismatch');
408
+ const actual = effective.mcp_servers ?? {};
409
+ if (JSON.stringify(Object.keys(actual).sort()) !== JSON.stringify(Object.keys(this.approvedMcp).sort()))
410
+ throw new Error('Codex MCP server inventory mismatch');
411
+ for (const [name, expected] of Object.entries(this.approvedMcp)) {
412
+ const server = actual[name];
413
+ if (server.command !== expected.command || server.url !== expected.url || server.cwd !== expected.cwd || JSON.stringify(server.args) !== JSON.stringify(expected.args) || Object.keys(server.env ?? {}).length !== Object.keys(expected.env ?? {}).length || Object.entries(expected.env ?? {}).some(([key, value]) => server.env?.[key] !== value) || Object.entries(expected.headers ?? {}).some(([key, value]) => server.http_headers?.[key] !== value) || ['enabled_tools', 'disabled_tools'].some(key => JSON.stringify(server[key]) !== JSON.stringify(expected[key])))
414
+ throw new Error('Codex MCP server configuration mismatch');
415
+ }
416
+ if (effective.notify?.length || (effective.hooks && Object.keys(effective.hooks).length))
417
+ throw new Error('Codex executable hooks are not permitted');
418
+ if (codex_policy_1.DISABLED_CODEX_FEATURES.some(name => effective.features?.[name] === true) ||
419
+ (effective.web_search !== undefined && effective.web_search !== 'disabled'))
420
+ throw new Error('Codex native capabilities exceed the gateway worker policy');
421
+ const provider = effective.model_providers?.gateway;
422
+ if (this.credentials.chatgpt) {
423
+ if (effective.model_provider !== 'openai' || effective.cli_auth_credentials_store !== 'ephemeral' || effective.model_providers?.openai?.base_url)
424
+ throw new Error('Codex native account configuration mismatch');
425
+ return;
426
+ }
427
+ if (effective.model_provider !== 'gateway' || provider?.base_url !== this.credentials.baseUrl || provider?.env_key !== 'GATEWAY_CODEX_API_KEY' || provider?.wire_api !== 'responses')
428
+ throw new Error('Codex provider configuration mismatch');
429
+ }
430
+ write(message) {
431
+ if (!this.child || this.exited)
432
+ throw new Error('Codex app-server is unavailable');
433
+ this.child.stdin.write(JSON.stringify(message) + '\n');
434
+ }
435
+ request(method, params) {
436
+ if (this.cancelled)
437
+ return Promise.reject(new Error('Codex process cancelled'));
438
+ const id = ++this.sequence;
439
+ return new Promise((resolve, reject) => {
440
+ const timer = setTimeout(() => { this.requests.delete(id); reject(new Error(`Codex ${method} timed out`)); }, 30000);
441
+ this.requests.set(id, { resolve, reject, timer });
442
+ try {
443
+ this.write({ id, method, params });
444
+ }
445
+ catch (error) {
446
+ clearTimeout(timer);
447
+ this.requests.delete(id);
448
+ reject(error);
449
+ }
450
+ });
451
+ }
452
+ rejectRequests(error) {
453
+ for (const request of this.requests.values()) {
454
+ clearTimeout(request.timer);
455
+ request.reject(error);
456
+ }
457
+ this.requests.clear();
458
+ }
459
+ async beginTurn(input) {
460
+ this.turnEnded = false;
461
+ this.finalText = '';
462
+ const response = await this.request('turn/start', { threadId: this.threadId, input, ...(this.options.config.reasoningEffort ? { effort: this.options.config.reasoningEffort } : {}), ...(this.options.agent.type === 'app-agent' ? { sandboxPolicy: { type: 'externalSandbox', networkAccess: 'enabled' } } : {}) });
463
+ if (typeof response.turn?.id !== 'string')
464
+ throw new Error('Codex omitted turn identity');
465
+ this.turnId = response.turn.id;
466
+ }
467
+ async refreshAuthentication(id, previousAccountId) {
468
+ try {
469
+ if (this.refreshingAuth || (previousAccountId && previousAccountId !== this.credentials?.chatgpt?.chatgptAccountId))
470
+ throw new Error('Invalid authentication refresh');
471
+ this.refreshingAuth = true;
472
+ const next = await (0, codex_auth_1.resolveCodexCredentials)({ ...this.options.config, bin: this.authExecutable, refreshToken: true });
473
+ if (!next.chatgpt || next.fingerprint !== this.identity)
474
+ throw new Error('Native Codex account changed');
475
+ if (!this.cancelled && !this.exited)
476
+ this.write({ id, result: next.chatgpt });
477
+ this.credentials = next;
478
+ }
479
+ catch {
480
+ if (!this.cancelled && !this.exited) {
481
+ this.write({ id, error: { code: -32001, message: 'Native Codex authentication refresh failed. Check codex login status under the gateway service user.' } });
482
+ this.fail('CODEX_AUTH_REFRESH_FAILED: Native Codex authentication could not be refreshed.');
483
+ void this.stop();
484
+ }
485
+ }
486
+ finally {
487
+ this.refreshingAuth = false;
488
+ }
489
+ }
490
+ event(event) {
491
+ if (typeof event.id === 'number' && !event.method) {
492
+ const pending = this.requests.get(event.id);
493
+ if (pending) {
494
+ clearTimeout(pending.timer);
495
+ this.requests.delete(event.id);
496
+ event.error ? pending.reject(new Error(event.error.message || JSON.stringify(event.error))) : pending.resolve(event.result);
497
+ }
498
+ return;
499
+ }
500
+ if (event.id !== undefined && event.method) {
501
+ if (event.method === 'account/chatgptAuthTokens/refresh' && this.credentials?.chatgpt) {
502
+ void this.refreshAuthentication(event.id, event.params?.previousAccountId);
503
+ return;
504
+ }
505
+ if (event.method === 'item/tool/requestUserInput' && this.options.requestInput) {
506
+ const questions = event.params?.questions;
507
+ if (!Array.isArray(questions) || !questions.length || questions.some((q) => !q || typeof q.question !== 'string' || q.options !== undefined && (!Array.isArray(q.options) || q.options.some((o) => !o || typeof o.label !== 'string' || o.description !== undefined && typeof o.description !== 'string'))))
508
+ throw new Error('Invalid Codex user-input request');
509
+ const text = questions.map((q) => [q.question, ...(q.options ?? []).map((option) => `${option.label}: ${option.description ?? ''}`)].join('\n')).join('\n\n');
510
+ // The existing task question flow owns delivery and resume. End this
511
+ // attempt without inventing an answer or holding a worker slot open.
512
+ this.options.requestInput(text);
513
+ this.write({ id: event.id, result: { answers: {} } });
514
+ this.terminal = true;
515
+ this.output({ type: 'result', is_error: false, result: 'Waiting for user input.' });
516
+ void this.stop();
517
+ return;
518
+ }
519
+ // This worker is noninteractive. Unexpected approval/tool requests fail closed.
520
+ this.write({ id: event.id, error: { code: -32601, message: 'Interactive requests are not supported by gateway workers' } });
521
+ this.fail(`Codex requested unsupported interaction: ${event.method}`);
522
+ void this.stop();
523
+ return;
524
+ }
525
+ if (this.terminal || this.cancelled)
526
+ return;
527
+ const p = event.params ?? {};
528
+ if (p.threadId && this.threadId && p.threadId !== this.threadId)
529
+ return;
530
+ if (event.method === 'turn/started') {
531
+ this.turnId = p.turn.id;
532
+ this.output({ type: 'stream_event', event: { type: 'message_start', message: { id: p.turn.id, model: this.options.config.model, content: [] } } });
533
+ }
534
+ else if (['item/agentMessage/delta', 'item/reasoning/summaryTextDelta', 'item/reasoning/textDelta'].includes(event.method) && typeof p.delta === 'string' && p.delta) {
535
+ // Activity is observable, but only the canonical completed answer is published.
536
+ this.output({ type: 'assistant', message: { model: this.options.config.model, content: [{ type: event.method === 'item/agentMessage/delta' ? 'text' : 'thinking', text: p.delta, thinking: p.delta }] } });
537
+ }
538
+ else if (event.method === 'error') {
539
+ this.lastError = p.error?.message || JSON.stringify(p.error);
540
+ }
541
+ else if (event.method === 'thread/tokenUsage/updated') {
542
+ this.contextMeasurement = (0, codex_context_1.observeCodexContext)(this.contextMeasurement ?? (0, codex_context_1.codexContextPolicy)(this.options.config.model, this.options.config.contextWindow), p.tokenUsage);
543
+ this.nativeUsage = p.tokenUsage?.total;
544
+ this.output({ type: 'system', subtype: 'native_usage', ...(this.nativeUsage ? { usage: this.normalizedUsage() } : {}), contextWindow: this.contextMeasurement });
545
+ if (this.contextMeasurement.configured !== null && this.contextMeasurement.observed !== null && this.contextMeasurement.observed > this.contextMeasurement.configured) {
546
+ this.fail('CODEX_CONTEXT_WINDOW_MISMATCH: native usable context exceeds the configured ceiling. Check the selected model and update Codex.');
547
+ void this.stop();
548
+ return;
549
+ }
550
+ }
551
+ else if (event.method === 'turn/completed') {
552
+ if (this.turnId && p.turn.id !== this.turnId)
553
+ return;
554
+ this.turnEnded = true;
555
+ if (p.turn.status !== 'completed') {
556
+ this.fail(p.turn.error?.message || this.lastError || `Codex turn ${p.turn.status}`);
557
+ return;
558
+ }
559
+ this.completion = this.completeTurn().catch(error => this.fail(error.message));
560
+ }
561
+ else if (event.method === 'item/started' || event.method === 'item/completed') {
562
+ const item = p.item;
563
+ if (!item || typeof item.id !== 'string')
564
+ return;
565
+ const completed = event.method === 'item/completed';
566
+ if (item.type === 'agentMessage' && completed) {
567
+ if (item.phase !== 'commentary')
568
+ this.finalText = item.text ?? '';
569
+ return;
570
+ }
571
+ const name = item.type === 'commandExecution' ? 'Bash' : item.type === 'fileChange' ? 'Edit' : item.type === 'mcpToolCall' ? `mcp__${item.server}__${item.tool}` : undefined;
572
+ if (!name)
573
+ return;
574
+ if (!this.tools.has(item.id)) {
575
+ this.tools.add(item.id);
576
+ this.output({ type: 'assistant', message: { model: this.options.config.model, content: [{ type: 'tool_use', id: item.id, name, input: item.type === 'commandExecution' ? { command: item.command } : item.type === 'fileChange' ? { changes: item.changes } : item.arguments ?? {} }] } });
577
+ }
578
+ if (completed && !this.completedTools.has(item.id)) {
579
+ this.completedTools.add(item.id);
580
+ this.output({ type: 'user', message: { content: [{ type: 'tool_result', tool_use_id: item.id, is_error: item.status === 'failed' || item.status === 'declined' || !!item.error || item.result?.isError === true || (typeof item.exitCode === 'number' && item.exitCode !== 0), content: item.aggregatedOutput ?? JSON.stringify(item.error ?? item.result ?? item.changes ?? '') }] } });
581
+ if (!this.steering) {
582
+ this.steering = this.steer().catch(error => { this.fail(`Codex task update failed: ${error.message}`); void this.stop(); }).finally(() => { this.steering = undefined; });
583
+ }
584
+ }
585
+ }
586
+ }
587
+ async steer() {
588
+ if (!this.options.checkpoint || this.cancelled || this.turnEnded)
589
+ return;
590
+ this.amendment ?? (this.amendment = await this.options.checkpoint());
591
+ if (!this.amendment || this.cancelled || this.turnEnded)
592
+ return;
593
+ try {
594
+ await this.request('turn/steer', { threadId: this.threadId, expectedTurnId: this.turnId, input: [{ type: 'text', text: this.amendment.text, text_elements: [] }] });
595
+ }
596
+ catch (error) {
597
+ // A just-completed turn cannot accept steering; preserve the amendment for the next turn.
598
+ if (this.turnEnded)
599
+ return;
600
+ throw error;
601
+ }
602
+ await this.amendment.acknowledge();
603
+ this.amendment = undefined;
604
+ }
605
+ async completeTurn() {
606
+ await this.steering;
607
+ if (this.cancelled || this.terminal)
608
+ return;
609
+ this.amendment ?? (this.amendment = await this.options.checkpoint?.());
610
+ if (this.cancelled)
611
+ return;
612
+ if (this.amendment?.kind === 'advice') {
613
+ await this.amendment.acknowledge();
614
+ this.amendment = undefined;
615
+ }
616
+ if (this.amendment) {
617
+ const amendment = this.amendment;
618
+ await this.beginTurn([{ type: 'text', text: amendment.text, text_elements: [] }]);
619
+ await amendment.acknowledge();
620
+ this.amendment = undefined;
621
+ return;
622
+ }
623
+ await this.persist();
624
+ if (this.cancelled)
625
+ return;
626
+ this.terminal = true;
627
+ this.output({ type: 'result', result: this.finalText, ...(this.nativeUsage ? { usage: this.normalizedUsage() } : {}) });
628
+ }
629
+ normalizedUsage() {
630
+ const count = (value) => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : 0;
631
+ const difference = (field) => Math.max(0, count(this.nativeUsage?.[field]) - count(this.saved?.usage?.[field]));
632
+ const input = difference('inputTokens'), cached = Math.min(input, difference('cachedInputTokens'));
633
+ // Codex's input total includes cache reads AND writes. Preserve a reported
634
+ // zero, but do not manufacture a measurement when either cumulative endpoint
635
+ // is unknown (notably a resumed transcript from an older Codex version).
636
+ const reportedWrites = this.nativeUsage?.cacheWriteInputTokens;
637
+ const previousWrites = this.saved?.usage?.cacheWriteInputTokens;
638
+ const writesKnown = typeof reportedWrites === 'number' && Number.isSafeInteger(reportedWrites) && reportedWrites >= 0 &&
639
+ (!this.saved?.usage || (typeof previousWrites === 'number' && Number.isSafeInteger(previousWrites) && previousWrites >= 0));
640
+ const written = writesKnown ? Math.min(input - cached, difference('cacheWriteInputTokens')) : 0;
641
+ return { input_tokens: input - cached - written, cache_read_input_tokens: cached,
642
+ ...(writesKnown ? { cache_creation_input_tokens: written } : {}), output_tokens: difference('outputTokens') };
643
+ }
644
+ async persist() {
645
+ if (!this.threadId)
646
+ throw new Error('Codex omitted its thread identity');
647
+ const temporary = this.mapping + '.' + (0, crypto_1.randomUUID)();
648
+ await (0, promises_1.writeFile)(temporary, JSON.stringify({ threadId: this.threadId, home: this.home, container: this.options.agent.container, containerId: this.containerId, identity: this.identity, usage: this.nativeUsage ?? this.saved?.usage }), { mode: 0o600 });
649
+ await (0, promises_1.rename)(temporary, this.mapping);
650
+ this.homePersisted = true;
651
+ }
652
+ interrupt() {
653
+ if (this.turnId && !this.cancelled && !this.exited) {
654
+ try {
655
+ this.write({ id: ++this.sequence, method: 'turn/interrupt', params: { threadId: this.threadId, turnId: this.turnId } });
656
+ }
657
+ catch { }
658
+ }
659
+ this.cancelled = true;
660
+ this.rejectRequests(new Error('Codex process cancelled'));
661
+ return !!this.child && !this.exited;
662
+ }
663
+ captureTrace() {
664
+ if (this.traceScan)
665
+ return this.traceScan;
666
+ this.traceScan = (async () => {
667
+ if (!this.home)
668
+ return;
669
+ const root = this.home + '/gateway-trace';
670
+ const captured = this.options.agent.type === 'app-agent'
671
+ ? JSON.parse(await (0, container_1.containerNode)(this.options.agent.container, `let s='';process.stdin.on('data',b=>s+=b);process.stdin.on('end',()=>process.stdout.write(JSON.stringify((${codex_tool_capture_1.scanCodexTrace.toString()})(process.argv[1],JSON.parse(s)))));`, [root], JSON.stringify(this.traceState)))
672
+ : (0, codex_tool_capture_1.scanCodexTrace)(root, this.traceState);
673
+ this.traceState = captured.state;
674
+ for (const value of captured.measurements) {
675
+ if (value.schemas) {
676
+ this.traceSchemas.set(value.schemas.messageId, value.schemas);
677
+ this.emit('request-tools', value.schemas);
678
+ }
679
+ if (value.request)
680
+ this.output({ type: 'assistant', message: { ...value.request, content: [] } });
681
+ }
682
+ })().catch(() => { }).finally(() => { this.traceScan = undefined; });
683
+ return this.traceScan;
684
+ }
685
+ async flushToolSchemas() {
686
+ // Native trace writes can trail the terminal app-server notification.
687
+ for (let i = 0; i < 3; i++) {
688
+ await new Promise(resolve => setTimeout(resolve, 50));
689
+ await this.captureTrace();
690
+ }
691
+ return [...this.traceSchemas.values()];
692
+ }
693
+ stop() {
694
+ this.interrupt();
695
+ return this.stopping ?? (this.stopping = this.shutdown());
696
+ }
697
+ async shutdown() {
698
+ await this.preparing?.catch(() => { });
699
+ await this.launching?.catch(() => { });
700
+ await this.completion;
701
+ if (this.traceTimer)
702
+ clearInterval(this.traceTimer);
703
+ await this.traceScan;
704
+ let stopped = true;
705
+ if (this.containerAttempt && this.child)
706
+ stopped = await (0, container_1.stopContainerProfile)(this.options.agent.container, this.containerAttempt.directory);
707
+ if (this.group)
708
+ stopped = await (0, process_supervisor_1.stopProcessGroup)(this.group) && stopped;
709
+ this.managedGroupStopped = stopped;
710
+ if (stopped)
711
+ this.group = undefined;
712
+ // Failed/interrupted turns also advance the durable token baseline.
713
+ if (stopped && this.threadId && this.nativeUsage)
714
+ await this.persist();
715
+ if (!this.child)
716
+ this.emit('exit', null, 'SIGINT');
717
+ if (stopped) {
718
+ await this.captureTrace();
719
+ await this.cleanupHomes();
720
+ }
721
+ }
722
+ async cleanupHomes() {
723
+ for (const filename of this.connectorPaths)
724
+ await (0, promises_1.rm)(filename, { force: true });
725
+ this.connectorPaths.clear();
726
+ if (!this.leaseOwned)
727
+ return;
728
+ // Only the most recent transcript home is needed after its replacement is durable.
729
+ if (this.saved && this.homePersisted && this.home !== this.saved.home) {
730
+ if (this.options.agent.type === 'app-agent')
731
+ await (0, container_1.containerNode)(this.options.agent.container, "require('fs').rmSync(process.argv[1],{recursive:true,force:true})", [this.saved.home]);
732
+ else
733
+ await (0, promises_1.rm)(this.saved.home, { recursive: true, force: true });
734
+ }
735
+ // Transcripts remain for explicit resume; short-lived MCP ticket configuration does not.
736
+ if (this.containerAttempt)
737
+ await (0, container_1.containerNode)(this.options.agent.container, "require('fs').rmSync(process.argv[1],{recursive:true,force:true})", [this.containerAttempt.directory]);
738
+ if (this.home) {
739
+ if (this.options.agent.type === 'app-agent')
740
+ await (0, container_1.containerNode)(this.options.agent.container, "require('fs').rmSync(process.argv[1],{recursive:true,force:true})", [this.home + '/gateway-trace']).catch(() => { });
741
+ else
742
+ await (0, promises_1.rm)(this.home + '/gateway-trace', { recursive: true, force: true });
743
+ if (this.options.agent.type === 'app-agent')
744
+ await (0, container_1.containerNode)(this.options.agent.container, "require('fs').rmSync(process.argv[1],{force:true})", [this.home + '/config.toml']).catch(() => { });
745
+ else
746
+ await (0, promises_1.rm)((0, path_1.join)(this.home, 'config.toml'), { force: true });
747
+ if (!this.homePersisted) {
748
+ if (this.options.agent.type === 'app-agent')
749
+ await (0, container_1.containerNode)(this.options.agent.container, "require('fs').rmSync(process.argv[1],{recursive:true,force:true})", [this.home]);
750
+ else
751
+ await (0, promises_1.rm)(this.home, { recursive: true, force: true });
752
+ }
753
+ }
754
+ await (0, promises_1.rm)((0, path_1.join)(this.root, '.active'), { recursive: true, force: true });
755
+ this.leaseOwned = false;
756
+ }
757
+ }
758
+ exports.CodexProcess = CodexProcess;
759
+ //# sourceMappingURL=codex-process.js.map