coding-tool-x 3.8.3 → 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 +18 -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 +13 -8
- 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
package/src/{server/services/omp-sessions.js → platforms/drivers/omp/sessions-implementation.js}
RENAMED
|
@@ -1,14 +1,40 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { PATHS, HOME_DIR } = require('
|
|
3
|
+
const { PATHS, HOME_DIR } = require('../../../config/paths');
|
|
4
|
+
const ompConfig = require('./config');
|
|
4
5
|
const {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} = require('
|
|
11
|
-
|
|
6
|
+
normalizeUsage: normalizeNativeUsage,
|
|
7
|
+
readJsonLines: readNativeJsonLines,
|
|
8
|
+
usageFieldPaths,
|
|
9
|
+
createSelectiveJsonLineParser,
|
|
10
|
+
createIncrementalJsonlCursor
|
|
11
|
+
} = require('../native-log-utils');
|
|
12
|
+
let sessionHistoryIndex = null;
|
|
13
|
+
let ompSessionPathsOverride = null;
|
|
14
|
+
|
|
15
|
+
function configure({ sessionHistoryIndex: index, pathContext } = {}) {
|
|
16
|
+
sessionHistoryIndex = index || null;
|
|
17
|
+
ompConfig.configure?.({ pathContext });
|
|
18
|
+
const native = pathContext?.customized ? (pathContext.native || {}) : {};
|
|
19
|
+
ompSessionPathsOverride = native.sessions
|
|
20
|
+
? { ...native, agentDir: native.dir || path.dirname(native.sessions) }
|
|
21
|
+
: null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getSessionHistoryIndex(options = {}) {
|
|
25
|
+
if (!sessionHistoryIndex) {
|
|
26
|
+
const { getDefaultDependencies } = require('../../../platforms/runtime');
|
|
27
|
+
sessionHistoryIndex = getDefaultDependencies().sessionHistoryIndex;
|
|
28
|
+
if (!sessionHistoryIndex) {
|
|
29
|
+
const indexModule = require('../../../server/services/session-history-index');
|
|
30
|
+
sessionHistoryIndex = Object.keys(options).length > 0
|
|
31
|
+
? indexModule.createSessionHistoryIndex({ config: options })
|
|
32
|
+
: indexModule;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return sessionHistoryIndex;
|
|
36
|
+
}
|
|
37
|
+
const { getOmpCommand, getOmpPaths, resolveOmpRuntime } = require('./config');
|
|
12
38
|
|
|
13
39
|
const PROJECT_ORDER_FILE = PATHS.ompProjectOrder;
|
|
14
40
|
const SESSION_ORDER_FILE = PATHS.ompSessionOrder;
|
|
@@ -116,34 +142,24 @@ function extractMessageText(message = {}) {
|
|
|
116
142
|
}
|
|
117
143
|
|
|
118
144
|
function parseUsage(usage = {}) {
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
const
|
|
145
|
+
const normalized = normalizeNativeUsage(usage);
|
|
146
|
+
const input = normalized.input;
|
|
147
|
+
const output = normalized.output;
|
|
148
|
+
const cacheRead = normalized.cacheRead;
|
|
149
|
+
const cacheWrite = normalized.cacheCreation;
|
|
150
|
+
const reasoning = normalized.reasoning;
|
|
151
|
+
const total = normalized.total;
|
|
125
152
|
const cost = typeof usage.cost === 'number'
|
|
126
153
|
? usage.cost
|
|
127
154
|
: Number(usage.cost?.total ?? usage.cost?.usd ?? 0) || 0;
|
|
128
|
-
return {
|
|
155
|
+
return {
|
|
156
|
+
input, output, cached: normalized.cached, cacheRead, cacheWrite,
|
|
157
|
+
cacheCreation: normalized.cacheCreation, reasoning, total, cost
|
|
158
|
+
};
|
|
129
159
|
}
|
|
130
160
|
|
|
131
161
|
function readJsonLines(filePath) {
|
|
132
|
-
|
|
133
|
-
const raw = fs.readFileSync(filePath, 'utf8');
|
|
134
|
-
return raw
|
|
135
|
-
.split(/\r?\n/)
|
|
136
|
-
.filter(line => line.trim())
|
|
137
|
-
.map((line) => {
|
|
138
|
-
try {
|
|
139
|
-
return JSON.parse(line);
|
|
140
|
-
} catch {
|
|
141
|
-
return { type: 'invalid', raw: line };
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
} catch {
|
|
145
|
-
return [];
|
|
146
|
-
}
|
|
162
|
+
return readNativeJsonLines(filePath, fs);
|
|
147
163
|
}
|
|
148
164
|
|
|
149
165
|
function convertOmpEntry(entry = {}, index = 0) {
|
|
@@ -219,43 +235,64 @@ function parseSessionFile(filePath) {
|
|
|
219
235
|
};
|
|
220
236
|
}
|
|
221
237
|
|
|
222
|
-
function
|
|
223
|
-
const entries = readJsonLines(filePath);
|
|
238
|
+
function createSessionUsageParserState(filePath, entries = [], previousState = {}) {
|
|
224
239
|
const header = entries.find(entry => entry?.type === 'session') || {};
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
240
|
+
return {
|
|
241
|
+
sessionId: previousState.sessionId || header.id || parseOmpSessionId(filePath),
|
|
242
|
+
sessionTimestamp: previousState.sessionTimestamp ?? header.timestamp ?? null,
|
|
243
|
+
activeProvider: previousState.activeProvider || '',
|
|
244
|
+
activeModel: previousState.activeModel || '',
|
|
245
|
+
entryIndex: Number.isInteger(previousState.entryIndex) ? previousState.entryIndex : 0
|
|
246
|
+
};
|
|
247
|
+
}
|
|
229
248
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
249
|
+
function parseSessionUsageEntry(filePath, entry, index, state) {
|
|
250
|
+
if (entry?.type === 'session') {
|
|
251
|
+
state.sessionId = entry.id || state.sessionId;
|
|
252
|
+
state.sessionTimestamp = entry.timestamp || state.sessionTimestamp;
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
if (entry?.type === 'model_change') {
|
|
256
|
+
state.activeProvider = entry.provider || state.activeProvider;
|
|
257
|
+
state.activeModel = entry.modelId || entry.model || state.activeModel;
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
if (entry?.type !== 'message') return null;
|
|
237
261
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
262
|
+
const message = entry.message || {};
|
|
263
|
+
const role = message.role || entry.role;
|
|
264
|
+
if (role !== 'assistant') return null;
|
|
241
265
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
266
|
+
const eventId = entry.id || message.id || `assistant-${index}`;
|
|
267
|
+
return {
|
|
268
|
+
key: `${filePath}:${eventId}`,
|
|
269
|
+
id: `${state.sessionId}:${eventId}`,
|
|
270
|
+
sessionId: state.sessionId,
|
|
271
|
+
filePath,
|
|
272
|
+
provider: entry.provider || message.provider || state.activeProvider || '',
|
|
273
|
+
model: entry.model || message.model || state.activeModel || '',
|
|
274
|
+
timestamp: entry.timestamp || message.timestamp || state.sessionTimestamp || null,
|
|
275
|
+
usage: parseUsage(entry.usage || message.usage || {})
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function parseSessionUsageEntries(filePath, entries, previousState = {}) {
|
|
280
|
+
const state = createSessionUsageParserState(filePath, entries, previousState);
|
|
281
|
+
const events = [];
|
|
282
|
+
entries.forEach((entry, index) => {
|
|
283
|
+
const event = parseSessionUsageEntry(filePath, entry, index, state);
|
|
284
|
+
if (event) events.push(event);
|
|
253
285
|
});
|
|
286
|
+
return { events, state };
|
|
287
|
+
}
|
|
254
288
|
|
|
255
|
-
|
|
289
|
+
function parseSessionUsageEvents(filePath) {
|
|
290
|
+
const entries = readJsonLines(filePath);
|
|
291
|
+
return parseSessionUsageEntries(filePath, entries).events;
|
|
256
292
|
}
|
|
257
293
|
|
|
258
294
|
function getOmpSessionPaths() {
|
|
295
|
+
if (ompSessionPathsOverride?.sessions) return ompSessionPathsOverride;
|
|
259
296
|
// Reading historical sessions normally only needs OMP's native directory
|
|
260
297
|
// convention. Avoid starting the CLI here: project/count snapshot workers
|
|
261
298
|
// invoke this path independently, which made Windows repeatedly open
|
|
@@ -294,8 +331,8 @@ function scanSessionFiles(rootDir = getOmpSessionPaths().sessions) {
|
|
|
294
331
|
}
|
|
295
332
|
|
|
296
333
|
async function getAllSessions(options = {}) {
|
|
297
|
-
const projects = await
|
|
298
|
-
const groups = await Promise.all(projects.map(project =>
|
|
334
|
+
const projects = await getSessionHistoryIndex().listProjects('omp', options);
|
|
335
|
+
const groups = await Promise.all(projects.map(project => getSessionHistoryIndex().listSessions('omp', project.name, options)));
|
|
299
336
|
return groups.flat().map(session => normalizeSession({
|
|
300
337
|
...session,
|
|
301
338
|
mtime: new Date(session.mtime).toISOString(),
|
|
@@ -316,34 +353,31 @@ function getOmpUsageEvents(rootDir = getOmpSessionPaths().sessions) {
|
|
|
316
353
|
});
|
|
317
354
|
}
|
|
318
355
|
|
|
319
|
-
|
|
320
|
-
|
|
356
|
+
const OMP_SELECTED_FIELDS = [
|
|
357
|
+
'type', 'id', 'timestamp', 'provider', 'model', 'modelId', 'cwd',
|
|
358
|
+
'role', 'message.role', 'message.id', 'message.timestamp', 'message.provider',
|
|
359
|
+
'message.model', 'message.modelId',
|
|
360
|
+
...usageFieldPaths('usage'),
|
|
361
|
+
...usageFieldPaths('message.usage')
|
|
362
|
+
];
|
|
321
363
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
signatures = nextSignatures;
|
|
341
|
-
return events;
|
|
342
|
-
},
|
|
343
|
-
reset() {
|
|
344
|
-
signatures = new Map();
|
|
364
|
+
function createOmpUsageEventCursor(rootDir = null, { skipInitialParse = false, onDiagnostic } = {}) {
|
|
365
|
+
return createIncrementalJsonlCursor({
|
|
366
|
+
scanFiles: () => scanSessionFiles(rootDir || getOmpSessionPaths().sessions),
|
|
367
|
+
createFileState: (filePath, _stat, previousState) => createSessionUsageParserState(
|
|
368
|
+
filePath,
|
|
369
|
+
[],
|
|
370
|
+
previousState || {}
|
|
371
|
+
),
|
|
372
|
+
parseLine: (filePath, record, state, index) => parseSessionUsageEntry(filePath, record, index, state),
|
|
373
|
+
fsImpl: fs,
|
|
374
|
+
skipInitialParse,
|
|
375
|
+
createLongLineParser: () => createSelectiveJsonLineParser(OMP_SELECTED_FIELDS),
|
|
376
|
+
onDiagnostic,
|
|
377
|
+
onError: (error, filePath) => {
|
|
378
|
+
console.warn('[OMP Sessions] Failed to read changed usage events:', filePath, error.message);
|
|
345
379
|
}
|
|
346
|
-
};
|
|
380
|
+
});
|
|
347
381
|
}
|
|
348
382
|
|
|
349
383
|
function loadProjectOrder() {
|
|
@@ -355,8 +389,8 @@ function loadSessionOrder() {
|
|
|
355
389
|
return safeReadJson(SESSION_ORDER_FILE, {});
|
|
356
390
|
}
|
|
357
391
|
|
|
358
|
-
async function getProjects(
|
|
359
|
-
const idxProjects = await
|
|
392
|
+
async function getProjects(options = {}) {
|
|
393
|
+
const idxProjects = await getSessionHistoryIndex().listProjects('omp', options);
|
|
360
394
|
const projects = idxProjects.map(p => ({
|
|
361
395
|
name: p.name,
|
|
362
396
|
path: p.fullPath || p.path || '',
|
|
@@ -383,8 +417,8 @@ async function getProjects(_options = {}) {
|
|
|
383
417
|
return projects;
|
|
384
418
|
}
|
|
385
419
|
|
|
386
|
-
async function getSessionsByProject(projectName,
|
|
387
|
-
const idxSessions = await
|
|
420
|
+
async function getSessionsByProject(projectName, options = {}) {
|
|
421
|
+
const idxSessions = await getSessionHistoryIndex().listSessions('omp', projectName, options);
|
|
388
422
|
const sessions = idxSessions.map(s => ({
|
|
389
423
|
sessionId: s.sessionId,
|
|
390
424
|
filePath: s.filePath,
|
|
@@ -437,7 +471,7 @@ function normalizeSession(session) {
|
|
|
437
471
|
}
|
|
438
472
|
|
|
439
473
|
async function getSessionById(sessionId) {
|
|
440
|
-
const status = await
|
|
474
|
+
const status = await getSessionHistoryIndex().getSessionStatus('omp', sessionId);
|
|
441
475
|
if (!status) return null;
|
|
442
476
|
return {
|
|
443
477
|
sessionId: status.sessionId,
|
|
@@ -465,7 +499,7 @@ async function getSessionMessages(sessionId) {
|
|
|
465
499
|
}
|
|
466
500
|
|
|
467
501
|
async function getRecentSessions(limit = 5) {
|
|
468
|
-
const indexed = await
|
|
502
|
+
const indexed = await getSessionHistoryIndex().getRecentSessions('omp', limit);
|
|
469
503
|
return indexed.map(session => normalizeSession({
|
|
470
504
|
...session,
|
|
471
505
|
mtime: new Date(session.mtime).toISOString(),
|
|
@@ -476,7 +510,7 @@ async function getRecentSessions(limit = 5) {
|
|
|
476
510
|
}
|
|
477
511
|
|
|
478
512
|
async function searchSessions(keyword, contextLength = 35, projectName = null) {
|
|
479
|
-
return
|
|
513
|
+
return getSessionHistoryIndex().searchSessions('omp', keyword, { contextLength, projectName });
|
|
480
514
|
}
|
|
481
515
|
|
|
482
516
|
async function deleteSession(sessionId) {
|
|
@@ -514,7 +548,7 @@ function saveSessionOrder(projectName, order) {
|
|
|
514
548
|
}
|
|
515
549
|
|
|
516
550
|
async function getProjectAndSessionCounts(options = {}) {
|
|
517
|
-
const projects = await
|
|
551
|
+
const projects = await getSessionHistoryIndex().listProjects('omp', options);
|
|
518
552
|
return {
|
|
519
553
|
projectCount: projects.length,
|
|
520
554
|
sessionCount: projects.reduce((sum, project) => sum + (project.sessionCount || 0), 0)
|
|
@@ -564,6 +598,7 @@ function isOmpCliInstalled() {
|
|
|
564
598
|
}
|
|
565
599
|
|
|
566
600
|
module.exports = {
|
|
601
|
+
configure,
|
|
567
602
|
buildLaunchCommand,
|
|
568
603
|
createOmpUsageEventCursor,
|
|
569
604
|
decodeProjectName,
|
|
@@ -573,6 +608,7 @@ module.exports = {
|
|
|
573
608
|
forkSession,
|
|
574
609
|
getAllSessions,
|
|
575
610
|
getOmpUsageEvents,
|
|
611
|
+
getOmpSessionPaths,
|
|
576
612
|
getProjectAndSessionCounts,
|
|
577
613
|
getProjects,
|
|
578
614
|
getRecentSessions,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { createCapabilityDriver } = require('../../../shared/capability-driver');
|
|
4
|
+
|
|
5
|
+
function createDriver(context = {}) {
|
|
6
|
+
return createCapabilityDriver({
|
|
7
|
+
...context,
|
|
8
|
+
platform: 'omp',
|
|
9
|
+
capability: 'sessions',
|
|
10
|
+
parserVersion: 2,
|
|
11
|
+
servicePath: './omp/sessions-implementation',
|
|
12
|
+
localServicePath: '../platforms/drivers/omp/sessions-implementation',
|
|
13
|
+
adapterLocalPath: '../platforms/drivers/omp/session-history-adapter',
|
|
14
|
+
adapterMethods: { inventory: 'inventory', parse: 'parse' },
|
|
15
|
+
methods: {
|
|
16
|
+
getProjects: 'getProjects',
|
|
17
|
+
listSessions: 'getSessionsByProject',
|
|
18
|
+
recent: 'getRecentSessions',
|
|
19
|
+
search: 'searchSessions',
|
|
20
|
+
getSessionById: 'getSessionById',
|
|
21
|
+
messages: 'getSessionMessages',
|
|
22
|
+
delete: 'deleteSession',
|
|
23
|
+
fork: 'forkSession',
|
|
24
|
+
saveSessionOrder: 'saveSessionOrder',
|
|
25
|
+
buildLaunchCommand: 'buildLaunchCommand',
|
|
26
|
+
status: 'getSessionStatus'
|
|
27
|
+
},
|
|
28
|
+
onSuccess: operation => {
|
|
29
|
+
if (['delete', 'fork', 'saveSessionOrder'].includes(operation)) {
|
|
30
|
+
context.sessionHistoryIndex?.invalidateSource('omp');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = { createDriver };
|
package/src/{server/services/omp-skill-discovery.js → platforms/drivers/omp/skill-discovery.js}
RENAMED
|
@@ -5,8 +5,9 @@ const {
|
|
|
5
5
|
getOmpCommand,
|
|
6
6
|
getOmpPaths,
|
|
7
7
|
readOmpSettings
|
|
8
|
-
} = require('./
|
|
9
|
-
const { HOME_DIR, NATIVE_PATHS } = require('
|
|
8
|
+
} = require('./config');
|
|
9
|
+
const { HOME_DIR, NATIVE_PATHS } = require('../../../config/paths');
|
|
10
|
+
const { assertNoSymlinkComponents } = require('../../../shared/project-config');
|
|
10
11
|
|
|
11
12
|
const DEFAULT_SKILL_SETTINGS = Object.freeze({
|
|
12
13
|
enabled: true,
|
|
@@ -23,6 +24,31 @@ const DEFAULT_SKILL_SETTINGS = Object.freeze({
|
|
|
23
24
|
disabledExtensions: []
|
|
24
25
|
});
|
|
25
26
|
|
|
27
|
+
const DISCOVERY_CACHE_TTL_MS = 1000;
|
|
28
|
+
const settingsCache = new Map();
|
|
29
|
+
const pluginPathsCache = new Map();
|
|
30
|
+
const discoveryCache = new Map();
|
|
31
|
+
|
|
32
|
+
function canonicalCwd(cwd) {
|
|
33
|
+
if (!cwd) return '';
|
|
34
|
+
const resolved = path.resolve(cwd);
|
|
35
|
+
try {
|
|
36
|
+
return fs.realpathSync(resolved);
|
|
37
|
+
} catch {
|
|
38
|
+
return resolved;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function cacheKey(cwd, scope = 'user') {
|
|
43
|
+
return `${scope}:${canonicalCwd(cwd)}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function cloneSkills(skills) {
|
|
47
|
+
return Array.isArray(skills)
|
|
48
|
+
? skills.map(skill => ({ ...skill, shadowedSources: Array.isArray(skill.shadowedSources) ? skill.shadowedSources.map(source => ({ ...source })) : [] }))
|
|
49
|
+
: [];
|
|
50
|
+
}
|
|
51
|
+
|
|
26
52
|
function expandHome(value) {
|
|
27
53
|
const input = String(value || '').trim();
|
|
28
54
|
if (input === '~') return HOME_DIR;
|
|
@@ -30,7 +56,7 @@ function expandHome(value) {
|
|
|
30
56
|
return input;
|
|
31
57
|
}
|
|
32
58
|
|
|
33
|
-
function
|
|
59
|
+
function _readEffectiveSettings(cwd) {
|
|
34
60
|
try {
|
|
35
61
|
const output = execFileSync(getOmpCommand(), ['config', 'list', '--json'], {
|
|
36
62
|
cwd: cwd || process.cwd(),
|
|
@@ -60,6 +86,18 @@ function readEffectiveSettings(cwd) {
|
|
|
60
86
|
}
|
|
61
87
|
}
|
|
62
88
|
|
|
89
|
+
function readEffectiveSettings(cwd, { force = false, scope = 'user' } = {}) {
|
|
90
|
+
const key = cacheKey(cwd, scope);
|
|
91
|
+
const now = Date.now();
|
|
92
|
+
const cached = settingsCache.get(key);
|
|
93
|
+
if (!force && cached && now - cached.checkedAt < DISCOVERY_CACHE_TTL_MS) {
|
|
94
|
+
return { ...cached.value };
|
|
95
|
+
}
|
|
96
|
+
const value = _readEffectiveSettings(cwd);
|
|
97
|
+
settingsCache.set(key, { value, checkedAt: now });
|
|
98
|
+
return { ...value };
|
|
99
|
+
}
|
|
100
|
+
|
|
63
101
|
function globMatches(value, pattern) {
|
|
64
102
|
const escaped = String(pattern || '')
|
|
65
103
|
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
@@ -84,6 +122,7 @@ function isIncluded(name, settings) {
|
|
|
84
122
|
function parseSkill(service, skillFile, provider, scope, requireDescription) {
|
|
85
123
|
let metadata;
|
|
86
124
|
try {
|
|
125
|
+
if (fs.lstatSync(skillFile).isSymbolicLink()) return null;
|
|
87
126
|
metadata = service.parseSkillMd(fs.readFileSync(skillFile, 'utf8'));
|
|
88
127
|
} catch {
|
|
89
128
|
return null;
|
|
@@ -104,6 +143,9 @@ function parseSkill(service, skillFile, provider, scope, requireDescription) {
|
|
|
104
143
|
const native = provider === 'native';
|
|
105
144
|
return {
|
|
106
145
|
key: `omp:${provider}:${scope}:${realPath}`,
|
|
146
|
+
sourceKey: native
|
|
147
|
+
? `native:omp:${directory}`
|
|
148
|
+
: `omp:${provider}:${directory}`,
|
|
107
149
|
name,
|
|
108
150
|
description,
|
|
109
151
|
directory,
|
|
@@ -125,8 +167,29 @@ function parseSkill(service, skillFile, provider, scope, requireDescription) {
|
|
|
125
167
|
};
|
|
126
168
|
}
|
|
127
169
|
|
|
128
|
-
function
|
|
170
|
+
function isSafeProjectScanRoot(root, projectRoot) {
|
|
171
|
+
if (!root || !projectRoot) return false;
|
|
172
|
+
const requestedRoot = path.resolve(root);
|
|
173
|
+
const requestedProjectRoot = path.resolve(projectRoot);
|
|
174
|
+
try {
|
|
175
|
+
const projectStat = fs.lstatSync(requestedProjectRoot);
|
|
176
|
+
const rootStat = fs.lstatSync(requestedRoot);
|
|
177
|
+
if (projectStat.isSymbolicLink() || rootStat.isSymbolicLink()) return false;
|
|
178
|
+
if (!projectStat.isDirectory() || !rootStat.isDirectory()) return false;
|
|
179
|
+
const resolvedProjectRoot = fs.realpathSync(requestedProjectRoot);
|
|
180
|
+
const resolvedRoot = fs.realpathSync(requestedRoot);
|
|
181
|
+
const relative = path.relative(resolvedProjectRoot, resolvedRoot);
|
|
182
|
+
if (relative.startsWith(`..${path.sep}`) || relative === '..' || path.isAbsolute(relative)) return false;
|
|
183
|
+
assertNoSymlinkComponents(resolvedProjectRoot, resolvedRoot, fs);
|
|
184
|
+
return true;
|
|
185
|
+
} catch {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function scanOneLevel(service, root, descriptor, settings, projectRoot = null) {
|
|
129
191
|
if (!root || !fs.existsSync(root)) return [];
|
|
192
|
+
if (descriptor.scope === 'project' && !isSafeProjectScanRoot(root, projectRoot)) return [];
|
|
130
193
|
const result = [];
|
|
131
194
|
let entries = [];
|
|
132
195
|
try {
|
|
@@ -136,15 +199,8 @@ function scanOneLevel(service, root, descriptor, settings) {
|
|
|
136
199
|
}
|
|
137
200
|
|
|
138
201
|
for (const entry of entries) {
|
|
202
|
+
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
139
203
|
const entryPath = path.join(root, entry.name);
|
|
140
|
-
if (!entry.isDirectory()) {
|
|
141
|
-
if (!entry.isSymbolicLink()) continue;
|
|
142
|
-
try {
|
|
143
|
-
if (!fs.statSync(entryPath).isDirectory()) continue;
|
|
144
|
-
} catch {
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
204
|
const skillFile = path.join(entryPath, 'SKILL.md');
|
|
149
205
|
if (!fs.existsSync(skillFile)) continue;
|
|
150
206
|
const skill = parseSkill(
|
|
@@ -161,7 +217,7 @@ function scanOneLevel(service, root, descriptor, settings) {
|
|
|
161
217
|
return result;
|
|
162
218
|
}
|
|
163
219
|
|
|
164
|
-
function
|
|
220
|
+
function _getPluginInstallPaths(cwd) {
|
|
165
221
|
try {
|
|
166
222
|
const output = execFileSync(getOmpCommand(), ['plugin', 'list', '--json'], {
|
|
167
223
|
cwd: cwd || process.cwd(),
|
|
@@ -196,6 +252,18 @@ function getPluginInstallPaths(cwd) {
|
|
|
196
252
|
}
|
|
197
253
|
}
|
|
198
254
|
|
|
255
|
+
function getPluginInstallPaths(cwd, { force = false, scope = 'user' } = {}) {
|
|
256
|
+
const key = cacheKey(cwd, scope);
|
|
257
|
+
const now = Date.now();
|
|
258
|
+
const cached = pluginPathsCache.get(key);
|
|
259
|
+
if (!force && cached && now - cached.checkedAt < DISCOVERY_CACHE_TTL_MS) {
|
|
260
|
+
return cached.value.map(item => ({ ...item }));
|
|
261
|
+
}
|
|
262
|
+
const value = _getPluginInstallPaths(cwd);
|
|
263
|
+
pluginPathsCache.set(key, { value, checkedAt: now });
|
|
264
|
+
return value.map(item => ({ ...item }));
|
|
265
|
+
}
|
|
266
|
+
|
|
199
267
|
function getClaudePluginSkillRoots() {
|
|
200
268
|
const pluginsDir = NATIVE_PATHS.claude.plugins
|
|
201
269
|
|| path.join(NATIVE_PATHS.claude.dir, 'plugins');
|
|
@@ -266,37 +334,63 @@ function compactShadow(skill) {
|
|
|
266
334
|
}
|
|
267
335
|
|
|
268
336
|
function deduplicateDiscoveredSkills(skills) {
|
|
269
|
-
const
|
|
337
|
+
const byIdentity = new Map();
|
|
270
338
|
const byRealPath = new Map();
|
|
271
339
|
const result = [];
|
|
340
|
+
const priority = skill => skill.sourceScope === 'project' ? 2 : 1;
|
|
341
|
+
const identityFor = skill => String(
|
|
342
|
+
skill.sourceKey || `${skill.sourceProvider || 'unknown'}:${String(skill.name || '').toLowerCase()}`
|
|
343
|
+
);
|
|
272
344
|
|
|
273
345
|
for (const skill of skills) {
|
|
274
|
-
const
|
|
346
|
+
const identity = identityFor(skill);
|
|
275
347
|
const pathKey = skill.realPath || skill.sourcePath;
|
|
276
|
-
const existing =
|
|
277
|
-
if (existing) {
|
|
278
|
-
|
|
348
|
+
const existing = byIdentity.get(identity) || byRealPath.get(pathKey);
|
|
349
|
+
if (!existing) {
|
|
350
|
+
byIdentity.set(identity, skill);
|
|
351
|
+
if (pathKey) byRealPath.set(pathKey, skill);
|
|
352
|
+
result.push(skill);
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (priority(skill) > priority(existing)) {
|
|
357
|
+
skill.shadowedSources.push(compactShadow(existing));
|
|
358
|
+
const index = result.indexOf(existing);
|
|
359
|
+
if (index >= 0) result[index] = skill;
|
|
360
|
+
for (const [key, value] of byIdentity) {
|
|
361
|
+
if (value === existing) byIdentity.delete(key);
|
|
362
|
+
}
|
|
363
|
+
for (const [key, value] of byRealPath) {
|
|
364
|
+
if (value === existing) byRealPath.delete(key);
|
|
365
|
+
}
|
|
366
|
+
byIdentity.set(identity, skill);
|
|
367
|
+
if (pathKey) byRealPath.set(pathKey, skill);
|
|
279
368
|
continue;
|
|
280
369
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
result.push(skill);
|
|
370
|
+
|
|
371
|
+
existing.shadowedSources.push(compactShadow(skill));
|
|
284
372
|
}
|
|
285
373
|
|
|
286
374
|
return result;
|
|
287
375
|
}
|
|
288
376
|
|
|
289
|
-
function
|
|
290
|
-
const cwd = options.cwd ?
|
|
291
|
-
const settings = readEffectiveSettings(cwd);
|
|
377
|
+
function _discoverOmpSkills(service, options = {}, settings = readEffectiveSettings(options.cwd), pluginPaths = getPluginInstallPaths(options.cwd), claudePluginRoots = getClaudePluginSkillRoots()) {
|
|
378
|
+
const cwd = options.cwd ? canonicalCwd(options.cwd) : null;
|
|
292
379
|
if (settings.enabled === false) return [];
|
|
293
380
|
|
|
294
|
-
const
|
|
295
|
-
const
|
|
381
|
+
const customNative = options.pathContext?.customized ? (options.pathContext.native || {}) : null;
|
|
382
|
+
const ompPaths = customNative
|
|
383
|
+
? {
|
|
384
|
+
...getOmpPaths(),
|
|
385
|
+
...customNative,
|
|
386
|
+
agentDir: customNative.dir || options.pathContext.home
|
|
387
|
+
}
|
|
388
|
+
: getOmpPaths();
|
|
389
|
+
const userHome = options.pathContext?.customized ? options.pathContext.home : HOME_DIR;
|
|
296
390
|
const descriptors = [
|
|
297
391
|
{ provider: 'native', scope: 'user', root: ompPaths.skills, requireDescription: true },
|
|
298
392
|
...(cwd ? [{ provider: 'native', scope: 'project', root: path.join(cwd, '.omp', 'skills'), requireDescription: true }] : []),
|
|
299
|
-
...
|
|
393
|
+
...pluginPaths
|
|
300
394
|
.filter(item => cwd || item.scope !== 'project')
|
|
301
395
|
.map(item => ({
|
|
302
396
|
provider: 'omp-plugins',
|
|
@@ -306,7 +400,7 @@ function discoverOmpSkills(service, options = {}) {
|
|
|
306
400
|
})),
|
|
307
401
|
{ provider: 'claude', scope: 'user', root: NATIVE_PATHS.claude.skills, requireDescription: false },
|
|
308
402
|
...(cwd ? [{ provider: 'claude', scope: 'project', root: path.join(cwd, '.claude', 'skills'), requireDescription: false }] : []),
|
|
309
|
-
...
|
|
403
|
+
...claudePluginRoots
|
|
310
404
|
.filter(item => cwd || item.scope !== 'project')
|
|
311
405
|
.map(item => ({
|
|
312
406
|
provider: 'claude-plugins',
|
|
@@ -329,7 +423,7 @@ function discoverOmpSkills(service, options = {}) {
|
|
|
329
423
|
const discovered = [];
|
|
330
424
|
for (const descriptor of descriptors) {
|
|
331
425
|
if (!providerEnabled(settings, descriptor.provider, descriptor.scope)) continue;
|
|
332
|
-
discovered.push(...scanOneLevel(service, descriptor.root, descriptor, settings));
|
|
426
|
+
discovered.push(...scanOneLevel(service, descriptor.root, descriptor, settings, cwd));
|
|
333
427
|
}
|
|
334
428
|
|
|
335
429
|
const customDirectories = Array.isArray(settings.customDirectories)
|
|
@@ -338,18 +432,51 @@ function discoverOmpSkills(service, options = {}) {
|
|
|
338
432
|
for (const customDirectory of customDirectories) {
|
|
339
433
|
const expanded = expandHome(customDirectory);
|
|
340
434
|
const root = path.isAbsolute(expanded)
|
|
341
|
-
? expanded
|
|
435
|
+
? path.resolve(expanded)
|
|
342
436
|
: path.resolve(cwd || process.cwd(), expanded);
|
|
437
|
+
const relative = cwd ? path.relative(cwd, root) : '..';
|
|
438
|
+
const isProjectRoot = Boolean(
|
|
439
|
+
cwd
|
|
440
|
+
&& relative !== '..'
|
|
441
|
+
&& !relative.startsWith(`..${path.sep}`)
|
|
442
|
+
&& !path.isAbsolute(relative)
|
|
443
|
+
);
|
|
343
444
|
discovered.push(...scanOneLevel(service, root, {
|
|
344
445
|
provider: 'custom',
|
|
345
|
-
scope:
|
|
446
|
+
scope: isProjectRoot ? 'project' : 'user',
|
|
346
447
|
requireDescription: true
|
|
347
|
-
}, settings));
|
|
448
|
+
}, settings, isProjectRoot ? cwd : null));
|
|
348
449
|
}
|
|
349
450
|
|
|
350
451
|
return deduplicateDiscoveredSkills(discovered);
|
|
351
452
|
}
|
|
352
453
|
|
|
454
|
+
function discoverOmpSkills(service, options = {}) {
|
|
455
|
+
const scope = options.scope || 'user';
|
|
456
|
+
const cwd = options.cwd ? canonicalCwd(options.cwd) : null;
|
|
457
|
+
const settings = readEffectiveSettings(cwd, { force: options.force === true, scope });
|
|
458
|
+
if (settings.enabled === false) return [];
|
|
459
|
+
const pluginPaths = getPluginInstallPaths(cwd, { force: options.force === true, scope });
|
|
460
|
+
const claudePluginRoots = getClaudePluginSkillRoots();
|
|
461
|
+
const fingerprint = JSON.stringify({
|
|
462
|
+
settings,
|
|
463
|
+
pluginPaths,
|
|
464
|
+
claudePluginRoots,
|
|
465
|
+
pathContext: options.pathContext?.customized ? options.pathContext : null
|
|
466
|
+
});
|
|
467
|
+
const key = cacheKey(cwd, scope);
|
|
468
|
+
const now = Date.now();
|
|
469
|
+
const cached = discoveryCache.get(key);
|
|
470
|
+
if (!options.force && cached
|
|
471
|
+
&& cached.fingerprint === fingerprint
|
|
472
|
+
&& now - cached.checkedAt < DISCOVERY_CACHE_TTL_MS) {
|
|
473
|
+
return cloneSkills(cached.skills);
|
|
474
|
+
}
|
|
475
|
+
const discovered = _discoverOmpSkills(service, { ...options, cwd, scope }, settings, pluginPaths, claudePluginRoots);
|
|
476
|
+
discoveryCache.set(key, { fingerprint, checkedAt: now, skills: cloneSkills(discovered) });
|
|
477
|
+
return cloneSkills(discovered);
|
|
478
|
+
}
|
|
479
|
+
|
|
353
480
|
module.exports = {
|
|
354
481
|
DEFAULT_SKILL_SETTINGS,
|
|
355
482
|
discoverOmpSkills,
|