@jingyi0605/codingns 0.5.5 → 0.6.0

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 (178) hide show
  1. package/dist/public/assets/{AdaptiveButlerPage-CUyNL98E.js → AdaptiveButlerPage-uFwDdN-F.js} +3 -3
  2. package/dist/public/assets/{App-BFP7LCSC.js → App-BZvapsi8.js} +3 -3
  3. package/dist/public/assets/App-CcDXqFl1.css +1 -0
  4. package/dist/public/assets/{BootstrapPage-G74dX2Us.js → BootstrapPage-gHSoa4JN.js} +1 -1
  5. package/dist/public/assets/ConversationPage-z3sXtKZ7.js +4 -0
  6. package/dist/public/assets/{DesktopDetachPreviewPage-IV7oEdOX.js → DesktopDetachPreviewPage-4eMRxiBW.js} +1 -1
  7. package/dist/public/assets/DesktopWindowPage-CZcoGApB.js +2 -0
  8. package/dist/public/assets/FileContextPanel-C3qex8bb.js +1 -0
  9. package/dist/public/assets/GitSidebar-BK6H16XU.js +6 -0
  10. package/dist/public/assets/{MobileCreateSessionSheet-DqVwz_Hp.js → MobileCreateSessionSheet-BYfbvK8o.js} +1 -1
  11. package/dist/public/assets/MobileSheet-Ckug8hTb.js +1 -0
  12. package/dist/public/assets/{MobileTopHeaderFrame-COTc7cRr.js → MobileTopHeaderFrame-Bwv8Ovm_.js} +1 -1
  13. package/dist/public/assets/MobileWorkspaceSwitcherHeader-RqWrBdn2.js +1 -0
  14. package/dist/public/assets/RelayConnectEntryPage-D_4YL-YH.js +1 -0
  15. package/dist/public/assets/ServerSettingsModal-CMSm3BZU.js +1 -0
  16. package/dist/public/assets/SessionIndexPage-DuK10DL5.js +1 -0
  17. package/dist/public/assets/SettingsPage-fyD-xaHL.js +1 -0
  18. package/dist/public/assets/TerminalManagerPanel-CCLr1Ypk.js +1 -0
  19. package/dist/public/assets/{TerminalPage-DpsvQQVR.js → TerminalPage-DaooFaJ4.js} +19 -19
  20. package/dist/public/assets/{TerminalRuntimeFallbackModal-CNzOt5v5.js → TerminalRuntimeFallbackModal-aUzjEBwP.js} +1 -1
  21. package/dist/public/assets/ToolFilesPage-CGxBvYG0.js +1 -0
  22. package/dist/public/assets/ToolGitPage-C264yjS9.js +1 -0
  23. package/dist/public/assets/ToolProcessesPage-BOP4A1cb.js +1 -0
  24. package/dist/public/assets/ToolsHomePage-CQxGiKQA.js +1 -0
  25. package/dist/public/assets/WorkbenchLandingPage-CvAY68ca.js +1 -0
  26. package/dist/public/assets/WorkbenchLayout-DGm8Tc5M.js +3 -0
  27. package/dist/public/assets/{WorkbenchModal-CbDxaCOR.js → WorkbenchModal-0tPIIhca.js} +1 -1
  28. package/dist/public/assets/{WorkbenchShellRoute-BMcnFadA.css → WorkbenchShellRoute-BF0nHWOk.css} +1 -1
  29. package/dist/public/assets/WorkbenchShellRoute-DBBOsJo9.js +1 -0
  30. package/dist/public/assets/WorkspaceDebugDetailPage-CDerFYd2.js +1 -0
  31. package/dist/public/assets/WorkspaceDetailPage-BlJc1CHE.js +1 -0
  32. package/dist/public/assets/WorkspaceHomePage-BUsKJ3lv.js +1 -0
  33. package/dist/public/assets/client-runtime-manager-BZpL17fc.js +1 -0
  34. package/dist/public/assets/{default-session-permission-mode-Cu5SreTG.js → default-session-permission-mode-DT4SGiwp.js} +1 -1
  35. package/dist/public/assets/{file-tree-icon-BMKuc5pw.js → file-tree-icon-Db5LXC8h.js} +7 -7
  36. package/dist/public/assets/index-BZLcEHW3.js +42 -0
  37. package/dist/public/assets/index-BbspQPC2.css +1 -0
  38. package/dist/public/assets/login-direct-candidate-resolver-1mxe_Oh8.js +1 -0
  39. package/dist/public/assets/{preferences-service-gv_9vGKz.js → preferences-service-DWnzl5a0.js} +1 -1
  40. package/dist/public/assets/relay-entry-C5_Iay0I.js +1 -0
  41. package/dist/public/assets/session-runtime-machine-DdLeDqQr.js +17 -0
  42. package/dist/public/assets/{styles-BWPBZvze.css → styles-CsEMfdaS.css} +1 -1
  43. package/dist/public/assets/{terminal-runtime-meta-B9xJGY__.js → terminal-runtime-meta-cdtWVfCm.js} +1 -1
  44. package/dist/public/assets/{useRegisteredDebugTemplates-CDfl54Wt.js → useRegisteredDebugTemplates-oFAQNIqh.js} +1 -1
  45. package/dist/public/assets/window-BVUB8gMK.js +1 -0
  46. package/dist/public/index.html +2 -2
  47. package/dist/server/config/env.d.ts +1 -0
  48. package/dist/server/config/env.js +3 -0
  49. package/dist/server/config/env.js.map +1 -1
  50. package/dist/server/modules/client/npm-global-package-service.d.ts +7 -1
  51. package/dist/server/modules/client/npm-global-package-service.js +149 -43
  52. package/dist/server/modules/client/npm-global-package-service.js.map +1 -1
  53. package/dist/server/modules/client/service-update-task-service.js +6 -2
  54. package/dist/server/modules/client/service-update-task-service.js.map +1 -1
  55. package/dist/server/modules/client/service-update-types.d.ts +2 -0
  56. package/dist/server/modules/git/git-controller.d.ts +3 -0
  57. package/dist/server/modules/git/git-controller.js +3 -0
  58. package/dist/server/modules/git/git-controller.js.map +1 -1
  59. package/dist/server/modules/git/git-read-service.js +47 -1
  60. package/dist/server/modules/git/git-read-service.js.map +1 -1
  61. package/dist/server/modules/git/git-write-service.d.ts +4 -0
  62. package/dist/server/modules/git/git-write-service.js +24 -0
  63. package/dist/server/modules/git/git-write-service.js.map +1 -1
  64. package/dist/server/modules/git/types.d.ts +1 -0
  65. package/dist/server/modules/git/workspace-repo-guard.d.ts +2 -0
  66. package/dist/server/modules/git/workspace-repo-guard.js +24 -10
  67. package/dist/server/modules/git/workspace-repo-guard.js.map +1 -1
  68. package/dist/server/modules/parallel-sessions/parallel-session-controller.d.ts +53 -0
  69. package/dist/server/modules/parallel-sessions/parallel-session-controller.js +70 -0
  70. package/dist/server/modules/parallel-sessions/parallel-session-controller.js.map +1 -0
  71. package/dist/server/modules/parallel-sessions/parallel-session-group-service.d.ts +83 -0
  72. package/dist/server/modules/parallel-sessions/parallel-session-group-service.js +591 -0
  73. package/dist/server/modules/parallel-sessions/parallel-session-group-service.js.map +1 -0
  74. package/dist/server/modules/parallel-sessions/session-isolated-workspace-service.d.ts +56 -0
  75. package/dist/server/modules/parallel-sessions/session-isolated-workspace-service.js +483 -0
  76. package/dist/server/modules/parallel-sessions/session-isolated-workspace-service.js.map +1 -0
  77. package/dist/server/modules/relay-tunnel/relay-tunnel-candidate-endpoints.d.ts +2 -0
  78. package/dist/server/modules/relay-tunnel/relay-tunnel-candidate-endpoints.js +129 -0
  79. package/dist/server/modules/relay-tunnel/relay-tunnel-candidate-endpoints.js.map +1 -0
  80. package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.js +12 -9
  81. package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.js.map +1 -1
  82. package/dist/server/modules/relay-tunnel/relay-tunnel-service.js +1 -128
  83. package/dist/server/modules/relay-tunnel/relay-tunnel-service.js.map +1 -1
  84. package/dist/server/modules/sessions/codex-app-server-helper-client.d.ts +3 -0
  85. package/dist/server/modules/sessions/codex-app-server-helper-client.js +56 -45
  86. package/dist/server/modules/sessions/codex-app-server-helper-client.js.map +1 -1
  87. package/dist/server/modules/sessions/codex-app-server-helper-process.js +21 -2
  88. package/dist/server/modules/sessions/codex-app-server-helper-process.js.map +1 -1
  89. package/dist/server/modules/sessions/session-history-service.d.ts +10 -1
  90. package/dist/server/modules/sessions/session-history-service.js +142 -14
  91. package/dist/server/modules/sessions/session-history-service.js.map +1 -1
  92. package/dist/server/modules/sessions/session-live-runtime-service.d.ts +8 -0
  93. package/dist/server/modules/sessions/session-live-runtime-service.js +208 -25
  94. package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
  95. package/dist/server/modules/workbench/codex-archive-watcher.d.ts +16 -0
  96. package/dist/server/modules/workbench/codex-archive-watcher.js +50 -0
  97. package/dist/server/modules/workbench/codex-archive-watcher.js.map +1 -0
  98. package/dist/server/modules/workbench/workbench-service.d.ts +11 -2
  99. package/dist/server/modules/workbench/workbench-service.js +37 -8
  100. package/dist/server/modules/workbench/workbench-service.js.map +1 -1
  101. package/dist/server/modules/workbench/workspace-panel-snapshot-service.d.ts +1 -1
  102. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js +26 -3
  103. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js.map +1 -1
  104. package/dist/server/modules/workspace/workspace-service.d.ts +3 -1
  105. package/dist/server/modules/workspace/workspace-service.js +10 -2
  106. package/dist/server/modules/workspace/workspace-service.js.map +1 -1
  107. package/dist/server/modules/worktree/worktree-base-ref-resolver.d.ts +20 -0
  108. package/dist/server/modules/worktree/worktree-base-ref-resolver.js +111 -0
  109. package/dist/server/modules/worktree/worktree-base-ref-resolver.js.map +1 -0
  110. package/dist/server/modules/worktree/worktree-cleanup-service.js +9 -3
  111. package/dist/server/modules/worktree/worktree-cleanup-service.js.map +1 -1
  112. package/dist/server/modules/worktree/worktree-manager.d.ts +0 -1
  113. package/dist/server/modules/worktree/worktree-manager.js +14 -20
  114. package/dist/server/modules/worktree/worktree-manager.js.map +1 -1
  115. package/dist/server/routes/git.js +1 -0
  116. package/dist/server/routes/git.js.map +1 -1
  117. package/dist/server/routes/parallel-groups.d.ts +3 -0
  118. package/dist/server/routes/parallel-groups.js +9 -0
  119. package/dist/server/routes/parallel-groups.js.map +1 -0
  120. package/dist/server/server/create-server.d.ts +8 -0
  121. package/dist/server/server/create-server.js +38 -4
  122. package/dist/server/server/create-server.js.map +1 -1
  123. package/dist/server/server/workbench-runtime-terminal-sync.d.ts +14 -0
  124. package/dist/server/server/workbench-runtime-terminal-sync.js +17 -0
  125. package/dist/server/server/workbench-runtime-terminal-sync.js.map +1 -0
  126. package/dist/server/storage/repositories/parallel-session-group-repository.d.ts +11 -0
  127. package/dist/server/storage/repositories/parallel-session-group-repository.js +131 -0
  128. package/dist/server/storage/repositories/parallel-session-group-repository.js.map +1 -0
  129. package/dist/server/storage/repositories/parallel-session-member-repository.d.ts +12 -0
  130. package/dist/server/storage/repositories/parallel-session-member-repository.js +150 -0
  131. package/dist/server/storage/repositories/parallel-session-member-repository.js.map +1 -0
  132. package/dist/server/storage/repositories/session-isolated-workspace-repository.d.ts +15 -0
  133. package/dist/server/storage/repositories/session-isolated-workspace-repository.js +230 -0
  134. package/dist/server/storage/repositories/session-isolated-workspace-repository.js.map +1 -0
  135. package/dist/server/storage/sqlite/schema.sql +73 -0
  136. package/dist/server/types/domain.d.ts +72 -0
  137. package/dist/server/ws/workbench-ws-hub.d.ts +3 -1
  138. package/dist/server/ws/workbench-ws-hub.js +23 -4
  139. package/dist/server/ws/workbench-ws-hub.js.map +1 -1
  140. package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +1 -0
  141. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +34 -0
  142. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
  143. package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.d.ts +3 -0
  144. package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js +46 -22
  145. package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js.map +1 -1
  146. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +488 -281
  147. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
  148. package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.js +29 -5
  149. package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.js.map +1 -1
  150. package/package.json +1 -1
  151. package/dist/public/assets/App-DUAg5urj.css +0 -1
  152. package/dist/public/assets/ConversationPage-Bz0_tvvM.js +0 -2
  153. package/dist/public/assets/DesktopWindowPage-BBmHyRg5.js +0 -2
  154. package/dist/public/assets/FileContextPanel--FVTxDrq.js +0 -1
  155. package/dist/public/assets/GitSidebar-DAiSi9oc.js +0 -6
  156. package/dist/public/assets/MobileSheet-D1lMrcvD.js +0 -1
  157. package/dist/public/assets/MobileWorkspaceSwitcherHeader-DJPV9ym2.js +0 -1
  158. package/dist/public/assets/RelayConnectEntryPage-dSwU8VzK.js +0 -1
  159. package/dist/public/assets/ServerSettingsModal-B34ms3ze.js +0 -1
  160. package/dist/public/assets/SessionIndexPage-D3tG1gmM.js +0 -1
  161. package/dist/public/assets/SettingsPage-B3-6-5GL.js +0 -1
  162. package/dist/public/assets/TerminalManagerPanel-DhuTEdzV.js +0 -1
  163. package/dist/public/assets/ToolFilesPage-BX9QDi9Y.js +0 -1
  164. package/dist/public/assets/ToolGitPage-4VtFox3p.js +0 -1
  165. package/dist/public/assets/ToolProcessesPage-DZJC6Qnt.js +0 -1
  166. package/dist/public/assets/ToolsHomePage-D7JbrAWv.js +0 -1
  167. package/dist/public/assets/WorkbenchLandingPage-C0yqnzqh.js +0 -1
  168. package/dist/public/assets/WorkbenchLayout-Brlj8K3i.js +0 -3
  169. package/dist/public/assets/WorkbenchShellRoute-puGpdDFY.js +0 -1
  170. package/dist/public/assets/WorkspaceDebugDetailPage-fTGweC9N.js +0 -1
  171. package/dist/public/assets/WorkspaceDetailPage-BtaIzSDB.js +0 -1
  172. package/dist/public/assets/WorkspaceHomePage-CUmmYDrM.js +0 -1
  173. package/dist/public/assets/client-runtime-manager-RHFa_iWo.js +0 -1
  174. package/dist/public/assets/index-Cq3ue0za.css +0 -1
  175. package/dist/public/assets/index-DEbFT-Aq.js +0 -42
  176. package/dist/public/assets/session-runtime-machine-Bfnxkk9B.js +0 -17
  177. package/dist/public/assets/window-BWqRixxq.js +0 -1
  178. /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;
