@getpaseo/server 0.1.62 → 0.1.65

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 (590) hide show
  1. package/README.md +4 -0
  2. package/dist/server/client/daemon-client-runtime-metrics.d.ts +6 -6
  3. package/dist/server/client/daemon-client-runtime-metrics.d.ts.map +1 -1
  4. package/dist/server/client/daemon-client-transport-types.d.ts +15 -13
  5. package/dist/server/client/daemon-client-transport-types.d.ts.map +1 -1
  6. package/dist/server/client/daemon-client-websocket-transport.d.ts +3 -2
  7. package/dist/server/client/daemon-client-websocket-transport.d.ts.map +1 -1
  8. package/dist/server/client/daemon-client-websocket-transport.js +9 -8
  9. package/dist/server/client/daemon-client-websocket-transport.js.map +1 -1
  10. package/dist/server/client/daemon-client.d.ts +88 -56
  11. package/dist/server/client/daemon-client.d.ts.map +1 -1
  12. package/dist/server/client/daemon-client.js +264 -111
  13. package/dist/server/client/daemon-client.js.map +1 -1
  14. package/dist/server/client/terminal-stream-router.d.ts +24 -0
  15. package/dist/server/client/terminal-stream-router.d.ts.map +1 -0
  16. package/dist/server/client/terminal-stream-router.js +100 -0
  17. package/dist/server/client/terminal-stream-router.js.map +1 -0
  18. package/dist/server/server/agent/activity-curator.d.ts +6 -3
  19. package/dist/server/server/agent/activity-curator.d.ts.map +1 -1
  20. package/dist/server/server/agent/activity-curator.js +45 -138
  21. package/dist/server/server/agent/activity-curator.js.map +1 -1
  22. package/dist/server/server/agent/agent-loading.d.ts.map +1 -1
  23. package/dist/server/server/agent/agent-loading.js +5 -3
  24. package/dist/server/server/agent/agent-loading.js.map +1 -1
  25. package/dist/server/server/agent/agent-manager.d.ts +46 -31
  26. package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
  27. package/dist/server/server/agent/agent-manager.js +457 -419
  28. package/dist/server/server/agent/agent-manager.js.map +1 -1
  29. package/dist/server/server/agent/agent-metadata-generator.d.ts +6 -11
  30. package/dist/server/server/agent/agent-metadata-generator.d.ts.map +1 -1
  31. package/dist/server/server/agent/agent-metadata-generator.js +3 -85
  32. package/dist/server/server/agent/agent-metadata-generator.js.map +1 -1
  33. package/dist/server/server/agent/agent-projections.d.ts +4 -6
  34. package/dist/server/server/agent/agent-projections.d.ts.map +1 -1
  35. package/dist/server/server/agent/agent-projections.js +59 -65
  36. package/dist/server/server/agent/agent-projections.js.map +1 -1
  37. package/dist/server/server/agent/agent-response-loop.d.ts +4 -4
  38. package/dist/server/server/agent/agent-response-loop.d.ts.map +1 -1
  39. package/dist/server/server/agent/agent-response-loop.js +58 -45
  40. package/dist/server/server/agent/agent-response-loop.js.map +1 -1
  41. package/dist/server/server/agent/agent-sdk-types.d.ts +58 -41
  42. package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
  43. package/dist/server/server/agent/agent-sdk-types.js.map +1 -1
  44. package/dist/server/server/agent/agent-storage.d.ts +2 -2
  45. package/dist/server/server/agent/agent-storage.d.ts.map +1 -1
  46. package/dist/server/server/agent/agent-storage.js +29 -36
  47. package/dist/server/server/agent/agent-storage.js.map +1 -1
  48. package/dist/server/server/agent/agent-stream-coalescer.d.ts +7 -7
  49. package/dist/server/server/agent/agent-stream-coalescer.d.ts.map +1 -1
  50. package/dist/server/server/agent/agent-stream-coalescer.js +1 -1
  51. package/dist/server/server/agent/agent-stream-coalescer.js.map +1 -1
  52. package/dist/server/server/agent/agent-timeline-store-types.d.ts +10 -10
  53. package/dist/server/server/agent/agent-timeline-store-types.d.ts.map +1 -1
  54. package/dist/server/server/agent/agent-timeline-store.d.ts +2 -2
  55. package/dist/server/server/agent/agent-timeline-store.d.ts.map +1 -1
  56. package/dist/server/server/agent/agent-timeline-store.js +103 -85
  57. package/dist/server/server/agent/agent-timeline-store.js.map +1 -1
  58. package/dist/server/server/agent/foreground-run-state.d.ts +50 -0
  59. package/dist/server/server/agent/foreground-run-state.d.ts.map +1 -0
  60. package/dist/server/server/agent/foreground-run-state.js +162 -0
  61. package/dist/server/server/agent/foreground-run-state.js.map +1 -0
  62. package/dist/server/server/agent/mcp-server.d.ts +5 -3
  63. package/dist/server/server/agent/mcp-server.d.ts.map +1 -1
  64. package/dist/server/server/agent/mcp-server.js +282 -234
  65. package/dist/server/server/agent/mcp-server.js.map +1 -1
  66. package/dist/server/server/agent/mcp-shared.d.ts +9 -2
  67. package/dist/server/server/agent/mcp-shared.d.ts.map +1 -1
  68. package/dist/server/server/agent/mcp-shared.js +9 -1
  69. package/dist/server/server/agent/mcp-shared.js.map +1 -1
  70. package/dist/server/server/agent/model-resolver.d.ts +2 -2
  71. package/dist/server/server/agent/model-resolver.d.ts.map +1 -1
  72. package/dist/server/server/agent/model-resolver.js +9 -5
  73. package/dist/server/server/agent/model-resolver.js.map +1 -1
  74. package/dist/server/server/agent/prompt-attachments.d.ts +4 -3
  75. package/dist/server/server/agent/prompt-attachments.d.ts.map +1 -1
  76. package/dist/server/server/agent/prompt-attachments.js +43 -4
  77. package/dist/server/server/agent/prompt-attachments.js.map +1 -1
  78. package/dist/server/server/agent/provider-launch-config.d.ts +28 -17
  79. package/dist/server/server/agent/provider-launch-config.d.ts.map +1 -1
  80. package/dist/server/server/agent/provider-launch-config.js +20 -9
  81. package/dist/server/server/agent/provider-launch-config.js.map +1 -1
  82. package/dist/server/server/agent/provider-manifest.d.ts.map +1 -1
  83. package/dist/server/server/agent/provider-manifest.js +7 -0
  84. package/dist/server/server/agent/provider-manifest.js.map +1 -1
  85. package/dist/server/server/agent/provider-registry.d.ts +4 -2
  86. package/dist/server/server/agent/provider-registry.d.ts.map +1 -1
  87. package/dist/server/server/agent/provider-registry.js +24 -21
  88. package/dist/server/server/agent/provider-registry.js.map +1 -1
  89. package/dist/server/server/agent/provider-snapshot-manager.d.ts +6 -5
  90. package/dist/server/server/agent/provider-snapshot-manager.d.ts.map +1 -1
  91. package/dist/server/server/agent/provider-snapshot-manager.js +40 -31
  92. package/dist/server/server/agent/provider-snapshot-manager.js.map +1 -1
  93. package/dist/server/server/agent/providers/acp-agent.d.ts +49 -13
  94. package/dist/server/server/agent/providers/acp-agent.d.ts.map +1 -1
  95. package/dist/server/server/agent/providers/acp-agent.js +404 -261
  96. package/dist/server/server/agent/providers/acp-agent.js.map +1 -1
  97. package/dist/server/server/agent/providers/claude/sidechain-tracker.d.ts +2 -0
  98. package/dist/server/server/agent/providers/claude/sidechain-tracker.d.ts.map +1 -1
  99. package/dist/server/server/agent/providers/claude/sidechain-tracker.js +47 -45
  100. package/dist/server/server/agent/providers/claude/sidechain-tracker.js.map +1 -1
  101. package/dist/server/server/agent/providers/claude/task-notification-tool-call.d.ts +2 -2
  102. package/dist/server/server/agent/providers/claude/task-notification-tool-call.d.ts.map +1 -1
  103. package/dist/server/server/agent/providers/claude/task-notification-tool-call.js +10 -5
  104. package/dist/server/server/agent/providers/claude/task-notification-tool-call.js.map +1 -1
  105. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts.map +1 -1
  106. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js +11 -2
  107. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js.map +1 -1
  108. package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts +2 -2
  109. package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts.map +1 -1
  110. package/dist/server/server/agent/providers/claude/tool-call-mapper.js +83 -206
  111. package/dist/server/server/agent/providers/claude/tool-call-mapper.js.map +1 -1
  112. package/dist/server/server/agent/providers/claude-agent.d.ts +20 -8
  113. package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
  114. package/dist/server/server/agent/providers/claude-agent.js +654 -554
  115. package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
  116. package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts +2 -2
  117. package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts.map +1 -1
  118. package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts +2 -2
  119. package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts.map +1 -1
  120. package/dist/server/server/agent/providers/codex/tool-call-mapper.js +174 -185
  121. package/dist/server/server/agent/providers/codex/tool-call-mapper.js.map +1 -1
  122. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +62 -13
  123. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
  124. package/dist/server/server/agent/providers/codex-app-server-agent.js +873 -646
  125. package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
  126. package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts +2 -2
  127. package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts.map +1 -1
  128. package/dist/server/server/agent/providers/codex-rollout-timeline.js +58 -47
  129. package/dist/server/server/agent/providers/codex-rollout-timeline.js.map +1 -1
  130. package/dist/server/server/agent/providers/copilot-acp-agent.d.ts +2 -2
  131. package/dist/server/server/agent/providers/copilot-acp-agent.d.ts.map +1 -1
  132. package/dist/server/server/agent/providers/diagnostic-utils.d.ts +3 -3
  133. package/dist/server/server/agent/providers/diagnostic-utils.d.ts.map +1 -1
  134. package/dist/server/server/agent/providers/diagnostic-utils.js +82 -9
  135. package/dist/server/server/agent/providers/diagnostic-utils.js.map +1 -1
  136. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +2 -2
  137. package/dist/server/server/agent/providers/generic-acp-agent.d.ts.map +1 -1
  138. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +6 -2
  139. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts.map +1 -1
  140. package/dist/server/server/agent/providers/mock-load-test-agent.js +294 -113
  141. package/dist/server/server/agent/providers/mock-load-test-agent.js.map +1 -1
  142. package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts +1 -1
  143. package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts.map +1 -1
  144. package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +94 -2
  145. package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js.map +1 -1
  146. package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts +2 -2
  147. package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts.map +1 -1
  148. package/dist/server/server/agent/providers/opencode/tool-call-mapper.js +24 -115
  149. package/dist/server/server/agent/providers/opencode/tool-call-mapper.js.map +1 -1
  150. package/dist/server/server/agent/providers/opencode-agent.d.ts +104 -3
  151. package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -1
  152. package/dist/server/server/agent/providers/opencode-agent.js +786 -503
  153. package/dist/server/server/agent/providers/opencode-agent.js.map +1 -1
  154. package/dist/server/server/agent/providers/pi-direct-agent.d.ts +1 -0
  155. package/dist/server/server/agent/providers/pi-direct-agent.d.ts.map +1 -1
  156. package/dist/server/server/agent/providers/pi-direct-agent.js +109 -140
  157. package/dist/server/server/agent/providers/pi-direct-agent.js.map +1 -1
  158. package/dist/server/server/agent/providers/provider-runner.d.ts +27 -0
  159. package/dist/server/server/agent/providers/provider-runner.d.ts.map +1 -0
  160. package/dist/server/server/agent/providers/provider-runner.js +80 -0
  161. package/dist/server/server/agent/providers/provider-runner.js.map +1 -0
  162. package/dist/server/server/agent/providers/test-utils/session-stream-adapter.d.ts.map +1 -1
  163. package/dist/server/server/agent/providers/test-utils/session-stream-adapter.js +3 -1
  164. package/dist/server/server/agent/providers/test-utils/session-stream-adapter.js.map +1 -1
  165. package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +9 -6
  166. package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -1
  167. package/dist/server/server/agent/providers/tool-call-detail-primitives.js +102 -73
  168. package/dist/server/server/agent/providers/tool-call-detail-primitives.js.map +1 -1
  169. package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +4 -2
  170. package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts.map +1 -1
  171. package/dist/server/server/agent/providers/tool-call-mapper-utils.js +31 -0
  172. package/dist/server/server/agent/providers/tool-call-mapper-utils.js.map +1 -1
  173. package/dist/server/server/agent/stt-manager.d.ts.map +1 -1
  174. package/dist/server/server/agent/stt-manager.js +63 -53
  175. package/dist/server/server/agent/stt-manager.js.map +1 -1
  176. package/dist/server/server/agent/timeline-projection.d.ts +27 -11
  177. package/dist/server/server/agent/timeline-projection.d.ts.map +1 -1
  178. package/dist/server/server/agent/timeline-projection.js +70 -15
  179. package/dist/server/server/agent/timeline-projection.js.map +1 -1
  180. package/dist/server/server/agent/tts-manager.d.ts.map +1 -1
  181. package/dist/server/server/agent/tts-manager.js +1 -0
  182. package/dist/server/server/agent/tts-manager.js.map +1 -1
  183. package/dist/server/server/agent-attention-policy.d.ts +2 -2
  184. package/dist/server/server/agent-attention-policy.d.ts.map +1 -1
  185. package/dist/server/server/auth.d.ts +25 -0
  186. package/dist/server/server/auth.d.ts.map +1 -0
  187. package/dist/server/server/auth.js +93 -0
  188. package/dist/server/server/auth.js.map +1 -0
  189. package/dist/server/server/bootstrap.d.ts +7 -5
  190. package/dist/server/server/bootstrap.d.ts.map +1 -1
  191. package/dist/server/server/bootstrap.js +550 -485
  192. package/dist/server/server/bootstrap.js.map +1 -1
  193. package/dist/server/server/chat/chat-service.d.ts +1 -1
  194. package/dist/server/server/chat/chat-service.d.ts.map +1 -1
  195. package/dist/server/server/chat/chat-service.js +3 -3
  196. package/dist/server/server/chat/chat-service.js.map +1 -1
  197. package/dist/server/server/checkout-diff-manager.d.ts +2 -2
  198. package/dist/server/server/checkout-diff-manager.d.ts.map +1 -1
  199. package/dist/server/server/checkout-git-utils.d.ts +5 -3
  200. package/dist/server/server/checkout-git-utils.d.ts.map +1 -1
  201. package/dist/server/server/checkout-git-utils.js +1 -2
  202. package/dist/server/server/checkout-git-utils.js.map +1 -1
  203. package/dist/server/server/config.d.ts.map +1 -1
  204. package/dist/server/server/config.js +79 -39
  205. package/dist/server/server/config.js.map +1 -1
  206. package/dist/server/server/connection-offer.d.ts +2 -2
  207. package/dist/server/server/connection-offer.d.ts.map +1 -1
  208. package/dist/server/server/daemon-config-store.d.ts +5 -3
  209. package/dist/server/server/daemon-config-store.d.ts.map +1 -1
  210. package/dist/server/server/daemon-config-store.js +26 -0
  211. package/dist/server/server/daemon-config-store.js.map +1 -1
  212. package/dist/server/server/daemon-keypair.d.ts +2 -2
  213. package/dist/server/server/daemon-keypair.d.ts.map +1 -1
  214. package/dist/server/server/editor-targets.d.ts +4 -4
  215. package/dist/server/server/editor-targets.d.ts.map +1 -1
  216. package/dist/server/server/editor-targets.js +11 -15
  217. package/dist/server/server/editor-targets.js.map +1 -1
  218. package/dist/server/server/exports.d.ts +10 -4
  219. package/dist/server/server/exports.d.ts.map +1 -1
  220. package/dist/server/server/exports.js +7 -4
  221. package/dist/server/server/exports.js.map +1 -1
  222. package/dist/server/server/file-download/token-store.d.ts +4 -4
  223. package/dist/server/server/file-download/token-store.d.ts.map +1 -1
  224. package/dist/server/server/file-explorer/service.d.ts +10 -0
  225. package/dist/server/server/file-explorer/service.d.ts.map +1 -1
  226. package/dist/server/server/file-explorer/service.js +38 -4
  227. package/dist/server/server/file-explorer/service.js.map +1 -1
  228. package/dist/server/server/index.js +25 -18
  229. package/dist/server/server/index.js.map +1 -1
  230. package/dist/server/server/logger.d.ts +4 -4
  231. package/dist/server/server/logger.d.ts.map +1 -1
  232. package/dist/server/server/logger.js +41 -21
  233. package/dist/server/server/logger.js.map +1 -1
  234. package/dist/server/server/loop/rpc-schemas.d.ts +52 -52
  235. package/dist/server/server/loop-service.d.ts +13 -12
  236. package/dist/server/server/loop-service.d.ts.map +1 -1
  237. package/dist/server/server/loop-service.js +22 -18
  238. package/dist/server/server/loop-service.js.map +1 -1
  239. package/dist/server/server/package-version.d.ts +2 -2
  240. package/dist/server/server/package-version.d.ts.map +1 -1
  241. package/dist/server/server/package-version.js +19 -17
  242. package/dist/server/server/package-version.js.map +1 -1
  243. package/dist/server/server/pagination/cursor.d.ts +16 -0
  244. package/dist/server/server/pagination/cursor.d.ts.map +1 -0
  245. package/dist/server/server/pagination/cursor.js +62 -0
  246. package/dist/server/server/pagination/cursor.js.map +1 -0
  247. package/dist/server/server/pagination/sortable-pager.d.ts +24 -0
  248. package/dist/server/server/pagination/sortable-pager.d.ts.map +1 -0
  249. package/dist/server/server/pagination/sortable-pager.js +68 -0
  250. package/dist/server/server/pagination/sortable-pager.js.map +1 -0
  251. package/dist/server/server/pairing-offer.d.ts +2 -2
  252. package/dist/server/server/pairing-offer.d.ts.map +1 -1
  253. package/dist/server/server/paseo-env.d.ts +9 -0
  254. package/dist/server/server/paseo-env.d.ts.map +1 -0
  255. package/dist/server/server/paseo-env.js +70 -0
  256. package/dist/server/server/paseo-env.js.map +1 -0
  257. package/dist/server/server/paseo-worktree-archive-service.d.ts +7 -5
  258. package/dist/server/server/paseo-worktree-archive-service.d.ts.map +1 -1
  259. package/dist/server/server/paseo-worktree-archive-service.js +70 -62
  260. package/dist/server/server/paseo-worktree-archive-service.js.map +1 -1
  261. package/dist/server/server/paseo-worktree-service.d.ts +13 -0
  262. package/dist/server/server/paseo-worktree-service.d.ts.map +1 -1
  263. package/dist/server/server/paseo-worktree-service.js +72 -3
  264. package/dist/server/server/paseo-worktree-service.js.map +1 -1
  265. package/dist/server/server/persisted-config.d.ts +87 -62
  266. package/dist/server/server/persisted-config.d.ts.map +1 -1
  267. package/dist/server/server/persisted-config.js +13 -4
  268. package/dist/server/server/persisted-config.js.map +1 -1
  269. package/dist/server/server/persistence-hooks.d.ts +8 -9
  270. package/dist/server/server/persistence-hooks.d.ts.map +1 -1
  271. package/dist/server/server/persistence-hooks.js +4 -12
  272. package/dist/server/server/persistence-hooks.js.map +1 -1
  273. package/dist/server/server/pid-lock.js.map +1 -1
  274. package/dist/server/server/push/push-service.d.ts.map +1 -1
  275. package/dist/server/server/push/push-service.js +1 -3
  276. package/dist/server/server/push/push-service.js.map +1 -1
  277. package/dist/server/server/relay-transport.d.ts +8 -8
  278. package/dist/server/server/relay-transport.d.ts.map +1 -1
  279. package/dist/server/server/relay-transport.js +43 -20
  280. package/dist/server/server/relay-transport.js.map +1 -1
  281. package/dist/server/server/resolve-worktree-creation-intent.d.ts +0 -10
  282. package/dist/server/server/resolve-worktree-creation-intent.d.ts.map +1 -1
  283. package/dist/server/server/resolve-worktree-creation-intent.js +1 -45
  284. package/dist/server/server/resolve-worktree-creation-intent.js.map +1 -1
  285. package/dist/server/server/schedule/service.d.ts.map +1 -1
  286. package/dist/server/server/schedule/service.js +2 -2
  287. package/dist/server/server/schedule/service.js.map +1 -1
  288. package/dist/server/server/script-health-monitor.d.ts.map +1 -1
  289. package/dist/server/server/script-health-monitor.js +7 -6
  290. package/dist/server/server/script-health-monitor.js.map +1 -1
  291. package/dist/server/server/script-proxy.js +1 -1
  292. package/dist/server/server/script-proxy.js.map +1 -1
  293. package/dist/server/server/script-status-projection.d.ts +10 -5
  294. package/dist/server/server/script-status-projection.d.ts.map +1 -1
  295. package/dist/server/server/script-status-projection.js +66 -47
  296. package/dist/server/server/script-status-projection.js.map +1 -1
  297. package/dist/server/server/server-id.d.ts +4 -4
  298. package/dist/server/server/server-id.d.ts.map +1 -1
  299. package/dist/server/server/session.d.ts +64 -65
  300. package/dist/server/server/session.d.ts.map +1 -1
  301. package/dist/server/server/session.js +1356 -1734
  302. package/dist/server/server/session.js.map +1 -1
  303. package/dist/server/server/speech/audio.js +1 -1
  304. package/dist/server/server/speech/audio.js.map +1 -1
  305. package/dist/server/server/speech/providers/local/config.d.ts +6 -6
  306. package/dist/server/server/speech/providers/local/config.d.ts.map +1 -1
  307. package/dist/server/server/speech/providers/local/config.js +41 -16
  308. package/dist/server/server/speech/providers/local/config.js.map +1 -1
  309. package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.d.ts +2 -2
  310. package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.d.ts.map +1 -1
  311. package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.js +42 -19
  312. package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.js.map +1 -1
  313. package/dist/server/server/speech/providers/local/runtime.d.ts +4 -4
  314. package/dist/server/server/speech/providers/local/runtime.d.ts.map +1 -1
  315. package/dist/server/server/speech/providers/local/runtime.js +108 -77
  316. package/dist/server/server/speech/providers/local/runtime.js.map +1 -1
  317. package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts +2 -2
  318. package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts.map +1 -1
  319. package/dist/server/server/speech/providers/local/sherpa/model-catalog.js +1 -4
  320. package/dist/server/server/speech/providers/local/sherpa/model-catalog.js.map +1 -1
  321. package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts +2 -2
  322. package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts.map +1 -1
  323. package/dist/server/server/speech/providers/local/sherpa/model-downloader.js +19 -19
  324. package/dist/server/server/speech/providers/local/sherpa/model-downloader.js.map +1 -1
  325. package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts +28 -7
  326. package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts.map +1 -1
  327. package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js.map +1 -1
  328. package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.d.ts +23 -4
  329. package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.d.ts.map +1 -1
  330. package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.js +35 -28
  331. package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.js.map +1 -1
  332. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.d.ts +5 -5
  333. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.d.ts.map +1 -1
  334. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts +7 -7
  335. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts.map +1 -1
  336. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js +5 -0
  337. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js.map +1 -1
  338. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.d.ts.map +1 -1
  339. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +3 -1
  340. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js.map +1 -1
  341. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts +2 -2
  342. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts.map +1 -1
  343. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +3 -1
  344. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js.map +1 -1
  345. package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.d.ts.map +1 -1
  346. package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js +10 -4
  347. package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js.map +1 -1
  348. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.d.ts +2 -2
  349. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.d.ts.map +1 -1
  350. package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.d.ts +2 -2
  351. package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.d.ts.map +1 -1
  352. package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.js +4 -1
  353. package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.js.map +1 -1
  354. package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts +2 -2
  355. package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts.map +1 -1
  356. package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js +18 -11
  357. package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js.map +1 -1
  358. package/dist/server/server/speech/providers/openai/config.d.ts +2 -2
  359. package/dist/server/server/speech/providers/openai/config.d.ts.map +1 -1
  360. package/dist/server/server/speech/providers/openai/config.js +58 -31
  361. package/dist/server/server/speech/providers/openai/config.js.map +1 -1
  362. package/dist/server/server/speech/providers/openai/realtime-transcription-session.d.ts.map +1 -1
  363. package/dist/server/server/speech/providers/openai/realtime-transcription-session.js +2 -2
  364. package/dist/server/server/speech/providers/openai/realtime-transcription-session.js.map +1 -1
  365. package/dist/server/server/speech/providers/openai/runtime.d.ts +4 -4
  366. package/dist/server/server/speech/providers/openai/runtime.d.ts.map +1 -1
  367. package/dist/server/server/speech/providers/openai/runtime.js +37 -32
  368. package/dist/server/server/speech/providers/openai/runtime.js.map +1 -1
  369. package/dist/server/server/speech/providers/openai/stt.d.ts.map +1 -1
  370. package/dist/server/server/speech/providers/openai/stt.js +4 -3
  371. package/dist/server/server/speech/providers/openai/stt.js.map +1 -1
  372. package/dist/server/server/speech/providers/openai/tts.d.ts.map +1 -1
  373. package/dist/server/server/speech/providers/openai/tts.js +3 -2
  374. package/dist/server/server/speech/providers/openai/tts.js.map +1 -1
  375. package/dist/server/server/speech/speech-config-resolver.d.ts.map +1 -1
  376. package/dist/server/server/speech/speech-config-resolver.js +46 -17
  377. package/dist/server/server/speech/speech-config-resolver.js.map +1 -1
  378. package/dist/server/server/speech/speech-provider.d.ts +2 -2
  379. package/dist/server/server/speech/speech-provider.d.ts.map +1 -1
  380. package/dist/server/server/speech/speech-runtime.d.ts +6 -6
  381. package/dist/server/server/speech/speech-runtime.d.ts.map +1 -1
  382. package/dist/server/server/speech/speech-runtime.js +17 -17
  383. package/dist/server/server/speech/speech-runtime.js.map +1 -1
  384. package/dist/server/server/speech/speech-types.d.ts +2 -2
  385. package/dist/server/server/speech/speech-types.d.ts.map +1 -1
  386. package/dist/server/server/speech/turn-detection-provider.d.ts +2 -2
  387. package/dist/server/server/speech/turn-detection-provider.d.ts.map +1 -1
  388. package/dist/server/server/utils/diff-highlighter.d.ts +0 -3
  389. package/dist/server/server/utils/diff-highlighter.d.ts.map +1 -1
  390. package/dist/server/server/utils/diff-highlighter.js +67 -66
  391. package/dist/server/server/utils/diff-highlighter.js.map +1 -1
  392. package/dist/server/server/voice/voice-turn-controller.d.ts.map +1 -1
  393. package/dist/server/server/voice/voice-turn-controller.js +1 -0
  394. package/dist/server/server/voice/voice-turn-controller.js.map +1 -1
  395. package/dist/server/server/voice-types.d.ts +2 -2
  396. package/dist/server/server/voice-types.d.ts.map +1 -1
  397. package/dist/server/server/websocket-server.d.ts +34 -22
  398. package/dist/server/server/websocket-server.d.ts.map +1 -1
  399. package/dist/server/server/websocket-server.js +360 -205
  400. package/dist/server/server/websocket-server.js.map +1 -1
  401. package/dist/server/server/workspace-directory.d.ts +69 -0
  402. package/dist/server/server/workspace-directory.d.ts.map +1 -0
  403. package/dist/server/server/workspace-directory.js +229 -0
  404. package/dist/server/server/workspace-directory.js.map +1 -0
  405. package/dist/server/server/workspace-git-metadata.d.ts +2 -2
  406. package/dist/server/server/workspace-git-metadata.d.ts.map +1 -1
  407. package/dist/server/server/workspace-git-metadata.js +2 -32
  408. package/dist/server/server/workspace-git-metadata.js.map +1 -1
  409. package/dist/server/server/workspace-git-service.d.ts +8 -4
  410. package/dist/server/server/workspace-git-service.d.ts.map +1 -1
  411. package/dist/server/server/workspace-git-service.js +163 -115
  412. package/dist/server/server/workspace-git-service.js.map +1 -1
  413. package/dist/server/server/workspace-reconciliation-service.d.ts +5 -4
  414. package/dist/server/server/workspace-reconciliation-service.d.ts.map +1 -1
  415. package/dist/server/server/workspace-reconciliation-service.js +82 -82
  416. package/dist/server/server/workspace-reconciliation-service.js.map +1 -1
  417. package/dist/server/server/workspace-registry-bootstrap.d.ts.map +1 -1
  418. package/dist/server/server/workspace-registry-bootstrap.js +40 -33
  419. package/dist/server/server/workspace-registry-bootstrap.js.map +1 -1
  420. package/dist/server/server/workspace-registry-model.d.ts +19 -6
  421. package/dist/server/server/workspace-registry-model.d.ts.map +1 -1
  422. package/dist/server/server/workspace-registry-model.js +35 -21
  423. package/dist/server/server/workspace-registry-model.js.map +1 -1
  424. package/dist/server/server/workspace-registry.d.ts +2 -2
  425. package/dist/server/server/workspace-script-runtime-store.d.ts +2 -2
  426. package/dist/server/server/workspace-script-runtime-store.d.ts.map +1 -1
  427. package/dist/server/server/workspace-service-env.js +3 -3
  428. package/dist/server/server/workspace-service-env.js.map +1 -1
  429. package/dist/server/server/worktree-bootstrap.d.ts +4 -4
  430. package/dist/server/server/worktree-bootstrap.d.ts.map +1 -1
  431. package/dist/server/server/worktree-bootstrap.js +101 -69
  432. package/dist/server/server/worktree-bootstrap.js.map +1 -1
  433. package/dist/server/server/worktree-core.d.ts +2 -0
  434. package/dist/server/server/worktree-core.d.ts.map +1 -1
  435. package/dist/server/server/worktree-core.js.map +1 -1
  436. package/dist/server/server/worktree-errors.d.ts +1 -1
  437. package/dist/server/server/worktree-errors.d.ts.map +1 -1
  438. package/dist/server/server/worktree-errors.js +1 -4
  439. package/dist/server/server/worktree-errors.js.map +1 -1
  440. package/dist/server/server/worktree-session.d.ts +54 -27
  441. package/dist/server/server/worktree-session.d.ts.map +1 -1
  442. package/dist/server/server/worktree-session.js +95 -44
  443. package/dist/server/server/worktree-session.js.map +1 -1
  444. package/dist/server/services/github-service.d.ts +1 -7
  445. package/dist/server/services/github-service.d.ts.map +1 -1
  446. package/dist/server/services/github-service.js +123 -143
  447. package/dist/server/services/github-service.js.map +1 -1
  448. package/dist/server/shared/agent-attention-notification.d.ts +9 -8
  449. package/dist/server/shared/agent-attention-notification.d.ts.map +1 -1
  450. package/dist/server/shared/agent-attention-notification.js +27 -17
  451. package/dist/server/shared/agent-attention-notification.js.map +1 -1
  452. package/dist/server/shared/binary-frames/file-transfer.d.ts +56 -0
  453. package/dist/server/shared/binary-frames/file-transfer.d.ts.map +1 -0
  454. package/dist/server/shared/binary-frames/file-transfer.js +108 -0
  455. package/dist/server/shared/binary-frames/file-transfer.js.map +1 -0
  456. package/dist/server/shared/binary-frames/index.d.ts +3 -0
  457. package/dist/server/shared/binary-frames/index.d.ts.map +1 -0
  458. package/dist/server/shared/binary-frames/index.js +3 -0
  459. package/dist/server/shared/binary-frames/index.js.map +1 -0
  460. package/dist/server/shared/{terminal-stream-protocol.d.ts → binary-frames/terminal.d.ts} +4 -4
  461. package/dist/server/shared/binary-frames/terminal.d.ts.map +1 -0
  462. package/dist/server/shared/{terminal-stream-protocol.js → binary-frames/terminal.js} +2 -2
  463. package/dist/server/shared/binary-frames/terminal.js.map +1 -0
  464. package/dist/server/shared/client-capabilities.d.ts +5 -0
  465. package/dist/server/shared/client-capabilities.d.ts.map +1 -0
  466. package/dist/server/shared/client-capabilities.js +4 -0
  467. package/dist/server/shared/client-capabilities.js.map +1 -0
  468. package/dist/server/shared/connection-offer.d.ts +8 -0
  469. package/dist/server/shared/connection-offer.d.ts.map +1 -1
  470. package/dist/server/shared/connection-offer.js +35 -0
  471. package/dist/server/shared/connection-offer.js.map +1 -1
  472. package/dist/server/shared/daemon-endpoints.d.ts +18 -3
  473. package/dist/server/shared/daemon-endpoints.d.ts.map +1 -1
  474. package/dist/server/shared/daemon-endpoints.js +82 -8
  475. package/dist/server/shared/daemon-endpoints.js.map +1 -1
  476. package/dist/server/shared/host-connection-schema.d.ts +23 -0
  477. package/dist/server/shared/host-connection-schema.d.ts.map +1 -0
  478. package/dist/server/shared/host-connection-schema.js +9 -0
  479. package/dist/server/shared/host-connection-schema.js.map +1 -0
  480. package/dist/server/shared/messages.d.ts +25073 -3453
  481. package/dist/server/shared/messages.d.ts.map +1 -1
  482. package/dist/server/shared/messages.js +152 -36
  483. package/dist/server/shared/messages.js.map +1 -1
  484. package/dist/server/shared/tool-call-display.d.ts +2 -2
  485. package/dist/server/shared/tool-call-display.d.ts.map +1 -1
  486. package/dist/server/terminal/terminal-manager-factory.d.ts +7 -0
  487. package/dist/server/terminal/terminal-manager-factory.d.ts.map +1 -0
  488. package/dist/server/terminal/terminal-manager-factory.js +13 -0
  489. package/dist/server/terminal/terminal-manager-factory.js.map +1 -0
  490. package/dist/server/terminal/terminal-manager.d.ts +7 -1
  491. package/dist/server/terminal/terminal-manager.d.ts.map +1 -1
  492. package/dist/server/terminal/terminal-manager.js +15 -4
  493. package/dist/server/terminal/terminal-manager.js.map +1 -1
  494. package/dist/server/terminal/terminal-output-coalescer.d.ts +6 -6
  495. package/dist/server/terminal/terminal-output-coalescer.d.ts.map +1 -1
  496. package/dist/server/terminal/terminal-session-controller.d.ts +63 -0
  497. package/dist/server/terminal/terminal-session-controller.d.ts.map +1 -0
  498. package/dist/server/terminal/terminal-session-controller.js +615 -0
  499. package/dist/server/terminal/terminal-session-controller.js.map +1 -0
  500. package/dist/server/terminal/terminal-ts-loader.mjs +20 -0
  501. package/dist/server/terminal/terminal-worker-process.d.ts +2 -0
  502. package/dist/server/terminal/terminal-worker-process.d.ts.map +1 -0
  503. package/dist/server/terminal/terminal-worker-process.js +221 -0
  504. package/dist/server/terminal/terminal-worker-process.js.map +1 -0
  505. package/dist/server/terminal/terminal-worker-protocol.d.ts +113 -0
  506. package/dist/server/terminal/terminal-worker-protocol.d.ts.map +1 -0
  507. package/dist/server/terminal/terminal-worker-protocol.js +2 -0
  508. package/dist/server/terminal/terminal-worker-protocol.js.map +1 -0
  509. package/dist/server/terminal/terminal.d.ts +10 -2
  510. package/dist/server/terminal/terminal.d.ts.map +1 -1
  511. package/dist/server/terminal/terminal.js +79 -28
  512. package/dist/server/terminal/terminal.js.map +1 -1
  513. package/dist/server/terminal/worker-terminal-manager.d.ts +19 -0
  514. package/dist/server/terminal/worker-terminal-manager.d.ts.map +1 -0
  515. package/dist/server/terminal/worker-terminal-manager.js +466 -0
  516. package/dist/server/terminal/worker-terminal-manager.js.map +1 -0
  517. package/dist/server/utils/checkout-git.d.ts +13 -12
  518. package/dist/server/utils/checkout-git.d.ts.map +1 -1
  519. package/dist/server/utils/checkout-git.js +351 -281
  520. package/dist/server/utils/checkout-git.js.map +1 -1
  521. package/dist/server/utils/directory-suggestions.d.ts.map +1 -1
  522. package/dist/server/utils/directory-suggestions.js +22 -34
  523. package/dist/server/utils/directory-suggestions.js.map +1 -1
  524. package/dist/server/utils/executable.d.ts +1 -14
  525. package/dist/server/utils/executable.d.ts.map +1 -1
  526. package/dist/server/utils/executable.js +13 -49
  527. package/dist/server/utils/executable.js.map +1 -1
  528. package/dist/server/utils/github-remote.d.ts +13 -0
  529. package/dist/server/utils/github-remote.d.ts.map +1 -0
  530. package/dist/server/utils/github-remote.js +128 -0
  531. package/dist/server/utils/github-remote.js.map +1 -0
  532. package/dist/server/utils/paseo-config-file.d.ts +30 -0
  533. package/dist/server/utils/paseo-config-file.d.ts.map +1 -0
  534. package/dist/server/utils/paseo-config-file.js +90 -0
  535. package/dist/server/utils/paseo-config-file.js.map +1 -0
  536. package/dist/server/utils/paseo-config-schema.d.ts +290 -0
  537. package/dist/server/utils/paseo-config-schema.d.ts.map +1 -0
  538. package/dist/server/utils/paseo-config-schema.js +60 -0
  539. package/dist/server/utils/paseo-config-schema.js.map +1 -0
  540. package/dist/server/utils/process-tree.d.ts +25 -0
  541. package/dist/server/utils/process-tree.d.ts.map +1 -0
  542. package/dist/server/utils/process-tree.js +96 -0
  543. package/dist/server/utils/process-tree.js.map +1 -0
  544. package/dist/server/utils/project-icon.d.ts.map +1 -1
  545. package/dist/server/utils/project-icon.js +84 -109
  546. package/dist/server/utils/project-icon.js.map +1 -1
  547. package/dist/server/utils/promise-timeout.d.ts +2 -2
  548. package/dist/server/utils/promise-timeout.d.ts.map +1 -1
  549. package/dist/server/utils/run-git-command.d.ts +3 -1
  550. package/dist/server/utils/run-git-command.d.ts.map +1 -1
  551. package/dist/server/utils/run-git-command.js +10 -1
  552. package/dist/server/utils/run-git-command.js.map +1 -1
  553. package/dist/server/utils/script-hostname.d.ts +2 -2
  554. package/dist/server/utils/script-hostname.d.ts.map +1 -1
  555. package/dist/server/utils/spawn.d.ts +10 -3
  556. package/dist/server/utils/spawn.d.ts.map +1 -1
  557. package/dist/server/utils/spawn.js +30 -5
  558. package/dist/server/utils/spawn.js.map +1 -1
  559. package/dist/server/utils/windows-command.d.ts +15 -0
  560. package/dist/server/utils/windows-command.d.ts.map +1 -0
  561. package/dist/server/utils/windows-command.js +41 -0
  562. package/dist/server/utils/windows-command.js.map +1 -0
  563. package/dist/server/utils/worktree-metadata.d.ts +44 -0
  564. package/dist/server/utils/worktree-metadata.d.ts.map +1 -1
  565. package/dist/server/utils/worktree-metadata.js +58 -0
  566. package/dist/server/utils/worktree-metadata.js.map +1 -1
  567. package/dist/server/utils/worktree.d.ts +23 -8
  568. package/dist/server/utils/worktree.d.ts.map +1 -1
  569. package/dist/server/utils/worktree.js +81 -63
  570. package/dist/server/utils/worktree.js.map +1 -1
  571. package/dist/src/server/pid-lock.js.map +1 -1
  572. package/package.json +17 -21
  573. package/dist/server/server/agent/llm-openai.d.ts +0 -7
  574. package/dist/server/server/agent/llm-openai.d.ts.map +0 -1
  575. package/dist/server/server/agent/llm-openai.js +0 -8
  576. package/dist/server/server/agent/llm-openai.js.map +0 -1
  577. package/dist/server/server/agent/orchestrator.d.ts +0 -12
  578. package/dist/server/server/agent/orchestrator.d.ts.map +0 -1
  579. package/dist/server/server/agent/orchestrator.js +0 -12
  580. package/dist/server/server/agent/orchestrator.js.map +0 -1
  581. package/dist/server/server/types.d.ts +0 -5
  582. package/dist/server/server/types.d.ts.map +0 -1
  583. package/dist/server/server/types.js +0 -3
  584. package/dist/server/server/types.js.map +0 -1
  585. package/dist/server/server/workspace-registry.test-helpers.d.ts +0 -37
  586. package/dist/server/server/workspace-registry.test-helpers.d.ts.map +0 -1
  587. package/dist/server/server/workspace-registry.test-helpers.js +0 -121
  588. package/dist/server/server/workspace-registry.test-helpers.js.map +0 -1
  589. package/dist/server/shared/terminal-stream-protocol.d.ts.map +0 -1
  590. package/dist/server/shared/terminal-stream-protocol.js.map +0 -1
