diff --git a/ccw/docs-site/.docusaurus/registry.js b/ccw/docs-site/.docusaurus/registry.js
index 1935039b..440b1fda 100644
--- a/ccw/docs-site/.docusaurus/registry.js
+++ b/ccw/docs-site/.docusaurus/registry.js
@@ -1,46 +1,38 @@
export default {
- "__comp---theme-debug-config-23-a-2ff": [() => import(/* webpackChunkName: "__comp---theme-debug-config-23-a-2ff" */ "@theme/DebugConfig"), "@theme/DebugConfig", require.resolveWeak("@theme/DebugConfig")],
- "__comp---theme-debug-contentba-8-ce7": [() => import(/* webpackChunkName: "__comp---theme-debug-contentba-8-ce7" */ "@theme/DebugContent"), "@theme/DebugContent", require.resolveWeak("@theme/DebugContent")],
- "__comp---theme-debug-global-dataede-0fa": [() => import(/* webpackChunkName: "__comp---theme-debug-global-dataede-0fa" */ "@theme/DebugGlobalData"), "@theme/DebugGlobalData", require.resolveWeak("@theme/DebugGlobalData")],
- "__comp---theme-debug-registry-679-501": [() => import(/* webpackChunkName: "__comp---theme-debug-registry-679-501" */ "@theme/DebugRegistry"), "@theme/DebugRegistry", require.resolveWeak("@theme/DebugRegistry")],
- "__comp---theme-debug-routes-946-699": [() => import(/* webpackChunkName: "__comp---theme-debug-routes-946-699" */ "@theme/DebugRoutes"), "@theme/DebugRoutes", require.resolveWeak("@theme/DebugRoutes")],
- "__comp---theme-debug-site-metadata-68-e-3d4": [() => import(/* webpackChunkName: "__comp---theme-debug-site-metadata-68-e-3d4" */ "@theme/DebugSiteMetadata"), "@theme/DebugSiteMetadata", require.resolveWeak("@theme/DebugSiteMetadata")],
- "__comp---theme-doc-item-178-a40": [() => import(/* webpackChunkName: "__comp---theme-doc-item-178-a40" */ "@theme/DocItem"), "@theme/DocItem", require.resolveWeak("@theme/DocItem")],
- "__comp---theme-doc-roota-94-67a": [() => import(/* webpackChunkName: "__comp---theme-doc-roota-94-67a" */ "@theme/DocRoot"), "@theme/DocRoot", require.resolveWeak("@theme/DocRoot")],
- "__comp---theme-doc-version-roota-7-b-5de": [() => import(/* webpackChunkName: "__comp---theme-doc-version-roota-7-b-5de" */ "@theme/DocVersionRoot"), "@theme/DocVersionRoot", require.resolveWeak("@theme/DocVersionRoot")],
- "__comp---theme-docs-root-5-e-9-0b6": [() => import(/* webpackChunkName: "__comp---theme-docs-root-5-e-9-0b6" */ "@theme/DocsRoot"), "@theme/DocsRoot", require.resolveWeak("@theme/DocsRoot")],
- "__props---docs-docsa-20-f19": [() => import(/* webpackChunkName: "__props---docs-docsa-20-f19" */ "@generated/docusaurus-plugin-content-docs/default/p/docs-docs-fbb.json"), "@generated/docusaurus-plugin-content-docs/default/p/docs-docs-fbb.json", require.resolveWeak("@generated/docusaurus-plugin-content-docs/default/p/docs-docs-fbb.json")],
- "__props---docs-docusaurus-debug-content-344-8d5": [() => import(/* webpackChunkName: "__props---docs-docusaurus-debug-content-344-8d5" */ "@generated/docusaurus-plugin-debug/default/p/docs-docusaurus-debug-content-a52.json"), "@generated/docusaurus-plugin-debug/default/p/docs-docusaurus-debug-content-a52.json", require.resolveWeak("@generated/docusaurus-plugin-debug/default/p/docs-docusaurus-debug-content-a52.json")],
- "content---docs-docs-commands-cli-cli-init-056-2d3": [() => import(/* webpackChunkName: "content---docs-docs-commands-cli-cli-init-056-2d3" */ "@site/docs/commands/cli/cli-init.mdx"), "@site/docs/commands/cli/cli-init.mdx", require.resolveWeak("@site/docs/commands/cli/cli-init.mdx")],
- "content---docs-docs-commands-cli-codex-reviewf-1-b-532": [() => import(/* webpackChunkName: "content---docs-docs-commands-cli-codex-reviewf-1-b-532" */ "@site/docs/commands/cli/codex-review.mdx"), "@site/docs/commands/cli/codex-review.mdx", require.resolveWeak("@site/docs/commands/cli/codex-review.mdx")],
- "content---docs-docs-commands-general-ccw-coordinatord-55-a04": [() => import(/* webpackChunkName: "content---docs-docs-commands-general-ccw-coordinatord-55-a04" */ "@site/docs/commands/general/ccw-coordinator.mdx"), "@site/docs/commands/general/ccw-coordinator.mdx", require.resolveWeak("@site/docs/commands/general/ccw-coordinator.mdx")],
- "content---docs-docs-commands-general-ccw-debug-97-c-2c8": [() => import(/* webpackChunkName: "content---docs-docs-commands-general-ccw-debug-97-c-2c8" */ "@site/docs/commands/general/ccw-debug.mdx"), "@site/docs/commands/general/ccw-debug.mdx", require.resolveWeak("@site/docs/commands/general/ccw-debug.mdx")],
- "content---docs-docs-commands-general-ccw-plan-04-d-aa3": [() => import(/* webpackChunkName: "content---docs-docs-commands-general-ccw-plan-04-d-aa3" */ "@site/docs/commands/general/ccw-plan.mdx"), "@site/docs/commands/general/ccw-plan.mdx", require.resolveWeak("@site/docs/commands/general/ccw-plan.mdx")],
- "content---docs-docs-commands-general-ccw-testcce-a5d": [() => import(/* webpackChunkName: "content---docs-docs-commands-general-ccw-testcce-a5d" */ "@site/docs/commands/general/ccw-test.mdx"), "@site/docs/commands/general/ccw-test.mdx", require.resolveWeak("@site/docs/commands/general/ccw-test.mdx")],
- "content---docs-docs-commands-general-ccwf-48-4f9": [() => import(/* webpackChunkName: "content---docs-docs-commands-general-ccwf-48-4f9" */ "@site/docs/commands/general/ccw.mdx"), "@site/docs/commands/general/ccw.mdx", require.resolveWeak("@site/docs/commands/general/ccw.mdx")],
- "content---docs-docs-commands-general-codex-coordinatorf-92-965": [() => import(/* webpackChunkName: "content---docs-docs-commands-general-codex-coordinatorf-92-965" */ "@site/docs/commands/general/codex-coordinator.mdx"), "@site/docs/commands/general/codex-coordinator.mdx", require.resolveWeak("@site/docs/commands/general/codex-coordinator.mdx")],
- "content---docs-docs-commands-general-flow-createfab-5a7": [() => import(/* webpackChunkName: "content---docs-docs-commands-general-flow-createfab-5a7" */ "@site/docs/commands/general/flow-create.mdx"), "@site/docs/commands/general/flow-create.mdx", require.resolveWeak("@site/docs/commands/general/flow-create.mdx")],
- "content---docs-docs-commands-issue-issue-convert-to-plan-5-c-7-428": [() => import(/* webpackChunkName: "content---docs-docs-commands-issue-issue-convert-to-plan-5-c-7-428" */ "@site/docs/commands/issue/issue-convert-to-plan.md"), "@site/docs/commands/issue/issue-convert-to-plan.md", require.resolveWeak("@site/docs/commands/issue/issue-convert-to-plan.md")],
- "content---docs-docs-commands-issue-issue-discover-1-e-3-61d": [() => import(/* webpackChunkName: "content---docs-docs-commands-issue-issue-discover-1-e-3-61d" */ "@site/docs/commands/issue/issue-discover.md"), "@site/docs/commands/issue/issue-discover.md", require.resolveWeak("@site/docs/commands/issue/issue-discover.md")],
- "content---docs-docs-commands-issue-issue-executefe-8-121": [() => import(/* webpackChunkName: "content---docs-docs-commands-issue-issue-executefe-8-121" */ "@site/docs/commands/issue/issue-execute.md"), "@site/docs/commands/issue/issue-execute.md", require.resolveWeak("@site/docs/commands/issue/issue-execute.md")],
- "content---docs-docs-commands-issue-issue-from-brainstorm-2-ec-ca5": [() => import(/* webpackChunkName: "content---docs-docs-commands-issue-issue-from-brainstorm-2-ec-ca5" */ "@site/docs/commands/issue/issue-from-brainstorm.md"), "@site/docs/commands/issue/issue-from-brainstorm.md", require.resolveWeak("@site/docs/commands/issue/issue-from-brainstorm.md")],
- "content---docs-docs-commands-issue-issue-new-4-ad-afb": [() => import(/* webpackChunkName: "content---docs-docs-commands-issue-issue-new-4-ad-afb" */ "@site/docs/commands/issue/issue-new.md"), "@site/docs/commands/issue/issue-new.md", require.resolveWeak("@site/docs/commands/issue/issue-new.md")],
- "content---docs-docs-commands-issue-issue-plana-6-c-1b0": [() => import(/* webpackChunkName: "content---docs-docs-commands-issue-issue-plana-6-c-1b0" */ "@site/docs/commands/issue/issue-plan.md"), "@site/docs/commands/issue/issue-plan.md", require.resolveWeak("@site/docs/commands/issue/issue-plan.md")],
- "content---docs-docs-commands-issue-issue-queue-1-ba-06f": [() => import(/* webpackChunkName: "content---docs-docs-commands-issue-issue-queue-1-ba-06f" */ "@site/docs/commands/issue/issue-queue.md"), "@site/docs/commands/issue/issue-queue.md", require.resolveWeak("@site/docs/commands/issue/issue-queue.md")],
- "content---docs-docs-commands-memory-memory-compact-7-a-1-f85": [() => import(/* webpackChunkName: "content---docs-docs-commands-memory-memory-compact-7-a-1-f85" */ "@site/docs/commands/memory/memory-compact.mdx"), "@site/docs/commands/memory/memory-compact.mdx", require.resolveWeak("@site/docs/commands/memory/memory-compact.mdx")],
- "content---docs-docs-commands-memory-memory-docs-full-cli-4-cc-b15": [() => import(/* webpackChunkName: "content---docs-docs-commands-memory-memory-docs-full-cli-4-cc-b15" */ "@site/docs/commands/memory/memory-docs-full-cli.mdx"), "@site/docs/commands/memory/memory-docs-full-cli.mdx", require.resolveWeak("@site/docs/commands/memory/memory-docs-full-cli.mdx")],
- "content---docs-docs-commands-memory-memory-docs-related-cli-60-e-28a": [() => import(/* webpackChunkName: "content---docs-docs-commands-memory-memory-docs-related-cli-60-e-28a" */ "@site/docs/commands/memory/memory-docs-related-cli.mdx"), "@site/docs/commands/memory/memory-docs-related-cli.mdx", require.resolveWeak("@site/docs/commands/memory/memory-docs-related-cli.mdx")],
- "content---docs-docs-commands-memory-memory-load-157-920": [() => import(/* webpackChunkName: "content---docs-docs-commands-memory-memory-load-157-920" */ "@site/docs/commands/memory/memory-load.mdx"), "@site/docs/commands/memory/memory-load.mdx", require.resolveWeak("@site/docs/commands/memory/memory-load.mdx")],
- "content---docs-docs-commands-memory-memory-update-full-666-28e": [() => import(/* webpackChunkName: "content---docs-docs-commands-memory-memory-update-full-666-28e" */ "@site/docs/commands/memory/memory-update-full.mdx"), "@site/docs/commands/memory/memory-update-full.mdx", require.resolveWeak("@site/docs/commands/memory/memory-update-full.mdx")],
- "content---docs-docs-commands-memory-memory-update-related-611-f0a": [() => import(/* webpackChunkName: "content---docs-docs-commands-memory-memory-update-related-611-f0a" */ "@site/docs/commands/memory/memory-update-related.mdx"), "@site/docs/commands/memory/memory-update-related.mdx", require.resolveWeak("@site/docs/commands/memory/memory-update-related.mdx")],
- "content---docs-docs-faqea-3-29f": [() => import(/* webpackChunkName: "content---docs-docs-faqea-3-29f" */ "@site/docs/faq.mdx"), "@site/docs/faq.mdx", require.resolveWeak("@site/docs/faq.mdx")],
- "content---docs-docs-overview-188-8fe": [() => import(/* webpackChunkName: "content---docs-docs-overview-188-8fe" */ "@site/docs/overview.mdx"), "@site/docs/overview.mdx", require.resolveWeak("@site/docs/overview.mdx")],
- "content---docs-docs-workflows-faqbcf-a47": [() => import(/* webpackChunkName: "content---docs-docs-workflows-faqbcf-a47" */ "@site/docs/workflows/faq.mdx"), "@site/docs/workflows/faq.mdx", require.resolveWeak("@site/docs/workflows/faq.mdx")],
- "content---docs-docs-workflows-introduction-9-f-4-dba": [() => import(/* webpackChunkName: "content---docs-docs-workflows-introduction-9-f-4-dba" */ "@site/docs/workflows/introduction.mdx"), "@site/docs/workflows/introduction.mdx", require.resolveWeak("@site/docs/workflows/introduction.mdx")],
- "content---docs-docs-workflows-level-1-ultra-lightweightc-5-a-692": [() => import(/* webpackChunkName: "content---docs-docs-workflows-level-1-ultra-lightweightc-5-a-692" */ "@site/docs/workflows/level-1-ultra-lightweight.mdx"), "@site/docs/workflows/level-1-ultra-lightweight.mdx", require.resolveWeak("@site/docs/workflows/level-1-ultra-lightweight.mdx")],
- "content---docs-docs-workflows-level-2-rapid-19-b-a2f": [() => import(/* webpackChunkName: "content---docs-docs-workflows-level-2-rapid-19-b-a2f" */ "@site/docs/workflows/level-2-rapid.mdx"), "@site/docs/workflows/level-2-rapid.mdx", require.resolveWeak("@site/docs/workflows/level-2-rapid.mdx")],
- "content---docs-docs-workflows-level-3-standardbdb-19a": [() => import(/* webpackChunkName: "content---docs-docs-workflows-level-3-standardbdb-19a" */ "@site/docs/workflows/level-3-standard.mdx"), "@site/docs/workflows/level-3-standard.mdx", require.resolveWeak("@site/docs/workflows/level-3-standard.mdx")],
- "content---docs-docs-workflows-level-4-brainstormd-04-69a": [() => import(/* webpackChunkName: "content---docs-docs-workflows-level-4-brainstormd-04-69a" */ "@site/docs/workflows/level-4-brainstorm.mdx"), "@site/docs/workflows/level-4-brainstorm.mdx", require.resolveWeak("@site/docs/workflows/level-4-brainstorm.mdx")],
- "content---docs-docs-workflows-level-5-intelligent-186-435": [() => import(/* webpackChunkName: "content---docs-docs-workflows-level-5-intelligent-186-435" */ "@site/docs/workflows/level-5-intelligent.mdx"), "@site/docs/workflows/level-5-intelligent.mdx", require.resolveWeak("@site/docs/workflows/level-5-intelligent.mdx")],
- "plugin---docs-docsaba-31e": [() => import(/* webpackChunkName: "plugin---docs-docsaba-31e" */ "@generated/docusaurus-plugin-content-docs/default/__plugin.json"), "@generated/docusaurus-plugin-content-docs/default/__plugin.json", require.resolveWeak("@generated/docusaurus-plugin-content-docs/default/__plugin.json")],
- "plugin---docs-docusaurus-debugb-38-c84": [() => import(/* webpackChunkName: "plugin---docs-docusaurus-debugb-38-c84" */ "@generated/docusaurus-plugin-debug/default/__plugin.json"), "@generated/docusaurus-plugin-debug/default/__plugin.json", require.resolveWeak("@generated/docusaurus-plugin-debug/default/__plugin.json")],};
+ "04db0a2e": [() => import(/* webpackChunkName: "04db0a2e" */ "@site/docs/commands/general/ccw-plan.mdx"), "@site/docs/commands/general/ccw-plan.mdx", require.resolveWeak("@site/docs/commands/general/ccw-plan.mdx")],
+ "0566a0a8": [() => import(/* webpackChunkName: "0566a0a8" */ "@site/docs/commands/cli/cli-init.mdx"), "@site/docs/commands/cli/cli-init.mdx", require.resolveWeak("@site/docs/commands/cli/cli-init.mdx")],
+ "157db180": [() => import(/* webpackChunkName: "157db180" */ "@site/docs/commands/memory/memory-load.mdx"), "@site/docs/commands/memory/memory-load.mdx", require.resolveWeak("@site/docs/commands/memory/memory-load.mdx")],
+ "17896441": [() => import(/* webpackChunkName: "17896441" */ "@theme/DocItem"), "@theme/DocItem", require.resolveWeak("@theme/DocItem")],
+ "186dcf4e": [() => import(/* webpackChunkName: "186dcf4e" */ "@site/docs/workflows/level-5-intelligent.mdx"), "@site/docs/workflows/level-5-intelligent.mdx", require.resolveWeak("@site/docs/workflows/level-5-intelligent.mdx")],
+ "18891827": [() => import(/* webpackChunkName: "18891827" */ "@site/docs/overview.mdx"), "@site/docs/overview.mdx", require.resolveWeak("@site/docs/overview.mdx")],
+ "19b64556": [() => import(/* webpackChunkName: "19b64556" */ "@site/docs/workflows/level-2-rapid.mdx"), "@site/docs/workflows/level-2-rapid.mdx", require.resolveWeak("@site/docs/workflows/level-2-rapid.mdx")],
+ "1bac9067": [() => import(/* webpackChunkName: "1bac9067" */ "@site/docs/commands/issue/issue-queue.md"), "@site/docs/commands/issue/issue-queue.md", require.resolveWeak("@site/docs/commands/issue/issue-queue.md")],
+ "1e3006f3": [() => import(/* webpackChunkName: "1e3006f3" */ "@site/docs/commands/issue/issue-discover.md"), "@site/docs/commands/issue/issue-discover.md", require.resolveWeak("@site/docs/commands/issue/issue-discover.md")],
+ "2ecf8b4a": [() => import(/* webpackChunkName: "2ecf8b4a" */ "@site/docs/commands/issue/issue-from-brainstorm.md"), "@site/docs/commands/issue/issue-from-brainstorm.md", require.resolveWeak("@site/docs/commands/issue/issue-from-brainstorm.md")],
+ "4ad7db0f": [() => import(/* webpackChunkName: "4ad7db0f" */ "@site/docs/commands/issue/issue-new.md"), "@site/docs/commands/issue/issue-new.md", require.resolveWeak("@site/docs/commands/issue/issue-new.md")],
+ "4cc74730": [() => import(/* webpackChunkName: "4cc74730" */ "@site/docs/commands/memory/memory-docs-full-cli.mdx"), "@site/docs/commands/memory/memory-docs-full-cli.mdx", require.resolveWeak("@site/docs/commands/memory/memory-docs-full-cli.mdx")],
+ "5c7b2278": [() => import(/* webpackChunkName: "5c7b2278" */ "@site/docs/commands/issue/issue-convert-to-plan.md"), "@site/docs/commands/issue/issue-convert-to-plan.md", require.resolveWeak("@site/docs/commands/issue/issue-convert-to-plan.md")],
+ "5e95c892": [() => import(/* webpackChunkName: "5e95c892" */ "@theme/DocsRoot"), "@theme/DocsRoot", require.resolveWeak("@theme/DocsRoot")],
+ "60eef997": [() => import(/* webpackChunkName: "60eef997" */ "@site/docs/commands/memory/memory-docs-related-cli.mdx"), "@site/docs/commands/memory/memory-docs-related-cli.mdx", require.resolveWeak("@site/docs/commands/memory/memory-docs-related-cli.mdx")],
+ "611877e1": [() => import(/* webpackChunkName: "611877e1" */ "@site/docs/commands/memory/memory-update-related.mdx"), "@site/docs/commands/memory/memory-update-related.mdx", require.resolveWeak("@site/docs/commands/memory/memory-update-related.mdx")],
+ "666bb1bf": [() => import(/* webpackChunkName: "666bb1bf" */ "@site/docs/commands/memory/memory-update-full.mdx"), "@site/docs/commands/memory/memory-update-full.mdx", require.resolveWeak("@site/docs/commands/memory/memory-update-full.mdx")],
+ "7a1ee27c": [() => import(/* webpackChunkName: "7a1ee27c" */ "@site/docs/commands/memory/memory-compact.mdx"), "@site/docs/commands/memory/memory-compact.mdx", require.resolveWeak("@site/docs/commands/memory/memory-compact.mdx")],
+ "97c6e66a": [() => import(/* webpackChunkName: "97c6e66a" */ "@site/docs/commands/general/ccw-debug.mdx"), "@site/docs/commands/general/ccw-debug.mdx", require.resolveWeak("@site/docs/commands/general/ccw-debug.mdx")],
+ "9f4ca91e": [() => import(/* webpackChunkName: "9f4ca91e" */ "@site/docs/workflows/introduction.mdx"), "@site/docs/workflows/introduction.mdx", require.resolveWeak("@site/docs/workflows/introduction.mdx")],
+ "a2065270": [() => import(/* webpackChunkName: "a2065270" */ "@generated/docusaurus-plugin-content-docs/default/p/docs-docs-fbb.json"), "@generated/docusaurus-plugin-content-docs/default/p/docs-docs-fbb.json", require.resolveWeak("@generated/docusaurus-plugin-content-docs/default/p/docs-docs-fbb.json")],
+ "a6c3df16": [() => import(/* webpackChunkName: "a6c3df16" */ "@site/docs/commands/issue/issue-plan.md"), "@site/docs/commands/issue/issue-plan.md", require.resolveWeak("@site/docs/commands/issue/issue-plan.md")],
+ "a7bd4aaa": [() => import(/* webpackChunkName: "a7bd4aaa" */ "@theme/DocVersionRoot"), "@theme/DocVersionRoot", require.resolveWeak("@theme/DocVersionRoot")],
+ "a94703ab": [() => import(/* webpackChunkName: "a94703ab" */ "@theme/DocRoot"), "@theme/DocRoot", require.resolveWeak("@theme/DocRoot")],
+ "aba21aa0": [() => import(/* webpackChunkName: "aba21aa0" */ "@generated/docusaurus-plugin-content-docs/default/__plugin.json"), "@generated/docusaurus-plugin-content-docs/default/__plugin.json", require.resolveWeak("@generated/docusaurus-plugin-content-docs/default/__plugin.json")],
+ "bcf6b37c": [() => import(/* webpackChunkName: "bcf6b37c" */ "@site/docs/workflows/faq.mdx"), "@site/docs/workflows/faq.mdx", require.resolveWeak("@site/docs/workflows/faq.mdx")],
+ "bdb2b105": [() => import(/* webpackChunkName: "bdb2b105" */ "@site/docs/workflows/level-3-standard.mdx"), "@site/docs/workflows/level-3-standard.mdx", require.resolveWeak("@site/docs/workflows/level-3-standard.mdx")],
+ "c5a82d8d": [() => import(/* webpackChunkName: "c5a82d8d" */ "@site/docs/workflows/level-1-ultra-lightweight.mdx"), "@site/docs/workflows/level-1-ultra-lightweight.mdx", require.resolveWeak("@site/docs/workflows/level-1-ultra-lightweight.mdx")],
+ "ccef5d0f": [() => import(/* webpackChunkName: "ccef5d0f" */ "@site/docs/commands/general/ccw-test.mdx"), "@site/docs/commands/general/ccw-test.mdx", require.resolveWeak("@site/docs/commands/general/ccw-test.mdx")],
+ "d045285b": [() => import(/* webpackChunkName: "d045285b" */ "@site/docs/workflows/level-4-brainstorm.mdx"), "@site/docs/workflows/level-4-brainstorm.mdx", require.resolveWeak("@site/docs/workflows/level-4-brainstorm.mdx")],
+ "d550a629": [() => import(/* webpackChunkName: "d550a629" */ "@site/docs/commands/general/ccw-coordinator.mdx"), "@site/docs/commands/general/ccw-coordinator.mdx", require.resolveWeak("@site/docs/commands/general/ccw-coordinator.mdx")],
+ "ea313555": [() => import(/* webpackChunkName: "ea313555" */ "@site/docs/faq.mdx"), "@site/docs/faq.mdx", require.resolveWeak("@site/docs/faq.mdx")],
+ "f1bf82ec": [() => import(/* webpackChunkName: "f1bf82ec" */ "@site/docs/commands/cli/codex-review.mdx"), "@site/docs/commands/cli/codex-review.mdx", require.resolveWeak("@site/docs/commands/cli/codex-review.mdx")],
+ "f4817052": [() => import(/* webpackChunkName: "f4817052" */ "@site/docs/commands/general/ccw.mdx"), "@site/docs/commands/general/ccw.mdx", require.resolveWeak("@site/docs/commands/general/ccw.mdx")],
+ "f9222419": [() => import(/* webpackChunkName: "f9222419" */ "@site/docs/commands/general/codex-coordinator.mdx"), "@site/docs/commands/general/codex-coordinator.mdx", require.resolveWeak("@site/docs/commands/general/codex-coordinator.mdx")],
+ "fabaf1c8": [() => import(/* webpackChunkName: "fabaf1c8" */ "@site/docs/commands/general/flow-create.mdx"), "@site/docs/commands/general/flow-create.mdx", require.resolveWeak("@site/docs/commands/general/flow-create.mdx")],
+ "fe8e3dcf": [() => import(/* webpackChunkName: "fe8e3dcf" */ "@site/docs/commands/issue/issue-execute.md"), "@site/docs/commands/issue/issue-execute.md", require.resolveWeak("@site/docs/commands/issue/issue-execute.md")],};
diff --git a/ccw/docs-site/.docusaurus/routes.js b/ccw/docs-site/.docusaurus/routes.js
index 3d7e5278..d711bb5f 100644
--- a/ccw/docs-site/.docusaurus/routes.js
+++ b/ccw/docs-site/.docusaurus/routes.js
@@ -2,41 +2,6 @@ import React from 'react';
import ComponentCreator from '@docusaurus/ComponentCreator';
export default [
- {
- path: '/docs/__docusaurus/debug',
- component: ComponentCreator('/docs/__docusaurus/debug', 'e58'),
- exact: true
- },
- {
- path: '/docs/__docusaurus/debug/config',
- component: ComponentCreator('/docs/__docusaurus/debug/config', '2ce'),
- exact: true
- },
- {
- path: '/docs/__docusaurus/debug/content',
- component: ComponentCreator('/docs/__docusaurus/debug/content', '11b'),
- exact: true
- },
- {
- path: '/docs/__docusaurus/debug/globalData',
- component: ComponentCreator('/docs/__docusaurus/debug/globalData', 'f13'),
- exact: true
- },
- {
- path: '/docs/__docusaurus/debug/metadata',
- component: ComponentCreator('/docs/__docusaurus/debug/metadata', 'bff'),
- exact: true
- },
- {
- path: '/docs/__docusaurus/debug/registry',
- component: ComponentCreator('/docs/__docusaurus/debug/registry', '830'),
- exact: true
- },
- {
- path: '/docs/__docusaurus/debug/routes',
- component: ComponentCreator('/docs/__docusaurus/debug/routes', '13e'),
- exact: true
- },
{
path: '/docs/docs',
component: ComponentCreator('/docs/docs', '942'),
diff --git a/ccw/docs-site/.docusaurus/routesChunkNames.json b/ccw/docs-site/.docusaurus/routesChunkNames.json
index e754b302..8f4104e8 100644
--- a/ccw/docs-site/.docusaurus/routesChunkNames.json
+++ b/ccw/docs-site/.docusaurus/routesChunkNames.json
@@ -1,182 +1,139 @@
{
- "/docs/__docusaurus/debug-e58": {
- "__comp": "__comp---theme-debug-config-23-a-2ff",
- "__context": {
- "plugin": "plugin---docs-docusaurus-debugb-38-c84"
- }
- },
- "/docs/__docusaurus/debug/config-2ce": {
- "__comp": "__comp---theme-debug-config-23-a-2ff",
- "__context": {
- "plugin": "plugin---docs-docusaurus-debugb-38-c84"
- }
- },
- "/docs/__docusaurus/debug/content-11b": {
- "__comp": "__comp---theme-debug-contentba-8-ce7",
- "__context": {
- "plugin": "plugin---docs-docusaurus-debugb-38-c84"
- },
- "__props": "__props---docs-docusaurus-debug-content-344-8d5"
- },
- "/docs/__docusaurus/debug/globalData-f13": {
- "__comp": "__comp---theme-debug-global-dataede-0fa",
- "__context": {
- "plugin": "plugin---docs-docusaurus-debugb-38-c84"
- }
- },
- "/docs/__docusaurus/debug/metadata-bff": {
- "__comp": "__comp---theme-debug-site-metadata-68-e-3d4",
- "__context": {
- "plugin": "plugin---docs-docusaurus-debugb-38-c84"
- }
- },
- "/docs/__docusaurus/debug/registry-830": {
- "__comp": "__comp---theme-debug-registry-679-501",
- "__context": {
- "plugin": "plugin---docs-docusaurus-debugb-38-c84"
- }
- },
- "/docs/__docusaurus/debug/routes-13e": {
- "__comp": "__comp---theme-debug-routes-946-699",
- "__context": {
- "plugin": "plugin---docs-docusaurus-debugb-38-c84"
- }
- },
"/docs/docs-942": {
- "__comp": "__comp---theme-docs-root-5-e-9-0b6",
+ "__comp": "5e95c892",
"__context": {
- "plugin": "plugin---docs-docsaba-31e"
+ "plugin": "aba21aa0"
}
},
"/docs/docs-a90": {
- "__comp": "__comp---theme-doc-version-roota-7-b-5de",
- "__props": "__props---docs-docsa-20-f19"
+ "__comp": "a7bd4aaa",
+ "__props": "a2065270"
},
"/docs/docs-c2e": {
- "__comp": "__comp---theme-doc-roota-94-67a"
+ "__comp": "a94703ab"
},
"/docs/docs/commands/cli/cli-init-c74": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-cli-cli-init-056-2d3"
+ "__comp": "17896441",
+ "content": "0566a0a8"
},
"/docs/docs/commands/cli/codex-review-937": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-cli-codex-reviewf-1-b-532"
+ "__comp": "17896441",
+ "content": "f1bf82ec"
},
"/docs/docs/commands/general/ccw-3fb": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-general-ccwf-48-4f9"
+ "__comp": "17896441",
+ "content": "f4817052"
},
"/docs/docs/commands/general/ccw-coordinator-a90": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-general-ccw-coordinatord-55-a04"
+ "__comp": "17896441",
+ "content": "d550a629"
},
"/docs/docs/commands/general/ccw-debug-663": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-general-ccw-debug-97-c-2c8"
+ "__comp": "17896441",
+ "content": "97c6e66a"
},
"/docs/docs/commands/general/ccw-plan-40b": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-general-ccw-plan-04-d-aa3"
+ "__comp": "17896441",
+ "content": "04db0a2e"
},
"/docs/docs/commands/general/ccw-test-99d": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-general-ccw-testcce-a5d"
+ "__comp": "17896441",
+ "content": "ccef5d0f"
},
"/docs/docs/commands/general/codex-coordinator-996": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-general-codex-coordinatorf-92-965"
+ "__comp": "17896441",
+ "content": "f9222419"
},
"/docs/docs/commands/general/flow-create-d91": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-general-flow-createfab-5a7"
+ "__comp": "17896441",
+ "content": "fabaf1c8"
},
"/docs/docs/commands/issue/issue-convert-to-plan-d90": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-issue-issue-convert-to-plan-5-c-7-428"
+ "__comp": "17896441",
+ "content": "5c7b2278"
},
"/docs/docs/commands/issue/issue-discover-2a1": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-issue-issue-discover-1-e-3-61d"
+ "__comp": "17896441",
+ "content": "1e3006f3"
},
"/docs/docs/commands/issue/issue-execute-abb": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-issue-issue-executefe-8-121"
+ "__comp": "17896441",
+ "content": "fe8e3dcf"
},
"/docs/docs/commands/issue/issue-from-brainstorm-72b": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-issue-issue-from-brainstorm-2-ec-ca5"
+ "__comp": "17896441",
+ "content": "2ecf8b4a"
},
"/docs/docs/commands/issue/issue-new-c58": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-issue-issue-new-4-ad-afb"
+ "__comp": "17896441",
+ "content": "4ad7db0f"
},
"/docs/docs/commands/issue/issue-plan-fd2": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-issue-issue-plana-6-c-1b0"
+ "__comp": "17896441",
+ "content": "a6c3df16"
},
"/docs/docs/commands/issue/issue-queue-1ce": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-issue-issue-queue-1-ba-06f"
+ "__comp": "17896441",
+ "content": "1bac9067"
},
"/docs/docs/commands/memory/memory-compact-74c": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-memory-memory-compact-7-a-1-f85"
+ "__comp": "17896441",
+ "content": "7a1ee27c"
},
"/docs/docs/commands/memory/memory-docs-full-cli-7a4": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-memory-memory-docs-full-cli-4-cc-b15"
+ "__comp": "17896441",
+ "content": "4cc74730"
},
"/docs/docs/commands/memory/memory-docs-related-cli-fb4": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-memory-memory-docs-related-cli-60-e-28a"
+ "__comp": "17896441",
+ "content": "60eef997"
},
"/docs/docs/commands/memory/memory-load-c66": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-memory-memory-load-157-920"
+ "__comp": "17896441",
+ "content": "157db180"
},
"/docs/docs/commands/memory/memory-update-full-b80": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-memory-memory-update-full-666-28e"
+ "__comp": "17896441",
+ "content": "666bb1bf"
},
"/docs/docs/commands/memory/memory-update-related-f0d": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-commands-memory-memory-update-related-611-f0a"
+ "__comp": "17896441",
+ "content": "611877e1"
},
"/docs/docs/faq-4b2": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-faqea-3-29f"
+ "__comp": "17896441",
+ "content": "ea313555"
},
"/docs/docs/overview-7df": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-overview-188-8fe"
+ "__comp": "17896441",
+ "content": "18891827"
},
"/docs/docs/workflows/faq-f47": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-workflows-faqbcf-a47"
+ "__comp": "17896441",
+ "content": "bcf6b37c"
},
"/docs/docs/workflows/introduction-4cb": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-workflows-introduction-9-f-4-dba"
+ "__comp": "17896441",
+ "content": "9f4ca91e"
},
"/docs/docs/workflows/level-1-ultra-lightweight-5c4": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-workflows-level-1-ultra-lightweightc-5-a-692"
+ "__comp": "17896441",
+ "content": "c5a82d8d"
},
"/docs/docs/workflows/level-2-rapid-ad8": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-workflows-level-2-rapid-19-b-a2f"
+ "__comp": "17896441",
+ "content": "19b64556"
},
"/docs/docs/workflows/level-3-standard-3ea": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-workflows-level-3-standardbdb-19a"
+ "__comp": "17896441",
+ "content": "bdb2b105"
},
"/docs/docs/workflows/level-4-brainstorm-f4f": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-workflows-level-4-brainstormd-04-69a"
+ "__comp": "17896441",
+ "content": "d045285b"
},
"/docs/docs/workflows/level-5-intelligent-84a": {
- "__comp": "__comp---theme-doc-item-178-a40",
- "content": "content---docs-docs-workflows-level-5-intelligent-186-435"
+ "__comp": "17896441",
+ "content": "186dcf4e"
}
}
\ No newline at end of file
diff --git a/ccw/docs-site/.docusaurus/site-metadata.json b/ccw/docs-site/.docusaurus/site-metadata.json
index 085f2863..503133f5 100644
--- a/ccw/docs-site/.docusaurus/site-metadata.json
+++ b/ccw/docs-site/.docusaurus/site-metadata.json
@@ -12,9 +12,9 @@
"name": "@docusaurus/plugin-content-pages",
"version": "3.9.2"
},
- "docusaurus-plugin-debug": {
+ "docusaurus-plugin-sitemap": {
"type": "package",
- "name": "@docusaurus/plugin-debug",
+ "name": "@docusaurus/plugin-sitemap",
"version": "3.9.2"
},
"docusaurus-plugin-svgr": {
diff --git a/ccw/frontend/src/components/dashboard/widgets/WorkflowTaskWidget.tsx b/ccw/frontend/src/components/dashboard/widgets/WorkflowTaskWidget.tsx
index 5fab51c1..95fa6755 100644
--- a/ccw/frontend/src/components/dashboard/widgets/WorkflowTaskWidget.tsx
+++ b/ccw/frontend/src/components/dashboard/widgets/WorkflowTaskWidget.tsx
@@ -13,6 +13,7 @@ import { Sparkline } from '@/components/charts/Sparkline';
import { useWorkflowStatusCounts, generateMockWorkflowStatusCounts } from '@/hooks/useWorkflowStatusCounts';
import { useDashboardStats } from '@/hooks/useDashboardStats';
import { useProjectOverview } from '@/hooks/useProjectOverview';
+import { useIndexStatus } from '@/hooks/useIndex';
import { cn } from '@/lib/utils';
import {
ListChecks,
@@ -37,6 +38,7 @@ import {
Sparkles,
BarChart3,
PieChart as PieChartIcon,
+ Database,
} from 'lucide-react';
export interface WorkflowTaskWidgetProps {
@@ -210,6 +212,7 @@ function WorkflowTaskWidgetComponent({ className }: WorkflowTaskWidgetProps) {
const { data, isLoading } = useWorkflowStatusCounts();
const { stats, isLoading: statsLoading } = useDashboardStats({ refetchInterval: 60000 });
const { projectOverview, isLoading: projectLoading } = useProjectOverview();
+ const { status: indexStatus } = useIndexStatus({ refetchInterval: 30000 });
const chartData = data || generateMockWorkflowStatusCounts();
const total = chartData.reduce((sum, item) => sum + item.count, 0);
@@ -320,6 +323,35 @@ function WorkflowTaskWidgetComponent({ className }: WorkflowTaskWidgetProps) {
{projectOverview?.developmentIndex?.enhancement?.length || 0}
{formatMessage({ id: 'projectOverview.devIndex.category.enhancements' })}
+
+ {/* Index Status Indicator */}
+
+
+
+ {indexStatus?.status === 'building' && (
+
+
+
+
+ )}
+
+
+ {indexStatus?.totalFiles || 0}
+
+
{formatMessage({ id: 'home.indexStatus.label' })}
+
{/* Date + Expand Button */}
diff --git a/ccw/frontend/src/components/layout/Sidebar.tsx b/ccw/frontend/src/components/layout/Sidebar.tsx
index b3b3f2c9..3a5bb138 100644
--- a/ccw/frontend/src/components/layout/Sidebar.tsx
+++ b/ccw/frontend/src/components/layout/Sidebar.tsx
@@ -1,7 +1,7 @@
// ========================================
// Sidebar Component
// ========================================
-// Collapsible navigation sidebar with 6-group accordion structure
+// Collapsible navigation sidebar with 5-group accordion structure
import { useCallback, useMemo } from 'react';
import { useIntl } from 'react-intl';
@@ -9,7 +9,6 @@ import {
Home,
FolderKanban,
Workflow,
- RefreshCw,
AlertCircle,
Sparkles,
Terminal,
@@ -60,7 +59,7 @@ interface NavGroupDef {
}>;
}
-// Define the 6 navigation groups with their items
+// Define the 5 navigation groups with their items
const navGroupDefinitions: NavGroupDef[] = [
{
id: 'overview',
@@ -80,8 +79,8 @@ const navGroupDefinitions: NavGroupDef[] = [
{ path: '/lite-tasks', labelKey: 'navigation.main.liteTasks', icon: Zap },
{ path: '/orchestrator', labelKey: 'navigation.main.orchestrator', icon: Workflow },
{ path: '/coordinator', labelKey: 'navigation.main.coordinator', icon: GitFork },
- { path: '/loops', labelKey: 'navigation.main.loops', icon: RefreshCw },
{ path: '/history', labelKey: 'navigation.main.history', icon: Clock },
+ { path: '/issues', labelKey: 'navigation.main.issues', icon: AlertCircle },
],
},
{
@@ -93,14 +92,7 @@ const navGroupDefinitions: NavGroupDef[] = [
{ path: '/prompts', labelKey: 'navigation.main.prompts', icon: History },
{ path: '/skills', labelKey: 'navigation.main.skills', icon: Sparkles },
{ path: '/commands', labelKey: 'navigation.main.commands', icon: Terminal },
- ],
- },
- {
- id: 'issues',
- titleKey: 'navigation.groups.issues',
- icon: AlertCircle,
- items: [
- { path: '/issues', labelKey: 'navigation.main.issues', icon: AlertCircle },
+ { path: '/settings/rules', labelKey: 'navigation.main.rules', icon: Shield },
],
},
{
@@ -109,6 +101,7 @@ const navGroupDefinitions: NavGroupDef[] = [
icon: Wrench,
items: [
{ path: '/hooks', labelKey: 'navigation.main.hooks', icon: GitFork },
+ { path: '/settings/mcp', labelKey: 'navigation.main.mcp', icon: Server },
],
},
{
@@ -116,11 +109,9 @@ const navGroupDefinitions: NavGroupDef[] = [
titleKey: 'navigation.groups.configuration',
icon: Cog,
items: [
- { path: '/settings', labelKey: 'navigation.main.settings', icon: Settings },
- { path: '/settings/mcp', labelKey: 'navigation.main.mcp', icon: Server },
- { path: '/settings/rules', labelKey: 'navigation.main.rules', icon: Shield },
{ path: '/settings/codexlens', labelKey: 'navigation.main.codexlens', icon: Sparkles },
{ path: '/api-settings', labelKey: 'navigation.main.apiSettings', icon: Server },
+ { path: '/settings', labelKey: 'navigation.main.settings', icon: Settings },
{ path: '/help', labelKey: 'navigation.main.help', icon: HelpCircle },
],
},
diff --git a/ccw/frontend/src/components/mcp/CcwToolsMcpCard.tsx b/ccw/frontend/src/components/mcp/CcwToolsMcpCard.tsx
index 93f42213..048d01d2 100644
--- a/ccw/frontend/src/components/mcp/CcwToolsMcpCard.tsx
+++ b/ccw/frontend/src/components/mcp/CcwToolsMcpCard.tsx
@@ -15,6 +15,9 @@ import {
Database,
FileText,
HardDrive,
+ MessageCircleQuestion,
+ ChevronDown,
+ ChevronRight,
} from 'lucide-react';
import { Card } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
@@ -83,6 +86,7 @@ export const CCW_MCP_TOOLS: CcwTool[] = [
{ name: 'edit_file', desc: 'Edit/replace content', core: true },
{ name: 'read_file', desc: 'Read file contents', core: true },
{ name: 'core_memory', desc: 'Core memory management', core: true },
+ { name: 'ask_question', desc: 'Interactive questions (A2UI)', core: false },
];
// ========== Component ==========
@@ -211,13 +215,9 @@ export function CcwToolsMcpCard({
{isExpanded ? (
-
- ▼
-
+
) : (
-
- ▶
-
+
)}
@@ -425,6 +425,8 @@ function getToolIcon(toolName: string): React.ReactElement {
return ;
case 'core_memory':
return ;
+ case 'ask_question':
+ return ;
default:
return ;
}
diff --git a/ccw/frontend/src/components/mcp/ConfigTypeToggle.tsx b/ccw/frontend/src/components/mcp/ConfigTypeToggle.tsx
index b9ca5ebe..1f64abf5 100644
--- a/ccw/frontend/src/components/mcp/ConfigTypeToggle.tsx
+++ b/ccw/frontend/src/components/mcp/ConfigTypeToggle.tsx
@@ -162,56 +162,32 @@ export function ConfigTypeToggle({
return (
<>
-
- {/* Label */}
-
-
- {formatMessage({ id: 'mcp.configType.label' })}
-
-
- {getConfigFileExtension(internalType)}
-
-
-
- {/* Toggle Buttons */}
-
-
-
-
-
- {/* Current Format Display */}
-
-
- {getConfigFileExtension(internalType)}
-
-
- {formatMessage({ id: 'mcp.configType.' + internalType.replace('-', '') })}
-
-
+ {/* Compact inline toggle */}
+
+
+
{/* Warning Dialog */}
diff --git a/ccw/frontend/src/components/mcp/McpServerDialog.tsx b/ccw/frontend/src/components/mcp/McpServerDialog.tsx
index 7eb54cbc..aea3aaa5 100644
--- a/ccw/frontend/src/components/mcp/McpServerDialog.tsx
+++ b/ccw/frontend/src/components/mcp/McpServerDialog.tsx
@@ -31,6 +31,7 @@ import {
} from '@/lib/api';
import { mcpServersKeys, useMcpTemplates } from '@/hooks';
import { cn } from '@/lib/utils';
+import { ConfigTypeToggle, type McpConfigType } from './ConfigTypeToggle';
// ========== Types ==========
@@ -90,6 +91,7 @@ export function McpServerDialog({
const [errors, setErrors] = useState
({});
const [argsInput, setArgsInput] = useState('');
const [envInput, setEnvInput] = useState('');
+ const [configType, setConfigType] = useState('mcp-json');
// Initialize form from server prop (edit mode)
useEffect(() => {
@@ -458,6 +460,20 @@ export function McpServerDialog({
+
+ {/* Config Type Toggle - Only for project scope */}
+ {formData.scope === 'project' && (
+
+
+ {formatMessage({ id: 'mcp.configType.format' })}:
+
+
+
+ )}
{/* Enabled */}
diff --git a/ccw/frontend/src/components/mcp/RecommendedMcpSection.tsx b/ccw/frontend/src/components/mcp/RecommendedMcpSection.tsx
index f51d079e..0da00293 100644
--- a/ccw/frontend/src/components/mcp/RecommendedMcpSection.tsx
+++ b/ccw/frontend/src/components/mcp/RecommendedMcpSection.tsx
@@ -1,52 +1,30 @@
// ========================================
// Recommended MCP Section Component
// ========================================
-// Display recommended MCP servers with one-click install functionality
+// Display recommended MCP servers with wizard-based install functionality
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
import { useIntl } from 'react-intl';
-import { useMutation, useQueryClient } from '@tanstack/react-query';
import {
Search,
Globe,
Sparkles,
Download,
Check,
- Loader2,
+ Settings,
+ Key,
+ Zap,
+ Code2,
} from 'lucide-react';
import { Card } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
import { Badge } from '@/components/ui/Badge';
-import {
- Dialog,
- DialogContent,
- DialogHeader,
- DialogTitle,
- DialogFooter,
-} from '@/components/ui/Dialog';
-import {
- createMcpServer,
- fetchMcpServers,
-} from '@/lib/api';
-import { mcpServersKeys } from '@/hooks';
-import { useNotifications } from '@/hooks/useNotifications';
+import { RecommendedMcpWizard, RecommendedMcpDefinition } from './RecommendedMcpWizard';
+import { fetchMcpConfig } from '@/lib/api';
import { cn } from '@/lib/utils';
// ========== Types ==========
-/**
- * Recommended server configuration
- */
-export interface RecommendedServer {
- id: string;
- name: string;
- description: string;
- command: string;
- args: string[];
- icon: React.ComponentType<{ className?: string }>;
- category: 'search' | 'browser' | 'ai';
-}
-
/**
* Props for RecommendedMcpSection component
*/
@@ -55,61 +33,135 @@ export interface RecommendedMcpSectionProps {
onInstallComplete?: () => void;
}
-interface RecommendedServerCardProps {
- server: RecommendedServer;
- isInstalled: boolean;
- isInstalling: boolean;
- onInstall: (server: RecommendedServer) => void;
-}
-
-// ========== Constants ==========
+// ========== Platform Detection ==========
+const isWindows = typeof navigator !== 'undefined' && navigator.platform?.toLowerCase().includes('win');
/**
- * Pre-configured recommended MCP servers
+ * Build cross-platform MCP config
+ * On Windows, wraps npx/node/python commands with cmd /c for proper execution
*/
-const RECOMMENDED_SERVERS: RecommendedServer[] = [
+function buildCrossPlatformMcpConfig(
+ command: string,
+ args: string[] = [],
+ options: { env?: Record; type?: string } = {}
+) {
+ const { env, type } = options;
+
+ const windowsWrappedCommands = ['npx', 'npm', 'node', 'python', 'python3', 'pip', 'pip3', 'pnpm', 'yarn', 'bun'];
+ const needsWindowsWrapper = isWindows && windowsWrappedCommands.includes(command.toLowerCase());
+
+ const config: { command: string; args: string[]; env?: Record; type?: string } = needsWindowsWrapper
+ ? { command: 'cmd', args: ['/c', command, ...args] }
+ : { command, args };
+
+ if (type) config.type = type;
+ if (env && Object.keys(env).length > 0) config.env = env;
+
+ return config;
+}
+
+// ========== Recommended MCP Definitions ==========
+
+/**
+ * Pre-configured recommended MCP servers with field definitions
+ * Matches original JS version structure for full wizard support
+ */
+const RECOMMENDED_MCP_DEFINITIONS: RecommendedMcpDefinition[] = [
{
id: 'ace-tool',
- name: 'ACE Tool',
- description: 'Advanced code search and context engine for intelligent code discovery',
- command: 'mcp__ace-tool__search_context',
- args: [],
- icon: Search,
+ nameKey: 'mcp.ace-tool.name',
+ descKey: 'mcp.ace-tool.desc',
+ icon: 'search-code',
category: 'search',
+ fields: [
+ {
+ key: 'baseUrl',
+ labelKey: 'mcp.ace-tool.field.baseUrl',
+ type: 'text',
+ default: 'https://acemcp.heroman.wtf/relay/',
+ placeholder: 'https://acemcp.heroman.wtf/relay/',
+ required: true,
+ descKey: 'mcp.ace-tool.field.baseUrl.desc',
+ },
+ {
+ key: 'token',
+ labelKey: 'mcp.ace-tool.field.token',
+ type: 'password',
+ default: '',
+ placeholder: 'ace_xxxxxxxxxxxxxxxx',
+ required: true,
+ descKey: 'mcp.ace-tool.field.token.desc',
+ },
+ ],
+ buildConfig: (values) => buildCrossPlatformMcpConfig('npx', [
+ 'ace-tool',
+ '--base-url',
+ values.baseUrl || 'https://acemcp.heroman.wtf/relay/',
+ '--token',
+ values.token,
+ ]),
},
{
id: 'chrome-devtools',
- name: 'Chrome DevTools',
- description: 'Browser automation and debugging tools for web development',
- command: 'mcp__chrome-devtools',
- args: [],
- icon: Globe,
+ nameKey: 'mcp.chrome-devtools.name',
+ descKey: 'mcp.chrome-devtools.desc',
+ icon: 'chrome',
category: 'browser',
+ fields: [],
+ buildConfig: () => buildCrossPlatformMcpConfig('npx', ['chrome-devtools-mcp@latest'], { type: 'stdio' }),
},
{
- id: 'exa-search',
- name: 'Exa Search',
- description: 'AI-powered web search with real-time crawling capabilities',
- command: 'mcp__exa__search',
- args: [],
- icon: Sparkles,
- category: 'ai',
+ id: 'exa',
+ nameKey: 'mcp.exa.name',
+ descKey: 'mcp.exa.desc',
+ icon: 'globe-2',
+ category: 'search',
+ fields: [
+ {
+ key: 'apiKey',
+ labelKey: 'mcp.exa.field.apiKey',
+ type: 'password',
+ default: '',
+ placeholder: 'your-exa-api-key',
+ required: false,
+ descKey: 'mcp.exa.field.apiKey.desc',
+ },
+ ],
+ buildConfig: (values) => {
+ const env = values.apiKey ? { EXA_API_KEY: values.apiKey } : undefined;
+ return buildCrossPlatformMcpConfig('npx', ['-y', 'exa-mcp-server'], { env });
+ },
},
];
+// ========== Icon Map ==========
+
+const ICON_MAP: Record> = {
+ 'search-code': Search,
+ 'chrome': Globe,
+ 'globe-2': Sparkles,
+ 'code-2': Code2,
+};
+
// ========== Helper Component ==========
+interface RecommendedServerCardProps {
+ definition: RecommendedMcpDefinition;
+ isInstalled: boolean;
+ onInstall: (definition: RecommendedMcpDefinition) => void;
+}
+
/**
* Individual recommended server card
*/
function RecommendedServerCard({
- server,
+ definition,
isInstalled,
- isInstalling,
onInstall,
}: RecommendedServerCardProps) {
const { formatMessage } = useIntl();
- const Icon = server.icon;
+ const Icon = ICON_MAP[definition.icon] || Settings;
+ const hasFields = definition.fields.length > 0;
return (
@@ -129,7 +181,7 @@ function RecommendedServerCard({
- {server.name}
+ {formatMessage({ id: definition.nameKey })}
{isInstalled && (
@@ -138,39 +190,40 @@ function RecommendedServerCard({
)}
- {server.description}
+ {formatMessage({ id: definition.descKey })}
- {/* Install Button */}
- {!isInstalled && (
+ {/* Config info + Install */}
+
+ {hasFields ? (
+
+
+ {definition.fields.length} {formatMessage({ id: 'mcp.configRequired' })}
+
+ ) : (
+
+
+ {formatMessage({ id: 'mcp.noConfigNeeded' })}
+
+ )}
- )}
-
- {/* Installed Indicator */}
- {isInstalled && (
-
-
- {formatMessage({ id: 'mcp.recommended.actions.installed' })}
-
- )}
+
@@ -180,88 +233,64 @@ function RecommendedServerCard({
// ========== Main Component ==========
/**
- * Recommended MCP servers section with one-click install
+ * Recommended MCP servers section with wizard-based install
*/
export function RecommendedMcpSection({
onInstallComplete,
}: RecommendedMcpSectionProps) {
const { formatMessage } = useIntl();
- const queryClient = useQueryClient();
- const { success, error } = useNotifications();
- const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
- const [selectedServer, setSelectedServer] = useState(null);
- const [installingServerId, setInstallingServerId] = useState(null);
+ const [wizardOpen, setWizardOpen] = useState(false);
+ const [selectedDefinition, setSelectedDefinition] = useState(null);
const [installedServerIds, setInstalledServerIds] = useState>(new Set());
// Check which servers are already installed
const checkInstalledServers = async () => {
try {
- const data = await fetchMcpServers();
- const allServers = [...data.project, ...data.global];
- const installedIds = new Set(
- allServers
- .filter(s => s.command.startsWith('mcp__'))
- .map(s => s.command)
- );
+ const data = await fetchMcpConfig();
+ const installedIds = new Set();
+
+ const globalServers = data.globalServers || {};
+ const userServers = data.userServers || {};
+ for (const name of Object.keys(globalServers)) installedIds.add(name);
+ for (const name of Object.keys(userServers)) installedIds.add(name);
+
+ const projects = data.projects || {};
+ for (const proj of Object.values(projects)) {
+ const servers = (proj as any).mcpServers || {};
+ for (const name of Object.keys(servers)) installedIds.add(name);
+ }
+
+ if ((data as any).codex?.servers) {
+ for (const name of Object.keys((data as any).codex.servers)) installedIds.add(name);
+ }
+
setInstalledServerIds(installedIds);
} catch {
// Ignore errors during check
}
};
- // Check on mount
- useState(() => {
+ useEffect(() => {
checkInstalledServers();
- });
+ }, []);
- // Create server mutation
- const createMutation = useMutation({
- mutationFn: (server: Omit) =>
- createMcpServer({
- command: server.command,
- args: server.args,
- scope: 'global',
- enabled: true,
- }),
- onSuccess: (_, variables) => {
- queryClient.invalidateQueries({ queryKey: mcpServersKeys.all });
- setInstalledServerIds(prev => new Set(prev).add(variables.command));
- setInstallingServerId(null);
- setConfirmDialogOpen(false);
- setSelectedServer(null);
- success(
- formatMessage({ id: 'mcp.recommended.actions.installed' }),
- formatMessage({ id: 'mcp.recommended.servers.' + selectedServer?.id + '.name' })
- );
- onInstallComplete?.();
- },
- onError: () => {
- setInstallingServerId(null);
- error(
- formatMessage({ id: 'mcp.dialog.validation.nameRequired' }),
- formatMessage({ id: 'mcp.dialog.validation.commandRequired' })
- );
- },
- });
-
- // Handle install click
- const handleInstallClick = (server: RecommendedServer) => {
- setSelectedServer(server);
- setConfirmDialogOpen(true);
+ // Handle install click - open wizard
+ const handleInstallClick = (definition: RecommendedMcpDefinition) => {
+ setSelectedDefinition(definition);
+ setWizardOpen(true);
};
- // Handle confirm install
- const handleConfirmInstall = () => {
- if (!selectedServer) return;
- setInstallingServerId(selectedServer.id);
- setConfirmDialogOpen(false);
- createMutation.mutate(selectedServer);
+ // Handle wizard close
+ const handleWizardClose = () => {
+ setWizardOpen(false);
+ setSelectedDefinition(null);
};
- // Check if server is installed
- const isServerInstalled = (server: RecommendedServer) => {
- return installedServerIds.has(server.command);
+ // Handle install complete
+ const handleInstallComplete = () => {
+ checkInstalledServers();
+ onInstallComplete?.();
};
return (
@@ -279,66 +308,24 @@ export function RecommendedMcpSection({
{/* Server Cards */}
- {RECOMMENDED_SERVERS.map((server) => (
+ {RECOMMENDED_MCP_DEFINITIONS.map((definition) => (
))}
- {/* Confirmation Dialog */}
-
+ {/* Wizard Dialog */}
+
>
);
}
diff --git a/ccw/frontend/src/components/mcp/RecommendedMcpWizard.tsx b/ccw/frontend/src/components/mcp/RecommendedMcpWizard.tsx
new file mode 100644
index 00000000..97ed51db
--- /dev/null
+++ b/ccw/frontend/src/components/mcp/RecommendedMcpWizard.tsx
@@ -0,0 +1,363 @@
+// ========================================
+// Recommended MCP Wizard Component
+// ========================================
+// Dynamic configuration wizard for recommended MCP servers
+// Supports text, password, and multi-select field types
+
+import { useState } from 'react';
+import { useIntl } from 'react-intl';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { Download, Loader2, X } from 'lucide-react';
+import {
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+ DialogFooter,
+} from '@/components/ui/Dialog';
+import { Button } from '@/components/ui/Button';
+import { Input } from '@/components/ui/Input';
+import { Label } from '@/components/ui/Label';
+import { Badge } from '@/components/ui/Badge';
+import {
+ addGlobalMcpServer,
+ addProjectMcpServer,
+} from '@/lib/api';
+import { mcpServersKeys } from '@/hooks';
+import { useNotifications } from '@/hooks/useNotifications';
+import { cn } from '@/lib/utils';
+
+// ========== Types ==========
+
+/**
+ * Field definition for wizard
+ */
+export interface WizardField {
+ key: string;
+ labelKey: string;
+ descKey?: string;
+ type: 'text' | 'password' | 'multi-select';
+ default?: string | string[];
+ placeholder?: string;
+ required?: boolean;
+ options?: Array<{
+ value: string;
+ label: string;
+ desc?: string;
+ }>;
+}
+
+/**
+ * Recommended MCP server definition
+ */
+export interface RecommendedMcpDefinition {
+ id: string;
+ nameKey: string;
+ descKey: string;
+ icon: string;
+ category: string;
+ fields: WizardField[];
+ buildConfig: (values: Record) => {
+ command: string;
+ args: string[];
+ env?: Record;
+ type?: string;
+ };
+}
+
+/**
+ * Props for RecommendedMcpWizard component
+ */
+export interface RecommendedMcpWizardProps {
+ open: boolean;
+ onClose: () => void;
+ mcpDefinition: RecommendedMcpDefinition | null;
+ onInstallComplete?: () => void;
+}
+
+// ========== Main Component ==========
+
+/**
+ * Wizard for installing recommended MCP servers with configuration
+ */
+export function RecommendedMcpWizard({
+ open,
+ onClose,
+ mcpDefinition,
+ onInstallComplete,
+}: RecommendedMcpWizardProps) {
+ const { formatMessage } = useIntl();
+ const queryClient = useQueryClient();
+ const { success: showSuccess, error: showError } = useNotifications();
+
+ // State for field values
+ const [fieldValues, setFieldValues] = useState>({});
+ const [selectedScope, setSelectedScope] = useState<'project' | 'global'>('global');
+
+ // Initialize field values when dialog opens
+ const initializeFieldValues = () => {
+ if (!mcpDefinition) return;
+
+ const initialValues: Record = {};
+ for (const field of mcpDefinition.fields) {
+ if (field.default !== undefined) {
+ initialValues[field.key] = field.default;
+ } else if (field.type === 'multi-select') {
+ initialValues[field.key] = [];
+ } else {
+ initialValues[field.key] = '';
+ }
+ }
+ setFieldValues(initialValues);
+ };
+
+ // Reset on open/close
+ const handleOpenChange = (newOpen: boolean) => {
+ if (newOpen && mcpDefinition) {
+ initializeFieldValues();
+ } else {
+ setFieldValues({});
+ onClose();
+ }
+ };
+
+ // Install mutation
+ const installMutation = useMutation({
+ mutationFn: async () => {
+ if (!mcpDefinition) throw new Error('No MCP definition');
+
+ const serverConfig = mcpDefinition.buildConfig(fieldValues);
+
+ if (selectedScope === 'global') {
+ return addGlobalMcpServer(mcpDefinition.id, serverConfig);
+ } else {
+ return addProjectMcpServer(mcpDefinition.id, serverConfig);
+ }
+ },
+ onSuccess: (result) => {
+ if (result.success) {
+ queryClient.invalidateQueries({ queryKey: mcpServersKeys.all });
+ showSuccess(
+ formatMessage({ id: 'mcp.wizard.installSuccess' }),
+ formatMessage({ id: mcpDefinition!.nameKey })
+ );
+ handleOpenChange(false);
+ onInstallComplete?.();
+ } else {
+ showError(
+ formatMessage({ id: 'mcp.wizard.installError' }),
+ result.error || 'Unknown error'
+ );
+ }
+ },
+ onError: (err: Error) => {
+ showError(
+ formatMessage({ id: 'mcp.wizard.installError' }),
+ err.message
+ );
+ },
+ });
+
+ // Handle field value change
+ const handleFieldChange = (key: string, value: any) => {
+ setFieldValues(prev => ({
+ ...prev,
+ [key]: value,
+ }));
+ };
+
+ // Handle multi-select toggle
+ const handleMultiSelectToggle = (key: string, value: string) => {
+ const current = fieldValues[key] || [];
+ const newValue = current.includes(value)
+ ? current.filter((v: string) => v !== value)
+ : [...current, value];
+ handleFieldChange(key, newValue);
+ };
+
+ // Validate required fields
+ const validateFields = (): boolean => {
+ if (!mcpDefinition) return false;
+
+ for (const field of mcpDefinition.fields) {
+ if (field.required) {
+ const value = fieldValues[field.key];
+ if (field.type === 'multi-select') {
+ if (!value || value.length === 0) return false;
+ } else {
+ if (!value || value.trim() === '') return false;
+ }
+ }
+ }
+ return true;
+ };
+
+ // Handle submit
+ const handleSubmit = () => {
+ if (!validateFields()) {
+ showError(
+ formatMessage({ id: 'mcp.wizard.validation' }),
+ formatMessage({ id: 'mcp.wizard.requiredFields' })
+ );
+ return;
+ }
+ installMutation.mutate();
+ };
+
+ if (!mcpDefinition) return null;
+
+ const hasFields = mcpDefinition.fields.length > 0;
+
+ return (
+
+ );
+}
+
+export default RecommendedMcpWizard;
diff --git a/ccw/frontend/src/lib/api.ts b/ccw/frontend/src/lib/api.ts
index 3c68f05c..e8da84b8 100644
--- a/ccw/frontend/src/lib/api.ts
+++ b/ccw/frontend/src/lib/api.ts
@@ -2015,6 +2015,21 @@ export interface McpServersResponse {
global: McpServer[];
}
+/**
+ * Fetch complete MCP configuration from all sources
+ * Returns raw config including projects, globalServers, userServers, enterpriseServers
+ */
+export async function fetchMcpConfig(): Promise<{
+ projects: Record; disabledMcpServers?: string[] }>;
+ globalServers: Record;
+ userServers: Record;
+ enterpriseServers: Record;
+ configSources: string[];
+ codex?: { servers: Record; configPath: string };
+}> {
+ return fetchApi('/api/mcp-config');
+}
+
/**
* Fetch all MCP servers (project and global scope) for a specific workspace
* @param projectPath - Optional project path to filter data by workspace
@@ -2551,6 +2566,47 @@ export async function deleteRule(
});
}
+/**
+ * Add MCP server to global scope (~/.claude.json mcpServers)
+ */
+export async function addGlobalMcpServer(
+ serverName: string,
+ serverConfig: {
+ command: string;
+ args?: string[];
+ env?: Record;
+ type?: string;
+ }
+): Promise<{ success: boolean; error?: string }> {
+ return fetchApi<{ success: boolean; error?: string }>('/api/mcp-add-global-server', {
+ method: 'POST',
+ body: JSON.stringify({ serverName, serverConfig }),
+ });
+}
+
+/**
+ * Copy/Add MCP server to project (.mcp.json or .claude.json)
+ */
+export async function copyMcpServerToProject(
+ serverName: string,
+ serverConfig: {
+ command: string;
+ args?: string[];
+ env?: Record;
+ type?: string;
+ },
+ projectPath?: string,
+ configType: 'mcp' | 'claude' = 'mcp'
+): Promise<{ success: boolean; error?: string }> {
+ // Use current project path from URL or fallback
+ const path = projectPath || window.location.pathname.split('/').filter(Boolean)[0] || '';
+
+ return fetchApi<{ success: boolean; error?: string }>('/api/mcp-copy-server', {
+ method: 'POST',
+ body: JSON.stringify({ projectPath: path, serverName, serverConfig, configType }),
+ });
+}
+
// ========== CCW Tools MCP API ==========
/**
@@ -2565,15 +2621,111 @@ export interface CcwMcpConfig {
}
/**
- * Fetch CCW Tools MCP configuration
+ * Platform detection for cross-platform MCP config
*/
-export async function fetchCcwMcpConfig(): Promise {
- const data = await fetchApi('/api/mcp/ccw-config');
- return data;
+const isWindows = typeof navigator !== 'undefined' && navigator.platform?.toLowerCase().includes('win');
+
+/**
+ * Build CCW MCP server config
+ */
+function buildCcwMcpServerConfig(config: {
+ enabledTools?: string[];
+ projectRoot?: string;
+ allowedDirs?: string;
+ disableSandbox?: boolean;
+}): { command: string; args: string[]; env: Record } {
+ const env: Record = {};
+
+ if (config.enabledTools && config.enabledTools.length > 0) {
+ env.CCW_ENABLED_TOOLS = config.enabledTools.join(',');
+ } else {
+ env.CCW_ENABLED_TOOLS = 'all';
+ }
+
+ if (config.projectRoot) {
+ env.CCW_PROJECT_ROOT = config.projectRoot;
+ }
+ if (config.allowedDirs) {
+ env.CCW_ALLOWED_DIRS = config.allowedDirs;
+ }
+ if (config.disableSandbox) {
+ env.CCW_DISABLE_SANDBOX = '1';
+ }
+
+ // Cross-platform config
+ if (isWindows) {
+ return {
+ command: 'cmd',
+ args: ['/c', 'npx', '-y', 'ccw-mcp'],
+ env
+ };
+ }
+ return {
+ command: 'npx',
+ args: ['-y', 'ccw-mcp'],
+ env
+ };
}
/**
- * Update CCW Tools MCP configuration
+ * Fetch CCW Tools MCP configuration by checking if ccw-tools server exists
+ */
+export async function fetchCcwMcpConfig(): Promise {
+ try {
+ const config = await fetchMcpConfig();
+
+ // Check if ccw-tools server exists in any config
+ let ccwServer: any = null;
+
+ // Check global servers
+ if (config.globalServers?.['ccw-tools']) {
+ ccwServer = config.globalServers['ccw-tools'];
+ }
+ // Check user servers
+ if (!ccwServer && config.userServers?.['ccw-tools']) {
+ ccwServer = config.userServers['ccw-tools'];
+ }
+ // Check project servers
+ if (!ccwServer && config.projects) {
+ for (const proj of Object.values(config.projects)) {
+ if (proj.mcpServers?.['ccw-tools']) {
+ ccwServer = proj.mcpServers['ccw-tools'];
+ break;
+ }
+ }
+ }
+
+ if (!ccwServer) {
+ return {
+ isInstalled: false,
+ enabledTools: [],
+ };
+ }
+
+ // Parse enabled tools from env
+ const env = ccwServer.env || {};
+ const enabledToolsStr = env.CCW_ENABLED_TOOLS || 'all';
+ const enabledTools = enabledToolsStr === 'all'
+ ? ['write_file', 'edit_file', 'read_file', 'core_memory', 'ask_question']
+ : enabledToolsStr.split(',').map((t: string) => t.trim());
+
+ return {
+ isInstalled: true,
+ enabledTools,
+ projectRoot: env.CCW_PROJECT_ROOT,
+ allowedDirs: env.CCW_ALLOWED_DIRS,
+ disableSandbox: env.CCW_DISABLE_SANDBOX === '1',
+ };
+ } catch {
+ return {
+ isInstalled: false,
+ enabledTools: [],
+ };
+ }
+}
+
+/**
+ * Update CCW Tools MCP configuration (re-install with new config)
*/
export async function updateCcwConfig(config: {
enabledTools?: string[];
@@ -2581,27 +2733,40 @@ export async function updateCcwConfig(config: {
allowedDirs?: string;
disableSandbox?: boolean;
}): Promise {
- return fetchApi('/api/mcp/ccw-config', {
- method: 'PATCH',
- body: JSON.stringify(config),
- });
+ const serverConfig = buildCcwMcpServerConfig(config);
+
+ // Install/update to global config
+ const result = await addGlobalMcpServer('ccw-tools', serverConfig);
+ if (!result.success) {
+ throw new Error(result.error || 'Failed to update CCW config');
+ }
+
+ return fetchCcwMcpConfig();
}
/**
* Install CCW Tools MCP server
*/
export async function installCcwMcp(): Promise {
- return fetchApi('/api/mcp/ccw-install', {
- method: 'POST',
+ const serverConfig = buildCcwMcpServerConfig({
+ enabledTools: ['write_file', 'edit_file', 'read_file', 'core_memory', 'ask_question'],
});
+
+ const result = await addGlobalMcpServer('ccw-tools', serverConfig);
+ if (!result.success) {
+ throw new Error(result.error || 'Failed to install CCW MCP');
+ }
+
+ return fetchCcwMcpConfig();
}
/**
* Uninstall CCW Tools MCP server
*/
export async function uninstallCcwMcp(): Promise {
- await fetchApi('/api/mcp/ccw-uninstall', {
+ await fetchApi<{ success: boolean }>('/api/mcp-remove-global-server', {
method: 'POST',
+ body: JSON.stringify({ serverName: 'ccw-tools' }),
});
}
diff --git a/ccw/frontend/src/locales/en/cli-hooks.json b/ccw/frontend/src/locales/en/cli-hooks.json
index 9bf9e27c..84ce94d1 100644
--- a/ccw/frontend/src/locales/en/cli-hooks.json
+++ b/ccw/frontend/src/locales/en/cli-hooks.json
@@ -58,6 +58,9 @@
"description": "Create your first hook to automate your CLI workflow",
"noHooksInEvent": "No hooks configured for this event"
},
+ "quickTemplates": {
+ "title": "Quick Install Templates"
+ },
"templates": {
"title": "Quick Install Templates",
"description": "One-click installation for common hook patterns",
diff --git a/ccw/frontend/src/locales/en/home.json b/ccw/frontend/src/locales/en/home.json
index 5ee15f48..2015b173 100644
--- a/ccw/frontend/src/locales/en/home.json
+++ b/ccw/frontend/src/locales/en/home.json
@@ -14,6 +14,9 @@
"runningLoops": "Running Loops",
"openIssues": "Open Issues"
},
+ "indexStatus": {
+ "label": "Indexed"
+ },
"sections": {
"statistics": "Statistics",
"recentSessions": "Recent Sessions",
diff --git a/ccw/frontend/src/locales/en/mcp-manager.json b/ccw/frontend/src/locales/en/mcp-manager.json
index db6c7801..f8ad31ec 100644
--- a/ccw/frontend/src/locales/en/mcp-manager.json
+++ b/ccw/frontend/src/locales/en/mcp-manager.json
@@ -128,6 +128,10 @@
"core_memory": {
"name": "core_memory",
"desc": "Manage core memory entries"
+ },
+ "ask_question": {
+ "name": "ask_question",
+ "desc": "Ask interactive questions through A2UI interface"
}
},
"paths": {
diff --git a/ccw/frontend/src/locales/zh/cli-hooks.json b/ccw/frontend/src/locales/zh/cli-hooks.json
index 73de71aa..36d55ff8 100644
--- a/ccw/frontend/src/locales/zh/cli-hooks.json
+++ b/ccw/frontend/src/locales/zh/cli-hooks.json
@@ -58,6 +58,9 @@
"description": "创建您的第一个钩子以自动化 CLI 工作流",
"noHooksInEvent": "此事件未配置钩子"
},
+ "quickTemplates": {
+ "title": "快速安装模板"
+ },
"templates": {
"title": "快速安装模板",
"description": "常见钩子模式的一键安装",
diff --git a/ccw/frontend/src/locales/zh/home.json b/ccw/frontend/src/locales/zh/home.json
index 4c885c0a..e66aeb9a 100644
--- a/ccw/frontend/src/locales/zh/home.json
+++ b/ccw/frontend/src/locales/zh/home.json
@@ -14,6 +14,9 @@
"runningLoops": "运行中的循环",
"openIssues": "开放问题"
},
+ "indexStatus": {
+ "label": "索引"
+ },
"sections": {
"statistics": "统计",
"recentSessions": "最近会话",
diff --git a/ccw/frontend/src/locales/zh/mcp-manager.json b/ccw/frontend/src/locales/zh/mcp-manager.json
index f8be0054..eabf44bd 100644
--- a/ccw/frontend/src/locales/zh/mcp-manager.json
+++ b/ccw/frontend/src/locales/zh/mcp-manager.json
@@ -128,6 +128,10 @@
"core_memory": {
"name": "core_memory",
"desc": "管理核心内存条目"
+ },
+ "ask_question": {
+ "name": "ask_question",
+ "desc": "通过 A2UI 界面发起交互式问答"
}
},
"paths": {
diff --git a/ccw/frontend/src/pages/McpManagerPage.tsx b/ccw/frontend/src/pages/McpManagerPage.tsx
index 64dde50e..389bc927 100644
--- a/ccw/frontend/src/pages/McpManagerPage.tsx
+++ b/ccw/frontend/src/pages/McpManagerPage.tsx
@@ -31,7 +31,6 @@ import { CodexMcpEditableCard } from '@/components/mcp/CodexMcpEditableCard';
import { CcwToolsMcpCard } from '@/components/mcp/CcwToolsMcpCard';
import { McpTemplatesSection } from '@/components/mcp/McpTemplatesSection';
import { RecommendedMcpSection } from '@/components/mcp/RecommendedMcpSection';
-import { ConfigTypeToggle } from '@/components/mcp/ConfigTypeToggle';
import { WindowsCompatibilityWarning } from '@/components/mcp/WindowsCompatibilityWarning';
import { CrossCliCopyButton } from '@/components/mcp/CrossCliCopyButton';
import { AllProjectsTable } from '@/components/mcp/AllProjectsTable';
@@ -207,7 +206,6 @@ export function McpManagerPage() {
const [editingServer, setEditingServer] = useState(undefined);
const [cliMode, setCliMode] = useState('claude');
const [codexExpandedServers, setCodexExpandedServers] = useState>(new Set());
- const [configType, setConfigType] = useState<'mcp-json' | 'claude-json'>('mcp-json');
const {
servers,
@@ -391,14 +389,24 @@ export function McpManagerPage() {
{/* Page Header */}
-
-
-
- {formatMessage({ id: 'mcp.title' })}
-
-
- {formatMessage({ id: 'mcp.description' })}
-
+
+
+
+
+ {formatMessage({ id: 'mcp.title' })}
+
+
+ {formatMessage({ id: 'mcp.description' })}
+
+
+ {/* CLI Mode Badge Switcher */}
+
+
+
- {/* CLI Mode Toggle */}
-
-
{/* Tabbed Interface */}
+
+ {/* Recommended MCP Servers */}
+
refetch()} />
+
+ {/* Templates Section */}
- {/* Recommended MCP Servers */}
- {cliMode === 'claude' && (
- refetch()} />
- )}
-
- {/* Config Type Toggle */}
- {cliMode === 'claude' && (
-
- )}
-
{/* Stats Cards - Claude mode only */}
{cliMode === 'claude' && (
diff --git a/ccw/frontend/src/pages/SettingsPage.tsx b/ccw/frontend/src/pages/SettingsPage.tsx
index e086998e..34c3a13f 100644
--- a/ccw/frontend/src/pages/SettingsPage.tsx
+++ b/ccw/frontend/src/pages/SettingsPage.tsx
@@ -17,11 +17,7 @@ import {
ChevronDown,
ChevronUp,
Languages,
- GitFork,
- Scale,
- Search,
- Power,
- PowerOff,
+ Plus,
} from 'lucide-react';
import { Card } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
@@ -29,12 +25,10 @@ import { Input } from '@/components/ui/Input';
import { Badge } from '@/components/ui/Badge';
import { ThemeSelector } from '@/components/shared/ThemeSelector';
import { useTheme } from '@/hooks';
-import { useHooks, useRules, useToggleHook, useToggleRule } from '@/hooks';
import { useConfigStore, selectCliTools, selectDefaultCliTool, selectUserPreferences } from '@/stores/configStore';
import type { CliToolConfig, UserPreferences } from '@/types/store';
import { cn } from '@/lib/utils';
import { LanguageSwitcher } from '@/components/layout/LanguageSwitcher';
-import { IndexManager } from '@/components/shared/IndexManager';
// ========== CLI Tool Card Component ==========
@@ -47,6 +41,9 @@ interface CliToolCardProps {
onToggleEnabled: () => void;
onSetDefault: () => void;
onUpdateModel: (field: 'primaryModel' | 'secondaryModel', value: string) => void;
+ onUpdateTags: (tags: string[]) => void;
+ onUpdateAvailableModels: (models: string[]) => void;
+ onUpdateSettingsFile: (settingsFile: string | undefined) => void;
}
function CliToolCard({
@@ -58,9 +55,49 @@ function CliToolCard({
onToggleEnabled,
onSetDefault,
onUpdateModel,
+ onUpdateTags,
+ onUpdateAvailableModels,
+ onUpdateSettingsFile,
}: CliToolCardProps) {
const { formatMessage } = useIntl();
+ // Local state for tag and model input
+ const [tagInput, setTagInput] = useState('');
+ const [modelInput, setModelInput] = useState('');
+
+ // Handler for adding tags
+ const handleAddTag = () => {
+ const newTag = tagInput.trim();
+ if (newTag && !config.tags.includes(newTag)) {
+ onUpdateTags([...config.tags, newTag]);
+ setTagInput('');
+ }
+ };
+
+ // Handler for removing tags
+ const handleRemoveTag = (tagToRemove: string) => {
+ onUpdateTags(config.tags.filter((t) => t !== tagToRemove));
+ };
+
+ // Handler for adding available models
+ const handleAddModel = () => {
+ const newModel = modelInput.trim();
+ const currentModels = config.availableModels || [];
+ if (newModel && !currentModels.includes(newModel)) {
+ onUpdateAvailableModels([...currentModels, newModel]);
+ setModelInput('');
+ }
+ };
+
+ // Handler for removing available models
+ const handleRemoveModel = (modelToRemove: string) => {
+ const currentModels = config.availableModels || [];
+ onUpdateAvailableModels(currentModels.filter((m) => m !== modelToRemove));
+ };
+
+ // Predefined tags
+ const predefinedTags = ['分析', 'Debug', 'implementation', 'refactoring', 'testing'];
+
return (
{/* Header */}
@@ -157,6 +194,146 @@ function CliToolCard({
/>
+
+ {/* Tags Section */}
+
+
+
+ {formatMessage({ id: 'apiSettings.cliSettings.tagsDescription' })}
+
+
+
+ {config.tags.map((tag) => (
+
+ {tag}
+
+
+ ))}
+ setTagInput(e.target.value)}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter') {
+ e.preventDefault();
+ handleAddTag();
+ }
+ }}
+ placeholder={config.tags.length === 0 ? formatMessage({ id: 'apiSettings.cliSettings.tagInputPlaceholder' }) : ''}
+ className="flex-1 min-w-[120px] bg-transparent border-0 outline-none text-sm placeholder:text-muted-foreground"
+ />
+
+
+
+ {/* Predefined Tags */}
+
+
+ {formatMessage({ id: 'apiSettings.cliSettings.predefinedTags' })}:
+
+ {predefinedTags.map((predefinedTag) => (
+
+ ))}
+
+
+
+ {/* Available Models Section */}
+
+
+
+
+ {(config.availableModels || []).map((model) => (
+
+ {model}
+
+
+ ))}
+ setModelInput(e.target.value)}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter') {
+ e.preventDefault();
+ handleAddModel();
+ }
+ }}
+ placeholder={(config.availableModels || []).length === 0 ? formatMessage({ id: 'apiSettings.cliSettings.availableModelsPlaceholder' }) : ''}
+ className="flex-1 min-w-[120px] bg-transparent border-0 outline-none text-sm placeholder:text-muted-foreground"
+ />
+
+
+
+
+ {formatMessage({ id: 'apiSettings.cliSettings.availableModelsHint' })}
+
+
+
+ {/* Settings File */}
+
+
+
onUpdateSettingsFile(e.target.value || undefined)}
+ placeholder={formatMessage({ id: 'apiSettings.cliSettings.settingsFilePlaceholder' })}
+ />
+
+ {formatMessage({ id: 'apiSettings.cliSettings.settingsFileHint' })}
+
+
+
{!isDefault && config.enabled && (
@@ -621,15 +609,6 @@ export function SettingsPage() {
- {/* Git Hooks */}
-
-
- {/* Rules */}
-
-
- {/* Index Manager */}
-
-
{/* Reset Settings */}
diff --git a/ccw/frontend/src/types/store.ts b/ccw/frontend/src/types/store.ts
index f268225a..d988d5d7 100644
--- a/ccw/frontend/src/types/store.ts
+++ b/ccw/frontend/src/types/store.ts
@@ -308,6 +308,7 @@ export interface CliToolConfig {
tags: string[];
type: 'builtin' | 'cli-wrapper' | 'api-endpoint';
settingsFile?: string;
+ availableModels?: string[];
}
export interface ApiEndpoints {
diff --git a/ccw/src/commands/stop.ts b/ccw/src/commands/stop.ts
index 1c87b75e..9256f43c 100644
--- a/ccw/src/commands/stop.ts
+++ b/ccw/src/commands/stop.ts
@@ -35,10 +35,17 @@ async function findProcessOnPort(port: number): Promise {
*/
async function killProcess(pid: string): Promise {
try {
- await execAsync(`taskkill /PID ${pid} /F`);
+ // Use PowerShell to avoid Git Bash path expansion issues with /PID
+ await execAsync(`powershell -Command "Stop-Process -Id ${pid} -Force -ErrorAction Stop"`);
return true;
} catch {
- return false;
+ // Fallback to taskkill via cmd
+ try {
+ await execAsync(`cmd /c "taskkill /PID ${pid} /F"`);
+ return true;
+ } catch {
+ return false;
+ }
}
}
@@ -52,7 +59,7 @@ export async function stopCommand(options: StopOptions): Promise {
const force = options.force || false;
console.log(chalk.blue.bold('\n CCW Dashboard\n'));
- console.log(chalk.gray(` Checking server on port ${port}...`));
+ console.log(chalk.gray(` Checking server on port ${port} and ${reactPort}...`));
try {
// Try graceful shutdown via API first
@@ -139,11 +146,18 @@ export async function stopCommand(options: StopOptions): Promise {
console.log(chalk.green(' Main server killed successfully!'));
// Also try to kill React frontend
+ console.log(chalk.gray(` Checking React frontend on port ${reactPort}...`));
const reactPid = await findProcessOnPort(reactPort);
if (reactPid) {
- console.log(chalk.cyan(` Cleaning up React frontend on port ${reactPort}...`));
- await killProcess(reactPid);
- console.log(chalk.green(' React frontend stopped!'));
+ console.log(chalk.cyan(` Cleaning up React frontend (PID: ${reactPid})...`));
+ const reactKilled = await killProcess(reactPid);
+ if (reactKilled) {
+ console.log(chalk.green(' React frontend stopped!'));
+ } else {
+ console.log(chalk.yellow(' Failed to stop React frontend'));
+ }
+ } else {
+ console.log(chalk.gray(' No React frontend running'));
}
console.log(chalk.green.bold('\n All processes stopped successfully!\n'));
@@ -153,6 +167,12 @@ export async function stopCommand(options: StopOptions): Promise {
process.exit(1);
}
} else {
+ // Also check React frontend port
+ const reactPid = await findProcessOnPort(reactPort);
+ if (reactPid) {
+ console.log(chalk.yellow(` React frontend running on port ${reactPort} (PID: ${reactPid})`));
+ }
+
console.log(chalk.gray(`\n This is not a CCW server. Use --force to kill it:`));
console.log(chalk.white(` ccw stop --force\n`));
process.exit(0);
diff --git a/ccw/src/commands/view.ts b/ccw/src/commands/view.ts
index 577101b2..baabf78c 100644
--- a/ccw/src/commands/view.ts
+++ b/ccw/src/commands/view.ts
@@ -78,7 +78,7 @@ export async function viewCommand(options: ViewOptions): Promise {
const host = options.host || '127.0.0.1';
const browserHost = host === '0.0.0.0' || host === '::' ? 'localhost' : host;
// --new flag is shorthand for --frontend react
- const frontend = options.new ? 'react' : (options.frontend || 'both');
+ const frontend = options.new ? 'react' : (options.frontend || 'js');
// Resolve workspace path
let workspacePath = process.cwd();
diff --git a/ccw/src/templates/dashboard-js/views/mcp-manager.js b/ccw/src/templates/dashboard-js/views/mcp-manager.js
index 97e26eb5..9be2ef21 100644
--- a/ccw/src/templates/dashboard-js/views/mcp-manager.js
+++ b/ccw/src/templates/dashboard-js/views/mcp-manager.js
@@ -8,6 +8,8 @@ const CCW_MCP_TOOLS = [
{ name: 'edit_file', desc: 'Edit/replace content', core: true },
{ name: 'read_file', desc: 'Read file contents', core: true },
{ name: 'core_memory', desc: 'Core memory management', core: true },
+ // Optional tools
+ { name: 'ask_question', desc: 'Interactive questions (A2UI)', core: false },
];
// Get currently enabled tools from installed config (Claude)