@jingyi0605/codingns 0.7.4 → 0.8.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.
- package/README.md +6 -0
- package/bin/codingns.mjs +747 -28
- package/bin/office-mcp-server.mjs +620 -0
- package/dist/public/assets/{AdaptiveButlerPage-CgBX49t-.js → AdaptiveButlerPage-BsgVNRAa.js} +1 -1
- package/dist/public/assets/{App-tXOqoHNl.js → App-tPcbyRdS.js} +3 -3
- package/dist/public/assets/{BootstrapPage-DoRMz87R.js → BootstrapPage--MDOigQi.js} +1 -1
- package/dist/public/assets/{ConversationPage-DXR6Hp4O.js → ConversationPage-BBss5ED8.js} +6 -6
- package/dist/public/assets/{DesktopDetachPreviewPage-Cyk-ZYCk.js → DesktopDetachPreviewPage-CB8DoqwU.js} +1 -1
- package/dist/public/assets/{DesktopWindowPage-DNVNK3hs.js → DesktopWindowPage-GtIx5m8K.js} +1 -1
- package/dist/public/assets/FileContextPanel-BcM7AIT4.js +1 -0
- package/dist/public/assets/{GitSidebar-Cr3Z9OUI.js → GitSidebar-CMtkaxuI.js} +2 -2
- package/dist/public/assets/{MobileCreateSessionSheet-DMW0V6GJ.js → MobileCreateSessionSheet-CrFY41_8.js} +1 -1
- package/dist/public/assets/{MobileTopHeaderFrame-CkdnZ_MU.js → MobileTopHeaderFrame-DGVOzXyg.js} +1 -1
- package/dist/public/assets/{MobileWorkspaceSwitcherHeader-KIbqBYJN.js → MobileWorkspaceSwitcherHeader-DLkACTnQ.js} +1 -1
- package/dist/public/assets/{RelayConnectEntryPage-DIRBH3hw.js → RelayConnectEntryPage-0MPPjxtQ.js} +1 -1
- package/dist/public/assets/{ServerSettingsModal-C-9RxdWP.js → ServerSettingsModal-vgOhwus4.js} +1 -1
- package/dist/public/assets/{SessionIndexPage-bRlIydRA.js → SessionIndexPage-KK626Ra9.js} +1 -1
- package/dist/public/assets/{SettingsPage-CMEt4ua9.js → SettingsPage-B3edBJIo.js} +2 -2
- package/dist/public/assets/{TerminalManagerPanel-2bi9wVhT.js → TerminalManagerPanel-BxlhZp8c.js} +1 -1
- package/dist/public/assets/{TerminalPage-DayZz2Tf.js → TerminalPage-B6Rdhylx.js} +1 -1
- package/dist/public/assets/{TerminalRuntimeFallbackModal-DgwYcp-Y.js → TerminalRuntimeFallbackModal-BVLfrpSa.js} +1 -1
- package/dist/public/assets/{ToolFilesPage-YvnP_FXW.js → ToolFilesPage-N_gwwUjD.js} +1 -1
- package/dist/public/assets/{ToolGitPage-GMcQKtV9.js → ToolGitPage-DOcuuWM1.js} +1 -1
- package/dist/public/assets/{ToolProcessesPage-DFIQ7BCd.js → ToolProcessesPage-D-FfJ7Re.js} +1 -1
- package/dist/public/assets/{ToolsHomePage-CSilFzXR.js → ToolsHomePage-CHfPxd20.js} +1 -1
- package/dist/public/assets/{WorkbenchLandingPage-1VtToSz9.js → WorkbenchLandingPage-CTTnfovY.js} +1 -1
- package/dist/public/assets/WorkbenchLayout-CbpJg0g1.js +244 -0
- package/dist/public/assets/{WorkbenchModal-BWXYSXmC.js → WorkbenchModal-Bt_1fYmM.js} +1 -1
- package/dist/public/assets/WorkbenchShellRoute-B4XB8SwG.css +1 -0
- package/dist/public/assets/WorkbenchShellRoute-DyaMnPfS.js +1 -0
- package/dist/public/assets/{WorkspaceDebugDetailPage-Ux8_Q7la.js → WorkspaceDebugDetailPage-s7yuDIxR.js} +1 -1
- package/dist/public/assets/{WorkspaceDetailPage-B402p99m.js → WorkspaceDetailPage-Cf-gVpqK.js} +1 -1
- package/dist/public/assets/{WorkspaceHomePage-D2pob6HI.js → WorkspaceHomePage-COf6I8sT.js} +1 -1
- package/dist/public/assets/{client-runtime-manager-C5D76ewj.js → client-runtime-manager-DGdKvYzx.js} +1 -1
- package/dist/public/assets/file-tree-icon-BeHqeru9.js +590 -0
- package/dist/public/assets/index-CcaQt50x.css +1 -0
- package/dist/public/assets/index-CuzMc7q2.js +42 -0
- package/dist/public/assets/{login-direct-candidate-resolver-wXSaB0i7.js → login-direct-candidate-resolver-DEP_xCmR.js} +1 -1
- package/dist/public/assets/{model-switch-api-CPtou49j.js → model-switch-api-c6kcbBGm.js} +1 -1
- package/dist/public/assets/{preferences-service-CdaK7zA8.js → preferences-service-CV6Ih0BG.js} +1 -1
- package/dist/public/assets/{realtime-client-BjQazYsK.js → realtime-client-CRCx5xBt.js} +1 -1
- package/dist/public/assets/{relay-entry-BwE5nw0l.js → relay-entry-C751A-Sm.js} +1 -1
- package/dist/public/assets/{terminal-runtime-meta-C-Lbyx2i.js → terminal-runtime-meta-CRAVR-8G.js} +1 -1
- package/dist/public/assets/{useRegisteredDebugTemplates-BM7-c-gx.js → useRegisteredDebugTemplates-D6YtNS0r.js} +1 -1
- package/dist/public/index.html +2 -2
- package/dist/server/config/env.d.ts +3 -0
- package/dist/server/config/env.js +67 -1
- package/dist/server/config/env.js.map +1 -1
- package/dist/server/config/opencode-base-url-resolver.d.ts +3 -2
- package/dist/server/config/opencode-base-url-resolver.js +64 -24
- package/dist/server/config/opencode-base-url-resolver.js.map +1 -1
- package/dist/server/middlewares/auth-guard.js +4 -0
- package/dist/server/middlewares/auth-guard.js.map +1 -1
- package/dist/server/modules/assistant-capability/assistant-capability-controller.d.ts +168 -1
- package/dist/server/modules/assistant-capability/assistant-capability-controller.js +205 -4
- package/dist/server/modules/assistant-capability/assistant-capability-controller.js.map +1 -1
- package/dist/server/modules/assistant-capability/assistant-capability-service.d.ts +296 -2
- package/dist/server/modules/assistant-capability/assistant-capability-service.js +872 -3
- package/dist/server/modules/assistant-capability/assistant-capability-service.js.map +1 -1
- package/dist/server/modules/auth/auth-service.d.ts +21 -1
- package/dist/server/modules/auth/auth-service.js +64 -0
- package/dist/server/modules/auth/auth-service.js.map +1 -1
- package/dist/server/modules/browser-runtime/browser-profile-service.d.ts +26 -0
- package/dist/server/modules/browser-runtime/browser-profile-service.js +85 -0
- package/dist/server/modules/browser-runtime/browser-profile-service.js.map +1 -0
- package/dist/server/modules/browser-runtime/browser-runtime-controller.d.ts +69 -0
- package/dist/server/modules/browser-runtime/browser-runtime-controller.js +83 -0
- package/dist/server/modules/browser-runtime/browser-runtime-controller.js.map +1 -0
- package/dist/server/modules/browser-runtime/browser-runtime-service.d.ts +56 -0
- package/dist/server/modules/browser-runtime/browser-runtime-service.js +215 -0
- package/dist/server/modules/browser-runtime/browser-runtime-service.js.map +1 -0
- package/dist/server/modules/browser-runtime/browser-task-execution-support.d.ts +65 -0
- package/dist/server/modules/browser-runtime/browser-task-execution-support.js +432 -0
- package/dist/server/modules/browser-runtime/browser-task-execution-support.js.map +1 -0
- package/dist/server/modules/browser-runtime/browser-task-executor-registry.d.ts +7 -0
- package/dist/server/modules/browser-runtime/browser-task-executor-registry.js +21 -0
- package/dist/server/modules/browser-runtime/browser-task-executor-registry.js.map +1 -0
- package/dist/server/modules/browser-runtime/browser-task-executor.d.ts +55 -0
- package/dist/server/modules/browser-runtime/browser-task-executor.js +2 -0
- package/dist/server/modules/browser-runtime/browser-task-executor.js.map +1 -0
- package/dist/server/modules/browser-runtime/browser-task-payload.d.ts +31 -0
- package/dist/server/modules/browser-runtime/browser-task-payload.js +55 -0
- package/dist/server/modules/browser-runtime/browser-task-payload.js.map +1 -0
- package/dist/server/modules/browser-runtime/opencli-bridge-browser-executor.d.ts +19 -0
- package/dist/server/modules/browser-runtime/opencli-bridge-browser-executor.js +219 -0
- package/dist/server/modules/browser-runtime/opencli-bridge-browser-executor.js.map +1 -0
- package/dist/server/modules/browser-runtime/opencli-browser-bridge-service.d.ts +15 -0
- package/dist/server/modules/browser-runtime/opencli-browser-bridge-service.js +33 -0
- package/dist/server/modules/browser-runtime/opencli-browser-bridge-service.js.map +1 -0
- package/dist/server/modules/browser-runtime/playwright-browser-executor.d.ts +16 -0
- package/dist/server/modules/browser-runtime/playwright-browser-executor.js +272 -0
- package/dist/server/modules/browser-runtime/playwright-browser-executor.js.map +1 -0
- package/dist/server/modules/butler/butler-auth-service.js +4 -0
- package/dist/server/modules/butler/butler-auth-service.js.map +1 -1
- package/dist/server/modules/butler/butler-inbox-instruction-adapter.js +1 -0
- package/dist/server/modules/butler/butler-inbox-instruction-adapter.js.map +1 -1
- package/dist/server/modules/butler/butler-session-summary-service.d.ts +1 -0
- package/dist/server/modules/butler/butler-session-summary-service.js +5 -3
- package/dist/server/modules/butler/butler-session-summary-service.js.map +1 -1
- package/dist/server/modules/butler/butler-workspace-context.js +23 -0
- package/dist/server/modules/butler/butler-workspace-context.js.map +1 -1
- package/dist/server/modules/debug-target/debug-target-service.d.ts +2 -0
- package/dist/server/modules/debug-target/debug-target-service.js +14 -0
- package/dist/server/modules/debug-target/debug-target-service.js.map +1 -1
- package/dist/server/modules/document-runtime/document-docx-fallback-renderer.py +139 -0
- package/dist/server/modules/document-runtime/document-export-executor.d.ts +50 -0
- package/dist/server/modules/document-runtime/document-export-executor.js +827 -0
- package/dist/server/modules/document-runtime/document-export-executor.js.map +1 -0
- package/dist/server/modules/document-runtime/document-runtime-controller.d.ts +127 -0
- package/dist/server/modules/document-runtime/document-runtime-controller.js +131 -0
- package/dist/server/modules/document-runtime/document-runtime-controller.js.map +1 -0
- package/dist/server/modules/document-runtime/document-runtime-service.d.ts +125 -0
- package/dist/server/modules/document-runtime/document-runtime-service.js +706 -0
- package/dist/server/modules/document-runtime/document-runtime-service.js.map +1 -0
- package/dist/server/modules/office/office-controller.d.ts +77 -0
- package/dist/server/modules/office/office-controller.js +174 -0
- package/dist/server/modules/office/office-controller.js.map +1 -0
- package/dist/server/modules/office/office-preview-link-service.d.ts +27 -0
- package/dist/server/modules/office/office-preview-link-service.js +121 -0
- package/dist/server/modules/office/office-preview-link-service.js.map +1 -0
- package/dist/server/modules/office/office-service.d.ts +67 -0
- package/dist/server/modules/office/office-service.js +359 -0
- package/dist/server/modules/office/office-service.js.map +1 -0
- package/dist/server/modules/opencli/opencli-bridge-skill-service.js +38 -14
- package/dist/server/modules/opencli/opencli-bridge-skill-service.js.map +1 -1
- package/dist/server/modules/opencli/opencli-install-discovery.d.ts +4 -0
- package/dist/server/modules/opencli/opencli-install-discovery.js +94 -0
- package/dist/server/modules/opencli/opencli-install-discovery.js.map +1 -1
- package/dist/server/modules/opencli/opencli-runtime-builder.js +29 -0
- package/dist/server/modules/opencli/opencli-runtime-builder.js.map +1 -1
- package/dist/server/modules/opencli/opencli-runtime-guard.d.ts +2 -0
- package/dist/server/modules/opencli/opencli-runtime-guard.js +5 -0
- package/dist/server/modules/opencli/opencli-runtime-guard.js.map +1 -0
- package/dist/server/modules/ops-runtime/ops-runtime-controller.d.ts +70 -0
- package/dist/server/modules/ops-runtime/ops-runtime-controller.js +83 -0
- package/dist/server/modules/ops-runtime/ops-runtime-controller.js.map +1 -0
- package/dist/server/modules/ops-runtime/ops-runtime-service.d.ts +80 -0
- package/dist/server/modules/ops-runtime/ops-runtime-service.js +327 -0
- package/dist/server/modules/ops-runtime/ops-runtime-service.js.map +1 -0
- package/dist/server/modules/ops-runtime/ssh-ops-executor.d.ts +41 -0
- package/dist/server/modules/ops-runtime/ssh-ops-executor.js +478 -0
- package/dist/server/modules/ops-runtime/ssh-ops-executor.js.map +1 -0
- package/dist/server/modules/presentation/presentation-controller.d.ts +22 -0
- package/dist/server/modules/presentation/presentation-controller.js +59 -0
- package/dist/server/modules/presentation/presentation-controller.js.map +1 -0
- package/dist/server/modules/presentation/presentation-export-task-service.d.ts +24 -0
- package/dist/server/modules/presentation/presentation-export-task-service.js +137 -0
- package/dist/server/modules/presentation/presentation-export-task-service.js.map +1 -0
- package/dist/server/modules/presentation/presentation-export-types.d.ts +12 -0
- package/dist/server/modules/presentation/presentation-export-types.js +2 -0
- package/dist/server/modules/presentation/presentation-export-types.js.map +1 -0
- package/dist/server/modules/presentation/presentation-pdf-export-service.d.ts +20 -0
- package/dist/server/modules/presentation/presentation-pdf-export-service.js +29 -0
- package/dist/server/modules/presentation/presentation-pdf-export-service.js.map +1 -0
- package/dist/server/modules/presentation/presentation-pptx-export-service.d.ts +20 -0
- package/dist/server/modules/presentation/presentation-pptx-export-service.js +64 -0
- package/dist/server/modules/presentation/presentation-pptx-export-service.js.map +1 -0
- package/dist/server/modules/presentation/presentation-renderer.d.ts +21 -0
- package/dist/server/modules/presentation/presentation-renderer.js +208 -0
- package/dist/server/modules/presentation/presentation-renderer.js.map +1 -0
- package/dist/server/modules/relay-tunnel/relay-tunnel-gateway-service.js +3 -3
- package/dist/server/modules/relay-tunnel/relay-tunnel-gateway-service.js.map +1 -1
- package/dist/server/modules/relay-tunnel/relay-tunnel-service.js +6 -1
- package/dist/server/modules/relay-tunnel/relay-tunnel-service.js.map +1 -1
- package/dist/server/modules/sessions/codex-app-server-helper-process.js +2 -1
- package/dist/server/modules/sessions/codex-app-server-helper-process.js.map +1 -1
- package/dist/server/modules/sessions/session-controller.d.ts +1 -0
- package/dist/server/modules/sessions/session-controller.js +59 -4
- package/dist/server/modules/sessions/session-controller.js.map +1 -1
- package/dist/server/modules/sessions/session-history-service.js +17 -5
- package/dist/server/modules/sessions/session-history-service.js.map +1 -1
- package/dist/server/modules/sessions/session-live-runtime-service.d.ts +5 -1
- package/dist/server/modules/sessions/session-live-runtime-service.js +86 -8
- package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
- package/dist/server/modules/sessions/session-provider-config-service.d.ts +25 -1
- package/dist/server/modules/sessions/session-provider-config-service.js +54 -5
- package/dist/server/modules/sessions/session-provider-config-service.js.map +1 -1
- package/dist/server/modules/sessions/workspace-office-mcp-config.d.ts +14 -0
- package/dist/server/modules/sessions/workspace-office-mcp-config.js +54 -0
- package/dist/server/modules/sessions/workspace-office-mcp-config.js.map +1 -0
- package/dist/server/modules/sessions/workspace-session-auth-service.d.ts +27 -0
- package/dist/server/modules/sessions/workspace-session-auth-service.js +109 -0
- package/dist/server/modules/sessions/workspace-session-auth-service.js.map +1 -0
- package/dist/server/modules/sessions/workspace-session-runtime-context-service.d.ts +50 -0
- package/dist/server/modules/sessions/workspace-session-runtime-context-service.js +332 -0
- package/dist/server/modules/sessions/workspace-session-runtime-context-service.js.map +1 -0
- package/dist/server/modules/skills/assistant-runtime-skill-catalog.js +5 -0
- package/dist/server/modules/skills/assistant-runtime-skill-catalog.js.map +1 -1
- package/dist/server/modules/skills/builtin-skills/codingns-workspace-session/SKILL.md +67 -0
- package/dist/server/modules/skills/builtin-skills/codingns-workspace-session/agents/openai.yaml +4 -0
- package/dist/server/modules/skills/builtin-skills/codingns-workspace-session/references/cli-workflow.md +133 -0
- package/dist/server/modules/skills/skill-controller.d.ts +7 -0
- package/dist/server/modules/skills/skill-controller.js +7 -0
- package/dist/server/modules/skills/skill-controller.js.map +1 -1
- package/dist/server/modules/skills/skill-manager-service.d.ts +61 -0
- package/dist/server/modules/skills/skill-manager-service.js +218 -0
- package/dist/server/modules/skills/skill-manager-service.js.map +1 -1
- package/dist/server/modules/skills/skill-name-policy.js +2 -1
- package/dist/server/modules/skills/skill-name-policy.js.map +1 -1
- package/dist/server/modules/tasks/task-helper-client.d.ts +1 -0
- package/dist/server/modules/tasks/task-helper-client.js +45 -9
- package/dist/server/modules/tasks/task-helper-client.js.map +1 -1
- package/dist/server/modules/tasks/task-types.d.ts +5 -0
- package/dist/server/modules/tasks/task-types.js +6 -1
- package/dist/server/modules/tasks/task-types.js.map +1 -1
- package/dist/server/modules/terminal/runtime/conpty-session-agent-process.js +2 -1
- package/dist/server/modules/terminal/runtime/conpty-session-agent-process.js.map +1 -1
- package/dist/server/modules/terminal/runtime/node-pty-loader.d.ts +5 -0
- package/dist/server/modules/terminal/runtime/node-pty-loader.js +68 -0
- package/dist/server/modules/terminal/runtime/node-pty-loader.js.map +1 -0
- package/dist/server/modules/terminal/runtime/pty-broker-agent-process.js +2 -1
- package/dist/server/modules/terminal/runtime/pty-broker-agent-process.js.map +1 -1
- package/dist/server/modules/terminal/runtime/pty-host-attachment-manager.js +6 -9
- package/dist/server/modules/terminal/runtime/pty-host-attachment-manager.js.map +1 -1
- package/dist/server/modules/terminal/runtime/pty-runtime-manager.js +6 -9
- package/dist/server/modules/terminal/runtime/pty-runtime-manager.js.map +1 -1
- package/dist/server/routes/assistant.d.ts +2 -1
- package/dist/server/routes/assistant.js +20 -1
- package/dist/server/routes/assistant.js.map +1 -1
- package/dist/server/routes/browser-runtime.d.ts +3 -0
- package/dist/server/routes/browser-runtime.js +14 -0
- package/dist/server/routes/browser-runtime.js.map +1 -0
- package/dist/server/routes/document-runtime.d.ts +3 -0
- package/dist/server/routes/document-runtime.js +18 -0
- package/dist/server/routes/document-runtime.js.map +1 -0
- package/dist/server/routes/office.d.ts +3 -0
- package/dist/server/routes/office.js +16 -0
- package/dist/server/routes/office.js.map +1 -0
- package/dist/server/routes/ops-runtime.d.ts +3 -0
- package/dist/server/routes/ops-runtime.js +13 -0
- package/dist/server/routes/ops-runtime.js.map +1 -0
- package/dist/server/routes/presentation.d.ts +3 -0
- package/dist/server/routes/presentation.js +5 -0
- package/dist/server/routes/presentation.js.map +1 -0
- package/dist/server/routes/skills.js +1 -0
- package/dist/server/routes/skills.js.map +1 -1
- package/dist/server/server/create-server.d.ts +36 -0
- package/dist/server/server/create-server.js +215 -4
- package/dist/server/server/create-server.js.map +1 -1
- package/dist/server/server/release-manifest-sync.d.ts +1 -0
- package/dist/server/server/release-manifest-sync.js +2 -2
- package/dist/server/server/release-manifest-sync.js.map +1 -1
- package/dist/server/server/start-host.js +1 -1
- package/dist/server/server/start-host.js.map +1 -1
- package/dist/server/storage/repositories/auth-token-repository.js +22 -6
- package/dist/server/storage/repositories/auth-token-repository.js.map +1 -1
- package/dist/server/storage/repositories/browser-profile-repository.d.ts +18 -0
- package/dist/server/storage/repositories/browser-profile-repository.js +134 -0
- package/dist/server/storage/repositories/browser-profile-repository.js.map +1 -0
- package/dist/server/storage/repositories/document-comment-repository.d.ts +10 -0
- package/dist/server/storage/repositories/document-comment-repository.js +118 -0
- package/dist/server/storage/repositories/document-comment-repository.js.map +1 -0
- package/dist/server/storage/repositories/document-repository.d.ts +16 -0
- package/dist/server/storage/repositories/document-repository.js +109 -0
- package/dist/server/storage/repositories/document-repository.js.map +1 -0
- package/dist/server/storage/repositories/document-revision-repository.d.ts +10 -0
- package/dist/server/storage/repositories/document-revision-repository.js +79 -0
- package/dist/server/storage/repositories/document-revision-repository.js.map +1 -0
- package/dist/server/storage/repositories/document-template-repository.d.ts +13 -0
- package/dist/server/storage/repositories/document-template-repository.js +244 -0
- package/dist/server/storage/repositories/document-template-repository.js.map +1 -0
- package/dist/server/storage/repositories/office-approval-repository.d.ts +11 -0
- package/dist/server/storage/repositories/office-approval-repository.js +109 -0
- package/dist/server/storage/repositories/office-approval-repository.js.map +1 -0
- package/dist/server/storage/repositories/office-artifact-repository.d.ts +10 -0
- package/dist/server/storage/repositories/office-artifact-repository.js +89 -0
- package/dist/server/storage/repositories/office-artifact-repository.js.map +1 -0
- package/dist/server/storage/repositories/office-audit-event-repository.d.ts +8 -0
- package/dist/server/storage/repositories/office-audit-event-repository.js +54 -0
- package/dist/server/storage/repositories/office-audit-event-repository.js.map +1 -0
- package/dist/server/storage/repositories/office-connector-repository.d.ts +10 -0
- package/dist/server/storage/repositories/office-connector-repository.js +97 -0
- package/dist/server/storage/repositories/office-connector-repository.js.map +1 -0
- package/dist/server/storage/repositories/office-receipt-repository.d.ts +8 -0
- package/dist/server/storage/repositories/office-receipt-repository.js +48 -0
- package/dist/server/storage/repositories/office-receipt-repository.js.map +1 -0
- package/dist/server/storage/repositories/office-rollback-record-repository.d.ts +8 -0
- package/dist/server/storage/repositories/office-rollback-record-repository.js +60 -0
- package/dist/server/storage/repositories/office-rollback-record-repository.js.map +1 -0
- package/dist/server/storage/repositories/office-task-repository.d.ts +19 -0
- package/dist/server/storage/repositories/office-task-repository.js +199 -0
- package/dist/server/storage/repositories/office-task-repository.js.map +1 -0
- package/dist/server/storage/repositories/office-task-step-repository.d.ts +10 -0
- package/dist/server/storage/repositories/office-task-step-repository.js +110 -0
- package/dist/server/storage/repositories/office-task-step-repository.js.map +1 -0
- package/dist/server/storage/repositories/ops-target-repository.d.ts +16 -0
- package/dist/server/storage/repositories/ops-target-repository.js +119 -0
- package/dist/server/storage/repositories/ops-target-repository.js.map +1 -0
- package/dist/server/storage/repositories/session-binding-repository.d.ts +4 -0
- package/dist/server/storage/repositories/session-binding-repository.js +70 -69
- package/dist/server/storage/repositories/session-binding-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-changed-file-repository.d.ts +6 -0
- package/dist/server/storage/repositories/session-changed-file-repository.js +44 -43
- package/dist/server/storage/repositories/session-changed-file-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-fork-repository.d.ts +2 -0
- package/dist/server/storage/repositories/session-fork-repository.js +42 -41
- package/dist/server/storage/repositories/session-fork-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-index-repository.d.ts +5 -0
- package/dist/server/storage/repositories/session-index-repository.js +153 -152
- package/dist/server/storage/repositories/session-index-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-message-attachment-repository.d.ts +7 -0
- package/dist/server/storage/repositories/session-message-attachment-repository.js +91 -90
- package/dist/server/storage/repositories/session-message-attachment-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-message-origin-repository.d.ts +2 -0
- package/dist/server/storage/repositories/session-message-origin-repository.js +25 -24
- package/dist/server/storage/repositories/session-message-origin-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-state-repository.d.ts +2 -0
- package/dist/server/storage/repositories/session-state-repository.js +35 -34
- package/dist/server/storage/repositories/session-state-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-status-snapshot-repository.d.ts +2 -0
- package/dist/server/storage/repositories/session-status-snapshot-repository.js +25 -24
- package/dist/server/storage/repositories/session-status-snapshot-repository.js.map +1 -1
- package/dist/server/storage/sqlite/client.js +123 -1
- package/dist/server/storage/sqlite/client.js.map +1 -1
- package/dist/server/storage/sqlite/schema.sql +300 -1
- package/dist/server/types/domain.d.ts +205 -1
- package/package.json +14 -7
- package/scripts/postinstall.mjs +159 -7
- package/dist/public/assets/FileContextPanel-xGTYDclT.js +0 -1
- package/dist/public/assets/WorkbenchLayout-DScHaza9.js +0 -244
- package/dist/public/assets/WorkbenchShellRoute-DN6LdrqC.js +0 -1
- package/dist/public/assets/WorkbenchShellRoute-DhQo_0vu.css +0 -1
- package/dist/public/assets/file-tree-icon-lfU9Ag77.js +0 -3
- package/dist/public/assets/index-CFYXCsyx.css +0 -1
- package/dist/public/assets/index-NGxWr8Ix.js +0 -42
- package/node_modules/@codingns/session-sync-core/dist/claude-message-utils.d.ts +0 -42
- package/node_modules/@codingns/session-sync-core/dist/claude-message-utils.js +0 -346
- package/node_modules/@codingns/session-sync-core/dist/claude-message-utils.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/codex-resume-history.d.ts +0 -1
- package/node_modules/@codingns/session-sync-core/dist/codex-resume-history.js +0 -80
- package/node_modules/@codingns/session-sync-core/dist/codex-resume-history.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/index.d.ts +0 -18
- package/node_modules/@codingns/session-sync-core/dist/index.js +0 -19
- package/node_modules/@codingns/session-sync-core/dist/index.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/kimi-message-normalizer.d.ts +0 -18
- package/node_modules/@codingns/session-sync-core/dist/kimi-message-normalizer.js +0 -659
- package/node_modules/@codingns/session-sync-core/dist/kimi-message-normalizer.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/kimi-shared.d.ts +0 -11
- package/node_modules/@codingns/session-sync-core/dist/kimi-shared.js +0 -72
- package/node_modules/@codingns/session-sync-core/dist/kimi-shared.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/patch-builder.d.ts +0 -67
- package/node_modules/@codingns/session-sync-core/dist/patch-builder.js +0 -752
- package/node_modules/@codingns/session-sync-core/dist/patch-builder.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.d.ts +0 -48
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js +0 -1184
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.d.ts +0 -11
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js +0 -105
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +0 -84
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +0 -2436
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/gemini.d.ts +0 -47
- package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js +0 -1480
- package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/kimi.d.ts +0 -33
- package/node_modules/@codingns/session-sync-core/dist/providers/kimi.js +0 -684
- package/node_modules/@codingns/session-sync-core/dist/providers/kimi.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/legna-code.d.ts +0 -9
- package/node_modules/@codingns/session-sync-core/dist/providers/legna-code.js +0 -17
- package/node_modules/@codingns/session-sync-core/dist/providers/legna-code.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode-permissions.d.ts +0 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode-permissions.js +0 -8
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode-permissions.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode-shared.d.ts +0 -48
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode-shared.js +0 -373
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode-shared.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.d.ts +0 -61
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js +0 -1191
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/utils.d.ts +0 -27
- package/node_modules/@codingns/session-sync-core/dist/providers/utils.js +0 -415
- package/node_modules/@codingns/session-sync-core/dist/providers/utils.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/registry.d.ts +0 -7
- package/node_modules/@codingns/session-sync-core/dist/registry.js +0 -22
- package/node_modules/@codingns/session-sync-core/dist/registry.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.d.ts +0 -24
- package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js +0 -329
- package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.d.ts +0 -30
- package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js +0 -939
- package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-permissions.d.ts +0 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-permissions.js +0 -16
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-permissions.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.d.ts +0 -70
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +0 -2571
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.d.ts +0 -21
- package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.js +0 -561
- package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/kimi-runtime.d.ts +0 -38
- package/node_modules/@codingns/session-sync-core/dist/runtime/kimi-runtime.js +0 -911
- package/node_modules/@codingns/session-sync-core/dist/runtime/kimi-runtime.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/legna-runtime.d.ts +0 -15
- package/node_modules/@codingns/session-sync-core/dist/runtime/legna-runtime.js +0 -16
- package/node_modules/@codingns/session-sync-core/dist/runtime/legna-runtime.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.d.ts +0 -37
- package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.js +0 -963
- package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/provider-runtime-service.d.ts +0 -21
- package/node_modules/@codingns/session-sync-core/dist/runtime/provider-runtime-service.js +0 -168
- package/node_modules/@codingns/session-sync-core/dist/runtime/provider-runtime-service.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/types.d.ts +0 -152
- package/node_modules/@codingns/session-sync-core/dist/runtime/types.js +0 -2
- package/node_modules/@codingns/session-sync-core/dist/runtime/types.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/services.d.ts +0 -28
- package/node_modules/@codingns/session-sync-core/dist/services.js +0 -148
- package/node_modules/@codingns/session-sync-core/dist/services.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.d.ts +0 -6
- package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.js +0 -9
- package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/dist/types.d.ts +0 -198
- package/node_modules/@codingns/session-sync-core/dist/types.js +0 -2
- package/node_modules/@codingns/session-sync-core/dist/types.js.map +0 -1
- package/node_modules/@codingns/session-sync-core/package.json +0 -33
|
@@ -1,2571 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
3
|
-
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
4
|
-
import { homedir } from "node:os";
|
|
5
|
-
import { performance } from "node:perf_hooks";
|
|
6
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
7
|
-
import { createInterface } from "node:readline";
|
|
8
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
9
|
-
import { appendJsonLine, createRawRef, ensureDirectory, extractTextBlocks, messageIdFromStableKey, messageIdFromRawRef, nextTimestamp, normalizeWorkspacePath } from "../providers/utils.js";
|
|
10
|
-
import { buildCodexResumeHistoryFromRawStore } from "../codex-resume-history.js";
|
|
11
|
-
import { buildApplyPatchFromCodexCommandLikeValue, buildApplyPatchFromFileChangeList, extractApplyPatchTargetPathsFromToolOutput, normalizeApplyPatchText } from "../patch-builder.js";
|
|
12
|
-
import { loadDatabaseSync } from "../sqlite/node-sqlite.js";
|
|
13
|
-
import { createCodexThreadPermissionOptions } from "./codex-permissions.js";
|
|
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;
|
|
16
|
-
function logCodexRuntimeStep(scope, startedAtMs, detail = {}) {
|
|
17
|
-
if (!CODEX_RUNTIME_DEBUG_ENABLED) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
const durationMs = Math.round(performance.now() - startedAtMs);
|
|
21
|
-
const suffix = formatCodexRuntimeDebugDetail(detail);
|
|
22
|
-
console.info(`[perf][codex-runtime] ${scope} ${durationMs}ms${suffix ? ` ${suffix}` : ""}`);
|
|
23
|
-
}
|
|
24
|
-
function formatCodexRuntimeDebugDetail(detail) {
|
|
25
|
-
const entries = Object.entries(detail).filter(([, value]) => value !== undefined);
|
|
26
|
-
if (entries.length === 0) {
|
|
27
|
-
return "";
|
|
28
|
-
}
|
|
29
|
-
return entries
|
|
30
|
-
.map(([key, value]) => `${key}=${formatCodexRuntimeDebugValue(value)}`)
|
|
31
|
-
.join(" ");
|
|
32
|
-
}
|
|
33
|
-
function formatCodexRuntimeDebugValue(value) {
|
|
34
|
-
if (value === null) {
|
|
35
|
-
return "null";
|
|
36
|
-
}
|
|
37
|
-
if (typeof value === "string") {
|
|
38
|
-
return JSON.stringify(value);
|
|
39
|
-
}
|
|
40
|
-
if (typeof value === "number") {
|
|
41
|
-
return Number.isFinite(value) ? String(Math.round(value)) : String(value);
|
|
42
|
-
}
|
|
43
|
-
if (typeof value === "boolean") {
|
|
44
|
-
return value ? "true" : "false";
|
|
45
|
-
}
|
|
46
|
-
try {
|
|
47
|
-
return JSON.stringify(value);
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
return String(value);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
export class CodexRuntimeAdapter {
|
|
54
|
-
options;
|
|
55
|
-
providerId = "codex";
|
|
56
|
-
constructor(options = {}) {
|
|
57
|
-
this.options = options;
|
|
58
|
-
}
|
|
59
|
-
async startSession(request, sink) {
|
|
60
|
-
const launchedAtMs = Date.now();
|
|
61
|
-
const launchPerfStartedAtMs = performance.now();
|
|
62
|
-
const transport = this.options.transportFactory
|
|
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({
|
|
125
|
-
sessionId: request.sessionId,
|
|
126
|
-
providerSessionId,
|
|
127
|
-
request: serverRequest
|
|
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);
|
|
146
|
-
}
|
|
147
|
-
logCodexRuntimeStep("start_session.turn_start", startTurnStartedAtMs, {
|
|
148
|
-
sessionId: request.sessionId,
|
|
149
|
-
providerSessionId
|
|
150
|
-
});
|
|
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
|
-
}
|
|
178
|
-
}
|
|
179
|
-
async resumeSyntheticThreadFromHistory(transport, request) {
|
|
180
|
-
const history = buildSyntheticResumeHistory(request.rawStoreRef);
|
|
181
|
-
if (history.length === 0) {
|
|
182
|
-
return null;
|
|
183
|
-
}
|
|
184
|
-
const resumeStartedAtMs = performance.now();
|
|
185
|
-
const resumed = await transport.resumeThreadFromHistory({
|
|
186
|
-
providerSessionId: null,
|
|
187
|
-
workspacePath: request.workspacePath,
|
|
188
|
-
history,
|
|
189
|
-
model: request.options.model
|
|
190
|
-
});
|
|
191
|
-
logCodexRuntimeStep("start_session.thread_resume_from_history", resumeStartedAtMs, {
|
|
192
|
-
sessionId: request.sessionId,
|
|
193
|
-
providerSessionId: resumed.providerSessionId,
|
|
194
|
-
messageCount: history.length
|
|
195
|
-
});
|
|
196
|
-
return resumed;
|
|
197
|
-
}
|
|
198
|
-
async continueSession(request, sink) {
|
|
199
|
-
const providerSessionId = resolveResumeThreadId(request.providerSessionId, request.rawStoreRef);
|
|
200
|
-
if (!providerSessionId) {
|
|
201
|
-
throw new Error("PROVIDER_SESSION_ID_REQUIRED");
|
|
202
|
-
}
|
|
203
|
-
const transport = this.options.transportFactory
|
|
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
|
|
209
|
-
});
|
|
210
|
-
try {
|
|
211
|
-
const runtimeStartedAtMs = performance.now();
|
|
212
|
-
const initializeStartedAtMs = performance.now();
|
|
213
|
-
await transport.initialize();
|
|
214
|
-
logCodexRuntimeStep("continue_session.initialize", initializeStartedAtMs, {
|
|
215
|
-
sessionId: request.sessionId,
|
|
216
|
-
providerSessionId
|
|
217
|
-
});
|
|
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, {
|
|
226
|
-
sessionId: request.sessionId,
|
|
227
|
-
providerSessionId: resolvedSessionId,
|
|
228
|
-
fallback: false
|
|
229
|
-
});
|
|
230
|
-
}
|
|
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
|
-
});
|
|
257
|
-
}
|
|
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, {
|
|
267
|
-
sessionId: request.sessionId,
|
|
268
|
-
providerSessionId: resolvedSessionId,
|
|
269
|
-
synthetic: isSyntheticRawStoreRef(rawStoreRef),
|
|
270
|
-
hasResumedRawStoreRef: Boolean(resumed.rawStoreRef),
|
|
271
|
-
hasRequestRawStoreRef: Boolean(request.rawStoreRef),
|
|
272
|
-
resumedRawStoreRefExists: Boolean(resumed.rawStoreRef && existsSync(resumed.rawStoreRef))
|
|
273
|
-
});
|
|
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
|
|
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);
|
|
317
|
-
}
|
|
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
|
-
}
|
|
349
|
-
}
|
|
350
|
-
async resolveContinueFallbackHistorySource(input) {
|
|
351
|
-
const candidates = [];
|
|
352
|
-
const seen = new Set();
|
|
353
|
-
const pushCandidate = (candidate) => {
|
|
354
|
-
const normalized = candidate?.trim();
|
|
355
|
-
if (!normalized || seen.has(normalized) || !existsSync(normalized)) {
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
seen.add(normalized);
|
|
359
|
-
candidates.push(normalized);
|
|
360
|
-
};
|
|
361
|
-
pushCandidate(input.rawStoreRef);
|
|
362
|
-
// 旧会话的 binding 可能只剩 synthetic stream,或者已经指到了父线程 transcript。
|
|
363
|
-
// 继续会话失败时,额外按真实 thread id 扫一次本地 transcript,尽量把历史恢复链路救回来。
|
|
364
|
-
pushCandidate(await this.resolveRealRawStoreRef(input.providerSessionId.trim(), input.workspacePath, input.homeDir));
|
|
365
|
-
let fallbackMatch = null;
|
|
366
|
-
for (const candidate of candidates) {
|
|
367
|
-
const history = buildCodexResumeHistoryFromRawStore(candidate);
|
|
368
|
-
if (history.length === 0) {
|
|
369
|
-
continue;
|
|
370
|
-
}
|
|
371
|
-
const meta = readSessionMeta(candidate);
|
|
372
|
-
if (meta?.threadId === input.providerSessionId.trim()) {
|
|
373
|
-
return {
|
|
374
|
-
rawStoreRef: candidate,
|
|
375
|
-
history
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
fallbackMatch ??= {
|
|
379
|
-
rawStoreRef: candidate,
|
|
380
|
-
history
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
return fallbackMatch;
|
|
384
|
-
}
|
|
385
|
-
async runTurn(thread, request, sink, providerSessionId, rawStoreRef, abortController, preparedEvents, bufferedEvents = [], launchedAtMs = Date.now(), launchPerfStartedAtMs = performance.now()) {
|
|
386
|
-
const context = {
|
|
387
|
-
providerSessionId,
|
|
388
|
-
rawStoreRef,
|
|
389
|
-
// 运行时消息必须接在历史消息后面,不能每轮都从 1 重新编号,
|
|
390
|
-
// 否则前端会把新 assistant/tool 消息排到旧消息前面,表现成用户消息一直挂在底部。
|
|
391
|
-
sequence: Math.max(0, request.sequenceBase ?? 0),
|
|
392
|
-
toolNameByCallId: new Map(),
|
|
393
|
-
stableMessageRefByIdentity: new Map(),
|
|
394
|
-
lastSignatureByIdentity: new Map(),
|
|
395
|
-
sink,
|
|
396
|
-
workspacePath: request.workspacePath,
|
|
397
|
-
firstUserMessage: request.options.content,
|
|
398
|
-
homeDir: request.runtimeHomeDir?.trim() || this.options.homeDir?.trim() || null,
|
|
399
|
-
launchedAtMs,
|
|
400
|
-
launchPerfStartedAtMs
|
|
401
|
-
};
|
|
402
|
-
try {
|
|
403
|
-
await this.refreshSessionBindingIfNeeded(context);
|
|
404
|
-
persistSyntheticUserMessageIfNeeded(context.rawStoreRef, context.providerSessionId, {
|
|
405
|
-
workspacePath: request.workspacePath,
|
|
406
|
-
content: request.options.content,
|
|
407
|
-
timestamp: nextTimestamp()
|
|
408
|
-
});
|
|
409
|
-
for (const event of bufferedEvents) {
|
|
410
|
-
await this.refreshSessionBindingIfNeeded(context);
|
|
411
|
-
persistSyntheticEventIfNeeded(context.rawStoreRef, context.providerSessionId, event);
|
|
412
|
-
await this.handleEvent(event, request, context, abortController.signal.aborted);
|
|
413
|
-
}
|
|
414
|
-
const events = preparedEvents ??
|
|
415
|
-
(await thread.runStreamed(createCodexInput(request), {
|
|
416
|
-
signal: abortController.signal
|
|
417
|
-
})).events[Symbol.asyncIterator]();
|
|
418
|
-
while (true) {
|
|
419
|
-
const next = await events.next();
|
|
420
|
-
if (next.done) {
|
|
421
|
-
return;
|
|
422
|
-
}
|
|
423
|
-
await this.refreshSessionBindingIfNeeded(context);
|
|
424
|
-
persistSyntheticEventIfNeeded(context.rawStoreRef, context.providerSessionId, next.value);
|
|
425
|
-
await this.handleEvent(next.value, request, context, abortController.signal.aborted);
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
catch (error) {
|
|
429
|
-
if (abortController.signal.aborted) {
|
|
430
|
-
await sink.emit({
|
|
431
|
-
type: "interrupted",
|
|
432
|
-
status: "interrupted",
|
|
433
|
-
interruptSource: "user",
|
|
434
|
-
providerSessionId: context.providerSessionId,
|
|
435
|
-
rawStoreRef: context.rawStoreRef,
|
|
436
|
-
detail: "codex turn interrupted",
|
|
437
|
-
timestamp: nextTimestamp()
|
|
438
|
-
});
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
const failure = classifyCodexRuntimeFailure(error);
|
|
442
|
-
await sink.emit({
|
|
443
|
-
type: "error",
|
|
444
|
-
status: "failed",
|
|
445
|
-
providerSessionId: context.providerSessionId,
|
|
446
|
-
rawStoreRef: context.rawStoreRef,
|
|
447
|
-
errorCode: failure.errorCode,
|
|
448
|
-
detail: failure.detail,
|
|
449
|
-
timestamp: nextTimestamp()
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
async handleEvent(event, request, context, interrupted) {
|
|
454
|
-
const eventType = ensureText(readProp(event, "type")).trim();
|
|
455
|
-
if (eventType.length === 0) {
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
458
|
-
if (context.lastSignatureByIdentity.size === 0 && eventType.startsWith("item.")) {
|
|
459
|
-
logCodexRuntimeStep("turn.first_item_event", context.launchPerfStartedAtMs, {
|
|
460
|
-
sessionId: request.sessionId,
|
|
461
|
-
providerSessionId: context.providerSessionId,
|
|
462
|
-
eventType
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
if (eventType === "turn.completed") {
|
|
466
|
-
await context.sink.emit({
|
|
467
|
-
type: "complete",
|
|
468
|
-
status: "completed",
|
|
469
|
-
providerSessionId: context.providerSessionId,
|
|
470
|
-
rawStoreRef: context.rawStoreRef,
|
|
471
|
-
detail: "codex turn completed",
|
|
472
|
-
timestamp: pickTimestamp(event)
|
|
473
|
-
});
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
|
-
if (eventType === "turn.failed") {
|
|
477
|
-
const detail = extractTextBlocks(readProp(event, "error")).trim() || "codex turn failed";
|
|
478
|
-
await context.sink.emit({
|
|
479
|
-
type: "error",
|
|
480
|
-
status: "failed",
|
|
481
|
-
providerSessionId: context.providerSessionId,
|
|
482
|
-
rawStoreRef: context.rawStoreRef,
|
|
483
|
-
errorCode: classifyCodexDetailErrorCode(detail, "CODEX_CLI_TURN_FAILED"),
|
|
484
|
-
detail,
|
|
485
|
-
timestamp: pickTimestamp(event)
|
|
486
|
-
});
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
if (eventType === "turn.interrupted") {
|
|
490
|
-
await context.sink.emit({
|
|
491
|
-
type: "interrupted",
|
|
492
|
-
status: "interrupted",
|
|
493
|
-
interruptSource: interrupted ? "user" : "runtime",
|
|
494
|
-
providerSessionId: context.providerSessionId,
|
|
495
|
-
rawStoreRef: context.rawStoreRef,
|
|
496
|
-
detail: "codex turn interrupted",
|
|
497
|
-
timestamp: pickTimestamp(event)
|
|
498
|
-
});
|
|
499
|
-
return;
|
|
500
|
-
}
|
|
501
|
-
if (interrupted) {
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
if (!eventType.startsWith("item.")) {
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
const item = readProp(event, "item");
|
|
508
|
-
const itemType = ensureText(readProp(item, "type")).trim();
|
|
509
|
-
if (itemType.length === 0) {
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
if (itemType === "agent_message" &&
|
|
513
|
-
(eventType === "item.updated" || eventType === "item.completed")) {
|
|
514
|
-
const content = pickFirstNonEmpty(ensureText(readProp(item, "text")).trim(), extractTextBlocks(readProp(item, "content")).trim());
|
|
515
|
-
if (content.length > 0) {
|
|
516
|
-
await this.emitStableMessage(context, {
|
|
517
|
-
identity: `assistant:text:${ensureText(readProp(item, "id")).trim() || "default"}`,
|
|
518
|
-
timestamp: pickTimestamp(item, event),
|
|
519
|
-
role: "assistant",
|
|
520
|
-
kind: "text",
|
|
521
|
-
content
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
return;
|
|
525
|
-
}
|
|
526
|
-
if (itemType === "reasoning" &&
|
|
527
|
-
(eventType === "item.updated" || eventType === "item.completed")) {
|
|
528
|
-
const content = pickFirstNonEmpty(ensureText(readProp(item, "text")).trim(), extractTextBlocks(readProp(item, "summary")).trim(), extractTextBlocks(readProp(item, "content")).trim());
|
|
529
|
-
if (content.length > 0) {
|
|
530
|
-
await this.emitStableMessage(context, {
|
|
531
|
-
identity: `assistant:thinking:${ensureText(readProp(item, "id")).trim() || "default"}`,
|
|
532
|
-
timestamp: pickTimestamp(item, event),
|
|
533
|
-
role: "assistant",
|
|
534
|
-
kind: "thinking",
|
|
535
|
-
content
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
if (!isToolItem(itemType)) {
|
|
541
|
-
return;
|
|
542
|
-
}
|
|
543
|
-
const callId = pickFirstNonEmpty(ensureText(readProp(item, "id")).trim(), ensureText(readProp(item, "call_id")).trim(), `${itemType}-${randomUUID()}`);
|
|
544
|
-
const name = pickFirstNonEmpty(ensureText(readProp(item, "name")).trim(), ensureText(readProp(item, "tool")).trim(), itemType);
|
|
545
|
-
if (eventType === "item.started") {
|
|
546
|
-
const input = resolveCodexToolInput(name, item);
|
|
547
|
-
const toolCall = {
|
|
548
|
-
callId,
|
|
549
|
-
name,
|
|
550
|
-
input,
|
|
551
|
-
output: null,
|
|
552
|
-
error: null,
|
|
553
|
-
status: "running"
|
|
554
|
-
};
|
|
555
|
-
context.toolNameByCallId.set(callId, name);
|
|
556
|
-
await this.emitStableMessage(context, {
|
|
557
|
-
identity: `tool:call:${callId}`,
|
|
558
|
-
timestamp: pickTimestamp(item, event),
|
|
559
|
-
role: "tool",
|
|
560
|
-
kind: "tool_call",
|
|
561
|
-
content: input,
|
|
562
|
-
toolCall
|
|
563
|
-
});
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
566
|
-
if (eventType === "item.updated") {
|
|
567
|
-
const knownName = context.toolNameByCallId.get(callId) ?? name;
|
|
568
|
-
const input = resolveCodexToolInput(knownName, item);
|
|
569
|
-
const output = pickFirstNonEmpty(extractTextBlocks(readProp(item, "result")).trim(), extractTextBlocks(readProp(item, "output")).trim(), extractTextBlocks(readProp(item, "aggregated_output")).trim(), extractTextBlocks(readProp(item, "error")).trim());
|
|
570
|
-
if (output.length === 0) {
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
|
-
context.toolNameByCallId.set(callId, knownName);
|
|
574
|
-
await this.emitStableMessage(context, {
|
|
575
|
-
identity: `tool:result:${callId}`,
|
|
576
|
-
timestamp: pickTimestamp(item, event),
|
|
577
|
-
role: "tool",
|
|
578
|
-
kind: "tool_result",
|
|
579
|
-
content: output,
|
|
580
|
-
toolCall: {
|
|
581
|
-
callId,
|
|
582
|
-
name: knownName,
|
|
583
|
-
input,
|
|
584
|
-
output,
|
|
585
|
-
error: null,
|
|
586
|
-
status: "running"
|
|
587
|
-
}
|
|
588
|
-
});
|
|
589
|
-
return;
|
|
590
|
-
}
|
|
591
|
-
if (eventType === "item.completed") {
|
|
592
|
-
const knownName = context.toolNameByCallId.get(callId) ?? name;
|
|
593
|
-
const input = resolveCodexToolInput(knownName, item);
|
|
594
|
-
const output = pickFirstNonEmpty(extractTextBlocks(readProp(item, "result")).trim(), extractTextBlocks(readProp(item, "output")).trim(), extractTextBlocks(readProp(item, "aggregated_output")).trim(), extractTextBlocks(readProp(item, "error")).trim());
|
|
595
|
-
const success = inferToolSuccess(item, output);
|
|
596
|
-
const toolCall = {
|
|
597
|
-
callId,
|
|
598
|
-
name: knownName,
|
|
599
|
-
input,
|
|
600
|
-
output: success ? output : null,
|
|
601
|
-
error: success ? null : output,
|
|
602
|
-
status: success ? "completed" : "failed"
|
|
603
|
-
};
|
|
604
|
-
await this.emitStableMessage(context, {
|
|
605
|
-
identity: `tool:result:${callId}`,
|
|
606
|
-
timestamp: pickTimestamp(item, event),
|
|
607
|
-
role: "tool",
|
|
608
|
-
kind: "tool_result",
|
|
609
|
-
content: output,
|
|
610
|
-
toolCall
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
async emitStableMessage(context, input) {
|
|
615
|
-
const message = this.buildMessage(context, {
|
|
616
|
-
timestamp: input.timestamp,
|
|
617
|
-
role: input.role,
|
|
618
|
-
kind: input.kind,
|
|
619
|
-
content: input.content,
|
|
620
|
-
toolCall: input.toolCall ?? null,
|
|
621
|
-
stableIdentity: input.identity
|
|
622
|
-
});
|
|
623
|
-
const signature = buildCodexMessageSignature(message);
|
|
624
|
-
if (context.lastSignatureByIdentity.get(input.identity) === signature) {
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
context.lastSignatureByIdentity.set(input.identity, signature);
|
|
628
|
-
await context.sink.emit({
|
|
629
|
-
type: "message",
|
|
630
|
-
message,
|
|
631
|
-
providerSessionId: context.providerSessionId,
|
|
632
|
-
rawStoreRef: context.rawStoreRef,
|
|
633
|
-
timestamp: input.timestamp,
|
|
634
|
-
rawEventRef: message.rawRef
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
async refreshSessionBindingIfNeeded(context) {
|
|
638
|
-
if (!isSyntheticRawStoreRef(context.rawStoreRef)) {
|
|
639
|
-
return;
|
|
640
|
-
}
|
|
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);
|
|
643
|
-
if (!resolved ||
|
|
644
|
-
(resolved.providerSessionId === context.providerSessionId &&
|
|
645
|
-
resolved.rawStoreRef === context.rawStoreRef)) {
|
|
646
|
-
return;
|
|
647
|
-
}
|
|
648
|
-
context.providerSessionId = resolved.providerSessionId;
|
|
649
|
-
context.rawStoreRef = resolved.rawStoreRef;
|
|
650
|
-
context.sink.updateSessionBinding({
|
|
651
|
-
providerSessionId: resolved.providerSessionId,
|
|
652
|
-
rawStoreRef: resolved.rawStoreRef
|
|
653
|
-
});
|
|
654
|
-
}
|
|
655
|
-
async resolveExistingSessionBinding(providerSessionId, rawStoreRef, workspacePath, homeDirOverride = null) {
|
|
656
|
-
const normalizedProviderSessionId = providerSessionId.trim();
|
|
657
|
-
const meta = readSessionMeta(rawStoreRef);
|
|
658
|
-
if (meta && meta.threadId === normalizedProviderSessionId && existsSync(rawStoreRef)) {
|
|
659
|
-
return {
|
|
660
|
-
providerSessionId: meta.threadId,
|
|
661
|
-
rawStoreRef
|
|
662
|
-
};
|
|
663
|
-
}
|
|
664
|
-
if (!normalizedProviderSessionId) {
|
|
665
|
-
return null;
|
|
666
|
-
}
|
|
667
|
-
const resolvedRawStoreRef = await this.resolveRealRawStoreRef(normalizedProviderSessionId, workspacePath, homeDirOverride);
|
|
668
|
-
if (!resolvedRawStoreRef) {
|
|
669
|
-
return null;
|
|
670
|
-
}
|
|
671
|
-
return {
|
|
672
|
-
providerSessionId: normalizedProviderSessionId,
|
|
673
|
-
rawStoreRef: resolvedRawStoreRef
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
async resolveLaunchedSessionBinding(workspacePath, firstUserMessage, launchedAtMs, homeDirOverride = null) {
|
|
677
|
-
for (let attempt = 0; attempt < 20; attempt += 1) {
|
|
678
|
-
const matched = this.findLaunchedSessionBindingOnce(workspacePath, firstUserMessage, launchedAtMs, homeDirOverride);
|
|
679
|
-
if (matched) {
|
|
680
|
-
return matched;
|
|
681
|
-
}
|
|
682
|
-
if (attempt < 19) {
|
|
683
|
-
await sleep(100);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
return null;
|
|
687
|
-
}
|
|
688
|
-
async resolveRealRawStoreRef(providerSessionId, workspacePath, homeDirOverride = null) {
|
|
689
|
-
for (let attempt = 0; attempt < 10; attempt += 1) {
|
|
690
|
-
const matched = this.findRawStoreRefOnce(providerSessionId, workspacePath, homeDirOverride);
|
|
691
|
-
if (matched) {
|
|
692
|
-
return matched;
|
|
693
|
-
}
|
|
694
|
-
if (attempt < 9) {
|
|
695
|
-
await sleep(150);
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
return null;
|
|
699
|
-
}
|
|
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");
|
|
705
|
-
const candidates = this.listSessionFiles(homeDir);
|
|
706
|
-
const normalizedWorkspace = normalizeWorkspacePath(workspacePath);
|
|
707
|
-
for (const filePath of candidates) {
|
|
708
|
-
const meta = readSessionMeta(filePath);
|
|
709
|
-
if (!meta) {
|
|
710
|
-
continue;
|
|
711
|
-
}
|
|
712
|
-
if (meta.threadId !== providerSessionId) {
|
|
713
|
-
continue;
|
|
714
|
-
}
|
|
715
|
-
if (meta.cwd && normalizeWorkspacePath(meta.cwd) !== normalizedWorkspace) {
|
|
716
|
-
continue;
|
|
717
|
-
}
|
|
718
|
-
return filePath;
|
|
719
|
-
}
|
|
720
|
-
return null;
|
|
721
|
-
}
|
|
722
|
-
listSessionFiles(homeDir) {
|
|
723
|
-
const now = new Date();
|
|
724
|
-
const currentYear = String(now.getUTCFullYear());
|
|
725
|
-
const currentMonth = String(now.getUTCMonth() + 1).padStart(2, "0");
|
|
726
|
-
const currentDay = String(now.getUTCDate()).padStart(2, "0");
|
|
727
|
-
const preferredRoots = [
|
|
728
|
-
join(homeDir, "sessions", currentYear, currentMonth, currentDay),
|
|
729
|
-
join(homeDir, "sessions"),
|
|
730
|
-
join(homeDir, "archived_sessions")
|
|
731
|
-
];
|
|
732
|
-
const seen = new Set();
|
|
733
|
-
const files = [];
|
|
734
|
-
for (const root of preferredRoots) {
|
|
735
|
-
for (const file of walkJsonlFiles(root)) {
|
|
736
|
-
if (seen.has(file)) {
|
|
737
|
-
continue;
|
|
738
|
-
}
|
|
739
|
-
seen.add(file);
|
|
740
|
-
files.push(file);
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
return files;
|
|
744
|
-
}
|
|
745
|
-
findLaunchedSessionBindingOnce(workspacePath, firstUserMessage, launchedAtMs, homeDirOverride = null) {
|
|
746
|
-
const dbPath = findLatestCodexStateDatabase(this.getCodexHomeDir(homeDirOverride));
|
|
747
|
-
if (!dbPath) {
|
|
748
|
-
return null;
|
|
749
|
-
}
|
|
750
|
-
const DatabaseSync = loadDatabaseSync();
|
|
751
|
-
let db = null;
|
|
752
|
-
try {
|
|
753
|
-
db = new DatabaseSync(dbPath, { open: true, readOnly: true });
|
|
754
|
-
const rows = db.prepare(`SELECT id, rollout_path, cwd, first_user_message, created_at
|
|
755
|
-
FROM threads
|
|
756
|
-
WHERE source = 'exec'
|
|
757
|
-
AND created_at >= ?
|
|
758
|
-
ORDER BY created_at DESC
|
|
759
|
-
LIMIT 30`).all(Math.max(0, Math.floor((launchedAtMs - 30_000) / 1000)));
|
|
760
|
-
const normalizedWorkspace = normalizeWorkspacePath(workspacePath);
|
|
761
|
-
const normalizedMessage = firstUserMessage.trim();
|
|
762
|
-
for (const row of rows) {
|
|
763
|
-
if (normalizeWorkspacePath(row.cwd) !== normalizedWorkspace ||
|
|
764
|
-
row.first_user_message.trim() !== normalizedMessage ||
|
|
765
|
-
!existsSync(row.rollout_path)) {
|
|
766
|
-
continue;
|
|
767
|
-
}
|
|
768
|
-
return {
|
|
769
|
-
providerSessionId: row.id,
|
|
770
|
-
rawStoreRef: row.rollout_path
|
|
771
|
-
};
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
catch {
|
|
775
|
-
return null;
|
|
776
|
-
}
|
|
777
|
-
finally {
|
|
778
|
-
db?.close();
|
|
779
|
-
}
|
|
780
|
-
return null;
|
|
781
|
-
}
|
|
782
|
-
getCodexHomeDir(homeDirOverride = null) {
|
|
783
|
-
return (homeDirOverride?.trim()
|
|
784
|
-
|| this.options.homeDir?.trim()
|
|
785
|
-
|| process.env.CODINGNS_CODEX_HOME
|
|
786
|
-
|| join(homedir(), ".codex"));
|
|
787
|
-
}
|
|
788
|
-
buildMessage(context, input) {
|
|
789
|
-
const stableRef = this.resolveStableMessageRef(context, input.stableIdentity ?? null);
|
|
790
|
-
const rawRef = stableRef?.rawRef ??
|
|
791
|
-
createRawRef(this.providerId, context.rawStoreRef, ++context.sequence);
|
|
792
|
-
const sequence = stableRef?.sequence ?? context.sequence;
|
|
793
|
-
const messageId = stableRef?.messageId ?? messageIdFromRawRef(rawRef);
|
|
794
|
-
return {
|
|
795
|
-
messageId,
|
|
796
|
-
provider: this.providerId,
|
|
797
|
-
providerSessionId: context.providerSessionId,
|
|
798
|
-
role: input.role,
|
|
799
|
-
kind: input.kind,
|
|
800
|
-
content: input.content,
|
|
801
|
-
toolCall: input.toolCall ?? null,
|
|
802
|
-
timestamp: input.timestamp,
|
|
803
|
-
sequence,
|
|
804
|
-
rawRef
|
|
805
|
-
};
|
|
806
|
-
}
|
|
807
|
-
resolveStableMessageRef(context, stableIdentity) {
|
|
808
|
-
if (!stableIdentity) {
|
|
809
|
-
return null;
|
|
810
|
-
}
|
|
811
|
-
const existing = context.stableMessageRefByIdentity.get(stableIdentity);
|
|
812
|
-
if (existing) {
|
|
813
|
-
return existing;
|
|
814
|
-
}
|
|
815
|
-
context.sequence += 1;
|
|
816
|
-
const rawRef = createRawRef(this.providerId, context.rawStoreRef, context.sequence);
|
|
817
|
-
const created = {
|
|
818
|
-
sequence: context.sequence,
|
|
819
|
-
rawRef,
|
|
820
|
-
messageId: messageIdFromStableKey(buildCodexStableMessageKey(context.providerSessionId, stableIdentity))
|
|
821
|
-
};
|
|
822
|
-
context.stableMessageRefByIdentity.set(stableIdentity, created);
|
|
823
|
-
return created;
|
|
824
|
-
}
|
|
825
|
-
async awaitThreadStarted(thread, events, workspacePath, firstUserMessage, launchedAtMs) {
|
|
826
|
-
const bufferedEvents = [];
|
|
827
|
-
while (true) {
|
|
828
|
-
const next = await events.next();
|
|
829
|
-
if (next.done) {
|
|
830
|
-
const resolved = await this.resolveLaunchedSessionBinding(workspacePath, firstUserMessage, launchedAtMs);
|
|
831
|
-
if (resolved) {
|
|
832
|
-
return {
|
|
833
|
-
providerSessionId: resolved.providerSessionId,
|
|
834
|
-
bufferedEvents
|
|
835
|
-
};
|
|
836
|
-
}
|
|
837
|
-
throw new Error("CODEX_THREAD_START_MISSING");
|
|
838
|
-
}
|
|
839
|
-
const eventType = ensureText(readProp(next.value, "type")).trim();
|
|
840
|
-
if (eventType === "thread.started") {
|
|
841
|
-
const providerSessionId = pickFirstNonEmpty(ensureText(readProp(next.value, "thread_id")).trim(), ensureText(thread.id).trim());
|
|
842
|
-
if (providerSessionId.length === 0) {
|
|
843
|
-
throw new Error("CODEX_THREAD_ID_MISSING");
|
|
844
|
-
}
|
|
845
|
-
return {
|
|
846
|
-
providerSessionId,
|
|
847
|
-
bufferedEvents
|
|
848
|
-
};
|
|
849
|
-
}
|
|
850
|
-
bufferedEvents.push(next.value);
|
|
851
|
-
const resolved = await this.resolveLaunchedSessionBinding(workspacePath, firstUserMessage, launchedAtMs);
|
|
852
|
-
if (resolved) {
|
|
853
|
-
return {
|
|
854
|
-
providerSessionId: resolved.providerSessionId,
|
|
855
|
-
bufferedEvents
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
function createCodexAppServerTransport(options) {
|
|
862
|
-
const commandPath = resolveCodexCommand(options.commandPath);
|
|
863
|
-
const launch = resolveCodexCommandLaunch(commandPath, ["app-server"]);
|
|
864
|
-
const runtimeEnv = options.runtimeEnv ?? null;
|
|
865
|
-
const child = spawn(launch.command, launch.args, {
|
|
866
|
-
env: {
|
|
867
|
-
...process.env,
|
|
868
|
-
...(runtimeEnv ?? {})
|
|
869
|
-
},
|
|
870
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
871
|
-
shell: launch.shell,
|
|
872
|
-
windowsHide: true
|
|
873
|
-
});
|
|
874
|
-
const stdout = createInterface({ input: child.stdout });
|
|
875
|
-
let notificationHandler = () => undefined;
|
|
876
|
-
let serverRequestHandler = async () => {
|
|
877
|
-
throw new Error("CODEX_APP_SERVER_REQUEST_NOT_SUPPORTED");
|
|
878
|
-
};
|
|
879
|
-
let requestSequence = 0;
|
|
880
|
-
let closed = false;
|
|
881
|
-
let activeTurnId = null;
|
|
882
|
-
let activeThreadId = null;
|
|
883
|
-
let closeHandler = null;
|
|
884
|
-
const pendingResponses = new Map();
|
|
885
|
-
const finalize = (error) => {
|
|
886
|
-
if (closed) {
|
|
887
|
-
return;
|
|
888
|
-
}
|
|
889
|
-
closed = true;
|
|
890
|
-
stdout.close();
|
|
891
|
-
for (const pending of pendingResponses.values()) {
|
|
892
|
-
pending.reject(error ?? new Error("CODEX_APP_SERVER_CLOSED"));
|
|
893
|
-
}
|
|
894
|
-
pendingResponses.clear();
|
|
895
|
-
closeHandler?.(error);
|
|
896
|
-
};
|
|
897
|
-
child.on("error", (error) => {
|
|
898
|
-
finalize(error);
|
|
899
|
-
});
|
|
900
|
-
child.on("exit", (code, signal) => {
|
|
901
|
-
if (closed) {
|
|
902
|
-
return;
|
|
903
|
-
}
|
|
904
|
-
const detail = signal
|
|
905
|
-
? `codex app-server exited with signal ${signal}`
|
|
906
|
-
: `codex app-server exited with code ${String(code ?? "unknown")}`;
|
|
907
|
-
finalize(new Error(detail));
|
|
908
|
-
});
|
|
909
|
-
stdout.on("line", (line) => {
|
|
910
|
-
const trimmed = line.trim();
|
|
911
|
-
if (!trimmed) {
|
|
912
|
-
return;
|
|
913
|
-
}
|
|
914
|
-
let parsed;
|
|
915
|
-
try {
|
|
916
|
-
parsed = JSON.parse(trimmed);
|
|
917
|
-
}
|
|
918
|
-
catch {
|
|
919
|
-
return;
|
|
920
|
-
}
|
|
921
|
-
if (typeof parsed.method === "string" && parsed.id !== undefined) {
|
|
922
|
-
void Promise.resolve(serverRequestHandler(parsed))
|
|
923
|
-
.then((result) => {
|
|
924
|
-
writeJsonRpcMessage(child, {
|
|
925
|
-
jsonrpc: "2.0",
|
|
926
|
-
id: parsed.id,
|
|
927
|
-
result
|
|
928
|
-
});
|
|
929
|
-
})
|
|
930
|
-
.catch((error) => {
|
|
931
|
-
writeJsonRpcMessage(child, {
|
|
932
|
-
jsonrpc: "2.0",
|
|
933
|
-
id: parsed.id,
|
|
934
|
-
error: {
|
|
935
|
-
code: -32000,
|
|
936
|
-
message: error instanceof Error ? error.message : "CODEX_APP_SERVER_REQUEST_FAILED"
|
|
937
|
-
}
|
|
938
|
-
});
|
|
939
|
-
});
|
|
940
|
-
return;
|
|
941
|
-
}
|
|
942
|
-
if (typeof parsed.method === "string") {
|
|
943
|
-
const method = parsed.method.trim();
|
|
944
|
-
const params = readJsonRpcParams(parsed);
|
|
945
|
-
if (method === "turn/started") {
|
|
946
|
-
activeTurnId = ensureText(readProp(readProp(params, "turn"), "id")).trim() || activeTurnId;
|
|
947
|
-
}
|
|
948
|
-
if (method === "thread/started") {
|
|
949
|
-
activeThreadId = ensureText(readProp(readProp(params, "thread"), "id")).trim() || activeThreadId;
|
|
950
|
-
}
|
|
951
|
-
void notificationHandler({
|
|
952
|
-
method,
|
|
953
|
-
params
|
|
954
|
-
});
|
|
955
|
-
return;
|
|
956
|
-
}
|
|
957
|
-
const responseId = String(parsed.id ?? "");
|
|
958
|
-
const pending = pendingResponses.get(responseId);
|
|
959
|
-
if (!pending) {
|
|
960
|
-
return;
|
|
961
|
-
}
|
|
962
|
-
pendingResponses.delete(responseId);
|
|
963
|
-
if (parsed.error && typeof parsed.error === "object") {
|
|
964
|
-
const message = ensureText(readProp(parsed.error, "message")).trim() || "CODEX_APP_SERVER_ERROR";
|
|
965
|
-
pending.reject(new Error(message));
|
|
966
|
-
return;
|
|
967
|
-
}
|
|
968
|
-
pending.resolve(readJsonRpcResult(parsed));
|
|
969
|
-
});
|
|
970
|
-
return {
|
|
971
|
-
async initialize() {
|
|
972
|
-
const startedAtMs = performance.now();
|
|
973
|
-
await sendJsonRpcRequest(child, pendingResponses, () => nextJsonRpcId("initialize", () => ++requestSequence), {
|
|
974
|
-
method: "initialize",
|
|
975
|
-
params: {
|
|
976
|
-
clientInfo: {
|
|
977
|
-
name: "codingns-runtime",
|
|
978
|
-
version: "0.0.0"
|
|
979
|
-
},
|
|
980
|
-
capabilities: null
|
|
981
|
-
}
|
|
982
|
-
});
|
|
983
|
-
writeJsonRpcMessage(child, {
|
|
984
|
-
jsonrpc: "2.0",
|
|
985
|
-
method: "initialized",
|
|
986
|
-
params: {}
|
|
987
|
-
});
|
|
988
|
-
logCodexRuntimeStep("transport.initialize", startedAtMs);
|
|
989
|
-
},
|
|
990
|
-
async startThread(request) {
|
|
991
|
-
const startedAtMs = performance.now();
|
|
992
|
-
const result = await sendJsonRpcRequest(child, pendingResponses, () => nextJsonRpcId("thread-start", () => ++requestSequence), {
|
|
993
|
-
method: "thread/start",
|
|
994
|
-
params: createThreadStartParams(request)
|
|
995
|
-
});
|
|
996
|
-
const thread = toRecord(result.thread);
|
|
997
|
-
const providerSessionId = ensureText(thread?.id).trim();
|
|
998
|
-
if (!providerSessionId) {
|
|
999
|
-
throw new Error("CODEX_APP_SERVER_THREAD_ID_MISSING");
|
|
1000
|
-
}
|
|
1001
|
-
activeThreadId = providerSessionId;
|
|
1002
|
-
logCodexRuntimeStep("transport.thread_start", startedAtMs, {
|
|
1003
|
-
sessionId: request.sessionId,
|
|
1004
|
-
providerSessionId
|
|
1005
|
-
});
|
|
1006
|
-
return {
|
|
1007
|
-
providerSessionId,
|
|
1008
|
-
rawStoreRef: normalizeText(thread?.path) || null
|
|
1009
|
-
};
|
|
1010
|
-
},
|
|
1011
|
-
async resumeThread(request, providerSessionId) {
|
|
1012
|
-
const startedAtMs = performance.now();
|
|
1013
|
-
const result = await sendJsonRpcRequest(child, pendingResponses, () => nextJsonRpcId("thread-resume", () => ++requestSequence), {
|
|
1014
|
-
method: "thread/resume",
|
|
1015
|
-
params: createThreadResumeParams(request, providerSessionId)
|
|
1016
|
-
});
|
|
1017
|
-
const thread = toRecord(result.thread);
|
|
1018
|
-
activeThreadId = ensureText(thread?.id).trim() || providerSessionId;
|
|
1019
|
-
logCodexRuntimeStep("transport.thread_resume", startedAtMs, {
|
|
1020
|
-
sessionId: request.sessionId,
|
|
1021
|
-
providerSessionId: activeThreadId
|
|
1022
|
-
});
|
|
1023
|
-
return {
|
|
1024
|
-
providerSessionId: activeThreadId,
|
|
1025
|
-
rawStoreRef: normalizeText(thread?.path) || null
|
|
1026
|
-
};
|
|
1027
|
-
},
|
|
1028
|
-
async resumeThreadFromHistory(input) {
|
|
1029
|
-
const startedAtMs = performance.now();
|
|
1030
|
-
const result = await sendJsonRpcRequest(child, pendingResponses, () => nextJsonRpcId("thread-resume-history", () => ++requestSequence), {
|
|
1031
|
-
method: "thread/resume",
|
|
1032
|
-
params: createThreadResumeWithHistoryParams(input)
|
|
1033
|
-
});
|
|
1034
|
-
const thread = toRecord(result.thread);
|
|
1035
|
-
const providerSessionId = ensureText(thread?.id).trim();
|
|
1036
|
-
if (!providerSessionId) {
|
|
1037
|
-
throw new Error("CODEX_APP_SERVER_THREAD_ID_MISSING");
|
|
1038
|
-
}
|
|
1039
|
-
activeThreadId = providerSessionId;
|
|
1040
|
-
logCodexRuntimeStep("transport.thread_resume_from_history", startedAtMs, {
|
|
1041
|
-
providerSessionId
|
|
1042
|
-
});
|
|
1043
|
-
return {
|
|
1044
|
-
providerSessionId,
|
|
1045
|
-
rawStoreRef: normalizeText(thread?.path) || null
|
|
1046
|
-
};
|
|
1047
|
-
},
|
|
1048
|
-
async startTurn(request, providerSessionId) {
|
|
1049
|
-
const startedAtMs = performance.now();
|
|
1050
|
-
const result = await sendJsonRpcRequest(child, pendingResponses, () => nextJsonRpcId("turn-start", () => ++requestSequence), {
|
|
1051
|
-
method: "turn/start",
|
|
1052
|
-
params: createTurnStartParams(request, providerSessionId)
|
|
1053
|
-
});
|
|
1054
|
-
const turn = toRecord(result.turn);
|
|
1055
|
-
activeTurnId = ensureText(readProp(turn, "id")).trim() || activeTurnId;
|
|
1056
|
-
logCodexRuntimeStep("transport.turn_start", startedAtMs, {
|
|
1057
|
-
sessionId: request.sessionId,
|
|
1058
|
-
providerSessionId,
|
|
1059
|
-
turnId: activeTurnId
|
|
1060
|
-
});
|
|
1061
|
-
return {
|
|
1062
|
-
notification: buildCodexTurnCompletionNotification(turn, providerSessionId)
|
|
1063
|
-
};
|
|
1064
|
-
},
|
|
1065
|
-
async steerTurn(options) {
|
|
1066
|
-
if (!activeThreadId || !activeTurnId) {
|
|
1067
|
-
throw new Error("SESSION_NOT_RUNNING");
|
|
1068
|
-
}
|
|
1069
|
-
try {
|
|
1070
|
-
const result = await sendJsonRpcRequest(child, pendingResponses, () => nextJsonRpcId("turn-steer", () => ++requestSequence), {
|
|
1071
|
-
method: "turn/steer",
|
|
1072
|
-
params: createTurnSteerParams(activeThreadId, activeTurnId, options)
|
|
1073
|
-
});
|
|
1074
|
-
const turnId = ensureText(readProp(result, "turnId")).trim();
|
|
1075
|
-
if (turnId) {
|
|
1076
|
-
activeTurnId = turnId;
|
|
1077
|
-
}
|
|
1078
|
-
return {
|
|
1079
|
-
turnId: turnId || activeTurnId
|
|
1080
|
-
};
|
|
1081
|
-
}
|
|
1082
|
-
catch (error) {
|
|
1083
|
-
throw normalizeCodexTurnSteerError(error);
|
|
1084
|
-
}
|
|
1085
|
-
},
|
|
1086
|
-
async interruptTurn() {
|
|
1087
|
-
if (!activeThreadId || !activeTurnId) {
|
|
1088
|
-
return;
|
|
1089
|
-
}
|
|
1090
|
-
await sendJsonRpcRequest(child, pendingResponses, () => nextJsonRpcId("turn-interrupt", () => ++requestSequence), {
|
|
1091
|
-
method: "turn/interrupt",
|
|
1092
|
-
params: {
|
|
1093
|
-
threadId: activeThreadId,
|
|
1094
|
-
turnId: activeTurnId
|
|
1095
|
-
}
|
|
1096
|
-
});
|
|
1097
|
-
},
|
|
1098
|
-
setNotificationHandler(handler) {
|
|
1099
|
-
notificationHandler = handler;
|
|
1100
|
-
},
|
|
1101
|
-
setServerRequestHandler(handler) {
|
|
1102
|
-
serverRequestHandler = handler;
|
|
1103
|
-
},
|
|
1104
|
-
setOnClose(handler) {
|
|
1105
|
-
closeHandler = handler;
|
|
1106
|
-
},
|
|
1107
|
-
isClosed() {
|
|
1108
|
-
return closed;
|
|
1109
|
-
},
|
|
1110
|
-
close() {
|
|
1111
|
-
if (closed) {
|
|
1112
|
-
return;
|
|
1113
|
-
}
|
|
1114
|
-
finalize(null);
|
|
1115
|
-
if (!child.stdin.destroyed) {
|
|
1116
|
-
child.stdin.end();
|
|
1117
|
-
}
|
|
1118
|
-
if (!child.killed) {
|
|
1119
|
-
child.kill("SIGTERM");
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
};
|
|
1123
|
-
}
|
|
1124
|
-
function buildCodexTurnCompletionNotification(turn, threadId) {
|
|
1125
|
-
const status = ensureText(readProp(turn, "status")).trim();
|
|
1126
|
-
if (status !== "completed" && status !== "failed" && status !== "interrupted") {
|
|
1127
|
-
return null;
|
|
1128
|
-
}
|
|
1129
|
-
return {
|
|
1130
|
-
method: "turn/completed",
|
|
1131
|
-
params: {
|
|
1132
|
-
threadId,
|
|
1133
|
-
turn
|
|
1134
|
-
}
|
|
1135
|
-
};
|
|
1136
|
-
}
|
|
1137
|
-
function createAsyncEventQueue() {
|
|
1138
|
-
const values = [];
|
|
1139
|
-
const waiters = [];
|
|
1140
|
-
let closed = false;
|
|
1141
|
-
let turnId = null;
|
|
1142
|
-
return {
|
|
1143
|
-
iterator: {
|
|
1144
|
-
next() {
|
|
1145
|
-
if (values.length > 0) {
|
|
1146
|
-
return Promise.resolve({
|
|
1147
|
-
done: false,
|
|
1148
|
-
value: values.shift()
|
|
1149
|
-
});
|
|
1150
|
-
}
|
|
1151
|
-
if (closed) {
|
|
1152
|
-
return Promise.resolve({
|
|
1153
|
-
done: true,
|
|
1154
|
-
value: undefined
|
|
1155
|
-
});
|
|
1156
|
-
}
|
|
1157
|
-
return new Promise((resolve) => {
|
|
1158
|
-
waiters.push(resolve);
|
|
1159
|
-
});
|
|
1160
|
-
}
|
|
1161
|
-
},
|
|
1162
|
-
push(value) {
|
|
1163
|
-
if (closed) {
|
|
1164
|
-
return;
|
|
1165
|
-
}
|
|
1166
|
-
const waiter = waiters.shift();
|
|
1167
|
-
if (waiter) {
|
|
1168
|
-
waiter({
|
|
1169
|
-
done: false,
|
|
1170
|
-
value
|
|
1171
|
-
});
|
|
1172
|
-
return;
|
|
1173
|
-
}
|
|
1174
|
-
values.push(value);
|
|
1175
|
-
},
|
|
1176
|
-
close() {
|
|
1177
|
-
if (closed) {
|
|
1178
|
-
return;
|
|
1179
|
-
}
|
|
1180
|
-
closed = true;
|
|
1181
|
-
while (waiters.length > 0) {
|
|
1182
|
-
waiters.shift()?.({
|
|
1183
|
-
done: true,
|
|
1184
|
-
value: undefined
|
|
1185
|
-
});
|
|
1186
|
-
}
|
|
1187
|
-
},
|
|
1188
|
-
setTurnId(nextTurnId) {
|
|
1189
|
-
turnId = nextTurnId;
|
|
1190
|
-
},
|
|
1191
|
-
getTurnId() {
|
|
1192
|
-
return turnId;
|
|
1193
|
-
}
|
|
1194
|
-
};
|
|
1195
|
-
}
|
|
1196
|
-
function createCodexTranslatedNotificationForwarder(eventQueue) {
|
|
1197
|
-
const seenReplayKeys = new Set();
|
|
1198
|
-
return (translated) => {
|
|
1199
|
-
if (translated.turnId) {
|
|
1200
|
-
eventQueue.setTurnId(translated.turnId);
|
|
1201
|
-
}
|
|
1202
|
-
for (const event of translated.events) {
|
|
1203
|
-
const replayKey = buildCodexTranslatedReplayKey(event);
|
|
1204
|
-
if (replayKey) {
|
|
1205
|
-
if (seenReplayKeys.has(replayKey)) {
|
|
1206
|
-
continue;
|
|
1207
|
-
}
|
|
1208
|
-
seenReplayKeys.add(replayKey);
|
|
1209
|
-
while (seenReplayKeys.size > 1024) {
|
|
1210
|
-
const oldest = seenReplayKeys.keys().next().value;
|
|
1211
|
-
if (typeof oldest !== "string") {
|
|
1212
|
-
break;
|
|
1213
|
-
}
|
|
1214
|
-
seenReplayKeys.delete(oldest);
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
eventQueue.push(event);
|
|
1218
|
-
}
|
|
1219
|
-
if (translated.terminal) {
|
|
1220
|
-
eventQueue.close();
|
|
1221
|
-
}
|
|
1222
|
-
};
|
|
1223
|
-
}
|
|
1224
|
-
function buildCodexTranslatedReplayKey(event) {
|
|
1225
|
-
const eventType = ensureText(event.type).trim();
|
|
1226
|
-
if (!eventType) {
|
|
1227
|
-
return null;
|
|
1228
|
-
}
|
|
1229
|
-
if (eventType === "turn.completed" || eventType === "turn.failed" || eventType === "turn.interrupted") {
|
|
1230
|
-
return `${eventType}:${ensureText(readProp(event, "turnId")).trim() || ""}`;
|
|
1231
|
-
}
|
|
1232
|
-
if (!eventType.startsWith("item.")) {
|
|
1233
|
-
return null;
|
|
1234
|
-
}
|
|
1235
|
-
const item = toRecord(readProp(event, "item"));
|
|
1236
|
-
if (!item) {
|
|
1237
|
-
return null;
|
|
1238
|
-
}
|
|
1239
|
-
return JSON.stringify({
|
|
1240
|
-
eventType,
|
|
1241
|
-
itemType: ensureText(item.type).trim(),
|
|
1242
|
-
id: ensureText(item.id).trim(),
|
|
1243
|
-
status: ensureText(item.status).trim(),
|
|
1244
|
-
text: ensureText(item.text).trim(),
|
|
1245
|
-
summary: normalizeReplayKeyText(readProp(item, "summary")),
|
|
1246
|
-
content: normalizeReplayKeyText(readProp(item, "content")),
|
|
1247
|
-
command: normalizeReplayKeyText(readProp(item, "command")),
|
|
1248
|
-
result: normalizeReplayKeyText(readProp(item, "result")),
|
|
1249
|
-
output: normalizeReplayKeyText(readProp(item, "output")),
|
|
1250
|
-
aggregatedOutput: normalizeReplayKeyText(readProp(item, "aggregated_output")),
|
|
1251
|
-
error: normalizeReplayKeyText(readProp(item, "error"))
|
|
1252
|
-
});
|
|
1253
|
-
}
|
|
1254
|
-
function normalizeReplayKeyText(value) {
|
|
1255
|
-
if (Array.isArray(value)) {
|
|
1256
|
-
return value.map((entry) => normalizeReplayKeyText(entry)).join("\n");
|
|
1257
|
-
}
|
|
1258
|
-
if (value && typeof value === "object") {
|
|
1259
|
-
try {
|
|
1260
|
-
return JSON.stringify(value);
|
|
1261
|
-
}
|
|
1262
|
-
catch {
|
|
1263
|
-
return String(value);
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
return ensureText(value).trim();
|
|
1267
|
-
}
|
|
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) ?? [])];
|
|
1294
|
-
return {
|
|
1295
|
-
type: "reasoning",
|
|
1296
|
-
id: itemId,
|
|
1297
|
-
summary,
|
|
1298
|
-
content
|
|
1299
|
-
};
|
|
1300
|
-
};
|
|
1301
|
-
const translateAgentMessageDelta = (params) => {
|
|
1302
|
-
const itemId = ensureText(params.itemId).trim();
|
|
1303
|
-
const delta = ensureText(params.delta);
|
|
1304
|
-
if (!itemId || delta.length === 0) {
|
|
1305
|
-
return {
|
|
1306
|
-
events: [],
|
|
1307
|
-
terminal: false,
|
|
1308
|
-
turnId: ensureText(params.turnId).trim() || null
|
|
1309
|
-
};
|
|
1310
|
-
}
|
|
1311
|
-
const nextText = `${agentMessageTextById.get(itemId) ?? ""}${delta}`;
|
|
1312
|
-
agentMessageTextById.set(itemId, nextText);
|
|
1313
|
-
return {
|
|
1314
|
-
events: [
|
|
1315
|
-
{
|
|
1316
|
-
type: "item.updated",
|
|
1317
|
-
item: {
|
|
1318
|
-
type: "agent_message",
|
|
1319
|
-
id: itemId,
|
|
1320
|
-
text: nextText
|
|
1321
|
-
},
|
|
1322
|
-
timestamp: nextTimestamp()
|
|
1323
|
-
}
|
|
1324
|
-
],
|
|
1325
|
-
terminal: false,
|
|
1326
|
-
turnId: ensureText(params.turnId).trim() || null
|
|
1327
|
-
};
|
|
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) {
|
|
1345
|
-
return {
|
|
1346
|
-
events: [],
|
|
1347
|
-
terminal: false,
|
|
1348
|
-
turnId: ensureText(params.turnId).trim() || null
|
|
1349
|
-
};
|
|
1350
|
-
}
|
|
1351
|
-
parts[summaryIndex] = `${parts[summaryIndex] ?? ""}${delta}`;
|
|
1352
|
-
return {
|
|
1353
|
-
events: [
|
|
1354
|
-
{
|
|
1355
|
-
type: "item.updated",
|
|
1356
|
-
item: buildReasoningSyntheticItem(itemId),
|
|
1357
|
-
timestamp: nextTimestamp()
|
|
1358
|
-
}
|
|
1359
|
-
],
|
|
1360
|
-
terminal: false,
|
|
1361
|
-
turnId: ensureText(params.turnId).trim() || null
|
|
1362
|
-
};
|
|
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) {
|
|
1370
|
-
return {
|
|
1371
|
-
events: [],
|
|
1372
|
-
terminal: false,
|
|
1373
|
-
turnId: ensureText(params.turnId).trim() || null
|
|
1374
|
-
};
|
|
1375
|
-
}
|
|
1376
|
-
parts[contentIndex] = `${parts[contentIndex] ?? ""}${delta}`;
|
|
1377
|
-
return {
|
|
1378
|
-
events: [
|
|
1379
|
-
{
|
|
1380
|
-
type: "item.updated",
|
|
1381
|
-
item: buildReasoningSyntheticItem(itemId),
|
|
1382
|
-
timestamp: nextTimestamp()
|
|
1383
|
-
}
|
|
1384
|
-
],
|
|
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,
|
|
1545
|
-
turnId: null
|
|
1546
|
-
};
|
|
1547
|
-
};
|
|
1548
|
-
}
|
|
1549
|
-
function translateCodexAppServerTurnItems(turn, eventType) {
|
|
1550
|
-
const rawItems = Array.isArray(turn?.items) ? turn.items : [];
|
|
1551
|
-
const translatedItems = rawItems
|
|
1552
|
-
.map((item) => translateCodexAppServerItem(toRecord(item)))
|
|
1553
|
-
.filter((item) => item !== null)
|
|
1554
|
-
.map((item) => ({
|
|
1555
|
-
type: eventType,
|
|
1556
|
-
item,
|
|
1557
|
-
timestamp: nextTimestamp()
|
|
1558
|
-
}));
|
|
1559
|
-
if (translatedItems.length > 0) {
|
|
1560
|
-
return translatedItems;
|
|
1561
|
-
}
|
|
1562
|
-
const lastAgentMessage = normalizeCodexTurnLastAgentMessage(turn);
|
|
1563
|
-
if (!lastAgentMessage) {
|
|
1564
|
-
return [];
|
|
1565
|
-
}
|
|
1566
|
-
return [
|
|
1567
|
-
{
|
|
1568
|
-
type: eventType,
|
|
1569
|
-
item: {
|
|
1570
|
-
type: "agent_message",
|
|
1571
|
-
id: ensureText(turn?.id).trim() || "turn-final-message",
|
|
1572
|
-
text: lastAgentMessage
|
|
1573
|
-
},
|
|
1574
|
-
timestamp: nextTimestamp()
|
|
1575
|
-
}
|
|
1576
|
-
];
|
|
1577
|
-
}
|
|
1578
|
-
function normalizeCodexTurnLastAgentMessage(turn) {
|
|
1579
|
-
const candidate = readProp(turn, "lastAgentMessage")
|
|
1580
|
-
?? readProp(turn, "last_agent_message")
|
|
1581
|
-
?? readProp(turn, "lastMessage")
|
|
1582
|
-
?? readProp(turn, "last_message");
|
|
1583
|
-
if (typeof candidate === "string") {
|
|
1584
|
-
const normalized = candidate.trim();
|
|
1585
|
-
return normalized.length > 0 ? normalized : null;
|
|
1586
|
-
}
|
|
1587
|
-
const record = toRecord(candidate);
|
|
1588
|
-
if (!record) {
|
|
1589
|
-
return null;
|
|
1590
|
-
}
|
|
1591
|
-
const content = pickFirstNonEmpty(ensureText(record.text).trim(), extractTextBlocks(readProp(record, "content")).trim(), ensureText(readProp(record, "message")).trim());
|
|
1592
|
-
return content.length > 0 ? content : null;
|
|
1593
|
-
}
|
|
1594
|
-
function buildCodexAppServerErrorDetail(error) {
|
|
1595
|
-
const message = ensureText(error?.message).trim();
|
|
1596
|
-
const additionalDetails = ensureText(error?.additionalDetails).trim();
|
|
1597
|
-
if (message && additionalDetails && !message.includes(additionalDetails)) {
|
|
1598
|
-
return `${message}\n${additionalDetails}`;
|
|
1599
|
-
}
|
|
1600
|
-
return message || additionalDetails || "codex app-server error";
|
|
1601
|
-
}
|
|
1602
|
-
function buildCodexMessageSignature(message) {
|
|
1603
|
-
return JSON.stringify({
|
|
1604
|
-
role: message.role,
|
|
1605
|
-
kind: message.kind,
|
|
1606
|
-
content: message.content,
|
|
1607
|
-
toolCall: message.toolCall
|
|
1608
|
-
? {
|
|
1609
|
-
callId: message.toolCall.callId,
|
|
1610
|
-
name: message.toolCall.name,
|
|
1611
|
-
input: message.toolCall.input,
|
|
1612
|
-
output: message.toolCall.output,
|
|
1613
|
-
error: message.toolCall.error,
|
|
1614
|
-
status: message.toolCall.status
|
|
1615
|
-
}
|
|
1616
|
-
: null
|
|
1617
|
-
});
|
|
1618
|
-
}
|
|
1619
|
-
function translateCodexAppServerItem(item) {
|
|
1620
|
-
if (!item) {
|
|
1621
|
-
return null;
|
|
1622
|
-
}
|
|
1623
|
-
const itemType = ensureText(item.type).trim();
|
|
1624
|
-
if (!itemType) {
|
|
1625
|
-
return null;
|
|
1626
|
-
}
|
|
1627
|
-
if (itemType === "agentMessage") {
|
|
1628
|
-
return {
|
|
1629
|
-
type: "agent_message",
|
|
1630
|
-
id: item.id,
|
|
1631
|
-
text: ensureText(item.text).trim()
|
|
1632
|
-
};
|
|
1633
|
-
}
|
|
1634
|
-
if (itemType === "reasoning") {
|
|
1635
|
-
return {
|
|
1636
|
-
type: "reasoning",
|
|
1637
|
-
id: item.id,
|
|
1638
|
-
text: Array.isArray(item.content) ? item.content.join("\n") : ensureText(item.text).trim(),
|
|
1639
|
-
summary: Array.isArray(item.summary) ? item.summary.join("\n") : ensureText(item.summary).trim()
|
|
1640
|
-
};
|
|
1641
|
-
}
|
|
1642
|
-
if (itemType === "commandExecution") {
|
|
1643
|
-
const patchText = extractApplyPatchTextFromCommandLikeValues(item.command);
|
|
1644
|
-
if (patchText) {
|
|
1645
|
-
return {
|
|
1646
|
-
type: "custom_tool_call",
|
|
1647
|
-
id: item.id,
|
|
1648
|
-
tool: "apply_patch",
|
|
1649
|
-
input: patchText,
|
|
1650
|
-
output: item.aggregatedOutput,
|
|
1651
|
-
error: item.error,
|
|
1652
|
-
status: normalizeCodexItemStatus(item.status)
|
|
1653
|
-
};
|
|
1654
|
-
}
|
|
1655
|
-
return {
|
|
1656
|
-
type: "command_execution",
|
|
1657
|
-
id: item.id,
|
|
1658
|
-
command: item.command,
|
|
1659
|
-
cwd: item.cwd,
|
|
1660
|
-
status: normalizeCodexItemStatus(item.status),
|
|
1661
|
-
commandActions: item.commandActions,
|
|
1662
|
-
aggregated_output: item.aggregatedOutput,
|
|
1663
|
-
exit_code: item.exitCode
|
|
1664
|
-
};
|
|
1665
|
-
}
|
|
1666
|
-
if (itemType === "fileChange") {
|
|
1667
|
-
const diffText = buildCodexFileChangeOutput(item.changes);
|
|
1668
|
-
return {
|
|
1669
|
-
type: "custom_tool_call",
|
|
1670
|
-
id: item.id,
|
|
1671
|
-
tool: "apply_patch",
|
|
1672
|
-
input: diffText,
|
|
1673
|
-
output: diffText,
|
|
1674
|
-
status: normalizeCodexItemStatus(item.status)
|
|
1675
|
-
};
|
|
1676
|
-
}
|
|
1677
|
-
if (itemType === "mcpToolCall") {
|
|
1678
|
-
return {
|
|
1679
|
-
type: "mcp_tool_call",
|
|
1680
|
-
id: item.id,
|
|
1681
|
-
tool: item.tool,
|
|
1682
|
-
server: item.server,
|
|
1683
|
-
arguments: item.arguments,
|
|
1684
|
-
result: item.result,
|
|
1685
|
-
error: item.error,
|
|
1686
|
-
status: normalizeCodexItemStatus(item.status)
|
|
1687
|
-
};
|
|
1688
|
-
}
|
|
1689
|
-
if (itemType === "dynamicToolCall") {
|
|
1690
|
-
const toolName = ensureText(item.tool).trim();
|
|
1691
|
-
const patchText = isCodexExecCommandToolName(toolName)
|
|
1692
|
-
? extractApplyPatchTextFromCommandLikeValues(item.arguments)
|
|
1693
|
-
: null;
|
|
1694
|
-
return {
|
|
1695
|
-
type: "custom_tool_call",
|
|
1696
|
-
id: item.id,
|
|
1697
|
-
tool: patchText ? "apply_patch" : item.tool,
|
|
1698
|
-
input: patchText ?? item.arguments,
|
|
1699
|
-
output: item.contentItems,
|
|
1700
|
-
success: item.success,
|
|
1701
|
-
status: normalizeCodexItemStatus(item.status)
|
|
1702
|
-
};
|
|
1703
|
-
}
|
|
1704
|
-
return null;
|
|
1705
|
-
}
|
|
1706
|
-
export function createThreadOptions(request) {
|
|
1707
|
-
const options = {
|
|
1708
|
-
workingDirectory: request.workspacePath,
|
|
1709
|
-
skipGitRepoCheck: true,
|
|
1710
|
-
...createCodexThreadPermissionOptions(request.options.permissionMode ?? "default")
|
|
1711
|
-
};
|
|
1712
|
-
if (request.options.model) {
|
|
1713
|
-
options.model = request.options.model;
|
|
1714
|
-
}
|
|
1715
|
-
const reasoningEffort = normalizeCodexReasoningEffort(request.options.reasoningLevel);
|
|
1716
|
-
if (reasoningEffort) {
|
|
1717
|
-
options.modelReasoningEffort = reasoningEffort;
|
|
1718
|
-
}
|
|
1719
|
-
const additionalDirectories = Array.from(new Set(request.options.attachments.map((attachment) => dirname(attachment.filePath))));
|
|
1720
|
-
if (additionalDirectories.length > 0) {
|
|
1721
|
-
options.additionalDirectories = additionalDirectories;
|
|
1722
|
-
}
|
|
1723
|
-
return options;
|
|
1724
|
-
}
|
|
1725
|
-
function createThreadStartParams(request) {
|
|
1726
|
-
const permissionOptions = createCodexThreadPermissionOptions(request.options.permissionMode ?? "default");
|
|
1727
|
-
const params = {
|
|
1728
|
-
cwd: request.workspacePath,
|
|
1729
|
-
approvalsReviewer: "user"
|
|
1730
|
-
};
|
|
1731
|
-
if (permissionOptions.approvalPolicy) {
|
|
1732
|
-
params.approvalPolicy = permissionOptions.approvalPolicy;
|
|
1733
|
-
}
|
|
1734
|
-
if (permissionOptions.sandboxMode) {
|
|
1735
|
-
params.sandbox = permissionOptions.sandboxMode;
|
|
1736
|
-
}
|
|
1737
|
-
if (request.options.model) {
|
|
1738
|
-
params.model = request.options.model;
|
|
1739
|
-
}
|
|
1740
|
-
return params;
|
|
1741
|
-
}
|
|
1742
|
-
function createThreadResumeParams(request, providerSessionId) {
|
|
1743
|
-
const permissionOptions = createCodexThreadPermissionOptions(request.options.permissionMode ?? "default");
|
|
1744
|
-
const params = {
|
|
1745
|
-
threadId: providerSessionId,
|
|
1746
|
-
cwd: request.workspacePath,
|
|
1747
|
-
approvalsReviewer: "user"
|
|
1748
|
-
};
|
|
1749
|
-
if (permissionOptions.approvalPolicy) {
|
|
1750
|
-
params.approvalPolicy = permissionOptions.approvalPolicy;
|
|
1751
|
-
}
|
|
1752
|
-
if (permissionOptions.sandboxMode) {
|
|
1753
|
-
params.sandbox = permissionOptions.sandboxMode;
|
|
1754
|
-
}
|
|
1755
|
-
if (request.options.model) {
|
|
1756
|
-
params.model = request.options.model;
|
|
1757
|
-
}
|
|
1758
|
-
return params;
|
|
1759
|
-
}
|
|
1760
|
-
function createThreadResumeWithHistoryParams(input) {
|
|
1761
|
-
const params = {
|
|
1762
|
-
threadId: input.providerSessionId && input.providerSessionId.trim().length > 0
|
|
1763
|
-
? input.providerSessionId.trim()
|
|
1764
|
-
: "__history_resume__",
|
|
1765
|
-
cwd: input.workspacePath,
|
|
1766
|
-
history: input.history,
|
|
1767
|
-
approvalsReviewer: "user"
|
|
1768
|
-
};
|
|
1769
|
-
if (input.model) {
|
|
1770
|
-
params.model = input.model;
|
|
1771
|
-
}
|
|
1772
|
-
return params;
|
|
1773
|
-
}
|
|
1774
|
-
function createTurnStartParams(request, providerSessionId) {
|
|
1775
|
-
const permissionOptions = createCodexThreadPermissionOptions(request.options.permissionMode ?? "default");
|
|
1776
|
-
const params = {
|
|
1777
|
-
threadId: providerSessionId,
|
|
1778
|
-
input: createCodexAppServerInput(request),
|
|
1779
|
-
cwd: request.workspacePath,
|
|
1780
|
-
approvalsReviewer: "user"
|
|
1781
|
-
};
|
|
1782
|
-
if (permissionOptions.approvalPolicy) {
|
|
1783
|
-
params.approvalPolicy = permissionOptions.approvalPolicy;
|
|
1784
|
-
}
|
|
1785
|
-
if (request.options.model) {
|
|
1786
|
-
params.model = request.options.model;
|
|
1787
|
-
}
|
|
1788
|
-
const reasoningEffort = normalizeCodexReasoningEffort(request.options.reasoningLevel);
|
|
1789
|
-
if (reasoningEffort) {
|
|
1790
|
-
params.effort = reasoningEffort;
|
|
1791
|
-
}
|
|
1792
|
-
return params;
|
|
1793
|
-
}
|
|
1794
|
-
function createTurnSteerParams(providerSessionId, activeTurnId, options) {
|
|
1795
|
-
return {
|
|
1796
|
-
threadId: providerSessionId,
|
|
1797
|
-
expectedTurnId: activeTurnId,
|
|
1798
|
-
input: createCodexAppServerInputFromOptions(options)
|
|
1799
|
-
};
|
|
1800
|
-
}
|
|
1801
|
-
function normalizeCodexReasoningEffort(value) {
|
|
1802
|
-
const normalized = value?.trim().toLowerCase() ?? null;
|
|
1803
|
-
if (!normalized) {
|
|
1804
|
-
return null;
|
|
1805
|
-
}
|
|
1806
|
-
if (normalized === "maximum") {
|
|
1807
|
-
return "xhigh";
|
|
1808
|
-
}
|
|
1809
|
-
if (normalized === "minimal" ||
|
|
1810
|
-
normalized === "low" ||
|
|
1811
|
-
normalized === "medium" ||
|
|
1812
|
-
normalized === "high" ||
|
|
1813
|
-
normalized === "xhigh") {
|
|
1814
|
-
return normalized;
|
|
1815
|
-
}
|
|
1816
|
-
return null;
|
|
1817
|
-
}
|
|
1818
|
-
function createCodexInput(request) {
|
|
1819
|
-
if (request.options.attachments.length === 0) {
|
|
1820
|
-
return request.options.content;
|
|
1821
|
-
}
|
|
1822
|
-
const input = [];
|
|
1823
|
-
const promptText = request.options.content.trim();
|
|
1824
|
-
if (promptText.length > 0) {
|
|
1825
|
-
input.push({
|
|
1826
|
-
type: "text",
|
|
1827
|
-
text: promptText
|
|
1828
|
-
});
|
|
1829
|
-
}
|
|
1830
|
-
request.options.attachments.forEach((attachment) => {
|
|
1831
|
-
if (attachment.kind !== "image") {
|
|
1832
|
-
return;
|
|
1833
|
-
}
|
|
1834
|
-
input.push({
|
|
1835
|
-
type: "local_image",
|
|
1836
|
-
path: attachment.filePath
|
|
1837
|
-
});
|
|
1838
|
-
});
|
|
1839
|
-
return input;
|
|
1840
|
-
}
|
|
1841
|
-
function createCodexAppServerInput(request) {
|
|
1842
|
-
return createCodexAppServerInputFromOptions(request.options);
|
|
1843
|
-
}
|
|
1844
|
-
function createCodexAppServerInputFromOptions(options) {
|
|
1845
|
-
const input = [];
|
|
1846
|
-
const promptText = (options.providerPrompt ?? options.content).trim();
|
|
1847
|
-
if (promptText.length > 0) {
|
|
1848
|
-
input.push({
|
|
1849
|
-
type: "text",
|
|
1850
|
-
text: promptText
|
|
1851
|
-
});
|
|
1852
|
-
}
|
|
1853
|
-
for (const attachment of options.attachments) {
|
|
1854
|
-
if (attachment.kind !== "image") {
|
|
1855
|
-
continue;
|
|
1856
|
-
}
|
|
1857
|
-
input.push({
|
|
1858
|
-
type: "localImage",
|
|
1859
|
-
path: attachment.filePath
|
|
1860
|
-
});
|
|
1861
|
-
}
|
|
1862
|
-
return input;
|
|
1863
|
-
}
|
|
1864
|
-
function normalizeCodexTurnSteerError(error) {
|
|
1865
|
-
const detail = error instanceof Error ? error.message.trim() : String(error).trim();
|
|
1866
|
-
const normalized = detail.toLowerCase();
|
|
1867
|
-
if (normalized.includes("method not found")
|
|
1868
|
-
|| (normalized.includes("turn/steer") && normalized.includes("not found"))
|
|
1869
|
-
|| normalized.includes("unknown method")) {
|
|
1870
|
-
return new Error("IN_RUN_INPUT_NOT_SUPPORTED");
|
|
1871
|
-
}
|
|
1872
|
-
if (normalized.includes("expectedturnid")
|
|
1873
|
-
|| normalized.includes("active turn")
|
|
1874
|
-
|| normalized.includes("turn mismatch")
|
|
1875
|
-
|| normalized.includes("no active turn")
|
|
1876
|
-
|| normalized.includes("not running")) {
|
|
1877
|
-
return new Error("SESSION_NOT_RUNNING");
|
|
1878
|
-
}
|
|
1879
|
-
return error instanceof Error ? error : new Error(detail || "CODEX_TURN_STEER_FAILED");
|
|
1880
|
-
}
|
|
1881
|
-
async function loadCodexClient() {
|
|
1882
|
-
const moduleName = "@openai/codex-sdk";
|
|
1883
|
-
const runtimeImport = new Function("name", "return import(name);");
|
|
1884
|
-
const resolvedModuleName = resolveCodexSdkModuleSpecifier(moduleName);
|
|
1885
|
-
const module = (await runtimeImport(resolvedModuleName));
|
|
1886
|
-
if (!module.Codex) {
|
|
1887
|
-
throw new Error("CODEX_SDK_UNAVAILABLE");
|
|
1888
|
-
}
|
|
1889
|
-
return new module.Codex();
|
|
1890
|
-
}
|
|
1891
|
-
function resolveCodexSdkModuleSpecifier(moduleName) {
|
|
1892
|
-
const localSdkEntry = findNodeModulesFile(dirname(fileURLToPath(import.meta.url)), ["@openai", "codex-sdk", "dist", "index.js"]);
|
|
1893
|
-
if (localSdkEntry) {
|
|
1894
|
-
return pathToFileURL(localSdkEntry).href;
|
|
1895
|
-
}
|
|
1896
|
-
if (typeof import.meta.resolve === "function") {
|
|
1897
|
-
return import.meta.resolve(moduleName);
|
|
1898
|
-
}
|
|
1899
|
-
return moduleName;
|
|
1900
|
-
}
|
|
1901
|
-
function findNodeModulesFile(startDirectory, relativeSegments) {
|
|
1902
|
-
let currentDirectory = startDirectory;
|
|
1903
|
-
while (true) {
|
|
1904
|
-
const candidate = resolveNodeModulesCandidate(currentDirectory, relativeSegments);
|
|
1905
|
-
if (existsSync(candidate)) {
|
|
1906
|
-
return candidate;
|
|
1907
|
-
}
|
|
1908
|
-
const parentDirectory = dirname(currentDirectory);
|
|
1909
|
-
if (parentDirectory === currentDirectory) {
|
|
1910
|
-
return null;
|
|
1911
|
-
}
|
|
1912
|
-
currentDirectory = parentDirectory;
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
1915
|
-
function resolveNodeModulesCandidate(currentDirectory, relativeSegments) {
|
|
1916
|
-
if (basename(currentDirectory) === "node_modules") {
|
|
1917
|
-
return resolve(currentDirectory, ...relativeSegments);
|
|
1918
|
-
}
|
|
1919
|
-
return resolve(currentDirectory, "node_modules", ...relativeSegments);
|
|
1920
|
-
}
|
|
1921
|
-
function buildRuntimeRawStoreRef(providerSessionId) {
|
|
1922
|
-
return resolve(process.cwd(), "runtime", "codex", `${providerSessionId}.stream`);
|
|
1923
|
-
}
|
|
1924
|
-
function pickAvailableCodexRawStoreRef(providerSessionId, candidates, fallbackRawStoreRef) {
|
|
1925
|
-
const normalizedProviderSessionId = providerSessionId.trim();
|
|
1926
|
-
const normalizedCandidates = [];
|
|
1927
|
-
const seen = new Set();
|
|
1928
|
-
for (const candidate of candidates) {
|
|
1929
|
-
const normalized = candidate?.trim();
|
|
1930
|
-
if (!normalized || seen.has(normalized) || !existsSync(normalized)) {
|
|
1931
|
-
continue;
|
|
1932
|
-
}
|
|
1933
|
-
seen.add(normalized);
|
|
1934
|
-
normalizedCandidates.push(normalized);
|
|
1935
|
-
}
|
|
1936
|
-
if (!normalizedProviderSessionId) {
|
|
1937
|
-
return normalizedCandidates[0] ?? fallbackRawStoreRef;
|
|
1938
|
-
}
|
|
1939
|
-
for (const candidate of normalizedCandidates) {
|
|
1940
|
-
if (readSessionMeta(candidate)?.threadId === normalizedProviderSessionId) {
|
|
1941
|
-
return candidate;
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
|
-
for (const candidate of normalizedCandidates) {
|
|
1945
|
-
if (doesRawStorePathLookLikeThread(candidate, normalizedProviderSessionId)) {
|
|
1946
|
-
return candidate;
|
|
1947
|
-
}
|
|
1948
|
-
}
|
|
1949
|
-
for (const candidate of normalizedCandidates) {
|
|
1950
|
-
if (isSyntheticRawStoreRef(candidate)) {
|
|
1951
|
-
return candidate;
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
for (const candidate of normalizedCandidates) {
|
|
1955
|
-
if (!readSessionMeta(candidate)) {
|
|
1956
|
-
return candidate;
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1959
|
-
return fallbackRawStoreRef;
|
|
1960
|
-
}
|
|
1961
|
-
function doesRawStorePathLookLikeThread(rawStoreRef, providerSessionId) {
|
|
1962
|
-
const fileName = basename(rawStoreRef, ".jsonl").trim().toLowerCase();
|
|
1963
|
-
const normalizedProviderSessionId = providerSessionId.trim().toLowerCase();
|
|
1964
|
-
if (!fileName || !normalizedProviderSessionId) {
|
|
1965
|
-
return false;
|
|
1966
|
-
}
|
|
1967
|
-
return fileName === normalizedProviderSessionId || fileName.includes(normalizedProviderSessionId);
|
|
1968
|
-
}
|
|
1969
|
-
function resolveRuntimeStoreKey(providerSessionId, sessionId) {
|
|
1970
|
-
return providerSessionId.trim() || sessionId;
|
|
1971
|
-
}
|
|
1972
|
-
function resolveCodexCommand(explicitPath) {
|
|
1973
|
-
const explicitCandidate = explicitPath?.trim() ||
|
|
1974
|
-
process.env.CODINGNS_CODEX_COMMAND?.trim() ||
|
|
1975
|
-
"codex";
|
|
1976
|
-
return explicitCandidate;
|
|
1977
|
-
}
|
|
1978
|
-
function resolveCodexCommandLaunch(commandPath, args) {
|
|
1979
|
-
const normalizedCommandPath = commandPath.trim();
|
|
1980
|
-
if (isNodeScriptPath(normalizedCommandPath)) {
|
|
1981
|
-
return {
|
|
1982
|
-
command: process.execPath,
|
|
1983
|
-
args: [normalizedCommandPath, ...args],
|
|
1984
|
-
shell: false
|
|
1985
|
-
};
|
|
1986
|
-
}
|
|
1987
|
-
return {
|
|
1988
|
-
command: normalizedCommandPath,
|
|
1989
|
-
args: [...args],
|
|
1990
|
-
shell: shouldSpawnViaShellOnWindows(normalizedCommandPath)
|
|
1991
|
-
};
|
|
1992
|
-
}
|
|
1993
|
-
function isNodeScriptPath(commandPath) {
|
|
1994
|
-
return /\.(?:c|m)?js$/i.test(commandPath);
|
|
1995
|
-
}
|
|
1996
|
-
function shouldSpawnViaShellOnWindows(commandPath) {
|
|
1997
|
-
if (process.platform !== "win32") {
|
|
1998
|
-
return false;
|
|
1999
|
-
}
|
|
2000
|
-
if (/\.(cmd|bat)$/i.test(commandPath)) {
|
|
2001
|
-
return true;
|
|
2002
|
-
}
|
|
2003
|
-
// Windows 上裸名命令(无扩展名、无路径分隔符)需要 shell 才能从 PATH 解析 .cmd 文件
|
|
2004
|
-
const extension = commandPath.split(".").pop()?.toLowerCase();
|
|
2005
|
-
const hasPathSep = commandPath.includes("\\") || commandPath.includes("/");
|
|
2006
|
-
if (!extension || extension === commandPath.toLowerCase()) {
|
|
2007
|
-
if (!hasPathSep) {
|
|
2008
|
-
return true;
|
|
2009
|
-
}
|
|
2010
|
-
}
|
|
2011
|
-
return false;
|
|
2012
|
-
}
|
|
2013
|
-
function nextJsonRpcId(prefix, allocate) {
|
|
2014
|
-
return `${prefix}:${allocate()}`;
|
|
2015
|
-
}
|
|
2016
|
-
function writeJsonRpcMessage(child, payload) {
|
|
2017
|
-
if (!child.stdin || child.stdin.destroyed || !child.stdin.writable) {
|
|
2018
|
-
throw new Error("CODEX_APP_SERVER_STDIN_UNAVAILABLE");
|
|
2019
|
-
}
|
|
2020
|
-
child.stdin.write(`${JSON.stringify(payload)}\n`, "utf8");
|
|
2021
|
-
}
|
|
2022
|
-
function sendJsonRpcRequest(child, pendingResponses, createRequestId, input) {
|
|
2023
|
-
const id = createRequestId();
|
|
2024
|
-
return new Promise((resolve, reject) => {
|
|
2025
|
-
const timeout = setTimeout(() => {
|
|
2026
|
-
pendingResponses.delete(id);
|
|
2027
|
-
reject(new Error("SERVER_TIMEOUT"));
|
|
2028
|
-
}, CODEX_APP_SERVER_REQUEST_TIMEOUT_MS);
|
|
2029
|
-
pendingResponses.set(id, {
|
|
2030
|
-
resolve: (value) => {
|
|
2031
|
-
clearTimeout(timeout);
|
|
2032
|
-
resolve(value);
|
|
2033
|
-
},
|
|
2034
|
-
reject: (error) => {
|
|
2035
|
-
clearTimeout(timeout);
|
|
2036
|
-
reject(error);
|
|
2037
|
-
}
|
|
2038
|
-
});
|
|
2039
|
-
try {
|
|
2040
|
-
writeJsonRpcMessage(child, {
|
|
2041
|
-
jsonrpc: "2.0",
|
|
2042
|
-
id,
|
|
2043
|
-
method: input.method,
|
|
2044
|
-
params: input.params
|
|
2045
|
-
});
|
|
2046
|
-
}
|
|
2047
|
-
catch (error) {
|
|
2048
|
-
clearTimeout(timeout);
|
|
2049
|
-
pendingResponses.delete(id);
|
|
2050
|
-
reject(error instanceof Error ? error : new Error("CODEX_APP_SERVER_REQUEST_WRITE_FAILED"));
|
|
2051
|
-
}
|
|
2052
|
-
});
|
|
2053
|
-
}
|
|
2054
|
-
function readJsonRpcParams(parsed) {
|
|
2055
|
-
return toRecord(parsed.params) ?? {};
|
|
2056
|
-
}
|
|
2057
|
-
function readJsonRpcResult(parsed) {
|
|
2058
|
-
return toRecord(parsed.result) ?? {};
|
|
2059
|
-
}
|
|
2060
|
-
function resolveResumeThreadId(providerSessionId, rawStoreRef) {
|
|
2061
|
-
const normalizedProviderSessionId = ensureText(providerSessionId).trim();
|
|
2062
|
-
if (normalizedProviderSessionId.length > 0) {
|
|
2063
|
-
return normalizedProviderSessionId;
|
|
2064
|
-
}
|
|
2065
|
-
const fromRawStore = readThreadIdFromRawStore(rawStoreRef);
|
|
2066
|
-
if (fromRawStore) {
|
|
2067
|
-
return fromRawStore;
|
|
2068
|
-
}
|
|
2069
|
-
return null;
|
|
2070
|
-
}
|
|
2071
|
-
function buildSyntheticResumeHistory(rawStoreRef) {
|
|
2072
|
-
const filePath = ensureText(rawStoreRef).trim();
|
|
2073
|
-
if (!filePath || !existsSync(filePath)) {
|
|
2074
|
-
return [];
|
|
2075
|
-
}
|
|
2076
|
-
const threadId = readThreadIdFromRawStore(filePath);
|
|
2077
|
-
if (!threadId || looksLikeCodexThreadId(threadId)) {
|
|
2078
|
-
return [];
|
|
2079
|
-
}
|
|
2080
|
-
return buildCodexResumeHistoryFromRawStore(filePath);
|
|
2081
|
-
}
|
|
2082
|
-
function shouldFallbackCodexContinueFromHistory(error, history) {
|
|
2083
|
-
if (history.length === 0) {
|
|
2084
|
-
return false;
|
|
2085
|
-
}
|
|
2086
|
-
return isCodexThreadLoadError(error) || isCodexRequestTimeoutError(error);
|
|
2087
|
-
}
|
|
2088
|
-
function isCodexThreadLoadError(error) {
|
|
2089
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
2090
|
-
const normalized = message.trim().toLowerCase();
|
|
2091
|
-
return (normalized.includes("thread not loaded") ||
|
|
2092
|
-
normalized.includes("no rollout found for thread id"));
|
|
2093
|
-
}
|
|
2094
|
-
function isCodexRequestTimeoutError(error) {
|
|
2095
|
-
return error instanceof Error && error.message === "SERVER_TIMEOUT";
|
|
2096
|
-
}
|
|
2097
|
-
function readProp(value, key) {
|
|
2098
|
-
if (!value || typeof value !== "object") {
|
|
2099
|
-
return null;
|
|
2100
|
-
}
|
|
2101
|
-
return value[key];
|
|
2102
|
-
}
|
|
2103
|
-
function toRecord(value) {
|
|
2104
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2105
|
-
return null;
|
|
2106
|
-
}
|
|
2107
|
-
return value;
|
|
2108
|
-
}
|
|
2109
|
-
function ensureText(value) {
|
|
2110
|
-
if (typeof value === "string") {
|
|
2111
|
-
return value;
|
|
2112
|
-
}
|
|
2113
|
-
if (value === undefined || value === null) {
|
|
2114
|
-
return "";
|
|
2115
|
-
}
|
|
2116
|
-
try {
|
|
2117
|
-
return JSON.stringify(value);
|
|
2118
|
-
}
|
|
2119
|
-
catch {
|
|
2120
|
-
return String(value);
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
function normalizeText(value) {
|
|
2124
|
-
const normalized = ensureText(value).trim();
|
|
2125
|
-
return normalized.length > 0 ? normalized : null;
|
|
2126
|
-
}
|
|
2127
|
-
function readThreadIdFromRawStore(rawStoreRef) {
|
|
2128
|
-
const filePath = ensureText(rawStoreRef).trim();
|
|
2129
|
-
if (!filePath || !existsSync(filePath)) {
|
|
2130
|
-
return null;
|
|
2131
|
-
}
|
|
2132
|
-
const firstLine = readFileSync(filePath, "utf8")
|
|
2133
|
-
.split(/\r?\n/, 1)
|
|
2134
|
-
.at(0)
|
|
2135
|
-
?.trim();
|
|
2136
|
-
if (!firstLine) {
|
|
2137
|
-
return null;
|
|
2138
|
-
}
|
|
2139
|
-
try {
|
|
2140
|
-
const record = JSON.parse(firstLine);
|
|
2141
|
-
if (ensureText(record.type).trim() !== "session_meta") {
|
|
2142
|
-
return null;
|
|
2143
|
-
}
|
|
2144
|
-
const threadId = ensureText(record.payload?.id).trim();
|
|
2145
|
-
return threadId.length > 0 ? threadId : null;
|
|
2146
|
-
}
|
|
2147
|
-
catch {
|
|
2148
|
-
return null;
|
|
2149
|
-
}
|
|
2150
|
-
}
|
|
2151
|
-
function looksLikeCodexThreadId(value) {
|
|
2152
|
-
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
2153
|
-
}
|
|
2154
|
-
function readSessionMeta(filePath) {
|
|
2155
|
-
if (!existsSync(filePath)) {
|
|
2156
|
-
return null;
|
|
2157
|
-
}
|
|
2158
|
-
const firstLine = readFileSync(filePath, "utf8")
|
|
2159
|
-
.split(/\r?\n/, 1)
|
|
2160
|
-
.at(0)
|
|
2161
|
-
?.trim();
|
|
2162
|
-
if (!firstLine) {
|
|
2163
|
-
return null;
|
|
2164
|
-
}
|
|
2165
|
-
try {
|
|
2166
|
-
const record = JSON.parse(firstLine);
|
|
2167
|
-
if (ensureText(record.type).trim() !== "session_meta") {
|
|
2168
|
-
return null;
|
|
2169
|
-
}
|
|
2170
|
-
const metaThreadId = ensureText(record.payload?.id).trim();
|
|
2171
|
-
const fileThreadId = basename(filePath, ".jsonl").trim();
|
|
2172
|
-
const threadId = looksLikeCodexThreadId(metaThreadId)
|
|
2173
|
-
? metaThreadId
|
|
2174
|
-
: looksLikeCodexThreadId(fileThreadId)
|
|
2175
|
-
? fileThreadId
|
|
2176
|
-
: metaThreadId;
|
|
2177
|
-
if (!threadId) {
|
|
2178
|
-
return null;
|
|
2179
|
-
}
|
|
2180
|
-
const cwdText = ensureText(record.payload?.cwd).trim();
|
|
2181
|
-
return {
|
|
2182
|
-
threadId,
|
|
2183
|
-
cwd: cwdText.length > 0 ? cwdText : null
|
|
2184
|
-
};
|
|
2185
|
-
}
|
|
2186
|
-
catch {
|
|
2187
|
-
return null;
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
function isSyntheticRawStoreRef(rawStoreRef) {
|
|
2191
|
-
const normalized = rawStoreRef.replaceAll("\\", "/").toLowerCase();
|
|
2192
|
-
return normalized.includes("/runtime/codex/") || normalized.startsWith("runtime/codex/");
|
|
2193
|
-
}
|
|
2194
|
-
function walkJsonlFiles(rootDir) {
|
|
2195
|
-
if (!existsSync(rootDir)) {
|
|
2196
|
-
return [];
|
|
2197
|
-
}
|
|
2198
|
-
const queue = [rootDir];
|
|
2199
|
-
const files = [];
|
|
2200
|
-
while (queue.length > 0) {
|
|
2201
|
-
const current = queue.shift();
|
|
2202
|
-
if (!current) {
|
|
2203
|
-
continue;
|
|
2204
|
-
}
|
|
2205
|
-
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
2206
|
-
const fullPath = join(current, entry.name);
|
|
2207
|
-
if (entry.isDirectory()) {
|
|
2208
|
-
queue.push(fullPath);
|
|
2209
|
-
continue;
|
|
2210
|
-
}
|
|
2211
|
-
if (entry.isFile() && basename(fullPath).endsWith(".jsonl")) {
|
|
2212
|
-
files.push(fullPath);
|
|
2213
|
-
}
|
|
2214
|
-
}
|
|
2215
|
-
}
|
|
2216
|
-
return files;
|
|
2217
|
-
}
|
|
2218
|
-
function sleep(ms) {
|
|
2219
|
-
return new Promise((resolve) => {
|
|
2220
|
-
setTimeout(resolve, ms);
|
|
2221
|
-
});
|
|
2222
|
-
}
|
|
2223
|
-
function findLatestCodexStateDatabase(homeDir) {
|
|
2224
|
-
if (!existsSync(homeDir)) {
|
|
2225
|
-
return null;
|
|
2226
|
-
}
|
|
2227
|
-
const candidates = readdirSync(homeDir, { withFileTypes: true })
|
|
2228
|
-
.filter((entry) => entry.isFile() && /^state_\d+\.sqlite$/i.test(entry.name))
|
|
2229
|
-
.map((entry) => {
|
|
2230
|
-
const filePath = join(homeDir, entry.name);
|
|
2231
|
-
return {
|
|
2232
|
-
filePath,
|
|
2233
|
-
mtimeMs: statSync(filePath).mtimeMs
|
|
2234
|
-
};
|
|
2235
|
-
})
|
|
2236
|
-
.sort((left, right) => right.mtimeMs - left.mtimeMs);
|
|
2237
|
-
return candidates[0]?.filePath ?? null;
|
|
2238
|
-
}
|
|
2239
|
-
function pickTimestamp(...candidates) {
|
|
2240
|
-
for (const candidate of candidates) {
|
|
2241
|
-
const raw = ensureText(readProp(candidate, "timestamp")).trim();
|
|
2242
|
-
if (raw.length > 0) {
|
|
2243
|
-
return raw;
|
|
2244
|
-
}
|
|
2245
|
-
}
|
|
2246
|
-
return nextTimestamp();
|
|
2247
|
-
}
|
|
2248
|
-
function pickFirstNonEmpty(...values) {
|
|
2249
|
-
for (const value of values) {
|
|
2250
|
-
if (value.trim().length > 0) {
|
|
2251
|
-
return value.trim();
|
|
2252
|
-
}
|
|
2253
|
-
}
|
|
2254
|
-
return "";
|
|
2255
|
-
}
|
|
2256
|
-
function isToolItem(itemType) {
|
|
2257
|
-
return (itemType === "command_execution" ||
|
|
2258
|
-
itemType === "file_change" ||
|
|
2259
|
-
itemType === "mcp_tool_call" ||
|
|
2260
|
-
itemType === "function_call" ||
|
|
2261
|
-
itemType === "custom_tool_call" ||
|
|
2262
|
-
itemType === "commandExecution" ||
|
|
2263
|
-
itemType === "fileChange" ||
|
|
2264
|
-
itemType === "mcpToolCall" ||
|
|
2265
|
-
itemType === "dynamicToolCall");
|
|
2266
|
-
}
|
|
2267
|
-
function inferToolSuccess(item, output) {
|
|
2268
|
-
const status = ensureText(readProp(item, "status")).trim().toLowerCase();
|
|
2269
|
-
if (status === "failed" || status === "error") {
|
|
2270
|
-
return false;
|
|
2271
|
-
}
|
|
2272
|
-
const lowered = output.toLowerCase();
|
|
2273
|
-
if (lowered.includes("apply_patch was requested via exec_command")) {
|
|
2274
|
-
return false;
|
|
2275
|
-
}
|
|
2276
|
-
if (status === "completed" || status === "success" || status === "succeeded") {
|
|
2277
|
-
return true;
|
|
2278
|
-
}
|
|
2279
|
-
const exitCode = readProp(item, "exit_code");
|
|
2280
|
-
if (typeof exitCode === "number") {
|
|
2281
|
-
return exitCode === 0;
|
|
2282
|
-
}
|
|
2283
|
-
if (lowered.includes("error")) {
|
|
2284
|
-
return false;
|
|
2285
|
-
}
|
|
2286
|
-
return true;
|
|
2287
|
-
}
|
|
2288
|
-
function classifyCodexRuntimeFailure(error) {
|
|
2289
|
-
const detail = error instanceof Error ? error.message : "codex runtime error";
|
|
2290
|
-
if (detail.includes("PROVIDER_SESSION_ID_REQUIRED")) {
|
|
2291
|
-
return {
|
|
2292
|
-
errorCode: "CODEX_PROVIDER_SESSION_ID_REQUIRED",
|
|
2293
|
-
detail
|
|
2294
|
-
};
|
|
2295
|
-
}
|
|
2296
|
-
if (detail.includes("Cannot find package") || detail.includes("ERR_MODULE_NOT_FOUND")) {
|
|
2297
|
-
return {
|
|
2298
|
-
errorCode: "CODEX_RUNTIME_SDK_MISSING",
|
|
2299
|
-
detail
|
|
2300
|
-
};
|
|
2301
|
-
}
|
|
2302
|
-
if (detail.includes("ENOENT") || detail.includes("spawn")) {
|
|
2303
|
-
return {
|
|
2304
|
-
errorCode: "CODEX_CLI_LAUNCH_FAILED",
|
|
2305
|
-
detail
|
|
2306
|
-
};
|
|
2307
|
-
}
|
|
2308
|
-
return {
|
|
2309
|
-
errorCode: classifyCodexDetailErrorCode(detail, "CODEX_RUNTIME_ERROR"),
|
|
2310
|
-
detail
|
|
2311
|
-
};
|
|
2312
|
-
}
|
|
2313
|
-
function classifyCodexDetailErrorCode(detail, fallback) {
|
|
2314
|
-
const normalized = detail.trim();
|
|
2315
|
-
if (!normalized) {
|
|
2316
|
-
return fallback;
|
|
2317
|
-
}
|
|
2318
|
-
const statusMatch = normalized.match(/\bstatus\s+(\d{3})\b/i)
|
|
2319
|
-
?? normalized.match(/\bHTTP\s+(\d{3})\b/i)
|
|
2320
|
-
?? normalized.match(/\b(\d{3})\s+(?:Bad Gateway|Too Many Requests|Gateway Timeout|Service Unavailable)\b/i);
|
|
2321
|
-
if (!statusMatch) {
|
|
2322
|
-
return fallback;
|
|
2323
|
-
}
|
|
2324
|
-
return `CODEX_HTTP_${statusMatch[1]}`;
|
|
2325
|
-
}
|
|
2326
|
-
function persistSyntheticUserMessageIfNeeded(rawStoreRef, providerSessionId, input) {
|
|
2327
|
-
if (!isSyntheticRawStoreRef(rawStoreRef) || input.content.trim().length === 0) {
|
|
2328
|
-
return;
|
|
2329
|
-
}
|
|
2330
|
-
ensureSyntheticRuntimeFile(rawStoreRef, providerSessionId, input.workspacePath, input.timestamp);
|
|
2331
|
-
appendJsonLine(rawStoreRef, {
|
|
2332
|
-
timestamp: input.timestamp,
|
|
2333
|
-
type: "event_msg",
|
|
2334
|
-
payload: {
|
|
2335
|
-
type: "user_message",
|
|
2336
|
-
message: input.content
|
|
2337
|
-
}
|
|
2338
|
-
});
|
|
2339
|
-
}
|
|
2340
|
-
function persistSyntheticEventIfNeeded(rawStoreRef, providerSessionId, event) {
|
|
2341
|
-
if (!isSyntheticRawStoreRef(rawStoreRef)) {
|
|
2342
|
-
return;
|
|
2343
|
-
}
|
|
2344
|
-
const serialized = toSyntheticRuntimeRecord(event, providerSessionId);
|
|
2345
|
-
if (!serialized) {
|
|
2346
|
-
return;
|
|
2347
|
-
}
|
|
2348
|
-
ensureSyntheticRuntimeFile(rawStoreRef, providerSessionId, null, serialized.timestamp);
|
|
2349
|
-
appendJsonLine(rawStoreRef, serialized.record);
|
|
2350
|
-
}
|
|
2351
|
-
function ensureSyntheticRuntimeFile(rawStoreRef, providerSessionId, workspacePath, timestamp) {
|
|
2352
|
-
if (existsSync(rawStoreRef)) {
|
|
2353
|
-
return;
|
|
2354
|
-
}
|
|
2355
|
-
ensureDirectory(dirname(rawStoreRef));
|
|
2356
|
-
appendJsonLine(rawStoreRef, {
|
|
2357
|
-
timestamp,
|
|
2358
|
-
type: "session_meta",
|
|
2359
|
-
payload: {
|
|
2360
|
-
id: providerSessionId,
|
|
2361
|
-
timestamp,
|
|
2362
|
-
cwd: workspacePath ?? "",
|
|
2363
|
-
originator: "CodingNS Runtime",
|
|
2364
|
-
source: "codingns-runtime"
|
|
2365
|
-
}
|
|
2366
|
-
});
|
|
2367
|
-
}
|
|
2368
|
-
function toSyntheticRuntimeRecord(event, providerSessionId) {
|
|
2369
|
-
const eventType = ensureText(readProp(event, "type")).trim();
|
|
2370
|
-
const timestamp = pickTimestamp(event);
|
|
2371
|
-
if (eventType === "turn.completed") {
|
|
2372
|
-
return {
|
|
2373
|
-
timestamp,
|
|
2374
|
-
record: {
|
|
2375
|
-
timestamp,
|
|
2376
|
-
type: "event_msg",
|
|
2377
|
-
payload: {
|
|
2378
|
-
type: "task_complete"
|
|
2379
|
-
}
|
|
2380
|
-
}
|
|
2381
|
-
};
|
|
2382
|
-
}
|
|
2383
|
-
if (eventType === "turn.failed") {
|
|
2384
|
-
return {
|
|
2385
|
-
timestamp,
|
|
2386
|
-
record: {
|
|
2387
|
-
timestamp,
|
|
2388
|
-
type: "event_msg",
|
|
2389
|
-
payload: {
|
|
2390
|
-
type: "task_failed",
|
|
2391
|
-
error: extractTextBlocks(readProp(event, "error")).trim()
|
|
2392
|
-
}
|
|
2393
|
-
}
|
|
2394
|
-
};
|
|
2395
|
-
}
|
|
2396
|
-
if (!eventType.startsWith("item.")) {
|
|
2397
|
-
return null;
|
|
2398
|
-
}
|
|
2399
|
-
const item = readProp(event, "item");
|
|
2400
|
-
const itemType = ensureText(readProp(item, "type")).trim();
|
|
2401
|
-
if (itemType.length === 0) {
|
|
2402
|
-
return null;
|
|
2403
|
-
}
|
|
2404
|
-
if (itemType === "agent_message" && eventType === "item.completed") {
|
|
2405
|
-
const content = pickFirstNonEmpty(ensureText(readProp(item, "text")).trim(), extractTextBlocks(readProp(item, "content")).trim());
|
|
2406
|
-
if (content.length === 0) {
|
|
2407
|
-
return null;
|
|
2408
|
-
}
|
|
2409
|
-
return {
|
|
2410
|
-
timestamp,
|
|
2411
|
-
record: {
|
|
2412
|
-
timestamp,
|
|
2413
|
-
type: "event_msg",
|
|
2414
|
-
payload: {
|
|
2415
|
-
type: "agent_message",
|
|
2416
|
-
id: ensureText(readProp(item, "id")).trim() || undefined,
|
|
2417
|
-
message: content
|
|
2418
|
-
}
|
|
2419
|
-
}
|
|
2420
|
-
};
|
|
2421
|
-
}
|
|
2422
|
-
if (itemType === "reasoning" && eventType === "item.completed") {
|
|
2423
|
-
const content = pickFirstNonEmpty(ensureText(readProp(item, "text")).trim(), extractTextBlocks(readProp(item, "summary")).trim(), extractTextBlocks(readProp(item, "content")).trim());
|
|
2424
|
-
if (content.length === 0) {
|
|
2425
|
-
return null;
|
|
2426
|
-
}
|
|
2427
|
-
return {
|
|
2428
|
-
timestamp,
|
|
2429
|
-
record: {
|
|
2430
|
-
timestamp,
|
|
2431
|
-
type: "event_msg",
|
|
2432
|
-
payload: {
|
|
2433
|
-
type: "agent_reasoning",
|
|
2434
|
-
id: ensureText(readProp(item, "id")).trim() || undefined,
|
|
2435
|
-
text: content
|
|
2436
|
-
}
|
|
2437
|
-
}
|
|
2438
|
-
};
|
|
2439
|
-
}
|
|
2440
|
-
if (!isToolItem(itemType)) {
|
|
2441
|
-
return null;
|
|
2442
|
-
}
|
|
2443
|
-
const callId = pickFirstNonEmpty(ensureText(readProp(item, "id")).trim(), ensureText(readProp(item, "call_id")).trim(), `${itemType}-${providerSessionId}`);
|
|
2444
|
-
const name = pickFirstNonEmpty(ensureText(readProp(item, "name")).trim(), ensureText(readProp(item, "tool")).trim(), itemType);
|
|
2445
|
-
if (eventType === "item.started") {
|
|
2446
|
-
const input = resolveCodexToolInput(name, item);
|
|
2447
|
-
return {
|
|
2448
|
-
timestamp,
|
|
2449
|
-
record: {
|
|
2450
|
-
timestamp,
|
|
2451
|
-
type: "response_item",
|
|
2452
|
-
payload: {
|
|
2453
|
-
type: mapToolStartItemType(itemType),
|
|
2454
|
-
call_id: callId,
|
|
2455
|
-
name,
|
|
2456
|
-
arguments: input,
|
|
2457
|
-
input
|
|
2458
|
-
}
|
|
2459
|
-
}
|
|
2460
|
-
};
|
|
2461
|
-
}
|
|
2462
|
-
if (eventType !== "item.completed") {
|
|
2463
|
-
return null;
|
|
2464
|
-
}
|
|
2465
|
-
const output = pickFirstNonEmpty(extractTextBlocks(readProp(item, "result")).trim(), extractTextBlocks(readProp(item, "output")).trim(), extractTextBlocks(readProp(item, "aggregated_output")).trim(), extractTextBlocks(readProp(item, "error")).trim());
|
|
2466
|
-
return {
|
|
2467
|
-
timestamp,
|
|
2468
|
-
record: {
|
|
2469
|
-
timestamp,
|
|
2470
|
-
type: "response_item",
|
|
2471
|
-
payload: {
|
|
2472
|
-
type: mapToolResultItemType(itemType),
|
|
2473
|
-
call_id: callId,
|
|
2474
|
-
name,
|
|
2475
|
-
output,
|
|
2476
|
-
status: inferToolSuccess(item, output) ? "completed" : "failed"
|
|
2477
|
-
}
|
|
2478
|
-
}
|
|
2479
|
-
};
|
|
2480
|
-
}
|
|
2481
|
-
function mapToolStartItemType(itemType) {
|
|
2482
|
-
return itemType === "custom_tool_call" ? "custom_tool_call" : "function_call";
|
|
2483
|
-
}
|
|
2484
|
-
function mapToolResultItemType(itemType) {
|
|
2485
|
-
return itemType === "custom_tool_call" ? "custom_tool_call_output" : "function_call_output";
|
|
2486
|
-
}
|
|
2487
|
-
function buildCodexStableMessageKey(providerSessionId, stableIdentity) {
|
|
2488
|
-
return `codex:${providerSessionId}:${stableIdentity}`;
|
|
2489
|
-
}
|
|
2490
|
-
function normalizeCodexItemStatus(value) {
|
|
2491
|
-
const normalized = ensureText(value).trim();
|
|
2492
|
-
if (!normalized) {
|
|
2493
|
-
return "in_progress";
|
|
2494
|
-
}
|
|
2495
|
-
if (normalized === "inProgress") {
|
|
2496
|
-
return "running";
|
|
2497
|
-
}
|
|
2498
|
-
if (normalized === "declined") {
|
|
2499
|
-
return "failed";
|
|
2500
|
-
}
|
|
2501
|
-
return normalized;
|
|
2502
|
-
}
|
|
2503
|
-
function buildCodexFileChangeOutput(value) {
|
|
2504
|
-
if (!Array.isArray(value)) {
|
|
2505
|
-
return "";
|
|
2506
|
-
}
|
|
2507
|
-
const structuredPatch = buildApplyPatchFromFileChangeList(value.map((change) => {
|
|
2508
|
-
const record = toRecord(change);
|
|
2509
|
-
return {
|
|
2510
|
-
path: ensureText(record?.path).trim() || null,
|
|
2511
|
-
kind: ensureText(record?.kind).trim() || null
|
|
2512
|
-
};
|
|
2513
|
-
}));
|
|
2514
|
-
if (structuredPatch) {
|
|
2515
|
-
return structuredPatch;
|
|
2516
|
-
}
|
|
2517
|
-
return value
|
|
2518
|
-
.map((change) => {
|
|
2519
|
-
const record = toRecord(change);
|
|
2520
|
-
if (!record) {
|
|
2521
|
-
return "";
|
|
2522
|
-
}
|
|
2523
|
-
const diff = ensureText(record.diff).trim();
|
|
2524
|
-
if (diff.length > 0) {
|
|
2525
|
-
return diff;
|
|
2526
|
-
}
|
|
2527
|
-
const path = ensureText(record.path).trim();
|
|
2528
|
-
return path.length > 0 ? `Updated ${path}` : "";
|
|
2529
|
-
})
|
|
2530
|
-
.filter((entry) => entry.length > 0)
|
|
2531
|
-
.join("\n\n");
|
|
2532
|
-
}
|
|
2533
|
-
function isCodexExecCommandToolName(value) {
|
|
2534
|
-
const normalized = value.trim().toLowerCase();
|
|
2535
|
-
return (normalized === "exec_command" ||
|
|
2536
|
-
normalized === "shell_command" ||
|
|
2537
|
-
normalized === "command_execution");
|
|
2538
|
-
}
|
|
2539
|
-
function extractApplyPatchTextFromCommandLikeValues(value) {
|
|
2540
|
-
return buildApplyPatchFromCodexCommandLikeValue(value);
|
|
2541
|
-
}
|
|
2542
|
-
function resolveCodexToolInput(name, item) {
|
|
2543
|
-
const rawInput = pickFirstNonEmpty(extractTextBlocks(readProp(item, "arguments")).trim(), extractTextBlocks(readProp(item, "input")).trim(), extractTextBlocks(readProp(item, "command")).trim());
|
|
2544
|
-
if (name.trim().toLowerCase() !== "apply_patch") {
|
|
2545
|
-
return rawInput;
|
|
2546
|
-
}
|
|
2547
|
-
return (normalizeApplyPatchText(rawInput, {
|
|
2548
|
-
fallbackPaths: collectCodexApplyPatchFallbackPaths(item)
|
|
2549
|
-
}) ?? rawInput);
|
|
2550
|
-
}
|
|
2551
|
-
function collectCodexApplyPatchFallbackPaths(item) {
|
|
2552
|
-
const directPaths = [
|
|
2553
|
-
ensureText(readProp(item, "path")).trim(),
|
|
2554
|
-
ensureText(readProp(item, "filePath")).trim(),
|
|
2555
|
-
ensureText(readProp(item, "file_path")).trim()
|
|
2556
|
-
].filter((value) => value.length > 0);
|
|
2557
|
-
const rawChanges = readProp(item, "changes");
|
|
2558
|
-
const changes = Array.isArray(rawChanges) ? rawChanges : [];
|
|
2559
|
-
const changePaths = changes
|
|
2560
|
-
.map((change) => ensureText(readProp(change, "path")).trim())
|
|
2561
|
-
.filter((value) => value.length > 0);
|
|
2562
|
-
const outputText = pickFirstNonEmpty(extractTextBlocks(readProp(item, "result")).trim(), extractTextBlocks(readProp(item, "output")).trim(), extractTextBlocks(readProp(item, "aggregated_output")).trim(), extractTextBlocks(readProp(item, "error")).trim());
|
|
2563
|
-
return [
|
|
2564
|
-
...new Set([
|
|
2565
|
-
...directPaths,
|
|
2566
|
-
...changePaths,
|
|
2567
|
-
...extractApplyPatchTargetPathsFromToolOutput(outputText)
|
|
2568
|
-
])
|
|
2569
|
-
];
|
|
2570
|
-
}
|
|
2571
|
-
//# sourceMappingURL=codex-runtime.js.map
|