@@ -5,15 +5,17 @@ import os from "node:os";
5
5
  import path from "node:path";
6
6
  import readline from "node:readline";
7
7
  import { z } from "zod";
8
- import { loadCodexPersistedTimeline } from "./codex-rollout-timeline.js";
9
8
  import { renderPromptAttachmentAsText } from "../prompt-attachments.js";
9
+ import { curateAgentActivity } from "../activity-curator.js";
10
10
  import { mapCodexRolloutToolCall, mapCodexToolCallFromThreadItem, } from "./codex/tool-call-mapper.js";
11
- import { applyProviderEnv, resolveProviderCommandPrefix, } from "../provider-launch-config.js";
11
+ import { createProviderEnv, createProviderEnvSpec, resolveProviderCommandPrefix, } from "../provider-launch-config.js";
12
12
  import { findExecutable, isCommandAvailable } from "../../../utils/executable.js";
13
+ import { terminateProcessTree } from "../../../utils/process-tree.js";
13
14
  import { spawnProcess } from "../../../utils/spawn.js";
14
15
  import { extractCodexTerminalSessionId, nonEmptyString } from "./tool-call-mapper-utils.js";
15
16
  import { buildCodexFeatures, codexModelSupportsFastMode } from "./codex-feature-definitions.js";
16
17
  import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, resolveBinaryVersion, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
