claude-code-workflow 6.1.4 → 6.2.2
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/.claude/CLAUDE.md +10 -0
- package/.claude/agents/action-planning-agent.md +857 -778
- package/.claude/agents/cli-execution-agent.md +266 -269
- package/.claude/agents/cli-explore-agent.md +2 -2
- package/.claude/agents/cli-lite-planning-agent.md +142 -92
- package/.claude/agents/cli-planning-agent.md +4 -4
- package/.claude/agents/code-developer.md +7 -6
- package/.claude/agents/conceptual-planning-agent.md +2 -2
- package/.claude/agents/context-search-agent.md +31 -32
- package/.claude/agents/doc-generator.md +4 -4
- package/.claude/agents/memory-bridge.md +93 -93
- package/.claude/agents/test-context-search-agent.md +8 -7
- package/.claude/agents/test-fix-agent.md +7 -6
- package/.claude/commands/clean.md +516 -0
- package/.claude/commands/memory/compact.md +383 -0
- package/.claude/commands/memory/docs-full-cli.md +471 -471
- package/.claude/commands/memory/docs-related-cli.md +386 -386
- package/.claude/commands/memory/docs.md +615 -615
- package/.claude/commands/memory/load.md +5 -5
- package/.claude/commands/memory/tech-research-rules.md +310 -0
- package/.claude/commands/memory/update-full.md +332 -332
- package/.claude/commands/memory/workflow-skill-memory.md +4 -4
- package/.claude/commands/task/create.md +151 -151
- package/.claude/commands/version.md +254 -254
- package/.claude/commands/workflow/brainstorm/api-designer.md +587 -585
- package/.claude/commands/workflow/brainstorm/artifacts.md +1 -0
- package/.claude/commands/workflow/brainstorm/auto-parallel.md +443 -443
- package/.claude/commands/workflow/brainstorm/data-architect.md +220 -220
- package/.claude/commands/workflow/brainstorm/product-manager.md +200 -200
- package/.claude/commands/workflow/brainstorm/product-owner.md +200 -200
- package/.claude/commands/workflow/brainstorm/scrum-master.md +200 -200
- package/.claude/commands/workflow/brainstorm/subject-matter-expert.md +200 -200
- package/.claude/commands/workflow/brainstorm/system-architect.md +389 -387
- package/.claude/commands/workflow/brainstorm/ui-designer.md +221 -221
- package/.claude/commands/workflow/brainstorm/ux-expert.md +221 -221
- package/.claude/commands/workflow/debug.md +321 -0
- package/.claude/commands/workflow/execute.md +13 -0
- package/.claude/commands/workflow/init.md +165 -164
- package/.claude/commands/workflow/lite-execute.md +119 -13
- package/.claude/commands/workflow/lite-fix.md +623 -621
- package/.claude/commands/workflow/lite-plan.md +610 -592
- package/.claude/commands/workflow/plan.md +5 -5
- package/.claude/commands/workflow/review-module-cycle.md +2 -0
- package/.claude/commands/workflow/review-session-cycle.md +2 -0
- package/.claude/commands/workflow/review.md +297 -291
- package/.claude/commands/workflow/session/complete.md +153 -500
- package/.claude/commands/workflow/session/list.md +95 -95
- package/.claude/commands/workflow/session/resume.md +60 -60
- package/.claude/commands/workflow/session/start.md +199 -199
- package/.claude/commands/workflow/tdd-plan.md +3 -3
- package/.claude/commands/workflow/tdd-verify.md +23 -9
- package/.claude/commands/workflow/test-cycle-execute.md +2 -0
- package/.claude/commands/workflow/test-fix-gen.md +699 -699
- package/.claude/commands/workflow/tools/conflict-resolution.md +104 -18
- package/.claude/commands/workflow/tools/context-gather.md +436 -434
- package/.claude/commands/workflow/tools/task-generate-agent.md +490 -291
- package/.claude/commands/workflow/tools/task-generate-tdd.md +18 -10
- package/.claude/commands/workflow/tools/test-concept-enhanced.md +2 -1
- package/.claude/commands/workflow/tools/test-context-gather.md +1 -0
- package/.claude/commands/workflow/tools/test-task-generate.md +1 -0
- package/.claude/commands/workflow/ui-design/import-from-code.md +9 -6
- package/.claude/skills/command-guide/SKILL.md +5 -5
- package/.claude/skills/command-guide/index/all-commands.json +1 -1
- package/.claude/skills/command-guide/index/by-category.json +1 -1
- package/.claude/skills/command-guide/index/by-use-case.json +1 -1
- package/.claude/skills/command-guide/reference/agents/action-planning-agent.md +857 -778
- package/.claude/skills/command-guide/reference/agents/cli-execution-agent.md +266 -269
- package/.claude/skills/command-guide/reference/agents/cli-explore-agent.md +2 -2
- package/.claude/skills/command-guide/reference/agents/cli-lite-planning-agent.md +142 -92
- package/.claude/skills/command-guide/reference/agents/cli-planning-agent.md +4 -4
- package/.claude/skills/command-guide/reference/agents/code-developer.md +7 -6
- package/.claude/skills/command-guide/reference/agents/conceptual-planning-agent.md +2 -2
- package/.claude/skills/command-guide/reference/agents/context-search-agent.md +31 -32
- package/.claude/skills/command-guide/reference/agents/doc-generator.md +4 -4
- package/.claude/skills/command-guide/reference/agents/memory-bridge.md +93 -93
- package/.claude/skills/command-guide/reference/agents/test-context-search-agent.md +8 -7
- package/.claude/skills/command-guide/reference/agents/test-fix-agent.md +7 -6
- package/.claude/skills/command-guide/reference/commands/memory/docs-full-cli.md +471 -471
- package/.claude/skills/command-guide/reference/commands/memory/docs-related-cli.md +386 -386
- package/.claude/skills/command-guide/reference/commands/memory/docs.md +17 -16
- package/.claude/skills/command-guide/reference/commands/memory/load.md +5 -5
- package/.claude/skills/command-guide/reference/commands/memory/tech-research.md +194 -357
- package/.claude/skills/command-guide/reference/commands/memory/update-full.md +332 -332
- package/.claude/skills/command-guide/reference/commands/memory/workflow-skill-memory.md +4 -4
- package/.claude/skills/command-guide/reference/commands/task/create.md +151 -151
- package/.claude/skills/command-guide/reference/commands/version.md +254 -254
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/api-designer.md +585 -585
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/auto-parallel.md +443 -443
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/data-architect.md +220 -220
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-manager.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-owner.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/scrum-master.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/subject-matter-expert.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/system-architect.md +387 -387
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ui-designer.md +221 -221
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ux-expert.md +221 -221
- package/.claude/skills/command-guide/reference/commands/workflow/execute.md +25 -20
- package/.claude/skills/command-guide/reference/commands/workflow/init.md +164 -164
- package/.claude/skills/command-guide/reference/commands/workflow/lite-execute.md +748 -686
- package/.claude/skills/command-guide/reference/commands/workflow/lite-fix.md +664 -621
- package/.claude/skills/command-guide/reference/commands/workflow/lite-plan.md +645 -592
- package/.claude/skills/command-guide/reference/commands/workflow/plan.md +5 -5
- package/.claude/skills/command-guide/reference/commands/workflow/review.md +25 -18
- package/.claude/skills/command-guide/reference/commands/workflow/session/complete.md +547 -500
- package/.claude/skills/command-guide/reference/commands/workflow/session/list.md +45 -27
- package/.claude/skills/command-guide/reference/commands/workflow/session/resume.md +35 -19
- package/.claude/skills/command-guide/reference/commands/workflow/session/start.md +90 -33
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-plan.md +3 -3
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-verify.md +23 -9
- package/.claude/skills/command-guide/reference/commands/workflow/test-fix-gen.md +699 -699
- package/.claude/skills/command-guide/reference/commands/workflow/tools/conflict-resolution.md +103 -17
- package/.claude/skills/command-guide/reference/commands/workflow/tools/context-gather.md +434 -434
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-agent.md +487 -291
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-tdd.md +17 -10
- package/.claude/skills/command-guide/reference/commands/workflow/tools/test-concept-enhanced.md +1 -1
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/import-from-code.md +6 -6
- package/.claude/workflows/chinese-response.md +38 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-api.txt +122 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-components.txt +122 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-config.txt +89 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-core.txt +60 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-patterns.txt +70 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-testing.txt +81 -0
- package/.claude/workflows/cli-templates/prompts/rules/tech-rules-agent-prompt.txt +89 -0
- package/.claude/workflows/cli-templates/prompts/workflow/gemini-solution-design.txt +131 -131
- package/.claude/workflows/cli-templates/prompts/workflow/skill-conflict-patterns.txt +5 -9
- package/.claude/workflows/cli-templates/prompts/workflow/skill-lessons-learned.txt +5 -9
- package/.claude/workflows/cli-templates/protocols/analysis-protocol.md +112 -0
- package/.claude/workflows/cli-templates/protocols/write-protocol.md +201 -0
- package/.claude/workflows/cli-templates/schemas/conflict-resolution-schema.json +137 -0
- package/.claude/workflows/cli-templates/schemas/debug-log-json-schema.json +127 -0
- package/.claude/workflows/cli-templates/schemas/fix-plan-json-schema.json +25 -0
- package/.claude/workflows/cli-templates/schemas/plan-json-schema.json +25 -0
- package/.claude/workflows/cli-tools-usage.md +526 -0
- package/{CLAUDE.md → .claude/workflows/coding-philosophy.md} +24 -45
- package/.claude/workflows/context-tools.md +84 -0
- package/.claude/workflows/file-modification.md +64 -0
- package/.claude/workflows/tool-strategy.md +216 -79
- package/.claude/workflows/windows-platform.md +16 -0
- package/.claude/workflows/workflow-architecture.md +942 -942
- package/.codex/AGENTS.md +63 -330
- package/.codex/prompts/debug.md +318 -0
- package/.codex/prompts/execute.md +273 -0
- package/.codex/prompts/lite-execute.md +164 -0
- package/.codex/prompts/lite-plan.md +469 -0
- package/.codex/prompts.zip +0 -0
- package/.gemini/GEMINI.md +25 -164
- package/.qwen/QWEN.md +0 -139
- package/README.md +29 -9
- package/ccw/README.md +30 -6
- package/ccw/bin/ccw-mcp.js +7 -0
- package/ccw/bin/ccw.js +9 -9
- package/ccw/package.json +65 -47
- package/ccw/src/.workflow/.cli-history/history.db +0 -0
- package/ccw/src/.workflow/.cli-history/history.db-shm +0 -0
- package/ccw/src/.workflow/.cli-history/history.db-wal +0 -0
- package/ccw/src/cli.ts +244 -0
- package/ccw/src/commands/cli.ts +740 -0
- package/ccw/src/commands/core-memory.ts +770 -0
- package/ccw/src/commands/hook.ts +315 -0
- package/ccw/src/commands/install.ts +519 -0
- package/ccw/src/commands/{list.js → list.ts} +1 -1
- package/ccw/src/commands/memory.ts +1090 -0
- package/ccw/src/commands/{serve.js → serve.ts} +14 -5
- package/ccw/src/commands/session-path-resolver.ts +372 -0
- package/ccw/src/commands/session.ts +1141 -0
- package/ccw/src/commands/{stop.js → stop.ts} +16 -6
- package/ccw/src/commands/tool.ts +201 -0
- package/ccw/src/commands/{uninstall.js → uninstall.ts} +89 -40
- package/ccw/src/commands/{upgrade.js → upgrade.ts} +68 -23
- package/ccw/src/commands/{view.js → view.ts} +22 -8
- package/ccw/src/config/storage-paths.ts +670 -0
- package/ccw/src/core/cache-manager.ts +294 -0
- package/ccw/src/core/claude-freshness.ts +319 -0
- package/ccw/src/core/core-memory-store.ts +1528 -0
- package/ccw/src/core/{dashboard-generator-patch.js → dashboard-generator-patch.ts} +18 -0
- package/ccw/src/core/{dashboard-generator.js → dashboard-generator.ts} +69 -12
- package/ccw/src/core/data-aggregator.ts +584 -0
- package/ccw/src/core/history-importer.ts +625 -0
- package/ccw/src/core/{lite-scanner.js → lite-scanner-complete.ts} +162 -66
- package/ccw/src/core/lite-scanner.ts +469 -0
- package/ccw/src/core/{manifest.js → manifest.ts} +104 -34
- package/ccw/src/core/memory-embedder-bridge.ts +262 -0
- package/ccw/src/core/memory-store.ts +978 -0
- package/ccw/src/core/routes/ccw-routes.ts +96 -0
- package/ccw/src/core/routes/claude-routes.ts +1183 -0
- package/ccw/src/core/routes/cli-routes.ts +561 -0
- package/ccw/src/core/routes/codexlens-routes.ts +806 -0
- package/ccw/src/core/routes/core-memory-routes.ts +605 -0
- package/ccw/src/core/routes/files-routes.ts +428 -0
- package/ccw/src/core/routes/graph-routes.md +164 -0
- package/ccw/src/core/routes/graph-routes.ts +626 -0
- package/ccw/src/core/routes/help-routes.ts +308 -0
- package/ccw/src/core/routes/hooks-routes.ts +405 -0
- package/ccw/src/core/routes/mcp-routes.ts +1271 -0
- package/ccw/src/core/routes/mcp-routes.ts.backup +550 -0
- package/ccw/src/core/routes/mcp-templates-db.ts +268 -0
- package/ccw/src/core/routes/memory-routes.ts +1206 -0
- package/ccw/src/core/routes/rules-routes.ts +526 -0
- package/ccw/src/core/routes/session-routes.ts +467 -0
- package/ccw/src/core/routes/skills-routes.ts +599 -0
- package/ccw/src/core/routes/status-routes.ts +57 -0
- package/ccw/src/core/routes/system-routes.ts +427 -0
- package/ccw/src/core/server.ts +431 -0
- package/ccw/src/core/session-clustering-service.ts +1258 -0
- package/ccw/src/core/session-scanner.ts +283 -0
- package/ccw/src/core/websocket.ts +190 -0
- package/ccw/src/{index.js → index.ts} +1 -0
- package/ccw/src/mcp-server/index.ts +186 -0
- package/ccw/src/templates/assets/css/github-dark.min.css +10 -0
- package/ccw/src/templates/assets/css/github.min.css +10 -0
- package/ccw/src/templates/assets/js/cytoscape.min.js +32 -0
- package/ccw/src/templates/assets/js/d3.min.js +2 -0
- package/ccw/src/templates/assets/js/highlight.min.js +1244 -0
- package/ccw/src/templates/assets/js/lucide.min.js +12 -0
- package/ccw/src/templates/assets/js/marked.min.js +69 -0
- package/ccw/src/templates/assets/js/tailwind.js +83 -0
- package/ccw/src/templates/dashboard-css/01-base.css +11 -0
- package/ccw/src/templates/dashboard-css/02-session.css +22 -0
- package/ccw/src/templates/dashboard-css/04-lite-tasks.css +10 -0
- package/ccw/src/templates/dashboard-css/06-cards.css +10 -4
- package/ccw/src/templates/dashboard-css/07-managers.css +1178 -7
- package/ccw/src/templates/dashboard-css/09-explorer.css +23 -12
- package/ccw/src/templates/dashboard-css/10-cli-status.css +337 -0
- package/ccw/src/templates/dashboard-css/11-cli-history.css +271 -0
- package/ccw/src/templates/dashboard-css/12-cli-legacy.css +796 -0
- package/ccw/src/templates/dashboard-css/13-cli-ccw.css +199 -0
- package/ccw/src/templates/dashboard-css/14-cli-modals.css +258 -0
- package/ccw/src/templates/dashboard-css/15-cli-endpoints.css +305 -0
- package/ccw/src/templates/dashboard-css/16-cli-session.css +241 -0
- package/ccw/src/templates/dashboard-css/17-cli-conversation.css +283 -0
- package/ccw/src/templates/dashboard-css/18-cli-settings.css +160 -0
- package/ccw/src/templates/dashboard-css/19-cli-native-session.css +496 -0
- package/ccw/src/templates/dashboard-css/20-cli-taskqueue.css +188 -0
- package/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +310 -0
- package/ccw/src/templates/dashboard-css/22-cli-semantic.css +240 -0
- package/ccw/src/templates/dashboard-css/23-memory.css +2390 -0
- package/ccw/src/templates/dashboard-css/24-prompt-history.css +1089 -0
- package/ccw/src/templates/dashboard-css/25-skills-rules.css +326 -0
- package/ccw/src/templates/dashboard-css/26-claude-manager.css +908 -0
- package/ccw/src/templates/dashboard-css/27-graph-explorer.css +1678 -0
- package/ccw/src/templates/dashboard-css/28-mcp-manager.css +748 -0
- package/ccw/src/templates/dashboard-css/29-help.css +264 -0
- package/ccw/src/templates/dashboard-css/30-core-memory.css +1700 -0
- package/ccw/src/templates/dashboard-js/api.js +162 -142
- package/ccw/src/templates/dashboard-js/components/carousel.js +4 -4
- package/ccw/src/templates/dashboard-js/components/cli-history.js +876 -0
- package/ccw/src/templates/dashboard-js/components/cli-status.js +978 -0
- package/ccw/src/templates/dashboard-js/components/global-notifications.js +508 -219
- package/ccw/src/templates/dashboard-js/components/hook-manager.js +1277 -282
- package/ccw/src/templates/dashboard-js/components/index-manager.js +302 -0
- package/ccw/src/templates/dashboard-js/components/mcp-manager.js +718 -27
- package/ccw/src/templates/dashboard-js/components/modals.js +66 -0
- package/ccw/src/templates/dashboard-js/components/navigation.js +80 -12
- package/ccw/src/templates/dashboard-js/components/notifications.js +758 -194
- package/ccw/src/templates/dashboard-js/components/storage-manager.js +478 -0
- package/ccw/src/templates/dashboard-js/components/tabs-other.js +157 -6
- package/ccw/src/templates/dashboard-js/components/task-queue-sidebar.js +716 -0
- package/ccw/src/templates/dashboard-js/help-i18n.js +272 -0
- package/ccw/src/templates/dashboard-js/i18n.js +2807 -0
- package/ccw/src/templates/dashboard-js/main.js +15 -0
- package/ccw/src/templates/dashboard-js/state.js +243 -42
- package/ccw/src/templates/dashboard-js/utils.js +47 -1
- package/ccw/src/templates/dashboard-js/views/claude-manager.js +912 -0
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +2272 -0
- package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +964 -0
- package/ccw/src/templates/dashboard-js/views/core-memory-clusters.js +503 -0
- package/ccw/src/templates/dashboard-js/views/core-memory.js +782 -0
- package/ccw/src/templates/dashboard-js/views/explorer.js +888 -852
- package/ccw/src/templates/dashboard-js/views/graph-explorer.js +1157 -0
- package/ccw/src/templates/dashboard-js/views/help.js +856 -0
- package/ccw/src/templates/dashboard-js/views/history.js +337 -0
- package/ccw/src/templates/dashboard-js/views/home.js +61 -15
- package/ccw/src/templates/dashboard-js/views/hook-manager.js +311 -43
- package/ccw/src/templates/dashboard-js/views/lite-tasks.js +204 -28
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js +2187 -411
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js.backup +1729 -0
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js.new +928 -0
- package/ccw/src/templates/dashboard-js/views/memory.js +1221 -0
- package/ccw/src/templates/dashboard-js/views/prompt-history.js +713 -0
- package/ccw/src/templates/dashboard-js/views/rules-manager.js +828 -0
- package/ccw/src/templates/dashboard-js/views/session-detail.js +54 -53
- package/ccw/src/templates/dashboard-js/views/skills-manager.js +819 -0
- package/ccw/src/templates/dashboard.html +185 -85
- package/ccw/src/templates/hooks-config-example.json +60 -0
- package/ccw/src/tools/classify-folders.ts +245 -0
- package/ccw/src/tools/cli-config-manager.ts +268 -0
- package/ccw/src/tools/cli-executor.ts +2014 -0
- package/ccw/src/tools/cli-history-store.ts +1195 -0
- package/ccw/src/tools/codex-lens.ts +1141 -0
- package/ccw/src/tools/{convert-tokens-to-css.js → convert-tokens-to-css.ts} +73 -23
- package/ccw/src/tools/core-memory.ts +444 -0
- package/ccw/src/tools/detect-changed-modules.ts +325 -0
- package/ccw/src/tools/{discover-design-files.js → discover-design-files.ts} +74 -24
- package/ccw/src/tools/edit-file.ts +568 -0
- package/ccw/src/tools/{generate-module-docs.js → generate-module-docs.ts} +207 -185
- package/ccw/src/tools/{get-modules-by-depth.js → get-modules-by-depth.ts} +120 -79
- package/ccw/src/tools/index.ts +370 -0
- package/ccw/src/tools/native-session-discovery.ts +795 -0
- package/ccw/src/tools/notifier.ts +129 -0
- package/ccw/src/tools/read-file.ts +410 -0
- package/ccw/src/tools/resume-strategy.ts +345 -0
- package/ccw/src/tools/session-content-parser.ts +619 -0
- package/ccw/src/tools/session-manager.ts +1026 -0
- package/ccw/src/tools/smart-context.ts +228 -0
- package/ccw/src/tools/smart-search.ts +2065 -0
- package/ccw/src/tools/smart-search.ts.backup +1233 -0
- package/ccw/src/tools/storage-manager.ts +455 -0
- package/ccw/src/tools/write-file.ts +222 -0
- package/ccw/src/types/config.ts +11 -0
- package/ccw/src/types/index.ts +3 -0
- package/ccw/src/types/session.ts +25 -0
- package/ccw/src/types/tool.ts +41 -0
- package/ccw/src/utils/{browser-launcher.js → browser-launcher.ts} +10 -8
- package/ccw/src/utils/file-utils.ts +48 -0
- package/ccw/src/utils/{path-resolver.js → path-resolver.ts} +114 -78
- package/ccw/src/utils/path-validator.ts +153 -0
- package/ccw/src/utils/{ui.js → ui.ts} +32 -25
- package/codex-lens/pyproject.toml +48 -0
- package/codex-lens/src/codexlens/.workflow/.cli-history/history.db +0 -0
- package/codex-lens/src/codexlens/__init__.py +28 -0
- package/codex-lens/src/codexlens/__main__.py +14 -0
- package/codex-lens/src/codexlens/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/__main__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/entities.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/errors.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__init__.py +27 -0
- package/codex-lens/src/codexlens/cli/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/commands.py +1931 -0
- package/codex-lens/src/codexlens/cli/embedding_manager.py +620 -0
- package/codex-lens/src/codexlens/cli/model_manager.py +289 -0
- package/codex-lens/src/codexlens/cli/output.py +124 -0
- package/codex-lens/src/codexlens/config.py +201 -0
- package/codex-lens/src/codexlens/entities.py +121 -0
- package/codex-lens/src/codexlens/errors.py +55 -0
- package/codex-lens/src/codexlens/indexing/README.md +77 -0
- package/codex-lens/src/codexlens/indexing/__init__.py +4 -0
- package/codex-lens/src/codexlens/indexing/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/indexing/__pycache__/symbol_extractor.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/indexing/symbol_extractor.py +243 -0
- package/codex-lens/src/codexlens/parsers/__init__.py +8 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/encoding.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/factory.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/tokenizer.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/treesitter_parser.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/encoding.py +202 -0
- package/codex-lens/src/codexlens/parsers/factory.py +256 -0
- package/codex-lens/src/codexlens/parsers/tokenizer.py +98 -0
- package/codex-lens/src/codexlens/parsers/treesitter_parser.py +335 -0
- package/codex-lens/src/codexlens/search/__init__.py +15 -0
- package/codex-lens/src/codexlens/search/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/enrichment.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/query_parser.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/chain_search.py +647 -0
- package/codex-lens/src/codexlens/search/enrichment.py +150 -0
- package/codex-lens/src/codexlens/search/hybrid_search.py +313 -0
- package/codex-lens/src/codexlens/search/query_parser.py +242 -0
- package/codex-lens/src/codexlens/search/ranking.py +274 -0
- package/codex-lens/src/codexlens/semantic/__init__.py +39 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/ann_index.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/code_extractor.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/graph_analyzer.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/llm_enhancer.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/ann_index.py +414 -0
- package/codex-lens/src/codexlens/semantic/chunker.py +448 -0
- package/codex-lens/src/codexlens/semantic/code_extractor.py +274 -0
- package/codex-lens/src/codexlens/semantic/embedder.py +185 -0
- package/codex-lens/src/codexlens/semantic/vector_store.py +955 -0
- package/codex-lens/src/codexlens/storage/__init__.py +29 -0
- package/codex-lens/src/codexlens/storage/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/file_cache.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/migration_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/registry.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/sqlite_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/sqlite_utils.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/dir_index.py +1850 -0
- package/codex-lens/src/codexlens/storage/file_cache.py +32 -0
- package/codex-lens/src/codexlens/storage/index_tree.py +776 -0
- package/codex-lens/src/codexlens/storage/migration_manager.py +154 -0
- package/codex-lens/src/codexlens/storage/migrations/__init__.py +1 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_001_normalize_keywords.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_002_add_token_metadata.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_003_code_relationships.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_004_dual_fts.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_005_cleanup_unused_fields.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_001_normalize_keywords.py +123 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_002_add_token_metadata.py +48 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_004_dual_fts.py +232 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_005_cleanup_unused_fields.py +196 -0
- package/codex-lens/src/codexlens/storage/path_mapper.py +274 -0
- package/codex-lens/src/codexlens/storage/registry.py +670 -0
- package/codex-lens/src/codexlens/storage/sqlite_store.py +576 -0
- package/codex-lens/src/codexlens/storage/sqlite_utils.py +64 -0
- package/package.json +4 -1
- package/.claude/commands/memory/tech-research.md +0 -477
- package/.claude/scripts/classify-folders.sh +0 -39
- package/.claude/scripts/convert_tokens_to_css.sh +0 -229
- package/.claude/scripts/detect_changed_modules.sh +0 -161
- package/.claude/scripts/discover-design-files.sh +0 -87
- package/.claude/scripts/extract-animations.js +0 -243
- package/.claude/scripts/extract-computed-styles.js +0 -118
- package/.claude/scripts/extract-layout-structure.js +0 -411
- package/.claude/scripts/generate_module_docs.sh +0 -717
- package/.claude/scripts/get_modules_by_depth.sh +0 -170
- package/.claude/scripts/ui-generate-preview.sh +0 -395
- package/.claude/scripts/ui-instantiate-prototypes.sh +0 -815
- package/.claude/scripts/update_module_claude.sh +0 -337
- package/.claude/workflows/context-search-strategy.md +0 -77
- package/.claude/workflows/intelligent-tools-strategy.md +0 -662
- package/ccw/src/cli.js +0 -119
- package/ccw/src/commands/install.js +0 -324
- package/ccw/src/commands/tool.js +0 -138
- package/ccw/src/core/data-aggregator.js +0 -409
- package/ccw/src/core/server.js +0 -2063
- package/ccw/src/core/session-scanner.js +0 -235
- package/ccw/src/tools/classify-folders.js +0 -204
- package/ccw/src/tools/detect-changed-modules.js +0 -288
- package/ccw/src/tools/edit-file.js +0 -266
- package/ccw/src/tools/index.js +0 -176
- package/ccw/src/utils/file-utils.js +0 -48
|
@@ -0,0 +1,928 @@
|
|
|
1
|
+
// MCP Manager View - Redesigned with Sectioned Layout
|
|
2
|
+
// Comprehensive MCP management for Claude and Codex with clear section separation
|
|
3
|
+
|
|
4
|
+
// ============================================================
|
|
5
|
+
// CONSTANTS & CONFIGURATION
|
|
6
|
+
// ============================================================
|
|
7
|
+
|
|
8
|
+
const CCW_MCP_TOOLS = [
|
|
9
|
+
{ name: 'write_file', desc: 'Write/create files', core: true },
|
|
10
|
+
{ name: 'edit_file', desc: 'Edit/replace content', core: true },
|
|
11
|
+
{ name: 'codex_lens', desc: 'Code index & search', core: true },
|
|
12
|
+
{ name: 'smart_search', desc: 'Quick regex/NL search', core: true },
|
|
13
|
+
{ name: 'session_manager', desc: 'Workflow sessions', core: false },
|
|
14
|
+
{ name: 'generate_module_docs', desc: 'Generate docs', core: false },
|
|
15
|
+
{ name: 'update_module_claude', desc: 'Update CLAUDE.md', core: false },
|
|
16
|
+
{ name: 'cli_executor', desc: 'Gemini/Qwen/Codex CLI', core: false },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const MCP_CATEGORIES = [
|
|
20
|
+
'Development Tools',
|
|
21
|
+
'Data & APIs',
|
|
22
|
+
'Files & Storage',
|
|
23
|
+
'AI & ML',
|
|
24
|
+
'DevOps',
|
|
25
|
+
'Custom'
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
// Get currently enabled tools from installed config (Claude)
|
|
29
|
+
function getCcwEnabledTools() {
|
|
30
|
+
const currentPath = projectPath;
|
|
31
|
+
const projectData = mcpAllProjects[currentPath] || {};
|
|
32
|
+
const ccwConfig = projectData.mcpServers?.['ccw-tools'];
|
|
33
|
+
if (ccwConfig?.env?.CCW_ENABLED_TOOLS) {
|
|
34
|
+
const val = ccwConfig.env.CCW_ENABLED_TOOLS;
|
|
35
|
+
if (val.toLowerCase() === 'all') return CCW_MCP_TOOLS.map(t => t.name);
|
|
36
|
+
return val.split(',').map(t => t.trim());
|
|
37
|
+
}
|
|
38
|
+
return CCW_MCP_TOOLS.filter(t => t.core).map(t => t.name);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Get currently enabled tools from Codex config
|
|
42
|
+
function getCcwEnabledToolsCodex() {
|
|
43
|
+
const ccwConfig = codexMcpServers?.['ccw-tools'];
|
|
44
|
+
if (ccwConfig?.env?.CCW_ENABLED_TOOLS) {
|
|
45
|
+
const val = ccwConfig.env.CCW_ENABLED_TOOLS;
|
|
46
|
+
if (val.toLowerCase() === 'all') return CCW_MCP_TOOLS.map(t => t.name);
|
|
47
|
+
return val.split(',').map(t => t.trim());
|
|
48
|
+
}
|
|
49
|
+
return CCW_MCP_TOOLS.filter(t => t.core).map(t => t.name);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ============================================================
|
|
53
|
+
// MODAL DIALOG COMPONENT
|
|
54
|
+
// ============================================================
|
|
55
|
+
|
|
56
|
+
function showMcpEditorModal(options = {}) {
|
|
57
|
+
const {
|
|
58
|
+
mode = 'create',
|
|
59
|
+
serverName = '',
|
|
60
|
+
serverConfig = {},
|
|
61
|
+
template = null,
|
|
62
|
+
cliMode = currentCliMode, // 'claude' or 'codex'
|
|
63
|
+
installTargets = cliMode === 'codex' ? ['codex'] : ['project', 'global']
|
|
64
|
+
} = options;
|
|
65
|
+
|
|
66
|
+
const isView = mode === 'view';
|
|
67
|
+
const isEdit = mode === 'edit';
|
|
68
|
+
const title = isView ? t('mcp.viewServer') : isEdit ? t('mcp.editServer') : t('mcp.createServer');
|
|
69
|
+
|
|
70
|
+
const initialName = serverName || template?.name || '';
|
|
71
|
+
const initialDesc = template?.description || '';
|
|
72
|
+
const initialCategory = template?.category || 'Development Tools';
|
|
73
|
+
const initialConfig = serverConfig || template?.serverConfig || {
|
|
74
|
+
command: '',
|
|
75
|
+
args: [],
|
|
76
|
+
env: {},
|
|
77
|
+
url: '',
|
|
78
|
+
cwd: ''
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const modalHtml = `
|
|
82
|
+
<div class="fixed inset-0 bg-black/50 flex items-center justify-center z-50" id="mcpEditorModal" style="backdrop-filter: blur(4px);">
|
|
83
|
+
<div class="bg-card border border-border rounded-xl shadow-2xl w-full max-w-3xl max-h-[90vh] overflow-hidden flex flex-col">
|
|
84
|
+
<div class="flex items-center justify-between px-6 py-4 border-b border-border bg-gradient-to-r from-primary/5 to-transparent">
|
|
85
|
+
<div class="flex items-center gap-3">
|
|
86
|
+
<div class="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center">
|
|
87
|
+
<i data-lucide="${isView ? 'eye' : isEdit ? 'edit-3' : 'plus-circle'}" class="w-5 h-5 text-primary"></i>
|
|
88
|
+
</div>
|
|
89
|
+
<div>
|
|
90
|
+
<h2 class="text-lg font-bold text-foreground">${title}</h2>
|
|
91
|
+
<p class="text-xs text-muted-foreground">${cliMode === 'codex' ? 'Codex MCP Server' : 'Claude MCP Server'}</p>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
<button onclick="closeMcpEditorModal()" class="text-muted-foreground hover:text-foreground transition-colors">
|
|
95
|
+
<i data-lucide="x" class="w-5 h-5"></i>
|
|
96
|
+
</button>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<div class="flex-1 overflow-y-auto px-6 py-4">
|
|
100
|
+
<div class="space-y-4 mb-6">
|
|
101
|
+
<div>
|
|
102
|
+
<label class="block text-sm font-medium text-foreground mb-1.5">${t('mcp.serverName')}</label>
|
|
103
|
+
<input type="text" id="mcpModalName" value="${initialName}" ${isView ? 'disabled' : ''}
|
|
104
|
+
placeholder="my-mcp-server"
|
|
105
|
+
class="w-full px-3 py-2 bg-background border border-border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/50 disabled:opacity-50 disabled:cursor-not-allowed" />
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
${!isView && cliMode !== 'codex' ? `
|
|
109
|
+
<div>
|
|
110
|
+
<label class="block text-sm font-medium text-foreground mb-1.5">${t('mcp.description')} (${t('mcp.optional')})</label>
|
|
111
|
+
<input type="text" id="mcpModalDesc" value="${initialDesc}" placeholder="Brief description"
|
|
112
|
+
class="w-full px-3 py-2 bg-background border border-border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/50" />
|
|
113
|
+
</div>
|
|
114
|
+
` : ''}
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<div class="mb-4">
|
|
118
|
+
<div class="flex items-center gap-2 border-b border-border">
|
|
119
|
+
<button class="px-4 py-2 text-sm font-medium border-b-2 border-primary text-primary"
|
|
120
|
+
onclick="switchMcpServerType('stdio')" id="mcpTypeStdio" ${isView ? 'disabled' : ''}>
|
|
121
|
+
<i data-lucide="terminal" class="w-4 h-4 inline mr-1.5"></i>
|
|
122
|
+
STDIO (Command)
|
|
123
|
+
</button>
|
|
124
|
+
<button class="px-4 py-2 text-sm font-medium border-b-2 border-transparent text-muted-foreground hover:text-foreground"
|
|
125
|
+
onclick="switchMcpServerType('http')" id="mcpTypeHttp" ${isView ? 'disabled' : ''}>
|
|
126
|
+
<i data-lucide="globe" class="w-4 h-4 inline mr-1.5"></i>
|
|
127
|
+
HTTP (URL)
|
|
128
|
+
</button>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
<div id="mcpStdioConfig" class="space-y-4">
|
|
133
|
+
<div>
|
|
134
|
+
<label class="block text-sm font-medium text-foreground mb-1.5">${t('mcp.command')}</label>
|
|
135
|
+
<input type="text" id="mcpModalCommand" value="${initialConfig.command || ''}" ${isView ? 'disabled' : ''}
|
|
136
|
+
placeholder="node" class="w-full px-3 py-2 bg-background border border-border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/50 disabled:opacity-50 disabled:cursor-not-allowed font-mono text-sm" />
|
|
137
|
+
</div>
|
|
138
|
+
<div>
|
|
139
|
+
<label class="block text-sm font-medium text-foreground mb-1.5">${t('mcp.args')} (${t('mcp.optional')})</label>
|
|
140
|
+
<textarea id="mcpModalArgs" ${isView ? 'disabled' : ''} rows="3" placeholder='["/path/to/server.js"]'
|
|
141
|
+
class="w-full px-3 py-2 bg-background border border-border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/50 disabled:opacity-50 disabled:cursor-not-allowed font-mono text-sm">${JSON.stringify(initialConfig.args || [], null, 2)}</textarea>
|
|
142
|
+
</div>
|
|
143
|
+
<div>
|
|
144
|
+
<label class="block text-sm font-medium text-foreground mb-1.5">${t('mcp.env')} (${t('mcp.optional')})</label>
|
|
145
|
+
<textarea id="mcpModalEnv" ${isView ? 'disabled' : ''} rows="4" placeholder='{"API_KEY": "your-key"}'
|
|
146
|
+
class="w-full px-3 py-2 bg-background border border-border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/50 disabled:opacity-50 disabled:cursor-not-allowed font-mono text-sm">${JSON.stringify(initialConfig.env || {}, null, 2)}</textarea>
|
|
147
|
+
</div>
|
|
148
|
+
<div>
|
|
149
|
+
<label class="block text-sm font-medium text-foreground mb-1.5">${t('mcp.cwd')} (${t('mcp.optional')})</label>
|
|
150
|
+
<input type="text" id="mcpModalCwd" value="${initialConfig.cwd || ''}" ${isView ? 'disabled' : ''}
|
|
151
|
+
placeholder="/path/to/working/directory" class="w-full px-3 py-2 bg-background border border-border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/50 disabled:opacity-50 disabled:cursor-not-allowed font-mono text-sm" />
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
<div id="mcpHttpConfig" class="space-y-4 hidden">
|
|
156
|
+
<div>
|
|
157
|
+
<label class="block text-sm font-medium text-foreground mb-1.5">${t('mcp.url')}</label>
|
|
158
|
+
<input type="text" id="mcpModalUrl" value="${initialConfig.url || ''}" ${isView ? 'disabled' : ''}
|
|
159
|
+
placeholder="https://api.example.com/mcp" class="w-full px-3 py-2 bg-background border border-border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/50 disabled:opacity-50 disabled:cursor-not-allowed font-mono text-sm" />
|
|
160
|
+
</div>
|
|
161
|
+
<div>
|
|
162
|
+
<label class="block text-sm font-medium text-foreground mb-1.5">${t('mcp.httpHeaders')} (${t('mcp.optional')})</label>
|
|
163
|
+
<textarea id="mcpModalHttpHeaders" ${isView ? 'disabled' : ''} rows="4" placeholder='{"Authorization": "Bearer token"}'
|
|
164
|
+
class="w-full px-3 py-2 bg-background border border-border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/50 disabled:opacity-50 disabled:cursor-not-allowed font-mono text-sm">${JSON.stringify(initialConfig.http_headers || initialConfig.httpHeaders || {}, null, 2)}</textarea>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
${!isView && cliMode !== 'codex' ? `
|
|
169
|
+
<div class="mt-6 pt-6 border-t border-border">
|
|
170
|
+
<label class="flex items-center gap-2 cursor-pointer">
|
|
171
|
+
<input type="checkbox" id="mcpModalSaveTemplate" class="w-4 h-4 rounded border-border text-primary focus:ring-2 focus:ring-primary/50" />
|
|
172
|
+
<span class="text-sm font-medium text-foreground">${t('mcp.saveAsTemplate')}</span>
|
|
173
|
+
</label>
|
|
174
|
+
</div>
|
|
175
|
+
` : ''}
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<div class="flex items-center justify-between px-6 py-4 border-t border-border bg-muted/30">
|
|
179
|
+
${!isView ? `
|
|
180
|
+
<div class="flex items-center gap-2">
|
|
181
|
+
<span class="text-sm font-medium text-foreground">${t('mcp.installTo')}:</span>
|
|
182
|
+
<select id="mcpModalTarget" class="px-3 py-1.5 bg-background border border-border rounded-lg text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary/50">
|
|
183
|
+
${installTargets.map(target => {
|
|
184
|
+
const labels = {
|
|
185
|
+
project: 'Project (.mcp.json)',
|
|
186
|
+
global: 'Global (~/.claude.json)',
|
|
187
|
+
codex: 'Codex (~/.codex/config.toml)'
|
|
188
|
+
};
|
|
189
|
+
return `<option value="${target}">${labels[target]}</option>`;
|
|
190
|
+
}).join('')}
|
|
191
|
+
</select>
|
|
192
|
+
</div>
|
|
193
|
+
` : '<div></div>'}
|
|
194
|
+
|
|
195
|
+
<div class="flex items-center gap-2">
|
|
196
|
+
<button onclick="closeMcpEditorModal()" class="px-4 py-2 text-sm font-medium text-foreground hover:bg-muted rounded-lg transition-colors">
|
|
197
|
+
${isView ? t('mcp.close') : t('mcp.cancel')}
|
|
198
|
+
</button>
|
|
199
|
+
${!isView ? `
|
|
200
|
+
<button onclick="saveMcpFromModal('${cliMode}')" class="px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors flex items-center gap-2">
|
|
201
|
+
<i data-lucide="save" class="w-4 h-4"></i>
|
|
202
|
+
${isEdit ? t('mcp.update') : t('mcp.install')}
|
|
203
|
+
</button>
|
|
204
|
+
` : ''}
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
`;
|
|
210
|
+
|
|
211
|
+
const existingModal = document.getElementById('mcpEditorModal');
|
|
212
|
+
if (existingModal) existingModal.remove();
|
|
213
|
+
document.body.insertAdjacentHTML('beforeend', modalHtml);
|
|
214
|
+
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
215
|
+
if (initialConfig.url) switchMcpServerType('http');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function switchMcpServerType(type) {
|
|
219
|
+
const stdioConfig = document.getElementById('mcpStdioConfig');
|
|
220
|
+
const httpConfig = document.getElementById('mcpHttpConfig');
|
|
221
|
+
const stdioBtn = document.getElementById('mcpTypeStdio');
|
|
222
|
+
const httpBtn = document.getElementById('mcpTypeHttp');
|
|
223
|
+
|
|
224
|
+
if (type === 'stdio') {
|
|
225
|
+
stdioConfig.classList.remove('hidden');
|
|
226
|
+
httpConfig.classList.add('hidden');
|
|
227
|
+
stdioBtn.classList.add('border-primary', 'text-primary');
|
|
228
|
+
stdioBtn.classList.remove('border-transparent', 'text-muted-foreground');
|
|
229
|
+
httpBtn.classList.remove('border-primary', 'text-primary');
|
|
230
|
+
httpBtn.classList.add('border-transparent', 'text-muted-foreground');
|
|
231
|
+
} else {
|
|
232
|
+
stdioConfig.classList.add('hidden');
|
|
233
|
+
httpConfig.classList.remove('hidden');
|
|
234
|
+
httpBtn.classList.add('border-primary', 'text-primary');
|
|
235
|
+
httpBtn.classList.remove('border-transparent', 'text-muted-foreground');
|
|
236
|
+
stdioBtn.classList.remove('border-primary', 'text-primary');
|
|
237
|
+
stdioBtn.classList.add('border-transparent', 'text-muted-foreground');
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function closeMcpEditorModal() {
|
|
242
|
+
const modal = document.getElementById('mcpEditorModal');
|
|
243
|
+
if (modal) modal.remove();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function saveMcpFromModal(cliMode) {
|
|
247
|
+
const name = document.getElementById('mcpModalName').value.trim();
|
|
248
|
+
const desc = document.getElementById('mcpModalDesc')?.value.trim() || '';
|
|
249
|
+
const target = document.getElementById('mcpModalTarget')?.value || (cliMode === 'codex' ? 'codex' : 'project');
|
|
250
|
+
const saveAsTemplate = document.getElementById('mcpModalSaveTemplate')?.checked || false;
|
|
251
|
+
|
|
252
|
+
if (!name) {
|
|
253
|
+
showToast(t('mcp.error'), t('mcp.nameRequired'), 'error');
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const isStdio = !document.getElementById('mcpStdioConfig').classList.contains('hidden');
|
|
258
|
+
let serverConfig = {};
|
|
259
|
+
|
|
260
|
+
if (isStdio) {
|
|
261
|
+
const command = document.getElementById('mcpModalCommand').value.trim();
|
|
262
|
+
if (!command) {
|
|
263
|
+
showToast(t('mcp.error'), t('mcp.commandRequired'), 'error');
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
serverConfig.command = command;
|
|
267
|
+
|
|
268
|
+
const argsText = document.getElementById('mcpModalArgs').value.trim();
|
|
269
|
+
if (argsText) {
|
|
270
|
+
try {
|
|
271
|
+
serverConfig.args = JSON.parse(argsText);
|
|
272
|
+
if (!Array.isArray(serverConfig.args)) throw new Error('Args must be an array');
|
|
273
|
+
} catch (e) {
|
|
274
|
+
showToast(t('mcp.error'), t('mcp.invalidArgsJson'), 'error');
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const envText = document.getElementById('mcpModalEnv').value.trim();
|
|
280
|
+
if (envText) {
|
|
281
|
+
try {
|
|
282
|
+
serverConfig.env = JSON.parse(envText);
|
|
283
|
+
if (typeof serverConfig.env !== 'object' || Array.isArray(serverConfig.env)) throw new Error('Env must be an object');
|
|
284
|
+
} catch (e) {
|
|
285
|
+
showToast(t('mcp.error'), t('mcp.invalidEnvJson'), 'error');
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const cwd = document.getElementById('mcpModalCwd').value.trim();
|
|
291
|
+
if (cwd) serverConfig.cwd = cwd;
|
|
292
|
+
} else {
|
|
293
|
+
const url = document.getElementById('mcpModalUrl').value.trim();
|
|
294
|
+
if (!url) {
|
|
295
|
+
showToast(t('mcp.error'), t('mcp.urlRequired'), 'error');
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
serverConfig.url = url;
|
|
299
|
+
|
|
300
|
+
const headersText = document.getElementById('mcpModalHttpHeaders').value.trim();
|
|
301
|
+
if (headersText) {
|
|
302
|
+
try {
|
|
303
|
+
const headers = JSON.parse(headersText);
|
|
304
|
+
if (typeof headers !== 'object' || Array.isArray(headers)) throw new Error('Headers must be an object');
|
|
305
|
+
serverConfig.http_headers = headers;
|
|
306
|
+
} catch (e) {
|
|
307
|
+
showToast(t('mcp.error'), t('mcp.invalidHeadersJson'), 'error');
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (saveAsTemplate && cliMode !== 'codex') {
|
|
314
|
+
try {
|
|
315
|
+
await fetch('/api/mcp-templates', {
|
|
316
|
+
method: 'POST',
|
|
317
|
+
headers: { 'Content-Type': 'application/json' },
|
|
318
|
+
body: JSON.stringify({ name, description: desc, serverConfig, category: 'Custom' })
|
|
319
|
+
});
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.error('Error saving template:', error);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
let endpoint = '';
|
|
327
|
+
let body = {};
|
|
328
|
+
|
|
329
|
+
if (cliMode === 'codex') {
|
|
330
|
+
endpoint = '/api/codex-mcp-add';
|
|
331
|
+
body = { serverName: name, serverConfig };
|
|
332
|
+
} else {
|
|
333
|
+
if (target === 'global') {
|
|
334
|
+
endpoint = '/api/mcp-add-global-server';
|
|
335
|
+
body = { serverName: name, serverConfig };
|
|
336
|
+
} else {
|
|
337
|
+
endpoint = '/api/mcp-copy-server';
|
|
338
|
+
body = { projectPath, serverName: name, serverConfig, configType: 'mcp' };
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const res = await fetch(endpoint, {
|
|
343
|
+
method: 'POST',
|
|
344
|
+
headers: { 'Content-Type': 'application/json' },
|
|
345
|
+
body: JSON.stringify(body)
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
const data = await res.json();
|
|
349
|
+
|
|
350
|
+
if (data.success || data.serverName) {
|
|
351
|
+
showToast(t('mcp.success'), t('mcp.serverInstalled'), 'success');
|
|
352
|
+
closeMcpEditorModal();
|
|
353
|
+
await loadMcpConfig();
|
|
354
|
+
renderMcpManager();
|
|
355
|
+
} else {
|
|
356
|
+
showToast(t('mcp.error'), data.error || 'Installation failed', 'error');
|
|
357
|
+
}
|
|
358
|
+
} catch (error) {
|
|
359
|
+
console.error('Error installing MCP server:', error);
|
|
360
|
+
showToast(t('mcp.error'), error.message, 'error');
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// ============================================================
|
|
365
|
+
// MAIN RENDER FUNCTION
|
|
366
|
+
// ============================================================
|
|
367
|
+
|
|
368
|
+
async function renderMcpManager() {
|
|
369
|
+
const container = document.getElementById('mainContent');
|
|
370
|
+
if (!container) return;
|
|
371
|
+
|
|
372
|
+
const statsGrid = document.getElementById('statsGrid');
|
|
373
|
+
const searchInput = document.getElementById('searchInput');
|
|
374
|
+
if (statsGrid) statsGrid.style.display = 'none';
|
|
375
|
+
if (searchInput) searchInput.parentElement.style.display = 'none';
|
|
376
|
+
|
|
377
|
+
if (!mcpConfig) await loadMcpConfig();
|
|
378
|
+
await loadMcpTemplates();
|
|
379
|
+
|
|
380
|
+
const currentPath = projectPath;
|
|
381
|
+
const projectData = mcpAllProjects[currentPath] || {};
|
|
382
|
+
const projectServers = projectData.mcpServers || {};
|
|
383
|
+
const disabledServers = projectData.disabledMcpServers || [];
|
|
384
|
+
const codexServers = codexMcpServers || {};
|
|
385
|
+
const isClaude = currentCliMode === 'claude';
|
|
386
|
+
|
|
387
|
+
// Section 1: Project Available (Enterprise + Global + Project-specific)
|
|
388
|
+
const projectAvailable = [];
|
|
389
|
+
|
|
390
|
+
if (isClaude) {
|
|
391
|
+
// Enterprise servers
|
|
392
|
+
for (const [name, config] of Object.entries(mcpEnterpriseServers || {})) {
|
|
393
|
+
projectAvailable.push({ name, config, source: 'enterprise', enabled: true, canRemove: false, canToggle: false });
|
|
394
|
+
}
|
|
395
|
+
// Global servers
|
|
396
|
+
for (const [name, config] of Object.entries(mcpUserServers || {})) {
|
|
397
|
+
if (!mcpEnterpriseServers?.[name]) {
|
|
398
|
+
projectAvailable.push({ name, config, source: 'global', enabled: !disabledServers.includes(name), canRemove: false, canToggle: true });
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
// Project servers
|
|
402
|
+
for (const [name, config] of Object.entries(projectServers)) {
|
|
403
|
+
if (!mcpEnterpriseServers?.[name] && !mcpUserServers?.[name]) {
|
|
404
|
+
projectAvailable.push({ name, config, source: 'project', enabled: !disabledServers.includes(name), canRemove: true, canToggle: true });
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
} else {
|
|
408
|
+
// Codex servers
|
|
409
|
+
for (const [name, config] of Object.entries(codexServers)) {
|
|
410
|
+
projectAvailable.push({ name, config, source: 'codex', enabled: config.enabled !== false, canRemove: true, canToggle: true });
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Section 2: Global Management (for Claude only)
|
|
415
|
+
const globalManagement = isClaude ? Object.entries(mcpUserServers || {}) : [];
|
|
416
|
+
|
|
417
|
+
// Section 3: Other Projects (for Claude only)
|
|
418
|
+
const allAvailableServers = isClaude ? getAllAvailableMcpServers() : {};
|
|
419
|
+
const currentProjectServerNames = Object.keys(projectServers);
|
|
420
|
+
const otherProjects = isClaude ? Object.entries(allAvailableServers).filter(([name, info]) => !currentProjectServerNames.includes(name) && !info.isGlobal) : [];
|
|
421
|
+
|
|
422
|
+
// Section 4: Cross-CLI servers (Available from other CLI)
|
|
423
|
+
const crossCliServers = [];
|
|
424
|
+
if (isClaude) {
|
|
425
|
+
// Show Codex servers when in Claude mode
|
|
426
|
+
for (const [name, config] of Object.entries(codexServers)) {
|
|
427
|
+
// Check if already exists in Claude (project or global)
|
|
428
|
+
const existsInClaude = currentProjectServerNames.includes(name) || mcpUserServers?.[name];
|
|
429
|
+
if (!existsInClaude) {
|
|
430
|
+
crossCliServers.push({ name, config, fromCli: 'codex' });
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
} else {
|
|
434
|
+
// Show Claude servers when in Codex mode
|
|
435
|
+
// Collect all Claude servers (global + project)
|
|
436
|
+
const allClaudeServers = { ...mcpUserServers, ...projectServers };
|
|
437
|
+
for (const [name, config] of Object.entries(allClaudeServers)) {
|
|
438
|
+
// Check if already exists in Codex
|
|
439
|
+
const existsInCodex = codexServers[name];
|
|
440
|
+
if (!existsInCodex) {
|
|
441
|
+
crossCliServers.push({ name, config, fromCli: 'claude' });
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
container.innerHTML = `
|
|
447
|
+
<div class="mcp-manager">
|
|
448
|
+
<!-- CLI Mode Toggle -->
|
|
449
|
+
<div class="mcp-cli-toggle mb-6">
|
|
450
|
+
<div class="flex items-center justify-between bg-card border border-border rounded-lg p-4">
|
|
451
|
+
<div class="flex items-center gap-3">
|
|
452
|
+
<span class="text-sm font-medium text-foreground">${t('mcp.cliMode')}</span>
|
|
453
|
+
<div class="flex items-center bg-muted rounded-lg p-1">
|
|
454
|
+
<button class="cli-mode-btn px-4 py-2 text-sm font-medium rounded-md transition-all ${isClaude ? 'bg-primary text-primary-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'}"
|
|
455
|
+
onclick="setCliMode('claude')">
|
|
456
|
+
<i data-lucide="bot" class="w-4 h-4 inline mr-1.5"></i>
|
|
457
|
+
Claude
|
|
458
|
+
</button>
|
|
459
|
+
<button class="cli-mode-btn px-4 py-2 text-sm font-medium rounded-md transition-all ${!isClaude ? 'shadow-sm' : 'text-muted-foreground hover:text-foreground'}"
|
|
460
|
+
onclick="setCliMode('codex')"
|
|
461
|
+
style="${!isClaude ? 'background-color: #f97316; color: white;' : ''}">
|
|
462
|
+
<i data-lucide="code-2" class="w-4 h-4 inline mr-1.5"></i>
|
|
463
|
+
Codex
|
|
464
|
+
</button>
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
<div class="flex items-center gap-3">
|
|
468
|
+
<button onclick="renderMcpTemplates()" class="px-4 py-2 text-sm font-medium bg-muted hover:bg-muted/80 text-foreground rounded-lg transition-colors flex items-center gap-2">
|
|
469
|
+
<i data-lucide="bookmark" class="w-4 h-4"></i>
|
|
470
|
+
${t('mcp.templates')}
|
|
471
|
+
</button>
|
|
472
|
+
<button onclick="showMcpEditorModal({ mode: 'create', cliMode: '${currentCliMode}' })"
|
|
473
|
+
class="px-4 py-2 text-sm font-medium ${isClaude ? 'bg-primary hover:bg-primary/90 text-primary-foreground' : 'bg-orange-500 hover:bg-orange-600 text-white'} rounded-lg transition-colors flex items-center gap-2">
|
|
474
|
+
<i data-lucide="plus-circle" class="w-4 h-4"></i>
|
|
475
|
+
${t('mcp.newServer')}
|
|
476
|
+
</button>
|
|
477
|
+
</div>
|
|
478
|
+
</div>
|
|
479
|
+
</div>
|
|
480
|
+
|
|
481
|
+
<!-- Section 1: Current Project Available -->
|
|
482
|
+
<div class="mcp-section mb-6">
|
|
483
|
+
<div class="flex items-center justify-between mb-4">
|
|
484
|
+
<h2 class="text-lg font-semibold text-foreground flex items-center gap-2">
|
|
485
|
+
<i data-lucide="folder-check" class="w-5 h-5"></i>
|
|
486
|
+
${isClaude ? t('mcp.projectAvailable') : 'Codex Global MCP Servers'}
|
|
487
|
+
<span class="text-sm text-muted-foreground font-normal">(${projectAvailable.length})</span>
|
|
488
|
+
</h2>
|
|
489
|
+
</div>
|
|
490
|
+
<div class="space-y-3">
|
|
491
|
+
${projectAvailable.length === 0 ? `
|
|
492
|
+
<div class="bg-card border border-dashed border-border rounded-lg p-8 text-center">
|
|
493
|
+
<i data-lucide="inbox" class="w-12 h-12 text-muted-foreground mx-auto mb-3"></i>
|
|
494
|
+
<p class="text-sm text-muted-foreground">${isClaude ? t('mcp.noMcpServers') : 'No Codex MCP servers configured'}</p>
|
|
495
|
+
</div>
|
|
496
|
+
` : projectAvailable.map(server => renderMcpServerCard(server, isClaude ? 'claude' : 'codex')).join('')}
|
|
497
|
+
</div>
|
|
498
|
+
</div>
|
|
499
|
+
|
|
500
|
+
${isClaude ? `
|
|
501
|
+
<!-- Section 2: Global Management -->
|
|
502
|
+
${globalManagement.length > 0 ? `
|
|
503
|
+
<div class="mcp-section mb-6">
|
|
504
|
+
<div class="flex items-center justify-between mb-4">
|
|
505
|
+
<h2 class="text-lg font-semibold text-foreground flex items-center gap-2">
|
|
506
|
+
<i data-lucide="globe" class="w-5 h-5"></i>
|
|
507
|
+
${t('mcp.user')}
|
|
508
|
+
<span class="text-sm text-muted-foreground font-normal">(${globalManagement.length})</span>
|
|
509
|
+
</h2>
|
|
510
|
+
</div>
|
|
511
|
+
<div class="space-y-3">
|
|
512
|
+
${globalManagement.map(([name, config]) => renderMcpServerCard({ name, config, source: 'global-manage', enabled: true, canRemove: true, canToggle: false }, 'claude')).join('')}
|
|
513
|
+
</div>
|
|
514
|
+
</div>
|
|
515
|
+
` : ''}
|
|
516
|
+
|
|
517
|
+
<!-- Section 3: Other Projects -->
|
|
518
|
+
${otherProjects.length > 0 ? `
|
|
519
|
+
<div class="mcp-section mb-6">
|
|
520
|
+
<div class="flex items-center justify-between mb-4">
|
|
521
|
+
<h2 class="text-lg font-semibold text-foreground flex items-center gap-2">
|
|
522
|
+
<i data-lucide="folder-open" class="w-5 h-5"></i>
|
|
523
|
+
${t('mcp.availableOther')}
|
|
524
|
+
<span class="text-sm text-muted-foreground font-normal">(${otherProjects.length})</span>
|
|
525
|
+
</h2>
|
|
526
|
+
</div>
|
|
527
|
+
<div class="space-y-3">
|
|
528
|
+
${otherProjects.map(([name, info]) => renderMcpServerCardAvailable(name, info)).join('')}
|
|
529
|
+
</div>
|
|
530
|
+
</div>
|
|
531
|
+
` : ''}
|
|
532
|
+
|
|
533
|
+
<!-- Section 4: Cross-CLI Servers -->
|
|
534
|
+
${crossCliServers.length > 0 ? `
|
|
535
|
+
<div class="mcp-section mb-6">
|
|
536
|
+
<div class="flex items-center justify-between mb-4">
|
|
537
|
+
<h2 class="text-lg font-semibold text-foreground flex items-center gap-2">
|
|
538
|
+
${isClaude ? `
|
|
539
|
+
<i data-lucide="circle-dashed" class="w-5 h-5 text-orange-500"></i>
|
|
540
|
+
${t('mcp.claude.copyFromCodex')}
|
|
541
|
+
` : `
|
|
542
|
+
<i data-lucide="circle" class="w-5 h-5 text-blue-500"></i>
|
|
543
|
+
${t('mcp.codex.copyFromClaude')}
|
|
544
|
+
`}
|
|
545
|
+
<span class="text-sm text-muted-foreground font-normal">(${crossCliServers.length})</span>
|
|
546
|
+
</h2>
|
|
547
|
+
</div>
|
|
548
|
+
<div class="space-y-3">
|
|
549
|
+
${crossCliServers.map(server => renderCrossCliServerCard(server, isClaude)).join('')}
|
|
550
|
+
</div>
|
|
551
|
+
</div>
|
|
552
|
+
` : ''}
|
|
553
|
+
` : ''}
|
|
554
|
+
</div>
|
|
555
|
+
`;
|
|
556
|
+
|
|
557
|
+
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function renderMcpServerCard(server, cliMode) {
|
|
561
|
+
const { name, config, source, enabled, canRemove, canToggle } = server;
|
|
562
|
+
|
|
563
|
+
const sourceInfo = {
|
|
564
|
+
enterprise: { icon: 'shield', color: 'purple', label: 'Enterprise' },
|
|
565
|
+
global: { icon: 'globe', color: 'green', label: 'Global' },
|
|
566
|
+
'global-manage': { icon: 'globe', color: 'green', label: 'Global' },
|
|
567
|
+
project: { icon: 'folder', color: 'blue', label: 'Project' },
|
|
568
|
+
codex: { icon: 'code-2', color: 'orange', label: 'Codex' }
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
const info = sourceInfo[source] || sourceInfo.project;
|
|
572
|
+
const isStdio = !!config.command;
|
|
573
|
+
const isHttp = !!config.url;
|
|
574
|
+
|
|
575
|
+
return `
|
|
576
|
+
<div class="bg-card border border-border rounded-lg p-4 hover:shadow-md transition-all ${!enabled ? 'opacity-60' : ''}">
|
|
577
|
+
<div class="flex items-start justify-between gap-4">
|
|
578
|
+
<div class="flex items-start gap-3 flex-1 min-w-0">
|
|
579
|
+
<div class="shrink-0 w-10 h-10 rounded-lg bg-${info.color}-500/10 flex items-center justify-center">
|
|
580
|
+
<i data-lucide="${info.icon}" class="w-5 h-5 text-${info.color}-500"></i>
|
|
581
|
+
</div>
|
|
582
|
+
<div class="flex-1 min-w-0">
|
|
583
|
+
<div class="flex items-center gap-2 mb-1">
|
|
584
|
+
<h3 class="font-semibold text-foreground truncate">${name}</h3>
|
|
585
|
+
<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium rounded-full bg-${info.color}-500/10 text-${info.color}-600 dark:text-${info.color}-400">
|
|
586
|
+
${info.label}
|
|
587
|
+
</span>
|
|
588
|
+
${enabled ? `
|
|
589
|
+
<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium rounded-full bg-success/10 text-success">
|
|
590
|
+
<i data-lucide="check" class="w-3 h-3"></i>
|
|
591
|
+
Enabled
|
|
592
|
+
</span>
|
|
593
|
+
` : `
|
|
594
|
+
<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium rounded-full bg-muted text-muted-foreground">
|
|
595
|
+
<i data-lucide="x" class="w-3 h-3"></i>
|
|
596
|
+
Disabled
|
|
597
|
+
</span>
|
|
598
|
+
`}
|
|
599
|
+
</div>
|
|
600
|
+
<div class="text-sm text-muted-foreground space-y-1">
|
|
601
|
+
${isStdio ? `
|
|
602
|
+
<div class="flex items-center gap-2">
|
|
603
|
+
<i data-lucide="terminal" class="w-3 h-3"></i>
|
|
604
|
+
<code class="text-xs">${config.command} ${(config.args || []).slice(0, 2).join(' ')}</code>
|
|
605
|
+
</div>
|
|
606
|
+
` : ''}
|
|
607
|
+
${isHttp ? `
|
|
608
|
+
<div class="flex items-center gap-2">
|
|
609
|
+
<i data-lucide="globe" class="w-3 h-3"></i>
|
|
610
|
+
<code class="text-xs truncate">${config.url}</code>
|
|
611
|
+
</div>
|
|
612
|
+
` : ''}
|
|
613
|
+
</div>
|
|
614
|
+
</div>
|
|
615
|
+
</div>
|
|
616
|
+
<div class="flex items-center gap-2">
|
|
617
|
+
${canToggle ? `
|
|
618
|
+
<button onclick="toggleMcpServer('${name}', '${cliMode}', ${!enabled})" class="p-2 rounded-lg hover:bg-muted transition-colors" title="${enabled ? 'Disable' : 'Enable'}">
|
|
619
|
+
<i data-lucide="${enabled ? 'toggle-right' : 'toggle-left'}" class="w-4 h-4 text-${enabled ? 'success' : 'muted-foreground'}"></i>
|
|
620
|
+
</button>
|
|
621
|
+
` : ''}
|
|
622
|
+
<button onclick="showMcpEditorModal({ mode: 'view', serverName: '${name}', serverConfig: ${JSON.stringify(config).replace(/"/g, '"')}, cliMode: '${cliMode}' })" class="p-2 rounded-lg hover:bg-muted transition-colors">
|
|
623
|
+
<i data-lucide="eye" class="w-4 h-4 text-foreground"></i>
|
|
624
|
+
</button>
|
|
625
|
+
${canRemove && source !== 'global-manage' ? `
|
|
626
|
+
<button onclick="showMcpEditorModal({ mode: 'edit', serverName: '${name}', serverConfig: ${JSON.stringify(config).replace(/"/g, '"')}, cliMode: '${cliMode}' })" class="p-2 rounded-lg hover:bg-muted transition-colors">
|
|
627
|
+
<i data-lucide="edit-3" class="w-4 h-4 text-foreground"></i>
|
|
628
|
+
</button>
|
|
629
|
+
` : ''}
|
|
630
|
+
${canRemove ? `
|
|
631
|
+
<button onclick="deleteMcpServer('${name}', '${source}', '${cliMode}')" class="p-2 rounded-lg hover:bg-destructive/10 transition-colors">
|
|
632
|
+
<i data-lucide="trash-2" class="w-4 h-4 text-destructive"></i>
|
|
633
|
+
</button>
|
|
634
|
+
` : ''}
|
|
635
|
+
</div>
|
|
636
|
+
</div>
|
|
637
|
+
</div>
|
|
638
|
+
`;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function renderMcpServerCardAvailable(name, info) {
|
|
642
|
+
return `
|
|
643
|
+
<div class="bg-card border border-dashed border-border rounded-lg p-4 hover:shadow-md hover:border-solid transition-all">
|
|
644
|
+
<div class="flex items-start justify-between gap-4">
|
|
645
|
+
<div class="flex items-start gap-3 flex-1">
|
|
646
|
+
<div class="shrink-0 w-10 h-10 rounded-lg bg-muted flex items-center justify-center">
|
|
647
|
+
<i data-lucide="folder" class="w-5 h-5 text-muted-foreground"></i>
|
|
648
|
+
</div>
|
|
649
|
+
<div class="flex-1">
|
|
650
|
+
<div class="flex items-center gap-2 mb-1">
|
|
651
|
+
<h3 class="font-semibold text-foreground">${name}</h3>
|
|
652
|
+
<span class="text-xs px-2 py-0.5 bg-muted rounded-full text-muted-foreground">${t('mcp.available')}</span>
|
|
653
|
+
</div>
|
|
654
|
+
<p class="text-xs text-muted-foreground">${t('mcp.from')} ${info.projectName || info.source}</p>
|
|
655
|
+
</div>
|
|
656
|
+
</div>
|
|
657
|
+
<button onclick="installServerFromOther('${name}', ${JSON.stringify(info.config).replace(/"/g, '"')})" class="px-3 py-1.5 text-sm font-medium bg-primary hover:bg-primary/90 text-primary-foreground rounded-lg transition-colors">
|
|
658
|
+
${t('mcp.addToProject')}
|
|
659
|
+
</button>
|
|
660
|
+
</div>
|
|
661
|
+
</div>
|
|
662
|
+
`;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function renderCrossCliServerCard(server, isClaude) {
|
|
666
|
+
const { name, config, fromCli } = server;
|
|
667
|
+
const isStdio = !!config.command;
|
|
668
|
+
const isHttp = !!config.url;
|
|
669
|
+
|
|
670
|
+
// Use solid circle for Claude, dashed circle for Codex
|
|
671
|
+
const icon = fromCli === 'codex' ? 'circle-dashed' : 'circle';
|
|
672
|
+
const iconColor = fromCli === 'codex' ? 'orange' : 'blue';
|
|
673
|
+
const targetCli = isClaude ? 'project' : 'codex';
|
|
674
|
+
const buttonText = isClaude ? t('mcp.codex.copyToClaude') : t('mcp.claude.copyToCodex');
|
|
675
|
+
|
|
676
|
+
return `
|
|
677
|
+
<div class="bg-card border border-dashed border-${iconColor}-200 dark:border-${iconColor}-800 rounded-lg p-4 hover:shadow-md hover:border-solid transition-all">
|
|
678
|
+
<div class="flex items-start justify-between gap-4">
|
|
679
|
+
<div class="flex items-start gap-3 flex-1 min-w-0">
|
|
680
|
+
<div class="shrink-0 w-10 h-10 rounded-full bg-${iconColor}-50 dark:bg-${iconColor}-950/30 flex items-center justify-center">
|
|
681
|
+
<i data-lucide="${icon}" class="w-5 h-5 text-${iconColor}-500"></i>
|
|
682
|
+
</div>
|
|
683
|
+
<div class="flex-1 min-w-0">
|
|
684
|
+
<div class="flex items-center gap-2 mb-1">
|
|
685
|
+
<h3 class="font-semibold text-foreground truncate">${name}</h3>
|
|
686
|
+
<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium rounded-full bg-${iconColor}-50 dark:bg-${iconColor}-950/30 text-${iconColor}-600 dark:text-${iconColor}-400">
|
|
687
|
+
<i data-lucide="${icon}" class="w-3 h-3"></i>
|
|
688
|
+
${fromCli === 'codex' ? 'Codex' : 'Claude'}
|
|
689
|
+
</span>
|
|
690
|
+
</div>
|
|
691
|
+
<div class="text-sm text-muted-foreground space-y-1">
|
|
692
|
+
${isStdio ? `
|
|
693
|
+
<div class="flex items-center gap-2">
|
|
694
|
+
<i data-lucide="terminal" class="w-3 h-3"></i>
|
|
695
|
+
<code class="text-xs truncate">${config.command} ${(config.args || []).slice(0, 2).join(' ')}</code>
|
|
696
|
+
</div>
|
|
697
|
+
` : ''}
|
|
698
|
+
${isHttp ? `
|
|
699
|
+
<div class="flex items-center gap-2">
|
|
700
|
+
<i data-lucide="globe" class="w-3 h-3"></i>
|
|
701
|
+
<code class="text-xs truncate">${config.url}</code>
|
|
702
|
+
</div>
|
|
703
|
+
` : ''}
|
|
704
|
+
</div>
|
|
705
|
+
</div>
|
|
706
|
+
</div>
|
|
707
|
+
<button onclick="copyCrossCliServer('${name}', ${JSON.stringify(config).replace(/"/g, '"')}, '${fromCli}', '${targetCli}')" class="px-3 py-1.5 text-sm font-medium bg-${iconColor}-500 hover:bg-${iconColor}-600 text-white rounded-lg transition-colors flex items-center gap-1.5">
|
|
708
|
+
<i data-lucide="copy" class="w-3.5 h-3.5"></i>
|
|
709
|
+
${buttonText}
|
|
710
|
+
</button>
|
|
711
|
+
</div>
|
|
712
|
+
</div>
|
|
713
|
+
`;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
async function copyCrossCliServer(name, config, fromCli, targetCli) {
|
|
717
|
+
try {
|
|
718
|
+
let endpoint, body;
|
|
719
|
+
|
|
720
|
+
if (targetCli === 'codex') {
|
|
721
|
+
// Copy from Claude to Codex
|
|
722
|
+
endpoint = '/api/codex-mcp-add';
|
|
723
|
+
body = { serverName: name, serverConfig: config };
|
|
724
|
+
} else if (targetCli === 'project') {
|
|
725
|
+
// Copy from Codex to Claude project
|
|
726
|
+
endpoint = '/api/mcp-copy-server';
|
|
727
|
+
body = { projectPath, serverName: name, serverConfig: config, configType: 'mcp' };
|
|
728
|
+
} else if (targetCli === 'global') {
|
|
729
|
+
// Copy to Claude global
|
|
730
|
+
endpoint = '/api/mcp-add-global-server';
|
|
731
|
+
body = { serverName: name, serverConfig: config };
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
const res = await fetch(endpoint, {
|
|
735
|
+
method: 'POST',
|
|
736
|
+
headers: { 'Content-Type': 'application/json' },
|
|
737
|
+
body: JSON.stringify(body)
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
const data = await res.json();
|
|
741
|
+
if (data.success) {
|
|
742
|
+
const targetName = targetCli === 'codex' ? 'Codex' : 'Claude';
|
|
743
|
+
showToast(t('mcp.success'), `${t('mcp.serverInstalled')} (${targetName})`, 'success');
|
|
744
|
+
await loadMcpConfig();
|
|
745
|
+
renderMcpManager();
|
|
746
|
+
} else {
|
|
747
|
+
showToast(t('mcp.error'), data.error, 'error');
|
|
748
|
+
}
|
|
749
|
+
} catch (error) {
|
|
750
|
+
showToast(t('mcp.error'), error.message, 'error');
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
async function installServerFromOther(name, config) {
|
|
755
|
+
try {
|
|
756
|
+
const res = await fetch('/api/mcp-copy-server', {
|
|
757
|
+
method: 'POST',
|
|
758
|
+
headers: { 'Content-Type': 'application/json' },
|
|
759
|
+
body: JSON.stringify({ projectPath, serverName: name, serverConfig: config, configType: 'mcp' })
|
|
760
|
+
});
|
|
761
|
+
const data = await res.json();
|
|
762
|
+
if (data.success) {
|
|
763
|
+
showToast(t('mcp.success'), t('mcp.serverInstalled'), 'success');
|
|
764
|
+
await loadMcpConfig();
|
|
765
|
+
renderMcpManager();
|
|
766
|
+
} else {
|
|
767
|
+
showToast(t('mcp.error'), data.error, 'error');
|
|
768
|
+
}
|
|
769
|
+
} catch (error) {
|
|
770
|
+
showToast(t('mcp.error'), error.message, 'error');
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
async function toggleMcpServer(serverName, cliMode, enable) {
|
|
775
|
+
try {
|
|
776
|
+
let endpoint = cliMode === 'codex' ? '/api/codex-mcp-toggle' : '/api/mcp-toggle';
|
|
777
|
+
let body = cliMode === 'codex' ? { serverName, enabled: enable } : { projectPath, serverName, enable };
|
|
778
|
+
|
|
779
|
+
const res = await fetch(endpoint, {
|
|
780
|
+
method: 'POST',
|
|
781
|
+
headers: { 'Content-Type': 'application/json' },
|
|
782
|
+
body: JSON.stringify(body)
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
const data = await res.json();
|
|
786
|
+
if (data.success || data.serverName) {
|
|
787
|
+
showToast(t('mcp.success'), enable ? t('mcp.serverEnabled') : t('mcp.serverDisabled'), 'success');
|
|
788
|
+
await loadMcpConfig();
|
|
789
|
+
renderMcpManager();
|
|
790
|
+
} else {
|
|
791
|
+
showToast(t('mcp.error'), data.error, 'error');
|
|
792
|
+
}
|
|
793
|
+
} catch (error) {
|
|
794
|
+
showToast(t('mcp.error'), error.message, 'error');
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
async function deleteMcpServer(serverName, source, cliMode) {
|
|
799
|
+
if (!confirm(`Are you sure you want to delete "${serverName}"?`)) return;
|
|
800
|
+
|
|
801
|
+
try {
|
|
802
|
+
let endpoint = '';
|
|
803
|
+
let body = {};
|
|
804
|
+
|
|
805
|
+
if (cliMode === 'codex') {
|
|
806
|
+
endpoint = '/api/codex-mcp-remove';
|
|
807
|
+
body = { serverName };
|
|
808
|
+
} else if (source === 'global-manage') {
|
|
809
|
+
endpoint = '/api/mcp-remove-global-server';
|
|
810
|
+
body = { serverName };
|
|
811
|
+
} else if (source === 'project') {
|
|
812
|
+
endpoint = '/api/mcp-remove-server';
|
|
813
|
+
body = { projectPath, serverName };
|
|
814
|
+
} else {
|
|
815
|
+
endpoint = '/api/mcp-remove-global-server';
|
|
816
|
+
body = { serverName };
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
const res = await fetch(endpoint, {
|
|
820
|
+
method: 'POST',
|
|
821
|
+
headers: { 'Content-Type': 'application/json' },
|
|
822
|
+
body: JSON.stringify(body)
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
const data = await res.json();
|
|
826
|
+
if (data.success || data.removed) {
|
|
827
|
+
showToast(t('mcp.success'), t('mcp.serverDeleted'), 'success');
|
|
828
|
+
await loadMcpConfig();
|
|
829
|
+
renderMcpManager();
|
|
830
|
+
} else {
|
|
831
|
+
showToast(t('mcp.error'), data.error, 'error');
|
|
832
|
+
}
|
|
833
|
+
} catch (error) {
|
|
834
|
+
showToast(t('mcp.error'), error.message, 'error');
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
async function renderMcpTemplates() {
|
|
839
|
+
const container = document.getElementById('mainContent');
|
|
840
|
+
if (!container) return;
|
|
841
|
+
|
|
842
|
+
if (!mcpTemplates || mcpTemplates.length === 0) await loadMcpTemplates();
|
|
843
|
+
const categories = [...new Set(mcpTemplates.map(t => t.category || 'Custom'))];
|
|
844
|
+
|
|
845
|
+
container.innerHTML = `
|
|
846
|
+
<div class="mcp-templates-view">
|
|
847
|
+
<div class="flex items-center justify-between mb-6">
|
|
848
|
+
<div>
|
|
849
|
+
<button onclick="renderMcpManager()" class="text-sm text-primary hover:underline flex items-center gap-1 mb-2">
|
|
850
|
+
<i data-lucide="arrow-left" class="w-4 h-4"></i>
|
|
851
|
+
${t('mcp.backToManager')}
|
|
852
|
+
</button>
|
|
853
|
+
<h1 class="text-2xl font-bold text-foreground">${t('mcp.templates')}</h1>
|
|
854
|
+
</div>
|
|
855
|
+
</div>
|
|
856
|
+
<div class="space-y-6">
|
|
857
|
+
${categories.map(category => {
|
|
858
|
+
const templates = mcpTemplates.filter(t => (t.category || 'Custom') === category);
|
|
859
|
+
return `
|
|
860
|
+
<div>
|
|
861
|
+
<h2 class="text-lg font-semibold text-foreground mb-3">${category} (${templates.length})</h2>
|
|
862
|
+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
863
|
+
${templates.map(template => `
|
|
864
|
+
<div class="bg-card border border-border rounded-lg p-4 hover:shadow-md transition-all">
|
|
865
|
+
<h3 class="font-semibold text-foreground mb-2">${template.name}</h3>
|
|
866
|
+
<p class="text-sm text-muted-foreground mb-4">${template.description || 'No description'}</p>
|
|
867
|
+
<div class="flex gap-2">
|
|
868
|
+
<button onclick="showMcpEditorModal({ mode: 'create', template: ${JSON.stringify(template).replace(/"/g, '"')} })" class="flex-1 px-3 py-2 text-sm bg-primary hover:bg-primary/90 text-primary-foreground rounded-lg">Install</button>
|
|
869
|
+
<button onclick="deleteTemplate('${template.name}')" class="px-3 py-2 text-sm bg-destructive/10 hover:bg-destructive/20 text-destructive rounded-lg">Delete</button>
|
|
870
|
+
</div>
|
|
871
|
+
</div>
|
|
872
|
+
`).join('')}
|
|
873
|
+
</div>
|
|
874
|
+
</div>
|
|
875
|
+
`;
|
|
876
|
+
}).join('')}
|
|
877
|
+
</div>
|
|
878
|
+
</div>
|
|
879
|
+
`;
|
|
880
|
+
|
|
881
|
+
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
async function deleteTemplate(name) {
|
|
885
|
+
if (!confirm(`Delete template "${name}"?`)) return;
|
|
886
|
+
try {
|
|
887
|
+
const res = await fetch(`/api/mcp-templates/${encodeURIComponent(name)}`, { method: 'DELETE' });
|
|
888
|
+
const data = await res.json();
|
|
889
|
+
if (data.success) {
|
|
890
|
+
showToast(t('mcp.success'), t('mcp.templateDeleted'), 'success');
|
|
891
|
+
await loadMcpTemplates();
|
|
892
|
+
renderMcpTemplates();
|
|
893
|
+
}
|
|
894
|
+
} catch (error) {
|
|
895
|
+
showToast(t('mcp.error'), error.message, 'error');
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
function showToast(title, message, type = 'info') {
|
|
900
|
+
console.log(`[${type.toUpperCase()}] ${title}: ${message}`);
|
|
901
|
+
if (typeof window.showNotification === 'function') {
|
|
902
|
+
window.showNotification(title, message, type);
|
|
903
|
+
} else {
|
|
904
|
+
alert(`${title}\n${message}`);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
async function loadMcpTemplates() {
|
|
909
|
+
try {
|
|
910
|
+
const res = await fetch('/api/mcp-templates');
|
|
911
|
+
const data = await res.json();
|
|
912
|
+
if (data.success) mcpTemplates = data.templates || [];
|
|
913
|
+
} catch (error) {
|
|
914
|
+
console.error('Error loading MCP templates:', error);
|
|
915
|
+
mcpTemplates = [];
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
window.renderMcpManager = renderMcpManager;
|
|
920
|
+
window.renderMcpTemplates = renderMcpTemplates;
|
|
921
|
+
window.showMcpEditorModal = showMcpEditorModal;
|
|
922
|
+
window.closeMcpEditorModal = closeMcpEditorModal;
|
|
923
|
+
window.saveMcpFromModal = saveMcpFromModal;
|
|
924
|
+
window.switchMcpServerType = switchMcpServerType;
|
|
925
|
+
window.toggleMcpServer = toggleMcpServer;
|
|
926
|
+
window.deleteMcpServer = deleteMcpServer;
|
|
927
|
+
window.deleteTemplate = deleteTemplate;
|
|
928
|
+
window.installServerFromOther = installServerFromOther;
|