coding-tool-x 3.8.4 → 3.8.6
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/CHANGELOG.md +15 -0
- package/README.md +86 -15
- package/dist/web/assets/AgentsDrawer-Db9wAyaZ.js +1 -0
- package/dist/web/assets/AgentsDrawer-Pw2k-ZAa.css +1 -0
- package/dist/web/assets/Analytics-C4gMzv7g.js +1 -0
- package/dist/web/assets/Analytics-CyHhR126.css +1 -0
- package/dist/web/assets/AssetPathField-Bd_nMFu3.js +1 -0
- package/dist/web/assets/ChatHistoryDrawer-B2qBQs9L.css +1 -0
- package/dist/web/assets/ChatHistoryDrawer-CwzJHyNP.js +1 -0
- package/dist/web/assets/CollapseItem-CTCfSiue.js +1 -0
- package/dist/web/assets/CommandsDrawer-BZJxlPvV.css +1 -0
- package/dist/web/assets/CommandsDrawer-vDghB1U9.js +1 -0
- package/dist/web/assets/ConfigExportDrawer-C-XDvlHc.js +1 -0
- package/dist/web/assets/ConfigExportDrawer-dwruRKWr.css +1 -0
- package/dist/web/assets/ConfigTemplates-CYY8XRED.js +1 -0
- package/dist/web/assets/ConfigTemplatesDrawer-BfDi8yO3.css +1 -0
- package/dist/web/assets/ConfigTemplatesDrawer-CbsJp76X.js +1 -0
- package/dist/web/assets/ConfigTemplatesPanel-CWyPtk67.css +1 -0
- package/dist/web/assets/ConfigTemplatesPanel-liMSTh7s.js +1 -0
- package/dist/web/assets/Divider-D28g1gwj.js +1 -0
- package/dist/web/assets/DrawerContent-ChXgZ1Xm.js +1 -0
- package/dist/web/assets/FavoritesDrawer-CG9eI9Ay.css +1 -0
- package/dist/web/assets/FavoritesDrawer-D6QSiYaL.js +1 -0
- package/dist/web/assets/GatewayConvertDrawer-CuNlf7AC.css +1 -0
- package/dist/web/assets/GatewayConvertDrawer-RvET6iNG.js +1 -0
- package/dist/web/assets/Home-CSuFuJ9Y.css +1 -0
- package/dist/web/assets/Home-P8eseZcf.js +1 -0
- package/dist/web/assets/MarkdownEditor-CYmLGYju.js +1 -0
- package/dist/web/assets/MarkdownEditor-qfVgSre_.css +1 -0
- package/dist/web/assets/McpDrawer-C0dnsZhQ.css +1 -0
- package/dist/web/assets/McpDrawer-Ch3bkKIq.js +1 -0
- package/dist/web/assets/McpFormDrawer-BRbDcawn.css +1 -0
- package/dist/web/assets/McpFormDrawer-BcTlgSpN.js +1 -0
- package/dist/web/assets/PluginManager-Dh2o0xkZ.js +1 -0
- package/dist/web/assets/PluginsDrawer-DM3QjprE.css +1 -0
- package/dist/web/assets/PluginsDrawer-deKQ5u3I.js +1 -0
- package/dist/web/assets/PluginsPanel-BofsgQgj.js +1 -0
- package/dist/web/assets/PluginsPanel-D6ZqITcR.css +1 -0
- package/dist/web/assets/ProjectList-677RLZ8O.css +1 -0
- package/dist/web/assets/ProjectList-DhSWJHTA.js +1 -0
- package/dist/web/assets/PromptsDrawer-BIgiYCEQ.css +1 -0
- package/dist/web/assets/PromptsDrawer-Cfb2FeeU.js +1 -0
- package/dist/web/assets/RecentSessionsDrawer-3eXamJhr.js +1 -0
- package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +1 -0
- package/dist/web/assets/SessionCard-CW0eHURI.js +1 -0
- package/dist/web/assets/SessionCard-aM2NHu6i.css +1 -0
- package/dist/web/assets/SessionList-BpYRz1cX.css +1 -0
- package/dist/web/assets/SessionList-DQfyDGWU.js +1 -0
- package/dist/web/assets/SettingsDrawer-Dw5NUgHC.css +1 -0
- package/dist/web/assets/SettingsDrawer-u_vwUuPS.js +1 -0
- package/dist/web/assets/SkillManager-C0GCT2Kb.css +1 -0
- package/dist/web/assets/SkillManager-DHMprJLA.js +1 -0
- package/dist/web/assets/SkillsDrawer-BCNme-aJ.css +1 -0
- package/dist/web/assets/SkillsDrawer-CkF3BpyC.js +1 -0
- package/dist/web/assets/SkillsPanel-B3Nm5j32.css +1 -0
- package/dist/web/assets/SkillsPanel-DWE4pFGx.js +1 -0
- package/dist/web/assets/SpeedTestDrawer-BgfG1Ked.js +1 -0
- package/dist/web/assets/SpeedTestDrawer-Dc0WToJ_.css +1 -0
- package/dist/web/assets/Upload-CNwaGOws.js +1 -0
- package/dist/web/assets/WorkspaceDrawer-Br5CeCzL.js +1 -0
- package/dist/web/assets/WorkspaceDrawer-CGnMu9p1.css +1 -0
- package/dist/web/assets/WorkspaceManager-B2O8-qIw.js +1 -0
- package/dist/web/assets/WorkspacePanel-5oDKit3c.js +1 -0
- package/dist/web/assets/WorkspacePanel-D0-zHTHP.css +1 -0
- package/dist/web/assets/_plugin-vue_export-helper-BeLZJZij.js +1 -0
- package/dist/web/assets/client-UDwXBP9i.js +1 -0
- package/dist/web/assets/clipboard-B46yyoz_.js +1 -0
- package/dist/web/assets/headers-cf-QapUq.js +1 -0
- package/dist/web/assets/icons-B2Vg-IOC.js +1 -0
- package/dist/web/assets/index-BMAUPq5K.js +2 -0
- package/dist/web/assets/index-Bi1MQHYX.css +1 -0
- package/dist/web/assets/light-Cp0t7v32.js +1 -0
- package/dist/web/assets/markdown-u082bbtj.js +1 -0
- package/dist/web/assets/platforms-CBkB45JP.js +1 -0
- package/dist/web/assets/platforms-FTpjxAT6.js +1 -0
- package/dist/web/assets/project-config-B2baPzYL.js +1 -0
- package/dist/web/assets/sessions-Cmy31slD.js +1 -0
- package/dist/web/assets/sessions-yC_oVVh8.js +1 -0
- package/dist/web/assets/skill-repo-input-B_fkGlUK.js +1 -0
- package/dist/web/assets/use-lock-html-scroll-DXIqmUW4.js +1 -0
- package/dist/web/assets/use-message-DoLM8C1C.js +1 -0
- package/dist/web/assets/useResponsiveDrawer-jbmqZuJs.js +1 -0
- package/dist/web/assets/vendors-D0c_0KLP.js +1 -0
- package/dist/web/assets/vue-vendor-BqZbbXHA.js +1 -0
- package/dist/web/assets/workspaces-mjyPVGS8.js +1 -0
- package/dist/web/assets/xml-CgY3RMlX.js +1 -0
- package/dist/web/index.html +12 -8
- package/docs/native-log-memory-2026-09-16.md +43 -0
- package/docs/superpowers/plans/2026-08-26-configuration-driven-cli-platform.md +1578 -0
- package/docs/superpowers/plans/2026-08-30-project-scoped-config-control.md +1260 -0
- package/docs/superpowers/plans/2026-09-01-omp-skill-refresh-boundary.md +213 -0
- package/docs/superpowers/plans/2026-09-01-realtime-logs-panel.md +125 -0
- package/docs/superpowers/plans/2026-09-02-config-driven-platform-boundary.md +86 -0
- package/docs/superpowers/plans/2026-09-02-platform-implementation-drivers.md +508 -0
- package/docs/superpowers/plans/2026-09-03-cli-platform-correctness-boundary.md +760 -0
- package/docs/superpowers/plans/2026-09-03-dependency-security-remediation.md +133 -0
- package/docs/superpowers/plans/2026-09-04-model-catalog-pricing-sync.md +1078 -0
- package/docs/superpowers/plans/2026-09-05-codex-project-scan-500.md +128 -0
- package/docs/superpowers/plans/2026-09-06-project-skill-path-fix.md +97 -0
- package/docs/superpowers/specs/2026-08-26-configuration-driven-cli-platform-design.md +408 -0
- package/docs/superpowers/specs/2026-08-30-project-scoped-config-control-design.md +467 -0
- package/docs/superpowers/specs/2026-09-01-claude-session-content-repair-design.md +111 -0
- package/docs/superpowers/specs/2026-09-01-omp-skill-refresh-boundary-design.md +83 -0
- package/docs/superpowers/specs/2026-09-01-realtime-logs-panel-design.md +27 -0
- package/docs/superpowers/specs/2026-09-02-config-driven-platform-boundary-design.md +64 -0
- package/docs/superpowers/specs/2026-09-02-platform-implementation-driver-boundary-design.md +123 -0
- package/docs/superpowers/specs/2026-09-03-cli-platform-correctness-boundary-design.md +249 -0
- package/docs/superpowers/specs/2026-09-03-dependency-security-remediation-design.md +87 -0
- package/docs/superpowers/specs/2026-09-04-model-catalog-pricing-sync-design.md +301 -0
- package/docs/superpowers/specs/2026-09-05-codex-project-scan-500-design.md +24 -0
- package/package.json +8 -4
- package/src/commands/channels.js +88 -191
- package/src/commands/cli-type.js +19 -11
- package/src/commands/daemon.js +104 -32
- package/src/commands/doctor.js +16 -9
- package/src/commands/export-config.js +23 -5
- package/src/commands/list.js +130 -52
- package/src/commands/logs.js +44 -27
- package/src/commands/platform-command-registry.js +78 -0
- package/src/commands/plugin.js +11 -5
- package/src/commands/port-config.js +34 -52
- package/src/commands/proxy-control.js +207 -145
- package/src/commands/proxy.js +2 -2
- package/src/commands/resume.js +87 -91
- package/src/commands/search.js +137 -67
- package/src/commands/stats.js +30 -22
- package/src/commands/switch.js +1 -1
- package/src/commands/toggle-proxy.js +94 -111
- package/src/commands/ui.js +67 -6
- package/src/commands/workspace.js +90 -8
- package/src/config/default.js +6 -53
- package/src/config/loader.js +61 -24
- package/src/config/model-metadata.js +49 -59
- package/src/config/model-metadata.json +4095 -99
- package/src/config/paths.js +181 -8
- package/src/index.js +134 -71
- package/src/platforms/access.js +196 -0
- package/src/{server/services → platforms}/agents-service.js +354 -197
- package/src/platforms/channel-auth-registry.js +165 -0
- package/src/platforms/channel-auth-service.js +107 -0
- package/src/{server/services → platforms}/commands-service.js +195 -115
- package/src/platforms/driver-registry.js +59 -0
- package/src/platforms/drivers/claude/api-operations.js +62 -0
- package/src/{server/services/channels.js → platforms/drivers/claude/channels-implementation.js} +131 -33
- package/src/platforms/drivers/claude/channels.js +39 -0
- package/src/{server/services/config-sync-service.js → platforms/drivers/claude/config-sync.js} +29 -5
- package/src/{server/services → platforms/drivers/claude}/health-check.js +4 -4
- package/src/platforms/drivers/claude/health.js +22 -0
- package/src/platforms/drivers/claude/mcp.js +9 -0
- package/src/{server/services/settings-manager.js → platforms/drivers/claude/native-config-implementation.js} +13 -4
- package/src/platforms/drivers/claude/native-config.js +46 -0
- package/src/platforms/drivers/claude/native-logs.js +72 -0
- package/src/{server/services/claude-openai-gateway.js → platforms/drivers/claude/openai-gateway.js} +8 -65
- package/src/platforms/drivers/claude/project-config.js +21 -0
- package/src/platforms/drivers/claude/projects.js +62 -0
- package/src/platforms/drivers/claude/prompts.js +9 -0
- package/src/{server/proxy-server.js → platforms/drivers/claude/proxy-implementation.js} +41 -278
- package/src/platforms/drivers/claude/proxy.js +16 -0
- package/src/platforms/drivers/claude/resource-sync.js +9 -0
- package/src/platforms/drivers/claude/session-history-adapter.js +313 -0
- package/src/{server/services/sessions.js → platforms/drivers/claude/sessions-implementation.js} +145 -35
- package/src/platforms/drivers/claude/sessions.js +76 -0
- package/src/{server/services/claude-statistics-service.js → platforms/drivers/claude/statistics-implementation.js} +2 -2
- package/src/platforms/drivers/claude/statistics.js +16 -0
- package/src/{server/services/claude-wire.js → platforms/drivers/claude/wire.js} +1 -1
- package/src/platforms/drivers/codex/api-operations.js +9 -0
- package/src/{server/services/codex-channels.js → platforms/drivers/codex/channels-implementation.js} +149 -14
- package/src/platforms/drivers/codex/channels.js +45 -0
- package/src/{server/services/codex-config.js → platforms/drivers/codex/config.js} +12 -2
- package/src/{server/services/codex-env-manager.js → platforms/drivers/codex/env-manager.js} +1 -1
- package/src/platforms/drivers/codex/mcp.js +9 -0
- package/src/{server/services/codex-settings-manager.js → platforms/drivers/codex/native-config-implementation.js} +15 -6
- package/src/platforms/drivers/codex/native-config.js +47 -0
- package/src/platforms/drivers/codex/native-logs.js +166 -0
- package/src/platforms/drivers/codex/project-config.js +21 -0
- package/src/platforms/drivers/codex/projects.js +26 -0
- package/src/platforms/drivers/codex/prompts.js +9 -0
- package/src/{server/codex-proxy-server.js → platforms/drivers/codex/proxy-implementation.js} +30 -233
- package/src/platforms/drivers/codex/proxy.js +16 -0
- package/src/platforms/drivers/codex/resource-sync.js +9 -0
- package/src/{server/services/session-history-adapters/codex.js → platforms/drivers/codex/session-history-adapter.js} +37 -23
- package/src/{server/services/codex-sessions.js → platforms/drivers/codex/sessions-implementation.js} +81 -75
- package/src/platforms/drivers/codex/sessions.js +36 -0
- package/src/{server/services/codex-statistics-service.js → platforms/drivers/codex/statistics-implementation.js} +2 -2
- package/src/platforms/drivers/codex/statistics.js +16 -0
- package/src/platforms/drivers/gemini/api-operations.js +9 -0
- package/src/{server/services/gemini-channels.js → platforms/drivers/gemini/channels-implementation.js} +202 -37
- package/src/platforms/drivers/gemini/channels.js +39 -0
- package/src/{server/services/gemini-config.js → platforms/drivers/gemini/config.js} +12 -2
- package/src/platforms/drivers/gemini/mcp.js +9 -0
- package/src/{server/services/gemini-settings-manager.js → platforms/drivers/gemini/native-config-implementation.js} +14 -5
- package/src/platforms/drivers/gemini/native-config.js +39 -0
- package/src/platforms/drivers/gemini/native-logs.js +180 -0
- package/src/platforms/drivers/gemini/project-config.js +21 -0
- package/src/platforms/drivers/gemini/projects.js +26 -0
- package/src/platforms/drivers/gemini/prompts.js +9 -0
- package/src/{server/gemini-proxy-server.js → platforms/drivers/gemini/proxy-implementation.js} +36 -267
- package/src/platforms/drivers/gemini/proxy.js +16 -0
- package/src/platforms/drivers/gemini/resource-sync.js +9 -0
- package/src/{server/services/session-history-adapters/gemini.js → platforms/drivers/gemini/session-history-adapter.js} +70 -18
- package/src/{server/services/gemini-sessions.js → platforms/drivers/gemini/sessions-implementation.js} +53 -37
- package/src/platforms/drivers/gemini/sessions.js +47 -0
- package/src/{server/services/gemini-statistics-service.js → platforms/drivers/gemini/statistics-implementation.js} +2 -2
- package/src/platforms/drivers/gemini/statistics.js +16 -0
- package/src/{server/services/gemini-wire.js → platforms/drivers/gemini/wire.js} +1 -1
- package/src/platforms/drivers/generic-filesystem.js +166 -0
- package/src/platforms/drivers/generic-jsonl.js +141 -0
- package/src/platforms/drivers/generic-mcp.js +44 -0
- package/src/platforms/drivers/generic-openai-compatible.js +45 -0
- package/src/platforms/drivers/generic-prompt.js +41 -0
- package/src/platforms/drivers/legacy.js +677 -0
- package/src/platforms/drivers/native-config-snapshot.js +125 -0
- package/src/platforms/drivers/native-log-utils.js +1292 -0
- package/src/platforms/drivers/notification-hooks.js +578 -0
- package/src/{server/api/omp-config.js → platforms/drivers/omp/api-operations.js} +52 -64
- package/src/{server/services/omp-auth-provider-worker.js → platforms/drivers/omp/auth-provider-worker.js} +1 -1
- package/src/{server/services/omp-auth-providers.js → platforms/drivers/omp/auth-providers.js} +1 -1
- package/src/{server/services/omp-channels.js → platforms/drivers/omp/channels-implementation.js} +166 -39
- package/src/platforms/drivers/omp/channels.js +58 -0
- package/src/{server/services/omp-config.js → platforms/drivers/omp/config.js} +53 -13
- package/src/{server/services/omp-gateway-routing.js → platforms/drivers/omp/gateway-routing.js} +14 -7
- package/src/{server/services/omp-gateway.js → platforms/drivers/omp/gateway.js} +4 -262
- package/src/platforms/drivers/omp/mcp.js +9 -0
- package/src/{server/services/omp-settings-manager.js → platforms/drivers/omp/native-config-implementation.js} +75 -10
- package/src/platforms/drivers/omp/native-config.js +46 -0
- package/src/platforms/drivers/omp/native-logs.js +52 -0
- package/src/{server/services/omp-native-plugin-adapter.js → platforms/drivers/omp/native-plugin-adapter.js} +91 -4
- package/src/platforms/drivers/omp/project-config.js +29 -0
- package/src/platforms/drivers/omp/projects.js +20 -0
- package/src/platforms/drivers/omp/prompts.js +9 -0
- package/src/{server/omp-proxy-server.js → platforms/drivers/omp/proxy-implementation.js} +6 -15
- package/src/platforms/drivers/omp/proxy.js +16 -0
- package/src/platforms/drivers/omp/resource-sync.js +9 -0
- package/src/{server/services/session-history-adapters/omp.js → platforms/drivers/omp/session-history-adapter.js} +42 -18
- package/src/{server/services/omp-sessions.js → platforms/drivers/omp/sessions-implementation.js} +130 -94
- package/src/platforms/drivers/omp/sessions.js +36 -0
- package/src/{server/services/omp-skill-discovery.js → platforms/drivers/omp/skill-discovery.js} +159 -32
- package/src/{server/services/omp-skill-settings-service.js → platforms/drivers/omp/skill-settings.js} +1 -1
- package/src/{server/services/omp-statistics-service.js → platforms/drivers/omp/statistics-implementation.js} +3 -3
- package/src/platforms/drivers/omp/statistics.js +16 -0
- package/src/platforms/drivers/opencode/api-operations.js +9 -0
- package/src/{server/services/opencode-channels.js → platforms/drivers/opencode/channels-implementation.js} +28 -9
- package/src/platforms/drivers/opencode/channels.js +40 -0
- package/src/platforms/drivers/opencode/conversion.js +41 -0
- package/src/{server/services/opencode-gateway-converter.js → platforms/drivers/opencode/gateway-converter.js} +1 -1
- package/src/platforms/drivers/opencode/mcp.js +9 -0
- package/src/{server/services/opencode-settings-manager.js → platforms/drivers/opencode/native-config-implementation.js} +17 -6
- package/src/platforms/drivers/opencode/native-config.js +26 -0
- package/src/platforms/drivers/opencode/native-logs.js +133 -0
- package/src/platforms/drivers/opencode/project-config.js +98 -0
- package/src/platforms/drivers/opencode/projects.js +20 -0
- package/src/platforms/drivers/opencode/prompts.js +9 -0
- package/src/{server/opencode-proxy-server.js → platforms/drivers/opencode/proxy-implementation.js} +27 -362
- package/src/platforms/drivers/opencode/proxy.js +16 -0
- package/src/platforms/drivers/opencode/resource-sync.js +9 -0
- package/src/{server/services/opencode-sessions.js → platforms/drivers/opencode/sessions-implementation.js} +211 -64
- package/src/platforms/drivers/opencode/sessions.js +48 -0
- package/src/{server/services/opencode-statistics-service.js → platforms/drivers/opencode/statistics-implementation.js} +2 -2
- package/src/platforms/drivers/opencode/statistics.js +16 -0
- package/src/platforms/drivers/secure-file-driver.js +272 -0
- package/src/platforms/drivers/unsupported.js +7 -0
- package/src/platforms/manifest-schema.js +398 -0
- package/src/platforms/manifests/claude.json +489 -0
- package/src/platforms/manifests/codex.json +448 -0
- package/src/platforms/manifests/gemini.json +447 -0
- package/src/platforms/manifests/omp.json +496 -0
- package/src/platforms/manifests/opencode.json +422 -0
- package/src/{server/services → platforms}/native-oauth-adapters.js +98 -418
- package/src/{server/services → platforms}/notification-hooks.js +190 -1023
- package/src/platforms/oauth-credentials-service.js +635 -0
- package/src/platforms/path-resolver.js +179 -0
- package/src/platforms/platform-path-context.js +305 -0
- package/src/platforms/registry.js +248 -0
- package/src/platforms/remote-notification-providers.js +678 -0
- package/src/platforms/runtime.js +259 -0
- package/src/{server/services/session-history-adapters/index.js → platforms/session-history-adapters.js} +8 -1
- package/src/plugins/plugin-loader.js +2 -2
- package/src/plugins/plugin-manager.js +2 -2
- package/src/plugins/registry.js +27 -10
- package/src/reset-config.js +21 -5
- package/src/server/api/agents.js +46 -72
- package/src/server/api/commands.js +16 -6
- package/src/server/api/config-registry.js +206 -59
- package/src/server/api/config-sync.js +3 -2
- package/src/server/api/config-templates.js +20 -4
- package/src/server/api/config.js +111 -102
- package/src/server/api/convert.js +54 -178
- package/src/server/api/dashboard.js +168 -102
- package/src/server/api/hooks.js +1 -1
- package/src/server/api/mcp.js +224 -84
- package/src/server/api/platform-api-config.js +102 -0
- package/src/server/api/platform-route-factory.js +215 -0
- package/src/server/api/platform-routes.js +26 -0
- package/src/server/api/platforms.js +110 -0
- package/src/server/api/plugins.js +57 -57
- package/src/server/api/project-config.js +168 -0
- package/src/server/api/prompts.js +58 -45
- package/src/server/api/settings.js +55 -8
- package/src/server/api/skills.js +262 -133
- package/src/server/api/ui-config.js +2 -2
- package/src/server/api/validation-errors.js +18 -4
- package/src/server/api/workspaces.js +47 -12
- package/src/server/index.js +164 -213
- package/src/server/platform-context.js +81 -0
- package/src/server/services/channel-balance.js +133 -24
- package/src/server/services/channel-health.js +21 -6
- package/src/server/services/channel-scheduler.js +29 -39
- package/src/server/services/channel-sync-utils.js +23 -13
- package/src/server/services/config-export-service.js +350 -319
- package/src/server/services/config-registry-service.js +280 -54
- package/src/server/services/config-sync-manager.js +172 -944
- package/src/server/services/config-templates-service.js +419 -353
- package/src/server/services/control-manifest-store.js +206 -0
- package/src/server/services/dashboard-snapshot-worker.js +656 -100
- package/src/server/services/effective-control-service.js +557 -0
- package/src/server/services/local-resource-index.js +314 -0
- package/src/server/services/mcp-service.js +607 -977
- package/src/server/services/model-detector.js +15 -10
- package/src/server/services/native-log-channel-resolver.js +214 -0
- package/src/server/services/native-log-observer.js +291 -0
- package/src/server/services/network-access.js +12 -2
- package/src/server/services/platform-catalog.js +82 -0
- package/src/server/services/platform-resolution.js +32 -29
- package/src/server/services/plugins-service.js +376 -122
- package/src/server/services/project-config-service.js +550 -0
- package/src/server/services/project-path-validation.js +31 -0
- package/src/server/services/prompts-service.js +267 -233
- package/src/server/services/proxy-runtime.js +7 -4
- package/src/server/services/remote-credential-cache.js +43 -0
- package/src/server/services/repo-scanner-base.js +182 -75
- package/src/server/services/request-logger.js +7 -4
- package/src/server/services/session-history-index.js +876 -214
- package/src/server/services/session-history-worker.js +228 -33
- package/src/server/services/session-snapshot-worker.js +124 -34
- package/src/server/services/session-snapshots.js +4 -2
- package/src/server/services/skill-artifact-store.js +355 -0
- package/src/server/services/skill-format-adapters.js +65 -0
- package/src/server/services/skill-projection-service.js +323 -0
- package/src/server/services/skill-refresh-task-service.js +275 -0
- package/src/server/services/skill-service.js +2020 -677
- package/src/server/services/snapshot-cache.js +30 -8
- package/src/server/services/speed-test.js +8 -8
- package/src/server/services/sqlite-connection.js +19 -3
- package/src/server/services/statistics-service.js +240 -57
- package/src/server/services/ui-config.js +107 -76
- package/src/server/services/usage-log-utils.js +98 -0
- package/src/server/services/web-build.js +1 -1
- package/src/server/services/workspace-service.js +59 -29
- package/src/server/utils/pricing.js +10 -19
- package/src/server/websocket-server.js +153 -28
- package/src/{server/services/base → shared}/base-channel-service.js +156 -28
- package/src/shared/capability-driver.js +104 -0
- package/src/shared/channel-auth-policy.js +27 -0
- package/src/shared/channel-driver.js +161 -0
- package/src/shared/driver-factories/api.js +180 -0
- package/src/shared/driver-factories/mcp.js +244 -0
- package/src/shared/driver-factories/projects.js +121 -0
- package/src/shared/driver-factories/prompts.js +58 -0
- package/src/shared/driver-factories/resource-sync.js +375 -0
- package/src/shared/driver-result.js +78 -0
- package/src/shared/mcp-format.js +189 -0
- package/src/shared/platforms.js +104 -167
- package/src/shared/project-config.js +512 -0
- package/src/shared/proxy-driver.js +57 -0
- package/src/{server/services/base → shared}/response-usage-parser.js +8 -4
- package/src/ui/menu.js +91 -67
- package/src/utils/port-helper.js +35 -19
- package/src/utils/session.js +1 -1
- package/dist/web/assets/Analytics-COEUXmd4.js +0 -25
- package/dist/web/assets/Analytics-RNn1BUbG.css +0 -1
- package/dist/web/assets/ConfigTemplates-DLLkS53H.js +0 -1
- package/dist/web/assets/Home-DCEyLzwX.js +0 -1
- package/dist/web/assets/Home-DYVy4cGZ.css +0 -1
- package/dist/web/assets/PluginManager-Oe1ZHoMO.js +0 -1
- package/dist/web/assets/ProjectList-CWjuAFof.js +0 -1
- package/dist/web/assets/ProjectList-VeMNXfgO.css +0 -1
- package/dist/web/assets/SessionList-C4chCPxK.css +0 -1
- package/dist/web/assets/SessionList-v3ehGg9U.js +0 -1
- package/dist/web/assets/SkillManager-BsX8Qpj0.css +0 -1
- package/dist/web/assets/SkillManager-DUF_qP5S.js +0 -1
- package/dist/web/assets/WorkspaceManager-CjAWBosO.js +0 -1
- package/dist/web/assets/icons-nGdSKQn2.js +0 -1
- package/dist/web/assets/index-D5hyHPj7.js +0 -2
- package/dist/web/assets/index-bJRG3RXH.css +0 -1
- package/dist/web/assets/markdown-BNJfEgCA.js +0 -1
- package/dist/web/assets/markdown-BfC0goYb.css +0 -10
- package/dist/web/assets/naive-ui-BALVpMgd.js +0 -1
- package/dist/web/assets/vendors-DQA4Hw9v.js +0 -7
- package/dist/web/assets/vue-vendor-B5RqjEjQ.js +0 -45
- package/src/config/model-pricing.js +0 -35
- package/src/server/api/channels.js +0 -439
- package/src/server/api/claude-hooks.js +0 -56
- package/src/server/api/claude-statistics.js +0 -57
- package/src/server/api/codex-channels.js +0 -491
- package/src/server/api/codex-projects.js +0 -117
- package/src/server/api/codex-proxy.js +0 -293
- package/src/server/api/codex-sessions.js +0 -652
- package/src/server/api/codex-statistics.js +0 -57
- package/src/server/api/gemini-channels.js +0 -392
- package/src/server/api/gemini-projects.js +0 -103
- package/src/server/api/gemini-proxy.js +0 -231
- package/src/server/api/gemini-sessions.js +0 -550
- package/src/server/api/gemini-statistics.js +0 -57
- package/src/server/api/health-check.js +0 -31
- package/src/server/api/oauth-credentials.js +0 -198
- package/src/server/api/omp-channels.js +0 -575
- package/src/server/api/omp-projects.js +0 -88
- package/src/server/api/omp-proxy.js +0 -125
- package/src/server/api/omp-sessions.js +0 -386
- package/src/server/api/omp-statistics.js +0 -40
- package/src/server/api/opencode-channels.js +0 -471
- package/src/server/api/opencode-projects.js +0 -110
- package/src/server/api/opencode-proxy.js +0 -354
- package/src/server/api/opencode-sessions.js +0 -466
- package/src/server/api/opencode-statistics.js +0 -57
- package/src/server/api/projects.js +0 -120
- package/src/server/api/proxy.js +0 -330
- package/src/server/api/sessions.js +0 -810
- package/src/server/services/oauth-credentials-service.js +0 -945
- package/src/server/services/omp-session-log-observer.js +0 -138
- package/src/server/services/opencode-gateway-adapters.js +0 -43
- package/src/server/services/project-snapshots.js +0 -59
- package/src/server/services/proxy-log-helper.js +0 -298
- package/src/server/services/session-cache.js +0 -127
- package/src/server/services/session-converter.js +0 -582
- package/src/server/services/session-history-adapters/claude.js +0 -235
- /package/src/{server/services/claude-token-recovery.js → platforms/drivers/claude/token-recovery.js} +0 -0
- /package/src/{server/services/codex-parser.js → platforms/drivers/codex/parser.js} +0 -0
- /package/src/{server/services/codex-speed-test-template.json → platforms/drivers/codex/speed-test-template.json} +0 -0
- /package/src/{server/services/codex-wire.js → platforms/drivers/codex/wire.js} +0 -0
- /package/src/{server/services/omp-auth-gateway-client.js → platforms/drivers/omp/auth-gateway-client.js} +0 -0
- /package/src/{server/services/opencode-normalization.js → platforms/drivers/opencode/normalization.js} +0 -0
- /package/src/{server/services → shared}/config-artifact-paths.js +0 -0
- /package/src/{server/services/base → shared}/proxy-utils.js +0 -0
|
@@ -4,10 +4,48 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const crypto = require('crypto');
|
|
6
6
|
const { HOME_DIR } = require('../../../config/paths');
|
|
7
|
-
const { getGeminiDir } = require('
|
|
7
|
+
const { getGeminiDir } = require('./config');
|
|
8
8
|
|
|
9
9
|
const HASH_RE = /^[a-f0-9]{64}$/;
|
|
10
10
|
const SESSION_FILE_RE = /^session-(.*)-([a-f0-9]+)\.(json|jsonl)$/;
|
|
11
|
+
const DESCRIPTOR_HEADER_BYTES = 64 * 1024;
|
|
12
|
+
|
|
13
|
+
function configure({ pathContext } = {}) {
|
|
14
|
+
require('./config').configure?.({ pathContext });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function readDescriptorMetadata(filePath, size) {
|
|
18
|
+
let fd;
|
|
19
|
+
try {
|
|
20
|
+
fd = fs.openSync(filePath, 'r');
|
|
21
|
+
const buffer = Buffer.alloc(Math.min(Math.max(Number(size) || 0, 1), DESCRIPTOR_HEADER_BYTES));
|
|
22
|
+
const bytesRead = fs.readSync(fd, buffer, 0, buffer.length, 0);
|
|
23
|
+
const chunk = buffer.toString('utf8', 0, bytesRead);
|
|
24
|
+
let state = null;
|
|
25
|
+
try {
|
|
26
|
+
const parsed = JSON.parse(chunk);
|
|
27
|
+
state = parsed?.$set || parsed;
|
|
28
|
+
} catch (_) {
|
|
29
|
+
const firstLine = chunk.split(/\r?\n/, 1)[0];
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(firstLine);
|
|
32
|
+
state = parsed?.$set || parsed;
|
|
33
|
+
} catch (_) {}
|
|
34
|
+
}
|
|
35
|
+
if (!state || typeof state !== 'object') return {};
|
|
36
|
+
return {
|
|
37
|
+
sessionId: state.sessionId || state.id || null,
|
|
38
|
+
projectHash: state.projectHash || state.project_hash || null,
|
|
39
|
+
projectPath: state.projectPath || state.project_path || state.cwd || null
|
|
40
|
+
};
|
|
41
|
+
} catch (_) {
|
|
42
|
+
return {};
|
|
43
|
+
} finally {
|
|
44
|
+
if (fd !== undefined) {
|
|
45
|
+
try { fs.closeSync(fd); } catch (_) {}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
11
49
|
|
|
12
50
|
/**
|
|
13
51
|
* Extract text content from Gemini message parts.
|
|
@@ -30,10 +68,10 @@ function extractContentText(value) {
|
|
|
30
68
|
/**
|
|
31
69
|
* Load storage-name → project root mapping from projects.json.
|
|
32
70
|
*/
|
|
33
|
-
function loadProjectRootsByStorageName() {
|
|
71
|
+
async function loadProjectRootsByStorageName() {
|
|
34
72
|
const projectsPath = path.join(getGeminiDir(), 'projects.json');
|
|
35
73
|
try {
|
|
36
|
-
const content = fs.
|
|
74
|
+
const content = await fs.promises.readFile(projectsPath, 'utf8');
|
|
37
75
|
const parsed = JSON.parse(content);
|
|
38
76
|
const projects = parsed && typeof parsed.projects === 'object' ? parsed.projects : {};
|
|
39
77
|
return new Map(
|
|
@@ -122,7 +160,7 @@ function parseSessionContentFromState(state, sessionId) {
|
|
|
122
160
|
const meta = {
|
|
123
161
|
sessionId: state.sessionId || state.id || sessionId,
|
|
124
162
|
projectHash: state.projectHash || state.project_hash || null,
|
|
125
|
-
projectPath: state.projectPath || state.project_path || null,
|
|
163
|
+
projectPath: state.projectPath || state.project_path || state.cwd || null,
|
|
126
164
|
lastUpdated: state.lastUpdated || state.last_updated || null,
|
|
127
165
|
messages: state.messages || []
|
|
128
166
|
};
|
|
@@ -194,12 +232,16 @@ async function inventory() {
|
|
|
194
232
|
const descriptors = [];
|
|
195
233
|
const tmpDir = path.join(getGeminiDir(), 'tmp');
|
|
196
234
|
|
|
197
|
-
|
|
235
|
+
try {
|
|
236
|
+
await fs.promises.stat(tmpDir);
|
|
237
|
+
} catch (_) {
|
|
238
|
+
return descriptors;
|
|
239
|
+
}
|
|
198
240
|
|
|
199
|
-
const projectRoots = loadProjectRootsByStorageName();
|
|
241
|
+
const projectRoots = await loadProjectRootsByStorageName();
|
|
200
242
|
let entries;
|
|
201
243
|
try {
|
|
202
|
-
entries = fs.
|
|
244
|
+
entries = await fs.promises.readdir(tmpDir, { withFileTypes: true });
|
|
203
245
|
} catch (_) {
|
|
204
246
|
return descriptors;
|
|
205
247
|
}
|
|
@@ -208,11 +250,15 @@ async function inventory() {
|
|
|
208
250
|
if (!entry.isDirectory()) continue;
|
|
209
251
|
const hashDir = path.join(tmpDir, entry.name);
|
|
210
252
|
const chatsDir = path.join(hashDir, 'chats');
|
|
211
|
-
|
|
253
|
+
try {
|
|
254
|
+
await fs.promises.stat(chatsDir);
|
|
255
|
+
} catch (_) {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
212
258
|
|
|
213
259
|
let chatFiles;
|
|
214
260
|
try {
|
|
215
|
-
chatFiles = fs.
|
|
261
|
+
chatFiles = await fs.promises.readdir(chatsDir);
|
|
216
262
|
} catch (_) {
|
|
217
263
|
continue;
|
|
218
264
|
}
|
|
@@ -223,24 +269,27 @@ async function inventory() {
|
|
|
223
269
|
const filePath = path.join(chatsDir, f);
|
|
224
270
|
let stat;
|
|
225
271
|
try {
|
|
226
|
-
stat = fs.
|
|
272
|
+
stat = await fs.promises.stat(filePath);
|
|
227
273
|
} catch (_) {
|
|
228
274
|
continue;
|
|
229
275
|
}
|
|
230
|
-
const
|
|
276
|
+
const header = readDescriptorMetadata(filePath, stat.size);
|
|
277
|
+
let projectRoot = projectRoots.get(entry.name) || null;
|
|
278
|
+
if (!projectRoot) {
|
|
231
279
|
try {
|
|
232
|
-
|
|
280
|
+
projectRoot = (await fs.promises.readFile(path.join(hashDir, '.project_root'), 'utf8')).trim() || null;
|
|
233
281
|
} catch (_) {
|
|
234
|
-
|
|
282
|
+
projectRoot = null;
|
|
235
283
|
}
|
|
236
|
-
}
|
|
284
|
+
}
|
|
285
|
+
projectRoot = header.projectPath || projectRoot;
|
|
237
286
|
|
|
238
287
|
descriptors.push({
|
|
239
288
|
filePath,
|
|
240
289
|
size: stat.size,
|
|
241
290
|
mtimeMs: stat.mtimeMs,
|
|
242
|
-
sessionId: match[1],
|
|
243
|
-
projectName: projectRoot ? getFilePathHash(projectRoot) : entry.name,
|
|
291
|
+
sessionId: header.sessionId || match[2] || match[1],
|
|
292
|
+
projectName: header.projectHash || (projectRoot ? getFilePathHash(projectRoot) : entry.name),
|
|
244
293
|
projectRoot
|
|
245
294
|
});
|
|
246
295
|
}
|
|
@@ -257,8 +306,11 @@ async function parse(descriptor) {
|
|
|
257
306
|
|
|
258
307
|
const { messages, meta } = parseSessionContent(filePath, sessionId);
|
|
259
308
|
const resolvedSessionId = meta.sessionId || sessionId;
|
|
260
|
-
const resolvedProjectName = meta.projectHash || projectName || 'unknown';
|
|
261
309
|
const resolvedProjectPath = meta.projectPath || projectRoot || null;
|
|
310
|
+
const resolvedProjectName = meta.projectHash
|
|
311
|
+
|| (resolvedProjectPath ? getFilePathHash(resolvedProjectPath) : null)
|
|
312
|
+
|| projectName
|
|
313
|
+
|| 'unknown';
|
|
262
314
|
const firstUserMsg = messages.find(m => m.role === 'user' && m.content);
|
|
263
315
|
const usage = messages.reduce((total, message) => {
|
|
264
316
|
const value = message.usage || {};
|
|
@@ -289,4 +341,4 @@ async function parse(descriptor) {
|
|
|
289
341
|
return { session, messages };
|
|
290
342
|
}
|
|
291
343
|
|
|
292
|
-
module.exports = { inventory, parse, extractContentText, normalizeMessageRecord, parseSessionContent };
|
|
344
|
+
module.exports = { configure, inventory, parse, extractContentText, normalizeMessageRecord, parseSessionContent };
|
|
@@ -1,10 +1,31 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const crypto = require('crypto');
|
|
4
|
-
const { HOME_DIR } = require('
|
|
5
|
-
const { getGeminiDir } = require('./
|
|
6
|
-
const {
|
|
7
|
-
const {
|
|
4
|
+
const { HOME_DIR } = require('../../../config/paths');
|
|
5
|
+
const { getGeminiDir } = require('./config');
|
|
6
|
+
const { normalizeUsageTokens } = require('../../../server/services/usage-log-utils');
|
|
7
|
+
const { resolveModelPricing, calculateTokenCost } = require('../../../server/utils/pricing');
|
|
8
|
+
let sessionHistoryIndex = null;
|
|
9
|
+
let geminiDirOverride = null;
|
|
10
|
+
|
|
11
|
+
function configure({ sessionHistoryIndex: index, pathContext } = {}) {
|
|
12
|
+
sessionHistoryIndex = index || null;
|
|
13
|
+
geminiDirOverride = pathContext?.customized ? (pathContext.native?.dir || null) : null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getSessionHistoryIndex(options = {}) {
|
|
17
|
+
if (!sessionHistoryIndex) {
|
|
18
|
+
const { getDefaultDependencies } = require('../../../platforms/runtime');
|
|
19
|
+
sessionHistoryIndex = getDefaultDependencies().sessionHistoryIndex;
|
|
20
|
+
if (!sessionHistoryIndex) {
|
|
21
|
+
const indexModule = require('../../../server/services/session-history-index');
|
|
22
|
+
sessionHistoryIndex = Object.keys(options).length > 0
|
|
23
|
+
? indexModule.createSessionHistoryIndex({ config: options })
|
|
24
|
+
: indexModule;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return sessionHistoryIndex;
|
|
28
|
+
}
|
|
8
29
|
|
|
9
30
|
const HASH_RE = /^[a-f0-9]{64}$/;
|
|
10
31
|
const SESSION_FILE_RE = /^session-(.*)-([a-f0-9]+)\.(json|jsonl)$/;
|
|
@@ -18,7 +39,7 @@ const PATH_MAPPING_CACHE_TTL = 60000; // 1分钟缓存
|
|
|
18
39
|
* 获取 Gemini tmp 目录(包含所有项目)
|
|
19
40
|
*/
|
|
20
41
|
function getTmpDir() {
|
|
21
|
-
return path.join(getGeminiDir(), 'tmp');
|
|
42
|
+
return path.join(geminiDirOverride || getGeminiDir(), 'tmp');
|
|
22
43
|
}
|
|
23
44
|
|
|
24
45
|
/**
|
|
@@ -52,7 +73,7 @@ function readProjectRootFile(projectDir) {
|
|
|
52
73
|
}
|
|
53
74
|
|
|
54
75
|
function loadProjectRootsByStorageName() {
|
|
55
|
-
const projectsPath = path.join(getGeminiDir(), 'projects.json');
|
|
76
|
+
const projectsPath = path.join(geminiDirOverride || getGeminiDir(), 'projects.json');
|
|
56
77
|
const content = readTextFile(projectsPath);
|
|
57
78
|
if (!content) {
|
|
58
79
|
return new Map();
|
|
@@ -487,17 +508,15 @@ function readSessionMeta(filePath) {
|
|
|
487
508
|
|
|
488
509
|
messages.forEach(msg => {
|
|
489
510
|
if (msg.tokens) {
|
|
490
|
-
|
|
511
|
+
const tokens = normalizeUsageTokens('gemini', msg.tokens);
|
|
512
|
+
totalTokens += tokens.total || 0;
|
|
491
513
|
|
|
492
|
-
// 计算成本(简化版本,使用 gemini-2.5-pro 的定价)
|
|
493
514
|
if (msg.model) {
|
|
494
515
|
model = msg.model;
|
|
495
|
-
const inputTokens = msg.tokens.input || 0;
|
|
496
|
-
const outputTokens = msg.tokens.output || 0;
|
|
497
516
|
const pricing = resolveModelPricing('gemini', msg.model);
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
517
|
+
totalCost += calculateTokenCost(pricing, tokens, {
|
|
518
|
+
reasoningBilledAsOutput: true
|
|
519
|
+
});
|
|
501
520
|
}
|
|
502
521
|
}
|
|
503
522
|
});
|
|
@@ -630,7 +649,7 @@ function getProjectPath(projectHash, options = {}) {
|
|
|
630
649
|
* @returns {Array} 项目对象数组
|
|
631
650
|
*/
|
|
632
651
|
async function getProjects(options = {}) {
|
|
633
|
-
const projects = await
|
|
652
|
+
const projects = await getSessionHistoryIndex().listProjects('gemini', options);
|
|
634
653
|
const paths = buildPathMapping();
|
|
635
654
|
return projects.map(project => {
|
|
636
655
|
const fullPath = project.fullPath || paths.get(project.name) || null;
|
|
@@ -651,7 +670,7 @@ async function getProjects(options = {}) {
|
|
|
651
670
|
* @returns {Array} 会话对象数组
|
|
652
671
|
*/
|
|
653
672
|
async function getProjectSessions(projectHash, options = {}) {
|
|
654
|
-
const indexed = await
|
|
673
|
+
const indexed = await getSessionHistoryIndex().listSessions('gemini', projectHash, options);
|
|
655
674
|
return indexed.map(session => ({
|
|
656
675
|
sessionId: session.sessionId,
|
|
657
676
|
mtime: new Date(session.mtime).toISOString(),
|
|
@@ -677,7 +696,7 @@ async function getProjectSessions(projectHash, options = {}) {
|
|
|
677
696
|
* @returns {Object|null} 完整会话数据
|
|
678
697
|
*/
|
|
679
698
|
async function getSession(sessionId) {
|
|
680
|
-
const status = await
|
|
699
|
+
const status = await getSessionHistoryIndex().getSessionStatus('gemini', sessionId);
|
|
681
700
|
return status ? readSessionFull(status.filePath) : null;
|
|
682
701
|
}
|
|
683
702
|
|
|
@@ -696,6 +715,7 @@ function deleteSession(sessionId) {
|
|
|
696
715
|
|
|
697
716
|
try {
|
|
698
717
|
fs.unlinkSync(session.filePath);
|
|
718
|
+
getSessionHistoryIndex().invalidateSource('gemini');
|
|
699
719
|
return { success: true, sessionId };
|
|
700
720
|
} catch (err) {
|
|
701
721
|
throw new Error('Failed to delete session: ' + err.message);
|
|
@@ -718,6 +738,7 @@ function deleteProject(projectHash) {
|
|
|
718
738
|
|
|
719
739
|
try {
|
|
720
740
|
fs.rmSync(projectDir, { recursive: true, force: true });
|
|
741
|
+
getSessionHistoryIndex().invalidateSource('gemini', { projectName: projectHash });
|
|
721
742
|
return { success: true, projectHash };
|
|
722
743
|
} catch (err) {
|
|
723
744
|
throw new Error('Failed to delete project: ' + err.message);
|
|
@@ -740,7 +761,7 @@ function saveProjectOrder(order) {
|
|
|
740
761
|
* @returns {Array} 会话对象数组
|
|
741
762
|
*/
|
|
742
763
|
async function getRecentSessions(limit = 5) {
|
|
743
|
-
const sessions = await
|
|
764
|
+
const sessions = await getSessionHistoryIndex().getRecentSessions('gemini', limit);
|
|
744
765
|
return sessions.map(session => ({
|
|
745
766
|
...session,
|
|
746
767
|
mtime: new Date(session.mtime).toISOString(),
|
|
@@ -754,7 +775,7 @@ async function getRecentSessions(limit = 5) {
|
|
|
754
775
|
* @returns {Object|null} 完整会话数据
|
|
755
776
|
*/
|
|
756
777
|
async function getSessionById(sessionId) {
|
|
757
|
-
const status = await
|
|
778
|
+
const status = await getSessionHistoryIndex().getSessionStatus('gemini', sessionId);
|
|
758
779
|
if (!status) return null;
|
|
759
780
|
const fullSession = readSessionFull(status.filePath);
|
|
760
781
|
if (!fullSession) return null;
|
|
@@ -773,8 +794,11 @@ async function getSessionById(sessionId) {
|
|
|
773
794
|
* @param {number} contextLength - 上下文长度(可选)
|
|
774
795
|
* @returns {Array} 搜索结果数组
|
|
775
796
|
*/
|
|
776
|
-
async function searchSessions(keyword, contextLength = 35) {
|
|
777
|
-
const results = await
|
|
797
|
+
async function searchSessions(keyword, contextLength = 35, options = {}) {
|
|
798
|
+
const results = await getSessionHistoryIndex().searchSessions('gemini', keyword, {
|
|
799
|
+
...options,
|
|
800
|
+
contextLength
|
|
801
|
+
});
|
|
778
802
|
return results.map(result => ({
|
|
779
803
|
sessionId: result.sessionId,
|
|
780
804
|
projectHash: result.projectName,
|
|
@@ -879,10 +903,11 @@ function forkSession(sessionId, options = {}) {
|
|
|
879
903
|
fs.writeFileSync(newFilePath, JSON.stringify(newSession, null, 2), 'utf8');
|
|
880
904
|
}
|
|
881
905
|
if (options.alias) {
|
|
882
|
-
const { setAlias } = require('
|
|
906
|
+
const { setAlias } = require('../../../server/services/alias');
|
|
883
907
|
setAlias(newSessionId, options.alias);
|
|
884
908
|
}
|
|
885
909
|
|
|
910
|
+
getSessionHistoryIndex(options).invalidateSource('gemini');
|
|
886
911
|
return {
|
|
887
912
|
success: true,
|
|
888
913
|
sessionId: newSessionId,
|
|
@@ -899,25 +924,16 @@ function forkSession(sessionId, options = {}) {
|
|
|
899
924
|
/**
|
|
900
925
|
* 获取 Gemini 项目与会话数量(仪表盘轻量统计)
|
|
901
926
|
*/
|
|
902
|
-
function getProjectAndSessionCounts() {
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
projectHashes.add(resolveProjectHashForEntry(entry));
|
|
909
|
-
sessionCount += scanEntrySessionFiles(entry).length;
|
|
910
|
-
});
|
|
911
|
-
return {
|
|
912
|
-
projectCount: Array.from(projectHashes).filter(Boolean).length,
|
|
913
|
-
sessionCount
|
|
914
|
-
};
|
|
915
|
-
} catch (err) {
|
|
916
|
-
return { projectCount: 0, sessionCount: 0 };
|
|
917
|
-
}
|
|
927
|
+
async function getProjectAndSessionCounts(options = {}) {
|
|
928
|
+
const projects = await getSessionHistoryIndex().listProjects('gemini', options);
|
|
929
|
+
return {
|
|
930
|
+
projectCount: projects.length,
|
|
931
|
+
sessionCount: projects.reduce((sum, project) => sum + (project.sessionCount || 0), 0)
|
|
932
|
+
};
|
|
918
933
|
}
|
|
919
934
|
|
|
920
935
|
module.exports = {
|
|
936
|
+
configure,
|
|
921
937
|
getAllSessions,
|
|
922
938
|
getProjects,
|
|
923
939
|
getProjectSessions,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { createCapabilityDriver } = require('../../../shared/capability-driver');
|
|
4
|
+
|
|
5
|
+
function createDriver(context = {}) {
|
|
6
|
+
return createCapabilityDriver({
|
|
7
|
+
...context,
|
|
8
|
+
platform: 'gemini',
|
|
9
|
+
capability: 'sessions',
|
|
10
|
+
parserVersion: 2,
|
|
11
|
+
servicePath: './gemini/sessions-implementation',
|
|
12
|
+
localServicePath: '../platforms/drivers/gemini/sessions-implementation',
|
|
13
|
+
adapterLocalPath: '../platforms/drivers/gemini/session-history-adapter',
|
|
14
|
+
adapterMethods: { inventory: 'inventory', parse: 'parse' },
|
|
15
|
+
methods: {
|
|
16
|
+
listSessions: 'getProjectSessions',
|
|
17
|
+
recent: 'getRecentSessions',
|
|
18
|
+
getSessionById: 'getSessionById',
|
|
19
|
+
getAllSessions: 'getAllSessions',
|
|
20
|
+
delete: 'deleteSession',
|
|
21
|
+
fork: 'forkSession',
|
|
22
|
+
saveSessionOrder: 'saveSessionOrder',
|
|
23
|
+
getProjectPath: 'getProjectPath',
|
|
24
|
+
status: 'getSessionStatus',
|
|
25
|
+
messages: 'getSessionMessages'
|
|
26
|
+
},
|
|
27
|
+
customMethods: {
|
|
28
|
+
search: (service, projectName, keyword, contextLength, options = {}) => service.searchSessions(
|
|
29
|
+
keyword,
|
|
30
|
+
contextLength,
|
|
31
|
+
{ ...options, projectName }
|
|
32
|
+
),
|
|
33
|
+
searchAcrossProjects: (service, keyword, contextLength, options = {}) => service.searchSessions(
|
|
34
|
+
keyword,
|
|
35
|
+
contextLength,
|
|
36
|
+
options
|
|
37
|
+
)
|
|
38
|
+
},
|
|
39
|
+
onSuccess: operation => {
|
|
40
|
+
if (['delete', 'fork', 'saveSessionOrder'].includes(operation)) {
|
|
41
|
+
context.sessionHistoryIndex?.invalidateSource('gemini');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = { createDriver };
|
|
@@ -3,8 +3,8 @@ const {
|
|
|
3
3
|
getStatistics: getSharedStatistics,
|
|
4
4
|
getDailyStatistics: getSharedDailyStatistics,
|
|
5
5
|
getTodayStatistics: getSharedTodayStatistics
|
|
6
|
-
} = require('
|
|
7
|
-
const { normalizeUsageTokens, toNumber } = require('
|
|
6
|
+
} = require('../../../server/services/statistics-service');
|
|
7
|
+
const { normalizeUsageTokens, toNumber } = require('../../../server/services/usage-log-utils');
|
|
8
8
|
|
|
9
9
|
const TOOL_TYPE = 'gemini';
|
|
10
10
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { createCapabilityDriver } = require('../../../shared/capability-driver');
|
|
4
|
+
|
|
5
|
+
function createDriver(context = {}) {
|
|
6
|
+
return createCapabilityDriver({
|
|
7
|
+
...context,
|
|
8
|
+
platform: 'gemini',
|
|
9
|
+
capability: 'statistics',
|
|
10
|
+
servicePath: './gemini/statistics-implementation',
|
|
11
|
+
localServicePath: '../platforms/drivers/gemini/statistics-implementation',
|
|
12
|
+
methods: {"getStatistics":"getStatistics","getDailyStatistics":"getDailyStatistics","getTodayStatistics":"getTodayStatistics","recordRequest":"recordRequest","resetStatistics":"resetStatistics"}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = { createDriver };
|
|
@@ -6,7 +6,7 @@ const {
|
|
|
6
6
|
normalizeToolResultContent,
|
|
7
7
|
extractText,
|
|
8
8
|
normalizeStopSequences
|
|
9
|
-
} = require('
|
|
9
|
+
} = require('../opencode/normalization');
|
|
10
10
|
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
12
12
|
// Gemini CLI constants
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs/promises');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
function failure({ platform, operation, type, name, error }) {
|
|
7
|
+
const result = {
|
|
8
|
+
status: 'failed',
|
|
9
|
+
platform,
|
|
10
|
+
capability: 'resourceSync',
|
|
11
|
+
operation,
|
|
12
|
+
error: error && error.message ? error.message : String(error)
|
|
13
|
+
};
|
|
14
|
+
if (type !== undefined) result.type = type;
|
|
15
|
+
if (name !== undefined) result.name = name;
|
|
16
|
+
if (error) Object.defineProperty(result, 'cause', { value: error, enumerable: false });
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function mappedRoot(manifest, type) {
|
|
21
|
+
const mapping = manifest.resourceMappings || {};
|
|
22
|
+
return mapping[type] || (manifest.paths && manifest.paths[type]);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function normalizeName(name) {
|
|
26
|
+
const rawName = String(name || '');
|
|
27
|
+
if (path.isAbsolute(rawName)) throw new Error(`Resource path must be relative: ${name}`);
|
|
28
|
+
const normalizedName = path.normalize(rawName);
|
|
29
|
+
if (!normalizedName || normalizedName === '.' || normalizedName === '..' || normalizedName.startsWith(`..${path.sep}`)) {
|
|
30
|
+
throw new Error(`Resource path escapes target root: ${name}`);
|
|
31
|
+
}
|
|
32
|
+
return normalizedName;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function resolveTarget(root, name) {
|
|
36
|
+
const normalizedName = normalizeName(name);
|
|
37
|
+
const resolvedRoot = path.resolve(root);
|
|
38
|
+
const target = path.resolve(resolvedRoot, normalizedName);
|
|
39
|
+
const relative = path.relative(resolvedRoot, target);
|
|
40
|
+
if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
41
|
+
throw new Error(`Resource path escapes target root: ${name}`);
|
|
42
|
+
}
|
|
43
|
+
return target;
|
|
44
|
+
}
|
|
45
|
+
async function assertNoSymlinkComponents(fsImpl, target) {
|
|
46
|
+
if (typeof fsImpl.lstat !== 'function') return;
|
|
47
|
+
const resolved = path.resolve(target);
|
|
48
|
+
const root = path.parse(resolved).root;
|
|
49
|
+
const parts = path.relative(root, resolved).split(path.sep).filter(Boolean);
|
|
50
|
+
let current = root;
|
|
51
|
+
for (let index = 0; index < parts.length; index += 1) {
|
|
52
|
+
current = path.join(current, parts[index]);
|
|
53
|
+
try {
|
|
54
|
+
const stat = await fsImpl.lstat(current);
|
|
55
|
+
if (index > 0 && stat.isSymbolicLink()) throw new Error(`Resource path contains symlink: ${target}`);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (error.code === 'ENOENT') break;
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const finalStat = await fsImpl.lstat(resolved).catch(error => {
|
|
62
|
+
if (error.code === 'ENOENT') return null;
|
|
63
|
+
throw error;
|
|
64
|
+
});
|
|
65
|
+
if (finalStat && finalStat.isSymbolicLink()) throw new Error(`Resource path contains symlink: ${target}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function assertSafeRoot(fsImpl, root, { allowMissingRoot = false } = {}) {
|
|
69
|
+
if (typeof fsImpl.realpath !== 'function' || typeof fsImpl.lstat !== 'function') return path.resolve(root);
|
|
70
|
+
const resolvedRoot = path.resolve(root);
|
|
71
|
+
await assertNoSymlinkComponents(fsImpl, resolvedRoot);
|
|
72
|
+
try {
|
|
73
|
+
return await fsImpl.realpath(resolvedRoot);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (error.code !== 'ENOENT' || !allowMissingRoot) throw error;
|
|
76
|
+
let current = path.dirname(resolvedRoot);
|
|
77
|
+
while (true) {
|
|
78
|
+
try {
|
|
79
|
+
await assertNoSymlinkComponents(fsImpl, current);
|
|
80
|
+
return await fsImpl.realpath(current);
|
|
81
|
+
} catch (parentError) {
|
|
82
|
+
if (parentError.code !== 'ENOENT') throw parentError;
|
|
83
|
+
const next = path.dirname(current);
|
|
84
|
+
if (next === current) return resolvedRoot;
|
|
85
|
+
current = next;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function assertContainedTarget(fsImpl, root, target, { allowMissingTarget = false, allowMissingRoot = false } = {}) {
|
|
92
|
+
if (typeof fsImpl.realpath !== 'function' || typeof fsImpl.lstat !== 'function') return;
|
|
93
|
+
const rootReal = await assertSafeRoot(fsImpl, root, { allowMissingRoot });
|
|
94
|
+
await assertNoSymlinkComponents(fsImpl, target);
|
|
95
|
+
const targetReal = await fsImpl.realpath(target).catch(error => {
|
|
96
|
+
if (allowMissingTarget && error.code === 'ENOENT') return null;
|
|
97
|
+
throw error;
|
|
98
|
+
});
|
|
99
|
+
if (!targetReal) return;
|
|
100
|
+
const relative = path.relative(rootReal, targetReal);
|
|
101
|
+
if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
102
|
+
throw new Error(`Resource path escapes target root: ${target}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function createGenericFilesystemDriver({ platform, manifest = {}, fsImpl = fs } = {}) {
|
|
106
|
+
function getRoot(type) {
|
|
107
|
+
const root = mappedRoot(manifest, type);
|
|
108
|
+
if (!root) throw new Error(`Unknown resource mapping: ${type}`);
|
|
109
|
+
return root;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
async list(type) {
|
|
114
|
+
try {
|
|
115
|
+
const root = getRoot(type);
|
|
116
|
+
await assertSafeRoot(fsImpl, root);
|
|
117
|
+
const names = await fsImpl.readdir(root);
|
|
118
|
+
const resources = [];
|
|
119
|
+
for (const name of names) {
|
|
120
|
+
const target = resolveTarget(root, name);
|
|
121
|
+
await assertContainedTarget(fsImpl, root, target);
|
|
122
|
+
const stat = await fsImpl.stat(target);
|
|
123
|
+
resources.push({ name, target, type: stat.isDirectory() ? 'directory' : 'file', size: stat.size, mtimeMs: stat.mtimeMs });
|
|
124
|
+
}
|
|
125
|
+
return resources;
|
|
126
|
+
} catch (error) {
|
|
127
|
+
return failure({ platform, operation: 'list', type, error });
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
async sync(type, name, sourceRoot) {
|
|
131
|
+
try {
|
|
132
|
+
const root = getRoot(type);
|
|
133
|
+
const target = resolveTarget(root, name);
|
|
134
|
+
await assertSafeRoot(fsImpl, root, { allowMissingRoot: true });
|
|
135
|
+
await assertContainedTarget(fsImpl, root, path.dirname(target), { allowMissingTarget: true, allowMissingRoot: true });
|
|
136
|
+
const sourceStat = await fsImpl.stat(sourceRoot);
|
|
137
|
+
await fsImpl.mkdir(path.dirname(target), { recursive: true });
|
|
138
|
+
await assertSafeRoot(fsImpl, root);
|
|
139
|
+
await assertContainedTarget(fsImpl, root, path.dirname(target));
|
|
140
|
+
await assertContainedTarget(fsImpl, root, target, { allowMissingTarget: true });
|
|
141
|
+
if (sourceStat.isDirectory()) {
|
|
142
|
+
await fsImpl.cp(sourceRoot, target, { recursive: true });
|
|
143
|
+
} else {
|
|
144
|
+
await fsImpl.copyFile(sourceRoot, target);
|
|
145
|
+
}
|
|
146
|
+
return { status: 'ok', target };
|
|
147
|
+
} catch (error) {
|
|
148
|
+
return failure({ platform, operation: 'sync', type, name, error });
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
async remove(type, name) {
|
|
152
|
+
try {
|
|
153
|
+
const root = getRoot(type);
|
|
154
|
+
const target = resolveTarget(root, name);
|
|
155
|
+
await assertSafeRoot(fsImpl, root);
|
|
156
|
+
await assertContainedTarget(fsImpl, root, target, { allowMissingTarget: true });
|
|
157
|
+
await fsImpl.rm(target, { recursive: true, force: true });
|
|
158
|
+
return { status: 'ok', target };
|
|
159
|
+
} catch (error) {
|
|
160
|
+
return failure({ platform, operation: 'remove', type, name, error });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
module.exports = { createGenericFilesystemDriver };
|