@jingyi0605/codingns 0.5.5 → 0.6.1

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 (257) hide show
  1. package/bin/codingns.mjs +15 -2
  2. package/dist/public/assets/{AdaptiveButlerPage-CUyNL98E.js → AdaptiveButlerPage-Dw72U3hG.js} +3 -3
  3. package/dist/public/assets/App-CcDXqFl1.css +1 -0
  4. package/dist/public/assets/{App-BFP7LCSC.js → App-Dsf3ooXU.js} +3 -3
  5. package/dist/public/assets/{BootstrapPage-G74dX2Us.js → BootstrapPage-CE0m1qSR.js} +1 -1
  6. package/dist/public/assets/ConversationPage-8wOY7SX-.js +4 -0
  7. package/dist/public/assets/{DesktopDetachPreviewPage-IV7oEdOX.js → DesktopDetachPreviewPage-Dxarr_Wf.js} +1 -1
  8. package/dist/public/assets/DesktopWindowPage-VytPwJ4c.js +2 -0
  9. package/dist/public/assets/FileContextPanel-DwFzLsOp.js +1 -0
  10. package/dist/public/assets/GitSidebar-CH6WqTrM.js +6 -0
  11. package/dist/public/assets/MobileCreateSessionSheet-DcxKM00P.js +1 -0
  12. package/dist/public/assets/{MobileTopHeaderFrame-COTc7cRr.js → MobileTopHeaderFrame-C5rIKQT6.js} +1 -1
  13. package/dist/public/assets/MobileWorkspaceSwitcherHeader-CfUnHgv_.js +1 -0
  14. package/dist/public/assets/RelayConnectEntryPage-CgMvVZwa.js +1 -0
  15. package/dist/public/assets/ServerSettingsModal-CFul__z1.js +1 -0
  16. package/dist/public/assets/SessionIndexPage-B-tRhBXC.js +1 -0
  17. package/dist/public/assets/SettingsPage-C9LGxSQZ.js +1 -0
  18. package/dist/public/assets/TerminalManagerPanel-BbORd-ee.js +1 -0
  19. package/dist/public/assets/{TerminalPage-DpsvQQVR.js → TerminalPage-DWHv6mlu.js} +19 -19
  20. package/dist/public/assets/TerminalRuntimeFallbackModal-B29YxbQe.js +1 -0
  21. package/dist/public/assets/ToolFilesPage-Dx9cv9hu.js +1 -0
  22. package/dist/public/assets/ToolGitPage-D7H3vAia.js +1 -0
  23. package/dist/public/assets/ToolProcessesPage-PqQWxsy-.js +1 -0
  24. package/dist/public/assets/ToolsHomePage-CX05Pe_4.js +1 -0
  25. package/dist/public/assets/WorkbenchLandingPage-CchkAC75.js +1 -0
  26. package/dist/public/assets/WorkbenchLayout-pOZvEqp7.js +3 -0
  27. package/dist/public/assets/{WorkbenchModal-CbDxaCOR.js → WorkbenchModal-ColqvV6a.js} +1 -1
  28. package/dist/public/assets/WorkbenchShellRoute-C0_h4lP6.js +1 -0
  29. package/dist/public/assets/WorkbenchShellRoute-RGZpA0_J.css +1 -0
  30. package/dist/public/assets/WorkspaceDebugDetailPage-Deqy2_pO.js +1 -0
  31. package/dist/public/assets/WorkspaceDetailPage-Cvf-ZdlB.js +1 -0
  32. package/dist/public/assets/WorkspaceHomePage-Dsyvqyk1.js +1 -0
  33. package/dist/public/assets/client-runtime-manager-DROQJ9v3.js +1 -0
  34. package/dist/public/assets/{file-tree-icon-BMKuc5pw.js → file-tree-icon-Bp3Ntt7u.js} +7 -7
  35. package/dist/public/assets/index-B84Po2NA.css +1 -0
  36. package/dist/public/assets/index-C-0oeG_5.js +42 -0
  37. package/dist/public/assets/legna-code-6TqgZ4Ls.png +0 -0
  38. package/dist/public/assets/login-direct-candidate-resolver-DotM530R.js +1 -0
  39. package/dist/public/assets/model-switch-api-Bh9nYslz.js +1 -0
  40. package/dist/public/assets/{preferences-service-gv_9vGKz.js → preferences-service-BG6GKG29.js} +1 -1
  41. package/dist/public/assets/relay-entry-pmr-c42O.js +1 -0
  42. package/dist/public/assets/session-runtime-machine-YN84QBlr.js +21 -0
  43. package/dist/public/assets/{styles-BWPBZvze.css → styles-CsEMfdaS.css} +1 -1
  44. package/dist/public/assets/{terminal-runtime-meta-B9xJGY__.js → terminal-runtime-meta-8_uRZf7h.js} +1 -1
  45. package/dist/public/assets/useRegisteredDebugTemplates-DWX7LXQu.js +1 -0
  46. package/dist/public/assets/window-BVUB8gMK.js +1 -0
  47. package/dist/public/index.html +2 -2
  48. package/dist/server/config/env.d.ts +3 -0
  49. package/dist/server/config/env.js +10 -0
  50. package/dist/server/config/env.js.map +1 -1
  51. package/dist/server/modules/client/npm-global-package-service.d.ts +7 -1
  52. package/dist/server/modules/client/npm-global-package-service.js +149 -43
  53. package/dist/server/modules/client/npm-global-package-service.js.map +1 -1
  54. package/dist/server/modules/client/service-update-task-service.js +6 -2
  55. package/dist/server/modules/client/service-update-task-service.js.map +1 -1
  56. package/dist/server/modules/client/service-update-types.d.ts +2 -0
  57. package/dist/server/modules/git/git-controller.d.ts +3 -0
  58. package/dist/server/modules/git/git-controller.js +3 -0
  59. package/dist/server/modules/git/git-controller.js.map +1 -1
  60. package/dist/server/modules/git/git-read-service.js +47 -1
  61. package/dist/server/modules/git/git-read-service.js.map +1 -1
  62. package/dist/server/modules/git/git-write-service.d.ts +4 -0
  63. package/dist/server/modules/git/git-write-service.js +24 -0
  64. package/dist/server/modules/git/git-write-service.js.map +1 -1
  65. package/dist/server/modules/git/types.d.ts +1 -0
  66. package/dist/server/modules/git/workspace-repo-guard.d.ts +2 -0
  67. package/dist/server/modules/git/workspace-repo-guard.js +24 -10
  68. package/dist/server/modules/git/workspace-repo-guard.js.map +1 -1
  69. package/dist/server/modules/model-switch/cc-switch-adapter.d.ts +7 -0
  70. package/dist/server/modules/model-switch/cc-switch-adapter.js +17 -0
  71. package/dist/server/modules/model-switch/cc-switch-adapter.js.map +1 -1
  72. package/dist/server/modules/parallel-sessions/parallel-session-controller.d.ts +57 -0
  73. package/dist/server/modules/parallel-sessions/parallel-session-controller.js +77 -0
  74. package/dist/server/modules/parallel-sessions/parallel-session-controller.js.map +1 -0
  75. package/dist/server/modules/parallel-sessions/parallel-session-group-service.d.ts +88 -0
  76. package/dist/server/modules/parallel-sessions/parallel-session-group-service.js +625 -0
  77. package/dist/server/modules/parallel-sessions/parallel-session-group-service.js.map +1 -0
  78. package/dist/server/modules/parallel-sessions/session-isolated-workspace-service.d.ts +56 -0
  79. package/dist/server/modules/parallel-sessions/session-isolated-workspace-service.js +483 -0
  80. package/dist/server/modules/parallel-sessions/session-isolated-workspace-service.js.map +1 -0
  81. package/dist/server/modules/provider/opencode-model-options.d.ts +1 -0
  82. package/dist/server/modules/provider/opencode-model-options.js +54 -12
  83. package/dist/server/modules/provider/opencode-model-options.js.map +1 -1
  84. package/dist/server/modules/provider/provider-controller.d.ts +6 -1
  85. package/dist/server/modules/provider/provider-controller.js +24 -2
  86. package/dist/server/modules/provider/provider-controller.js.map +1 -1
  87. package/dist/server/modules/provider/provider-discovery-helper-client.d.ts +2 -0
  88. package/dist/server/modules/provider/provider-discovery-helper-client.js.map +1 -1
  89. package/dist/server/modules/provider/provider-discovery-helper-process.js +1 -1
  90. package/dist/server/modules/provider/provider-discovery-helper-process.js.map +1 -1
  91. package/dist/server/modules/provider/provider-discovery-runtime.js +5 -1
  92. package/dist/server/modules/provider/provider-discovery-runtime.js.map +1 -1
  93. package/dist/server/modules/relay-tunnel/relay-tunnel-candidate-endpoints.d.ts +2 -0
  94. package/dist/server/modules/relay-tunnel/relay-tunnel-candidate-endpoints.js +129 -0
  95. package/dist/server/modules/relay-tunnel/relay-tunnel-candidate-endpoints.js.map +1 -0
  96. package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.js +12 -9
  97. package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.js.map +1 -1
  98. package/dist/server/modules/relay-tunnel/relay-tunnel-service.js +1 -128
  99. package/dist/server/modules/relay-tunnel/relay-tunnel-service.js.map +1 -1
  100. package/dist/server/modules/sessions/claude-runtime-helper-client.d.ts +1 -0
  101. package/dist/server/modules/sessions/claude-runtime-helper-client.js +14 -0
  102. package/dist/server/modules/sessions/claude-runtime-helper-client.js.map +1 -1
  103. package/dist/server/modules/sessions/codex-app-server-helper-client.d.ts +4 -0
  104. package/dist/server/modules/sessions/codex-app-server-helper-client.js +66 -45
  105. package/dist/server/modules/sessions/codex-app-server-helper-client.js.map +1 -1
  106. package/dist/server/modules/sessions/codex-app-server-helper-process.js +21 -2
  107. package/dist/server/modules/sessions/codex-app-server-helper-process.js.map +1 -1
  108. package/dist/server/modules/sessions/provider-session-delete-cli.js +2 -0
  109. package/dist/server/modules/sessions/provider-session-delete-cli.js.map +1 -1
  110. package/dist/server/modules/sessions/session-controller.d.ts +7 -0
  111. package/dist/server/modules/sessions/session-controller.js +22 -0
  112. package/dist/server/modules/sessions/session-controller.js.map +1 -1
  113. package/dist/server/modules/sessions/session-history-service.d.ts +21 -2
  114. package/dist/server/modules/sessions/session-history-service.js +425 -29
  115. package/dist/server/modules/sessions/session-history-service.js.map +1 -1
  116. package/dist/server/modules/sessions/session-live-runtime-service.d.ts +23 -2
  117. package/dist/server/modules/sessions/session-live-runtime-service.js +472 -74
  118. package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
  119. package/dist/server/modules/sessions/session-message-attachment-service.js +2 -2
  120. package/dist/server/modules/sessions/session-message-attachment-service.js.map +1 -1
  121. package/dist/server/modules/sessions/session-provider-config-service.d.ts +66 -0
  122. package/dist/server/modules/sessions/session-provider-config-service.js +821 -0
  123. package/dist/server/modules/sessions/session-provider-config-service.js.map +1 -0
  124. package/dist/server/modules/sessions/session-provider-error-mapper.d.ts +2 -0
  125. package/dist/server/modules/sessions/session-provider-error-mapper.js +42 -0
  126. package/dist/server/modules/sessions/session-provider-error-mapper.js.map +1 -1
  127. package/dist/server/modules/workbench/codex-archive-watcher.d.ts +16 -0
  128. package/dist/server/modules/workbench/codex-archive-watcher.js +50 -0
  129. package/dist/server/modules/workbench/codex-archive-watcher.js.map +1 -0
  130. package/dist/server/modules/workbench/workbench-service.d.ts +11 -2
  131. package/dist/server/modules/workbench/workbench-service.js +37 -8
  132. package/dist/server/modules/workbench/workbench-service.js.map +1 -1
  133. package/dist/server/modules/workbench/workspace-panel-snapshot-service.d.ts +1 -1
  134. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js +26 -3
  135. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js.map +1 -1
  136. package/dist/server/modules/workspace/workspace-service.d.ts +3 -1
  137. package/dist/server/modules/workspace/workspace-service.js +10 -2
  138. package/dist/server/modules/workspace/workspace-service.js.map +1 -1
  139. package/dist/server/modules/worktree/worktree-base-ref-resolver.d.ts +20 -0
  140. package/dist/server/modules/worktree/worktree-base-ref-resolver.js +111 -0
  141. package/dist/server/modules/worktree/worktree-base-ref-resolver.js.map +1 -0
  142. package/dist/server/modules/worktree/worktree-cleanup-service.js +9 -3
  143. package/dist/server/modules/worktree/worktree-cleanup-service.js.map +1 -1
  144. package/dist/server/modules/worktree/worktree-manager.d.ts +0 -1
  145. package/dist/server/modules/worktree/worktree-manager.js +14 -20
  146. package/dist/server/modules/worktree/worktree-manager.js.map +1 -1
  147. package/dist/server/routes/git.js +1 -0
  148. package/dist/server/routes/git.js.map +1 -1
  149. package/dist/server/routes/parallel-groups.d.ts +3 -0
  150. package/dist/server/routes/parallel-groups.js +9 -0
  151. package/dist/server/routes/parallel-groups.js.map +1 -0
  152. package/dist/server/server/create-server.d.ts +8 -0
  153. package/dist/server/server/create-server.js +48 -11
  154. package/dist/server/server/create-server.js.map +1 -1
  155. package/dist/server/server/workbench-runtime-terminal-sync.d.ts +14 -0
  156. package/dist/server/server/workbench-runtime-terminal-sync.js +17 -0
  157. package/dist/server/server/workbench-runtime-terminal-sync.js.map +1 -0
  158. package/dist/server/storage/repositories/parallel-session-group-repository.d.ts +11 -0
  159. package/dist/server/storage/repositories/parallel-session-group-repository.js +131 -0
  160. package/dist/server/storage/repositories/parallel-session-group-repository.js.map +1 -0
  161. package/dist/server/storage/repositories/parallel-session-member-repository.d.ts +12 -0
  162. package/dist/server/storage/repositories/parallel-session-member-repository.js +150 -0
  163. package/dist/server/storage/repositories/parallel-session-member-repository.js.map +1 -0
  164. package/dist/server/storage/repositories/session-binding-repository.js +44 -5
  165. package/dist/server/storage/repositories/session-binding-repository.js.map +1 -1
  166. package/dist/server/storage/repositories/session-index-repository.js +6 -0
  167. package/dist/server/storage/repositories/session-index-repository.js.map +1 -1
  168. package/dist/server/storage/repositories/session-isolated-workspace-repository.d.ts +15 -0
  169. package/dist/server/storage/repositories/session-isolated-workspace-repository.js +230 -0
  170. package/dist/server/storage/repositories/session-isolated-workspace-repository.js.map +1 -0
  171. package/dist/server/storage/sqlite/client.js +19 -0
  172. package/dist/server/storage/sqlite/client.js.map +1 -1
  173. package/dist/server/storage/sqlite/schema.sql +78 -0
  174. package/dist/server/types/domain.d.ts +78 -0
  175. package/dist/server/ws/workbench-ws-hub.d.ts +3 -1
  176. package/dist/server/ws/workbench-ws-hub.js +23 -4
  177. package/dist/server/ws/workbench-ws-hub.js.map +1 -1
  178. package/node_modules/@codingns/session-sync-core/dist/claude-message-utils.d.ts +5 -2
  179. package/node_modules/@codingns/session-sync-core/dist/claude-message-utils.js +40 -8
  180. package/node_modules/@codingns/session-sync-core/dist/claude-message-utils.js.map +1 -1
  181. package/node_modules/@codingns/session-sync-core/dist/index.d.ts +2 -0
  182. package/node_modules/@codingns/session-sync-core/dist/index.js +2 -0
  183. package/node_modules/@codingns/session-sync-core/dist/index.js.map +1 -1
  184. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.d.ts +10 -1
  185. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js +110 -35
  186. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js.map +1 -1
  187. package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.d.ts +11 -0
  188. package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js +105 -0
  189. package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js.map +1 -0
  190. package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +1 -0
  191. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +34 -0
  192. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
  193. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js +131 -39
  194. package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js.map +1 -1
  195. package/node_modules/@codingns/session-sync-core/dist/providers/legna-code.d.ts +9 -0
  196. package/node_modules/@codingns/session-sync-core/dist/providers/legna-code.js +17 -0
  197. package/node_modules/@codingns/session-sync-core/dist/providers/legna-code.js.map +1 -0
  198. package/node_modules/@codingns/session-sync-core/dist/providers/opencode-shared.d.ts +8 -1
  199. package/node_modules/@codingns/session-sync-core/dist/providers/opencode-shared.js +19 -6
  200. package/node_modules/@codingns/session-sync-core/dist/providers/opencode-shared.js.map +1 -1
  201. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.d.ts +1 -0
  202. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js +13 -8
  203. package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js.map +1 -1
  204. package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.d.ts +3 -0
  205. package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js +46 -22
  206. package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js.map +1 -1
  207. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.d.ts +5 -1
  208. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js +103 -51
  209. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js.map +1 -1
  210. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.d.ts +2 -1
  211. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +528 -301
  212. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
  213. package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.js +32 -8
  214. package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.js.map +1 -1
  215. package/node_modules/@codingns/session-sync-core/dist/runtime/legna-runtime.d.ts +10 -0
  216. package/node_modules/@codingns/session-sync-core/dist/runtime/legna-runtime.js +16 -0
  217. package/node_modules/@codingns/session-sync-core/dist/runtime/legna-runtime.js.map +1 -0
  218. package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.js +196 -15
  219. package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.js.map +1 -1
  220. package/node_modules/@codingns/session-sync-core/dist/runtime/types.d.ts +2 -0
  221. package/node_modules/@codingns/session-sync-core/dist/types.d.ts +1 -1
  222. package/node_modules/@codingns/session-sync-core/dist/types.js +1 -1
  223. package/node_modules/@codingns/session-sync-core/dist/types.js.map +1 -1
  224. package/package.json +1 -1
  225. package/dist/public/assets/App-DUAg5urj.css +0 -1
  226. package/dist/public/assets/ConversationPage-Bz0_tvvM.js +0 -2
  227. package/dist/public/assets/DesktopWindowPage-BBmHyRg5.js +0 -2
  228. package/dist/public/assets/FileContextPanel--FVTxDrq.js +0 -1
  229. package/dist/public/assets/GitSidebar-DAiSi9oc.js +0 -6
  230. package/dist/public/assets/MobileCreateSessionSheet-DqVwz_Hp.js +0 -1
  231. package/dist/public/assets/MobileSheet-D1lMrcvD.js +0 -1
  232. package/dist/public/assets/MobileWorkspaceSwitcherHeader-DJPV9ym2.js +0 -1
  233. package/dist/public/assets/RelayConnectEntryPage-dSwU8VzK.js +0 -1
  234. package/dist/public/assets/ServerSettingsModal-B34ms3ze.js +0 -1
  235. package/dist/public/assets/SessionIndexPage-D3tG1gmM.js +0 -1
  236. package/dist/public/assets/SettingsPage-B3-6-5GL.js +0 -1
  237. package/dist/public/assets/TerminalManagerPanel-DhuTEdzV.js +0 -1
  238. package/dist/public/assets/TerminalRuntimeFallbackModal-CNzOt5v5.js +0 -1
  239. package/dist/public/assets/ToolFilesPage-BX9QDi9Y.js +0 -1
  240. package/dist/public/assets/ToolGitPage-4VtFox3p.js +0 -1
  241. package/dist/public/assets/ToolProcessesPage-DZJC6Qnt.js +0 -1
  242. package/dist/public/assets/ToolsHomePage-D7JbrAWv.js +0 -1
  243. package/dist/public/assets/WorkbenchLandingPage-C0yqnzqh.js +0 -1
  244. package/dist/public/assets/WorkbenchLayout-Brlj8K3i.js +0 -3
  245. package/dist/public/assets/WorkbenchShellRoute-BMcnFadA.css +0 -1
  246. package/dist/public/assets/WorkbenchShellRoute-puGpdDFY.js +0 -1
  247. package/dist/public/assets/WorkspaceDebugDetailPage-fTGweC9N.js +0 -1
  248. package/dist/public/assets/WorkspaceDetailPage-BtaIzSDB.js +0 -1
  249. package/dist/public/assets/WorkspaceHomePage-CUmmYDrM.js +0 -1
  250. package/dist/public/assets/client-runtime-manager-RHFa_iWo.js +0 -1
  251. package/dist/public/assets/default-session-permission-mode-Cu5SreTG.js +0 -1
  252. package/dist/public/assets/index-Cq3ue0za.css +0 -1
  253. package/dist/public/assets/index-DEbFT-Aq.js +0 -42
  254. package/dist/public/assets/session-runtime-machine-Bfnxkk9B.js +0 -17
  255. package/dist/public/assets/useRegisteredDebugTemplates-CDfl54Wt.js +0 -1
  256. package/dist/public/assets/window-BWqRixxq.js +0 -1
  257. /package/dist/public/assets/{styles-CSUx5LGe.js → styles-DRVvx_kv.js} +0 -0