@@ -61,108 +62,115 @@ export class CodexRuntimeAdapter {
61
62
  const transport = this.options.transportFactory
62
63
  ? this.options.transportFactory()
63
64
  : 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, {
65
+ try {
66
+ const initializeStartedAtMs = performance.now();
67
+ await transport.initialize();
68
+ logCodexRuntimeStep("start_session.initialize", initializeStartedAtMs, {
69
+ sessionId: request.sessionId,
70
+ workspacePath: request.workspacePath
71
+ });
72
+ const abortController = new AbortController();
73
+ const eventQueue = createAsyncEventQueue();
74
+ const translateNotification = createCodexAppServerNotificationTranslator();
75
+ const forwardTranslatedNotification = createCodexTranslatedNotificationForwarder(eventQueue);
76
+ const resumedSyntheticSession = await this.resumeSyntheticThreadFromHistory(transport, request);
77
+ const startedSession = resumedSyntheticSession ??
78
+ await (async () => {
79
+ const startThreadStartedAtMs = performance.now();
80
+ const started = await transport.startThread(request);
81
+ logCodexRuntimeStep("start_session.thread_start", startThreadStartedAtMs, {
82
+ sessionId: request.sessionId,
83
+ providerSessionId: started.providerSessionId
84
+ });
85
+ return started;
86
+ })();
87
+ const providerSessionId = startedSession.providerSessionId;
88
+ const syntheticRawStoreRef = buildRuntimeRawStoreRef(resolveRuntimeStoreKey(providerSessionId, request.sessionId));
89
+ const rawStoreRef = pickAvailableCodexRawStoreRef(providerSessionId, resumedSyntheticSession
90
+ ? [resumedSyntheticSession.rawStoreRef]
91
+ : [startedSession.rawStoreRef, request.rawStoreRef], syntheticRawStoreRef);
92
+ logCodexRuntimeStep("start_session.raw_store_ref_ready", launchPerfStartedAtMs, {
93
+ sessionId: request.sessionId,
94
+ providerSessionId,
95
+ synthetic: isSyntheticRawStoreRef(rawStoreRef),
96
+ hasProviderRawStoreRef: Boolean(startedSession.rawStoreRef),
97
+ providerRawStoreRefExists: Boolean(startedSession.rawStoreRef && existsSync(startedSession.rawStoreRef))
98
+ });
99
+ sink.updateSessionBinding({
100
+ providerSessionId,
101
+ rawStoreRef
102
+ });
103
+ let firstNotificationLogged = false;
104
+ transport.setNotificationHandler(async (notification) => {
105
+ if (!firstNotificationLogged) {
106
+ firstNotificationLogged = true;
107
+ logCodexRuntimeStep("start_session.first_notification", launchPerfStartedAtMs, {
108
+ sessionId: request.sessionId,
109
+ providerSessionId,
110
+ method: ensureText(notification.method).trim() || null
111
+ });
112
+ }
113
+ const translated = translateNotification(notification);
114
+ forwardTranslatedNotification(translated);
115
+ });
116
+ transport.setServerRequestHandler(async (serverRequest) => {
117
+ if (!this.options.handleServerRequest) {
118
+ throw new Error("CODEX_APP_SERVER_REQUEST_NOT_SUPPORTED");
119
+ }
120
+ return this.options.handleServerRequest({
105
121
  sessionId: request.sessionId,
106
122
  providerSessionId,
107
- method: ensureText(notification.method).trim() || null
123
+ request: serverRequest
108
124
  });
125
+ });
126
+ transport.setOnClose((error) => {
127
+ if (error) {
128
+ eventQueue.push({
129
+ type: "turn.failed",
130
+ timestamp: nextTimestamp(),
131
+ error: error.message
132
+ });
133
+ }
134
+ eventQueue.close();
135
+ });
136
+ const startTurnStartedAtMs = performance.now();
137
+ const startTurnResult = await transport.startTurn(request, providerSessionId);
138
+ const startTurnNotification = startTurnResult?.notification ?? null;
139
+ if (startTurnNotification) {
140
+ const translated = translateNotification(startTurnNotification);
141
+ forwardTranslatedNotification(translated);
109
142
  }
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({
143
+ logCodexRuntimeStep("start_session.turn_start", startTurnStartedAtMs, {
118
144
  sessionId: request.sessionId,
119
- providerSessionId,
120
- request: serverRequest
145
+ providerSessionId
121
146
  });
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
- };
147
+ logCodexRuntimeStep("start_session.ready", launchPerfStartedAtMs, {
148
+ sessionId: request.sessionId,
149
+ providerSessionId
150
+ });
151
+ return {
152
+ providerSessionId,
153
+ rawStoreRef,
154
+ submitDuringRun: async (options) => {
155
+ await transport.steerTurn(options);
156
+ },
157
+ interrupt: async () => {
158
+ abortController.abort();
159
+ await transport.interruptTurn().catch(() => {
160
+ return;
161
+ });
162
+ transport.close();
163
+ },
164
+ isAlive: () => transport.isClosed() === false,
165
+ completed: this.runTurn(null, request, sink, providerSessionId, rawStoreRef, abortController, eventQueue.iterator, [], launchedAtMs, launchPerfStartedAtMs).finally(() => {
166
+ transport.close();
167
+ })
168
+ };
169
+ }
170
+ catch (error) {
171
+ transport.close();
172
+ throw error;
173
+ }
166
174
  }
167
175
  async resumeSyntheticThreadFromHistory(transport, request) {
168
176
  const history = buildSyntheticResumeHistory(request.rawStoreRef);
@@ -191,137 +199,144 @@ export class CodexRuntimeAdapter {
191
199
  const transport = this.options.transportFactory
192
200
  ? this.options.transportFactory()
193
201
  : 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
202
  try {
207
- resumed = await transport.resumeThread(request, resolvedSessionId);
208
- logCodexRuntimeStep("continue_session.thread_resume", resumeThreadStartedAtMs, {
203
+ const runtimeStartedAtMs = performance.now();
204
+ const initializeStartedAtMs = performance.now();
205
+ await transport.initialize();
206
+ logCodexRuntimeStep("continue_session.initialize", initializeStartedAtMs, {
209
207
  sessionId: request.sessionId,
210
- providerSessionId: resolvedSessionId,
211
- fallback: false
212
- });
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, {
234
- sessionId: request.sessionId,
235
- requestedProviderSessionId: providerSessionId,
236
- providerSessionId: resolvedSessionId,
237
- historyLength: resumeHistory.length
208
+ providerSessionId
238
209
  });
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, {
210
+ const syntheticRawStoreRef = buildRuntimeRawStoreRef(providerSessionId);
211
+ let resolvedSessionId = providerSessionId;
212
+ let resolvedFallbackHistoryRawStoreRef = null;
213
+ const resumeThreadStartedAtMs = performance.now();
214
+ let resumed;
215
+ try {
216
+ resumed = await transport.resumeThread(request, resolvedSessionId);
217
+ logCodexRuntimeStep("continue_session.thread_resume", resumeThreadStartedAtMs, {
264
218
  sessionId: request.sessionId,
265
219
  providerSessionId: resolvedSessionId,
266
- method: ensureText(notification.method).trim() || null
220
+ fallback: false
267
221
  });
268
222
  }
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");
223
+ catch (error) {
224
+ const fallbackHistorySource = await this.resolveContinueFallbackHistorySource({
225
+ providerSessionId,
226
+ rawStoreRef: request.rawStoreRef,
227
+ workspacePath: request.workspacePath
228
+ });
229
+ const resumeHistory = fallbackHistorySource?.history ?? [];
230
+ if (!shouldFallbackCodexContinueFromHistory(error, resumeHistory)) {
231
+ throw error;
232
+ }
233
+ resolvedFallbackHistoryRawStoreRef = fallbackHistorySource?.rawStoreRef ?? null;
234
+ const resumeFallbackStartedAtMs = performance.now();
235
+ resumed = await transport.resumeThreadFromHistory({
236
+ providerSessionId: null,
237
+ workspacePath: request.workspacePath,
238
+ history: resumeHistory,
239
+ model: request.options.model
240
+ });
241
+ resolvedSessionId = resumed.providerSessionId;
242
+ logCodexRuntimeStep("continue_session.thread_resume_from_history_fallback", resumeFallbackStartedAtMs, {
243
+ sessionId: request.sessionId,
244
+ requestedProviderSessionId: providerSessionId,
245
+ providerSessionId: resolvedSessionId,
246
+ historyLength: resumeHistory.length
247
+ });
275
248
  }
276
- return this.options.handleServerRequest({
249
+ const pickedRawStoreRef = pickAvailableCodexRawStoreRef(resolvedSessionId, [resolvedFallbackHistoryRawStoreRef, request.rawStoreRef, resumed.rawStoreRef], syntheticRawStoreRef);
250
+ const rawStoreRef = !resumed.rawStoreRef?.trim() && resolvedFallbackHistoryRawStoreRef
251
+ ? resolvedFallbackHistoryRawStoreRef
252
+ : pickedRawStoreRef;
253
+ const abortController = new AbortController();
254
+ const eventQueue = createAsyncEventQueue();
255
+ const translateNotification = createCodexAppServerNotificationTranslator();
256
+ const forwardTranslatedNotification = createCodexTranslatedNotificationForwarder(eventQueue);
257
+ logCodexRuntimeStep("continue_session.raw_store_ref_ready", runtimeStartedAtMs, {
277
258
  sessionId: request.sessionId,
278
259
  providerSessionId: resolvedSessionId,
279
- request: serverRequest
260
+ synthetic: isSyntheticRawStoreRef(rawStoreRef),
261
+ hasResumedRawStoreRef: Boolean(resumed.rawStoreRef),
262
+ hasRequestRawStoreRef: Boolean(request.rawStoreRef),
263
+ resumedRawStoreRefExists: Boolean(resumed.rawStoreRef && existsSync(resumed.rawStoreRef))
280
264
  });
281
- });
282
- transport.setOnClose((error) => {
283
- if (error) {
284
- eventQueue.push({
285
- type: "turn.failed",
286
- timestamp: nextTimestamp(),
287
- error: error.message
265
+ sink.updateSessionBinding({
266
+ providerSessionId: resolvedSessionId,
267
+ rawStoreRef
268
+ });
269
+ let firstNotificationLogged = false;
270
+ transport.setNotificationHandler(async (notification) => {
271
+ if (!firstNotificationLogged) {
272
+ firstNotificationLogged = true;
273
+ logCodexRuntimeStep("continue_session.first_notification", runtimeStartedAtMs, {
274
+ sessionId: request.sessionId,
275
+ providerSessionId: resolvedSessionId,
276
+ method: ensureText(notification.method).trim() || null
277
+ });
278
+ }
279
+ const translated = translateNotification(notification);
280
+ forwardTranslatedNotification(translated);
281
+ });
282
+ transport.setServerRequestHandler(async (serverRequest) => {
283
+ if (!this.options.handleServerRequest) {
284
+ throw new Error("CODEX_APP_SERVER_REQUEST_NOT_SUPPORTED");
285
+ }
286
+ return this.options.handleServerRequest({
287
+ sessionId: request.sessionId,
288
+ providerSessionId: resolvedSessionId,
289
+ request: serverRequest
288
290
  });
291
+ });
292
+ transport.setOnClose((error) => {
293
+ if (error) {
294
+ eventQueue.push({
295
+ type: "turn.failed",
296
+ timestamp: nextTimestamp(),
297
+ error: error.message
298
+ });
299
+ }
300
+ eventQueue.close();
301
+ });
302
+ const startTurnStartedAtMs = performance.now();
303
+ const startTurnResult = await transport.startTurn(request, resolvedSessionId);
304
+ const startTurnNotification = startTurnResult?.notification ?? null;
305
+ if (startTurnNotification) {
306
+ const translated = translateNotification(startTurnNotification);
307
+ forwardTranslatedNotification(translated);
289
308
  }
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
- };
309
+ logCodexRuntimeStep("continue_session.turn_start", startTurnStartedAtMs, {
310
+ sessionId: request.sessionId,
311
+ providerSessionId: resolvedSessionId
312
+ });
313
+ logCodexRuntimeStep("continue_session.ready", runtimeStartedAtMs, {
314
+ sessionId: request.sessionId,
315
+ providerSessionId: resolvedSessionId
316
+ });
317
+ return {
318
+ providerSessionId: resolvedSessionId,
319
+ rawStoreRef,
320
+ submitDuringRun: async (options) => {
321
+ await transport.steerTurn(options);
322
+ },
323
+ interrupt: async () => {
324
+ abortController.abort();
325
+ await transport.interruptTurn().catch(() => {
326
+ return;
327
+ });
328
+ transport.close();
329
+ },
330
+ isAlive: () => transport.isClosed() === false,
331
+ completed: this.runTurn(null, request, sink, resolvedSessionId, rawStoreRef, abortController, eventQueue.iterator, [], Date.now()).finally(() => {
332
+ transport.close();
333
+ })
334
+ };
335
+ }
336
+ catch (error) {
337
+ transport.close();
338
+ throw error;
339
+ }
325
340
  }
326
341
  async resolveContinueFallbackHistorySource(input) {
327
342
  const candidates = [];
@@ -1230,110 +1245,285 @@ function normalizeReplayKeyText(value) {
1230
1245
  }
1231
1246
  return ensureText(value).trim();
1232
1247
  }
1233
- function translateCodexAppServerNotification(notification) {
1234
- const method = ensureText(notification.method).trim();
1235
- const params = toRecord(notification.params) ?? {};
1236
- if (method === "turn/started") {
1248
+ function createCodexAppServerNotificationTranslator() {
1249
+ const agentMessageTextById = new Map();
1250
+ const reasoningSummaryPartsById = new Map();
1251
+ const reasoningContentPartsById = new Map();
1252
+ const resetStreamState = () => {
1253
+ agentMessageTextById.clear();
1254
+ reasoningSummaryPartsById.clear();
1255
+ reasoningContentPartsById.clear();
1256
+ };
1257
+ const ensureIndexedTextPart = (store, itemId, index) => {
1258
+ if (!itemId || !Number.isInteger(index) || index < 0) {
1259
+ return null;
1260
+ }
1261
+ const existing = store.get(itemId) ?? [];
1262
+ while (existing.length <= index) {
1263
+ existing.push("");
1264
+ }
1265
+ store.set(itemId, existing);
1266
+ return existing;
1267
+ };
1268
+ const buildReasoningSyntheticItem = (itemId) => {
1269
+ // 这里必须复制一份快照,不能把可变数组引用直接塞进事件队列。
1270
+ // 否则后续 delta 继续追加时,前一帧事件里的 summary/content 也会被同步改掉,
1271
+ // 最终所有帧都会看起来像“最后一帧”,下游稳定消息去重就会把中间增量吃掉。
1272
+ const summary = [...(reasoningSummaryPartsById.get(itemId) ?? [])];
1273
+ const content = [...(reasoningContentPartsById.get(itemId) ?? [])];
1237
1274
  return {
1238
- events: [],
1239
- terminal: false,
1240
- turnId: ensureText(readProp(readProp(params, "turn"), "id")).trim() || null
1275
+ type: "reasoning",
1276
+ id: itemId,
1277
+ summary,
1278
+ content
1241
1279
  };
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") {
1280
+ };
1281
+ const translateAgentMessageDelta = (params) => {
1282
+ const itemId = ensureText(params.itemId).trim();
1283
+ const delta = ensureText(params.delta);
1284
+ if (!itemId || delta.length === 0) {
1262
1285
  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
1286
+ events: [],
1287
+ terminal: false,
1288
+ turnId: ensureText(params.turnId).trim() || null
1272
1289
  };
1273
1290
  }
1291
+ const nextText = `${agentMessageTextById.get(itemId) ?? ""}${delta}`;
1292
+ agentMessageTextById.set(itemId, nextText);
1274
1293
  return {
1275
1294
  events: [
1276
- ...itemEvents,
1277
1295
  {
1278
- type: "turn.completed",
1296
+ type: "item.updated",
1297
+ item: {
1298
+ type: "agent_message",
1299
+ id: itemId,
1300
+ text: nextText
1301
+ },
1279
1302
  timestamp: nextTimestamp()
1280
1303
  }
1281
1304
  ],
1282
- terminal: true,
1283
- turnId: ensureText(turn?.id).trim() || null
1305
+ terminal: false,
1306
+ turnId: ensureText(params.turnId).trim() || null
1284
1307
  };
1285
- }
1286
- if (method === "error") {
1287
- const error = toRecord(params.error);
1288
- const detail = buildCodexAppServerErrorDetail(error);
1289
- if (params.willRetry === true) {
1308
+ };
1309
+ const translateReasoningSummaryPartAdded = (params) => {
1310
+ const itemId = ensureText(params.itemId).trim();
1311
+ const summaryIndex = Math.trunc(Number(params.summaryIndex));
1312
+ ensureIndexedTextPart(reasoningSummaryPartsById, itemId, summaryIndex);
1313
+ return {
1314
+ events: [],
1315
+ terminal: false,
1316
+ turnId: ensureText(params.turnId).trim() || null
1317
+ };
1318
+ };
1319
+ const translateReasoningSummaryTextDelta = (params) => {
1320
+ const itemId = ensureText(params.itemId).trim();
1321
+ const summaryIndex = Math.trunc(Number(params.summaryIndex));
1322
+ const delta = ensureText(params.delta);
1323
+ const parts = ensureIndexedTextPart(reasoningSummaryPartsById, itemId, summaryIndex);
1324
+ if (!parts || delta.length === 0) {
1290
1325
  return {
1291
1326
  events: [],
1292
1327
  terminal: false,
1293
1328
  turnId: ensureText(params.turnId).trim() || null
1294
1329
  };
1295
1330
  }
1331
+ parts[summaryIndex] = `${parts[summaryIndex] ?? ""}${delta}`;
1296
1332
  return {
1297
1333
  events: [
1298
1334
  {
1299
- type: "turn.failed",
1300
- timestamp: nextTimestamp(),
1301
- error: detail
1335
+ type: "item.updated",
1336
+ item: buildReasoningSyntheticItem(itemId),
1337
+ timestamp: nextTimestamp()
1302
1338
  }
1303
1339
  ],
1304
- terminal: true,
1340
+ terminal: false,
1305
1341
  turnId: ensureText(params.turnId).trim() || null
1306
1342
  };
1307
- }
1308
- if (method === "item/started" || method === "item/updated" || method === "item/completed") {
1309
- const item = translateCodexAppServerItem(toRecord(params.item));
1310
- if (!item) {
1343
+ };
1344
+ const translateReasoningTextDelta = (params) => {
1345
+ const itemId = ensureText(params.itemId).trim();
1346
+ const contentIndex = Math.trunc(Number(params.contentIndex));
1347
+ const delta = ensureText(params.delta);
1348
+ const parts = ensureIndexedTextPart(reasoningContentPartsById, itemId, contentIndex);
1349
+ if (!parts || delta.length === 0) {
1311
1350
  return {
1312
1351
  events: [],
1313
1352
  terminal: false,
1314
- turnId: null
1353
+ turnId: ensureText(params.turnId).trim() || null
1315
1354
  };
1316
1355
  }
1356
+ parts[contentIndex] = `${parts[contentIndex] ?? ""}${delta}`;
1317
1357
  return {
1318
1358
  events: [
1319
1359
  {
1320
- type: method === "item/started"
1321
- ? "item.started"
1322
- : method === "item/updated"
1323
- ? "item.updated"
1324
- : "item.completed",
1325
- item,
1360
+ type: "item.updated",
1361
+ item: buildReasoningSyntheticItem(itemId),
1326
1362
  timestamp: nextTimestamp()
1327
1363
  }
1328
1364
  ],
1329
1365
  terminal: false,
1366
+ turnId: ensureText(params.turnId).trim() || null
1367
+ };
1368
+ };
1369
+ return (notification) => {
1370
+ const method = ensureText(notification.method).trim();
1371
+ const params = toRecord(notification.params) ?? {};
1372
+ if (method === "turn/started") {
1373
+ return {
1374
+ events: [],
1375
+ terminal: false,
1376
+ turnId: ensureText(readProp(readProp(params, "turn"), "id")).trim() || null
1377
+ };
1378
+ }
1379
+ if (method === "turn/completed") {
1380
+ const turn = toRecord(params.turn);
1381
+ const status = ensureText(turn?.status).trim();
1382
+ const itemEvents = translateCodexAppServerTurnItems(turn, "item.completed");
1383
+ resetStreamState();
1384
+ if (status === "failed") {
1385
+ return {
1386
+ events: [
1387
+ ...itemEvents,
1388
+ {
1389
+ type: "turn.failed",
1390
+ timestamp: nextTimestamp(),
1391
+ error: ensureText(readProp(turn?.error, "message")).trim() || "codex turn failed"
1392
+ }
1393
+ ],
1394
+ terminal: true,
1395
+ turnId: ensureText(turn?.id).trim() || null
1396
+ };
1397
+ }
1398
+ if (status === "interrupted") {
1399
+ return {
1400
+ events: [
1401
+ ...itemEvents,
1402
+ {
1403
+ type: "turn.interrupted",
1404
+ timestamp: nextTimestamp()
1405
+ }
1406
+ ],
1407
+ terminal: true,
1408
+ turnId: ensureText(turn?.id).trim() || null
1409
+ };
1410
+ }
1411
+ return {
1412
+ events: [
1413
+ ...itemEvents,
1414
+ {
1415
+ type: "turn.completed",
1416
+ timestamp: nextTimestamp()
1417
+ }
1418
+ ],
1419
+ terminal: true,
1420
+ turnId: ensureText(turn?.id).trim() || null
1421
+ };
1422
+ }
1423
+ if (method === "error") {
1424
+ const error = toRecord(params.error);
1425
+ const detail = buildCodexAppServerErrorDetail(error);
1426
+ if (params.willRetry === true) {
1427
+ return {
1428
+ events: [],
1429
+ terminal: false,
1430
+ turnId: ensureText(params.turnId).trim() || null
1431
+ };
1432
+ }
1433
+ resetStreamState();
1434
+ return {
1435
+ events: [
1436
+ {
1437
+ type: "turn.failed",
1438
+ timestamp: nextTimestamp(),
1439
+ error: detail
1440
+ }
1441
+ ],
1442
+ terminal: true,
1443
+ turnId: ensureText(params.turnId).trim() || null
1444
+ };
1445
+ }
1446
+ if (method === "item/agentMessage/delta") {
1447
+ return translateAgentMessageDelta(params);
1448
+ }
1449
+ if (method === "item/reasoning/summaryPartAdded") {
1450
+ return translateReasoningSummaryPartAdded(params);
1451
+ }
1452
+ if (method === "item/reasoning/summaryTextDelta") {
1453
+ return translateReasoningSummaryTextDelta(params);
1454
+ }
1455
+ if (method === "item/reasoning/textDelta") {
1456
+ return translateReasoningTextDelta(params);
1457
+ }
1458
+ if (method === "item/started" || method === "item/updated" || method === "item/completed") {
1459
+ const item = translateCodexAppServerItem(toRecord(params.item));
1460
+ if (!item) {
1461
+ return {
1462
+ events: [],
1463
+ terminal: false,
1464
+ turnId: null
1465
+ };
1466
+ }
1467
+ if (ensureText(item.type).trim() === "agent_message") {
1468
+ const itemId = ensureText(item.id).trim();
1469
+ const itemText = ensureText(item.text);
1470
+ if (itemId) {
1471
+ if (itemText.length > 0) {
1472
+ agentMessageTextById.set(itemId, itemText);
1473
+ }
1474
+ else if (method === "item/completed") {
1475
+ agentMessageTextById.delete(itemId);
1476
+ }
1477
+ }
1478
+ }
1479
+ if (ensureText(item.type).trim() === "reasoning") {
1480
+ const itemId = ensureText(item.id).trim();
1481
+ if (itemId) {
1482
+ const summary = Array.isArray(item.summary)
1483
+ ? item.summary.map((entry) => ensureText(entry))
1484
+ : ensureText(item.summary).trim()
1485
+ ? [ensureText(item.summary)]
1486
+ : [];
1487
+ const content = Array.isArray(item.content)
1488
+ ? item.content.map((entry) => ensureText(entry))
1489
+ : ensureText(item.text).trim()
1490
+ ? [ensureText(item.text)]
1491
+ : [];
1492
+ if (summary.length > 0) {
1493
+ reasoningSummaryPartsById.set(itemId, summary);
1494
+ }
1495
+ else if (method === "item/completed") {
1496
+ reasoningSummaryPartsById.delete(itemId);
1497
+ }
1498
+ if (content.length > 0) {
1499
+ reasoningContentPartsById.set(itemId, content);
1500
+ }
1501
+ else if (method === "item/completed") {
1502
+ reasoningContentPartsById.delete(itemId);
1503
+ }
1504
+ }
1505
+ }
1506
+ return {
1507
+ events: [
1508
+ {
1509
+ type: method === "item/started"
1510
+ ? "item.started"
1511
+ : method === "item/updated"
1512
+ ? "item.updated"
1513
+ : "item.completed",
1514
+ item,
1515
+ timestamp: nextTimestamp()
1516
+ }
1517
+ ],
1518
+ terminal: false,
1519
+ turnId: null
1520
+ };
1521
+ }
1522
+ return {
1523
+ events: [],
1524
+ terminal: false,
1330
1525
  turnId: null
1331
1526
  };
1332
- }
1333
- return {
1334
- events: [],
1335
- terminal: false,
1336
- turnId: null
1337
1527
  };
1338
1528
  }
1339
1529
  function translateCodexAppServerTurnItems(turn, eventType) {
@@ -1796,7 +1986,20 @@ function writeJsonRpcMessage(child, payload) {
1796
1986
  function sendJsonRpcRequest(child, pendingResponses, createRequestId, input) {
1797
1987
  const id = createRequestId();
1798
1988
  return new Promise((resolve, reject) => {
1799
- pendingResponses.set(id, { resolve, reject });
1989
+ const timeout = setTimeout(() => {
1990
+ pendingResponses.delete(id);
1991
+ reject(new Error("SERVER_TIMEOUT"));
1992
+ }, CODEX_APP_SERVER_REQUEST_TIMEOUT_MS);
1993
+ pendingResponses.set(id, {
1994
+ resolve: (value) => {
1995
+ clearTimeout(timeout);
1996
+ resolve(value);
1997
+ },
1998
+ reject: (error) => {
1999
+ clearTimeout(timeout);
2000
+ reject(error);
2001
+ }
2002
+ });
1800
2003
  try {
1801
2004
  writeJsonRpcMessage(child, {
1802
2005
  jsonrpc: "2.0",
@@ -1806,6 +2009,7 @@ function sendJsonRpcRequest(child, pendingResponses, createRequestId, input) {
1806
2009
  });
1807
2010
  }
1808
2011
  catch (error) {
2012
+ clearTimeout(timeout);
1809
2013
  pendingResponses.delete(id);
1810
2014
  reject(error instanceof Error ? error : new Error("CODEX_APP_SERVER_REQUEST_WRITE_FAILED"));
1811
2015
  }
@@ -1843,7 +2047,7 @@ function shouldFallbackCodexContinueFromHistory(error, history) {
1843
2047
  if (history.length === 0) {
1844
2048
  return false;
1845
2049
  }
1846
- return isCodexThreadLoadError(error);
2050
+ return isCodexThreadLoadError(error) || isCodexRequestTimeoutError(error);
1847
2051
  }
1848
2052
  function isCodexThreadLoadError(error) {
1849
2053
  const message = error instanceof Error ? error.message : String(error);
@@ -1851,6 +2055,9 @@ function isCodexThreadLoadError(error) {
1851
2055
  return (normalized.includes("thread not loaded") ||
1852
2056
  normalized.includes("no rollout found for thread id"));
1853
2057
  }
2058
+ function isCodexRequestTimeoutError(error) {
2059
+ return error instanceof Error && error.message === "SERVER_TIMEOUT";
2060
+ }
1854
2061
  function readProp(value, key) {
1855
2062
  if (!value || typeof value !== "object") {
1856
2063
  return null;