@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,1480 +0,0 @@
|
|
|
1
|
-
import { execFile as nodeExecFile } from "node:child_process";
|
|
2
|
-
import { accessSync, constants, existsSync, readdirSync, readFileSync, rmSync, statSync } from "node:fs";
|
|
3
|
-
import { basename, delimiter, dirname, extname, join } from "node:path";
|
|
4
|
-
import { promisify } from "node:util";
|
|
5
|
-
import { buildApplyPatchFromStructuredFileTool } from "../patch-builder.js";
|
|
6
|
-
import { ensureText, extractTextBlocks, messageIdFromRawRef, nextTimestamp, normalizeWorkspacePath, sliceHistory, stringifyStructuredValue } from "./utils.js";
|
|
7
|
-
const execFile = promisify(nodeExecFile);
|
|
8
|
-
const GEMINI_RAW_STORE_PREFIX = "gemini://session/";
|
|
9
|
-
const DEFAULT_GEMINI_TITLE_LENGTH = 48;
|
|
10
|
-
export class GeminiAdapter {
|
|
11
|
-
options;
|
|
12
|
-
providerId = "gemini";
|
|
13
|
-
parsedChatCache = new Map();
|
|
14
|
-
localSessionCache = new Map();
|
|
15
|
-
constructor(options) {
|
|
16
|
-
this.options = options;
|
|
17
|
-
}
|
|
18
|
-
async detectSessions(workspacePath, options) {
|
|
19
|
-
const discovery = await this.detectSessionsDetailed(workspacePath, options);
|
|
20
|
-
return discovery.sessions;
|
|
21
|
-
}
|
|
22
|
-
async detectSessionsDetailed(workspacePath, options) {
|
|
23
|
-
const startedAt = Date.now();
|
|
24
|
-
const targetPath = normalizeWorkspacePath(workspacePath);
|
|
25
|
-
const knownSessions = (options?.knownSessions ?? []).filter((session) => session.provider === this.providerId);
|
|
26
|
-
const knownByProviderSessionId = new Map(knownSessions.map((session) => [session.providerSessionId, session]));
|
|
27
|
-
const localScan = this.readLocalSessionsDetailed();
|
|
28
|
-
const localSessions = localScan.sessions;
|
|
29
|
-
const cliResult = await this.readCliSessions(workspacePath);
|
|
30
|
-
const mergedByProviderSessionId = new Map();
|
|
31
|
-
for (const localSession of localSessions) {
|
|
32
|
-
const known = knownByProviderSessionId.get(localSession.providerSessionId);
|
|
33
|
-
const resolvedWorkspacePath = localSession.workspacePath || ensureNonEmptyText(known?.workspacePath);
|
|
34
|
-
if (!this.matchesWorkspace(resolvedWorkspacePath, targetPath)) {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
mergedByProviderSessionId.set(localSession.providerSessionId, {
|
|
38
|
-
provider: this.providerId,
|
|
39
|
-
providerSessionId: localSession.providerSessionId,
|
|
40
|
-
title: localSession.title,
|
|
41
|
-
workspacePath: resolvedWorkspacePath || workspacePath,
|
|
42
|
-
rawStoreRef: buildGeminiRawStoreRef(localSession.providerSessionId),
|
|
43
|
-
lastMessageAt: localSession.lastMessageAt ?? known?.lastMessageAt ?? null,
|
|
44
|
-
messageCount: localSession.messageCount,
|
|
45
|
-
sourceMtimeMs: localSession.sourceMtimeMs,
|
|
46
|
-
sourceSizeBytes: localSession.sourceSizeBytes
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
for (const cliSession of cliResult.sessions) {
|
|
50
|
-
const known = knownByProviderSessionId.get(cliSession.providerSessionId);
|
|
51
|
-
const local = mergedByProviderSessionId.get(cliSession.providerSessionId);
|
|
52
|
-
const resolvedWorkspacePath = cliSession.workspacePath ||
|
|
53
|
-
local?.workspacePath ||
|
|
54
|
-
ensureNonEmptyText(known?.workspacePath);
|
|
55
|
-
if (!this.matchesWorkspace(resolvedWorkspacePath, targetPath)) {
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
mergedByProviderSessionId.set(cliSession.providerSessionId, {
|
|
59
|
-
provider: this.providerId,
|
|
60
|
-
providerSessionId: cliSession.providerSessionId,
|
|
61
|
-
title: local?.title ||
|
|
62
|
-
cliSession.title ||
|
|
63
|
-
known?.title ||
|
|
64
|
-
cliSession.providerSessionId,
|
|
65
|
-
workspacePath: resolvedWorkspacePath || workspacePath,
|
|
66
|
-
rawStoreRef: buildGeminiRawStoreRef(cliSession.providerSessionId),
|
|
67
|
-
lastMessageAt: local?.lastMessageAt ??
|
|
68
|
-
cliSession.lastMessageAt ??
|
|
69
|
-
known?.lastMessageAt ??
|
|
70
|
-
null,
|
|
71
|
-
messageCount: local?.messageCount ??
|
|
72
|
-
cliSession.messageCount ??
|
|
73
|
-
known?.messageCount ??
|
|
74
|
-
0,
|
|
75
|
-
sourceMtimeMs: local?.sourceMtimeMs ?? known?.sourceMtimeMs,
|
|
76
|
-
sourceSizeBytes: local?.sourceSizeBytes ?? known?.sourceSizeBytes
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
// 当 CLI 临时失败时,用 knownSessions 补回最近一次已发现的会话,避免列表突然丢失。
|
|
80
|
-
if (!cliResult.isComplete) {
|
|
81
|
-
for (const known of knownSessions) {
|
|
82
|
-
if (mergedByProviderSessionId.has(known.providerSessionId)) {
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
if (!this.matchesWorkspace(known.workspacePath, targetPath)) {
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
mergedByProviderSessionId.set(known.providerSessionId, known);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
const diagnostic = {
|
|
92
|
-
provider: this.providerId,
|
|
93
|
-
status: cliResult.isComplete ? "success" : "partial",
|
|
94
|
-
durationMs: Date.now() - startedAt,
|
|
95
|
-
sessionCount: mergedByProviderSessionId.size,
|
|
96
|
-
isComplete: cliResult.isComplete,
|
|
97
|
-
errorMessage: null,
|
|
98
|
-
scannedFiles: localScan.scannedFiles,
|
|
99
|
-
skippedByMtimeSize: localScan.skippedByMtimeSize,
|
|
100
|
-
parsedFiles: localScan.parsedFiles,
|
|
101
|
-
bytesRead: localScan.bytesRead
|
|
102
|
-
};
|
|
103
|
-
return {
|
|
104
|
-
sessions: [...mergedByProviderSessionId.values()].sort((left, right) => (right.lastMessageAt ?? "").localeCompare(left.lastMessageAt ?? "")),
|
|
105
|
-
isComplete: cliResult.isComplete,
|
|
106
|
-
providerDiagnostics: [diagnostic]
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
async readSessionHistory(providerSessionId, rawStoreRef, cursor, limit, direction = "forward") {
|
|
110
|
-
const resolvedProviderSessionId = this.resolveProviderSessionId(providerSessionId, rawStoreRef);
|
|
111
|
-
const parsedChat = this.readParsedChatBySessionId(resolvedProviderSessionId, resolveGeminiScopedHomeDir(rawStoreRef));
|
|
112
|
-
return sliceHistory(parsedChat.messages, cursor, limit, direction);
|
|
113
|
-
}
|
|
114
|
-
subscribeSession(providerSessionId, rawStoreRef, cursor, limit, onEvent) {
|
|
115
|
-
const sessionRef = this.resolveSessionRef(providerSessionId, rawStoreRef);
|
|
116
|
-
let currentCursor = cursor;
|
|
117
|
-
let lastSeenSignature = "";
|
|
118
|
-
let closed = false;
|
|
119
|
-
const timer = setInterval(() => {
|
|
120
|
-
if (closed || !sessionRef.providerSessionId) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
let page;
|
|
124
|
-
try {
|
|
125
|
-
page = this.readSessionHistorySync(sessionRef.providerSessionId, rawStoreRef, currentCursor, limit);
|
|
126
|
-
}
|
|
127
|
-
catch {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
if (page.messages.length === 0) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
const signature = `${page.messages.at(-1)?.messageId ?? ""}:${page.cursor ?? ""}`;
|
|
134
|
-
if (signature === lastSeenSignature) {
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
lastSeenSignature = signature;
|
|
138
|
-
currentCursor = page.cursor;
|
|
139
|
-
void onEvent({
|
|
140
|
-
messages: page.messages,
|
|
141
|
-
cursor: page.cursor
|
|
142
|
-
});
|
|
143
|
-
}, 700);
|
|
144
|
-
return {
|
|
145
|
-
close() {
|
|
146
|
-
closed = true;
|
|
147
|
-
clearInterval(timer);
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
async resumeSession(providerSessionId, rawStoreRef) {
|
|
152
|
-
const resolvedProviderSessionId = this.resolveProviderSessionId(providerSessionId, rawStoreRef);
|
|
153
|
-
this.readParsedChatBySessionId(resolvedProviderSessionId, resolveGeminiScopedHomeDir(rawStoreRef));
|
|
154
|
-
return {
|
|
155
|
-
provider: this.providerId,
|
|
156
|
-
providerSessionId: resolvedProviderSessionId,
|
|
157
|
-
resumedAt: nextTimestamp(),
|
|
158
|
-
rawStoreRef: buildGeminiRawStoreRef(resolvedProviderSessionId, resolveGeminiScopedHomeDir(rawStoreRef))
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
async startSession(_workspacePath, _options) {
|
|
162
|
-
throw new Error("GEMINI_READ_ONLY_PROVIDER");
|
|
163
|
-
}
|
|
164
|
-
async sendMessage(_providerSessionId, _rawStoreRef, _content, _clientRequestId, _permissionMode) {
|
|
165
|
-
throw new Error("GEMINI_READ_ONLY_PROVIDER");
|
|
166
|
-
}
|
|
167
|
-
async readSessionTitle(providerSessionId, rawStoreRef) {
|
|
168
|
-
const resolvedProviderSessionId = this.resolveProviderSessionId(providerSessionId, rawStoreRef);
|
|
169
|
-
const parsedChat = this.readParsedChatBySessionId(resolvedProviderSessionId, resolveGeminiScopedHomeDir(rawStoreRef));
|
|
170
|
-
return parsedChat.title;
|
|
171
|
-
}
|
|
172
|
-
async renameSessionTitle(_providerSessionId, _rawStoreRef, _title) {
|
|
173
|
-
throw new Error("GEMINI_READ_ONLY_PROVIDER");
|
|
174
|
-
}
|
|
175
|
-
async updateSessionArchiveState(_providerSessionId, _rawStoreRef, _isArchived) {
|
|
176
|
-
throw new Error("GEMINI_ARCHIVE_NOT_SUPPORTED");
|
|
177
|
-
}
|
|
178
|
-
async deleteSession(providerSessionId, rawStoreRef) {
|
|
179
|
-
const resolvedProviderSessionId = this.resolveProviderSessionId(providerSessionId, rawStoreRef);
|
|
180
|
-
const matchedFilePaths = this.findLocalChatFilePathsBySessionId(resolvedProviderSessionId, resolveGeminiScopedHomeDir(rawStoreRef));
|
|
181
|
-
let deletedAny = false;
|
|
182
|
-
for (const filePath of matchedFilePaths) {
|
|
183
|
-
if (!existsSync(filePath)) {
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
rmSync(filePath, { force: true });
|
|
187
|
-
this.parsedChatCache.delete(filePath);
|
|
188
|
-
this.localSessionCache.delete(filePath);
|
|
189
|
-
deletedAny = true;
|
|
190
|
-
}
|
|
191
|
-
if (!deletedAny) {
|
|
192
|
-
throw new Error("PROVIDER_SESSION_NOT_FOUND");
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
getProviderCapabilities() {
|
|
196
|
-
return {
|
|
197
|
-
provider: this.providerId,
|
|
198
|
-
canStartSession: true,
|
|
199
|
-
canResumeSession: true,
|
|
200
|
-
canSendMessage: true,
|
|
201
|
-
inRunInputMode: "none",
|
|
202
|
-
supportsSubagents: false,
|
|
203
|
-
supportsInterrupt: true,
|
|
204
|
-
supportsStructuredToolCalls: true,
|
|
205
|
-
supportsTokenUsage: false,
|
|
206
|
-
supportsAttachments: false,
|
|
207
|
-
supportsPermissionPrompt: false,
|
|
208
|
-
supportsCheckpoint: false,
|
|
209
|
-
supportsSessionDelete: true,
|
|
210
|
-
limitations: [
|
|
211
|
-
"当前 Gemini 仅接入会话发现与历史只读能力,运行时链路尚未启用",
|
|
212
|
-
"本地 chats schema 属于非稳定公开协议,升级 CLI 后需要通过 fixture 回归"
|
|
213
|
-
]
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
async getSessionCapabilities(_providerSessionId) {
|
|
217
|
-
return this.getProviderCapabilities();
|
|
218
|
-
}
|
|
219
|
-
readSessionHistorySync(providerSessionId, rawStoreRef, cursor, limit, direction = "forward") {
|
|
220
|
-
const resolvedProviderSessionId = this.resolveProviderSessionId(providerSessionId, rawStoreRef);
|
|
221
|
-
const parsedChat = this.readParsedChatBySessionId(resolvedProviderSessionId, resolveGeminiScopedHomeDir(rawStoreRef));
|
|
222
|
-
return sliceHistory(parsedChat.messages, cursor, limit, direction);
|
|
223
|
-
}
|
|
224
|
-
resolveProviderSessionId(providerSessionId, rawStoreRef) {
|
|
225
|
-
const sessionRef = this.resolveSessionRef(providerSessionId, rawStoreRef);
|
|
226
|
-
if (!sessionRef.providerSessionId) {
|
|
227
|
-
throw new Error("PROVIDER_SESSION_ID_REQUIRED");
|
|
228
|
-
}
|
|
229
|
-
return sessionRef.providerSessionId;
|
|
230
|
-
}
|
|
231
|
-
resolveSessionRef(providerSessionId, rawStoreRef) {
|
|
232
|
-
const trimmedProviderSessionId = providerSessionId.trim();
|
|
233
|
-
if (trimmedProviderSessionId) {
|
|
234
|
-
return {
|
|
235
|
-
providerSessionId: trimmedProviderSessionId,
|
|
236
|
-
homeDir: resolveGeminiScopedHomeDir(rawStoreRef),
|
|
237
|
-
fromRawStoreRef: false
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
return {
|
|
241
|
-
providerSessionId: parseGeminiRawStoreRef(rawStoreRef),
|
|
242
|
-
homeDir: resolveGeminiScopedHomeDir(rawStoreRef),
|
|
243
|
-
fromRawStoreRef: true
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
async readCliSessions(workspacePath) {
|
|
247
|
-
if (this.options.listSessions) {
|
|
248
|
-
try {
|
|
249
|
-
return {
|
|
250
|
-
sessions: await this.options.listSessions(),
|
|
251
|
-
isComplete: true
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
catch {
|
|
255
|
-
return {
|
|
256
|
-
sessions: [],
|
|
257
|
-
isComplete: false
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
const commandPath = this.options.commandPath?.trim() || "gemini";
|
|
262
|
-
// CLI 没装是正常场景,直接回退到本地 chats 扫描,不要把整个工作区打成 partial。
|
|
263
|
-
if (!isCommandAvailable(commandPath)) {
|
|
264
|
-
return {
|
|
265
|
-
sessions: [],
|
|
266
|
-
isComplete: true
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
try {
|
|
270
|
-
const sessions = await this.readCliSessionsFromCommand(workspacePath);
|
|
271
|
-
return {
|
|
272
|
-
sessions,
|
|
273
|
-
isComplete: true
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
catch {
|
|
277
|
-
return {
|
|
278
|
-
sessions: [],
|
|
279
|
-
isComplete: false
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
async readCliSessionsFromCommand(workspacePath) {
|
|
284
|
-
const commandPath = this.options.commandPath?.trim() || "gemini";
|
|
285
|
-
const env = {
|
|
286
|
-
...process.env,
|
|
287
|
-
GEMINI_HOME: this.options.homeDir
|
|
288
|
-
};
|
|
289
|
-
const attempts = [
|
|
290
|
-
["--list-sessions", "--output-format", "json"],
|
|
291
|
-
["--list-sessions"]
|
|
292
|
-
];
|
|
293
|
-
let lastError = null;
|
|
294
|
-
for (const args of attempts) {
|
|
295
|
-
try {
|
|
296
|
-
const result = await execFile(commandPath, args, {
|
|
297
|
-
env,
|
|
298
|
-
cwd: workspacePath,
|
|
299
|
-
timeout: 8_000,
|
|
300
|
-
windowsHide: true,
|
|
301
|
-
shell: shouldUseShellForCommand(commandPath)
|
|
302
|
-
});
|
|
303
|
-
return parseGeminiCliSessionOutput(result.stdout, workspacePath);
|
|
304
|
-
}
|
|
305
|
-
catch (error) {
|
|
306
|
-
lastError = error;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
throw lastError ?? new Error("GEMINI_LIST_SESSIONS_FAILED");
|
|
310
|
-
}
|
|
311
|
-
readLocalSessionsDetailed() {
|
|
312
|
-
const sessions = [];
|
|
313
|
-
const latestByProviderSessionId = new Map();
|
|
314
|
-
let scannedFiles = 0;
|
|
315
|
-
let skippedByMtimeSize = 0;
|
|
316
|
-
let parsedFiles = 0;
|
|
317
|
-
let bytesRead = 0;
|
|
318
|
-
for (const filePath of listGeminiChatFiles(this.options.homeDir)) {
|
|
319
|
-
scannedFiles += 1;
|
|
320
|
-
let localSession;
|
|
321
|
-
try {
|
|
322
|
-
const stats = statSync(filePath);
|
|
323
|
-
const cached = this.localSessionCache.get(filePath);
|
|
324
|
-
if (cached && cached.mtimeMs === stats.mtimeMs && cached.size === stats.size) {
|
|
325
|
-
skippedByMtimeSize += 1;
|
|
326
|
-
localSession = cached.session;
|
|
327
|
-
}
|
|
328
|
-
else {
|
|
329
|
-
parsedFiles += 1;
|
|
330
|
-
bytesRead += stats.size;
|
|
331
|
-
localSession = this.parseLocalSessionSummary(filePath, stats);
|
|
332
|
-
this.localSessionCache.set(filePath, {
|
|
333
|
-
mtimeMs: stats.mtimeMs,
|
|
334
|
-
size: stats.size,
|
|
335
|
-
session: localSession
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
catch {
|
|
340
|
-
continue;
|
|
341
|
-
}
|
|
342
|
-
const existing = latestByProviderSessionId.get(localSession.providerSessionId);
|
|
343
|
-
if (existing &&
|
|
344
|
-
(existing.sourceMtimeMs > localSession.sourceMtimeMs ||
|
|
345
|
-
(existing.sourceMtimeMs === localSession.sourceMtimeMs &&
|
|
346
|
-
existing.sourceSizeBytes >= localSession.sourceSizeBytes))) {
|
|
347
|
-
continue;
|
|
348
|
-
}
|
|
349
|
-
latestByProviderSessionId.set(localSession.providerSessionId, localSession);
|
|
350
|
-
}
|
|
351
|
-
sessions.push(...latestByProviderSessionId.values());
|
|
352
|
-
return {
|
|
353
|
-
sessions,
|
|
354
|
-
scannedFiles,
|
|
355
|
-
skippedByMtimeSize,
|
|
356
|
-
parsedFiles,
|
|
357
|
-
bytesRead
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
readParsedChatBySessionId(providerSessionId, scopedHomeDir = null) {
|
|
361
|
-
const sessionId = providerSessionId.trim();
|
|
362
|
-
if (!sessionId) {
|
|
363
|
-
throw new Error("PROVIDER_SESSION_ID_REQUIRED");
|
|
364
|
-
}
|
|
365
|
-
const chatFiles = listGeminiChatFiles(scopedHomeDir ?? this.options.homeDir);
|
|
366
|
-
let matchedByName = null;
|
|
367
|
-
let matchedBySessionId = null;
|
|
368
|
-
for (const filePath of chatFiles) {
|
|
369
|
-
if (basename(filePath, ".json") === sessionId) {
|
|
370
|
-
matchedByName = filePath;
|
|
371
|
-
}
|
|
372
|
-
let summary;
|
|
373
|
-
try {
|
|
374
|
-
const stats = statSync(filePath);
|
|
375
|
-
const cached = this.localSessionCache.get(filePath);
|
|
376
|
-
if (cached && cached.mtimeMs === stats.mtimeMs && cached.size === stats.size) {
|
|
377
|
-
summary = cached.session;
|
|
378
|
-
}
|
|
379
|
-
else {
|
|
380
|
-
summary = this.parseLocalSessionSummary(filePath, stats);
|
|
381
|
-
this.localSessionCache.set(filePath, {
|
|
382
|
-
mtimeMs: stats.mtimeMs,
|
|
383
|
-
size: stats.size,
|
|
384
|
-
session: summary
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
catch (error) {
|
|
389
|
-
if (basename(filePath, ".json") === sessionId) {
|
|
390
|
-
throw wrapGeminiSchemaError(filePath, error);
|
|
391
|
-
}
|
|
392
|
-
continue;
|
|
393
|
-
}
|
|
394
|
-
if (summary.providerSessionId === sessionId) {
|
|
395
|
-
matchedBySessionId = filePath;
|
|
396
|
-
break;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
if (matchedBySessionId) {
|
|
400
|
-
return this.readCachedLocalChatFile(matchedBySessionId);
|
|
401
|
-
}
|
|
402
|
-
if (matchedByName) {
|
|
403
|
-
try {
|
|
404
|
-
return this.readCachedLocalChatFile(matchedByName);
|
|
405
|
-
}
|
|
406
|
-
catch (error) {
|
|
407
|
-
throw wrapGeminiSchemaError(matchedByName, error);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
throw new Error("GEMINI_CHAT_NOT_FOUND");
|
|
411
|
-
}
|
|
412
|
-
findLocalChatFilePathsBySessionId(providerSessionId, scopedHomeDir = null) {
|
|
413
|
-
const sessionId = providerSessionId.trim();
|
|
414
|
-
if (!sessionId) {
|
|
415
|
-
throw new Error("PROVIDER_SESSION_ID_REQUIRED");
|
|
416
|
-
}
|
|
417
|
-
const matchedFilePaths = new Set();
|
|
418
|
-
for (const filePath of listGeminiChatFiles(scopedHomeDir ?? this.options.homeDir)) {
|
|
419
|
-
if (basename(filePath, ".json") === sessionId) {
|
|
420
|
-
matchedFilePaths.add(filePath);
|
|
421
|
-
continue;
|
|
422
|
-
}
|
|
423
|
-
try {
|
|
424
|
-
const stats = statSync(filePath);
|
|
425
|
-
const cached = this.localSessionCache.get(filePath);
|
|
426
|
-
const summary = cached && cached.mtimeMs === stats.mtimeMs && cached.size === stats.size
|
|
427
|
-
? cached.session
|
|
428
|
-
: this.parseLocalSessionSummary(filePath, stats);
|
|
429
|
-
if (!cached || cached.mtimeMs !== stats.mtimeMs || cached.size !== stats.size) {
|
|
430
|
-
this.localSessionCache.set(filePath, {
|
|
431
|
-
mtimeMs: stats.mtimeMs,
|
|
432
|
-
size: stats.size,
|
|
433
|
-
session: summary
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
if (summary.providerSessionId === sessionId) {
|
|
437
|
-
matchedFilePaths.add(filePath);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
catch {
|
|
441
|
-
continue;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
return [...matchedFilePaths];
|
|
445
|
-
}
|
|
446
|
-
readCachedLocalChatFile(filePath) {
|
|
447
|
-
const stats = statSync(filePath);
|
|
448
|
-
const cached = this.parsedChatCache.get(filePath);
|
|
449
|
-
if (cached && cached.mtimeMs === stats.mtimeMs && cached.size === stats.size) {
|
|
450
|
-
return cached.parsedChat;
|
|
451
|
-
}
|
|
452
|
-
const parsedChat = this.parseLocalChatFile(filePath, stats);
|
|
453
|
-
this.parsedChatCache.set(filePath, {
|
|
454
|
-
mtimeMs: stats.mtimeMs,
|
|
455
|
-
size: stats.size,
|
|
456
|
-
parsedChat
|
|
457
|
-
});
|
|
458
|
-
return parsedChat;
|
|
459
|
-
}
|
|
460
|
-
parseLocalChatFile(filePath, stats) {
|
|
461
|
-
const parsedRecord = readGeminiParsedChatSource(filePath).record;
|
|
462
|
-
const providerSessionId = this.resolveLocalProviderSessionId(parsedRecord, filePath);
|
|
463
|
-
const messageNodes = readMessageNodes(parsedRecord);
|
|
464
|
-
const messages = normalizeMessageNodes({
|
|
465
|
-
sessionId: providerSessionId,
|
|
466
|
-
filePath,
|
|
467
|
-
messageNodes
|
|
468
|
-
});
|
|
469
|
-
const title = resolveStringField(parsedRecord, ["title", "name", "chatTitle"]) ||
|
|
470
|
-
messages.find((message) => message.role === "user")?.content.slice(0, DEFAULT_GEMINI_TITLE_LENGTH) ||
|
|
471
|
-
providerSessionId;
|
|
472
|
-
const workspacePath = resolveWorkspacePath(parsedRecord, messageNodes, filePath);
|
|
473
|
-
const lastMessageAt = messages.at(-1)?.timestamp ||
|
|
474
|
-
resolveStringField(parsedRecord, [
|
|
475
|
-
"updatedAt",
|
|
476
|
-
"updated_at",
|
|
477
|
-
"lastUpdated",
|
|
478
|
-
"last_updated",
|
|
479
|
-
"lastMessageAt",
|
|
480
|
-
"last_message_at",
|
|
481
|
-
"startTime",
|
|
482
|
-
"start_time",
|
|
483
|
-
"createdAt",
|
|
484
|
-
"created_at"
|
|
485
|
-
]) ||
|
|
486
|
-
null;
|
|
487
|
-
return {
|
|
488
|
-
providerSessionId,
|
|
489
|
-
workspacePath,
|
|
490
|
-
title,
|
|
491
|
-
lastMessageAt,
|
|
492
|
-
messages,
|
|
493
|
-
sourceMtimeMs: stats.mtimeMs,
|
|
494
|
-
sourceSizeBytes: stats.size
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
parseLocalSessionSummary(filePath, stats) {
|
|
498
|
-
const parsedRecord = readGeminiParsedChatSource(filePath).record;
|
|
499
|
-
const providerSessionId = this.resolveLocalProviderSessionId(parsedRecord, filePath);
|
|
500
|
-
const messageNodes = readMessageNodes(parsedRecord);
|
|
501
|
-
const messageSummary = summarizeGeminiMessageNodes(messageNodes);
|
|
502
|
-
const workspacePath = resolveWorkspacePath(parsedRecord, messageNodes, filePath);
|
|
503
|
-
return {
|
|
504
|
-
providerSessionId,
|
|
505
|
-
workspacePath,
|
|
506
|
-
title: resolveStringField(parsedRecord, ["title", "name", "chatTitle"]) ||
|
|
507
|
-
messageSummary.firstUserText?.slice(0, DEFAULT_GEMINI_TITLE_LENGTH) ||
|
|
508
|
-
providerSessionId,
|
|
509
|
-
lastMessageAt: resolveStringField(parsedRecord, [
|
|
510
|
-
"updatedAt",
|
|
511
|
-
"updated_at",
|
|
512
|
-
"lastUpdated",
|
|
513
|
-
"last_updated",
|
|
514
|
-
"lastMessageAt",
|
|
515
|
-
"last_message_at",
|
|
516
|
-
"startTime",
|
|
517
|
-
"start_time",
|
|
518
|
-
"createdAt",
|
|
519
|
-
"created_at"
|
|
520
|
-
]) ||
|
|
521
|
-
messageSummary.lastMessageAt,
|
|
522
|
-
messageCount: resolveGeminiSummaryMessageCount(parsedRecord, messageSummary.messageCount),
|
|
523
|
-
filePath,
|
|
524
|
-
sourceMtimeMs: stats.mtimeMs,
|
|
525
|
-
sourceSizeBytes: stats.size
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
resolveLocalProviderSessionId(record, filePath) {
|
|
529
|
-
const sessionId = resolveStringField(record, [
|
|
530
|
-
"sessionId",
|
|
531
|
-
"session_id",
|
|
532
|
-
"id",
|
|
533
|
-
"chatId",
|
|
534
|
-
"conversationId",
|
|
535
|
-
"conversation_id"
|
|
536
|
-
]) || stripGeminiChatFileExtension(filePath);
|
|
537
|
-
if (!sessionId.trim()) {
|
|
538
|
-
throw new Error("GEMINI_CHAT_SCHEMA_INVALID");
|
|
539
|
-
}
|
|
540
|
-
return sessionId.trim();
|
|
541
|
-
}
|
|
542
|
-
matchesWorkspace(workspacePath, targetPath) {
|
|
543
|
-
const normalizedWorkspacePath = normalizeWorkspacePath(workspacePath ?? "");
|
|
544
|
-
if (!normalizedWorkspacePath) {
|
|
545
|
-
return false;
|
|
546
|
-
}
|
|
547
|
-
return normalizedWorkspacePath === targetPath;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
function parseGeminiRawStoreRef(rawStoreRef) {
|
|
551
|
-
const trimmed = rawStoreRef.trim();
|
|
552
|
-
if (!trimmed.startsWith(GEMINI_RAW_STORE_PREFIX)) {
|
|
553
|
-
return null;
|
|
554
|
-
}
|
|
555
|
-
const rawSessionId = trimmed.slice(GEMINI_RAW_STORE_PREFIX.length).split(/[?#]/, 1)[0];
|
|
556
|
-
return rawSessionId ? decodeURIComponent(rawSessionId) : null;
|
|
557
|
-
}
|
|
558
|
-
function resolveGeminiScopedHomeDir(rawStoreRef) {
|
|
559
|
-
const trimmed = rawStoreRef.trim();
|
|
560
|
-
if (!trimmed.startsWith(GEMINI_RAW_STORE_PREFIX)) {
|
|
561
|
-
return null;
|
|
562
|
-
}
|
|
563
|
-
const query = trimmed.split("?", 2)[1] ?? "";
|
|
564
|
-
const params = new URLSearchParams(query);
|
|
565
|
-
const homeDir = params.get("homeDir")?.trim();
|
|
566
|
-
return homeDir ? homeDir : null;
|
|
567
|
-
}
|
|
568
|
-
function buildGeminiRawStoreRef(providerSessionId, scopedHomeDir = null) {
|
|
569
|
-
const encodedSessionId = encodeURIComponent(providerSessionId);
|
|
570
|
-
if (!scopedHomeDir?.trim()) {
|
|
571
|
-
return `${GEMINI_RAW_STORE_PREFIX}${encodedSessionId}`;
|
|
572
|
-
}
|
|
573
|
-
return `${GEMINI_RAW_STORE_PREFIX}${encodedSessionId}?homeDir=${encodeURIComponent(scopedHomeDir)}`;
|
|
574
|
-
}
|
|
575
|
-
function listGeminiChatFiles(homeDir) {
|
|
576
|
-
const tmpRoot = join(homeDir, "tmp");
|
|
577
|
-
if (!existsSync(tmpRoot)) {
|
|
578
|
-
return [];
|
|
579
|
-
}
|
|
580
|
-
const queue = [tmpRoot];
|
|
581
|
-
const chatFiles = [];
|
|
582
|
-
while (queue.length > 0) {
|
|
583
|
-
const current = queue.shift();
|
|
584
|
-
if (!current) {
|
|
585
|
-
continue;
|
|
586
|
-
}
|
|
587
|
-
const entries = readdirSync(current, { withFileTypes: true });
|
|
588
|
-
for (const entry of entries) {
|
|
589
|
-
const entryPath = join(current, entry.name);
|
|
590
|
-
if (entry.isDirectory()) {
|
|
591
|
-
queue.push(entryPath);
|
|
592
|
-
continue;
|
|
593
|
-
}
|
|
594
|
-
if (!entry.isFile()
|
|
595
|
-
|| (!entry.name.endsWith(".json") && !entry.name.endsWith(".jsonl"))) {
|
|
596
|
-
continue;
|
|
597
|
-
}
|
|
598
|
-
if (!isGeminiChatFile(entryPath)) {
|
|
599
|
-
continue;
|
|
600
|
-
}
|
|
601
|
-
chatFiles.push(entryPath);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
return chatFiles;
|
|
605
|
-
}
|
|
606
|
-
function readGeminiParsedChatSource(filePath) {
|
|
607
|
-
const raw = readFileSync(filePath, "utf8").trim();
|
|
608
|
-
if (!raw) {
|
|
609
|
-
throw new Error("GEMINI_CHAT_SCHEMA_INVALID");
|
|
610
|
-
}
|
|
611
|
-
try {
|
|
612
|
-
if (filePath.endsWith(".jsonl")) {
|
|
613
|
-
return {
|
|
614
|
-
record: parseGeminiJsonlChat(raw)
|
|
615
|
-
};
|
|
616
|
-
}
|
|
617
|
-
return {
|
|
618
|
-
record: toRecord(JSON.parse(raw))
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
catch (error) {
|
|
622
|
-
throw wrapGeminiSchemaError(filePath, error);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
function parseGeminiJsonlChat(raw) {
|
|
626
|
-
const lines = raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
627
|
-
if (lines.length === 0) {
|
|
628
|
-
throw new Error("GEMINI_CHAT_SCHEMA_INVALID");
|
|
629
|
-
}
|
|
630
|
-
const root = {};
|
|
631
|
-
const messages = [];
|
|
632
|
-
for (const line of lines) {
|
|
633
|
-
const parsedLine = toRecord(JSON.parse(line));
|
|
634
|
-
const patch = maybeRecord(parsedLine.$set);
|
|
635
|
-
if (patch) {
|
|
636
|
-
Object.assign(root, patch);
|
|
637
|
-
continue;
|
|
638
|
-
}
|
|
639
|
-
if (isGeminiJsonlMessageLine(parsedLine)) {
|
|
640
|
-
messages.push(parsedLine);
|
|
641
|
-
continue;
|
|
642
|
-
}
|
|
643
|
-
Object.assign(root, parsedLine);
|
|
644
|
-
}
|
|
645
|
-
root.messages = messages;
|
|
646
|
-
return root;
|
|
647
|
-
}
|
|
648
|
-
function isGeminiJsonlMessageLine(record) {
|
|
649
|
-
const type = ensureText(record.type).trim().toLowerCase();
|
|
650
|
-
if (type === "user" || type === "gemini" || type === "tool" || type === "system") {
|
|
651
|
-
return true;
|
|
652
|
-
}
|
|
653
|
-
return Boolean(record.content !== undefined
|
|
654
|
-
|| record.parts !== undefined
|
|
655
|
-
|| record.toolCalls !== undefined
|
|
656
|
-
|| record.tool_calls !== undefined
|
|
657
|
-
|| record.thoughts !== undefined);
|
|
658
|
-
}
|
|
659
|
-
function stripGeminiChatFileExtension(filePath) {
|
|
660
|
-
const name = basename(filePath);
|
|
661
|
-
if (name.endsWith(".jsonl")) {
|
|
662
|
-
return name.slice(0, -".jsonl".length);
|
|
663
|
-
}
|
|
664
|
-
if (name.endsWith(".json")) {
|
|
665
|
-
return name.slice(0, -".json".length);
|
|
666
|
-
}
|
|
667
|
-
return name;
|
|
668
|
-
}
|
|
669
|
-
function isGeminiChatFile(filePath) {
|
|
670
|
-
return filePath.replaceAll("\\", "/").includes("/chats/");
|
|
671
|
-
}
|
|
672
|
-
function parseGeminiCliSessionOutput(stdout, workspacePathFallback = null) {
|
|
673
|
-
const trimmed = stdout.trim();
|
|
674
|
-
if (!trimmed) {
|
|
675
|
-
return [];
|
|
676
|
-
}
|
|
677
|
-
const parsedAsWhole = parseJsonSafe(trimmed);
|
|
678
|
-
const normalizedWhole = normalizeCliSessionsPayload(parsedAsWhole, workspacePathFallback);
|
|
679
|
-
if (normalizedWhole.length > 0) {
|
|
680
|
-
return normalizedWhole;
|
|
681
|
-
}
|
|
682
|
-
const normalizedText = parseGeminiPlainTextSessions(trimmed, workspacePathFallback);
|
|
683
|
-
if (normalizedText.length > 0) {
|
|
684
|
-
return normalizedText;
|
|
685
|
-
}
|
|
686
|
-
const sessions = [];
|
|
687
|
-
for (const line of trimmed.split(/\r?\n/)) {
|
|
688
|
-
const parsedLine = parseJsonSafe(line.trim());
|
|
689
|
-
if (!parsedLine) {
|
|
690
|
-
continue;
|
|
691
|
-
}
|
|
692
|
-
sessions.push(...normalizeCliSessionsPayload(parsedLine, workspacePathFallback));
|
|
693
|
-
}
|
|
694
|
-
return dedupeCliSessions(sessions);
|
|
695
|
-
}
|
|
696
|
-
function normalizeCliSessionsPayload(payload, workspacePathFallback) {
|
|
697
|
-
if (!payload) {
|
|
698
|
-
return [];
|
|
699
|
-
}
|
|
700
|
-
if (Array.isArray(payload)) {
|
|
701
|
-
return dedupeCliSessions(payload
|
|
702
|
-
.map((item) => normalizeCliSessionRecord(item, workspacePathFallback))
|
|
703
|
-
.filter((item) => item !== null));
|
|
704
|
-
}
|
|
705
|
-
const record = toRecord(payload);
|
|
706
|
-
const wrappedArray = arrayFromUnknown(record.sessions) ||
|
|
707
|
-
arrayFromUnknown(record.items) ||
|
|
708
|
-
arrayFromUnknown(record.data);
|
|
709
|
-
if (wrappedArray) {
|
|
710
|
-
return dedupeCliSessions(wrappedArray
|
|
711
|
-
.map((item) => normalizeCliSessionRecord(item, workspacePathFallback))
|
|
712
|
-
.filter((item) => item !== null));
|
|
713
|
-
}
|
|
714
|
-
const single = normalizeCliSessionRecord(record, workspacePathFallback);
|
|
715
|
-
return single ? [single] : [];
|
|
716
|
-
}
|
|
717
|
-
function normalizeCliSessionRecord(payload, workspacePathFallback) {
|
|
718
|
-
const record = toRecord(payload);
|
|
719
|
-
const providerSessionId = resolveStringField(record, [
|
|
720
|
-
"sessionId",
|
|
721
|
-
"session_id",
|
|
722
|
-
"id",
|
|
723
|
-
"conversationId",
|
|
724
|
-
"conversation_id"
|
|
725
|
-
]);
|
|
726
|
-
if (!providerSessionId) {
|
|
727
|
-
return null;
|
|
728
|
-
}
|
|
729
|
-
const messageCountValue = resolveNumberField(record, ["messageCount", "message_count"]);
|
|
730
|
-
return {
|
|
731
|
-
providerSessionId,
|
|
732
|
-
workspacePath: resolveStringField(record, [
|
|
733
|
-
"workspacePath",
|
|
734
|
-
"workspace_path",
|
|
735
|
-
"cwd",
|
|
736
|
-
"directory",
|
|
737
|
-
"projectPath",
|
|
738
|
-
"project_path"
|
|
739
|
-
]) || workspacePathFallback,
|
|
740
|
-
title: resolveStringField(record, ["title", "name", "summary"]) || null,
|
|
741
|
-
lastMessageAt: resolveStringField(record, [
|
|
742
|
-
"updatedAt",
|
|
743
|
-
"updated_at",
|
|
744
|
-
"lastUpdated",
|
|
745
|
-
"last_updated",
|
|
746
|
-
"lastMessageAt",
|
|
747
|
-
"last_message_at",
|
|
748
|
-
"startTime",
|
|
749
|
-
"start_time",
|
|
750
|
-
"createdAt",
|
|
751
|
-
"created_at"
|
|
752
|
-
]) || null,
|
|
753
|
-
messageCount: messageCountValue === null ? null : messageCountValue
|
|
754
|
-
};
|
|
755
|
-
}
|
|
756
|
-
function dedupeCliSessions(sessions) {
|
|
757
|
-
const deduped = new Map();
|
|
758
|
-
for (const session of sessions) {
|
|
759
|
-
const existing = deduped.get(session.providerSessionId);
|
|
760
|
-
if (!existing ||
|
|
761
|
-
(existing.lastMessageAt ?? "").localeCompare(session.lastMessageAt ?? "") < 0) {
|
|
762
|
-
deduped.set(session.providerSessionId, session);
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
return [...deduped.values()];
|
|
766
|
-
}
|
|
767
|
-
function resolveWorkspacePath(record, messageNodes, filePath) {
|
|
768
|
-
const directWorkspace = resolveStringField(record, [
|
|
769
|
-
"workspacePath",
|
|
770
|
-
"workspace_path",
|
|
771
|
-
"cwd",
|
|
772
|
-
"projectPath",
|
|
773
|
-
"project_path"
|
|
774
|
-
]);
|
|
775
|
-
if (directWorkspace) {
|
|
776
|
-
return directWorkspace;
|
|
777
|
-
}
|
|
778
|
-
for (const node of messageNodes) {
|
|
779
|
-
const nodeRecord = toRecord(node);
|
|
780
|
-
const workspace = resolveStringField(nodeRecord, [
|
|
781
|
-
"workspacePath",
|
|
782
|
-
"workspace_path",
|
|
783
|
-
"cwd",
|
|
784
|
-
"projectPath",
|
|
785
|
-
"project_path"
|
|
786
|
-
]);
|
|
787
|
-
if (workspace) {
|
|
788
|
-
return workspace;
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
return resolveWorkspacePathFromChatFile(filePath);
|
|
792
|
-
}
|
|
793
|
-
function readMessageNodes(record) {
|
|
794
|
-
const candidates = [
|
|
795
|
-
record.messages,
|
|
796
|
-
record.history,
|
|
797
|
-
record.events,
|
|
798
|
-
record.contents,
|
|
799
|
-
record.turns,
|
|
800
|
-
toRecord(record.chat).messages,
|
|
801
|
-
toRecord(record.conversation).messages,
|
|
802
|
-
toRecord(record.transcript).messages
|
|
803
|
-
];
|
|
804
|
-
for (const candidate of candidates) {
|
|
805
|
-
const array = arrayFromUnknown(candidate);
|
|
806
|
-
if (array && array.length > 0) {
|
|
807
|
-
return array;
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
return [];
|
|
811
|
-
}
|
|
812
|
-
function normalizeMessageNodes(input) {
|
|
813
|
-
const messages = [];
|
|
814
|
-
let sequence = 0;
|
|
815
|
-
const identityState = {
|
|
816
|
-
userTextIndex: 0,
|
|
817
|
-
assistantTextIndex: 0
|
|
818
|
-
};
|
|
819
|
-
for (let index = 0; index < input.messageNodes.length; index += 1) {
|
|
820
|
-
const node = input.messageNodes[index];
|
|
821
|
-
const nodeRecord = toRecord(node);
|
|
822
|
-
const role = resolveGeminiRole(nodeRecord);
|
|
823
|
-
const timestamp = resolveMessageTimestamp(nodeRecord);
|
|
824
|
-
const descriptors = readMessageDescriptors(nodeRecord, role);
|
|
825
|
-
if (descriptors.length === 0) {
|
|
826
|
-
continue;
|
|
827
|
-
}
|
|
828
|
-
for (let descriptorIndex = 0; descriptorIndex < descriptors.length; descriptorIndex += 1) {
|
|
829
|
-
const descriptor = descriptors[descriptorIndex];
|
|
830
|
-
sequence += 1;
|
|
831
|
-
const rawRef = buildGeminiMessageRawRef(input.sessionId, input.filePath, index, descriptorIndex);
|
|
832
|
-
const messageId = buildGeminiMessageId({
|
|
833
|
-
sessionId: input.sessionId,
|
|
834
|
-
descriptor,
|
|
835
|
-
rawRef,
|
|
836
|
-
identityState
|
|
837
|
-
});
|
|
838
|
-
messages.push({
|
|
839
|
-
messageId,
|
|
840
|
-
provider: "gemini",
|
|
841
|
-
providerSessionId: input.sessionId,
|
|
842
|
-
role: descriptor.role,
|
|
843
|
-
kind: descriptor.kind,
|
|
844
|
-
content: descriptor.content,
|
|
845
|
-
toolCall: descriptor.toolCall,
|
|
846
|
-
timestamp: descriptor.timestamp ?? timestamp,
|
|
847
|
-
sequence,
|
|
848
|
-
rawRef
|
|
849
|
-
});
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
return messages;
|
|
853
|
-
}
|
|
854
|
-
function summarizeGeminiMessageNodes(messageNodes) {
|
|
855
|
-
let messageCount = 0;
|
|
856
|
-
let lastMessageAt = null;
|
|
857
|
-
let firstUserText = null;
|
|
858
|
-
for (const node of messageNodes) {
|
|
859
|
-
const nodeRecord = toRecord(node);
|
|
860
|
-
const role = resolveGeminiRole(nodeRecord);
|
|
861
|
-
const nodeTimestamp = resolveMessageTimestamp(nodeRecord);
|
|
862
|
-
const descriptors = readMessageDescriptors(nodeRecord, role);
|
|
863
|
-
if (descriptors.length === 0) {
|
|
864
|
-
continue;
|
|
865
|
-
}
|
|
866
|
-
messageCount += descriptors.length;
|
|
867
|
-
lastMessageAt = descriptors.at(-1)?.timestamp ?? nodeTimestamp;
|
|
868
|
-
if (firstUserText) {
|
|
869
|
-
continue;
|
|
870
|
-
}
|
|
871
|
-
const firstUserDescriptor = descriptors.find((descriptor) => descriptor.role === "user" &&
|
|
872
|
-
descriptor.kind === "text" &&
|
|
873
|
-
descriptor.content.trim().length > 0);
|
|
874
|
-
if (firstUserDescriptor) {
|
|
875
|
-
firstUserText = firstUserDescriptor.content.trim();
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
return {
|
|
879
|
-
messageCount,
|
|
880
|
-
lastMessageAt,
|
|
881
|
-
firstUserText
|
|
882
|
-
};
|
|
883
|
-
}
|
|
884
|
-
function resolveGeminiSummaryMessageCount(record, fallbackMessageCount) {
|
|
885
|
-
const explicitMessageCount = firstGeminiNumber(record.messageCount, record.message_count, record.totalMessages, record.total_messages, record.messageTotal);
|
|
886
|
-
if (explicitMessageCount !== null && explicitMessageCount >= 0) {
|
|
887
|
-
return Math.trunc(explicitMessageCount);
|
|
888
|
-
}
|
|
889
|
-
return fallbackMessageCount;
|
|
890
|
-
}
|
|
891
|
-
function firstGeminiNumber(...values) {
|
|
892
|
-
for (const value of values) {
|
|
893
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
894
|
-
return value;
|
|
895
|
-
}
|
|
896
|
-
if (typeof value === "string") {
|
|
897
|
-
const trimmed = value.trim();
|
|
898
|
-
if (!trimmed) {
|
|
899
|
-
continue;
|
|
900
|
-
}
|
|
901
|
-
const parsed = Number(trimmed);
|
|
902
|
-
if (Number.isFinite(parsed)) {
|
|
903
|
-
return parsed;
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
return null;
|
|
908
|
-
}
|
|
909
|
-
function readMessageDescriptors(nodeRecord, fallbackRole) {
|
|
910
|
-
const descriptors = [];
|
|
911
|
-
descriptors.push(...readGeminiThoughtDescriptors(nodeRecord));
|
|
912
|
-
descriptors.push(...readGeminiToolCallDescriptors(nodeRecord));
|
|
913
|
-
const parts = arrayFromUnknown(nodeRecord.parts) ||
|
|
914
|
-
arrayFromUnknown(nodeRecord.content) ||
|
|
915
|
-
arrayFromUnknown(toRecord(nodeRecord.message).parts) ||
|
|
916
|
-
null;
|
|
917
|
-
const partDescriptors = [];
|
|
918
|
-
if (parts && parts.length > 0) {
|
|
919
|
-
for (const part of parts) {
|
|
920
|
-
const descriptor = normalizeMessagePart(part, fallbackRole);
|
|
921
|
-
if (descriptor) {
|
|
922
|
-
partDescriptors.push(descriptor);
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
if (partDescriptors.length > 0) {
|
|
927
|
-
descriptors.push(...partDescriptors);
|
|
928
|
-
return descriptors;
|
|
929
|
-
}
|
|
930
|
-
const fallbackDescriptor = normalizeMessagePart(nodeRecord, fallbackRole);
|
|
931
|
-
if (fallbackDescriptor) {
|
|
932
|
-
descriptors.push(fallbackDescriptor);
|
|
933
|
-
}
|
|
934
|
-
return descriptors;
|
|
935
|
-
}
|
|
936
|
-
function normalizeMessagePart(value, fallbackRole) {
|
|
937
|
-
const record = toRecord(value);
|
|
938
|
-
const toolCallPayload = maybeRecord(record.tool_use) ??
|
|
939
|
-
maybeRecord(record.toolUse) ??
|
|
940
|
-
maybeRecord(record.functionCall) ??
|
|
941
|
-
(record.type === "tool_use" || record.type === "function_call" ? record : null);
|
|
942
|
-
if (toolCallPayload) {
|
|
943
|
-
const timestamp = resolveOptionalMessageTimestamp(record);
|
|
944
|
-
const patchText = buildGeminiApplyPatchFromInput(toolCallPayload);
|
|
945
|
-
const callId = resolveStringField(toolCallPayload, ["id", "toolCallId", "call_id"]) || "gemini-call";
|
|
946
|
-
const name = patchText
|
|
947
|
-
? "apply_patch"
|
|
948
|
-
: resolveStringField(toolCallPayload, ["name", "toolName", "tool_name"]) || "unknown_tool";
|
|
949
|
-
const inputPayload = toolCallPayload.input ??
|
|
950
|
-
toolCallPayload.arguments ??
|
|
951
|
-
toolCallPayload.args ??
|
|
952
|
-
null;
|
|
953
|
-
const inputText = patchText || stringifyStructuredValue(inputPayload);
|
|
954
|
-
return {
|
|
955
|
-
role: patchText ? "tool" : "assistant",
|
|
956
|
-
kind: "tool_call",
|
|
957
|
-
content: inputText,
|
|
958
|
-
toolCall: {
|
|
959
|
-
callId,
|
|
960
|
-
name,
|
|
961
|
-
input: inputText,
|
|
962
|
-
output: null,
|
|
963
|
-
error: null,
|
|
964
|
-
status: "running"
|
|
965
|
-
},
|
|
966
|
-
timestamp
|
|
967
|
-
};
|
|
968
|
-
}
|
|
969
|
-
const toolResultPayload = maybeRecord(record.tool_result) ??
|
|
970
|
-
maybeRecord(record.toolResult) ??
|
|
971
|
-
maybeRecord(record.functionResponse) ??
|
|
972
|
-
(record.type === "tool_result" || record.type === "function_response" ? record : null);
|
|
973
|
-
if (toolResultPayload) {
|
|
974
|
-
const timestamp = resolveOptionalMessageTimestamp(record);
|
|
975
|
-
const errorDetail = resolveStringField(toolResultPayload, ["error", "error_message"]);
|
|
976
|
-
const outputPayload = toolResultPayload.output ??
|
|
977
|
-
toolResultPayload.result ??
|
|
978
|
-
toolResultPayload.content ??
|
|
979
|
-
null;
|
|
980
|
-
const normalizedName = resolveStringField(toolResultPayload, [
|
|
981
|
-
"name",
|
|
982
|
-
"tool_name",
|
|
983
|
-
"toolName"
|
|
984
|
-
]) || "unknown_tool";
|
|
985
|
-
const name = isGeminiEditableToolName(normalizedName) ? "apply_patch" : normalizedName;
|
|
986
|
-
return {
|
|
987
|
-
role: "tool",
|
|
988
|
-
kind: "tool_result",
|
|
989
|
-
content: extractTextBlocks(outputPayload).trim() || stringifyStructuredValue(outputPayload),
|
|
990
|
-
toolCall: {
|
|
991
|
-
callId: resolveStringField(toolResultPayload, [
|
|
992
|
-
"tool_use_id",
|
|
993
|
-
"toolUseId",
|
|
994
|
-
"call_id",
|
|
995
|
-
"callId"
|
|
996
|
-
]) || "gemini-tool-result",
|
|
997
|
-
name,
|
|
998
|
-
input: "",
|
|
999
|
-
output: stringifyStructuredValue(outputPayload),
|
|
1000
|
-
error: errorDetail,
|
|
1001
|
-
status: errorDetail ? "failed" : "completed"
|
|
1002
|
-
},
|
|
1003
|
-
timestamp
|
|
1004
|
-
};
|
|
1005
|
-
}
|
|
1006
|
-
const text = extractTextBlocks(record.text ??
|
|
1007
|
-
record.content ??
|
|
1008
|
-
record.output ??
|
|
1009
|
-
record.message ??
|
|
1010
|
-
value).trim();
|
|
1011
|
-
if (!text) {
|
|
1012
|
-
return null;
|
|
1013
|
-
}
|
|
1014
|
-
const partType = ensureText(record.type).toLowerCase();
|
|
1015
|
-
const kind = partType.includes("think") ? "thinking" : "text";
|
|
1016
|
-
return {
|
|
1017
|
-
role: fallbackRole,
|
|
1018
|
-
kind,
|
|
1019
|
-
content: text,
|
|
1020
|
-
toolCall: null,
|
|
1021
|
-
timestamp: resolveOptionalMessageTimestamp(record)
|
|
1022
|
-
};
|
|
1023
|
-
}
|
|
1024
|
-
function readGeminiThoughtDescriptors(nodeRecord) {
|
|
1025
|
-
const thoughts = arrayFromUnknown(nodeRecord.thoughts) ??
|
|
1026
|
-
arrayFromUnknown(nodeRecord.reasoning) ??
|
|
1027
|
-
null;
|
|
1028
|
-
if (!thoughts || thoughts.length === 0) {
|
|
1029
|
-
return [];
|
|
1030
|
-
}
|
|
1031
|
-
return thoughts
|
|
1032
|
-
.map((thought) => normalizeGeminiThoughtDescriptor(thought))
|
|
1033
|
-
.filter((descriptor) => descriptor !== null);
|
|
1034
|
-
}
|
|
1035
|
-
function normalizeGeminiThoughtDescriptor(value) {
|
|
1036
|
-
const record = toRecord(value);
|
|
1037
|
-
const subject = resolveStringField(record, ["subject", "title", "name"]);
|
|
1038
|
-
const description = resolveStringField(record, [
|
|
1039
|
-
"description",
|
|
1040
|
-
"content",
|
|
1041
|
-
"text",
|
|
1042
|
-
"message"
|
|
1043
|
-
]);
|
|
1044
|
-
const content = [subject, description].filter((item) => Boolean(item)).join("\n\n").trim();
|
|
1045
|
-
if (!content) {
|
|
1046
|
-
return null;
|
|
1047
|
-
}
|
|
1048
|
-
return {
|
|
1049
|
-
role: "assistant",
|
|
1050
|
-
kind: "thinking",
|
|
1051
|
-
content,
|
|
1052
|
-
toolCall: null,
|
|
1053
|
-
timestamp: resolveOptionalMessageTimestamp(record)
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
function readGeminiToolCallDescriptors(nodeRecord) {
|
|
1057
|
-
const toolCalls = arrayFromUnknown(nodeRecord.toolCalls) ??
|
|
1058
|
-
arrayFromUnknown(nodeRecord.tool_calls) ??
|
|
1059
|
-
null;
|
|
1060
|
-
if (!toolCalls || toolCalls.length === 0) {
|
|
1061
|
-
return [];
|
|
1062
|
-
}
|
|
1063
|
-
const descriptors = [];
|
|
1064
|
-
for (let index = 0; index < toolCalls.length; index += 1) {
|
|
1065
|
-
const descriptorSet = normalizeGeminiToolCall(toolCalls[index], index);
|
|
1066
|
-
if (descriptorSet.call) {
|
|
1067
|
-
descriptors.push(descriptorSet.call);
|
|
1068
|
-
}
|
|
1069
|
-
if (descriptorSet.result) {
|
|
1070
|
-
descriptors.push(descriptorSet.result);
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
return descriptors;
|
|
1074
|
-
}
|
|
1075
|
-
function normalizeGeminiToolCall(value, index) {
|
|
1076
|
-
const record = toRecord(value);
|
|
1077
|
-
const timestamp = resolveOptionalMessageTimestamp(record);
|
|
1078
|
-
const patchText = buildGeminiApplyPatchFromInput(record);
|
|
1079
|
-
const callId = resolveStringField(record, ["id", "toolCallId", "call_id"]) ||
|
|
1080
|
-
`gemini-tool-call-${index + 1}`;
|
|
1081
|
-
const rawName = resolveStringField(record, ["name", "toolName", "tool_name", "displayName"]) || "tool";
|
|
1082
|
-
const name = patchText ? "apply_patch" : rawName;
|
|
1083
|
-
const inputPayload = record.args ?? record.input ?? record.arguments ?? null;
|
|
1084
|
-
const inputText = patchText || stringifyStructuredValue(inputPayload);
|
|
1085
|
-
const callDescriptor = {
|
|
1086
|
-
role: patchText ? "tool" : "assistant",
|
|
1087
|
-
kind: "tool_call",
|
|
1088
|
-
content: inputText || name,
|
|
1089
|
-
toolCall: {
|
|
1090
|
-
callId,
|
|
1091
|
-
name,
|
|
1092
|
-
input: inputText,
|
|
1093
|
-
output: null,
|
|
1094
|
-
error: null,
|
|
1095
|
-
status: "running"
|
|
1096
|
-
},
|
|
1097
|
-
timestamp
|
|
1098
|
-
};
|
|
1099
|
-
return {
|
|
1100
|
-
call: callDescriptor,
|
|
1101
|
-
result: normalizeGeminiToolCallResult(record, callId, name, timestamp)
|
|
1102
|
-
};
|
|
1103
|
-
}
|
|
1104
|
-
function normalizeGeminiToolCallResult(record, callId, name, fallbackTimestamp) {
|
|
1105
|
-
const output = extractGeminiToolCallOutput(record);
|
|
1106
|
-
const error = extractGeminiToolCallError(record);
|
|
1107
|
-
const hasResultPayload = Array.isArray(record.result) ||
|
|
1108
|
-
record.result !== undefined ||
|
|
1109
|
-
record.output !== undefined ||
|
|
1110
|
-
record.resultDisplay !== undefined ||
|
|
1111
|
-
error !== null;
|
|
1112
|
-
if (!hasResultPayload) {
|
|
1113
|
-
return null;
|
|
1114
|
-
}
|
|
1115
|
-
const status = normalizeGeminiToolCallStatus(record, error);
|
|
1116
|
-
const content = output || error || name;
|
|
1117
|
-
if (!content.trim()) {
|
|
1118
|
-
return null;
|
|
1119
|
-
}
|
|
1120
|
-
return {
|
|
1121
|
-
role: "tool",
|
|
1122
|
-
kind: "tool_result",
|
|
1123
|
-
content,
|
|
1124
|
-
toolCall: {
|
|
1125
|
-
callId,
|
|
1126
|
-
name,
|
|
1127
|
-
input: "",
|
|
1128
|
-
output: output || null,
|
|
1129
|
-
error,
|
|
1130
|
-
status
|
|
1131
|
-
},
|
|
1132
|
-
timestamp: resolveStringField(record, [
|
|
1133
|
-
"timestamp",
|
|
1134
|
-
"updatedAt",
|
|
1135
|
-
"updated_at",
|
|
1136
|
-
"lastUpdated",
|
|
1137
|
-
"last_updated"
|
|
1138
|
-
]) || fallbackTimestamp
|
|
1139
|
-
};
|
|
1140
|
-
}
|
|
1141
|
-
function extractGeminiToolCallOutput(record) {
|
|
1142
|
-
const resultItems = arrayFromUnknown(record.result) ?? [];
|
|
1143
|
-
for (const item of resultItems) {
|
|
1144
|
-
const itemRecord = toRecord(item);
|
|
1145
|
-
const functionResponse = toRecord(itemRecord.functionResponse);
|
|
1146
|
-
const response = toRecord(functionResponse.response);
|
|
1147
|
-
const outputText = extractTextBlocks(response.output ??
|
|
1148
|
-
itemRecord.output ??
|
|
1149
|
-
itemRecord.result ??
|
|
1150
|
-
itemRecord.content).trim();
|
|
1151
|
-
if (outputText) {
|
|
1152
|
-
return outputText;
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
const directOutput = extractTextBlocks(record.output ??
|
|
1156
|
-
record.result ??
|
|
1157
|
-
toRecord(record.resultDisplay).fileDiff ??
|
|
1158
|
-
toRecord(record.resultDisplay).newContent).trim();
|
|
1159
|
-
return directOutput;
|
|
1160
|
-
}
|
|
1161
|
-
function extractGeminiToolCallError(record) {
|
|
1162
|
-
const directError = resolveStringField(record, [
|
|
1163
|
-
"error",
|
|
1164
|
-
"error_message",
|
|
1165
|
-
"failure",
|
|
1166
|
-
"description"
|
|
1167
|
-
]);
|
|
1168
|
-
if (directError && normalizeGeminiToolCallStatus(record, null) === "failed") {
|
|
1169
|
-
return directError;
|
|
1170
|
-
}
|
|
1171
|
-
return null;
|
|
1172
|
-
}
|
|
1173
|
-
function normalizeGeminiToolCallStatus(record, error) {
|
|
1174
|
-
if (error) {
|
|
1175
|
-
return "failed";
|
|
1176
|
-
}
|
|
1177
|
-
const normalizedStatus = ensureText(record.status).trim().toLowerCase();
|
|
1178
|
-
if (!normalizedStatus || normalizedStatus === "success" || normalizedStatus === "completed") {
|
|
1179
|
-
return "completed";
|
|
1180
|
-
}
|
|
1181
|
-
if (["error", "failed", "failure", "cancelled", "canceled"].includes(normalizedStatus)) {
|
|
1182
|
-
return "failed";
|
|
1183
|
-
}
|
|
1184
|
-
return "completed";
|
|
1185
|
-
}
|
|
1186
|
-
function buildGeminiApplyPatchFromInput(value) {
|
|
1187
|
-
const input = value && typeof value === "object" && !Array.isArray(value)
|
|
1188
|
-
? value
|
|
1189
|
-
: null;
|
|
1190
|
-
if (!input) {
|
|
1191
|
-
return null;
|
|
1192
|
-
}
|
|
1193
|
-
const candidates = [toRecord(input.input), toRecord(input.arguments), toRecord(input.args), input];
|
|
1194
|
-
for (const candidate of candidates) {
|
|
1195
|
-
const patchText = buildApplyPatchFromStructuredFileTool(candidate);
|
|
1196
|
-
if (patchText) {
|
|
1197
|
-
return patchText;
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
return null;
|
|
1201
|
-
}
|
|
1202
|
-
function isGeminiEditableToolName(toolName) {
|
|
1203
|
-
const normalized = toolName.trim().toLowerCase();
|
|
1204
|
-
return [
|
|
1205
|
-
"write_file",
|
|
1206
|
-
"writefile",
|
|
1207
|
-
"create_file",
|
|
1208
|
-
"edit_file",
|
|
1209
|
-
"replace",
|
|
1210
|
-
"replace_file",
|
|
1211
|
-
"update_file",
|
|
1212
|
-
"multi_edit",
|
|
1213
|
-
"multiedit"
|
|
1214
|
-
].includes(normalized);
|
|
1215
|
-
}
|
|
1216
|
-
function resolveGeminiRole(record) {
|
|
1217
|
-
const candidate = resolveStringField(record, [
|
|
1218
|
-
"role",
|
|
1219
|
-
"author",
|
|
1220
|
-
"sender",
|
|
1221
|
-
"source",
|
|
1222
|
-
"participant",
|
|
1223
|
-
"type"
|
|
1224
|
-
])?.toLowerCase();
|
|
1225
|
-
if (!candidate) {
|
|
1226
|
-
return "assistant";
|
|
1227
|
-
}
|
|
1228
|
-
if (candidate.includes("user") || candidate.includes("human")) {
|
|
1229
|
-
return "user";
|
|
1230
|
-
}
|
|
1231
|
-
if (candidate.includes("tool")) {
|
|
1232
|
-
return "tool";
|
|
1233
|
-
}
|
|
1234
|
-
if (candidate.includes("system")) {
|
|
1235
|
-
return "system";
|
|
1236
|
-
}
|
|
1237
|
-
if (candidate.includes("assistant")
|
|
1238
|
-
|| candidate.includes("model")
|
|
1239
|
-
|| candidate.includes("gemini")) {
|
|
1240
|
-
return "assistant";
|
|
1241
|
-
}
|
|
1242
|
-
return "assistant";
|
|
1243
|
-
}
|
|
1244
|
-
function resolveMessageTimestamp(record) {
|
|
1245
|
-
const direct = resolveStringField(record, [
|
|
1246
|
-
"timestamp",
|
|
1247
|
-
"time",
|
|
1248
|
-
"createdAt",
|
|
1249
|
-
"created_at",
|
|
1250
|
-
"updatedAt",
|
|
1251
|
-
"updated_at"
|
|
1252
|
-
]);
|
|
1253
|
-
if (direct) {
|
|
1254
|
-
return direct;
|
|
1255
|
-
}
|
|
1256
|
-
return nextTimestamp();
|
|
1257
|
-
}
|
|
1258
|
-
function resolveOptionalMessageTimestamp(record) {
|
|
1259
|
-
return resolveStringField(record, [
|
|
1260
|
-
"timestamp",
|
|
1261
|
-
"time",
|
|
1262
|
-
"createdAt",
|
|
1263
|
-
"created_at",
|
|
1264
|
-
"updatedAt",
|
|
1265
|
-
"updated_at",
|
|
1266
|
-
"lastUpdated",
|
|
1267
|
-
"last_updated"
|
|
1268
|
-
]);
|
|
1269
|
-
}
|
|
1270
|
-
function buildGeminiMessageRawRef(sessionId, filePath, messageIndex, partIndex) {
|
|
1271
|
-
return `${GEMINI_RAW_STORE_PREFIX}${encodeURIComponent(sessionId)}#file=${encodeURIComponent(filePath.replaceAll("\\", "/"))}&index=${messageIndex}&part=${partIndex}`;
|
|
1272
|
-
}
|
|
1273
|
-
function buildGeminiMessageId(input) {
|
|
1274
|
-
const { descriptor, identityState, rawRef, sessionId } = input;
|
|
1275
|
-
if (descriptor.kind === "text" && descriptor.toolCall === null) {
|
|
1276
|
-
if (descriptor.role === "user") {
|
|
1277
|
-
identityState.userTextIndex += 1;
|
|
1278
|
-
return messageIdFromRawRef(buildGeminiRuntimeTextRawRef(sessionId, "user", identityState.userTextIndex));
|
|
1279
|
-
}
|
|
1280
|
-
if (descriptor.role === "assistant") {
|
|
1281
|
-
identityState.assistantTextIndex += 1;
|
|
1282
|
-
return messageIdFromRawRef(buildGeminiRuntimeTextRawRef(sessionId, "assistant", identityState.assistantTextIndex));
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
if ((descriptor.kind === "tool_call" || descriptor.kind === "tool_result")
|
|
1286
|
-
&& descriptor.toolCall?.callId?.trim()) {
|
|
1287
|
-
return messageIdFromRawRef(buildGeminiRuntimeToolRawRef(sessionId, descriptor.toolCall.callId.trim(), descriptor.kind === "tool_call" ? "call" : "result"));
|
|
1288
|
-
}
|
|
1289
|
-
return messageIdFromRawRef(rawRef);
|
|
1290
|
-
}
|
|
1291
|
-
function buildGeminiRuntimeTextRawRef(sessionId, role, index) {
|
|
1292
|
-
return `${GEMINI_RAW_STORE_PREFIX}${encodeURIComponent(sessionId)}/message/${role}-${index}`;
|
|
1293
|
-
}
|
|
1294
|
-
function buildGeminiRuntimeToolRawRef(sessionId, toolId, kind) {
|
|
1295
|
-
return `${GEMINI_RAW_STORE_PREFIX}${encodeURIComponent(sessionId)}/tool/${encodeURIComponent(toolId)}/${kind}`;
|
|
1296
|
-
}
|
|
1297
|
-
function resolveStringField(record, fieldNames) {
|
|
1298
|
-
for (const fieldName of fieldNames) {
|
|
1299
|
-
const value = ensureNonEmptyText(record[fieldName]);
|
|
1300
|
-
if (value) {
|
|
1301
|
-
return value;
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
const metadata = toRecord(record.metadata);
|
|
1305
|
-
for (const fieldName of fieldNames) {
|
|
1306
|
-
const value = ensureNonEmptyText(metadata[fieldName]);
|
|
1307
|
-
if (value) {
|
|
1308
|
-
return value;
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
return null;
|
|
1312
|
-
}
|
|
1313
|
-
function resolveNumberField(record, fieldNames) {
|
|
1314
|
-
for (const fieldName of fieldNames) {
|
|
1315
|
-
const value = record[fieldName];
|
|
1316
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1317
|
-
return Math.max(0, Math.trunc(value));
|
|
1318
|
-
}
|
|
1319
|
-
if (typeof value === "string") {
|
|
1320
|
-
const parsed = Number.parseInt(value, 10);
|
|
1321
|
-
if (Number.isFinite(parsed)) {
|
|
1322
|
-
return Math.max(0, parsed);
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
return null;
|
|
1327
|
-
}
|
|
1328
|
-
function parseGeminiPlainTextSessions(stdout, workspacePathFallback) {
|
|
1329
|
-
const sessions = stdout
|
|
1330
|
-
.split(/\r?\n/)
|
|
1331
|
-
.map((line) => normalizePlainTextCliSessionLine(line, workspacePathFallback))
|
|
1332
|
-
.filter((item) => item !== null);
|
|
1333
|
-
return dedupeCliSessions(sessions);
|
|
1334
|
-
}
|
|
1335
|
-
function normalizePlainTextCliSessionLine(line, workspacePathFallback) {
|
|
1336
|
-
const trimmed = line.trim();
|
|
1337
|
-
if (!trimmed) {
|
|
1338
|
-
return null;
|
|
1339
|
-
}
|
|
1340
|
-
const sessionIdMatch = trimmed.match(/\[([^\]]+)\]\s*$/);
|
|
1341
|
-
if (!sessionIdMatch?.[1]) {
|
|
1342
|
-
return null;
|
|
1343
|
-
}
|
|
1344
|
-
const providerSessionId = sessionIdMatch[1].trim();
|
|
1345
|
-
if (!providerSessionId) {
|
|
1346
|
-
return null;
|
|
1347
|
-
}
|
|
1348
|
-
let prefix = trimmed.slice(0, sessionIdMatch.index).trim();
|
|
1349
|
-
prefix = prefix.replace(/^\d+\.\s*/, "").trim();
|
|
1350
|
-
const timeSuffixMatch = prefix.match(/\(([^()]*)\)\s*$/);
|
|
1351
|
-
const title = (timeSuffixMatch && typeof timeSuffixMatch.index === "number"
|
|
1352
|
-
? prefix.slice(0, timeSuffixMatch.index)
|
|
1353
|
-
: prefix).trim() || providerSessionId;
|
|
1354
|
-
return {
|
|
1355
|
-
providerSessionId,
|
|
1356
|
-
workspacePath: workspacePathFallback,
|
|
1357
|
-
title,
|
|
1358
|
-
lastMessageAt: null,
|
|
1359
|
-
messageCount: null
|
|
1360
|
-
};
|
|
1361
|
-
}
|
|
1362
|
-
function ensureNonEmptyText(value) {
|
|
1363
|
-
const text = ensureText(value).trim();
|
|
1364
|
-
return text.length > 0 ? text : null;
|
|
1365
|
-
}
|
|
1366
|
-
function parseJsonSafe(value) {
|
|
1367
|
-
if (!value) {
|
|
1368
|
-
return null;
|
|
1369
|
-
}
|
|
1370
|
-
try {
|
|
1371
|
-
return JSON.parse(value);
|
|
1372
|
-
}
|
|
1373
|
-
catch {
|
|
1374
|
-
return null;
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
function arrayFromUnknown(value) {
|
|
1378
|
-
return Array.isArray(value) ? value : null;
|
|
1379
|
-
}
|
|
1380
|
-
function toRecord(value) {
|
|
1381
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1382
|
-
return value;
|
|
1383
|
-
}
|
|
1384
|
-
return {};
|
|
1385
|
-
}
|
|
1386
|
-
function maybeRecord(value) {
|
|
1387
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1388
|
-
return value;
|
|
1389
|
-
}
|
|
1390
|
-
return null;
|
|
1391
|
-
}
|
|
1392
|
-
function resolveWorkspacePathFromChatFile(filePath) {
|
|
1393
|
-
const projectRootFile = join(dirname(dirname(filePath)), ".project_root");
|
|
1394
|
-
if (!existsSync(projectRootFile)) {
|
|
1395
|
-
return null;
|
|
1396
|
-
}
|
|
1397
|
-
try {
|
|
1398
|
-
return ensureNonEmptyText(readFileSync(projectRootFile, "utf8"));
|
|
1399
|
-
}
|
|
1400
|
-
catch {
|
|
1401
|
-
return null;
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
function shouldUseShellForCommand(commandPath) {
|
|
1405
|
-
return process.platform === "win32" && [".cmd", ".bat"].includes(extname(commandPath).toLowerCase());
|
|
1406
|
-
}
|
|
1407
|
-
function isCommandAvailable(commandPath) {
|
|
1408
|
-
const normalizedCommandPath = stripWrappingQuotes(commandPath);
|
|
1409
|
-
if (!normalizedCommandPath) {
|
|
1410
|
-
return false;
|
|
1411
|
-
}
|
|
1412
|
-
if (normalizedCommandPath.includes("/")
|
|
1413
|
-
|| normalizedCommandPath.includes("\\")) {
|
|
1414
|
-
if (!existsSync(normalizedCommandPath)) {
|
|
1415
|
-
return false;
|
|
1416
|
-
}
|
|
1417
|
-
const extension = extname(normalizedCommandPath).toLowerCase();
|
|
1418
|
-
if ([".js", ".cjs", ".mjs"].includes(extension)) {
|
|
1419
|
-
return true;
|
|
1420
|
-
}
|
|
1421
|
-
if (process.platform === "win32") {
|
|
1422
|
-
return true;
|
|
1423
|
-
}
|
|
1424
|
-
try {
|
|
1425
|
-
accessSync(normalizedCommandPath, constants.X_OK);
|
|
1426
|
-
return true;
|
|
1427
|
-
}
|
|
1428
|
-
catch {
|
|
1429
|
-
return false;
|
|
1430
|
-
}
|
|
1431
|
-
}
|
|
1432
|
-
const pathEntries = (process.env.PATH ?? "")
|
|
1433
|
-
.split(delimiter)
|
|
1434
|
-
.map((entry) => entry.trim())
|
|
1435
|
-
.filter(Boolean);
|
|
1436
|
-
if (process.platform === "win32") {
|
|
1437
|
-
const pathextEntries = (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM")
|
|
1438
|
-
.split(";")
|
|
1439
|
-
.map((entry) => entry.trim().toLowerCase())
|
|
1440
|
-
.filter(Boolean);
|
|
1441
|
-
const candidateNames = extname(normalizedCommandPath)
|
|
1442
|
-
? [normalizedCommandPath]
|
|
1443
|
-
: pathextEntries.map((entry) => `${normalizedCommandPath}${entry.toLowerCase()}`);
|
|
1444
|
-
for (const entry of pathEntries) {
|
|
1445
|
-
for (const candidateName of candidateNames) {
|
|
1446
|
-
if (existsSync(join(entry, candidateName))) {
|
|
1447
|
-
return true;
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1450
|
-
}
|
|
1451
|
-
return false;
|
|
1452
|
-
}
|
|
1453
|
-
for (const entry of pathEntries) {
|
|
1454
|
-
const candidatePath = join(entry, normalizedCommandPath);
|
|
1455
|
-
if (!existsSync(candidatePath)) {
|
|
1456
|
-
continue;
|
|
1457
|
-
}
|
|
1458
|
-
try {
|
|
1459
|
-
accessSync(candidatePath, constants.X_OK);
|
|
1460
|
-
return true;
|
|
1461
|
-
}
|
|
1462
|
-
catch {
|
|
1463
|
-
continue;
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
return false;
|
|
1467
|
-
}
|
|
1468
|
-
function stripWrappingQuotes(value) {
|
|
1469
|
-
const trimmed = value.trim();
|
|
1470
|
-
if ((trimmed.startsWith("\"") && trimmed.endsWith("\""))
|
|
1471
|
-
|| (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
|
|
1472
|
-
return trimmed.slice(1, -1).trim();
|
|
1473
|
-
}
|
|
1474
|
-
return trimmed;
|
|
1475
|
-
}
|
|
1476
|
-
function wrapGeminiSchemaError(filePath, error) {
|
|
1477
|
-
const detail = error instanceof Error ? error.message : ensureText(error);
|
|
1478
|
-
return new Error(`GEMINI_CHAT_SCHEMA_INVALID: file=${filePath.replaceAll("\\", "/")} detail=${detail}`);
|
|
1479
|
-
}
|
|
1480
|
-
//# sourceMappingURL=gemini.js.map
|