@@ -12,6 +12,7 @@ import { buildApplyPatchFromFileChangeList, extractApplyPatchTargetPathsFromTool
12
12
  import { loadDatabaseSync } from "../sqlite/node-sqlite.js";
13
13
  import { createCodexThreadPermissionOptions } from "./codex-permissions.js";
14
14
  const CODEX_RUNTIME_DEBUG_ENABLED = /^(1|true|yes)$/i.test(process.env.CODINGNS_PERF_DEBUG?.trim() ?? "");
15
+ const CODEX_APP_SERVER_REQUEST_TIMEOUT_MS = 20_000;
15
16
  function logCodexRuntimeStep(scope, startedAtMs, detail = {}) {
16
17
  if (!CODEX_RUNTIME_DEBUG_ENABLED) {
17
18
  return;
@@ -59,110 +60,121 @@ export class CodexRuntimeAdapter {
59
60
  const launchedAtMs = Date.now();
60
61
  const launchPerfStartedAtMs = performance.now();
61
62
  const transport = this.options.transportFactory
62
- ? this.options.transportFactory()
63
- : createCodexAppServerTransport(this.options);
64
- const initializeStartedAtMs = performance.now();
65
- await transport.initialize();
66
- logCodexRuntimeStep("start_session.initialize", initializeStartedAtMs, {
67
- sessionId: request.sessionId,
68
- workspacePath: request.workspacePath
69
- });
70
- const abortController = new AbortController();
71
- const eventQueue = createAsyncEventQueue();
72
- const forwardTranslatedNotification = createCodexTranslatedNotificationForwarder(eventQueue);
73
- const resumedSyntheticSession = await this.resumeSyntheticThreadFromHistory(transport, request);
74
- const startedSession = resumedSyntheticSession ??
75
- await (async () => {
76
- const startThreadStartedAtMs = performance.now();
77
- const started = await transport.startThread(request);
78
- logCodexRuntimeStep("start_session.thread_start", startThreadStartedAtMs, {
79
- sessionId: request.sessionId,
80
- providerSessionId: started.providerSessionId
81
- });
82
- return started;
83
- })();
84
- const providerSessionId = startedSession.providerSessionId;
85
- const syntheticRawStoreRef = buildRuntimeRawStoreRef(resolveRuntimeStoreKey(providerSessionId, request.sessionId));
86
- const rawStoreRef = pickAvailableCodexRawStoreRef(providerSessionId, resumedSyntheticSession
87
- ? [resumedSyntheticSession.rawStoreRef]
88
- : [startedSession.rawStoreRef, request.rawStoreRef], syntheticRawStoreRef);
89
- logCodexRuntimeStep("start_session.raw_store_ref_ready", launchPerfStartedAtMs, {
90
- sessionId: request.sessionId,
91
- providerSessionId,
92
- synthetic: isSyntheticRawStoreRef(rawStoreRef),
93
- hasProviderRawStoreRef: Boolean(startedSession.rawStoreRef),
94
- providerRawStoreRefExists: Boolean(startedSession.rawStoreRef && existsSync(startedSession.rawStoreRef))
95
- });
96
- sink.updateSessionBinding({
97
- providerSessionId,
98
- rawStoreRef
99
- });
100
- let firstNotificationLogged = false;
101
- transport.setNotificationHandler(async (notification) => {
102
- if (!firstNotificationLogged) {
103
- firstNotificationLogged = true;
104
- logCodexRuntimeStep("start_session.first_notification", launchPerfStartedAtMs, {
63
+ ? this.options.transportFactory(request)
64
+ : createCodexAppServerTransport({
65
+ ...this.options,
66
+ homeDir: request.runtimeHomeDir?.trim() || this.options.homeDir,
67
+ runtimeEnv: request.runtimeEnv ?? this.options.runtimeEnv ?? null
68
+ });
69
+ try {
70
+ const initializeStartedAtMs = performance.now();
71
+ await transport.initialize();
72
+ logCodexRuntimeStep("start_session.initialize", initializeStartedAtMs, {
73
+ sessionId: request.sessionId,
74
+ workspacePath: request.workspacePath
75
+ });
76
+ const abortController = new AbortController();
77
+ const eventQueue = createAsyncEventQueue();
78
+ const translateNotification = createCodexAppServerNotificationTranslator();
79
+ const forwardTranslatedNotification = createCodexTranslatedNotificationForwarder(eventQueue);
80
+ const resumedSyntheticSession = await this.resumeSyntheticThreadFromHistory(transport, request);
81
+ const startedSession = resumedSyntheticSession ??
82
+ await (async () => {
83
+ const startThreadStartedAtMs = performance.now();
84
+ const started = await transport.startThread(request);
85
+ logCodexRuntimeStep("start_session.thread_start", startThreadStartedAtMs, {
86
+ sessionId: request.sessionId,
87
+ providerSessionId: started.providerSessionId
88
+ });
89
+ return started;
90
+ })();
91
+ const providerSessionId = startedSession.providerSessionId;
92
+ const syntheticRawStoreRef = buildRuntimeRawStoreRef(resolveRuntimeStoreKey(providerSessionId, request.sessionId));
93
+ const rawStoreRef = pickAvailableCodexRawStoreRef(providerSessionId, resumedSyntheticSession
94
+ ? [resumedSyntheticSession.rawStoreRef]
95
+ : [startedSession.rawStoreRef, request.rawStoreRef], syntheticRawStoreRef);
96
+ logCodexRuntimeStep("start_session.raw_store_ref_ready", launchPerfStartedAtMs, {
97
+ sessionId: request.sessionId,
98
+ providerSessionId,
99
+ synthetic: isSyntheticRawStoreRef(rawStoreRef),
100
+ hasProviderRawStoreRef: Boolean(startedSession.rawStoreRef),
101
+ providerRawStoreRefExists: Boolean(startedSession.rawStoreRef && existsSync(startedSession.rawStoreRef))
102
+ });
103
+ sink.updateSessionBinding({
104
+ providerSessionId,
105
+ rawStoreRef
106
+ });
107
+ let firstNotificationLogged = false;
108
+ transport.setNotificationHandler(async (notification) => {
109
+ if (!firstNotificationLogged) {
110
+ firstNotificationLogged = true;
111
+ logCodexRuntimeStep("start_session.first_notification", launchPerfStartedAtMs, {
112
+ sessionId: request.sessionId,
113
+ providerSessionId,
114
+ method: ensureText(notification.method).trim() || null
115
+ });
116
+ }
117
+ const translated = translateNotification(notification);
118
+ forwardTranslatedNotification(translated);
119
+ });
120
+ transport.setServerRequestHandler(async (serverRequest) => {
121
+ if (!this.options.handleServerRequest) {
122
+ throw new Error("CODEX_APP_SERVER_REQUEST_NOT_SUPPORTED");
123
+ }
124
+ return this.options.handleServerRequest({
105
125
  sessionId: request.sessionId,
106
126
  providerSessionId,
107
- method: ensureText(notification.method).trim() || null
127
+ request: serverRequest
108
128
  });
129
+ });
130
+ transport.setOnClose((error) => {
131
+ if (error) {
132
+ eventQueue.push({
133
+ type: "turn.failed",
134
+ timestamp: nextTimestamp(),
135
+ error: error.message
136
+ });
137
+ }
138
+ eventQueue.close();
139
+ });
140
+ const startTurnStartedAtMs = performance.now();
141
+ const startTurnResult = await transport.startTurn(request, providerSessionId);
142
+ const startTurnNotification = startTurnResult?.notification ?? null;
143
+ if (startTurnNotification) {
144
+ const translated = translateNotification(startTurnNotification);
145
+ forwardTranslatedNotification(translated);
109
146
  }
110
- const translated = translateCodexAppServerNotification(notification);
111
- forwardTranslatedNotification(translated);
112
- });
113
- transport.setServerRequestHandler(async (serverRequest) => {
114
- if (!this.options.handleServerRequest) {
115
- throw new Error("CODEX_APP_SERVER_REQUEST_NOT_SUPPORTED");
116
- }
117
- return this.options.handleServerRequest({
147
+ logCodexRuntimeStep("start_session.turn_start", startTurnStartedAtMs, {
118
148
  sessionId: request.sessionId,
119
- providerSessionId,
120
- request: serverRequest
149
+ providerSessionId
121
150
  });
122
- });
123
- transport.setOnClose((error) => {
124
- if (error) {
125
- eventQueue.push({
126
- type: "turn.failed",
127
- timestamp: nextTimestamp(),
128
- error: error.message
129
- });
130
- }
131
- eventQueue.close();
132
- });
133
- const startTurnStartedAtMs = performance.now();
134
- const startTurnResult = await transport.startTurn(request, providerSessionId);
135
- const startTurnNotification = startTurnResult?.notification ?? null;
136
- if (startTurnNotification) {
137
- const translated = translateCodexAppServerNotification(startTurnNotification);
138
- forwardTranslatedNotification(translated);
139
- }
140
- logCodexRuntimeStep("start_session.turn_start", startTurnStartedAtMs, {
141
- sessionId: request.sessionId,
142
- providerSessionId
143
- });
144
- logCodexRuntimeStep("start_session.ready", launchPerfStartedAtMs, {
145
- sessionId: request.sessionId,
146
- providerSessionId
147
- });
148
- return {
149
- providerSessionId,
150
- rawStoreRef,
151
- submitDuringRun: async (options) => {
152
- await transport.steerTurn(options);
153
- },
154
- interrupt: async () => {
155
- abortController.abort();
156
- await transport.interruptTurn().catch(() => {
157
- return;
158
- });
159
- transport.close();
160
- },
161
- isAlive: () => transport.isClosed() === false,
162
- completed: this.runTurn(null, request, sink, providerSessionId, rawStoreRef, abortController, eventQueue.iterator, [], launchedAtMs, launchPerfStartedAtMs).finally(() => {
163
- transport.close();
164
- })
165
- };
151
+ logCodexRuntimeStep("start_session.ready", launchPerfStartedAtMs, {
152
+ sessionId: request.sessionId,
153
+ providerSessionId
154
+ });
155
+ return {
156
+ providerSessionId,
157
+ rawStoreRef,
158
+ submitDuringRun: async (options) => {
159
+ await transport.steerTurn(options);
160
+ },
161
+ interrupt: async () => {
162
+ abortController.abort();
163
+ await transport.interruptTurn().catch(() => {
164
+ return;
165
+ });
166
+ transport.close();
167
+ },
168
+ isAlive: () => transport.isClosed() === false,
169
+ completed: this.runTurn(null, request, sink, providerSessionId, rawStoreRef, abortController, eventQueue.iterator, [], launchedAtMs, launchPerfStartedAtMs).finally(() => {
170
+ transport.close();
171
+ })
172
+ };
173
+ }
174
+ catch (error) {
175
+ transport.close();
176
+ throw error;
177
+ }
166
178
  }
167
179
  async resumeSyntheticThreadFromHistory(transport, request) {
168
180
  const history = buildSyntheticResumeHistory(request.rawStoreRef);
@@ -189,139 +201,151 @@ export class CodexRuntimeAdapter {
189
201
  throw new Error("PROVIDER_SESSION_ID_REQUIRED");
190
202
  }
191
203
  const transport = this.options.transportFactory
192
- ? this.options.transportFactory()
193
- : createCodexAppServerTransport(this.options);
194
- const runtimeStartedAtMs = performance.now();
195
- const initializeStartedAtMs = performance.now();
196
- await transport.initialize();
197
- logCodexRuntimeStep("continue_session.initialize", initializeStartedAtMs, {
198
- sessionId: request.sessionId,
199
- providerSessionId
200
- });
201
- const syntheticRawStoreRef = buildRuntimeRawStoreRef(providerSessionId);
202
- let resolvedSessionId = providerSessionId;
203
- let resolvedFallbackHistoryRawStoreRef = null;
204
- const resumeThreadStartedAtMs = performance.now();
205
- let resumed;
206
- try {
207
- resumed = await transport.resumeThread(request, resolvedSessionId);
208
- logCodexRuntimeStep("continue_session.thread_resume", resumeThreadStartedAtMs, {
209
- sessionId: request.sessionId,
210
- providerSessionId: resolvedSessionId,
211
- fallback: false
204
+ ? this.options.transportFactory(request)
205
+ : createCodexAppServerTransport({
206
+ ...this.options,
207
+ homeDir: request.runtimeHomeDir?.trim() || this.options.homeDir,
208
+ runtimeEnv: request.runtimeEnv ?? this.options.runtimeEnv ?? null
212
209
  });
213
- }
214
- catch (error) {
215
- const fallbackHistorySource = await this.resolveContinueFallbackHistorySource({
216
- providerSessionId,
217
- rawStoreRef: request.rawStoreRef,
218
- workspacePath: request.workspacePath
219
- });
220
- const resumeHistory = fallbackHistorySource?.history ?? [];
221
- if (!shouldFallbackCodexContinueFromHistory(error, resumeHistory)) {
222
- throw error;
223
- }
224
- resolvedFallbackHistoryRawStoreRef = fallbackHistorySource?.rawStoreRef ?? null;
225
- const resumeFallbackStartedAtMs = performance.now();
226
- resumed = await transport.resumeThreadFromHistory({
227
- providerSessionId: null,
228
- workspacePath: request.workspacePath,
229
- history: resumeHistory,
230
- model: request.options.model
231
- });
232
- resolvedSessionId = resumed.providerSessionId;
233
- logCodexRuntimeStep("continue_session.thread_resume_from_history_fallback", resumeFallbackStartedAtMs, {
210
+ try {
211
+ const runtimeStartedAtMs = performance.now();
212
+ const initializeStartedAtMs = performance.now();
213
+ await transport.initialize();
214
+ logCodexRuntimeStep("continue_session.initialize", initializeStartedAtMs, {
234
215
  sessionId: request.sessionId,
235
- requestedProviderSessionId: providerSessionId,
236
- providerSessionId: resolvedSessionId,
237
- historyLength: resumeHistory.length
216
+ providerSessionId
238
217
  });
239
- }
240
- const pickedRawStoreRef = pickAvailableCodexRawStoreRef(resolvedSessionId, [resolvedFallbackHistoryRawStoreRef, request.rawStoreRef, resumed.rawStoreRef], syntheticRawStoreRef);
241
- const rawStoreRef = !resumed.rawStoreRef?.trim() && resolvedFallbackHistoryRawStoreRef
242
- ? resolvedFallbackHistoryRawStoreRef
243
- : pickedRawStoreRef;
244
- const abortController = new AbortController();
245
- const eventQueue = createAsyncEventQueue();
246
- const forwardTranslatedNotification = createCodexTranslatedNotificationForwarder(eventQueue);
247
- logCodexRuntimeStep("continue_session.raw_store_ref_ready", runtimeStartedAtMs, {
248
- sessionId: request.sessionId,
249
- providerSessionId: resolvedSessionId,
250
- synthetic: isSyntheticRawStoreRef(rawStoreRef),
251
- hasResumedRawStoreRef: Boolean(resumed.rawStoreRef),
252
- hasRequestRawStoreRef: Boolean(request.rawStoreRef),
253
- resumedRawStoreRefExists: Boolean(resumed.rawStoreRef && existsSync(resumed.rawStoreRef))
254
- });
255
- sink.updateSessionBinding({
256
- providerSessionId: resolvedSessionId,
257
- rawStoreRef
258
- });
259
- let firstNotificationLogged = false;
260
- transport.setNotificationHandler(async (notification) => {
261
- if (!firstNotificationLogged) {
262
- firstNotificationLogged = true;
263
- logCodexRuntimeStep("continue_session.first_notification", runtimeStartedAtMs, {
218
+ const syntheticRawStoreRef = buildRuntimeRawStoreRef(providerSessionId);
219
+ let resolvedSessionId = providerSessionId;
220
+ let resolvedFallbackHistoryRawStoreRef = null;
221
+ const resumeThreadStartedAtMs = performance.now();
222
+ let resumed;
223
+ try {
224
+ resumed = await transport.resumeThread(request, resolvedSessionId);
225
+ logCodexRuntimeStep("continue_session.thread_resume", resumeThreadStartedAtMs, {
264
226
  sessionId: request.sessionId,
265
227
  providerSessionId: resolvedSessionId,
266
- method: ensureText(notification.method).trim() || null
228
+ fallback: false
267
229
  });
268
230
  }
269
- const translated = translateCodexAppServerNotification(notification);
270
- forwardTranslatedNotification(translated);
271
- });
272
- transport.setServerRequestHandler(async (serverRequest) => {
273
- if (!this.options.handleServerRequest) {
274
- throw new Error("CODEX_APP_SERVER_REQUEST_NOT_SUPPORTED");
231
+ catch (error) {
232
+ const fallbackHistorySource = await this.resolveContinueFallbackHistorySource({
233
+ providerSessionId,
234
+ rawStoreRef: request.rawStoreRef,
235
+ workspacePath: request.workspacePath,
236
+ homeDir: request.runtimeHomeDir?.trim() || this.options.homeDir?.trim() || null
237
+ });
238
+ const resumeHistory = fallbackHistorySource?.history ?? [];
239
+ if (!shouldFallbackCodexContinueFromHistory(error, resumeHistory)) {
240
+ throw error;
241
+ }
242
+ resolvedFallbackHistoryRawStoreRef = fallbackHistorySource?.rawStoreRef ?? null;
243
+ const resumeFallbackStartedAtMs = performance.now();
244
+ resumed = await transport.resumeThreadFromHistory({
245
+ providerSessionId: null,
246
+ workspacePath: request.workspacePath,
247
+ history: resumeHistory,
248
+ model: request.options.model
249
+ });
250
+ resolvedSessionId = resumed.providerSessionId;
251
+ logCodexRuntimeStep("continue_session.thread_resume_from_history_fallback", resumeFallbackStartedAtMs, {
252
+ sessionId: request.sessionId,
253
+ requestedProviderSessionId: providerSessionId,
254
+ providerSessionId: resolvedSessionId,
255
+ historyLength: resumeHistory.length
256
+ });
275
257
  }
276
- return this.options.handleServerRequest({
258
+ const pickedRawStoreRef = pickAvailableCodexRawStoreRef(resolvedSessionId, [resolvedFallbackHistoryRawStoreRef, request.rawStoreRef, resumed.rawStoreRef], syntheticRawStoreRef);
259
+ const rawStoreRef = !resumed.rawStoreRef?.trim() && resolvedFallbackHistoryRawStoreRef
260
+ ? resolvedFallbackHistoryRawStoreRef
261
+ : pickedRawStoreRef;
262
+ const abortController = new AbortController();
263
+ const eventQueue = createAsyncEventQueue();
264
+ const translateNotification = createCodexAppServerNotificationTranslator();
265
+ const forwardTranslatedNotification = createCodexTranslatedNotificationForwarder(eventQueue);
266
+ logCodexRuntimeStep("continue_session.raw_store_ref_ready", runtimeStartedAtMs, {
277
267
  sessionId: request.sessionId,
278
268
  providerSessionId: resolvedSessionId,
279
- request: serverRequest
269
+ synthetic: isSyntheticRawStoreRef(rawStoreRef),
270
+ hasResumedRawStoreRef: Boolean(resumed.rawStoreRef),
271
+ hasRequestRawStoreRef: Boolean(request.rawStoreRef),
272
+ resumedRawStoreRefExists: Boolean(resumed.rawStoreRef && existsSync(resumed.rawStoreRef))
280
273
  });
281
- });
282
- transport.setOnClose((error) => {
283
- if (error) {
284
- eventQueue.push({
285
- type: "turn.failed",
286
- timestamp: nextTimestamp(),
287
- error: error.message
274
+ sink.updateSessionBinding({
275
+ providerSessionId: resolvedSessionId,
276
+ rawStoreRef
277
+ });
278
+ let firstNotificationLogged = false;
279
+ transport.setNotificationHandler(async (notification) => {
280
+ if (!firstNotificationLogged) {
281
+ firstNotificationLogged = true;
282
+ logCodexRuntimeStep("continue_session.first_notification", runtimeStartedAtMs, {
283
+ sessionId: request.sessionId,
284
+ providerSessionId: resolvedSessionId,
285
+ method: ensureText(notification.method).trim() || null
286
+ });
287
+ }
288
+ const translated = translateNotification(notification);
289
+ forwardTranslatedNotification(translated);
290
+ });
291
+ transport.setServerRequestHandler(async (serverRequest) => {
292
+ if (!this.options.handleServerRequest) {
293
+ throw new Error("CODEX_APP_SERVER_REQUEST_NOT_SUPPORTED");
294
+ }
295
+ return this.options.handleServerRequest({
296
+ sessionId: request.sessionId,
297
+ providerSessionId: resolvedSessionId,
298
+ request: serverRequest
288
299
  });
300
+ });
301
+ transport.setOnClose((error) => {
302
+ if (error) {
303
+ eventQueue.push({
304
+ type: "turn.failed",
305
+ timestamp: nextTimestamp(),
306
+ error: error.message
307
+ });
308
+ }
309
+ eventQueue.close();
310
+ });
311
+ const startTurnStartedAtMs = performance.now();
312
+ const startTurnResult = await transport.startTurn(request, resolvedSessionId);
313
+ const startTurnNotification = startTurnResult?.notification ?? null;
314
+ if (startTurnNotification) {
315
+ const translated = translateNotification(startTurnNotification);
316
+ forwardTranslatedNotification(translated);
289
317
  }
290
- eventQueue.close();
291
- });
292
- const startTurnStartedAtMs = performance.now();
293
- const startTurnResult = await transport.startTurn(request, resolvedSessionId);
294
- const startTurnNotification = startTurnResult?.notification ?? null;
295
- if (startTurnNotification) {
296
- const translated = translateCodexAppServerNotification(startTurnNotification);
297
- forwardTranslatedNotification(translated);
298
- }
299
- logCodexRuntimeStep("continue_session.turn_start", startTurnStartedAtMs, {
300
- sessionId: request.sessionId,
301
- providerSessionId: resolvedSessionId
302
- });
303
- logCodexRuntimeStep("continue_session.ready", runtimeStartedAtMs, {
304
- sessionId: request.sessionId,
305
- providerSessionId: resolvedSessionId
306
- });
307
- return {
308
- providerSessionId: resolvedSessionId,
309
- rawStoreRef,
310
- submitDuringRun: async (options) => {
311
- await transport.steerTurn(options);
312
- },
313
- interrupt: async () => {
314
- abortController.abort();
315
- await transport.interruptTurn().catch(() => {
316
- return;
317
- });
318
- transport.close();
319
- },
320
- isAlive: () => transport.isClosed() === false,
321
- completed: this.runTurn(null, request, sink, resolvedSessionId, rawStoreRef, abortController, eventQueue.iterator, [], Date.now()).finally(() => {
322
- transport.close();
323
- })
324
- };
318
+ logCodexRuntimeStep("continue_session.turn_start", startTurnStartedAtMs, {
319
+ sessionId: request.sessionId,
320
+ providerSessionId: resolvedSessionId
321
+ });
322
+ logCodexRuntimeStep("continue_session.ready", runtimeStartedAtMs, {
323
+ sessionId: request.sessionId,
324
+ providerSessionId: resolvedSessionId
325
+ });
326
+ return {
327
+ providerSessionId: resolvedSessionId,
328
+ rawStoreRef,
329
+ submitDuringRun: async (options) => {
330
+ await transport.steerTurn(options);
331
+ },
332
+ interrupt: async () => {
333
+ abortController.abort();
334
+ await transport.interruptTurn().catch(() => {
335
+ return;
336
+ });
337
+ transport.close();
338
+ },
339
+ isAlive: () => transport.isClosed() === false,
340
+ completed: this.runTurn(null, request, sink, resolvedSessionId, rawStoreRef, abortController, eventQueue.iterator, [], Date.now()).finally(() => {
341
+ transport.close();
342
+ })
343
+ };
344
+ }
345
+ catch (error) {
346
+ transport.close();
347
+ throw error;
348
+ }
325
349
  }
326
350
  async resolveContinueFallbackHistorySource(input) {
327
351
  const candidates = [];
@@ -337,7 +361,7 @@ export class CodexRuntimeAdapter {
337
361
  pushCandidate(input.rawStoreRef);
338
362
  // 旧会话的 binding 可能只剩 synthetic stream,或者已经指到了父线程 transcript。
339
363
  // 继续会话失败时,额外按真实 thread id 扫一次本地 transcript,尽量把历史恢复链路救回来。
340
- pushCandidate(await this.resolveRealRawStoreRef(input.providerSessionId.trim(), input.workspacePath));
364
+ pushCandidate(await this.resolveRealRawStoreRef(input.providerSessionId.trim(), input.workspacePath, input.homeDir));
341
365
  let fallbackMatch = null;
342
366
  for (const candidate of candidates) {
343
367
  const history = buildCodexResumeHistoryFromRawStore(candidate);
@@ -371,6 +395,7 @@ export class CodexRuntimeAdapter {
371
395
  sink,
372
396
  workspacePath: request.workspacePath,
373
397
  firstUserMessage: request.options.content,
398
+ homeDir: request.runtimeHomeDir?.trim() || this.options.homeDir?.trim() || null,
374
399
  launchedAtMs,
375
400
  launchPerfStartedAtMs
376
401
  };
@@ -613,8 +638,8 @@ export class CodexRuntimeAdapter {
613
638
  if (!isSyntheticRawStoreRef(context.rawStoreRef)) {
614
639
  return;
615
640
  }
616
- const resolved = await this.resolveLaunchedSessionBinding(context.workspacePath, context.firstUserMessage, context.launchedAtMs) ??
617
- await this.resolveExistingSessionBinding(context.providerSessionId, context.rawStoreRef, context.workspacePath);
641
+ const resolved = await this.resolveLaunchedSessionBinding(context.workspacePath, context.firstUserMessage, context.launchedAtMs, context.homeDir) ??
642
+ await this.resolveExistingSessionBinding(context.providerSessionId, context.rawStoreRef, context.workspacePath, context.homeDir);
618
643
  if (!resolved ||
619
644
  (resolved.providerSessionId === context.providerSessionId &&
620
645
  resolved.rawStoreRef === context.rawStoreRef)) {
@@ -627,7 +652,7 @@ export class CodexRuntimeAdapter {
627
652
  rawStoreRef: resolved.rawStoreRef
628
653
  });
629
654
  }
630
- async resolveExistingSessionBinding(providerSessionId, rawStoreRef, workspacePath) {
655
+ async resolveExistingSessionBinding(providerSessionId, rawStoreRef, workspacePath, homeDirOverride = null) {
631
656
  const normalizedProviderSessionId = providerSessionId.trim();
632
657
  const meta = readSessionMeta(rawStoreRef);
633
658
  if (meta && meta.threadId === normalizedProviderSessionId && existsSync(rawStoreRef)) {
@@ -639,7 +664,7 @@ export class CodexRuntimeAdapter {
639
664
  if (!normalizedProviderSessionId) {
640
665
  return null;
641
666
  }
642
- const resolvedRawStoreRef = await this.resolveRealRawStoreRef(normalizedProviderSessionId, workspacePath);
667
+ const resolvedRawStoreRef = await this.resolveRealRawStoreRef(normalizedProviderSessionId, workspacePath, homeDirOverride);
643
668
  if (!resolvedRawStoreRef) {
644
669
  return null;
645
670
  }
@@ -648,9 +673,9 @@ export class CodexRuntimeAdapter {
648
673
  rawStoreRef: resolvedRawStoreRef
649
674
  };
650
675
  }
651
- async resolveLaunchedSessionBinding(workspacePath, firstUserMessage, launchedAtMs) {
676
+ async resolveLaunchedSessionBinding(workspacePath, firstUserMessage, launchedAtMs, homeDirOverride = null) {
652
677
  for (let attempt = 0; attempt < 20; attempt += 1) {
653
- const matched = this.findLaunchedSessionBindingOnce(workspacePath, firstUserMessage, launchedAtMs);
678
+ const matched = this.findLaunchedSessionBindingOnce(workspacePath, firstUserMessage, launchedAtMs, homeDirOverride);
654
679
  if (matched) {
655
680
  return matched;
656
681
  }
@@ -660,9 +685,9 @@ export class CodexRuntimeAdapter {
660
685
  }
661
686
  return null;
662
687
  }
663
- async resolveRealRawStoreRef(providerSessionId, workspacePath) {
688
+ async resolveRealRawStoreRef(providerSessionId, workspacePath, homeDirOverride = null) {
664
689
  for (let attempt = 0; attempt < 10; attempt += 1) {
665
- const matched = this.findRawStoreRefOnce(providerSessionId, workspacePath);
690
+ const matched = this.findRawStoreRefOnce(providerSessionId, workspacePath, homeDirOverride);
666
691
  if (matched) {
667
692
  return matched;
668
693
  }
@@ -672,8 +697,11 @@ export class CodexRuntimeAdapter {
672
697
  }
673
698
  return null;
674
699
  }
675
- findRawStoreRefOnce(providerSessionId, workspacePath) {
676
- const homeDir = this.options.homeDir?.trim() || process.env.CODINGNS_CODEX_HOME || join(homedir(), ".codex");
700
+ findRawStoreRefOnce(providerSessionId, workspacePath, homeDirOverride = null) {
701
+ const homeDir = homeDirOverride?.trim()
702
+ || this.options.homeDir?.trim()
703
+ || process.env.CODINGNS_CODEX_HOME
704
+ || join(homedir(), ".codex");
677
705
  const candidates = this.listSessionFiles(homeDir);
678
706
  const normalizedWorkspace = normalizeWorkspacePath(workspacePath);
679
707
  for (const filePath of candidates) {
@@ -714,8 +742,8 @@ export class CodexRuntimeAdapter {
714
742
  }
715
743
  return files;
716
744
  }
717
- findLaunchedSessionBindingOnce(workspacePath, firstUserMessage, launchedAtMs) {
718
- const dbPath = findLatestCodexStateDatabase(this.getCodexHomeDir());
745
+ findLaunchedSessionBindingOnce(workspacePath, firstUserMessage, launchedAtMs, homeDirOverride = null) {
746
+ const dbPath = findLatestCodexStateDatabase(this.getCodexHomeDir(homeDirOverride));
719
747
  if (!dbPath) {
720
748
  return null;
721
749
  }
@@ -751,8 +779,11 @@ export class CodexRuntimeAdapter {
751
779
  }
752
780
  return null;
753
781
  }
754
- getCodexHomeDir() {
755
- return this.options.homeDir?.trim() || process.env.CODINGNS_CODEX_HOME || join(homedir(), ".codex");
782
+ getCodexHomeDir(homeDirOverride = null) {
783
+ return (homeDirOverride?.trim()
784
+ || this.options.homeDir?.trim()
785
+ || process.env.CODINGNS_CODEX_HOME
786
+ || join(homedir(), ".codex"));
756
787
  }
757
788
  buildMessage(context, input) {
758
789
  const stableRef = this.resolveStableMessageRef(context, input.stableIdentity ?? null);
@@ -830,8 +861,12 @@ export class CodexRuntimeAdapter {
830
861
  function createCodexAppServerTransport(options) {
831
862
  const commandPath = resolveCodexCommand(options.commandPath);
832
863
  const launch = resolveCodexCommandLaunch(commandPath, ["app-server"]);
864
+ const runtimeEnv = options.runtimeEnv ?? null;
833
865
  const child = spawn(launch.command, launch.args, {
834
- env: process.env,
866
+ env: {
867
+ ...process.env,
868
+ ...(runtimeEnv ?? {})
869
+ },
835
870
  stdio: ["pipe", "pipe", "pipe"],
836
871
  shell: launch.shell,
837
872
  windowsHide: true
@@ -1230,110 +1265,285 @@ function normalizeReplayKeyText(value) {
1230
1265
  }
1231
1266
  return ensureText(value).trim();
1232
1267
  }
1233
- function translateCodexAppServerNotification(notification) {
1234
- const method = ensureText(notification.method).trim();
1235
- const params = toRecord(notification.params) ?? {};
1236
- if (method === "turn/started") {
1268
+ function createCodexAppServerNotificationTranslator() {
1269
+ const agentMessageTextById = new Map();
1270
+ const reasoningSummaryPartsById = new Map();
1271
+ const reasoningContentPartsById = new Map();
1272
+ const resetStreamState = () => {
1273
+ agentMessageTextById.clear();
1274
+ reasoningSummaryPartsById.clear();
1275
+ reasoningContentPartsById.clear();
1276
+ };
1277
+ const ensureIndexedTextPart = (store, itemId, index) => {
1278
+ if (!itemId || !Number.isInteger(index) || index < 0) {
1279
+ return null;
1280
+ }
1281
+ const existing = store.get(itemId) ?? [];
1282
+ while (existing.length <= index) {
1283
+ existing.push("");
1284
+ }
1285
+ store.set(itemId, existing);
1286
+ return existing;
1287
+ };
1288
+ const buildReasoningSyntheticItem = (itemId) => {
1289
+ // 这里必须复制一份快照,不能把可变数组引用直接塞进事件队列。
1290
+ // 否则后续 delta 继续追加时,前一帧事件里的 summary/content 也会被同步改掉,
1291
+ // 最终所有帧都会看起来像“最后一帧”,下游稳定消息去重就会把中间增量吃掉。
1292
+ const summary = [...(reasoningSummaryPartsById.get(itemId) ?? [])];
1293
+ const content = [...(reasoningContentPartsById.get(itemId) ?? [])];
1237
1294
  return {
1238
- events: [],
1239
- terminal: false,
1240
- turnId: ensureText(readProp(readProp(params, "turn"), "id")).trim() || null
1295
+ type: "reasoning",
1296
+ id: itemId,
1297
+ summary,
1298
+ content
1241
1299
  };
1242
- }
1243
- if (method === "turn/completed") {
1244
- const turn = toRecord(params.turn);
1245
- const status = ensureText(turn?.status).trim();
1246
- const itemEvents = translateCodexAppServerTurnItems(turn, "item.completed");
1247
- if (status === "failed") {
1248
- return {
1249
- events: [
1250
- ...itemEvents,
1251
- {
1252
- type: "turn.failed",
1253
- timestamp: nextTimestamp(),
1254
- error: ensureText(readProp(turn?.error, "message")).trim() || "codex turn failed"
1255
- }
1256
- ],
1257
- terminal: true,
1258
- turnId: ensureText(turn?.id).trim() || null
1259
- };
1260
- }
1261
- if (status === "interrupted") {
1300
+ };
1301
+ const translateAgentMessageDelta = (params) => {
1302
+ const itemId = ensureText(params.itemId).trim();
1303
+ const delta = ensureText(params.delta);
1304
+ if (!itemId || delta.length === 0) {
1262
1305
  return {
1263
- events: [
1264
- ...itemEvents,
1265
- {
1266
- type: "turn.interrupted",
1267
- timestamp: nextTimestamp()
1268
- }
1269
- ],
1270
- terminal: true,
1271
- turnId: ensureText(turn?.id).trim() || null
1306
+ events: [],
1307
+ terminal: false,
1308
+ turnId: ensureText(params.turnId).trim() || null
1272
1309
  };
1273
1310
  }
1311
+ const nextText = `${agentMessageTextById.get(itemId) ?? ""}${delta}`;
1312
+ agentMessageTextById.set(itemId, nextText);
1274
1313
  return {
1275
1314
  events: [
1276
- ...itemEvents,
1277
1315
  {
1278
- type: "turn.completed",
1316
+ type: "item.updated",
1317
+ item: {
1318
+ type: "agent_message",
1319
+ id: itemId,
1320
+ text: nextText
1321
+ },
1279
1322
  timestamp: nextTimestamp()
1280
1323
  }
1281
1324
  ],
1282
- terminal: true,
1283
- turnId: ensureText(turn?.id).trim() || null
1325
+ terminal: false,
1326
+ turnId: ensureText(params.turnId).trim() || null
1284
1327
  };
1285
- }
1286
- if (method === "error") {
1287
- const error = toRecord(params.error);
1288
- const detail = buildCodexAppServerErrorDetail(error);
1289
- if (params.willRetry === true) {
1328
+ };
1329
+ const translateReasoningSummaryPartAdded = (params) => {
1330
+ const itemId = ensureText(params.itemId).trim();
1331
+ const summaryIndex = Math.trunc(Number(params.summaryIndex));
1332
+ ensureIndexedTextPart(reasoningSummaryPartsById, itemId, summaryIndex);
1333
+ return {
1334
+ events: [],
1335
+ terminal: false,
1336
+ turnId: ensureText(params.turnId).trim() || null
1337
+ };
1338
+ };
1339
+ const translateReasoningSummaryTextDelta = (params) => {
1340
+ const itemId = ensureText(params.itemId).trim();
1341
+ const summaryIndex = Math.trunc(Number(params.summaryIndex));
1342
+ const delta = ensureText(params.delta);
1343
+ const parts = ensureIndexedTextPart(reasoningSummaryPartsById, itemId, summaryIndex);
1344
+ if (!parts || delta.length === 0) {
1290
1345
  return {
1291
1346
  events: [],
1292
1347
  terminal: false,
1293
1348
  turnId: ensureText(params.turnId).trim() || null
1294
1349
  };
1295
1350
  }
1351
+ parts[summaryIndex] = `${parts[summaryIndex] ?? ""}${delta}`;
1296
1352
  return {
1297
1353
  events: [
1298
1354
  {
1299
- type: "turn.failed",
1300
- timestamp: nextTimestamp(),
1301
- error: detail
1355
+ type: "item.updated",
1356
+ item: buildReasoningSyntheticItem(itemId),
1357
+ timestamp: nextTimestamp()
1302
1358
  }
1303
1359
  ],
1304
- terminal: true,
1360
+ terminal: false,
1305
1361
  turnId: ensureText(params.turnId).trim() || null
1306
1362
  };
1307
- }
1308
- if (method === "item/started" || method === "item/updated" || method === "item/completed") {
1309
- const item = translateCodexAppServerItem(toRecord(params.item));
1310
- if (!item) {
1363
+ };
1364
+ const translateReasoningTextDelta = (params) => {
1365
+ const itemId = ensureText(params.itemId).trim();
1366
+ const contentIndex = Math.trunc(Number(params.contentIndex));
1367
+ const delta = ensureText(params.delta);
1368
+ const parts = ensureIndexedTextPart(reasoningContentPartsById, itemId, contentIndex);
1369
+ if (!parts || delta.length === 0) {
1311
1370
  return {
1312
1371
  events: [],
1313
1372
  terminal: false,
1314
- turnId: null
1373
+ turnId: ensureText(params.turnId).trim() || null
1315
1374
  };
1316
1375
  }
1376
+ parts[contentIndex] = `${parts[contentIndex] ?? ""}${delta}`;
1317
1377
  return {
1318
1378
  events: [
1319
1379
  {
1320
- type: method === "item/started"
1321
- ? "item.started"
1322
- : method === "item/updated"
1323
- ? "item.updated"
1324
- : "item.completed",
1325
- item,
1380
+ type: "item.updated",
1381
+ item: buildReasoningSyntheticItem(itemId),
1326
1382
  timestamp: nextTimestamp()
1327
1383
  }
1328
1384
  ],
1329
1385
  terminal: false,
1386
+ turnId: ensureText(params.turnId).trim() || null
1387
+ };
1388
+ };
1389
+ return (notification) => {
1390
+ const method = ensureText(notification.method).trim();
1391
+ const params = toRecord(notification.params) ?? {};
1392
+ if (method === "turn/started") {
1393
+ return {
1394
+ events: [],
1395
+ terminal: false,
1396
+ turnId: ensureText(readProp(readProp(params, "turn"), "id")).trim() || null
1397
+ };
1398
+ }
1399
+ if (method === "turn/completed") {
1400
+ const turn = toRecord(params.turn);
1401
+ const status = ensureText(turn?.status).trim();
1402
+ const itemEvents = translateCodexAppServerTurnItems(turn, "item.completed");
1403
+ resetStreamState();
1404
+ if (status === "failed") {
1405
+ return {
1406
+ events: [
1407
+ ...itemEvents,
1408
+ {
1409
+ type: "turn.failed",
1410
+ timestamp: nextTimestamp(),
1411
+ error: ensureText(readProp(turn?.error, "message")).trim() || "codex turn failed"
1412
+ }
1413
+ ],
1414
+ terminal: true,
1415
+ turnId: ensureText(turn?.id).trim() || null
1416
+ };
1417
+ }
1418
+ if (status === "interrupted") {
1419
+ return {
1420
+ events: [
1421
+ ...itemEvents,
1422
+ {
1423
+ type: "turn.interrupted",
1424
+ timestamp: nextTimestamp()
1425
+ }
1426
+ ],
1427
+ terminal: true,
1428
+ turnId: ensureText(turn?.id).trim() || null
1429
+ };
1430
+ }
1431
+ return {
1432
+ events: [
1433
+ ...itemEvents,
1434
+ {
1435
+ type: "turn.completed",
1436
+ timestamp: nextTimestamp()
1437
+ }
1438
+ ],
1439
+ terminal: true,
1440
+ turnId: ensureText(turn?.id).trim() || null
1441
+ };
1442
+ }
1443
+ if (method === "error") {
1444
+ const error = toRecord(params.error);
1445
+ const detail = buildCodexAppServerErrorDetail(error);
1446
+ if (params.willRetry === true) {
1447
+ return {
1448
+ events: [],
1449
+ terminal: false,
1450
+ turnId: ensureText(params.turnId).trim() || null
1451
+ };
1452
+ }
1453
+ resetStreamState();
1454
+ return {
1455
+ events: [
1456
+ {
1457
+ type: "turn.failed",
1458
+ timestamp: nextTimestamp(),
1459
+ error: detail
1460
+ }
1461
+ ],
1462
+ terminal: true,
1463
+ turnId: ensureText(params.turnId).trim() || null
1464
+ };
1465
+ }
1466
+ if (method === "item/agentMessage/delta") {
1467
+ return translateAgentMessageDelta(params);
1468
+ }
1469
+ if (method === "item/reasoning/summaryPartAdded") {
1470
+ return translateReasoningSummaryPartAdded(params);
1471
+ }
1472
+ if (method === "item/reasoning/summaryTextDelta") {
1473
+ return translateReasoningSummaryTextDelta(params);
1474
+ }
1475
+ if (method === "item/reasoning/textDelta") {
1476
+ return translateReasoningTextDelta(params);
1477
+ }
1478
+ if (method === "item/started" || method === "item/updated" || method === "item/completed") {
1479
+ const item = translateCodexAppServerItem(toRecord(params.item));
1480
+ if (!item) {
1481
+ return {
1482
+ events: [],
1483
+ terminal: false,
1484
+ turnId: null
1485
+ };
1486
+ }
1487
+ if (ensureText(item.type).trim() === "agent_message") {
1488
+ const itemId = ensureText(item.id).trim();
1489
+ const itemText = ensureText(item.text);
1490
+ if (itemId) {
1491
+ if (itemText.length > 0) {
1492
+ agentMessageTextById.set(itemId, itemText);
1493
+ }
1494
+ else if (method === "item/completed") {
1495
+ agentMessageTextById.delete(itemId);
1496
+ }
1497
+ }
1498
+ }
1499
+ if (ensureText(item.type).trim() === "reasoning") {
1500
+ const itemId = ensureText(item.id).trim();
1501
+ if (itemId) {
1502
+ const summary = Array.isArray(item.summary)
1503
+ ? item.summary.map((entry) => ensureText(entry))
1504
+ : ensureText(item.summary).trim()
1505
+ ? [ensureText(item.summary)]
1506
+ : [];
1507
+ const content = Array.isArray(item.content)
1508
+ ? item.content.map((entry) => ensureText(entry))
1509
+ : ensureText(item.text).trim()
1510
+ ? [ensureText(item.text)]
1511
+ : [];
1512
+ if (summary.length > 0) {
1513
+ reasoningSummaryPartsById.set(itemId, summary);
1514
+ }
1515
+ else if (method === "item/completed") {
1516
+ reasoningSummaryPartsById.delete(itemId);
1517
+ }
1518
+ if (content.length > 0) {
1519
+ reasoningContentPartsById.set(itemId, content);
1520
+ }
1521
+ else if (method === "item/completed") {
1522
+ reasoningContentPartsById.delete(itemId);
1523
+ }
1524
+ }
1525
+ }
1526
+ return {
1527
+ events: [
1528
+ {
1529
+ type: method === "item/started"
1530
+ ? "item.started"
1531
+ : method === "item/updated"
1532
+ ? "item.updated"
1533
+ : "item.completed",
1534
+ item,
1535
+ timestamp: nextTimestamp()
1536
+ }
1537
+ ],
1538
+ terminal: false,
1539
+ turnId: null
1540
+ };
1541
+ }
1542
+ return {
1543
+ events: [],
1544
+ terminal: false,
1330
1545
  turnId: null
1331
1546
  };
1332
- }
1333
- return {
1334
- events: [],
1335
- terminal: false,
1336
- turnId: null
1337
1547
  };
1338
1548
  }
1339
1549
  function translateCodexAppServerTurnItems(turn, eventType) {
@@ -1796,7 +2006,20 @@ function writeJsonRpcMessage(child, payload) {
1796
2006
  function sendJsonRpcRequest(child, pendingResponses, createRequestId, input) {
1797
2007
  const id = createRequestId();
1798
2008
  return new Promise((resolve, reject) => {
1799
- pendingResponses.set(id, { resolve, reject });
2009
+ const timeout = setTimeout(() => {
2010
+ pendingResponses.delete(id);
2011
+ reject(new Error("SERVER_TIMEOUT"));
2012
+ }, CODEX_APP_SERVER_REQUEST_TIMEOUT_MS);
2013
+ pendingResponses.set(id, {
2014
+ resolve: (value) => {
2015
+ clearTimeout(timeout);
2016
+ resolve(value);
2017
+ },
2018
+ reject: (error) => {
2019
+ clearTimeout(timeout);
2020
+ reject(error);
2021
+ }
2022
+ });
1800
2023
  try {
1801
2024
  writeJsonRpcMessage(child, {
1802
2025
  jsonrpc: "2.0",
@@ -1806,6 +2029,7 @@ function sendJsonRpcRequest(child, pendingResponses, createRequestId, input) {
1806
2029
  });
1807
2030
  }
1808
2031
  catch (error) {
2032
+ clearTimeout(timeout);
1809
2033
  pendingResponses.delete(id);
1810
2034
  reject(error instanceof Error ? error : new Error("CODEX_APP_SERVER_REQUEST_WRITE_FAILED"));
1811
2035
  }
@@ -1843,7 +2067,7 @@ function shouldFallbackCodexContinueFromHistory(error, history) {
1843
2067
  if (history.length === 0) {
1844
2068
  return false;
1845
2069
  }
1846
- return isCodexThreadLoadError(error);
2070
+ return isCodexThreadLoadError(error) || isCodexRequestTimeoutError(error);
1847
2071
  }
1848
2072
  function isCodexThreadLoadError(error) {
1849
2073
  const message = error instanceof Error ? error.message : String(error);
@@ -1851,6 +2075,9 @@ function isCodexThreadLoadError(error) {
1851
2075
  return (normalized.includes("thread not loaded") ||
1852
2076
  normalized.includes("no rollout found for thread id"));
1853
2077
  }
2078
+ function isCodexRequestTimeoutError(error) {
2079
+ return error instanceof Error && error.message === "SERVER_TIMEOUT";
2080
+ }
1854
2081
  function readProp(value, key) {
1855
2082
  if (!value || typeof value !== "object") {
1856
2083
  return null;