18
+ import { runProviderTurn } from "./provider-runner.js";
17
19
  const DEFAULT_TIMEOUT_MS = 14 * 24 * 60 * 60 * 1000;
18
20
  const TURN_START_TIMEOUT_MS = 90 * 1000;
19
21
  const INTERRUPT_TIMEOUT_MS = 2000;
@@ -21,6 +23,7 @@ const APP_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT_MS = 2000;
21
23
  const APP_SERVER_FORCE_SHUTDOWN_TIMEOUT_MS = 1000;
22
24
  const CODEX_PROVIDER = "codex";
23
25
  const CODEX_IMAGE_ATTACHMENT_DIR = "paseo-attachments";
26
+ const ASSISTANT_MESSAGE_BOUNDARY_MARKDOWN = "\n\n---\n\n";
24
27
  const CODEX_PLAN_IMPLEMENTATION_PROMPT_PREFIX = "The user approved the plan. Implement it now. Do not restate or revise the plan unless blocked.";
25
28
  const CODEX_APP_SERVER_CAPABILITIES = {
26
29
  supportsStreaming: true,
@@ -96,16 +99,16 @@ function isObjectSchemaNode(schema) {
96
99
  type === "object" ||
97
100
  (Array.isArray(type) && type.includes("object")));
98
101
  }
