coding-tool-x 3.8.4 → 3.8.5
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-BG6P3DX-.js +1 -0
- package/dist/web/assets/AgentsDrawer-Pw2k-ZAa.css +1 -0
- package/dist/web/assets/Analytics--z_FmL5P.js +1 -0
- package/dist/web/assets/Analytics-CyHhR126.css +1 -0
- package/dist/web/assets/AssetPathField-CrJtRKHy.js +1 -0
- package/dist/web/assets/ChatHistoryDrawer-B2qBQs9L.css +1 -0
- package/dist/web/assets/ChatHistoryDrawer-BiuEryJj.js +1 -0
- package/dist/web/assets/CollapseItem-BAYEsL_Q.js +1 -0
- package/dist/web/assets/CommandsDrawer-BZJxlPvV.css +1 -0
- package/dist/web/assets/CommandsDrawer-YJ-U7BXN.js +1 -0
- package/dist/web/assets/ConfigExportDrawer-Ce_hAknW.js +1 -0
- package/dist/web/assets/ConfigExportDrawer-dwruRKWr.css +1 -0
- package/dist/web/assets/ConfigTemplates-Bvr1NN6K.js +1 -0
- package/dist/web/assets/ConfigTemplatesDrawer-BfDi8yO3.css +1 -0
- package/dist/web/assets/ConfigTemplatesDrawer-BjIeHfF-.js +1 -0
- package/dist/web/assets/ConfigTemplatesPanel-AV00tm_D.js +1 -0
- package/dist/web/assets/ConfigTemplatesPanel-CWyPtk67.css +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-Cz95o4CD.js +1 -0
- package/dist/web/assets/GatewayConvertDrawer-CuNlf7AC.css +1 -0
- package/dist/web/assets/GatewayConvertDrawer-DLlbMz27.js +1 -0
- package/dist/web/assets/Home-CSuFuJ9Y.css +1 -0
- package/dist/web/assets/Home-D7CCOFQC.js +1 -0
- package/dist/web/assets/MarkdownEditor-qfVgSre_.css +1 -0
- package/dist/web/assets/MarkdownEditor-rEZ-c72L.js +1 -0
- package/dist/web/assets/McpDrawer-C0dnsZhQ.css +1 -0
- package/dist/web/assets/McpDrawer-DfoCyxU2.js +1 -0
- package/dist/web/assets/McpFormDrawer-BRbDcawn.css +1 -0
- package/dist/web/assets/McpFormDrawer-SKu8HNUR.js +1 -0
- package/dist/web/assets/PluginManager-BbeK-3rV.js +1 -0
- package/dist/web/assets/PluginsDrawer-CWVJ7yjS.js +1 -0
- package/dist/web/assets/PluginsDrawer-DM3QjprE.css +1 -0
- package/dist/web/assets/PluginsPanel-Cm2N3StG.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-CsjnsNPv.js +1 -0
- package/dist/web/assets/PromptsDrawer-BIgiYCEQ.css +1 -0
- package/dist/web/assets/PromptsDrawer-EGd3djFa.js +1 -0
- package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +1 -0
- package/dist/web/assets/RecentSessionsDrawer-D1vtoLAs.js +1 -0
- package/dist/web/assets/SessionCard-BgLg49U3.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-TRiTklWk.js +1 -0
- package/dist/web/assets/SettingsDrawer-d5liXjHq.css +1 -0
- package/dist/web/assets/SettingsDrawer-rz2WejGY.js +1 -0
- package/dist/web/assets/SkillManager-BTjTUbHq.js +1 -0
- package/dist/web/assets/SkillManager-C0GCT2Kb.css +1 -0
- package/dist/web/assets/SkillsDrawer-BCNme-aJ.css +1 -0
- package/dist/web/assets/SkillsDrawer-pN0hbkK3.js +1 -0
- package/dist/web/assets/SkillsPanel-B3Nm5j32.css +1 -0
- package/dist/web/assets/SkillsPanel-gmBWEoiF.js +1 -0
- package/dist/web/assets/SpeedTestDrawer-Dc0WToJ_.css +1 -0
- package/dist/web/assets/SpeedTestDrawer-DcNzuVJk.js +1 -0
- package/dist/web/assets/Upload-v5rV0qTT.js +1 -0
- package/dist/web/assets/WorkspaceDrawer-CGnMu9p1.css +1 -0
- package/dist/web/assets/WorkspaceDrawer-DxmicM4U.js +1 -0
- package/dist/web/assets/WorkspaceManager-CJHCjARN.js +1 -0
- package/dist/web/assets/WorkspacePanel-D0-zHTHP.css +1 -0
- package/dist/web/assets/WorkspacePanel-D8_Zq-du.js +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-C0EHRym0.css +1 -0
- package/dist/web/assets/index-DnEocV0M.js +2 -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-B3uojyvV.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 +94 -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 +162 -0
- package/src/platforms/channel-auth-service.js +82 -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 +87 -417
- package/src/{server/services → platforms}/notification-hooks.js +140 -1023
- package/src/platforms/oauth-credentials-service.js +506 -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 +11 -20
- 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 +1 -1
- 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 +780 -213
- 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
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const readline = require('readline');
|
|
6
|
+
const { NATIVE_PATHS } = require('../../../config/paths');
|
|
7
|
+
|
|
8
|
+
const DEFAULT_CLAUDE_PROJECTS_DIR = NATIVE_PATHS?.claude?.projects || '';
|
|
9
|
+
let claudeProjectsDir = DEFAULT_CLAUDE_PROJECTS_DIR;
|
|
10
|
+
|
|
11
|
+
function configure({ pathContext } = {}) {
|
|
12
|
+
claudeProjectsDir = pathContext?.customized
|
|
13
|
+
? (pathContext.native?.projects || DEFAULT_CLAUDE_PROJECTS_DIR)
|
|
14
|
+
: DEFAULT_CLAUDE_PROJECTS_DIR;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function _asContentBlocks(content) {
|
|
18
|
+
if (Array.isArray(content)) return content;
|
|
19
|
+
return content && typeof content === 'object' ? [content] : [];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function _formatJsonBlock(value, fallback = '') {
|
|
23
|
+
if (typeof value === 'string') return value;
|
|
24
|
+
try {
|
|
25
|
+
const serialized = JSON.stringify(value, null, 2);
|
|
26
|
+
return serialized === undefined ? fallback : serialized;
|
|
27
|
+
} catch (_) {
|
|
28
|
+
return fallback;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get Claude user-visible text from a message content block.
|
|
34
|
+
* Shared with sessions.js API for display consistency.
|
|
35
|
+
*/
|
|
36
|
+
function getClaudeUserText(content) {
|
|
37
|
+
if (typeof content === 'string') {
|
|
38
|
+
return content === 'Warmup' ? '' : content;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const parts = [];
|
|
42
|
+
for (const item of _asContentBlocks(content)) {
|
|
43
|
+
if (item?.type === 'text' && item.text) {
|
|
44
|
+
parts.push(item.text);
|
|
45
|
+
} else if (item?.type === 'image') {
|
|
46
|
+
parts.push('[图片]');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return parts.join('\n\n').trim();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getClaudeToolResultText(content) {
|
|
54
|
+
const parts = [];
|
|
55
|
+
for (const item of _asContentBlocks(content)) {
|
|
56
|
+
if (item?.type !== 'tool_result') continue;
|
|
57
|
+
const resultContent = _formatJsonBlock(item.content, '');
|
|
58
|
+
if (resultContent) {
|
|
59
|
+
parts.push(`**[工具结果]**\n\`\`\`\n${resultContent}\n\`\`\``);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return parts.join('\n\n').trim();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getClaudeAssistantText(content) {
|
|
66
|
+
if (typeof content === 'string') {
|
|
67
|
+
return content === 'Warmup' ? '' : content;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const parts = [];
|
|
71
|
+
let subtype = null;
|
|
72
|
+
for (const item of _asContentBlocks(content)) {
|
|
73
|
+
if (item?.type === 'text' && item.text) {
|
|
74
|
+
parts.push(item.text);
|
|
75
|
+
} else if (item?.type === 'image') {
|
|
76
|
+
parts.push('[图片]');
|
|
77
|
+
} else if (item?.type === 'tool_use') {
|
|
78
|
+
subtype = 'tool_use';
|
|
79
|
+
const input = _formatJsonBlock(item.input, '{}');
|
|
80
|
+
parts.push(`**[调用工具: ${item.name || 'unknown'}]**\n\`\`\`json\n${input}\n\`\`\``);
|
|
81
|
+
} else if (item?.type === 'tool_result') {
|
|
82
|
+
subtype = subtype || 'tool_result';
|
|
83
|
+
const resultContent = _formatJsonBlock(item.content, '');
|
|
84
|
+
if (resultContent) {
|
|
85
|
+
parts.push(`**[工具结果]**\n\`\`\`\n${resultContent}\n\`\`\``);
|
|
86
|
+
}
|
|
87
|
+
} else if (item?.type === 'thinking') {
|
|
88
|
+
subtype = subtype || 'thinking';
|
|
89
|
+
if (item.thinking) parts.push(`**[思考]**\n${item.thinking}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return { content: parts.join('\n\n').trim(), subtype };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Parse real project path from encoded name.
|
|
98
|
+
*/
|
|
99
|
+
function parseRealProjectPath(encodedName, config = {}) {
|
|
100
|
+
const { parseRealProjectPath: fn } = require('./sessions-implementation');
|
|
101
|
+
return fn(encodedName, config);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Inventory all Claude session files.
|
|
106
|
+
* @returns {Promise<Array<{filePath: string, size: number, mtimeMs: number, sessionId: string, projectHint: string}>>}
|
|
107
|
+
*/
|
|
108
|
+
async function inventory({ projectsDir } = {}) {
|
|
109
|
+
const descriptors = [];
|
|
110
|
+
const rootDir = projectsDir || claudeProjectsDir;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
await fs.promises.stat(rootDir);
|
|
114
|
+
} catch (_) {
|
|
115
|
+
return descriptors;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const projects = await fs.promises.readdir(rootDir, { withFileTypes: true });
|
|
119
|
+
for (const entry of projects) {
|
|
120
|
+
if (!entry.isDirectory()) continue;
|
|
121
|
+
const projectName = entry.name;
|
|
122
|
+
const projectPath = path.join(rootDir, projectName);
|
|
123
|
+
|
|
124
|
+
let files;
|
|
125
|
+
try {
|
|
126
|
+
files = await fs.promises.readdir(projectPath);
|
|
127
|
+
} catch (_) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
for (const f of files) {
|
|
132
|
+
if (!f.endsWith('.jsonl') || f.startsWith('agent-')) continue;
|
|
133
|
+
const filePath = path.join(projectPath, f);
|
|
134
|
+
let stat;
|
|
135
|
+
try {
|
|
136
|
+
stat = await fs.promises.stat(filePath);
|
|
137
|
+
} catch (_) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
descriptors.push({
|
|
141
|
+
filePath,
|
|
142
|
+
size: stat.size,
|
|
143
|
+
mtimeMs: stat.mtimeMs,
|
|
144
|
+
sessionId: f.replace(/\.jsonl$/, ''),
|
|
145
|
+
projectHint: projectName
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return descriptors;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Parse a Claude session file into normalized session + messages.
|
|
155
|
+
* @param {{filePath: string, size: number, mtimeMs: number, sessionId: string, projectHint: string}} descriptor
|
|
156
|
+
* @returns {Promise<{session: object, messages: Array}>}
|
|
157
|
+
*/
|
|
158
|
+
async function parse(descriptor) {
|
|
159
|
+
const { filePath, size, mtimeMs, sessionId, projectHint } = descriptor;
|
|
160
|
+
const { fullPath, projectName: displayName } = parseRealProjectPath(projectHint, { projectsDir: descriptor.projectsDir });
|
|
161
|
+
|
|
162
|
+
const messages = [];
|
|
163
|
+
let firstMessage = null;
|
|
164
|
+
let gitBranch = null;
|
|
165
|
+
let provider = null;
|
|
166
|
+
let model = null;
|
|
167
|
+
let startedAt = null;
|
|
168
|
+
let updatedAt = null;
|
|
169
|
+
let usageJson = null;
|
|
170
|
+
const extra = {};
|
|
171
|
+
let userMessageNumber = 0;
|
|
172
|
+
|
|
173
|
+
const stream = fs.createReadStream(filePath, { encoding: 'utf8' });
|
|
174
|
+
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
175
|
+
|
|
176
|
+
for await (const line of rl) {
|
|
177
|
+
if (!line.trim()) continue;
|
|
178
|
+
|
|
179
|
+
let json;
|
|
180
|
+
try {
|
|
181
|
+
json = JSON.parse(line);
|
|
182
|
+
} catch (_) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const messagePayload = json.message && typeof json.message === 'object' && !Array.isArray(json.message)
|
|
187
|
+
? json.message
|
|
188
|
+
: {};
|
|
189
|
+
const recordTimestamp = json.timestamp || messagePayload.timestamp || null;
|
|
190
|
+
const timestampValue = recordTimestamp ? new Date(recordTimestamp).getTime() : null;
|
|
191
|
+
const timestamp = Number.isFinite(timestampValue) ? timestampValue : null;
|
|
192
|
+
const recordModel = json.model || messagePayload.model || null;
|
|
193
|
+
const recordProvider = json.provider || messagePayload.provider || null;
|
|
194
|
+
const recordUsage = json.usage || messagePayload.usage || null;
|
|
195
|
+
|
|
196
|
+
if (json.type === 'metadata' || json.type === 'summary') {
|
|
197
|
+
if (json.cwd || messagePayload.cwd) extra.cwd = json.cwd || messagePayload.cwd;
|
|
198
|
+
if (json.gitBranch || messagePayload.gitBranch) {
|
|
199
|
+
gitBranch = json.gitBranch || messagePayload.gitBranch;
|
|
200
|
+
}
|
|
201
|
+
if (json.summary) extra.summary = json.summary;
|
|
202
|
+
if (timestamp !== null && startedAt === null) startedAt = timestamp;
|
|
203
|
+
if (recordModel) model = recordModel;
|
|
204
|
+
if (recordProvider) provider = recordProvider;
|
|
205
|
+
if (recordUsage) usageJson = JSON.stringify(recordUsage);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const role = json.role
|
|
210
|
+
|| messagePayload.role
|
|
211
|
+
|| (json.type === 'user' || json.type === 'human'
|
|
212
|
+
? 'user'
|
|
213
|
+
: json.type === 'assistant' || json.type === 'ai'
|
|
214
|
+
? 'assistant'
|
|
215
|
+
: null);
|
|
216
|
+
if (role !== 'user' && role !== 'assistant') continue;
|
|
217
|
+
|
|
218
|
+
const rawContent = json.content !== undefined && json.content !== null && json.content !== ''
|
|
219
|
+
? json.content
|
|
220
|
+
: messagePayload.content !== undefined
|
|
221
|
+
? messagePayload.content
|
|
222
|
+
: typeof json.message === 'string' ? json.message : '';
|
|
223
|
+
const messageId = messagePayload.id || json.uuid || json.id || null;
|
|
224
|
+
|
|
225
|
+
if (timestamp !== null) {
|
|
226
|
+
if (startedAt === null) startedAt = timestamp;
|
|
227
|
+
updatedAt = timestamp;
|
|
228
|
+
}
|
|
229
|
+
if (recordModel) model = recordModel;
|
|
230
|
+
if (recordProvider) provider = recordProvider;
|
|
231
|
+
if (recordUsage) usageJson = JSON.stringify(recordUsage);
|
|
232
|
+
|
|
233
|
+
if (role === 'user') {
|
|
234
|
+
const content = getClaudeUserText(rawContent);
|
|
235
|
+
if (content) {
|
|
236
|
+
userMessageNumber++;
|
|
237
|
+
if (!firstMessage) firstMessage = content;
|
|
238
|
+
messages.push({
|
|
239
|
+
messageId,
|
|
240
|
+
role,
|
|
241
|
+
type: json.type || role,
|
|
242
|
+
subtype: null,
|
|
243
|
+
content,
|
|
244
|
+
timestamp,
|
|
245
|
+
model: recordModel || model || null,
|
|
246
|
+
provider: recordProvider || provider || null,
|
|
247
|
+
userMessageNumber,
|
|
248
|
+
extraJson: null
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const toolResultContent = getClaudeToolResultText(rawContent);
|
|
253
|
+
if (toolResultContent) {
|
|
254
|
+
messages.push({
|
|
255
|
+
messageId: messageId ? `${messageId}-tool-result` : null,
|
|
256
|
+
role: 'assistant',
|
|
257
|
+
type: 'assistant',
|
|
258
|
+
subtype: 'tool_result',
|
|
259
|
+
content: toolResultContent,
|
|
260
|
+
timestamp,
|
|
261
|
+
model: recordModel || model || null,
|
|
262
|
+
provider: recordProvider || provider || null,
|
|
263
|
+
userMessageNumber: null,
|
|
264
|
+
extraJson: null
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const assistant = getClaudeAssistantText(rawContent);
|
|
271
|
+
if (!assistant.content) continue;
|
|
272
|
+
messages.push({
|
|
273
|
+
messageId,
|
|
274
|
+
role,
|
|
275
|
+
type: json.type || role,
|
|
276
|
+
subtype: assistant.subtype,
|
|
277
|
+
content: assistant.content,
|
|
278
|
+
timestamp,
|
|
279
|
+
model: recordModel || model || null,
|
|
280
|
+
provider: recordProvider || provider || null,
|
|
281
|
+
userMessageNumber: null,
|
|
282
|
+
extraJson: null
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
rl.close();
|
|
287
|
+
stream.destroy();
|
|
288
|
+
|
|
289
|
+
const session = {
|
|
290
|
+
sessionId,
|
|
291
|
+
projectName: projectHint,
|
|
292
|
+
projectDisplayName: displayName,
|
|
293
|
+
projectFullPath: fullPath,
|
|
294
|
+
firstMessage: firstMessage || null,
|
|
295
|
+
gitBranch,
|
|
296
|
+
provider,
|
|
297
|
+
model,
|
|
298
|
+
startedAt,
|
|
299
|
+
updatedAt: updatedAt || mtimeMs,
|
|
300
|
+
usageJson,
|
|
301
|
+
extraJson: JSON.stringify(extra)
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
session,
|
|
306
|
+
messages: messages.map((message) => ({
|
|
307
|
+
...message,
|
|
308
|
+
extraJson: message.extraJson ? JSON.stringify(message.extraJson) : null
|
|
309
|
+
}))
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
module.exports = { configure, inventory, parse, getClaudeUserText };
|
package/src/{server/services/sessions.js → platforms/drivers/claude/sessions-implementation.js}
RENAMED
|
@@ -1,18 +1,41 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const crypto = require('crypto');
|
|
4
|
-
const {
|
|
5
|
-
const {
|
|
6
|
-
const {
|
|
7
|
-
const {
|
|
8
|
-
|
|
4
|
+
const { spawnSync } = require('child_process');
|
|
5
|
+
const { getAllSessions, parseSessionInfoFast } = require('../../../utils/session');
|
|
6
|
+
const { loadAliases, setAlias } = require('../../../server/services/alias');
|
|
7
|
+
const { globalCache, CacheKeys } = require('../../../server/services/enhanced-cache');
|
|
8
|
+
let sessionHistoryIndex = null;
|
|
9
|
+
|
|
10
|
+
function getSessionHistoryIndex(config = {}) {
|
|
11
|
+
if (!sessionHistoryIndex) {
|
|
12
|
+
const { getDefaultDependencies } = require('../../../platforms/runtime');
|
|
13
|
+
sessionHistoryIndex = getDefaultDependencies().sessionHistoryIndex;
|
|
14
|
+
if (!sessionHistoryIndex) {
|
|
15
|
+
const indexModule = require('../../../server/services/session-history-index');
|
|
16
|
+
sessionHistoryIndex = Object.keys(config).length > 0
|
|
17
|
+
? indexModule.createSessionHistoryIndex({ config })
|
|
18
|
+
: indexModule;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return sessionHistoryIndex;
|
|
22
|
+
}
|
|
23
|
+
const { PATHS, NATIVE_PATHS } = require('../../../config/paths');
|
|
9
24
|
|
|
10
|
-
const
|
|
25
|
+
const DEFAULT_CLAUDE_PROJECTS_DIR = NATIVE_PATHS.claude.projects;
|
|
11
26
|
const CODEX_PROJECTS_DIR = path.join(path.dirname(NATIVE_PATHS.codex.config), 'projects');
|
|
12
27
|
const GEMINI_PROJECTS_DIR = path.join(path.dirname(NATIVE_PATHS.gemini.env), 'projects');
|
|
28
|
+
let claudeProjectsDir = DEFAULT_CLAUDE_PROJECTS_DIR;
|
|
29
|
+
|
|
30
|
+
function configure({ sessionHistoryIndex: index, pathContext } = {}) {
|
|
31
|
+
sessionHistoryIndex = index || null;
|
|
32
|
+
claudeProjectsDir = pathContext?.customized
|
|
33
|
+
? (pathContext.native?.projects || DEFAULT_CLAUDE_PROJECTS_DIR)
|
|
34
|
+
: DEFAULT_CLAUDE_PROJECTS_DIR;
|
|
35
|
+
}
|
|
13
36
|
|
|
14
37
|
function resolveProjectsDir(config = {}) {
|
|
15
|
-
return config.projectsDir ||
|
|
38
|
+
return config.projectsDir || claudeProjectsDir;
|
|
16
39
|
}
|
|
17
40
|
|
|
18
41
|
function withResolvedProjectsDir(config = {}) {
|
|
@@ -24,6 +47,81 @@ function getOrderFilePath() { return PATHS.projectOrder; }
|
|
|
24
47
|
function getForkRelationsFilePath() { return PATHS.forkRelations; }
|
|
25
48
|
function getSessionOrderFilePath() { return PATHS.sessionOrder; }
|
|
26
49
|
|
|
50
|
+
function readSessionCwd(config = {}, sessionId) {
|
|
51
|
+
const sessionFile = path.join(
|
|
52
|
+
resolveProjectsDir(config),
|
|
53
|
+
config.currentProject || '',
|
|
54
|
+
`${sessionId}.jsonl`
|
|
55
|
+
);
|
|
56
|
+
let fd;
|
|
57
|
+
try {
|
|
58
|
+
fd = fs.openSync(sessionFile, 'r');
|
|
59
|
+
const buffer = Buffer.alloc(2048);
|
|
60
|
+
const bytesRead = fs.readSync(fd, buffer, 0, buffer.length, 0);
|
|
61
|
+
const lines = buffer.subarray(0, bytesRead).toString('utf8').split('\n').slice(0, 5);
|
|
62
|
+
for (const line of lines) {
|
|
63
|
+
try {
|
|
64
|
+
const value = JSON.parse(line);
|
|
65
|
+
if (typeof value.cwd === 'string' && value.cwd.trim()) return value.cwd;
|
|
66
|
+
} catch (_) {
|
|
67
|
+
// 忽略无效的会话元数据
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
} catch (_) {
|
|
71
|
+
return null;
|
|
72
|
+
} finally {
|
|
73
|
+
if (fd !== undefined) {
|
|
74
|
+
try {
|
|
75
|
+
fs.closeSync(fd);
|
|
76
|
+
} catch (_) {
|
|
77
|
+
// 忽略文件关闭错误
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function resolveLaunchCwd(config, sessionId, cwd) {
|
|
85
|
+
const candidate = typeof cwd === 'string' && cwd.trim()
|
|
86
|
+
? cwd
|
|
87
|
+
: readSessionCwd(config, sessionId);
|
|
88
|
+
if (candidate) {
|
|
89
|
+
try {
|
|
90
|
+
if (fs.statSync(candidate).isDirectory()) return candidate;
|
|
91
|
+
} catch (_) {
|
|
92
|
+
// 使用当前目录
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return process.cwd();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function launch(sessionId, {
|
|
99
|
+
fork = false,
|
|
100
|
+
config = {},
|
|
101
|
+
cwd,
|
|
102
|
+
processRunner = spawnSync
|
|
103
|
+
} = {}) {
|
|
104
|
+
const normalizedSessionId = String(sessionId || '');
|
|
105
|
+
const args = ['-r', normalizedSessionId];
|
|
106
|
+
if (fork) args.push('--fork-session');
|
|
107
|
+
const launchCwd = resolveLaunchCwd(config, normalizedSessionId, cwd);
|
|
108
|
+
const result = processRunner('claude', args, {
|
|
109
|
+
cwd: launchCwd,
|
|
110
|
+
stdio: 'inherit',
|
|
111
|
+
windowsHide: true
|
|
112
|
+
});
|
|
113
|
+
if (result?.error) {
|
|
114
|
+
throw result.error instanceof Error ? result.error : new Error(String(result.error));
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
...(result && typeof result === 'object' ? result : {}),
|
|
118
|
+
status: result?.status ?? 0,
|
|
119
|
+
signal: result?.signal || null,
|
|
120
|
+
cwd: launchCwd,
|
|
121
|
+
args
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
27
125
|
function getProjectOrder(config) {
|
|
28
126
|
const orderFile = getOrderFilePath();
|
|
29
127
|
try { if (fs.existsSync(orderFile)) return JSON.parse(fs.readFileSync(orderFile, 'utf8')); } catch (_) {}
|
|
@@ -101,20 +199,20 @@ function sliceClaudeSessionContentByUserMessage(content, afterUserMessageNumber)
|
|
|
101
199
|
|
|
102
200
|
// ===== Read-side: all project/list/session/recent/search delegate to session-history-index =====
|
|
103
201
|
|
|
104
|
-
async function getProjects(config) {
|
|
105
|
-
const indexed = await
|
|
202
|
+
async function getProjects(config = {}, options = {}) {
|
|
203
|
+
const indexed = await getSessionHistoryIndex(config).listProjects('claude', { ...options, config });
|
|
106
204
|
return indexed.map(p => p.name);
|
|
107
205
|
}
|
|
108
206
|
|
|
109
|
-
async function getProjectsWithStats(config, options = {}) {
|
|
110
|
-
return
|
|
207
|
+
async function getProjectsWithStats(config = {}, options = {}) {
|
|
208
|
+
return getSessionHistoryIndex(config).listProjects('claude', { ...options, config });
|
|
111
209
|
}
|
|
112
210
|
|
|
113
211
|
// ===== Path resolution helpers (kept for mutation/conversion paths) =====
|
|
114
212
|
|
|
115
|
-
function parseRealProjectPath(encodedName) {
|
|
213
|
+
function parseRealProjectPath(encodedName, config = {}) {
|
|
116
214
|
const isWindows = process.platform === 'win32';
|
|
117
|
-
const fallbackFromSessions = tryResolvePathFromSessions(encodedName);
|
|
215
|
+
const fallbackFromSessions = tryResolvePathFromSessions(encodedName, config);
|
|
118
216
|
const windowsDriveMatch = encodedName.match(/^([A-Z])--(.+)$/);
|
|
119
217
|
|
|
120
218
|
if (isWindows && windowsDriveMatch) {
|
|
@@ -197,9 +295,9 @@ function validateProjectPath(candidatePath) {
|
|
|
197
295
|
return (candidatePath && fs.existsSync(candidatePath)) ? candidatePath : null;
|
|
198
296
|
}
|
|
199
297
|
|
|
200
|
-
function tryResolvePathFromSessions(encodedName) {
|
|
298
|
+
function tryResolvePathFromSessions(encodedName, config = {}) {
|
|
201
299
|
try {
|
|
202
|
-
const projectDir = path.join(
|
|
300
|
+
const projectDir = path.join(resolveProjectsDir(config), encodedName);
|
|
203
301
|
if (!fs.existsSync(projectDir)) return null;
|
|
204
302
|
const files = fs.readdirSync(projectDir).filter(f => f.endsWith('.jsonl'));
|
|
205
303
|
for (const file of files) {
|
|
@@ -228,24 +326,19 @@ function extractCwdFromSessionHeader(sessionFile) {
|
|
|
228
326
|
|
|
229
327
|
// ===== Counts: delegates to index =====
|
|
230
328
|
|
|
231
|
-
async function getProjectAndSessionCounts(config) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
return { projectCount: projects.length, sessionCount };
|
|
237
|
-
} catch (_) {
|
|
238
|
-
return { projectCount: 0, sessionCount: 0 };
|
|
239
|
-
}
|
|
329
|
+
async function getProjectAndSessionCounts(config = {}, options = {}) {
|
|
330
|
+
const projects = await getSessionHistoryIndex().listProjects('claude', { ...options, config });
|
|
331
|
+
let sessionCount = 0;
|
|
332
|
+
for (const project of projects) sessionCount += project.sessionCount || 0;
|
|
333
|
+
return { projectCount: projects.length, sessionCount };
|
|
240
334
|
}
|
|
241
335
|
|
|
242
336
|
// ===== Sessions for project: index + saved order + fork relations =====
|
|
243
337
|
|
|
244
338
|
async function getSessionsForProject(config, projectName, options = {}) {
|
|
245
|
-
const indexed = await
|
|
339
|
+
const indexed = await getSessionHistoryIndex().listSessions('claude', projectName, { ...options, config });
|
|
246
340
|
const forkRelations = getForkRelations();
|
|
247
341
|
const savedOrder = getSessionOrder(projectName);
|
|
248
|
-
|
|
249
342
|
let sessions = indexed.map(s => ({
|
|
250
343
|
sessionId: s.sessionId,
|
|
251
344
|
mtime: s.mtime,
|
|
@@ -269,7 +362,6 @@ async function getSessionsForProject(config, projectName, options = {}) {
|
|
|
269
362
|
const totalSize = sessions.reduce((sum, s) => sum + (s.size || 0), 0);
|
|
270
363
|
return { sessions, totalSize };
|
|
271
364
|
}
|
|
272
|
-
|
|
273
365
|
// ===== Mutations (sync) =====
|
|
274
366
|
|
|
275
367
|
function deleteSession(config, projectName, sessionId) {
|
|
@@ -343,8 +435,8 @@ function deleteProject(config, projectName) {
|
|
|
343
435
|
|
|
344
436
|
// ===== Search: delegates to index =====
|
|
345
437
|
|
|
346
|
-
async function searchSessions(config, projectName, keyword, contextLength = 15) {
|
|
347
|
-
const results = await
|
|
438
|
+
async function searchSessions(config, projectName, keyword, contextLength = 15, options = {}) {
|
|
439
|
+
const results = await getSessionHistoryIndex().searchSessions('claude', keyword, { projectName, contextLength, ...options, config });
|
|
348
440
|
const aliases = loadAliases();
|
|
349
441
|
return results.map(r => ({
|
|
350
442
|
sessionId: r.sessionId,
|
|
@@ -354,10 +446,10 @@ async function searchSessions(config, projectName, keyword, contextLength = 15)
|
|
|
354
446
|
}));
|
|
355
447
|
}
|
|
356
448
|
|
|
357
|
-
async function getRecentSessions(config, limit = 5) {
|
|
358
|
-
const indexed = await
|
|
359
|
-
const aliases = loadAliases();
|
|
449
|
+
async function getRecentSessions(config, limit = 5, options = {}) {
|
|
450
|
+
const indexed = await getSessionHistoryIndex().getRecentSessions('claude', limit, { ...options, config });
|
|
360
451
|
const forkRelations = getForkRelations();
|
|
452
|
+
const aliases = loadAliases();
|
|
361
453
|
return indexed.map(s => ({
|
|
362
454
|
sessionId: s.sessionId,
|
|
363
455
|
projectName: s.projectName,
|
|
@@ -377,13 +469,13 @@ async function searchSessionsAcrossProjects(config, keyword, contextLength = 35)
|
|
|
377
469
|
const allResults = [];
|
|
378
470
|
|
|
379
471
|
try {
|
|
380
|
-
const claudeResults = await
|
|
472
|
+
const claudeResults = await getSessionHistoryIndex().searchSessions('claude', keyword, { contextLength });
|
|
381
473
|
for (const r of claudeResults) allResults.push({ ...r, channel: 'claude' });
|
|
382
474
|
} catch (_) {}
|
|
383
475
|
|
|
384
476
|
try {
|
|
385
477
|
if (fs.existsSync(CODEX_PROJECTS_DIR)) {
|
|
386
|
-
const { searchSessions: codexSearch } = require('
|
|
478
|
+
const { searchSessions: codexSearch } = require('../codex/sessions-implementation');
|
|
387
479
|
const codexResults = await codexSearch(keyword);
|
|
388
480
|
for (const r of codexResults) allResults.push({ ...r, channel: 'codex' });
|
|
389
481
|
}
|
|
@@ -391,7 +483,7 @@ async function searchSessionsAcrossProjects(config, keyword, contextLength = 35)
|
|
|
391
483
|
|
|
392
484
|
try {
|
|
393
485
|
if (fs.existsSync(GEMINI_PROJECTS_DIR)) {
|
|
394
|
-
const { searchSessions: geminiSearch } = require('
|
|
486
|
+
const { searchSessions: geminiSearch } = require('../gemini/sessions-implementation');
|
|
395
487
|
const geminiResults = await geminiSearch(keyword, contextLength);
|
|
396
488
|
for (const r of geminiResults) allResults.push({ ...r, channel: 'gemini' });
|
|
397
489
|
}
|
|
@@ -400,13 +492,31 @@ async function searchSessionsAcrossProjects(config, keyword, contextLength = 35)
|
|
|
400
492
|
allResults.sort((a, b) => (b.matchCount || 0) - (a.matchCount || 0));
|
|
401
493
|
return allResults;
|
|
402
494
|
}
|
|
495
|
+
function hasActualMessages(sessionFile) {
|
|
496
|
+
if (!sessionFile || !fs.existsSync(sessionFile)) return false;
|
|
497
|
+
return fs.readFileSync(sessionFile, 'utf8')
|
|
498
|
+
.split(/\r?\n/)
|
|
499
|
+
.some(line => {
|
|
500
|
+
if (!line.trim()) return false;
|
|
501
|
+
try {
|
|
502
|
+
const entry = JSON.parse(line);
|
|
503
|
+
return entry.type === 'user' || entry.type === 'assistant'
|
|
504
|
+
|| entry.message?.role === 'user' || entry.message?.role === 'assistant';
|
|
505
|
+
} catch (_) {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
|
|
403
511
|
|
|
404
512
|
module.exports = {
|
|
513
|
+
configure,
|
|
405
514
|
getProjects,
|
|
406
515
|
getProjectsWithStats,
|
|
407
516
|
getSessionsForProject,
|
|
408
517
|
deleteSession,
|
|
409
518
|
forkSession,
|
|
519
|
+
launch,
|
|
410
520
|
getRecentSessions,
|
|
411
521
|
getProjectOrder,
|
|
412
522
|
saveProjectOrder,
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { createCapabilityDriver } = require('../../../shared/capability-driver');
|
|
4
|
+
|
|
5
|
+
function createDriver(context = {}) {
|
|
6
|
+
return createCapabilityDriver({
|
|
7
|
+
...context,
|
|
8
|
+
platform: 'claude',
|
|
9
|
+
capability: 'sessions',
|
|
10
|
+
parserVersion: 2,
|
|
11
|
+
servicePath: './claude/sessions-implementation',
|
|
12
|
+
localServicePath: '../platforms/drivers/claude/sessions-implementation',
|
|
13
|
+
adapterLocalPath: '../platforms/drivers/claude/session-history-adapter',
|
|
14
|
+
adapterMethods: { inventory: 'inventory', parse: 'parse' },
|
|
15
|
+
methods: {
|
|
16
|
+
launch: 'launch',
|
|
17
|
+
saveSessionOrder: 'saveSessionOrder',
|
|
18
|
+
getSessionOrder: 'getSessionOrder',
|
|
19
|
+
parseRealProjectPath: 'parseRealProjectPath',
|
|
20
|
+
hasActualMessages: 'hasActualMessages',
|
|
21
|
+
status: 'getSessionStatus',
|
|
22
|
+
messages: 'getSessionMessages'
|
|
23
|
+
},
|
|
24
|
+
customMethods: {
|
|
25
|
+
delete: (service, projectName, sessionId, options = {}) => {
|
|
26
|
+
const result = service.deleteSession(options.config || {}, projectName, sessionId);
|
|
27
|
+
context.sessionHistoryIndex?.invalidateSource('claude');
|
|
28
|
+
return result;
|
|
29
|
+
},
|
|
30
|
+
fork: (service, projectName, sessionId, options = {}) => {
|
|
31
|
+
const result = service.forkSession(options.config || {}, projectName, sessionId, options);
|
|
32
|
+
context.sessionHistoryIndex?.invalidateSource('claude');
|
|
33
|
+
return result;
|
|
34
|
+
},
|
|
35
|
+
listSessions: (service, projectNameOrRequest, options = {}) => {
|
|
36
|
+
const descriptorRequest = projectNameOrRequest && typeof projectNameOrRequest === 'object';
|
|
37
|
+
const request = descriptorRequest ? projectNameOrRequest : options;
|
|
38
|
+
const projectName = descriptorRequest
|
|
39
|
+
? request.params?.projectName
|
|
40
|
+
: projectNameOrRequest;
|
|
41
|
+
return service.getSessionsForProject(
|
|
42
|
+
request.config || {},
|
|
43
|
+
projectName,
|
|
44
|
+
request
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
recent: (service, limitOrRequest, options = {}) => {
|
|
48
|
+
const descriptorRequest = limitOrRequest && typeof limitOrRequest === 'object';
|
|
49
|
+
const request = descriptorRequest ? limitOrRequest : options;
|
|
50
|
+
const limit = descriptorRequest
|
|
51
|
+
? Number.parseInt(request.query?.limit, 10) || 5
|
|
52
|
+
: limitOrRequest;
|
|
53
|
+
return service.getRecentSessions(request.config || {}, limit, request);
|
|
54
|
+
},
|
|
55
|
+
search: (service, projectName, keyword, contextLength, options = {}) => service.searchSessions(
|
|
56
|
+
options.config || {},
|
|
57
|
+
projectName,
|
|
58
|
+
keyword,
|
|
59
|
+
contextLength,
|
|
60
|
+
options
|
|
61
|
+
),
|
|
62
|
+
searchAcrossProjects: (service, keyword, limit, options = {}) => service.searchSessionsAcrossProjects(
|
|
63
|
+
options.config || {},
|
|
64
|
+
keyword,
|
|
65
|
+
limit
|
|
66
|
+
)
|
|
67
|
+
},
|
|
68
|
+
onSuccess: operation => {
|
|
69
|
+
if (['delete', 'fork', 'saveSessionOrder'].includes(operation)) {
|
|
70
|
+
context.sessionHistoryIndex?.invalidateSource('claude');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
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 = 'claude-code';
|
|
10
10
|
const USAGE_SOURCE = 'claude';
|