99
- function normalizeCodexOutputSchemaNode(schema, path) {
102
+ function normalizeCodexOutputSchemaNode(schema, schemaPath) {
100
103
  if (Array.isArray(schema)) {
101
- return schema.map((entry, index) => normalizeCodexOutputSchemaNode(entry, `${path}[${index}]`));
104
+ return schema.map((entry, index) => normalizeCodexOutputSchemaNode(entry, `${schemaPath}[${index}]`));
102
105
  }
103
106
  if (!isSchemaRecord(schema)) {
104
107
  return schema;
105
108
  }
106
109
  const normalized = {};
107
110
  for (const [key, value] of Object.entries(schema)) {
108
- normalized[key] = normalizeCodexOutputSchemaNode(value, `${path}.${key}`);
111
+ normalized[key] = normalizeCodexOutputSchemaNode(value, `${schemaPath}.${key}`);
109
112
  }
110
113
  if (!isObjectSchemaNode(normalized)) {
111
114
  return normalized;
@@ -114,7 +117,7 @@ function normalizeCodexOutputSchemaNode(schema, path) {
114
117
  normalized.additionalProperties = false;
115
118
  }
116
119
  else if (normalized.additionalProperties !== false) {
117
- throw new Error(`Codex structured outputs require ${path} to set additionalProperties to false for object schemas.`);
120
+ throw new Error(`Codex structured outputs require ${schemaPath} to set additionalProperties to false for object schemas.`);
118
121
  }
119
122
  const properties = isSchemaRecord(normalized.properties) ? normalized.properties : null;
120
123
  if (!properties) {
@@ -156,6 +159,29 @@ async function resolveCodexLaunchPrefix(runtimeSettings) {
156
159
  function resolveCodexHomeDir() {
157
160
  return process.env.CODEX_HOME ?? path.join(os.homedir(), ".codex");
158
161
  }
162
+ function decodeEscapedChar(next) {
163
+ if (next === "n")
164
+ return "\n";
165
+ if (next === "t")
166
+ return "\t";
167
+ return next;
168
+ }
169
+ function resolvePermissionDecision(response) {
170
+ if (response.behavior === "allow")
171
+ return "accept";
172
+ if (response.interrupt)
173
+ return "cancel";
174
+ return "decline";
175
+ }
176
+ function firstPositiveFiniteNumber(primary, secondary) {
177
+ if (typeof primary === "number" && Number.isFinite(primary) && primary > 0) {
178
+ return primary;
179
+ }
180
+ if (typeof secondary === "number" && Number.isFinite(secondary) && secondary > 0) {
181
+ return secondary;
182
+ }
183
+ return undefined;
184
+ }
159
185
  function tokenizeCommandArgs(args) {
160
186
  const tokens = [];
161
187
  let current = "";
@@ -171,7 +197,7 @@ function tokenizeCommandArgs(args) {
171
197
  const next = args[i + 1];
172
198
  if (next === quote || next === "\\" || next === "n" || next === "t") {
173
199
  i += 1;
174
- current += next === "n" ? "\n" : next === "t" ? "\t" : next;
200
+ current += decodeEscapedChar(next);
175
201
  continue;
176
202
  }
177
203
  }
@@ -242,35 +268,27 @@ async function listCodexCustomPrompts() {
242
268
  catch {
243
269
  return [];
244
270
  }
245
- const commands = [];
246
- for (const entry of entries) {
247
- if (!entry.isFile()) {
248
- continue;
249
- }
250
- if (!entry.name.endsWith(".md")) {
251
- continue;
252
- }
271
+ const mdEntries = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".md") && entry.name.slice(0, -".md".length));
272
+ const parsedCommands = await Promise.all(mdEntries.map(async (entry) => {
253
273
  const name = entry.name.slice(0, -".md".length);
254
- if (!name) {
255
- continue;
256
- }
257
274
  const fullPath = path.join(promptsDir, entry.name);
258
275
  let content;
259
276
  try {
260
277
  content = await fs.readFile(fullPath, "utf8");
261
278
  }
262
279
  catch {
263
- continue;
280
+ return null;
264
281
  }
265
282
  const parsed = parseFrontMatter(content);
266
283
  const description = parsed.frontMatter["description"] ?? "Custom prompt";
267
284
  const argumentHint = parsed.frontMatter["argument-hint"] ?? parsed.frontMatter["argument_hint"] ?? "";
268
- commands.push({
285
+ return {
269
286
  name: `prompts:${name}`,
270
287
  description,
271
288
  argumentHint,
272
- });
273
- }
289
+ };
290
+ }));
291
+ const commands = parsedCommands.filter((cmd) => cmd !== null);
274
292
  return commands.sort((a, b) => a.name.localeCompare(b.name));
275
293
  }
276
294
  async function listCodexSkills(cwd, workspaceGitService) {
@@ -284,28 +302,30 @@ async function listCodexSkills(cwd, workspaceGitService) {
284
302
  candidates.push(path.join(repoRoot, ".codex", "skills"));
285
303
  }
286
304
  candidates.push(path.join(resolveCodexHomeDir(), "skills"));
287
- const commandsByName = new Map();
288
- for (const dir of candidates) {
305
+ const candidateReads = await Promise.all(candidates.map(async (dir) => {
289
306
  let entries;
290
307
  try {
291
308
  entries = await fs.readdir(dir, { withFileTypes: true });
292
309
  }
293
310
  catch {
294
- continue;
311
+ return [];
295
312
  }
296
- for (const entry of entries) {
297
- if (!entry.isDirectory() && !entry.isSymbolicLink()) {
298
- continue;
299
- }
313
+ const dirEntries = entries.filter((entry) => entry.isDirectory() || entry.isSymbolicLink());
314
+ const skillContents = await Promise.all(dirEntries.map(async (entry) => {
300
315
  const skillDir = path.join(dir, entry.name);
301
316
  const skillPath = path.join(skillDir, "SKILL.md");
302
- let content;
303
317
  try {
304
- content = await fs.readFile(skillPath, "utf8");
318
+ return await fs.readFile(skillPath, "utf8");
305
319
  }
306
320
  catch {
307
- continue;
321
+ return null;
308
322
  }
323
+ }));
324
+ return skillContents.filter((content) => content !== null);
325
+ }));
326
+ const commandsByName = new Map();
327
+ for (const skillContents of candidateReads) {
328
+ for (const content of skillContents) {
309
329
  const { frontMatter } = parseFrontMatter(content);
310
330
  const name = frontMatter["name"];
311
331
  const description = frontMatter["description"];
@@ -389,11 +409,7 @@ class CodexAppServerClient {
389
409
  this.nextId = 1;
390
410
  this.disposed = false;
391
411
  this.stderrBuffer = "";
392
- this.resolveExitPromise = null;
393
412
  this.rl = readline.createInterface({ input: child.stdout });
394
- this.exitPromise = new Promise((resolve) => {
395
- this.resolveExitPromise = resolve;
396
- });
397
413
  this.rl.on("line", (line) => this.handleLine(line));
398
414
  child.stderr.on("data", (chunk) => {
399
415
  this.stderrBuffer += chunk.toString();
@@ -409,8 +425,6 @@ class CodexAppServerClient {
409
425
  }
410
426
  this.pending.clear();
411
427
  this.disposed = true;
412
- this.resolveExitPromise?.();
413
- this.resolveExitPromise = null;
414
428
  });
415
429
  child.on("exit", (code, signal) => {
416
430
  const message = code === 0 && !signal
@@ -423,8 +437,6 @@ class CodexAppServerClient {
423
437
  }
424
438
  this.pending.clear();
425
439
  this.disposed = true;
426
- this.resolveExitPromise?.();
427
- this.resolveExitPromise = null;
428
440
  });
429
441
  }
430
442
  setNotificationHandler(handler) {
@@ -478,31 +490,15 @@ class CodexAppServerClient {
478
490
  catch {
479
491
  // ignore
480
492
  }
481
- signalChildProcessTree(this.child, "SIGTERM");
482
- if (await this.waitForExit(APP_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT_MS)) {
483
- return;
484
- }
485
- this.logger.warn({ timeoutMs: APP_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT_MS }, "Codex app-server did not exit after SIGTERM; sending SIGKILL");
486
- signalChildProcessTree(this.child, "SIGKILL");
487
- if (await this.waitForExit(APP_SERVER_FORCE_SHUTDOWN_TIMEOUT_MS)) {
488
- return;
489
- }
490
- this.logger.warn({ timeoutMs: APP_SERVER_FORCE_SHUTDOWN_TIMEOUT_MS }, "Codex app-server did not report exit after SIGKILL");
491
- }
492
- async waitForExit(timeoutMs) {
493
- let timer = null;
494
- try {
495
- return await Promise.race([
496
- this.exitPromise.then(() => true),
497
- new Promise((resolve) => {
498
- timer = setTimeout(() => resolve(false), timeoutMs);
499
- }),
500
- ]);
501
- }
502
- finally {
503
- if (timer) {
504
- clearTimeout(timer);
505
- }
493
+ const result = await terminateProcessTree(this.child, {
494
+ gracefulTimeoutMs: APP_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT_MS,
495
+ forceTimeoutMs: APP_SERVER_FORCE_SHUTDOWN_TIMEOUT_MS,
496
+ onForceSignal: () => {
497
+ this.logger.warn({ timeoutMs: APP_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT_MS }, "Codex app-server did not exit after SIGTERM; sending SIGKILL");
498
+ },
499
+ });
500
+ if (result === "kill-timeout") {
501
+ this.logger.warn({ timeoutMs: APP_SERVER_FORCE_SHUTDOWN_TIMEOUT_MS }, "Codex app-server did not report exit after SIGKILL");
506
502
  }
507
503
  }
508
504
  async handleLine(line) {
@@ -555,48 +551,12 @@ class CodexAppServerClient {
555
551
  }
556
552
  }
557
553
  }
558
- function signalChildProcessTree(child, signal) {
559
- if (child.exitCode !== null || child.signalCode !== null) {
560
- return;
561
- }
562
- if (process.platform !== "win32" && typeof child.pid === "number" && child.pid > 0) {
563
- try {
564
- process.kill(-child.pid, signal);
565
- return;
566
- }
567
- catch {
568
- // Fall back to the direct child when no separate process group exists.
569
- }
570
- }
571
- try {
572
- child.kill(signal);
573
- }
574
- catch {
575
- // ignore
576
- }
577
- }
578
554
  function toAgentUsage(tokenUsage) {
579
555
  if (!tokenUsage || typeof tokenUsage !== "object")
580
556
  return undefined;
581
557
  const usage = tokenUsage;
582
- const contextWindowMaxTokens = typeof usage.model_context_window === "number" &&
583
- Number.isFinite(usage.model_context_window) &&
584
- usage.model_context_window > 0
585
- ? usage.model_context_window
586
- : typeof usage.modelContextWindow === "number" &&
587
- Number.isFinite(usage.modelContextWindow) &&
588
- usage.modelContextWindow > 0
589
- ? usage.modelContextWindow
590
- : undefined;
591
- const contextWindowUsedTokens = typeof usage.last?.total_tokens === "number" &&
592
- Number.isFinite(usage.last.total_tokens) &&
593
- usage.last.total_tokens > 0
594
- ? usage.last.total_tokens
595
- : typeof usage.last?.totalTokens === "number" &&
596
- Number.isFinite(usage.last.totalTokens) &&
597
- usage.last.totalTokens > 0
598
- ? usage.last.totalTokens
599
- : undefined;
558
+ const contextWindowMaxTokens = firstPositiveFiniteNumber(usage.model_context_window, usage.modelContextWindow);
559
+ const contextWindowUsedTokens = firstPositiveFiniteNumber(usage.last?.total_tokens, usage.last?.totalTokens);
600
560
  return {
601
561
  inputTokens: usage.last?.inputTokens,
602
562
  cachedInputTokens: usage.last?.cachedInputTokens,
@@ -880,6 +840,8 @@ function normalizeCodexThreadItemType(rawType) {
880
840
  return "mcpToolCall";
881
841
  case "WebSearch":
882
842
  return "webSearch";
843
+ case "CollabAgentToolCall":
844
+ return "collabAgentToolCall";
883
845
  default:
884
846
  return rawType;
885
847
  }
@@ -970,8 +932,8 @@ function parseCodexPatchChanges(changes) {
970
932
  ];
971
933
  }
972
934
  return Object.entries(recordChanges)
973
- .map(([path, value]) => {
974
- const normalizedPath = path.trim();
935
+ .map(([entryPath, value]) => {
936
+ const normalizedPath = entryPath.trim();
975
937
  if (!normalizedPath) {
976
938
  return null;
977
939
  }
@@ -1096,11 +1058,7 @@ function mapCodexPatchNotificationToToolCall(params) {
1096
1058
  : {
1097
1059
  ...(files.length > 0
1098
1060
  ? {
1099
- files: files.map((file) => ({
1100
- path: file.path,
1101
- ...(file.kind ? { kind: file.kind } : {}),
1102
- ...codexPatchTextFields(file.content ?? patchText),
1103
- })),
1061
+ files: files.map((file) => Object.assign({ path: file.path }, file.kind ? { kind: file.kind } : {}, codexPatchTextFields(file.content ?? patchText))),
1104
1062
  }
1105
1063
  : {}),
1106
1064
  ...(params.stdout ? { stdout: params.stdout } : {}),
@@ -1139,52 +1097,98 @@ function mapCodexTerminalInteractionToToolCall(params) {
1139
1097
  ...(processId ? { metadata: { processId } } : {}),
1140
1098
  };
1141
1099
  }
1100
+ function mapCodexThreadPlanItem(normalizedItem) {
1101
+ const callId = nonEmptyString(normalizedItem.id ?? normalizedItem.itemId ?? undefined) ??
1102
+ `plan:${normalizePlanMarkdown(typeof normalizedItem.text === "string" ? normalizedItem.text : "")}`;
1103
+ return mapCodexPlanToToolCall({
1104
+ callId,
1105
+ text: typeof normalizedItem.text === "string" ? normalizedItem.text : "",
1106
+ });
1107
+ }
1108
+ function mapCodexThreadReasoningItem(normalizedItem) {
1109
+ const summary = Array.isArray(normalizedItem.summary) ? normalizedItem.summary.join("\n") : "";
1110
+ const content = Array.isArray(normalizedItem.content) ? normalizedItem.content.join("\n") : "";
1111
+ const text = summary || content;
1112
+ return text ? { type: "reasoning", text } : null;
1113
+ }
1114
+ function mapCodexThreadUserMessageItem(normalizedItem, includeUserMessage) {
1115
+ if (!includeUserMessage) {
1116
+ return null;
1117
+ }
1118
+ const text = extractUserText(normalizedItem.content) ?? "";
1119
+ return { type: "user_message", text };
1120
+ }
1142
1121
  function threadItemToTimeline(item, options) {
1143
1122
  if (!item || typeof item !== "object")
1144
1123
  return null;
1124
+ const itemRecord = item;
1145
1125
  const includeUserMessage = options?.includeUserMessage ?? true;
1146
1126
  const cwd = options?.cwd ?? null;
1147
- const normalizedType = normalizeCodexThreadItemType(typeof item.type === "string" ? item.type : undefined);
1148
- const normalizedItem = normalizedType && normalizedType !== item.type
1149
- ? { ...item, type: normalizedType }
1150
- : item;
1127
+ const normalizedType = normalizeCodexThreadItemType(typeof itemRecord.type === "string" ? itemRecord.type : undefined);
1128
+ const normalizedItem = normalizedType && normalizedType !== itemRecord.type
1129
+ ? { ...itemRecord, type: normalizedType }
1130
+ : itemRecord;
1151
1131
  switch (normalizedType) {
1152
- case "userMessage": {
1153
- if (!includeUserMessage) {
1154
- return null;
1155
- }
1156
- const text = extractUserText(normalizedItem.content) ?? "";
1157
- return { type: "user_message", text };
1158
- }
1159
- case "agentMessage": {
1160
- return { type: "assistant_message", text: normalizedItem.text ?? "" };
1161
- }
1162
- case "plan": {
1163
- return mapCodexPlanToToolCall({
1164
- callId: nonEmptyString(normalizedItem.id ?? normalizedItem.itemId ?? undefined) ??
1165
- `plan:${normalizePlanMarkdown(normalizedItem.text ?? "")}`,
1166
- text: normalizedItem.text ?? "",
1167
- });
1168
- }
1169
- case "reasoning": {
1170
- const summary = Array.isArray(normalizedItem.summary)
1171
- ? normalizedItem.summary.join("\n")
1172
- : "";
1173
- const content = Array.isArray(normalizedItem.content)
1174
- ? normalizedItem.content.join("\n")
1175
- : "";
1176
- const text = summary || content;
1177
- return text ? { type: "reasoning", text } : null;
1178
- }
1132
+ case "userMessage":
1133
+ return mapCodexThreadUserMessageItem(normalizedItem, includeUserMessage);
1134
+ case "agentMessage":
1135
+ return {
1136
+ type: "assistant_message",
1137
+ text: typeof normalizedItem.text === "string" ? normalizedItem.text : "",
1138
+ };
1139
+ case "plan":
1140
+ return mapCodexThreadPlanItem(normalizedItem);
1141
+ case "reasoning":
1142
+ return mapCodexThreadReasoningItem(normalizedItem);
1179
1143
  case "commandExecution":
1180
1144
  case "fileChange":
1181
1145
  case "mcpToolCall":
1182
1146
  case "webSearch":
1147
+ case "collabAgentToolCall":
1183
1148
  return mapCodexToolCallFromThreadItem(normalizedItem, { cwd });
1184
1149
  default:
1185
1150
  return null;
1186
1151
  }
1187
1152
  }
1153
+ const CodexThreadReadResponseSchema = z
1154
+ .object({
1155
+ thread: z
1156
+ .object({
1157
+ turns: z
1158
+ .array(z
1159
+ .object({
1160
+ items: z.array(z.unknown()).default([]),
1161
+ })
1162
+ .passthrough())
1163
+ .default([]),
1164
+ })
1165
+ .passthrough()
1166
+ .default({ turns: [] }),
1167
+ })
1168
+ .passthrough();
1169
+ async function requestCodexThreadHistory(requestThread, threadId) {
1170
+ const response = await requestThread(threadId);
1171
+ return CodexThreadReadResponseSchema.parse(response);
1172
+ }
1173
+ async function loadCodexThreadHistoryTimeline(params) {
1174
+ const response = await requestCodexThreadHistory(params.requestThread, params.threadId);
1175
+ const timeline = [];
1176
+ for (const turn of response.thread.turns) {
1177
+ for (const item of turn.items) {
1178
+ const timelineItem = threadItemToTimeline(item, { cwd: params.cwd });
1179
+ if (timelineItem) {
1180
+ timeline.push(timelineItem);
1181
+ }
1182
+ }
1183
+ }
1184
+ return timeline;
1185
+ }
1186
+ function readCodexThread(client, threadId) {
1187
+ return client.request("thread/read", {
1188
+ threadId,
1189
+ includeTurns: true,
1190
+ });
1191
+ }
1188
1192
  function toSandboxPolicy(type, networkAccess) {
1189
1193
  switch (type) {
1190
1194
  case "read-only":
@@ -1231,11 +1235,13 @@ const ThreadStartedNotificationSchema = z
1231
1235
  .passthrough();
1232
1236
  const TurnStartedNotificationSchema = z
1233
1237
  .object({
1238
+ threadId: z.string().optional(),
1234
1239
  turn: z.object({ id: z.string() }).passthrough(),
1235
1240
  })
1236
1241
  .passthrough();
1237
1242
  const TurnCompletedNotificationSchema = z
1238
1243
  .object({
1244
+ threadId: z.string().optional(),
1239
1245
  turn: z
1240
1246
  .object({
1241
1247
  status: z.string(),
@@ -1272,12 +1278,14 @@ const ThreadTokenUsageUpdatedNotificationSchema = z
1272
1278
  .passthrough();
1273
1279
  const ItemTextDeltaNotificationSchema = z
1274
1280
  .object({
1281
+ threadId: z.string().optional(),
1275
1282
  itemId: z.string(),
1276
1283
  delta: z.string(),
1277
1284
  })
1278
1285
  .passthrough();
1279
1286
  const ItemLifecycleNotificationSchema = z
1280
1287
  .object({
1288
+ threadId: z.string().optional(),
1281
1289
  item: z
1282
1290
  .object({
1283
1291
  id: z.string().optional(),
@@ -1307,9 +1315,12 @@ const CodexEventTaskCompleteNotificationSchema = z
1307
1315
  .passthrough();
1308
1316
  const CodexEventItemLifecycleNotificationSchema = z
1309
1317
  .object({
1318
+ threadId: z.string().optional(),
1310
1319
  msg: z
1311
1320
  .object({
1312
1321
  type: z.enum(["item_started", "item_completed"]),
1322
+ threadId: z.string().optional(),
1323
+ thread_id: z.string().optional(),
1313
1324
  item: z
1314
1325
  .object({
1315
1326
  id: z.string().optional(),
@@ -1439,9 +1450,11 @@ const CodexNotificationSchema = z.union([
1439
1450
  method,
1440
1451
  params,
1441
1452
  })),
1442
- z
1443
- .object({ method: z.literal("turn/started"), params: TurnStartedNotificationSchema })
1444
- .transform(({ params }) => ({ kind: "turn_started", turnId: params.turn.id })),
1453
+ z.object({ method: z.literal("turn/started"), params: TurnStartedNotificationSchema }).transform(({ params }) => ({
1454
+ kind: "turn_started",
1455
+ turnId: params.turn.id,
1456
+ threadId: params.threadId ?? null,
1457
+ })),
1445
1458
  z.object({ method: z.literal("turn/started"), params: z.unknown() }).transform(({ method, params }) => ({
1446
1459
  kind: "invalid_payload",
1447
1460
  method,
@@ -1453,6 +1466,7 @@ const CodexNotificationSchema = z.union([
1453
1466
  kind: "turn_completed",
1454
1467
  status: params.turn.status,
1455
1468
  errorMessage: params.turn.error?.message ?? null,
1469
+ threadId: params.threadId ?? null,
1456
1470
  })),
1457
1471
  z.object({ method: z.literal("turn/completed"), params: z.unknown() }).transform(({ method, params }) => ({
1458
1472
  kind: "invalid_payload",
@@ -1504,6 +1518,7 @@ const CodexNotificationSchema = z.union([
1504
1518
  kind: "agent_message_delta",
1505
1519
  itemId: params.itemId,
1506
1520
  delta: params.delta,
1521
+ threadId: params.threadId ?? null,
1507
1522
  })),
1508
1523
  z.object({ method: z.literal("item/agentMessage/delta"), params: z.unknown() }).transform(({ method, params }) => ({
1509
1524
  kind: "invalid_payload",
@@ -1519,6 +1534,7 @@ const CodexNotificationSchema = z.union([
1519
1534
  kind: "reasoning_delta",
1520
1535
  itemId: params.itemId,
1521
1536
  delta: params.delta,
1537
+ threadId: params.threadId ?? null,
1522
1538
  })),
1523
1539
  z.object({ method: z.literal("item/reasoning/summaryTextDelta"), params: z.unknown() }).transform(({ method, params }) => ({
1524
1540
  kind: "invalid_payload",
@@ -1530,6 +1546,7 @@ const CodexNotificationSchema = z.union([
1530
1546
  .transform(({ params }) => ({
1531
1547
  kind: "item_completed",
1532
1548
  source: "item",
1549
+ threadId: params.threadId ?? null,
1533
1550
  item: params.item,
1534
1551
  })),
1535
1552
  z.object({ method: z.literal("item/completed"), params: z.unknown() }).transform(({ method, params }) => ({
@@ -1542,6 +1559,7 @@ const CodexNotificationSchema = z.union([
1542
1559
  .transform(({ params }) => ({
1543
1560
  kind: "item_started",
1544
1561
  source: "item",
1562
+ threadId: params.threadId ?? null,
1545
1563
  item: params.item,
1546
1564
  })),
1547
1565
  z.object({ method: z.literal("item/started"), params: z.unknown() }).transform(({ method, params }) => ({
@@ -1557,6 +1575,7 @@ const CodexNotificationSchema = z.union([
1557
1575
  .transform(({ params }) => ({
1558
1576
  kind: "item_started",
1559
1577
  source: "codex_event",
1578
+ threadId: params.threadId ?? params.msg.threadId ?? params.msg.thread_id ?? null,
1560
1579
  item: params.msg.item,
1561
1580
  })),
1562
1581
  z.object({ method: z.literal("codex/event/item_started"), params: z.unknown() }).transform(({ method, params }) => ({
@@ -1572,6 +1591,7 @@ const CodexNotificationSchema = z.union([
1572
1591
  .transform(({ params }) => ({
1573
1592
  kind: "item_completed",
1574
1593
  source: "codex_event",
1594
+ threadId: params.threadId ?? params.msg.threadId ?? params.msg.thread_id ?? null,
1575
1595
  item: params.msg.item,
1576
1596
  })),
1577
1597
  z.object({ method: z.literal("codex/event/item_completed"), params: z.unknown() }).transform(({ method, params }) => ({
@@ -1756,6 +1776,7 @@ const CodexNotificationSchema = z.union([
1756
1776
  kind: "turn_completed",
1757
1777
  status: "interrupted",
1758
1778
  errorMessage: null,
1779
+ threadId: null,
1759
1780
  })),
1760
1781
  z.object({ method: z.literal("codex/event/turn_aborted"), params: z.unknown() }).transform(({ method, params }) => ({
1761
1782
  kind: "invalid_payload",
@@ -1771,6 +1792,7 @@ const CodexNotificationSchema = z.union([
1771
1792
  kind: "turn_completed",
1772
1793
  status: "completed",
1773
1794
  errorMessage: null,
1795
+ threadId: null,
1774
1796
  })),
1775
1797
  z.object({ method: z.literal("codex/event/task_complete"), params: z.unknown() }).transform(({ method, params }) => ({
1776
1798
  kind: "invalid_payload",
@@ -1821,54 +1843,55 @@ async function readCodexConfiguredDefaults(client, logger) {
1821
1843
  }
1822
1844
  export async function codexAppServerTurnInputFromPrompt(prompt, logger) {
1823
1845
  if (typeof prompt === "string") {
1824
- return [{ type: "text", text: prompt }];
1846
+ return [toCodexTextInput(prompt)];
1825
1847
  }
1826
- const blocks = prompt;
1827
1848
  const output = [];
1828
- for (const block of blocks) {
1829
- if (!block || typeof block !== "object") {
1849
+ let previousTextBlock = false;
1850
+ for (const block of prompt) {
1851
+ if (block.type === "text") {
1852
+ output.push(toCodexTextInput(block.text));
1853
+ previousTextBlock = block.text.length > 0;
1854
+ continue;
1855
+ }
1856
+ if (block.type === "skill") {
1830
1857
  output.push(block);
1858
+ previousTextBlock = false;
1831
1859
  continue;
1832
1860
  }
1833
- const record = block;
1834
- if (record.type === "image" &&
1835
- typeof record.mimeType === "string" &&
1836
- typeof record.data === "string") {
1861
+ if (block.type === "image") {
1837
1862
  try {
1838
- const filePath = await writeImageAttachment(record.mimeType, record.data);
1863
+ const filePath = await writeImageAttachment(block.mimeType, block.data);
1839
1864
  output.push({ type: "localImage", path: filePath });
1840
1865
  }
1841
1866
  catch (error) {
1842
1867
  const message = error instanceof Error ? error.message : String(error);
1843
1868
  logger.warn({ message }, "Failed to write Codex image attachment");
1844
1869
  output.push({
1845
- type: "text",
1846
- text: `User attached image (failed to write temp file): ${message}`,
1870
+ ...toCodexTextInput(`User attached image (failed to write temp file): ${message}`),
1847
1871
  });
1848
1872
  }
1873
+ previousTextBlock = false;
1849
1874
  continue;
1850
1875
  }
1851
- if (record.type === "github_pr" || record.type === "github_issue") {
1852
- output.push({
1853
- type: "text",
1854
- text: renderPromptAttachmentAsText(record),
1855
- });
1856
- continue;
1857
- }
1858
- output.push(block);
1876
+ const attachmentText = renderPromptAttachmentAsText(block);
1877
+ output.push(toCodexTextInput(previousTextBlock ? `\n\n${attachmentText}` : attachmentText));
1878
+ previousTextBlock = true;
1859
1879
  }
1860
1880
  return output;
1861
1881
  }
1862
- function buildCodexAppServerEnv(runtimeSettings, launchEnv) {
1863
- const env = applyProviderEnv(process.env, runtimeSettings);
1864
- if (!launchEnv) {
1865
- return env;
1866
- }
1882
+ function toCodexTextInput(text) {
1867
1883
  return {
1868
- ...env,
1869
- ...launchEnv,
1884
+ type: "text",
1885
+ text,
1886
+ text_elements: [],
1870
1887
  };
1871
1888
  }
1889
+ function buildCodexAppServerEnv(runtimeSettings, launchEnv) {
1890
+ return createProviderEnv({
1891
+ runtimeSettings,
1892
+ overlays: [launchEnv],
1893
+ });
1894
+ }
1872
1895
  function buildCodexAppServerInitializeParams() {
1873
1896
  return {
1874
1897
  clientInfo: {
@@ -1906,6 +1929,7 @@ class CodexAppServerAgentSession {
1906
1929
  this.pendingReasoning = new Map();
1907
1930
  this.pendingCommandOutputDeltas = new Map();
1908
1931
  this.pendingFileChangeOutputDeltas = new Map();
1932
+ this.pendingAssistantMessageBoundary = false;
1909
1933
  this.terminalCommandByProcessId = new Map();
1910
1934
  this.pendingUnlabeledTerminalInteractions = new Set();
1911
1935
  this.emittedTerminalInteractionKeys = new Set();
@@ -1913,6 +1937,8 @@ class CodexAppServerAgentSession {
1913
1937
  this.emittedExecCommandCompletedCallIds = new Set();
1914
1938
  this.emittedItemStartedIds = new Set();
1915
1939
  this.emittedItemCompletedIds = new Set();
1940
+ this.subAgentCallsByCallId = new Map();
1941
+ this.subAgentCallIdByChildThreadId = new Map();
1916
1942
  this.warnedUnknownNotificationMethods = new Set();
1917
1943
  this.warnedInvalidNotificationPayloads = new Set();
1918
1944
  this.warnedIncompleteEditToolCallIds = new Set();
@@ -1963,8 +1989,8 @@ class CodexAppServerAgentSession {
1963
1989
  await this.loadCollaborationModes();
1964
1990
  await this.loadSkills();
1965
1991
  if (this.currentThreadId) {
1966
- await this.loadPersistedHistory();
1967
1992
  await this.ensureThreadLoaded();
1993
+ await this.loadPersistedHistory();
1968
1994
  }
1969
1995
  this.connected = true;
1970
1996
  }
@@ -1975,11 +2001,11 @@ class CodexAppServerAgentSession {
1975
2001
  const response = (await this.client.request("collaborationMode/list", {}));
1976
2002
  const data = Array.isArray(response?.data) ? response.data : [];
1977
2003
  this.collaborationModes = data.map((entry) => ({
1978
- name: String(entry.name ?? ""),
1979
- mode: entry.mode ?? null,
1980
- model: entry.model ?? null,
1981
- reasoning_effort: entry.reasoning_effort ?? null,
1982
- developer_instructions: entry.developer_instructions ?? null,
2004
+ name: typeof entry.name === "string" ? entry.name : "",
2005
+ mode: typeof entry.mode === "string" ? entry.mode : null,
2006
+ model: typeof entry.model === "string" ? entry.model : null,
2007
+ reasoning_effort: typeof entry.reasoning_effort === "string" ? entry.reasoning_effort : null,
2008
+ developer_instructions: typeof entry.developer_instructions === "string" ? entry.developer_instructions : null,
1983
2009
  }));
1984
2010
  }
1985
2011
  catch (error) {
@@ -1998,13 +2024,15 @@ class CodexAppServerAgentSession {
1998
2024
  const entries = Array.isArray(response?.data) ? response.data : [];
1999
2025
  const skills = [];
2000
2026
  for (const entry of entries) {
2001
- const list = Array.isArray(entry.skills) ? entry.skills : [];
2027
+ const list = Array.isArray(entry.skills)
2028
+ ? entry.skills
2029
+ : [];
2002
2030
  for (const skill of list) {
2003
- if (!skill?.name || !skill?.path)
2031
+ if (typeof skill?.name !== "string" || typeof skill?.path !== "string")
2004
2032
  continue;
2005
2033
  skills.push({
2006
2034
  name: skill.name,
2007
- description: skill.description ?? skill.shortDescription ?? "Skill",
2035
+ description: resolveSkillDescription(skill),
2008
2036
  path: skill.path,
2009
2037
  });
2010
2038
  }
@@ -2063,7 +2091,7 @@ class CodexAppServerAgentSession {
2063
2091
  }
2064
2092
  applyFeatureValue(featureId, value) {
2065
2093
  this.config.featureValues = {
2066
- ...(this.config.featureValues ?? {}),
2094
+ ...this.config.featureValues,
2067
2095
  [featureId]: value,
2068
2096
  };
2069
2097
  if (featureId === "fast_mode") {
@@ -2131,37 +2159,16 @@ class CodexAppServerAgentSession {
2131
2159
  async loadPersistedHistory() {
2132
2160
  if (!this.client || !this.currentThreadId)
2133
2161
  return;
2162
+ const client = this.client;
2163
+ const threadId = this.currentThreadId;
2134
2164
  try {
2135
- let rolloutTimeline = [];
2136
- try {
2137
- rolloutTimeline = await loadCodexPersistedTimeline(this.currentThreadId, undefined, this.logger);
2138
- }
2139
- catch {
2140
- rolloutTimeline = [];
2141
- }
2142
- const response = (await this.client.request("thread/read", {
2143
- threadId: this.currentThreadId,
2144
- includeTurns: true,
2145
- }));
2146
- const thread = response?.thread;
2147
- const threadTimeline = [];
2148
- if (thread && Array.isArray(thread.turns)) {
2149
- for (const turn of thread.turns) {
2150
- const items = Array.isArray(turn.items) ? turn.items : [];
2151
- for (const item of items) {
2152
- const timelineItem = threadItemToTimeline(item, {
2153
- cwd: this.config.cwd ?? null,
2154
- });
2155
- if (timelineItem) {
2156
- if (timelineItem.type === "tool_call") {
2157
- this.warnOnIncompleteEditToolCall(timelineItem, "thread_read", item);
2158
- }
2159
- threadTimeline.push(timelineItem);
2160
- }
2161
- }
2162
- }
2163
- }
2164
- const timeline = rolloutTimeline.length > 0 ? rolloutTimeline : threadTimeline;
2165
+ const timeline = await loadCodexThreadHistoryTimeline({
2166
+ threadId,
2167
+ cwd: this.config.cwd ?? null,
2168
+ requestThread: (threadIdToRead) => {
2169
+ return readCodexThread(client, threadIdToRead);
2170
+ },
2171
+ });
2165
2172
  if (timeline.length > 0) {
2166
2173
  this.persistedHistory = timeline;
2167
2174
  this.historyPending = true;
@@ -2258,79 +2265,22 @@ class CodexAppServerAgentSession {
2258
2265
  return args ? `$${commandName} ${args}` : `$${commandName}`;
2259
2266
  }
2260
2267
  async run(prompt, options) {
2261
- const timeline = [];
2262
- let finalText = "";
2263
- let usage;
2264
- let turnId = null;
2265
- const bufferedEvents = [];
2266
- let settled = false;
2267
- let resolveCompletion;
2268
- let rejectCompletion;
2269
- const processEvent = (event) => {
2270
- if (settled) {
2271
- return;
2272
- }
2273
- const eventTurnId = event.turnId;
2274
- if (turnId && eventTurnId && eventTurnId !== turnId) {
2275
- return;
2276
- }
2277
- if (event.type === "timeline") {
2278
- timeline.push(event.item);
2279
- if (event.item.type === "assistant_message") {
2280
- finalText = event.item.text;
2268
+ return runProviderTurn({
2269
+ prompt,
2270
+ runOptions: options,
2271
+ startTurn: (p, o) => this.startTurn(p, o),
2272
+ subscribe: (callback) => this.subscribe(callback),
2273
+ getSessionId: async () => (await this.getRuntimeInfo()).sessionId ?? "",
2274
+ reduceFinalText: ({ current, item }) => {
2275
+ if (item.type === "assistant_message") {
2276
+ return item.text;
2281
2277
  }
2282
- else if (event.item.type === "tool_call" && event.item.detail.type === "plan") {
2283
- finalText = event.item.detail.text;
2278
+ if (item.type === "tool_call" && item.detail.type === "plan") {
2279
+ return item.detail.text;
2284
2280
  }
2285
- return;
2286
- }
2287
- if (event.type === "turn_completed") {
2288
- usage = event.usage;
2289
- settled = true;
2290
- resolveCompletion();
2291
- return;
2292
- }
2293
- if (event.type === "turn_failed") {
2294
- settled = true;
2295
- rejectCompletion(new Error(event.error));
2296
- return;
2297
- }
2298
- if (event.type === "turn_canceled") {
2299
- settled = true;
2300
- resolveCompletion();
2301
- }
2302
- };
2303
- const completion = new Promise((resolve, reject) => {
2304
- resolveCompletion = resolve;
2305
- rejectCompletion = reject;
2306
- });
2307
- const unsubscribe = this.subscribe((event) => {
2308
- if (!turnId) {
2309
- bufferedEvents.push(event);
2310
- return;
2311
- }
2312
- processEvent(event);
2281
+ return current;
2282
+ },
2313
2283
  });
2314
- try {
2315
- const result = await this.startTurn(prompt, options);
2316
- turnId = result.turnId;
2317
- for (const event of bufferedEvents) {
2318
- processEvent(event);
2319
- }
2320
- if (!settled) {
2321
- await completion;
2322
- }
2323
- }
2324
- finally {
2325
- unsubscribe();
2326
- }
2327
- const info = await this.getRuntimeInfo();
2328
- return {
2329
- sessionId: info.sessionId ?? "",
2330
- finalText,
2331
- usage,
2332
- timeline,
2333
- };
2334
2284
  }
2335
2285
  async startTurn(prompt, options) {
2336
2286
  if (this.activeForegroundTurnId) {
@@ -2486,55 +2436,13 @@ class CodexAppServerAgentSession {
2486
2436
  }
2487
2437
  const pendingRequest = this.pendingPermissions.get(requestId) ?? null;
2488
2438
  if (pending.kind === "plan") {
2489
- let followUpPrompt;
2490
- if (response.behavior === "allow") {
2491
- followUpPrompt = this.preparePlanImplementation({
2492
- planText: pending.planText ?? pendingRequest?.metadata?.planText,
2493
- });
2494
- }
2495
- this.pendingPermissionHandlers.delete(requestId);
2496
- this.pendingPermissions.delete(requestId);
2497
- this.resolvedPermissionRequests.add(requestId);
2498
- this.emitEvent({
2499
- type: "permission_resolved",
2500
- provider: CODEX_PROVIDER,
2501
- requestId,
2502
- resolution: response,
2503
- });
2504
- if (followUpPrompt) {
2505
- return { followUpPrompt };
2506
- }
2507
- return;
2439
+ return this.handlePlanPermissionResponse({ requestId, response, pending, pendingRequest });
2508
2440
  }
2509
2441
  this.pendingPermissionHandlers.delete(requestId);
2510
2442
  this.pendingPermissions.delete(requestId);
2511
2443
  this.resolvedPermissionRequests.add(requestId);
2512
2444
  if (response.behavior === "deny" && pendingRequest?.kind === "tool") {
2513
- const fallbackName = pendingRequest.name === "CodexBash"
2514
- ? "shell"
2515
- : pendingRequest.name === "CodexFileChange"
2516
- ? "apply_patch"
2517
- : pendingRequest.name;
2518
- this.emitEvent({
2519
- type: "timeline",
2520
- provider: CODEX_PROVIDER,
2521
- item: {
2522
- type: "tool_call",
2523
- callId: requestId,
2524
- name: fallbackName,
2525
- status: "failed",
2526
- error: { message: response.message ?? "Permission denied" },
2527
- detail: pendingRequest.detail ?? {
2528
- type: "unknown",
2529
- input: pendingRequest.input ?? null,
2530
- output: null,
2531
- },
2532
- metadata: {
2533
- permissionRequestId: requestId,
2534
- denied: true,
2535
- },
2536
- },
2537
- });
2445
+ this.emitDeniedToolCallTimelineEvent({ requestId, response, pendingRequest });
2538
2446
  }
2539
2447
  this.emitEvent({
2540
2448
  type: "permission_resolved",
@@ -2543,13 +2451,11 @@ class CodexAppServerAgentSession {
2543
2451
  resolution: response,
2544
2452
  });
2545
2453
  if (pending.kind === "command") {
2546
- const decision = response.behavior === "allow" ? "accept" : response.interrupt ? "cancel" : "decline";
2547
- pending.resolve({ decision });
2454
+ pending.resolve({ decision: resolvePermissionDecision(response) });
2548
2455
  return;
2549
2456
  }
2550
2457
  if (pending.kind === "file") {
2551
- const decision = response.behavior === "allow" ? "accept" : response.interrupt ? "cancel" : "decline";
2552
- pending.resolve({ decision });
2458
+ pending.resolve({ decision: resolvePermissionDecision(response) });
2553
2459
  return;
2554
2460
  }
2555
2461
  const questions = pending.questions ?? [];
@@ -2593,6 +2499,60 @@ class CodexAppServerAgentSession {
2593
2499
  });
2594
2500
  pending.resolve({ answers: {} });
2595
2501
  }
2502
+ handlePlanPermissionResponse(params) {
2503
+ const { requestId, response, pending, pendingRequest } = params;
2504
+ let followUpPrompt;
2505
+ if (response.behavior === "allow") {
2506
+ followUpPrompt = this.preparePlanImplementation({
2507
+ planText: pending.planText ?? pendingRequest?.metadata?.planText,
2508
+ });
2509
+ }
2510
+ this.pendingPermissionHandlers.delete(requestId);
2511
+ this.pendingPermissions.delete(requestId);
2512
+ this.resolvedPermissionRequests.add(requestId);
2513
+ this.emitEvent({
2514
+ type: "permission_resolved",
2515
+ provider: CODEX_PROVIDER,
2516
+ requestId,
2517
+ resolution: response,
2518
+ });
2519
+ if (followUpPrompt) {
2520
+ return { followUpPrompt };
2521
+ }
2522
+ }
2523
+ emitDeniedToolCallTimelineEvent(params) {
2524
+ const { requestId, response, pendingRequest } = params;
2525
+ let fallbackName;
2526
+ if (pendingRequest.name === "CodexBash") {
2527
+ fallbackName = "shell";
2528
+ }
2529
+ else if (pendingRequest.name === "CodexFileChange") {
2530
+ fallbackName = "apply_patch";
2531
+ }
2532
+ else {
2533
+ fallbackName = pendingRequest.name;
2534
+ }
2535
+ this.emitEvent({
2536
+ type: "timeline",
2537
+ provider: CODEX_PROVIDER,
2538
+ item: {
2539
+ type: "tool_call",
2540
+ callId: requestId,
2541
+ name: fallbackName,
2542
+ status: "failed",
2543
+ error: { message: response.message ?? "Permission denied" },
2544
+ detail: pendingRequest.detail ?? {
2545
+ type: "unknown",
2546
+ input: pendingRequest.input ?? null,
2547
+ output: null,
2548
+ },
2549
+ metadata: {
2550
+ permissionRequestId: requestId,
2551
+ denied: true,
2552
+ },
2553
+ },
2554
+ });
2555
+ }
2596
2556
  describePersistence() {
2597
2557
  if (!this.currentThreadId)
2598
2558
  return null;
@@ -2663,12 +2623,10 @@ class CodexAppServerAgentSession {
2663
2623
  : [];
2664
2624
  return [...appServerSkills, ...fallbackSkills, ...prompts].sort((a, b) => a.name.localeCompare(b.name));
2665
2625
  }
2666
- async ensureThread() {
2667
- if (!this.client)
2668
- return;
2669
- if (this.currentThreadId)
2670
- return;
2671
- // Resolve model + thinking defaults when omitted.
2626
+ async resolveModelAndThinking() {
2627
+ if (!this.client) {
2628
+ throw new Error("Codex client is not initialized");
2629
+ }
2672
2630
  let configuredDefaults = {};
2673
2631
  let model = this.config.model;
2674
2632
  let thinkingOptionId = normalizeCodexThinkingOptionId(this.config.thinkingOptionId);
@@ -2696,6 +2654,17 @@ class CodexAppServerAgentSession {
2696
2654
  thinkingOptionId = normalizeCodexThinkingOptionId(selectedModel.defaultReasoningEffort);
2697
2655
  }
2698
2656
  }
2657
+ if (!model) {
2658
+ throw new Error("Unable to resolve Codex model");
2659
+ }
2660
+ return { model, thinkingOptionId };
2661
+ }
2662
+ async ensureThread() {
2663
+ if (!this.client)
2664
+ return;
2665
+ if (this.currentThreadId)
2666
+ return;
2667
+ const { model, thinkingOptionId } = await this.resolveModelAndThinking();
2699
2668
  this.config.model = model;
2700
2669
  this.config.thinkingOptionId = thinkingOptionId;
2701
2670
  const preset = MODE_PRESETS[this.currentMode] ?? MODE_PRESETS[DEFAULT_CODEX_MODE_ID];
@@ -2734,17 +2703,11 @@ class CodexAppServerAgentSession {
2734
2703
  }
2735
2704
  async buildUserInput(prompt) {
2736
2705
  if (typeof prompt === "string") {
2737
- return [{ type: "text", text: prompt }];
2706
+ return [toCodexTextInput(prompt)];
2738
2707
  }
2739
- const blocks = prompt;
2740
- return await codexAppServerTurnInputFromPrompt(blocks, this.logger);
2708
+ return await codexAppServerTurnInputFromPrompt(prompt, this.logger);
2741
2709
  }
2742
2710
  emitEvent(event) {
2743
- if (event.type === "timeline") {
2744
- if (event.item.type === "assistant_message") {
2745
- this.pendingAgentMessages.clear();
2746
- }
2747
- }
2748
2711
  this.notifySubscribers(event);
2749
2712
  }
2750
2713
  notifySubscribers(event) {
@@ -2764,105 +2727,208 @@ class CodexAppServerAgentSession {
2764
2727
  }
2765
2728
  handleNotification(method, params) {
2766
2729
  const parsed = CodexNotificationSchema.parse({ method, params });
2767
- if (parsed.kind === "thread_started") {
2768
- this.currentThreadId = parsed.threadId;
2769
- this.emitEvent({
2770
- type: "thread_started",
2771
- provider: CODEX_PROVIDER,
2772
- sessionId: parsed.threadId,
2773
- });
2774
- return;
2730
+ switch (parsed.kind) {
2731
+ case "thread_started":
2732
+ this.handleThreadStartedNotification(parsed);
2733
+ return;
2734
+ case "turn_started":
2735
+ this.handleTurnStartedNotification(parsed);
2736
+ return;
2737
+ case "turn_completed":
2738
+ this.handleTurnCompletedNotification(parsed);
2739
+ return;
2740
+ case "plan_updated":
2741
+ this.handlePlanUpdatedNotification(parsed);
2742
+ return;
2743
+ case "diff_updated":
2744
+ // NOTE: Codex app-server emits frequent `turn/diff/updated` notifications
2745
+ // containing a full accumulated unified diff for the *entire turn*.
2746
+ // This is not a concrete file-change tool call; it is progress telemetry.
2747
+ return;
2748
+ case "token_usage_updated":
2749
+ this.handleTokenUsageUpdatedNotification(parsed);
2750
+ return;
2751
+ case "agent_message_delta":
2752
+ case "reasoning_delta":
2753
+ case "exec_command_output_delta":
2754
+ case "file_change_output_delta":
2755
+ this.handleCodexDeltaNotification(parsed);
2756
+ return;
2757
+ case "exec_command_started":
2758
+ this.handleExecCommandStartedNotification(parsed);
2759
+ return;
2760
+ case "exec_command_completed":
2761
+ this.handleExecCommandCompletedNotification(parsed);
2762
+ return;
2763
+ case "terminal_interaction":
2764
+ this.handleTerminalInteractionNotification(parsed);
2765
+ return;
2766
+ case "patch_apply_started":
2767
+ this.handlePatchApplyStartedNotification(parsed);
2768
+ return;
2769
+ case "patch_apply_completed":
2770
+ this.handlePatchApplyCompletedNotification(parsed);
2771
+ return;
2772
+ case "item_completed":
2773
+ this.handleItemCompletedNotification(parsed);
2774
+ return;
2775
+ case "item_started":
2776
+ this.handleItemStartedNotification(parsed);
2777
+ return;
2778
+ case "invalid_payload":
2779
+ this.warnInvalidNotificationPayload(parsed.method, parsed.params);
2780
+ return;
2781
+ default:
2782
+ this.warnUnknownNotificationMethod(parsed.method, parsed.params);
2775
2783
  }
2776
- if (parsed.kind === "turn_started") {
2777
- this.currentTurnId = parsed.turnId;
2778
- this.latestPlanResult = null;
2779
- this.emittedItemStartedIds.clear();
2780
- this.emittedItemCompletedIds.clear();
2781
- this.emittedExecCommandStartedCallIds.clear();
2782
- this.emittedExecCommandCompletedCallIds.clear();
2783
- this.pendingCommandOutputDeltas.clear();
2784
- this.pendingFileChangeOutputDeltas.clear();
2785
- this.warnedIncompleteEditToolCallIds.clear();
2786
- this.emitEvent({ type: "turn_started", provider: CODEX_PROVIDER });
2787
- return;
2784
+ }
2785
+ getSubAgentCallIdForThread(threadId) {
2786
+ if (!threadId || threadId === this.currentThreadId) {
2787
+ return null;
2788
2788
  }
2789
- if (parsed.kind === "turn_completed") {
2790
- if (parsed.status === "failed") {
2791
- this.emitEvent({
2792
- type: "turn_failed",
2793
- provider: CODEX_PROVIDER,
2794
- error: parsed.errorMessage ?? "Codex turn failed",
2795
- });
2796
- }
2797
- else if (parsed.status === "interrupted") {
2798
- this.emitEvent({ type: "turn_canceled", provider: CODEX_PROVIDER, reason: "interrupted" });
2799
- }
2800
- else {
2801
- if (this.planModeEnabled && this.latestPlanResult?.text) {
2802
- this.emitSyntheticPlanApprovalRequest(this.latestPlanResult.text);
2803
- }
2804
- this.emitEvent({
2805
- type: "turn_completed",
2806
- provider: CODEX_PROVIDER,
2807
- usage: this.latestUsage,
2808
- });
2809
- }
2810
- this.activeForegroundTurnId = null;
2811
- this.latestPlanResult = null;
2812
- this.emittedItemStartedIds.clear();
2813
- this.emittedItemCompletedIds.clear();
2814
- this.emittedExecCommandStartedCallIds.clear();
2815
- this.emittedExecCommandCompletedCallIds.clear();
2816
- this.pendingCommandOutputDeltas.clear();
2817
- this.pendingFileChangeOutputDeltas.clear();
2818
- this.warnedIncompleteEditToolCallIds.clear();
2789
+ return this.subAgentCallIdByChildThreadId.get(threadId) ?? null;
2790
+ }
2791
+ registerSubAgentToolCall(timelineItem, rawItem) {
2792
+ if (timelineItem.detail.type !== "sub_agent") {
2819
2793
  return;
2820
2794
  }
2821
- if (parsed.kind === "plan_updated") {
2822
- const timelineItem = mapCodexPlanToToolCall({
2823
- callId: `plan:${this.currentTurnId ?? this.currentThreadId ?? "current"}`,
2824
- text: planStepsToMarkdown(parsed.plan.map((entry) => ({
2825
- step: entry.step ?? "",
2826
- status: entry.status ?? "pending",
2827
- }))),
2828
- });
2829
- if (timelineItem) {
2830
- this.rememberPlanResult(timelineItem);
2831
- this.emitEvent({
2832
- type: "timeline",
2833
- provider: CODEX_PROVIDER,
2834
- item: timelineItem,
2835
- });
2836
- }
2795
+ const existing = this.subAgentCallsByCallId.get(timelineItem.callId);
2796
+ const state = existing ??
2797
+ {
2798
+ callId: timelineItem.callId,
2799
+ toolCall: timelineItem,
2800
+ childItemOrder: [],
2801
+ childItems: new Map(),
2802
+ };
2803
+ state.toolCall = {
2804
+ ...timelineItem,
2805
+ detail: {
2806
+ ...timelineItem.detail,
2807
+ log: timelineItem.detail.log ||
2808
+ (state.toolCall.detail.type === "sub_agent" ? state.toolCall.detail.log : ""),
2809
+ },
2810
+ };
2811
+ this.subAgentCallsByCallId.set(timelineItem.callId, state);
2812
+ const receiverThreadIds = Array.isArray(rawItem.receiverThreadIds)
2813
+ ? rawItem.receiverThreadIds.filter((value) => typeof value === "string")
2814
+ : [];
2815
+ for (const receiverThreadId of receiverThreadIds) {
2816
+ this.subAgentCallIdByChildThreadId.set(receiverThreadId, timelineItem.callId);
2817
+ }
2818
+ }
2819
+ upsertSubAgentChildItem(callId, itemId, item) {
2820
+ const state = this.subAgentCallsByCallId.get(callId);
2821
+ if (!state) {
2837
2822
  return;
2838
2823
  }
2839
- if (parsed.kind === "diff_updated") {
2840
- // NOTE: Codex app-server emits frequent `turn/diff/updated` notifications
2841
- // containing a full accumulated unified diff for the *entire turn*.
2842
- // This is not a concrete file-change tool call; it is progress telemetry.
2843
- // We intentionally do NOT store every diff update in the timeline.
2824
+ if (!state.childItems.has(itemId)) {
2825
+ state.childItemOrder.push(itemId);
2826
+ }
2827
+ state.childItems.set(itemId, item);
2828
+ }
2829
+ getSubAgentChildTimeline(state) {
2830
+ return state.childItemOrder
2831
+ .map((itemId) => state.childItems.get(itemId))
2832
+ .filter((item) => Boolean(item));
2833
+ }
2834
+ emitSubAgentActivityUpdate(callId, status) {
2835
+ const state = this.subAgentCallsByCallId.get(callId);
2836
+ if (!state || state.toolCall.detail.type !== "sub_agent") {
2844
2837
  return;
2845
2838
  }
2846
- if (parsed.kind === "token_usage_updated") {
2847
- this.latestUsage = toAgentUsage(parsed.tokenUsage);
2848
- if (this.latestUsage) {
2849
- this.notifySubscribers({
2850
- type: "usage_updated",
2851
- provider: CODEX_PROVIDER,
2852
- usage: this.latestUsage,
2853
- });
2839
+ const childTimeline = this.getSubAgentChildTimeline(state);
2840
+ const log = childTimeline.length > 0
2841
+ ? curateAgentActivity(childTimeline, { labelAssistantMessages: true })
2842
+ : "";
2843
+ const resolvedStatus = status ?? state.toolCall.status;
2844
+ const baseToolCall = {
2845
+ ...state.toolCall,
2846
+ detail: {
2847
+ ...state.toolCall.detail,
2848
+ log,
2849
+ },
2850
+ };
2851
+ const nextToolCall = resolvedStatus === "failed"
2852
+ ? {
2853
+ ...baseToolCall,
2854
+ status: "failed",
2855
+ error: state.toolCall.error ?? { message: "Sub-agent failed" },
2854
2856
  }
2855
- return;
2857
+ : {
2858
+ ...baseToolCall,
2859
+ status: resolvedStatus,
2860
+ error: null,
2861
+ };
2862
+ state.toolCall = nextToolCall;
2863
+ this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: nextToolCall });
2864
+ }
2865
+ handleSubAgentChildItemCompleted(callId, itemId, timelineItem) {
2866
+ this.applyBufferedDeltaTextToTimelineItem(timelineItem, itemId);
2867
+ if (itemId) {
2868
+ this.upsertSubAgentChildItem(callId, itemId, timelineItem);
2869
+ this.pendingAgentMessages.delete(itemId);
2870
+ this.pendingReasoning.delete(itemId);
2871
+ this.pendingCommandOutputDeltas.delete(itemId);
2872
+ this.pendingFileChangeOutputDeltas.delete(itemId);
2856
2873
  }
2874
+ this.emitSubAgentActivityUpdate(callId, timelineItem.type === "tool_call" && timelineItem.status === "failed" ? "failed" : "running");
2875
+ }
2876
+ shouldSkipCompletedThreadItem(timelineItem, normalizedItemType, itemId) {
2877
+ // For commandExecution items, codex/event/exec_command_* is authoritative.
2878
+ if (timelineItem.type === "tool_call" && normalizedItemType === "commandExecution") {
2879
+ const callId = timelineItem.callId || itemId;
2880
+ return Boolean(callId && this.emittedExecCommandCompletedCallIds.has(callId));
2881
+ }
2882
+ return Boolean(itemId && this.emittedItemCompletedIds.has(itemId));
2883
+ }
2884
+ handleCodexDeltaNotification(parsed) {
2857
2885
  if (parsed.kind === "agent_message_delta") {
2858
2886
  const prev = this.pendingAgentMessages.get(parsed.itemId) ?? "";
2859
- this.pendingAgentMessages.set(parsed.itemId, prev + parsed.delta);
2887
+ const text = prev + parsed.delta;
2888
+ this.pendingAgentMessages.set(parsed.itemId, text);
2889
+ const subAgentCallId = this.getSubAgentCallIdForThread(parsed.threadId);
2890
+ if (subAgentCallId) {
2891
+ this.upsertSubAgentChildItem(subAgentCallId, parsed.itemId, {
2892
+ type: "assistant_message",
2893
+ text,
2894
+ });
2895
+ this.emitSubAgentActivityUpdate(subAgentCallId, "running");
2896
+ return;
2897
+ }
2898
+ const isFirstDeltaForItem = prev.length === 0;
2899
+ this.emitEvent({
2900
+ type: "timeline",
2901
+ provider: CODEX_PROVIDER,
2902
+ item: {
2903
+ type: "assistant_message",
2904
+ text: isFirstDeltaForItem && this.pendingAssistantMessageBoundary
2905
+ ? `${ASSISTANT_MESSAGE_BOUNDARY_MARKDOWN}${parsed.delta}`
2906
+ : parsed.delta,
2907
+ },
2908
+ });
2909
+ if (isFirstDeltaForItem) {
2910
+ this.pendingAssistantMessageBoundary = false;
2911
+ }
2860
2912
  return;
2861
2913
  }
2862
2914
  if (parsed.kind === "reasoning_delta") {
2863
2915
  const prev = this.pendingReasoning.get(parsed.itemId) ?? [];
2864
2916
  prev.push(parsed.delta);
2865
2917
  this.pendingReasoning.set(parsed.itemId, prev);
2918
+ const subAgentCallId = this.getSubAgentCallIdForThread(parsed.threadId);
2919
+ if (subAgentCallId) {
2920
+ this.upsertSubAgentChildItem(subAgentCallId, parsed.itemId, {
2921
+ type: "reasoning",
2922
+ text: prev.join(""),
2923
+ });
2924
+ this.emitSubAgentActivityUpdate(subAgentCallId, "running");
2925
+ return;
2926
+ }
2927
+ this.emitEvent({
2928
+ type: "timeline",
2929
+ provider: CODEX_PROVIDER,
2930
+ item: { type: "reasoning", text: parsed.delta },
2931
+ });
2866
2932
  return;
2867
2933
  }
2868
2934
  if (parsed.kind === "exec_command_output_delta") {
@@ -2871,192 +2937,340 @@ class CodexAppServerAgentSession {
2871
2937
  });
2872
2938
  return;
2873
2939
  }
2874
- if (parsed.kind === "file_change_output_delta") {
2875
- this.appendOutputDeltaChunk(this.pendingFileChangeOutputDeltas, parsed.itemId, parsed.delta);
2940
+ this.appendOutputDeltaChunk(this.pendingFileChangeOutputDeltas, parsed.itemId, parsed.delta);
2941
+ }
2942
+ handleThreadStartedNotification(parsed) {
2943
+ this.currentThreadId = parsed.threadId;
2944
+ this.emitEvent({
2945
+ type: "thread_started",
2946
+ provider: CODEX_PROVIDER,
2947
+ sessionId: parsed.threadId,
2948
+ });
2949
+ }
2950
+ handleTurnStartedNotification(parsed) {
2951
+ const subAgentCallId = this.getSubAgentCallIdForThread(parsed.threadId);
2952
+ if (subAgentCallId) {
2953
+ this.emitSubAgentActivityUpdate(subAgentCallId, "running");
2876
2954
  return;
2877
2955
  }
2878
- if (parsed.kind === "exec_command_started") {
2879
- if (parsed.callId) {
2880
- this.emittedExecCommandStartedCallIds.add(parsed.callId);
2881
- this.pendingCommandOutputDeltas.delete(parsed.callId);
2956
+ this.currentTurnId = parsed.turnId;
2957
+ this.resetTurnTrackingState();
2958
+ this.emitEvent({ type: "turn_started", provider: CODEX_PROVIDER });
2959
+ }
2960
+ handleTurnCompletedNotification(parsed) {
2961
+ const subAgentCallId = this.getSubAgentCallIdForThread(parsed.threadId);
2962
+ if (subAgentCallId) {
2963
+ let status = "completed";
2964
+ if (parsed.status === "failed") {
2965
+ status = "failed";
2882
2966
  }
2883
- const timelineItem = mapCodexExecNotificationToToolCall({
2884
- callId: parsed.callId,
2885
- command: parsed.command,
2886
- cwd: parsed.cwd ?? this.config.cwd ?? null,
2887
- running: true,
2888
- });
2889
- if (timelineItem) {
2890
- this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
2967
+ else if (parsed.status === "interrupted") {
2968
+ status = "canceled";
2891
2969
  }
2970
+ this.emitSubAgentActivityUpdate(subAgentCallId, status);
2892
2971
  return;
2893
2972
  }
2894
- if (parsed.kind === "exec_command_completed") {
2895
- const bufferedOutput = this.consumeOutputDelta(this.pendingCommandOutputDeltas, parsed.callId);
2896
- const resolvedOutput = parsed.output ?? bufferedOutput;
2897
- this.rememberTerminalProcessForCommand(parsed.command, resolvedOutput);
2898
- const timelineItem = mapCodexExecNotificationToToolCall({
2899
- callId: parsed.callId,
2900
- command: parsed.command,
2901
- cwd: parsed.cwd ?? this.config.cwd ?? null,
2902
- output: resolvedOutput,
2903
- exitCode: parsed.exitCode,
2904
- success: parsed.success,
2905
- stderr: parsed.stderr,
2906
- running: false,
2973
+ if (parsed.status === "failed") {
2974
+ this.emitEvent({
2975
+ type: "turn_failed",
2976
+ provider: CODEX_PROVIDER,
2977
+ error: parsed.errorMessage ?? "Codex turn failed",
2907
2978
  });
2908
- if (timelineItem) {
2909
- this.emittedExecCommandCompletedCallIds.add(timelineItem.callId);
2910
- this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
2979
+ }
2980
+ else if (parsed.status === "interrupted") {
2981
+ this.emitEvent({ type: "turn_canceled", provider: CODEX_PROVIDER, reason: "interrupted" });
2982
+ }
2983
+ else {
2984
+ if (this.planModeEnabled && this.latestPlanResult?.text) {
2985
+ this.emitSyntheticPlanApprovalRequest(this.latestPlanResult.text);
2911
2986
  }
2912
- return;
2987
+ this.emitEvent({
2988
+ type: "turn_completed",
2989
+ provider: CODEX_PROVIDER,
2990
+ usage: this.latestUsage,
2991
+ });
2913
2992
  }
2914
- if (parsed.kind === "terminal_interaction") {
2915
- const interactionKey = [parsed.processId ?? "", parsed.stdin ?? ""].join("\u0000");
2916
- if (!this.shouldEmitTerminalInteractionKey(interactionKey)) {
2993
+ this.activeForegroundTurnId = null;
2994
+ this.resetTurnTrackingState();
2995
+ }
2996
+ resetTurnTrackingState() {
2997
+ this.latestPlanResult = null;
2998
+ this.emittedItemStartedIds.clear();
2999
+ this.emittedItemCompletedIds.clear();
3000
+ this.emittedExecCommandStartedCallIds.clear();
3001
+ this.emittedExecCommandCompletedCallIds.clear();
3002
+ this.pendingAgentMessages.clear();
3003
+ this.pendingReasoning.clear();
3004
+ this.pendingCommandOutputDeltas.clear();
3005
+ this.pendingFileChangeOutputDeltas.clear();
3006
+ this.pendingAssistantMessageBoundary = false;
3007
+ this.warnedIncompleteEditToolCallIds.clear();
3008
+ }
3009
+ handlePlanUpdatedNotification(parsed) {
3010
+ const timelineItem = mapCodexPlanToToolCall({
3011
+ callId: `plan:${this.currentTurnId ?? this.currentThreadId ?? "current"}`,
3012
+ text: planStepsToMarkdown(parsed.plan.map((entry) => ({
3013
+ step: entry.step ?? "",
3014
+ status: entry.status ?? "pending",
3015
+ }))),
3016
+ });
3017
+ if (timelineItem) {
3018
+ this.rememberPlanResult(timelineItem);
3019
+ // In plan mode, the same plan is rendered through the synthetic approval
3020
+ // permission. Keep the remembered text for that card, but do not also
3021
+ // emit a static timeline plan panel.
3022
+ if (this.planModeEnabled) {
2917
3023
  return;
2918
3024
  }
2919
- const command = (parsed.processId ? this.terminalCommandByProcessId.get(parsed.processId) : undefined) ??
2920
- null;
2921
- if (!command && parsed.processId) {
2922
- this.pendingUnlabeledTerminalInteractions.add(parsed.processId);
2923
- }
2924
- const timelineItem = mapCodexTerminalInteractionToToolCall({
2925
- processId: parsed.processId,
2926
- fallbackCallId: parsed.callId,
2927
- command,
3025
+ this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
3026
+ }
3027
+ }
3028
+ handleTokenUsageUpdatedNotification(parsed) {
3029
+ this.latestUsage = toAgentUsage(parsed.tokenUsage);
3030
+ if (this.latestUsage) {
3031
+ this.notifySubscribers({
3032
+ type: "usage_updated",
3033
+ provider: CODEX_PROVIDER,
3034
+ usage: this.latestUsage,
2928
3035
  });
3036
+ }
3037
+ }
3038
+ handleExecCommandStartedNotification(parsed) {
3039
+ if (parsed.callId) {
3040
+ this.emittedExecCommandStartedCallIds.add(parsed.callId);
3041
+ this.pendingCommandOutputDeltas.delete(parsed.callId);
3042
+ }
3043
+ const timelineItem = mapCodexExecNotificationToToolCall({
3044
+ callId: parsed.callId,
3045
+ command: parsed.command,
3046
+ cwd: parsed.cwd ?? this.config.cwd ?? null,
3047
+ running: true,
3048
+ });
3049
+ if (timelineItem) {
3050
+ this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
3051
+ }
3052
+ }
3053
+ handleExecCommandCompletedNotification(parsed) {
3054
+ const bufferedOutput = this.consumeOutputDelta(this.pendingCommandOutputDeltas, parsed.callId);
3055
+ const resolvedOutput = parsed.output ?? bufferedOutput;
3056
+ this.rememberTerminalProcessForCommand(parsed.command, resolvedOutput);
3057
+ const timelineItem = mapCodexExecNotificationToToolCall({
3058
+ callId: parsed.callId,
3059
+ command: parsed.command,
3060
+ cwd: parsed.cwd ?? this.config.cwd ?? null,
3061
+ output: resolvedOutput,
3062
+ exitCode: parsed.exitCode,
3063
+ success: parsed.success,
3064
+ stderr: parsed.stderr,
3065
+ running: false,
3066
+ });
3067
+ if (timelineItem) {
3068
+ this.emittedExecCommandCompletedCallIds.add(timelineItem.callId);
2929
3069
  this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
3070
+ }
3071
+ }
3072
+ handleTerminalInteractionNotification(parsed) {
3073
+ const interactionKey = [parsed.processId ?? "", parsed.stdin ?? ""].join("\u0000");
3074
+ if (!this.shouldEmitTerminalInteractionKey(interactionKey)) {
2930
3075
  return;
2931
3076
  }
2932
- if (parsed.kind === "patch_apply_started") {
2933
- if (parsed.callId) {
2934
- this.pendingFileChangeOutputDeltas.delete(parsed.callId);
2935
- }
2936
- const timelineItem = mapCodexPatchNotificationToToolCall({
3077
+ const command = (parsed.processId ? this.terminalCommandByProcessId.get(parsed.processId) : undefined) ??
3078
+ null;
3079
+ if (!command && parsed.processId) {
3080
+ this.pendingUnlabeledTerminalInteractions.add(parsed.processId);
3081
+ }
3082
+ const timelineItem = mapCodexTerminalInteractionToToolCall({
3083
+ processId: parsed.processId,
3084
+ fallbackCallId: parsed.callId,
3085
+ command,
3086
+ });
3087
+ this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
3088
+ }
3089
+ handlePatchApplyStartedNotification(parsed) {
3090
+ if (parsed.callId) {
3091
+ this.pendingFileChangeOutputDeltas.delete(parsed.callId);
3092
+ }
3093
+ const timelineItem = mapCodexPatchNotificationToToolCall({
3094
+ callId: parsed.callId,
3095
+ changes: parsed.changes,
3096
+ cwd: this.config.cwd ?? null,
3097
+ running: true,
3098
+ });
3099
+ if (timelineItem) {
3100
+ this.warnOnIncompleteEditToolCall(timelineItem, "patch_apply_started", {
2937
3101
  callId: parsed.callId,
2938
3102
  changes: parsed.changes,
2939
- cwd: this.config.cwd ?? null,
2940
- running: true,
2941
3103
  });
2942
- if (timelineItem) {
2943
- this.warnOnIncompleteEditToolCall(timelineItem, "patch_apply_started", {
2944
- callId: parsed.callId,
2945
- changes: parsed.changes,
2946
- });
2947
- this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
2948
- }
2949
- return;
3104
+ this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
2950
3105
  }
2951
- if (parsed.kind === "patch_apply_completed") {
2952
- const bufferedOutput = this.consumeOutputDelta(this.pendingFileChangeOutputDeltas, parsed.callId);
2953
- const timelineItem = mapCodexPatchNotificationToToolCall({
3106
+ }
3107
+ handlePatchApplyCompletedNotification(parsed) {
3108
+ const bufferedOutput = this.consumeOutputDelta(this.pendingFileChangeOutputDeltas, parsed.callId);
3109
+ const timelineItem = mapCodexPatchNotificationToToolCall({
3110
+ callId: parsed.callId,
3111
+ changes: parsed.changes,
3112
+ cwd: this.config.cwd ?? null,
3113
+ stdout: parsed.stdout ?? bufferedOutput,
3114
+ stderr: parsed.stderr,
3115
+ success: parsed.success,
3116
+ running: false,
3117
+ });
3118
+ if (timelineItem) {
3119
+ this.warnOnIncompleteEditToolCall(timelineItem, "patch_apply_completed", {
2954
3120
  callId: parsed.callId,
2955
3121
  changes: parsed.changes,
2956
- cwd: this.config.cwd ?? null,
2957
- stdout: parsed.stdout ?? bufferedOutput,
2958
- stderr: parsed.stderr,
2959
- success: parsed.success,
2960
- running: false,
3122
+ stdout: parsed.stdout,
2961
3123
  });
2962
- if (timelineItem) {
2963
- this.warnOnIncompleteEditToolCall(timelineItem, "patch_apply_completed", {
2964
- callId: parsed.callId,
2965
- changes: parsed.changes,
2966
- stdout: parsed.stdout,
2967
- });
2968
- this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
2969
- }
3124
+ this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
3125
+ }
3126
+ }
3127
+ handleItemCompletedNotification(parsed) {
3128
+ // Codex emits mirrored lifecycle notifications via both `codex/event/item_*`
3129
+ // and canonical `item/*`. We render only the canonical channel to avoid
3130
+ // duplicated assistant/reasoning rows.
3131
+ if (parsed.source === "codex_event") {
2970
3132
  return;
2971
3133
  }
2972
- if (parsed.kind === "item_completed") {
2973
- // Codex emits mirrored lifecycle notifications via both `codex/event/item_*`
2974
- // and canonical `item/*`. We render only the canonical channel to avoid
2975
- // duplicated assistant/reasoning rows.
2976
- if (parsed.source === "codex_event") {
2977
- return;
3134
+ const timelineItem = threadItemToTimeline(parsed.item, {
3135
+ includeUserMessage: false,
3136
+ cwd: this.config.cwd ?? null,
3137
+ });
3138
+ if (!timelineItem) {
3139
+ return;
3140
+ }
3141
+ const childSubAgentCallId = this.getSubAgentCallIdForThread(parsed.threadId);
3142
+ if (childSubAgentCallId) {
3143
+ this.handleSubAgentChildItemCompleted(childSubAgentCallId, parsed.item.id, timelineItem);
3144
+ return;
3145
+ }
3146
+ const normalizedItemType = normalizeCodexThreadItemType(typeof parsed.item.type === "string" ? parsed.item.type : undefined);
3147
+ const itemId = parsed.item.id;
3148
+ if (this.shouldSkipCompletedThreadItem(timelineItem, normalizedItemType, itemId)) {
3149
+ return;
3150
+ }
3151
+ if (this.consumeStreamedTextCompletion(timelineItem, itemId)) {
3152
+ if (timelineItem.type === "assistant_message") {
3153
+ this.pendingAssistantMessageBoundary = true;
2978
3154
  }
2979
- const timelineItem = threadItemToTimeline(parsed.item, {
2980
- includeUserMessage: false,
2981
- cwd: this.config.cwd ?? null,
2982
- });
2983
- if (timelineItem) {
2984
- const normalizedItemType = normalizeCodexThreadItemType(typeof parsed.item.type === "string" ? parsed.item.type : undefined);
2985
- const itemId = parsed.item.id;
2986
- // For commandExecution items, codex/event/exec_command_* is authoritative.
2987
- // Keep item/completed as fallback only when no exec_command completion was seen.
2988
- if (timelineItem.type === "tool_call" && normalizedItemType === "commandExecution") {
2989
- const callId = timelineItem.callId || itemId;
2990
- if (callId && this.emittedExecCommandCompletedCallIds.has(callId)) {
2991
- return;
2992
- }
2993
- }
2994
- if (itemId && this.emittedItemCompletedIds.has(itemId)) {
3155
+ if (itemId) {
3156
+ this.emittedItemCompletedIds.add(itemId);
3157
+ this.emittedItemStartedIds.delete(itemId);
3158
+ }
3159
+ return;
3160
+ }
3161
+ this.applyBufferedDeltaTextToTimelineItem(timelineItem, itemId);
3162
+ if (timelineItem.type === "tool_call") {
3163
+ this.registerSubAgentToolCall(timelineItem, parsed.item);
3164
+ if (timelineItem.detail.type === "plan") {
3165
+ this.rememberPlanResult(timelineItem);
3166
+ // Codex can surface plans both as turn/plan updates and as completed
3167
+ // thread items. In plan mode, approval owns the visible plan card.
3168
+ if (this.planModeEnabled) {
2995
3169
  return;
2996
3170
  }
2997
- if (timelineItem.type === "assistant_message" && itemId) {
2998
- const buffered = this.pendingAgentMessages.get(itemId);
2999
- if (buffered && buffered.length > 0) {
3000
- timelineItem.text = buffered;
3001
- }
3002
- }
3003
- if (timelineItem.type === "reasoning" && itemId) {
3004
- const buffered = this.pendingReasoning.get(itemId);
3005
- if (buffered && buffered.length > 0) {
3006
- timelineItem.text = buffered.join("");
3007
- }
3008
- }
3009
- if (timelineItem.type === "tool_call") {
3010
- if (timelineItem.detail.type === "plan") {
3011
- this.rememberPlanResult(timelineItem);
3012
- }
3013
- this.warnOnIncompleteEditToolCall(timelineItem, "item_completed", parsed.item);
3014
- }
3015
- this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
3016
- if (itemId) {
3017
- this.emittedItemCompletedIds.add(itemId);
3018
- this.emittedItemStartedIds.delete(itemId);
3019
- this.pendingCommandOutputDeltas.delete(itemId);
3020
- this.pendingFileChangeOutputDeltas.delete(itemId);
3021
- }
3022
3171
  }
3172
+ this.warnOnIncompleteEditToolCall(timelineItem, "item_completed", parsed.item);
3173
+ }
3174
+ this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
3175
+ if (timelineItem.type === "assistant_message") {
3176
+ this.pendingAssistantMessageBoundary = true;
3177
+ }
3178
+ if (itemId) {
3179
+ this.emittedItemCompletedIds.add(itemId);
3180
+ this.emittedItemStartedIds.delete(itemId);
3181
+ this.pendingCommandOutputDeltas.delete(itemId);
3182
+ this.pendingFileChangeOutputDeltas.delete(itemId);
3183
+ }
3184
+ }
3185
+ consumeStreamedTextCompletion(timelineItem, itemId) {
3186
+ if (!itemId) {
3187
+ return false;
3188
+ }
3189
+ if (timelineItem.type === "assistant_message" && this.pendingAgentMessages.has(itemId)) {
3190
+ const streamedText = this.pendingAgentMessages.get(itemId) ?? "";
3191
+ this.pendingAgentMessages.delete(itemId);
3192
+ this.emitMissingFinalTextSuffix(timelineItem, streamedText);
3193
+ return true;
3194
+ }
3195
+ if (timelineItem.type === "reasoning" && this.pendingReasoning.has(itemId)) {
3196
+ const streamedText = this.pendingReasoning.get(itemId)?.join("") ?? "";
3197
+ this.pendingReasoning.delete(itemId);
3198
+ this.emitMissingFinalTextSuffix(timelineItem, streamedText);
3199
+ return true;
3200
+ }
3201
+ return false;
3202
+ }
3203
+ emitMissingFinalTextSuffix(timelineItem, streamedText) {
3204
+ if (!timelineItem.text.startsWith(streamedText)) {
3205
+ this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
3023
3206
  return;
3024
3207
  }
3025
- if (parsed.kind === "item_started") {
3026
- if (parsed.source === "codex_event") {
3027
- return;
3208
+ const suffix = timelineItem.text.slice(streamedText.length);
3209
+ if (!suffix) {
3210
+ return;
3211
+ }
3212
+ this.emitEvent({
3213
+ type: "timeline",
3214
+ provider: CODEX_PROVIDER,
3215
+ item: { type: timelineItem.type, text: suffix },
3216
+ });
3217
+ }
3218
+ applyBufferedDeltaTextToTimelineItem(timelineItem, itemId) {
3219
+ if (!itemId) {
3220
+ return;
3221
+ }
3222
+ if (timelineItem.type === "assistant_message") {
3223
+ const buffered = this.pendingAgentMessages.get(itemId);
3224
+ if (buffered && buffered.length > 0) {
3225
+ timelineItem.text = buffered;
3028
3226
  }
3029
- const timelineItem = threadItemToTimeline(parsed.item, {
3030
- includeUserMessage: false,
3031
- cwd: this.config.cwd ?? null,
3032
- });
3033
- if (timelineItem && timelineItem.type === "tool_call") {
3034
- const normalizedItemType = normalizeCodexThreadItemType(typeof parsed.item.type === "string" ? parsed.item.type : undefined);
3035
- const itemId = parsed.item.id;
3036
- if (normalizedItemType === "commandExecution") {
3037
- const callId = timelineItem.callId || itemId;
3038
- if (callId && this.emittedExecCommandStartedCallIds.has(callId)) {
3039
- return;
3040
- }
3041
- }
3042
- if (itemId && this.emittedItemStartedIds.has(itemId)) {
3043
- return;
3044
- }
3045
- this.warnOnIncompleteEditToolCall(timelineItem, "item_started", parsed.item);
3046
- this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
3047
- if (itemId) {
3048
- this.emittedItemStartedIds.add(itemId);
3049
- this.pendingCommandOutputDeltas.delete(itemId);
3050
- this.pendingFileChangeOutputDeltas.delete(itemId);
3051
- }
3227
+ return;
3228
+ }
3229
+ if (timelineItem.type === "reasoning") {
3230
+ const buffered = this.pendingReasoning.get(itemId);
3231
+ if (buffered && buffered.length > 0) {
3232
+ timelineItem.text = buffered.join("");
3233
+ }
3234
+ }
3235
+ }
3236
+ handleItemStartedNotification(parsed) {
3237
+ if (parsed.source === "codex_event") {
3238
+ return;
3239
+ }
3240
+ const timelineItem = threadItemToTimeline(parsed.item, {
3241
+ includeUserMessage: false,
3242
+ cwd: this.config.cwd ?? null,
3243
+ });
3244
+ if (!timelineItem || timelineItem.type !== "tool_call") {
3245
+ return;
3246
+ }
3247
+ const childSubAgentCallId = this.getSubAgentCallIdForThread(parsed.threadId);
3248
+ if (childSubAgentCallId) {
3249
+ if (parsed.item.id) {
3250
+ this.upsertSubAgentChildItem(childSubAgentCallId, parsed.item.id, timelineItem);
3052
3251
  }
3252
+ this.emitSubAgentActivityUpdate(childSubAgentCallId, "running");
3053
3253
  return;
3054
3254
  }
3055
- if (parsed.kind === "invalid_payload") {
3056
- this.warnInvalidNotificationPayload(parsed.method, parsed.params);
3255
+ const normalizedItemType = normalizeCodexThreadItemType(typeof parsed.item.type === "string" ? parsed.item.type : undefined);
3256
+ const itemId = parsed.item.id;
3257
+ if (normalizedItemType === "commandExecution") {
3258
+ const callId = timelineItem.callId || itemId;
3259
+ if (callId && this.emittedExecCommandStartedCallIds.has(callId)) {
3260
+ return;
3261
+ }
3262
+ }
3263
+ if (itemId && this.emittedItemStartedIds.has(itemId)) {
3057
3264
  return;
3058
3265
  }
3059
- this.warnUnknownNotificationMethod(parsed.method, parsed.params);
3266
+ this.warnOnIncompleteEditToolCall(timelineItem, "item_started", parsed.item);
3267
+ this.registerSubAgentToolCall(timelineItem, parsed.item);
3268
+ this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
3269
+ if (itemId) {
3270
+ this.emittedItemStartedIds.add(itemId);
3271
+ this.pendingCommandOutputDeltas.delete(itemId);
3272
+ this.pendingFileChangeOutputDeltas.delete(itemId);
3273
+ }
3060
3274
  }
3061
3275
  warnUnknownNotificationMethod(method, params) {
3062
3276
  if (this.warnedUnknownNotificationMethods.has(method)) {
@@ -3280,7 +3494,10 @@ export class CodexAppServerAgentClient {
3280
3494
  return spawnProcess(launchPrefix.command, [...launchPrefix.args, "app-server"], {
3281
3495
  detached: process.platform !== "win32",
3282
3496
  stdio: ["pipe", "pipe", "pipe"],
3283
- env: buildCodexAppServerEnv(this.runtimeSettings, launchEnv),
3497
+ ...createProviderEnvSpec({
3498
+ runtimeSettings: this.runtimeSettings,
3499
+ overlays: [launchEnv],
3500
+ }),
3284
3501
  });
3285
3502
  }
3286
3503
  async createSession(config, launchContext) {
@@ -3310,38 +3527,31 @@ export class CodexAppServerAgentClient {
3310
3527
  const limit = options?.limit ?? 20;
3311
3528
  const response = (await client.request("thread/list", { limit }));
3312
3529
  const threads = Array.isArray(response?.data) ? response.data : [];
3313
- const descriptors = [];
3314
- for (const thread of threads.slice(0, limit)) {
3315
- const threadId = thread.id;
3316
- const cwd = thread.cwd ?? process.cwd();
3317
- const title = thread.preview ?? null;
3530
+ const descriptors = await Promise.all(threads.slice(0, limit).map(async (thread) => {
3531
+ const threadId = typeof thread.id === "string" ? thread.id : "";
3532
+ const cwd = typeof thread.cwd === "string" ? thread.cwd : process.cwd();
3533
+ const title = typeof thread.preview === "string" ? thread.preview : null;
3318
3534
  let timeline = [];
3319
3535
  try {
3320
- const rolloutTimeline = await loadCodexPersistedTimeline(threadId, undefined, this.logger);
3321
- const read = (await client.request("thread/read", {
3536
+ timeline = await loadCodexThreadHistoryTimeline({
3322
3537
  threadId,
3323
- includeTurns: true,
3324
- }));
3325
- const turns = read.thread?.turns ?? [];
3326
- const itemsFromThreadRead = [];
3327
- for (const turn of turns) {
3328
- for (const item of turn.items ?? []) {
3329
- const timelineItem = threadItemToTimeline(item, { cwd });
3330
- if (timelineItem)
3331
- itemsFromThreadRead.push(timelineItem);
3332
- }
3333
- }
3334
- timeline = rolloutTimeline.length > 0 ? rolloutTimeline : itemsFromThreadRead;
3538
+ cwd,
3539
+ requestThread: (threadIdToRead) => {
3540
+ return readCodexThread(client, threadIdToRead);
3541
+ },
3542
+ });
3335
3543
  }
3336
3544
  catch {
3337
3545
  timeline = [];
3338
3546
  }
3339
- descriptors.push({
3547
+ return {
3340
3548
  provider: CODEX_PROVIDER,
3341
3549
  sessionId: threadId,
3342
3550
  cwd,
3343
3551
  title,
3344
- lastActivityAt: new Date((thread.updatedAt ?? thread.createdAt ?? 0) * 1000),
3552
+ lastActivityAt: new Date(((typeof thread.updatedAt === "number" ? thread.updatedAt : undefined) ??
3553
+ (typeof thread.createdAt === "number" ? thread.createdAt : undefined) ??
3554
+ 0) * 1000),
3345
3555
  persistence: {
3346
3556
  provider: CODEX_PROVIDER,
3347
3557
  sessionId: threadId,
@@ -3354,8 +3564,8 @@ export class CodexAppServerAgentClient {
3354
3564
  },
3355
3565
  },
3356
3566
  timeline,
3357
- });
3358
- }
3567
+ };
3568
+ }));
3359
3569
  return descriptors;
3360
3570
  }
3361
3571
  finally {
@@ -3377,55 +3587,11 @@ export class CodexAppServerAgentClient {
3377
3587
  const hasConfiguredDefaultModel = typeof configuredDefaultModelId === "string"
3378
3588
  ? models.some((model) => model?.id === configuredDefaultModelId)
3379
3589
  : false;
3380
- return models.map((model) => {
3381
- const defaultReasoningEffort = normalizeCodexThinkingOptionId(typeof model.defaultReasoningEffort === "string" ? model.defaultReasoningEffort : null);
3382
- const resolvedDefaultReasoningEffort = configuredDefaultThinkingOptionId ?? defaultReasoningEffort;
3383
- const thinkingById = new Map();
3384
- if (Array.isArray(model.supportedReasoningEfforts)) {
3385
- for (const entry of model.supportedReasoningEfforts) {
3386
- const id = normalizeCodexThinkingOptionId(typeof entry?.reasoningEffort === "string" ? entry.reasoningEffort : null);
3387
- if (!id)
3388
- continue;
3389
- const description = typeof entry?.description === "string" && entry.description.trim().length > 0
3390
- ? entry.description
3391
- : undefined;
3392
- thinkingById.set(id, { id, label: id, description });
3393
- }
3394
- }
3395
- if (resolvedDefaultReasoningEffort && !thinkingById.has(resolvedDefaultReasoningEffort)) {
3396
- thinkingById.set(resolvedDefaultReasoningEffort, {
3397
- id: resolvedDefaultReasoningEffort,
3398
- label: resolvedDefaultReasoningEffort,
3399
- description: configuredDefaultThinkingOptionId === resolvedDefaultReasoningEffort
3400
- ? "Configured default reasoning effort"
3401
- : "Model default reasoning effort",
3402
- });
3403
- }
3404
- const thinkingOptions = Array.from(thinkingById.values()).map((option) => ({
3405
- ...option,
3406
- isDefault: option.id === resolvedDefaultReasoningEffort,
3407
- }));
3408
- const defaultThinkingOptionId = resolvedDefaultReasoningEffort ??
3409
- thinkingOptions.find((option) => option.isDefault)?.id ??
3410
- thinkingOptions[0]?.id;
3411
- const isDefaultModel = hasConfiguredDefaultModel
3412
- ? model.id === configuredDefaultModelId
3413
- : model.isDefault;
3414
- return {
3415
- provider: CODEX_PROVIDER,
3416
- id: model.id,
3417
- label: normalizeCodexModelLabel(model.displayName),
3418
- description: model.description,
3419
- isDefault: isDefaultModel,
3420
- thinkingOptions: thinkingOptions.length > 0 ? thinkingOptions : undefined,
3421
- defaultThinkingOptionId,
3422
- metadata: {
3423
- model: model.model,
3424
- defaultReasoningEffort: model.defaultReasoningEffort,
3425
- supportedReasoningEfforts: model.supportedReasoningEfforts,
3426
- },
3427
- };
3428
- });
3590
+ return models.map((model) => buildCodexModelDefinition(model, {
3591
+ configuredDefaultModelId,
3592
+ configuredDefaultThinkingOptionId,
3593
+ hasConfiguredDefaultModel,
3594
+ }));
3429
3595
  }
3430
3596
  finally {
3431
3597
  await client.dispose();
@@ -3484,6 +3650,67 @@ export class CodexAppServerAgentClient {
3484
3650
  }
3485
3651
  }
3486
3652
  }
3653
+ function buildCodexModelDefinition(model, ctx) {
3654
+ const defaultReasoningEffort = normalizeCodexThinkingOptionId(typeof model.defaultReasoningEffort === "string" ? model.defaultReasoningEffort : null);
3655
+ const resolvedDefaultReasoningEffort = ctx.configuredDefaultThinkingOptionId ?? defaultReasoningEffort;
3656
+ const thinkingById = buildCodexThinkingOptionMap(model.supportedReasoningEfforts, resolvedDefaultReasoningEffort, ctx.configuredDefaultThinkingOptionId);
3657
+ const thinkingOptions = Array.from(thinkingById.values()).map((option) => Object.assign({}, option, {
3658
+ isDefault: option.id === resolvedDefaultReasoningEffort,
3659
+ }));
3660
+ const defaultThinkingOptionId = resolvedDefaultReasoningEffort ??
3661
+ thinkingOptions.find((option) => option.isDefault)?.id ??
3662
+ thinkingOptions[0]?.id;
3663
+ const isDefaultModel = ctx.hasConfiguredDefaultModel
3664
+ ? model.id === ctx.configuredDefaultModelId
3665
+ : model.isDefault;
3666
+ return {
3667
+ provider: CODEX_PROVIDER,
3668
+ id: model.id,
3669
+ label: normalizeCodexModelLabel(model.displayName ?? ""),
3670
+ description: model.description,
3671
+ isDefault: isDefaultModel,
3672
+ thinkingOptions: thinkingOptions.length > 0 ? thinkingOptions : undefined,
3673
+ defaultThinkingOptionId,
3674
+ metadata: {
3675
+ model: model.model,
3676
+ defaultReasoningEffort: model.defaultReasoningEffort,
3677
+ supportedReasoningEfforts: model.supportedReasoningEfforts,
3678
+ },
3679
+ };
3680
+ }
3681
+ function buildCodexThinkingOptionMap(supportedReasoningEfforts, resolvedDefaultReasoningEffort, configuredDefaultThinkingOptionId) {
3682
+ const thinkingById = new Map();
3683
+ if (Array.isArray(supportedReasoningEfforts)) {
3684
+ for (const entry of supportedReasoningEfforts) {
3685
+ const id = normalizeCodexThinkingOptionId(typeof entry?.reasoningEffort === "string" ? entry.reasoningEffort : null);
3686
+ if (!id)
3687
+ continue;
3688
+ const description = typeof entry?.description === "string" && entry.description.trim().length > 0
3689
+ ? entry.description
3690
+ : undefined;
3691
+ thinkingById.set(id, { id, label: id, description });
3692
+ }
3693
+ }
3694
+ if (resolvedDefaultReasoningEffort && !thinkingById.has(resolvedDefaultReasoningEffort)) {
3695
+ thinkingById.set(resolvedDefaultReasoningEffort, {
3696
+ id: resolvedDefaultReasoningEffort,
3697
+ label: resolvedDefaultReasoningEffort,
3698
+ description: configuredDefaultThinkingOptionId === resolvedDefaultReasoningEffort
3699
+ ? "Configured default reasoning effort"
3700
+ : "Model default reasoning effort",
3701
+ });
3702
+ }
3703
+ return thinkingById;
3704
+ }
3705
+ function resolveSkillDescription(skill) {
3706
+ if (typeof skill.description === "string") {
3707
+ return skill.description;
3708
+ }
3709
+ if (typeof skill.shortDescription === "string") {
3710
+ return skill.shortDescription;
3711
+ }
3712
+ return "Skill";
3713
+ }
3487
3714
  export const __codexAppServerInternals = {
3488
3715
  buildCodexAppServerEnv,
3489
3716
  CodexAppServerClient,