feat: enhance MCP server management and system settings

- Added functionality to save MCP server configurations as templates in the MCP Manager.
- Implemented new hooks for managing system settings including Chinese response, Windows platform, and Codex CLI enhancements.
- Updated API calls to support fetching and toggling system settings.
- Introduced UI components for displaying and managing response language settings and system status.
- Enhanced error handling and notifications for server deletion and template saving actions.
- Updated localization files for new settings and descriptions in English and Chinese.
This commit is contained in:
catlog22
2026-02-07 21:17:18 +08:00
parent d29527ae16
commit 2094c1085b
52 changed files with 2061 additions and 602 deletions

View File

@@ -1 +1,84 @@
{}
{
"theme.AnnouncementBar.closeButtonAriaLabel": "关闭",
"theme.BackToTopButton.buttonAriaLabel": "回到顶部",
"theme.CodeBlock.copied": "复制成功",
"theme.CodeBlock.copy": "复制",
"theme.CodeBlock.copyButtonAriaLabel": "复制代码到剪贴板",
"theme.CodeBlock.wordWrapToggle": "切换自动换行",
"theme.DocSidebarItem.collapseCategoryAriaLabel": "折叠侧边栏分类 '{label}'",
"theme.DocSidebarItem.expandCategoryAriaLabel": "展开侧边栏分类 '{label}'",
"theme.ErrorPageContent.title": "页面已崩溃。",
"theme.ErrorPageContent.tryAgain": "重试",
"theme.IconExternalLink.ariaLabel": "(opens in new tab)",
"theme.NavBar.navAriaLabel": "主导航",
"theme.NotFound.p1": "我们找不到您要找的页面。",
"theme.NotFound.p2": "请联系原始链接来源网站的所有者,并告知他们链接已损坏。",
"theme.NotFound.title": "找不到页面",
"theme.TOCCollapsible.toggleButtonLabel": "本页总览",
"theme.admonition.caution": "警告",
"theme.admonition.danger": "危险",
"theme.admonition.info": "信息",
"theme.admonition.note": "备注",
"theme.admonition.tip": "提示",
"theme.admonition.warning": "注意",
"theme.blog.archive.description": "历史博文",
"theme.blog.archive.title": "历史博文",
"theme.blog.author.noPosts": "该作者尚未撰写任何文章。",
"theme.blog.author.pageTitle": "{authorName} - {nPosts}",
"theme.blog.authorsList.pageTitle": "作者",
"theme.blog.authorsList.viewAll": "查看所有作者",
"theme.blog.paginator.navAriaLabel": "博文列表分页导航",
"theme.blog.paginator.newerEntries": "较新的博文",
"theme.blog.paginator.olderEntries": "较旧的博文",
"theme.blog.post.paginator.navAriaLabel": "博文分页导航",
"theme.blog.post.paginator.newerPost": "较新一篇",
"theme.blog.post.paginator.olderPost": "较旧一篇",
"theme.blog.post.plurals": "{count} 篇博文",
"theme.blog.post.readMore": "阅读更多",
"theme.blog.post.readMoreLabel": "阅读 {title} 的全文",
"theme.blog.post.readingTime.plurals": "阅读需 {readingTime} 分钟",
"theme.blog.sidebar.navAriaLabel": "最近博文导航",
"theme.blog.tagTitle": "{nPosts} 含有标签「{tagName}」",
"theme.colorToggle.ariaLabel": "切换浅色/暗黑模式(当前为{mode}",
"theme.colorToggle.ariaLabel.mode.dark": "暗黑模式",
"theme.colorToggle.ariaLabel.mode.light": "浅色模式",
"theme.colorToggle.ariaLabel.mode.system": "system mode",
"theme.common.editThisPage": "编辑此页",
"theme.common.headingLinkTitle": "{heading}的直接链接",
"theme.common.skipToMainContent": "跳到主要内容",
"theme.contentVisibility.draftBanner.message": "此页面是草稿,仅在开发环境中可见,不会包含在正式版本中。",
"theme.contentVisibility.draftBanner.title": "草稿页",
"theme.contentVisibility.unlistedBanner.message": "此页面未列出。搜索引擎不会对其索引,只有拥有直接链接的用户才能访问。",
"theme.contentVisibility.unlistedBanner.title": "未列出页",
"theme.docs.DocCard.categoryDescription.plurals": "{count} 个项目",
"theme.docs.breadcrumbs.home": "主页面",
"theme.docs.breadcrumbs.navAriaLabel": "页面路径",
"theme.docs.paginator.navAriaLabel": "文件选项卡",
"theme.docs.paginator.next": "下一页",
"theme.docs.paginator.previous": "上一页",
"theme.docs.sidebar.closeSidebarButtonAriaLabel": "关闭导航栏",
"theme.docs.sidebar.collapseButtonAriaLabel": "收起侧边栏",
"theme.docs.sidebar.collapseButtonTitle": "收起侧边栏",
"theme.docs.sidebar.expandButtonAriaLabel": "展开侧边栏",
"theme.docs.sidebar.expandButtonTitle": "展开侧边栏",
"theme.docs.sidebar.navAriaLabel": "文档侧边栏",
"theme.docs.sidebar.toggleSidebarButtonAriaLabel": "切换导航栏",
"theme.docs.tagDocListPageTitle": "{nDocsTagged}「{tagName}」",
"theme.docs.tagDocListPageTitle.nDocsTagged": "{count} 篇文档带有标签",
"theme.docs.versionBadge.label": "版本:{versionLabel}",
"theme.docs.versions.latestVersionLinkLabel": "最新版本",
"theme.docs.versions.latestVersionSuggestionLabel": "最新的文档请参阅 {latestVersionLink} ({versionLabel})。",
"theme.docs.versions.unmaintainedVersionLabel": "此为 {siteTitle} {versionLabel} 版的文档,现已不再积极维护。",
"theme.docs.versions.unreleasedVersionLabel": "此为 {siteTitle} {versionLabel} 版尚未发行的文档。",
"theme.lastUpdated.atDate": "于 {date} ",
"theme.lastUpdated.byUser": "由 {user} ",
"theme.lastUpdated.lastUpdatedAtBy": "最后{byUser}{atDate}更新",
"theme.navbar.mobileDropdown.collapseButton.collapseAriaLabel": "Collapse the dropdown",
"theme.navbar.mobileDropdown.collapseButton.expandAriaLabel": "Expand the dropdown",
"theme.navbar.mobileLanguageDropdown.label": "选择语言",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← 回到主菜单",
"theme.navbar.mobileVersionsDropdown.label": "选择版本",
"theme.tags.tagsListLabel": "标签:",
"theme.tags.tagsPageLink": "查看所有标签",
"theme.tags.tagsPageTitle": "标签"
}

View File

@@ -1 +1 @@
{"options":{"path":"docs","routeBasePath":"/","sidebarPath":"D:\\Claude_dms3\\ccw\\docs-site\\sidebars.ts","editUrl":"https://github.com/ccw/docs/tree/main/","editCurrentVersion":false,"editLocalizedFiles":false,"tagsBasePath":"tags","include":["**/*.{md,mdx}"],"exclude":["**/_*.{js,jsx,ts,tsx,md,mdx}","**/_*/**","**/*.test.{js,jsx,ts,tsx}","**/__tests__/**"],"sidebarCollapsible":true,"sidebarCollapsed":true,"docsRootComponent":"@theme/DocsRoot","docVersionRootComponent":"@theme/DocVersionRoot","docRootComponent":"@theme/DocRoot","docItemComponent":"@theme/DocItem","docTagsListComponent":"@theme/DocTagsListPage","docTagDocListComponent":"@theme/DocTagDocListPage","docCategoryGeneratedIndexComponent":"@theme/DocCategoryGeneratedIndexPage","remarkPlugins":[],"rehypePlugins":[],"recmaPlugins":[],"beforeDefaultRemarkPlugins":[],"beforeDefaultRehypePlugins":[],"admonitions":true,"showLastUpdateTime":false,"showLastUpdateAuthor":false,"includeCurrentVersion":true,"disableVersioning":false,"versions":{},"breadcrumbs":true,"onInlineTags":"warn","id":"default"},"versionsMetadata":[{"versionName":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","path":"/docs/","tagsPath":"/docs/tags","editUrl":"https://github.com/ccw/docs/tree/main/docs","isLast":true,"routePriority":-1,"sidebarFilePath":"D:\\Claude_dms3\\ccw\\docs-site\\sidebars.ts","contentPath":"D:\\Claude_dms3\\ccw\\docs-site\\docs"}]}
{"options":{"path":"docs","routeBasePath":"/","sidebarPath":"D:\\Claude_dms3\\ccw\\docs-site\\sidebars.ts","editUrl":"https://github.com/ccw/docs/tree/main/","editCurrentVersion":false,"editLocalizedFiles":false,"tagsBasePath":"tags","include":["**/*.{md,mdx}"],"exclude":["**/_*.{js,jsx,ts,tsx,md,mdx}","**/_*/**","**/*.test.{js,jsx,ts,tsx}","**/__tests__/**"],"sidebarCollapsible":true,"sidebarCollapsed":true,"docsRootComponent":"@theme/DocsRoot","docVersionRootComponent":"@theme/DocVersionRoot","docRootComponent":"@theme/DocRoot","docItemComponent":"@theme/DocItem","docTagsListComponent":"@theme/DocTagsListPage","docTagDocListComponent":"@theme/DocTagDocListPage","docCategoryGeneratedIndexComponent":"@theme/DocCategoryGeneratedIndexPage","remarkPlugins":[],"rehypePlugins":[],"recmaPlugins":[],"beforeDefaultRemarkPlugins":[],"beforeDefaultRehypePlugins":[],"admonitions":true,"showLastUpdateTime":false,"showLastUpdateAuthor":false,"includeCurrentVersion":true,"disableVersioning":false,"versions":{},"breadcrumbs":true,"onInlineTags":"warn","id":"default"},"versionsMetadata":[{"versionName":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","path":"/docs/zh/","tagsPath":"/docs/zh/tags","editUrl":"https://github.com/ccw/docs/tree/main/docs","editUrlLocalized":"https://github.com/ccw/docs/tree/main/i18n/zh/docusaurus-plugin-content-docs/current","isLast":true,"routePriority":-1,"sidebarFilePath":"D:\\Claude_dms3\\ccw\\docs-site\\sidebars.ts","contentPath":"D:\\Claude_dms3\\ccw\\docs-site\\docs","contentPathLocalized":"D:\\Claude_dms3\\ccw\\docs-site\\i18n\\zh\\docusaurus-plugin-content-docs\\current"}]}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/cli/cli-init.mdx",
"sourceDirName": "commands/cli",
"slug": "/commands/cli/cli-init",
"permalink": "/docs/commands/cli/cli-init",
"permalink": "/docs/zh/commands/cli/cli-init",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/cli/cli-init.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "issue:convert-to-plan",
"permalink": "/docs/commands/issue/issue-convert-to-plan"
"permalink": "/docs/zh/commands/issue/issue-convert-to-plan"
},
"next": {
"title": "/cli:codex-review",
"permalink": "/docs/commands/cli/codex-review"
"permalink": "/docs/zh/commands/cli/codex-review"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/cli/codex-review.mdx",
"sourceDirName": "commands/cli",
"slug": "/commands/cli/codex-review",
"permalink": "/docs/commands/cli/codex-review",
"permalink": "/docs/zh/commands/cli/codex-review",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/cli/codex-review.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/cli:cli-init",
"permalink": "/docs/commands/cli/cli-init"
"permalink": "/docs/zh/commands/cli/cli-init"
},
"next": {
"title": "/memory:update-full",
"permalink": "/docs/commands/memory/memory-update-full"
"permalink": "/docs/zh/commands/memory/memory-update-full"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/general/ccw-coordinator.mdx",
"sourceDirName": "commands/general",
"slug": "/commands/general/ccw-coordinator",
"permalink": "/docs/commands/general/ccw-coordinator",
"permalink": "/docs/zh/commands/general/ccw-coordinator",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/general/ccw-coordinator.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/ccw-test",
"permalink": "/docs/commands/general/ccw-test"
"permalink": "/docs/zh/commands/general/ccw-test"
},
"next": {
"title": "/ccw-debug",
"permalink": "/docs/commands/general/ccw-debug"
"permalink": "/docs/zh/commands/general/ccw-debug"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/general/ccw-debug.mdx",
"sourceDirName": "commands/general",
"slug": "/commands/general/ccw-debug",
"permalink": "/docs/commands/general/ccw-debug",
"permalink": "/docs/zh/commands/general/ccw-debug",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/general/ccw-debug.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/ccw-coordinator",
"permalink": "/docs/commands/general/ccw-coordinator"
"permalink": "/docs/zh/commands/general/ccw-coordinator"
},
"next": {
"title": "/flow-create",
"permalink": "/docs/commands/general/flow-create"
"permalink": "/docs/zh/commands/general/flow-create"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/general/ccw.mdx",
"sourceDirName": "commands/general",
"slug": "/commands/general/ccw",
"permalink": "/docs/commands/general/ccw",
"permalink": "/docs/zh/commands/general/ccw",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/general/ccw.mdx",
@@ -20,11 +20,11 @@
},
"sidebar": "docs",
"previous": {
"title": "Overview",
"permalink": "/docs/overview"
"title": "概览",
"permalink": "/docs/zh/overview"
},
"next": {
"title": "/ccw-plan",
"permalink": "/docs/commands/general/ccw-plan"
"permalink": "/docs/zh/commands/general/ccw-plan"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/general/ccw-plan.mdx",
"sourceDirName": "commands/general",
"slug": "/commands/general/ccw-plan",
"permalink": "/docs/commands/general/ccw-plan",
"permalink": "/docs/zh/commands/general/ccw-plan",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/general/ccw-plan.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/ccw",
"permalink": "/docs/commands/general/ccw"
"permalink": "/docs/zh/commands/general/ccw"
},
"next": {
"title": "/ccw-test",
"permalink": "/docs/commands/general/ccw-test"
"permalink": "/docs/zh/commands/general/ccw-test"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/general/ccw-test.mdx",
"sourceDirName": "commands/general",
"slug": "/commands/general/ccw-test",
"permalink": "/docs/commands/general/ccw-test",
"permalink": "/docs/zh/commands/general/ccw-test",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/general/ccw-test.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/ccw-plan",
"permalink": "/docs/commands/general/ccw-plan"
"permalink": "/docs/zh/commands/general/ccw-plan"
},
"next": {
"title": "/ccw-coordinator",
"permalink": "/docs/commands/general/ccw-coordinator"
"permalink": "/docs/zh/commands/general/ccw-coordinator"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/general/codex-coordinator.mdx",
"sourceDirName": "commands/general",
"slug": "/commands/general/codex-coordinator",
"permalink": "/docs/commands/general/codex-coordinator",
"permalink": "/docs/zh/commands/general/codex-coordinator",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/general/codex-coordinator.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/flow-create",
"permalink": "/docs/commands/general/flow-create"
"permalink": "/docs/zh/commands/general/flow-create"
},
"next": {
"title": "issue:new",
"permalink": "/docs/commands/issue/issue-new"
"permalink": "/docs/zh/commands/issue/issue-new"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/general/flow-create.mdx",
"sourceDirName": "commands/general",
"slug": "/commands/general/flow-create",
"permalink": "/docs/commands/general/flow-create",
"permalink": "/docs/zh/commands/general/flow-create",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/general/flow-create.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/ccw-debug",
"permalink": "/docs/commands/general/ccw-debug"
"permalink": "/docs/zh/commands/general/ccw-debug"
},
"next": {
"title": "/codex-coordinator",
"permalink": "/docs/commands/general/codex-coordinator"
"permalink": "/docs/zh/commands/general/codex-coordinator"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/issue/issue-convert-to-plan.md",
"sourceDirName": "commands/issue",
"slug": "/commands/issue/issue-convert-to-plan",
"permalink": "/docs/commands/issue/issue-convert-to-plan",
"permalink": "/docs/zh/commands/issue/issue-convert-to-plan",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/issue/issue-convert-to-plan.md",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "issue:from-brainstorm",
"permalink": "/docs/commands/issue/issue-from-brainstorm"
"permalink": "/docs/zh/commands/issue/issue-from-brainstorm"
},
"next": {
"title": "/cli:cli-init",
"permalink": "/docs/commands/cli/cli-init"
"permalink": "/docs/zh/commands/cli/cli-init"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/issue/issue-discover.md",
"sourceDirName": "commands/issue",
"slug": "/commands/issue/issue-discover",
"permalink": "/docs/commands/issue/issue-discover",
"permalink": "/docs/zh/commands/issue/issue-discover",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/issue/issue-discover.md",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "issue:new",
"permalink": "/docs/commands/issue/issue-new"
"permalink": "/docs/zh/commands/issue/issue-new"
},
"next": {
"title": "issue:plan",
"permalink": "/docs/commands/issue/issue-plan"
"permalink": "/docs/zh/commands/issue/issue-plan"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/issue/issue-execute.md",
"sourceDirName": "commands/issue",
"slug": "/commands/issue/issue-execute",
"permalink": "/docs/commands/issue/issue-execute",
"permalink": "/docs/zh/commands/issue/issue-execute",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/issue/issue-execute.md",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "issue:queue",
"permalink": "/docs/commands/issue/issue-queue"
"permalink": "/docs/zh/commands/issue/issue-queue"
},
"next": {
"title": "issue:from-brainstorm",
"permalink": "/docs/commands/issue/issue-from-brainstorm"
"permalink": "/docs/zh/commands/issue/issue-from-brainstorm"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/issue/issue-from-brainstorm.md",
"sourceDirName": "commands/issue",
"slug": "/commands/issue/issue-from-brainstorm",
"permalink": "/docs/commands/issue/issue-from-brainstorm",
"permalink": "/docs/zh/commands/issue/issue-from-brainstorm",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/issue/issue-from-brainstorm.md",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "issue:execute",
"permalink": "/docs/commands/issue/issue-execute"
"permalink": "/docs/zh/commands/issue/issue-execute"
},
"next": {
"title": "issue:convert-to-plan",
"permalink": "/docs/commands/issue/issue-convert-to-plan"
"permalink": "/docs/zh/commands/issue/issue-convert-to-plan"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/issue/issue-new.md",
"sourceDirName": "commands/issue",
"slug": "/commands/issue/issue-new",
"permalink": "/docs/commands/issue/issue-new",
"permalink": "/docs/zh/commands/issue/issue-new",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/issue/issue-new.md",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/codex-coordinator",
"permalink": "/docs/commands/general/codex-coordinator"
"permalink": "/docs/zh/commands/general/codex-coordinator"
},
"next": {
"title": "issue:discover",
"permalink": "/docs/commands/issue/issue-discover"
"permalink": "/docs/zh/commands/issue/issue-discover"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/issue/issue-plan.md",
"sourceDirName": "commands/issue",
"slug": "/commands/issue/issue-plan",
"permalink": "/docs/commands/issue/issue-plan",
"permalink": "/docs/zh/commands/issue/issue-plan",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/issue/issue-plan.md",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "issue:discover",
"permalink": "/docs/commands/issue/issue-discover"
"permalink": "/docs/zh/commands/issue/issue-discover"
},
"next": {
"title": "issue:queue",
"permalink": "/docs/commands/issue/issue-queue"
"permalink": "/docs/zh/commands/issue/issue-queue"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/issue/issue-queue.md",
"sourceDirName": "commands/issue",
"slug": "/commands/issue/issue-queue",
"permalink": "/docs/commands/issue/issue-queue",
"permalink": "/docs/zh/commands/issue/issue-queue",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/issue/issue-queue.md",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "issue:plan",
"permalink": "/docs/commands/issue/issue-plan"
"permalink": "/docs/zh/commands/issue/issue-plan"
},
"next": {
"title": "issue:execute",
"permalink": "/docs/commands/issue/issue-execute"
"permalink": "/docs/zh/commands/issue/issue-execute"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/memory/memory-compact.mdx",
"sourceDirName": "commands/memory",
"slug": "/commands/memory/memory-compact",
"permalink": "/docs/commands/memory/memory-compact",
"permalink": "/docs/zh/commands/memory/memory-compact",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/memory/memory-compact.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/memory:docs-related-cli",
"permalink": "/docs/commands/memory/memory-docs-related-cli"
"permalink": "/docs/zh/commands/memory/memory-docs-related-cli"
},
"next": {
"title": "Introduction",
"permalink": "/docs/workflows/introduction"
"permalink": "/docs/zh/workflows/introduction"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/memory/memory-docs-full-cli.mdx",
"sourceDirName": "commands/memory",
"slug": "/commands/memory/memory-docs-full-cli",
"permalink": "/docs/commands/memory/memory-docs-full-cli",
"permalink": "/docs/zh/commands/memory/memory-docs-full-cli",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/memory/memory-docs-full-cli.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/memory:load",
"permalink": "/docs/commands/memory/memory-load"
"permalink": "/docs/zh/commands/memory/memory-load"
},
"next": {
"title": "/memory:docs-related-cli",
"permalink": "/docs/commands/memory/memory-docs-related-cli"
"permalink": "/docs/zh/commands/memory/memory-docs-related-cli"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/memory/memory-docs-related-cli.mdx",
"sourceDirName": "commands/memory",
"slug": "/commands/memory/memory-docs-related-cli",
"permalink": "/docs/commands/memory/memory-docs-related-cli",
"permalink": "/docs/zh/commands/memory/memory-docs-related-cli",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/memory/memory-docs-related-cli.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/memory:docs-full-cli",
"permalink": "/docs/commands/memory/memory-docs-full-cli"
"permalink": "/docs/zh/commands/memory/memory-docs-full-cli"
},
"next": {
"title": "/memory:compact",
"permalink": "/docs/commands/memory/memory-compact"
"permalink": "/docs/zh/commands/memory/memory-compact"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/memory/memory-load.mdx",
"sourceDirName": "commands/memory",
"slug": "/commands/memory/memory-load",
"permalink": "/docs/commands/memory/memory-load",
"permalink": "/docs/zh/commands/memory/memory-load",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/memory/memory-load.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/memory:update-related",
"permalink": "/docs/commands/memory/memory-update-related"
"permalink": "/docs/zh/commands/memory/memory-update-related"
},
"next": {
"title": "/memory:docs-full-cli",
"permalink": "/docs/commands/memory/memory-docs-full-cli"
"permalink": "/docs/zh/commands/memory/memory-docs-full-cli"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/memory/memory-update-full.mdx",
"sourceDirName": "commands/memory",
"slug": "/commands/memory/memory-update-full",
"permalink": "/docs/commands/memory/memory-update-full",
"permalink": "/docs/zh/commands/memory/memory-update-full",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/memory/memory-update-full.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/cli:codex-review",
"permalink": "/docs/commands/cli/codex-review"
"permalink": "/docs/zh/commands/cli/codex-review"
},
"next": {
"title": "/memory:update-related",
"permalink": "/docs/commands/memory/memory-update-related"
"permalink": "/docs/zh/commands/memory/memory-update-related"
}
}

View File

@@ -5,7 +5,7 @@
"source": "@site/docs/commands/memory/memory-update-related.mdx",
"sourceDirName": "commands/memory",
"slug": "/commands/memory/memory-update-related",
"permalink": "/docs/commands/memory/memory-update-related",
"permalink": "/docs/zh/commands/memory/memory-update-related",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/ccw/docs/tree/main/docs/commands/memory/memory-update-related.mdx",
@@ -21,10 +21,10 @@
"sidebar": "docs",
"previous": {
"title": "/memory:update-full",
"permalink": "/docs/commands/memory/memory-update-full"
"permalink": "/docs/zh/commands/memory/memory-update-full"
},
"next": {
"title": "/memory:load",
"permalink": "/docs/commands/memory/memory-load"
"permalink": "/docs/zh/commands/memory/memory-load"
}
}

View File

@@ -8,7 +8,7 @@ export default {
"tagline": "Professional Workflow Automation Platform",
"favicon": "img/favicon.svg",
"url": "http://localhost:3001",
"baseUrl": "/docs/",
"baseUrl": "/docs/zh/",
"organizationName": "ccw",
"projectName": "docs",
"trailingSlash": false,
@@ -48,9 +48,9 @@ export default {
],
"themeConfig": {
"navbar": {
"title": "CCW Help",
"title": "CCW 帮助",
"logo": {
"alt": "CCW Logo",
"alt": "CCW 标志",
"src": "img/logo.svg"
},
"items": [
@@ -65,7 +65,7 @@ export default {
},
"footer": {
"style": "dark",
"copyright": "Copyright © 2026 CCW. Built with Docusaurus.",
"copyright": "版权 © 2026 CCW。使用 Docusaurus 构建。",
"links": []
},
"prism": {

View File

@@ -1,172 +1,172 @@
{
"docusaurus-plugin-content-docs": {
"default": {
"path": "/docs/",
"path": "/docs/zh/",
"versions": [
{
"name": "current",
"label": "Next",
"label": "当前",
"isLast": true,
"path": "/docs/",
"path": "/docs/zh/",
"mainDocId": "index",
"docs": [
{
"id": "commands/cli/cli-init",
"path": "/docs/commands/cli/cli-init",
"path": "/docs/zh/commands/cli/cli-init",
"sidebar": "docs"
},
{
"id": "commands/cli/codex-review",
"path": "/docs/commands/cli/codex-review",
"path": "/docs/zh/commands/cli/codex-review",
"sidebar": "docs"
},
{
"id": "commands/general/ccw",
"path": "/docs/commands/general/ccw",
"path": "/docs/zh/commands/general/ccw",
"sidebar": "docs"
},
{
"id": "commands/general/ccw-coordinator",
"path": "/docs/commands/general/ccw-coordinator",
"path": "/docs/zh/commands/general/ccw-coordinator",
"sidebar": "docs"
},
{
"id": "commands/general/ccw-debug",
"path": "/docs/commands/general/ccw-debug",
"path": "/docs/zh/commands/general/ccw-debug",
"sidebar": "docs"
},
{
"id": "commands/general/ccw-plan",
"path": "/docs/commands/general/ccw-plan",
"path": "/docs/zh/commands/general/ccw-plan",
"sidebar": "docs"
},
{
"id": "commands/general/ccw-test",
"path": "/docs/commands/general/ccw-test",
"path": "/docs/zh/commands/general/ccw-test",
"sidebar": "docs"
},
{
"id": "commands/general/codex-coordinator",
"path": "/docs/commands/general/codex-coordinator",
"path": "/docs/zh/commands/general/codex-coordinator",
"sidebar": "docs"
},
{
"id": "commands/general/flow-create",
"path": "/docs/commands/general/flow-create",
"path": "/docs/zh/commands/general/flow-create",
"sidebar": "docs"
},
{
"id": "commands/issue/issue-convert-to-plan",
"path": "/docs/commands/issue/issue-convert-to-plan",
"path": "/docs/zh/commands/issue/issue-convert-to-plan",
"sidebar": "docs"
},
{
"id": "commands/issue/issue-discover",
"path": "/docs/commands/issue/issue-discover",
"path": "/docs/zh/commands/issue/issue-discover",
"sidebar": "docs"
},
{
"id": "commands/issue/issue-execute",
"path": "/docs/commands/issue/issue-execute",
"path": "/docs/zh/commands/issue/issue-execute",
"sidebar": "docs"
},
{
"id": "commands/issue/issue-from-brainstorm",
"path": "/docs/commands/issue/issue-from-brainstorm",
"path": "/docs/zh/commands/issue/issue-from-brainstorm",
"sidebar": "docs"
},
{
"id": "commands/issue/issue-new",
"path": "/docs/commands/issue/issue-new",
"path": "/docs/zh/commands/issue/issue-new",
"sidebar": "docs"
},
{
"id": "commands/issue/issue-plan",
"path": "/docs/commands/issue/issue-plan",
"path": "/docs/zh/commands/issue/issue-plan",
"sidebar": "docs"
},
{
"id": "commands/issue/issue-queue",
"path": "/docs/commands/issue/issue-queue",
"path": "/docs/zh/commands/issue/issue-queue",
"sidebar": "docs"
},
{
"id": "commands/memory/memory-compact",
"path": "/docs/commands/memory/memory-compact",
"path": "/docs/zh/commands/memory/memory-compact",
"sidebar": "docs"
},
{
"id": "commands/memory/memory-docs-full-cli",
"path": "/docs/commands/memory/memory-docs-full-cli",
"path": "/docs/zh/commands/memory/memory-docs-full-cli",
"sidebar": "docs"
},
{
"id": "commands/memory/memory-docs-related-cli",
"path": "/docs/commands/memory/memory-docs-related-cli",
"path": "/docs/zh/commands/memory/memory-docs-related-cli",
"sidebar": "docs"
},
{
"id": "commands/memory/memory-load",
"path": "/docs/commands/memory/memory-load",
"path": "/docs/zh/commands/memory/memory-load",
"sidebar": "docs"
},
{
"id": "commands/memory/memory-update-full",
"path": "/docs/commands/memory/memory-update-full",
"path": "/docs/zh/commands/memory/memory-update-full",
"sidebar": "docs"
},
{
"id": "commands/memory/memory-update-related",
"path": "/docs/commands/memory/memory-update-related",
"path": "/docs/zh/commands/memory/memory-update-related",
"sidebar": "docs"
},
{
"id": "faq",
"path": "/docs/faq",
"path": "/docs/zh/faq",
"sidebar": "docs"
},
{
"id": "index",
"path": "/docs/",
"path": "/docs/zh/",
"sidebar": "docs"
},
{
"id": "overview",
"path": "/docs/overview",
"path": "/docs/zh/overview",
"sidebar": "docs"
},
{
"id": "workflows/faq",
"path": "/docs/workflows/faq"
"path": "/docs/zh/workflows/faq"
},
{
"id": "workflows/introduction",
"path": "/docs/workflows/introduction",
"path": "/docs/zh/workflows/introduction",
"sidebar": "docs"
},
{
"id": "workflows/level-1-ultra-lightweight",
"path": "/docs/workflows/level-1-ultra-lightweight",
"path": "/docs/zh/workflows/level-1-ultra-lightweight",
"sidebar": "docs"
},
{
"id": "workflows/level-2-rapid",
"path": "/docs/workflows/level-2-rapid",
"path": "/docs/zh/workflows/level-2-rapid",
"sidebar": "docs"
},
{
"id": "workflows/level-3-standard",
"path": "/docs/workflows/level-3-standard",
"path": "/docs/zh/workflows/level-3-standard",
"sidebar": "docs"
},
{
"id": "workflows/level-4-brainstorm",
"path": "/docs/workflows/level-4-brainstorm",
"path": "/docs/zh/workflows/level-4-brainstorm",
"sidebar": "docs"
},
{
"id": "workflows/level-5-intelligent",
"path": "/docs/workflows/level-5-intelligent",
"path": "/docs/zh/workflows/level-5-intelligent",
"sidebar": "docs"
}
],
@@ -174,7 +174,7 @@
"sidebars": {
"docs": {
"link": {
"path": "/docs/",
"path": "/docs/zh/",
"label": "Home"
}
}

View File

@@ -5,7 +5,7 @@
"zh"
],
"path": "i18n",
"currentLocale": "en",
"currentLocale": "zh",
"localeConfigs": {
"en": {
"label": "English",

View File

@@ -1,47 +1,39 @@
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-11-b-f70": [() => import(/* webpackChunkName: "__props---docs-11-b-f70" */ "@generated/docusaurus-plugin-content-docs/default/p/docs-7fc.json"), "@generated/docusaurus-plugin-content-docs/default/p/docs-7fc.json", require.resolveWeak("@generated/docusaurus-plugin-content-docs/default/p/docs-7fc.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-4-ed-831": [() => import(/* webpackChunkName: "content---docs-4-ed-831" */ "@site/docs/index.mdx"), "@site/docs/index.mdx", require.resolveWeak("@site/docs/index.mdx")],
"content---docs-commands-cli-cli-init-056-ce1": [() => import(/* webpackChunkName: "content---docs-commands-cli-cli-init-056-ce1" */ "@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-commands-cli-codex-reviewf-1-b-55f": [() => import(/* webpackChunkName: "content---docs-commands-cli-codex-reviewf-1-b-55f" */ "@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-commands-general-ccw-coordinatord-55-c6b": [() => import(/* webpackChunkName: "content---docs-commands-general-ccw-coordinatord-55-c6b" */ "@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-commands-general-ccw-debug-97-c-a72": [() => import(/* webpackChunkName: "content---docs-commands-general-ccw-debug-97-c-a72" */ "@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-commands-general-ccw-plan-04-d-fe0": [() => import(/* webpackChunkName: "content---docs-commands-general-ccw-plan-04-d-fe0" */ "@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-commands-general-ccw-testcce-912": [() => import(/* webpackChunkName: "content---docs-commands-general-ccw-testcce-912" */ "@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-commands-general-ccwf-48-8c4": [() => import(/* webpackChunkName: "content---docs-commands-general-ccwf-48-8c4" */ "@site/docs/commands/general/ccw.mdx"), "@site/docs/commands/general/ccw.mdx", require.resolveWeak("@site/docs/commands/general/ccw.mdx")],
"content---docs-commands-general-codex-coordinatorf-92-1dc": [() => import(/* webpackChunkName: "content---docs-commands-general-codex-coordinatorf-92-1dc" */ "@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-commands-general-flow-createfab-98a": [() => import(/* webpackChunkName: "content---docs-commands-general-flow-createfab-98a" */ "@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-commands-issue-issue-convert-to-plan-5-c-7-184": [() => import(/* webpackChunkName: "content---docs-commands-issue-issue-convert-to-plan-5-c-7-184" */ "@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-commands-issue-issue-discover-1-e-3-569": [() => import(/* webpackChunkName: "content---docs-commands-issue-issue-discover-1-e-3-569" */ "@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-commands-issue-issue-executefe-8-c03": [() => import(/* webpackChunkName: "content---docs-commands-issue-issue-executefe-8-c03" */ "@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-commands-issue-issue-from-brainstorm-2-ec-eeb": [() => import(/* webpackChunkName: "content---docs-commands-issue-issue-from-brainstorm-2-ec-eeb" */ "@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-commands-issue-issue-new-4-ad-3f0": [() => import(/* webpackChunkName: "content---docs-commands-issue-issue-new-4-ad-3f0" */ "@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-commands-issue-issue-plana-6-c-fbd": [() => import(/* webpackChunkName: "content---docs-commands-issue-issue-plana-6-c-fbd" */ "@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-commands-issue-issue-queue-1-ba-55f": [() => import(/* webpackChunkName: "content---docs-commands-issue-issue-queue-1-ba-55f" */ "@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-commands-memory-memory-compact-7-a-1-41c": [() => import(/* webpackChunkName: "content---docs-commands-memory-memory-compact-7-a-1-41c" */ "@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-commands-memory-memory-docs-full-cli-4-cc-96f": [() => import(/* webpackChunkName: "content---docs-commands-memory-memory-docs-full-cli-4-cc-96f" */ "@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-commands-memory-memory-docs-related-cli-60-e-dd0": [() => import(/* webpackChunkName: "content---docs-commands-memory-memory-docs-related-cli-60-e-dd0" */ "@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-commands-memory-memory-load-157-952": [() => import(/* webpackChunkName: "content---docs-commands-memory-memory-load-157-952" */ "@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-commands-memory-memory-update-full-666-002": [() => import(/* webpackChunkName: "content---docs-commands-memory-memory-update-full-666-002" */ "@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-commands-memory-memory-update-related-611-8d3": [() => import(/* webpackChunkName: "content---docs-commands-memory-memory-update-related-611-8d3" */ "@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-faqea-3-888": [() => import(/* webpackChunkName: "content---docs-faqea-3-888" */ "@site/docs/faq.mdx"), "@site/docs/faq.mdx", require.resolveWeak("@site/docs/faq.mdx")],
"content---docs-overview-188-429": [() => import(/* webpackChunkName: "content---docs-overview-188-429" */ "@site/docs/overview.mdx"), "@site/docs/overview.mdx", require.resolveWeak("@site/docs/overview.mdx")],
"content---docs-workflows-faqbcf-045": [() => import(/* webpackChunkName: "content---docs-workflows-faqbcf-045" */ "@site/docs/workflows/faq.mdx"), "@site/docs/workflows/faq.mdx", require.resolveWeak("@site/docs/workflows/faq.mdx")],
"content---docs-workflows-introduction-9-f-4-275": [() => import(/* webpackChunkName: "content---docs-workflows-introduction-9-f-4-275" */ "@site/docs/workflows/introduction.mdx"), "@site/docs/workflows/introduction.mdx", require.resolveWeak("@site/docs/workflows/introduction.mdx")],
"content---docs-workflows-level-1-ultra-lightweightc-5-a-5db": [() => import(/* webpackChunkName: "content---docs-workflows-level-1-ultra-lightweightc-5-a-5db" */ "@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-workflows-level-2-rapid-19-b-095": [() => import(/* webpackChunkName: "content---docs-workflows-level-2-rapid-19-b-095" */ "@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-workflows-level-3-standardbdb-61a": [() => import(/* webpackChunkName: "content---docs-workflows-level-3-standardbdb-61a" */ "@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-workflows-level-4-brainstormd-04-14f": [() => import(/* webpackChunkName: "content---docs-workflows-level-4-brainstormd-04-14f" */ "@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-workflows-level-5-intelligent-186-b05": [() => import(/* webpackChunkName: "content---docs-workflows-level-5-intelligent-186-b05" */ "@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-aba-4f5": [() => import(/* webpackChunkName: "plugin---docs-aba-4f5" */ "@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")],
"05467734": [() => import(/* webpackChunkName: "05467734" */ "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-2-rapid.mdx"), "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-2-rapid.mdx", require.resolveWeak("@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-2-rapid.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")],
"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")],
"2a5e3eff": [() => import(/* webpackChunkName: "2a5e3eff" */ "@site/i18n/zh/docusaurus-plugin-content-docs/current/faq.mdx"), "@site/i18n/zh/docusaurus-plugin-content-docs/current/faq.mdx", require.resolveWeak("@site/i18n/zh/docusaurus-plugin-content-docs/current/faq.mdx")],
"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")],
"3f1fe4a1": [() => import(/* webpackChunkName: "3f1fe4a1" */ "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-3-standard.mdx"), "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-3-standard.mdx", require.resolveWeak("@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-3-standard.mdx")],
"46f40178": [() => import(/* webpackChunkName: "46f40178" */ "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/faq.mdx"), "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/faq.mdx", require.resolveWeak("@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/faq.mdx")],
"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")],
"562bb8cb": [() => import(/* webpackChunkName: "562bb8cb" */ "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-5-intelligent.mdx"), "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-5-intelligent.mdx", require.resolveWeak("@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-5-intelligent.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")],
"6ab014e9": [() => import(/* webpackChunkName: "6ab014e9" */ "@site/i18n/zh/docusaurus-plugin-content-docs/current/index.mdx"), "@site/i18n/zh/docusaurus-plugin-content-docs/current/index.mdx", require.resolveWeak("@site/i18n/zh/docusaurus-plugin-content-docs/current/index.mdx")],
"775938bf": [() => import(/* webpackChunkName: "775938bf" */ "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-4-brainstorm.mdx"), "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-4-brainstorm.mdx", require.resolveWeak("@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-4-brainstorm.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")],
"8a7e39ed": [() => import(/* webpackChunkName: "8a7e39ed" */ "@site/i18n/zh/docusaurus-plugin-content-docs/current/overview.mdx"), "@site/i18n/zh/docusaurus-plugin-content-docs/current/overview.mdx", require.resolveWeak("@site/i18n/zh/docusaurus-plugin-content-docs/current/overview.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")],
"9cf7cb6b": [() => import(/* webpackChunkName: "9cf7cb6b" */ "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-1-ultra-lightweight.mdx"), "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-1-ultra-lightweight.mdx", require.resolveWeak("@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/level-1-ultra-lightweight.mdx")],
"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")],
"b17e4002": [() => import(/* webpackChunkName: "b17e4002" */ "@generated/docusaurus-plugin-content-docs/default/p/docs-zh-d2a.json"), "@generated/docusaurus-plugin-content-docs/default/p/docs-zh-d2a.json", require.resolveWeak("@generated/docusaurus-plugin-content-docs/default/p/docs-zh-d2a.json")],
"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")],
"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")],
"e5f6eee3": [() => import(/* webpackChunkName: "e5f6eee3" */ "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/introduction.mdx"), "@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/introduction.mdx", require.resolveWeak("@site/i18n/zh/docusaurus-plugin-content-docs/current/workflows/introduction.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")],};

View File

@@ -3,240 +3,205 @@ 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/',
component: ComponentCreator('/docs/', 'a3f'),
path: '/docs/zh/',
component: ComponentCreator('/docs/zh/', 'b34'),
routes: [
{
path: '/docs/',
component: ComponentCreator('/docs/', 'fa7'),
path: '/docs/zh/',
component: ComponentCreator('/docs/zh/', 'a8e'),
routes: [
{
path: '/docs/',
component: ComponentCreator('/docs/', '294'),
path: '/docs/zh/',
component: ComponentCreator('/docs/zh/', '632'),
routes: [
{
path: '/docs/commands/cli/cli-init',
component: ComponentCreator('/docs/commands/cli/cli-init', '159'),
path: '/docs/zh/commands/cli/cli-init',
component: ComponentCreator('/docs/zh/commands/cli/cli-init', 'fe3'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/cli/codex-review',
component: ComponentCreator('/docs/commands/cli/codex-review', 'c66'),
path: '/docs/zh/commands/cli/codex-review',
component: ComponentCreator('/docs/zh/commands/cli/codex-review', 'e65'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/general/ccw',
component: ComponentCreator('/docs/commands/general/ccw', '3c1'),
path: '/docs/zh/commands/general/ccw',
component: ComponentCreator('/docs/zh/commands/general/ccw', '83a'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/general/ccw-coordinator',
component: ComponentCreator('/docs/commands/general/ccw-coordinator', '3b4'),
path: '/docs/zh/commands/general/ccw-coordinator',
component: ComponentCreator('/docs/zh/commands/general/ccw-coordinator', 'f35'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/general/ccw-debug',
component: ComponentCreator('/docs/commands/general/ccw-debug', 'e0c'),
path: '/docs/zh/commands/general/ccw-debug',
component: ComponentCreator('/docs/zh/commands/general/ccw-debug', 'b0a'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/general/ccw-plan',
component: ComponentCreator('/docs/commands/general/ccw-plan', '9ae'),
path: '/docs/zh/commands/general/ccw-plan',
component: ComponentCreator('/docs/zh/commands/general/ccw-plan', '39d'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/general/ccw-test',
component: ComponentCreator('/docs/commands/general/ccw-test', 'e6f'),
path: '/docs/zh/commands/general/ccw-test',
component: ComponentCreator('/docs/zh/commands/general/ccw-test', '765'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/general/codex-coordinator',
component: ComponentCreator('/docs/commands/general/codex-coordinator', 'e7d'),
path: '/docs/zh/commands/general/codex-coordinator',
component: ComponentCreator('/docs/zh/commands/general/codex-coordinator', '486'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/general/flow-create',
component: ComponentCreator('/docs/commands/general/flow-create', '507'),
path: '/docs/zh/commands/general/flow-create',
component: ComponentCreator('/docs/zh/commands/general/flow-create', 'd53'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/issue/issue-convert-to-plan',
component: ComponentCreator('/docs/commands/issue/issue-convert-to-plan', 'a36'),
path: '/docs/zh/commands/issue/issue-convert-to-plan',
component: ComponentCreator('/docs/zh/commands/issue/issue-convert-to-plan', '0df'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/issue/issue-discover',
component: ComponentCreator('/docs/commands/issue/issue-discover', '5ae'),
path: '/docs/zh/commands/issue/issue-discover',
component: ComponentCreator('/docs/zh/commands/issue/issue-discover', '9b4'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/issue/issue-execute',
component: ComponentCreator('/docs/commands/issue/issue-execute', '20b'),
path: '/docs/zh/commands/issue/issue-execute',
component: ComponentCreator('/docs/zh/commands/issue/issue-execute', 'cfd'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/issue/issue-from-brainstorm',
component: ComponentCreator('/docs/commands/issue/issue-from-brainstorm', '10c'),
path: '/docs/zh/commands/issue/issue-from-brainstorm',
component: ComponentCreator('/docs/zh/commands/issue/issue-from-brainstorm', 'd2f'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/issue/issue-new',
component: ComponentCreator('/docs/commands/issue/issue-new', 'abb'),
path: '/docs/zh/commands/issue/issue-new',
component: ComponentCreator('/docs/zh/commands/issue/issue-new', '7f9'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/issue/issue-plan',
component: ComponentCreator('/docs/commands/issue/issue-plan', '57f'),
path: '/docs/zh/commands/issue/issue-plan',
component: ComponentCreator('/docs/zh/commands/issue/issue-plan', 'ed4'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/issue/issue-queue',
component: ComponentCreator('/docs/commands/issue/issue-queue', '316'),
path: '/docs/zh/commands/issue/issue-queue',
component: ComponentCreator('/docs/zh/commands/issue/issue-queue', 'a4b'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/memory/memory-compact',
component: ComponentCreator('/docs/commands/memory/memory-compact', 'fbd'),
path: '/docs/zh/commands/memory/memory-compact',
component: ComponentCreator('/docs/zh/commands/memory/memory-compact', '8dc'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/memory/memory-docs-full-cli',
component: ComponentCreator('/docs/commands/memory/memory-docs-full-cli', '8b8'),
path: '/docs/zh/commands/memory/memory-docs-full-cli',
component: ComponentCreator('/docs/zh/commands/memory/memory-docs-full-cli', '1a7'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/memory/memory-docs-related-cli',
component: ComponentCreator('/docs/commands/memory/memory-docs-related-cli', '707'),
path: '/docs/zh/commands/memory/memory-docs-related-cli',
component: ComponentCreator('/docs/zh/commands/memory/memory-docs-related-cli', 'f28'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/memory/memory-load',
component: ComponentCreator('/docs/commands/memory/memory-load', '1db'),
path: '/docs/zh/commands/memory/memory-load',
component: ComponentCreator('/docs/zh/commands/memory/memory-load', 'aee'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/memory/memory-update-full',
component: ComponentCreator('/docs/commands/memory/memory-update-full', '3fa'),
path: '/docs/zh/commands/memory/memory-update-full',
component: ComponentCreator('/docs/zh/commands/memory/memory-update-full', '2a1'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/commands/memory/memory-update-related',
component: ComponentCreator('/docs/commands/memory/memory-update-related', 'c50'),
path: '/docs/zh/commands/memory/memory-update-related',
component: ComponentCreator('/docs/zh/commands/memory/memory-update-related', '991'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/faq',
component: ComponentCreator('/docs/faq', '296'),
path: '/docs/zh/faq',
component: ComponentCreator('/docs/zh/faq', 'd6c'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/overview',
component: ComponentCreator('/docs/overview', 'f90'),
path: '/docs/zh/overview',
component: ComponentCreator('/docs/zh/overview', '2d1'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/workflows/faq',
component: ComponentCreator('/docs/workflows/faq', '58c'),
path: '/docs/zh/workflows/faq',
component: ComponentCreator('/docs/zh/workflows/faq', '319'),
exact: true
},
{
path: '/docs/workflows/introduction',
component: ComponentCreator('/docs/workflows/introduction', '702'),
path: '/docs/zh/workflows/introduction',
component: ComponentCreator('/docs/zh/workflows/introduction', 'dc8'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/workflows/level-1-ultra-lightweight',
component: ComponentCreator('/docs/workflows/level-1-ultra-lightweight', 'b4b'),
path: '/docs/zh/workflows/level-1-ultra-lightweight',
component: ComponentCreator('/docs/zh/workflows/level-1-ultra-lightweight', '4d3'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/workflows/level-2-rapid',
component: ComponentCreator('/docs/workflows/level-2-rapid', 'fe1'),
path: '/docs/zh/workflows/level-2-rapid',
component: ComponentCreator('/docs/zh/workflows/level-2-rapid', 'e2a'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/workflows/level-3-standard',
component: ComponentCreator('/docs/workflows/level-3-standard', '65f'),
path: '/docs/zh/workflows/level-3-standard',
component: ComponentCreator('/docs/zh/workflows/level-3-standard', '936'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/workflows/level-4-brainstorm',
component: ComponentCreator('/docs/workflows/level-4-brainstorm', 'fae'),
path: '/docs/zh/workflows/level-4-brainstorm',
component: ComponentCreator('/docs/zh/workflows/level-4-brainstorm', '87d'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/workflows/level-5-intelligent',
component: ComponentCreator('/docs/workflows/level-5-intelligent', 'fa9'),
path: '/docs/zh/workflows/level-5-intelligent',
component: ComponentCreator('/docs/zh/workflows/level-5-intelligent', 'b09'),
exact: true,
sidebar: "docs"
},
{
path: '/docs/',
component: ComponentCreator('/docs/', '6df'),
path: '/docs/zh/',
component: ComponentCreator('/docs/zh/', '0e3'),
exact: true,
sidebar: "docs"
}

View File

@@ -1,186 +1,143 @@
{
"/docs/__docusaurus/debug-e58": {
"__comp": "__comp---theme-debug-config-23-a-2ff",
"/docs/zh/-b34": {
"__comp": "5e95c892",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
"plugin": "aba21aa0"
}
},
"/docs/__docusaurus/debug/config-2ce": {
"__comp": "__comp---theme-debug-config-23-a-2ff",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
}
"/docs/zh/-a8e": {
"__comp": "a7bd4aaa",
"__props": "b17e4002"
},
"/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/zh/-632": {
"__comp": "a94703ab"
},
"/docs/__docusaurus/debug/globalData-f13": {
"__comp": "__comp---theme-debug-global-dataede-0fa",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
}
"/docs/zh/commands/cli/cli-init-fe3": {
"__comp": "17896441",
"content": "0566a0a8"
},
"/docs/__docusaurus/debug/metadata-bff": {
"__comp": "__comp---theme-debug-site-metadata-68-e-3d4",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
}
"/docs/zh/commands/cli/codex-review-e65": {
"__comp": "17896441",
"content": "f1bf82ec"
},
"/docs/__docusaurus/debug/registry-830": {
"__comp": "__comp---theme-debug-registry-679-501",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
}
"/docs/zh/commands/general/ccw-83a": {
"__comp": "17896441",
"content": "f4817052"
},
"/docs/__docusaurus/debug/routes-13e": {
"__comp": "__comp---theme-debug-routes-946-699",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
}
"/docs/zh/commands/general/ccw-coordinator-f35": {
"__comp": "17896441",
"content": "d550a629"
},
"/docs/-a3f": {
"__comp": "__comp---theme-docs-root-5-e-9-0b6",
"__context": {
"plugin": "plugin---docs-aba-4f5"
}
"/docs/zh/commands/general/ccw-debug-b0a": {
"__comp": "17896441",
"content": "97c6e66a"
},
"/docs/-fa7": {
"__comp": "__comp---theme-doc-version-roota-7-b-5de",
"__props": "__props---docs-11-b-f70"
"/docs/zh/commands/general/ccw-plan-39d": {
"__comp": "17896441",
"content": "04db0a2e"
},
"/docs/-294": {
"__comp": "__comp---theme-doc-roota-94-67a"
"/docs/zh/commands/general/ccw-test-765": {
"__comp": "17896441",
"content": "ccef5d0f"
},
"/docs/commands/cli/cli-init-159": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-cli-cli-init-056-ce1"
"/docs/zh/commands/general/codex-coordinator-486": {
"__comp": "17896441",
"content": "f9222419"
},
"/docs/commands/cli/codex-review-c66": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-cli-codex-reviewf-1-b-55f"
"/docs/zh/commands/general/flow-create-d53": {
"__comp": "17896441",
"content": "fabaf1c8"
},
"/docs/commands/general/ccw-3c1": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-general-ccwf-48-8c4"
"/docs/zh/commands/issue/issue-convert-to-plan-0df": {
"__comp": "17896441",
"content": "5c7b2278"
},
"/docs/commands/general/ccw-coordinator-3b4": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-general-ccw-coordinatord-55-c6b"
"/docs/zh/commands/issue/issue-discover-9b4": {
"__comp": "17896441",
"content": "1e3006f3"
},
"/docs/commands/general/ccw-debug-e0c": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-general-ccw-debug-97-c-a72"
"/docs/zh/commands/issue/issue-execute-cfd": {
"__comp": "17896441",
"content": "fe8e3dcf"
},
"/docs/commands/general/ccw-plan-9ae": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-general-ccw-plan-04-d-fe0"
"/docs/zh/commands/issue/issue-from-brainstorm-d2f": {
"__comp": "17896441",
"content": "2ecf8b4a"
},
"/docs/commands/general/ccw-test-e6f": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-general-ccw-testcce-912"
"/docs/zh/commands/issue/issue-new-7f9": {
"__comp": "17896441",
"content": "4ad7db0f"
},
"/docs/commands/general/codex-coordinator-e7d": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-general-codex-coordinatorf-92-1dc"
"/docs/zh/commands/issue/issue-plan-ed4": {
"__comp": "17896441",
"content": "a6c3df16"
},
"/docs/commands/general/flow-create-507": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-general-flow-createfab-98a"
"/docs/zh/commands/issue/issue-queue-a4b": {
"__comp": "17896441",
"content": "1bac9067"
},
"/docs/commands/issue/issue-convert-to-plan-a36": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-issue-issue-convert-to-plan-5-c-7-184"
"/docs/zh/commands/memory/memory-compact-8dc": {
"__comp": "17896441",
"content": "7a1ee27c"
},
"/docs/commands/issue/issue-discover-5ae": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-issue-issue-discover-1-e-3-569"
"/docs/zh/commands/memory/memory-docs-full-cli-1a7": {
"__comp": "17896441",
"content": "4cc74730"
},
"/docs/commands/issue/issue-execute-20b": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-issue-issue-executefe-8-c03"
"/docs/zh/commands/memory/memory-docs-related-cli-f28": {
"__comp": "17896441",
"content": "60eef997"
},
"/docs/commands/issue/issue-from-brainstorm-10c": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-issue-issue-from-brainstorm-2-ec-eeb"
"/docs/zh/commands/memory/memory-load-aee": {
"__comp": "17896441",
"content": "157db180"
},
"/docs/commands/issue/issue-new-abb": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-issue-issue-new-4-ad-3f0"
"/docs/zh/commands/memory/memory-update-full-2a1": {
"__comp": "17896441",
"content": "666bb1bf"
},
"/docs/commands/issue/issue-plan-57f": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-issue-issue-plana-6-c-fbd"
"/docs/zh/commands/memory/memory-update-related-991": {
"__comp": "17896441",
"content": "611877e1"
},
"/docs/commands/issue/issue-queue-316": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-issue-issue-queue-1-ba-55f"
"/docs/zh/faq-d6c": {
"__comp": "17896441",
"content": "2a5e3eff"
},
"/docs/commands/memory/memory-compact-fbd": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-memory-memory-compact-7-a-1-41c"
"/docs/zh/overview-2d1": {
"__comp": "17896441",
"content": "8a7e39ed"
},
"/docs/commands/memory/memory-docs-full-cli-8b8": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-memory-memory-docs-full-cli-4-cc-96f"
"/docs/zh/workflows/faq-319": {
"__comp": "17896441",
"content": "46f40178"
},
"/docs/commands/memory/memory-docs-related-cli-707": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-memory-memory-docs-related-cli-60-e-dd0"
"/docs/zh/workflows/introduction-dc8": {
"__comp": "17896441",
"content": "e5f6eee3"
},
"/docs/commands/memory/memory-load-1db": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-memory-memory-load-157-952"
"/docs/zh/workflows/level-1-ultra-lightweight-4d3": {
"__comp": "17896441",
"content": "9cf7cb6b"
},
"/docs/commands/memory/memory-update-full-3fa": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-memory-memory-update-full-666-002"
"/docs/zh/workflows/level-2-rapid-e2a": {
"__comp": "17896441",
"content": "05467734"
},
"/docs/commands/memory/memory-update-related-c50": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-commands-memory-memory-update-related-611-8d3"
"/docs/zh/workflows/level-3-standard-936": {
"__comp": "17896441",
"content": "3f1fe4a1"
},
"/docs/faq-296": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-faqea-3-888"
"/docs/zh/workflows/level-4-brainstorm-87d": {
"__comp": "17896441",
"content": "775938bf"
},
"/docs/overview-f90": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-overview-188-429"
"/docs/zh/workflows/level-5-intelligent-b09": {
"__comp": "17896441",
"content": "562bb8cb"
},
"/docs/workflows/faq-58c": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-workflows-faqbcf-045"
},
"/docs/workflows/introduction-702": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-workflows-introduction-9-f-4-275"
},
"/docs/workflows/level-1-ultra-lightweight-b4b": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-workflows-level-1-ultra-lightweightc-5-a-5db"
},
"/docs/workflows/level-2-rapid-fe1": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-workflows-level-2-rapid-19-b-095"
},
"/docs/workflows/level-3-standard-65f": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-workflows-level-3-standardbdb-61a"
},
"/docs/workflows/level-4-brainstorm-fae": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-workflows-level-4-brainstormd-04-14f"
},
"/docs/workflows/level-5-intelligent-fa9": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-workflows-level-5-intelligent-186-b05"
},
"/docs/-6df": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-4-ed-831"
"/docs/zh/-0e3": {
"__comp": "17896441",
"content": "6ab014e9"
}
}

View File

@@ -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": {

View File

@@ -56,6 +56,7 @@ interface NavGroupDef {
icon: React.ElementType;
badge?: number | string;
badgeVariant?: 'default' | 'success' | 'warning' | 'info';
end?: boolean;
}>;
}
@@ -110,7 +111,7 @@ const navGroupDefinitions: NavGroupDef[] = [
items: [
{ 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: '/settings', labelKey: 'navigation.main.settings', icon: Settings, end: true },
{ path: '/help', labelKey: 'navigation.main.help', icon: HelpCircle },
],
},

View File

@@ -115,6 +115,7 @@ export function CcwToolsMcpCard({
mutationFn: installCcwMcp,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: mcpServersKeys.all });
queryClient.invalidateQueries({ queryKey: ['ccwMcpConfig'] });
onInstall();
},
});
@@ -123,8 +124,12 @@ export function CcwToolsMcpCard({
mutationFn: uninstallCcwMcp,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: mcpServersKeys.all });
queryClient.invalidateQueries({ queryKey: ['ccwMcpConfig'] });
onInstall();
},
onError: (error) => {
console.error('Failed to uninstall CCW MCP:', error);
},
});
const updateConfigMutation = useMutation({

View File

@@ -27,6 +27,7 @@ import {
createMcpServer,
updateMcpServer,
fetchMcpServers,
saveMcpTemplate,
type McpServer,
type McpProjectConfigType,
} from '@/lib/api';
@@ -95,6 +96,7 @@ export function McpServerDialog({
const [argsInput, setArgsInput] = useState('');
const [envInput, setEnvInput] = useState('');
const [configType, setConfigType] = useState<McpConfigType>('mcp-json');
const [saveAsTemplate, setSaveAsTemplate] = useState(false);
const projectConfigType: McpProjectConfigType = configType === 'claude-json' ? 'claude' : 'mcp';
// Initialize form from server prop (edit mode)
@@ -128,6 +130,7 @@ export function McpServerDialog({
setEnvInput('');
}
setSelectedTemplate('');
setSaveAsTemplate(false);
setErrors({});
}, [server, mode, open]);
@@ -261,6 +264,23 @@ export function McpServerDialog({
return;
}
// Save as template if checked
if (saveAsTemplate) {
try {
await saveMcpTemplate({
name: formData.name,
category: 'custom',
serverConfig: {
command: formData.command,
args: formData.args.length > 0 ? formData.args : undefined,
env: Object.keys(formData.env).length > 0 ? formData.env : undefined,
},
});
} catch {
// Template save failure should not block server creation
}
}
if (mode === 'add') {
createMutation.mutate({
server: {
@@ -501,6 +521,20 @@ export function McpServerDialog({
{formatMessage({ id: 'mcp.dialog.form.enabled' })}
</label>
</div>
{/* Save as Template */}
<div className="flex items-center gap-2">
<input
type="checkbox"
id="save-as-template"
checked={saveAsTemplate}
onChange={(e) => setSaveAsTemplate(e.target.checked)}
className="w-4 h-4"
/>
<label htmlFor="save-as-template" className="text-sm font-medium text-foreground cursor-pointer">
{formatMessage({ id: 'mcp.templates.actions.saveAsTemplate' })}
</label>
</div>
</div>
<DialogFooter>

View File

@@ -58,17 +58,18 @@ import type { McpTemplate } from '@/types/store';
export interface McpTemplatesSectionProps {
/** Callback when template is installed (opens McpServerDialog) */
onInstallTemplate?: (template: McpTemplate) => void;
/** Callback when current server should be saved as template */
onSaveAsTemplate?: (serverName: string, config: { command: string; args: string[]; env?: Record<string, string> }) => void;
/** Callback when saving a new template */
onSaveAsTemplate?: (name: string, category: string, description: string, serverConfig: { command: string; args: string[]; env: Record<string, string> }) => void;
}
interface TemplateSaveDialogProps {
open: boolean;
onClose: () => void;
onSave: (name: string, category: string, description: string) => void;
onSave: (name: string, category: string, description: string, serverConfig: { command: string; args: string[]; env: Record<string, string> }) => void;
defaultName?: string;
defaultCommand?: string;
defaultArgs?: string[];
defaultEnv?: Record<string, string>;
}
interface TemplateCardProps {
@@ -181,18 +182,26 @@ function TemplateCard({ template, onInstall, onDelete, isInstalling, isDeleting
/**
* Template Save Dialog - Save current server configuration as template
*/
function TemplateSaveDialog({
export function TemplateSaveDialog({
open,
onClose,
onSave,
defaultName = '',
defaultCommand = '',
defaultArgs = [],
defaultEnv = {},
}: TemplateSaveDialogProps) {
const { formatMessage } = useIntl();
const [name, setName] = useState(defaultName);
const [category, setCategory] = useState('');
const [description, setDescription] = useState('');
const [errors, setErrors] = useState<{ name?: string }>({});
const [command, setCommand] = useState(defaultCommand);
const [argsInput, setArgsInput] = useState(defaultArgs.join(', '));
const [envInput, setEnvInput] = useState(
Object.entries(defaultEnv).map(([k, v]) => `${k}=${v}`).join('\n')
);
const [errors, setErrors] = useState<{ name?: string; command?: string }>({});
// Reset form when dialog opens
useEffect(() => {
@@ -200,25 +209,52 @@ function TemplateSaveDialog({
setName(defaultName || '');
setCategory('');
setDescription('');
setCommand(defaultCommand || '');
setArgsInput((defaultArgs || []).join(', '));
setEnvInput(
Object.entries(defaultEnv || {}).map(([k, v]) => `${k}=${v}`).join('\n')
);
setErrors({});
}
}, [open, defaultName]);
}, [open, defaultName, defaultCommand, defaultArgs, defaultEnv]);
const handleSave = () => {
const newErrors: { name?: string; command?: string } = {};
if (!name.trim()) {
setErrors({ name: formatMessage({ id: 'mcp.templates.saveDialog.validation.nameRequired' }) });
newErrors.name = formatMessage({ id: 'mcp.templates.saveDialog.validation.nameRequired' });
}
if (!command.trim()) {
newErrors.command = formatMessage({ id: 'mcp.dialog.validation.commandRequired' });
}
if (Object.keys(newErrors).length > 0) {
setErrors(newErrors);
return;
}
onSave(name.trim(), category.trim(), description.trim());
setName('');
setCategory('');
setDescription('');
setErrors({});
const args = argsInput
.split(',')
.map((a) => a.trim())
.filter((a) => a.length > 0);
const env: Record<string, string> = {};
for (const line of envInput.split('\n')) {
const trimmed = line.trim();
if (trimmed && trimmed.includes('=')) {
const [key, ...valParts] = trimmed.split('=');
if (key) env[key.trim()] = valParts.join('=').trim();
}
}
onSave(name.trim(), category.trim(), description.trim(), {
command: command.trim(),
args,
env,
});
};
return (
<Dialog open={open} onOpenChange={onClose}>
<DialogContent className="max-w-md">
<DialogContent className="max-w-md max-h-[85vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>
{formatMessage({ id: 'mcp.templates.saveDialog.title' })}
@@ -235,7 +271,7 @@ function TemplateSaveDialog({
value={name}
onChange={(e) => {
setName(e.target.value);
if (errors.name) setErrors({});
if (errors.name) setErrors((prev) => ({ ...prev, name: undefined }));
}}
placeholder={formatMessage({ id: 'mcp.templates.saveDialog.namePlaceholder' })}
error={!!errors.name}
@@ -245,6 +281,54 @@ function TemplateSaveDialog({
)}
</div>
{/* Command */}
<div className="space-y-2">
<label className="text-sm font-medium text-foreground">
{formatMessage({ id: 'mcp.dialog.form.command' })}
<span className="text-destructive ml-1">*</span>
</label>
<Input
value={command}
onChange={(e) => {
setCommand(e.target.value);
if (errors.command) setErrors((prev) => ({ ...prev, command: undefined }));
}}
placeholder={formatMessage({ id: 'mcp.dialog.form.commandPlaceholder' })}
error={!!errors.command}
/>
{errors.command && (
<p className="text-sm text-destructive">{errors.command}</p>
)}
</div>
{/* Args */}
<div className="space-y-2">
<label className="text-sm font-medium text-foreground">
{formatMessage({ id: 'mcp.dialog.form.args' })}
</label>
<Input
value={argsInput}
onChange={(e) => setArgsInput(e.target.value)}
placeholder={formatMessage({ id: 'mcp.dialog.form.argsPlaceholder' })}
/>
<p className="text-xs text-muted-foreground">
{formatMessage({ id: 'mcp.dialog.form.argsHint' })}
</p>
</div>
{/* Environment Variables */}
<div className="space-y-2">
<label className="text-sm font-medium text-foreground">
{formatMessage({ id: 'mcp.dialog.form.env' })}
</label>
<textarea
value={envInput}
onChange={(e) => setEnvInput(e.target.value)}
placeholder={formatMessage({ id: 'mcp.dialog.form.envPlaceholder' })}
className="flex min-h-[60px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm font-mono ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
</div>
{/* Category */}
<div className="space-y-2">
<label className="text-sm font-medium text-foreground">
@@ -273,7 +357,7 @@ function TemplateSaveDialog({
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder={formatMessage({ id: 'mcp.templates.saveDialog.descriptionPlaceholder' })}
className="flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
className="flex min-h-[60px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
</div>
</div>
@@ -374,8 +458,8 @@ export function McpTemplatesSection({ onInstallTemplate, onSaveAsTemplate }: Mcp
}
}, [templateToDelete, deleteMutation]);
const handleSaveTemplate = useCallback((_name: string, _category: string, _description: string) => {
onSaveAsTemplate?.(_name, { command: '', args: [] });
const handleSaveTemplate = useCallback((_name: string, _category: string, _description: string, _serverConfig: { command: string; args: string[]; env: Record<string, string> }) => {
onSaveAsTemplate?.(_name, _category, _description, _serverConfig);
setSaveDialogOpen(false);
}, [onSaveAsTemplate]);

View File

@@ -18,6 +18,8 @@ export interface NavItem {
icon: React.ElementType;
badge?: number | string;
badgeVariant?: 'default' | 'success' | 'warning' | 'info';
/** When true, only exact path match activates this item (no prefix matching) */
end?: boolean;
}
export interface NavGroupProps {
@@ -54,10 +56,10 @@ export function NavGroup({
{items.map((item) => {
const ItemIcon = item.icon;
const [basePath] = item.path.split('?');
// More precise matching: exact match or basePath followed by '/' to avoid parent/child conflicts
const isActive =
location.pathname === basePath ||
(basePath !== '/' && location.pathname.startsWith(basePath + '/'));
const isActive = item.end
? location.pathname === basePath
: location.pathname === basePath ||
(basePath !== '/' && location.pathname.startsWith(basePath + '/'));
return (
<NavLink
@@ -94,10 +96,10 @@ export function NavGroup({
{items.map((item) => {
const ItemIcon = item.icon;
const [basePath, searchParams] = item.path.split('?');
// More precise matching: exact match or basePath followed by '/' to avoid parent/child conflicts
const isActive =
location.pathname === basePath ||
(basePath !== '/' && location.pathname.startsWith(basePath + '/'));
const isActive = item.end
? location.pathname === basePath
: location.pathname === basePath ||
(basePath !== '/' && location.pathname.startsWith(basePath + '/'));
const isQueryParamActive =
searchParams && location.search.includes(searchParams);

View File

@@ -0,0 +1,406 @@
// ========================================
// Skill Create Dialog Component
// ========================================
// Modal dialog for creating/importing skills with two modes:
// - Import: import existing skill folder
// - CLI Generate: AI-generated skill from description
import { useState, useCallback } from 'react';
import { useIntl } from 'react-intl';
import {
Folder,
User,
FolderInput,
Sparkles,
CheckCircle,
XCircle,
Loader2,
Info,
} from 'lucide-react';
import {
Dialog,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
} from '@/components/ui/Dialog';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { Textarea } from '@/components/ui/Textarea';
import { Label } from '@/components/ui/Label';
import { validateSkillImport, createSkill } from '@/lib/api';
import { useWorkflowStore, selectProjectPath } from '@/stores/workflowStore';
import { cn } from '@/lib/utils';
export interface SkillCreateDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onCreated: () => void;
}
type CreateMode = 'import' | 'cli-generate';
type SkillLocation = 'project' | 'user';
interface ValidationResult {
valid: boolean;
errors?: string[];
skillInfo?: { name: string; description: string; version?: string; supportingFiles?: string[] };
}
export function SkillCreateDialog({ open, onOpenChange, onCreated }: SkillCreateDialogProps) {
const { formatMessage } = useIntl();
const projectPath = useWorkflowStore(selectProjectPath);
const [mode, setMode] = useState<CreateMode>('import');
const [location, setLocation] = useState<SkillLocation>('project');
// Import mode state
const [sourcePath, setSourcePath] = useState('');
const [customName, setCustomName] = useState('');
const [validationResult, setValidationResult] = useState<ValidationResult | null>(null);
const [isValidating, setIsValidating] = useState(false);
// CLI Generate mode state
const [skillName, setSkillName] = useState('');
const [description, setDescription] = useState('');
const [isCreating, setIsCreating] = useState(false);
const resetState = useCallback(() => {
setMode('import');
setLocation('project');
setSourcePath('');
setCustomName('');
setValidationResult(null);
setIsValidating(false);
setSkillName('');
setDescription('');
setIsCreating(false);
}, []);
const handleOpenChange = useCallback((open: boolean) => {
if (!open) {
resetState();
}
onOpenChange(open);
}, [onOpenChange, resetState]);
const handleValidate = useCallback(async () => {
if (!sourcePath.trim()) return;
setIsValidating(true);
setValidationResult(null);
try {
const result = await validateSkillImport(sourcePath.trim());
setValidationResult(result);
} catch (err) {
setValidationResult({
valid: false,
errors: [err instanceof Error ? err.message : String(err)],
});
} finally {
setIsValidating(false);
}
}, [sourcePath]);
const handleCreate = useCallback(async () => {
if (mode === 'import') {
if (!sourcePath.trim()) return;
if (!validationResult?.valid) return;
} else {
if (!skillName.trim()) return;
if (!description.trim()) return;
}
setIsCreating(true);
try {
await createSkill({
mode,
location,
sourcePath: mode === 'import' ? sourcePath.trim() : undefined,
skillName: mode === 'import' ? (customName.trim() || undefined) : skillName.trim(),
description: mode === 'cli-generate' ? description.trim() : undefined,
generationType: mode === 'cli-generate' ? 'description' : undefined,
projectPath,
});
handleOpenChange(false);
onCreated();
} catch (err) {
console.error('Failed to create skill:', err);
if (mode === 'import') {
setValidationResult({
valid: false,
errors: [err instanceof Error ? err.message : formatMessage({ id: 'skills.create.createError' })],
});
}
} finally {
setIsCreating(false);
}
}, [mode, location, sourcePath, customName, skillName, description, validationResult, projectPath, handleOpenChange, onCreated, formatMessage]);
const canCreate = mode === 'import'
? sourcePath.trim() && validationResult?.valid && !isCreating
: skillName.trim() && description.trim() && !isCreating;
return (
<Dialog open={open} onOpenChange={handleOpenChange}>
<DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>{formatMessage({ id: 'skills.create.title' })}</DialogTitle>
<DialogDescription>
{formatMessage({ id: 'skills.description' })}
</DialogDescription>
</DialogHeader>
<div className="space-y-5 py-2">
{/* Location Selection */}
<div className="space-y-2">
<Label>{formatMessage({ id: 'skills.create.location' })}</Label>
<div className="grid grid-cols-2 gap-3">
<button
type="button"
className={cn(
'px-4 py-3 text-left border-2 rounded-lg transition-all',
location === 'project'
? 'border-primary bg-primary/10'
: 'border-border hover:border-primary/50'
)}
onClick={() => setLocation('project')}
>
<div className="flex items-center gap-2">
<Folder className="w-5 h-5" />
<div>
<div className="font-medium text-sm">{formatMessage({ id: 'skills.create.locationProject' })}</div>
<div className="text-xs text-muted-foreground">{formatMessage({ id: 'skills.create.locationProjectHint' })}</div>
</div>
</div>
</button>
<button
type="button"
className={cn(
'px-4 py-3 text-left border-2 rounded-lg transition-all',
location === 'user'
? 'border-primary bg-primary/10'
: 'border-border hover:border-primary/50'
)}
onClick={() => setLocation('user')}
>
<div className="flex items-center gap-2">
<User className="w-5 h-5" />
<div>
<div className="font-medium text-sm">{formatMessage({ id: 'skills.create.locationUser' })}</div>
<div className="text-xs text-muted-foreground">{formatMessage({ id: 'skills.create.locationUserHint' })}</div>
</div>
</div>
</button>
</div>
</div>
{/* Mode Selection */}
<div className="space-y-2">
<Label>{formatMessage({ id: 'skills.create.mode' })}</Label>
<div className="grid grid-cols-2 gap-3">
<button
type="button"
className={cn(
'px-4 py-3 text-left border-2 rounded-lg transition-all',
mode === 'import'
? 'border-primary bg-primary/10'
: 'border-border hover:border-primary/50'
)}
onClick={() => setMode('import')}
>
<div className="flex items-center gap-2">
<FolderInput className="w-5 h-5" />
<div>
<div className="font-medium text-sm">{formatMessage({ id: 'skills.create.modeImport' })}</div>
<div className="text-xs text-muted-foreground">{formatMessage({ id: 'skills.create.modeImportHint' })}</div>
</div>
</div>
</button>
<button
type="button"
className={cn(
'px-4 py-3 text-left border-2 rounded-lg transition-all',
mode === 'cli-generate'
? 'border-primary bg-primary/10'
: 'border-border hover:border-primary/50'
)}
onClick={() => setMode('cli-generate')}
>
<div className="flex items-center gap-2">
<Sparkles className="w-5 h-5" />
<div>
<div className="font-medium text-sm">{formatMessage({ id: 'skills.create.modeGenerate' })}</div>
<div className="text-xs text-muted-foreground">{formatMessage({ id: 'skills.create.modeGenerateHint' })}</div>
</div>
</div>
</button>
</div>
</div>
{/* Import Mode Content */}
{mode === 'import' && (
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="sourcePath">{formatMessage({ id: 'skills.create.sourcePath' })}</Label>
<Input
id="sourcePath"
value={sourcePath}
onChange={(e) => {
setSourcePath(e.target.value);
setValidationResult(null);
}}
placeholder={formatMessage({ id: 'skills.create.sourcePathPlaceholder' })}
className="font-mono text-sm"
/>
<p className="text-xs text-muted-foreground">{formatMessage({ id: 'skills.create.sourcePathHint' })}</p>
</div>
<div className="space-y-2">
<Label htmlFor="customName">
{formatMessage({ id: 'skills.create.customName' })}
<span className="text-muted-foreground ml-1">({formatMessage({ id: 'skills.create.customNameHint' })})</span>
</Label>
<Input
id="customName"
value={customName}
onChange={(e) => setCustomName(e.target.value)}
placeholder={formatMessage({ id: 'skills.create.customNamePlaceholder' })}
/>
</div>
{/* Validation Result */}
{isValidating && (
<div className="flex items-center gap-2 p-3 bg-muted/50 rounded-lg">
<Loader2 className="w-4 h-4 animate-spin" />
<span className="text-sm text-muted-foreground">{formatMessage({ id: 'skills.create.validating' })}</span>
</div>
)}
{validationResult && !isValidating && (
validationResult.valid ? (
<div className="p-4 bg-green-500/10 border border-green-500/20 rounded-lg">
<div className="flex items-center gap-2 text-green-600 mb-2">
<CheckCircle className="w-5 h-5" />
<span className="font-medium">{formatMessage({ id: 'skills.create.validSkill' })}</span>
</div>
{validationResult.skillInfo && (
<div className="space-y-1 text-sm">
<div>
<span className="text-muted-foreground">{formatMessage({ id: 'skills.card.description' })}: </span>
<span>{validationResult.skillInfo.name}</span>
</div>
{validationResult.skillInfo.description && (
<div>
<span className="text-muted-foreground">{formatMessage({ id: 'skills.card.description' })}: </span>
<span>{validationResult.skillInfo.description}</span>
</div>
)}
{validationResult.skillInfo.version && (
<div>
<span className="text-muted-foreground">{formatMessage({ id: 'skills.card.version' })}: </span>
<span>{validationResult.skillInfo.version}</span>
</div>
)}
</div>
)}
</div>
) : (
<div className="p-4 bg-destructive/10 border border-destructive/20 rounded-lg">
<div className="flex items-center gap-2 text-destructive mb-2">
<XCircle className="w-5 h-5" />
<span className="font-medium">{formatMessage({ id: 'skills.create.invalidSkill' })}</span>
</div>
{validationResult.errors && (
<ul className="space-y-1 text-sm">
{validationResult.errors.map((error, i) => (
<li key={i} className="text-destructive">{error}</li>
))}
</ul>
)}
</div>
)
)}
</div>
)}
{/* CLI Generate Mode Content */}
{mode === 'cli-generate' && (
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="skillName">
{formatMessage({ id: 'skills.create.skillName' })} <span className="text-destructive">*</span>
</Label>
<Input
id="skillName"
value={skillName}
onChange={(e) => setSkillName(e.target.value)}
placeholder={formatMessage({ id: 'skills.create.skillNamePlaceholder' })}
/>
<p className="text-xs text-muted-foreground">{formatMessage({ id: 'skills.create.skillNameHint' })}</p>
</div>
<div className="space-y-2">
<Label htmlFor="description">
{formatMessage({ id: 'skills.create.descriptionLabel' })} <span className="text-destructive">*</span>
</Label>
<Textarea
id="description"
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder={formatMessage({ id: 'skills.create.descriptionPlaceholder' })}
rows={6}
/>
<p className="text-xs text-muted-foreground">{formatMessage({ id: 'skills.create.descriptionHint' })}</p>
</div>
<div className="p-3 bg-blue-500/10 border border-blue-500/20 rounded-lg">
<div className="flex items-start gap-2">
<Info className="w-4 h-4 text-blue-600 mt-0.5" />
<div className="text-sm text-blue-600">
<p className="font-medium">{formatMessage({ id: 'skills.create.generateInfo' })}</p>
<p className="text-xs mt-1">{formatMessage({ id: 'skills.create.generateTimeHint' })}</p>
</div>
</div>
</div>
</div>
)}
</div>
<DialogFooter className="gap-2">
<Button variant="outline" onClick={() => handleOpenChange(false)} disabled={isCreating}>
{formatMessage({ id: 'skills.actions.cancel' })}
</Button>
{mode === 'import' && (
<Button
variant="outline"
onClick={handleValidate}
disabled={!sourcePath.trim() || isValidating || isCreating}
>
{isValidating && <Loader2 className="w-4 h-4 mr-2 animate-spin" />}
{formatMessage({ id: 'skills.create.validate' })}
</Button>
)}
<Button
onClick={handleCreate}
disabled={!canCreate}
>
{isCreating && <Loader2 className="w-4 h-4 mr-2 animate-spin" />}
{isCreating
? formatMessage({ id: 'skills.create.creating' })
: mode === 'import'
? formatMessage({ id: 'skills.create.import' })
: formatMessage({ id: 'skills.create.generate' })
}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
export default SkillCreateDialog;

View File

@@ -19,6 +19,9 @@ export type { SkillCardProps } from './SkillCard';
export { SkillDetailPanel } from './SkillDetailPanel';
export type { SkillDetailPanelProps } from './SkillDetailPanel';
export { SkillCreateDialog } from './SkillCreateDialog';
export type { SkillCreateDialogProps } from './SkillCreateDialog';
export { StatCard, StatCardSkeleton } from './StatCard';
export type { StatCardProps } from './StatCard';

View File

@@ -196,6 +196,27 @@ export type {
UseRulesReturn,
} from './useCli';
// ========== System Settings ==========
export {
useChineseResponseStatus,
useToggleChineseResponse,
useWindowsPlatformStatus,
useToggleWindowsPlatform,
useCodexCliEnhancementStatus,
useToggleCodexCliEnhancement,
useRefreshCodexCliEnhancement,
useCcwInstallStatus,
useCliToolStatus,
systemSettingsKeys,
} from './useSystemSettings';
export type {
UseChineseResponseStatusReturn,
UseWindowsPlatformStatusReturn,
UseCodexCliEnhancementStatusReturn,
UseCcwInstallStatusReturn,
UseCliToolStatusReturn,
} from './useSystemSettings';
// ========== CLI Execution ==========
export {
useCliExecutionDetail,

View File

@@ -189,6 +189,7 @@ export function useDeleteMcpServer(): UseDeleteMcpServerReturn {
deleteMcpServer(serverName, scope, { projectPath: projectPath ?? undefined }),
onSettled: () => {
queryClient.invalidateQueries({ queryKey: mcpServersKeys.all });
queryClient.invalidateQueries({ queryKey: ['ccwMcpConfig'] });
},
});

View File

@@ -0,0 +1,238 @@
// ========================================
// useSystemSettings Hook
// ========================================
// TanStack Query hooks for system settings (language, install status, tool status)
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
fetchChineseResponseStatus,
toggleChineseResponse,
fetchWindowsPlatformStatus,
toggleWindowsPlatform,
fetchCodexCliEnhancementStatus,
toggleCodexCliEnhancement,
refreshCodexCliEnhancement,
fetchAggregatedStatus,
fetchCliToolStatus,
type ChineseResponseStatus,
type WindowsPlatformStatus,
type CodexCliEnhancementStatus,
type CcwInstallStatus,
} from '../lib/api';
// Query key factory
export const systemSettingsKeys = {
all: ['systemSettings'] as const,
chineseResponse: () => [...systemSettingsKeys.all, 'chineseResponse'] as const,
windowsPlatform: () => [...systemSettingsKeys.all, 'windowsPlatform'] as const,
codexCliEnhancement: () => [...systemSettingsKeys.all, 'codexCliEnhancement'] as const,
aggregatedStatus: () => [...systemSettingsKeys.all, 'aggregatedStatus'] as const,
cliToolStatus: () => [...systemSettingsKeys.all, 'cliToolStatus'] as const,
};
const STALE_TIME = 60 * 1000; // 1 minute
// ========================================
// Chinese Response Hooks
// ========================================
export interface UseChineseResponseStatusReturn {
data: ChineseResponseStatus | undefined;
isLoading: boolean;
error: Error | null;
refetch: () => void;
}
export function useChineseResponseStatus(): UseChineseResponseStatusReturn {
const query = useQuery({
queryKey: systemSettingsKeys.chineseResponse(),
queryFn: fetchChineseResponseStatus,
staleTime: STALE_TIME,
retry: 1,
});
return {
data: query.data,
isLoading: query.isLoading,
error: query.error,
refetch: () => { query.refetch(); },
};
}
export function useToggleChineseResponse() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: ({ enabled, target }: { enabled: boolean; target: 'claude' | 'codex' }) =>
toggleChineseResponse(enabled, target),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: systemSettingsKeys.chineseResponse() });
},
});
return {
toggle: (enabled: boolean, target: 'claude' | 'codex') =>
mutation.mutateAsync({ enabled, target }),
isPending: mutation.isPending,
error: mutation.error,
};
}
// ========================================
// Windows Platform Hooks
// ========================================
export interface UseWindowsPlatformStatusReturn {
data: WindowsPlatformStatus | undefined;
isLoading: boolean;
error: Error | null;
refetch: () => void;
}
export function useWindowsPlatformStatus(): UseWindowsPlatformStatusReturn {
const query = useQuery({
queryKey: systemSettingsKeys.windowsPlatform(),
queryFn: fetchWindowsPlatformStatus,
staleTime: STALE_TIME,
retry: 1,
});
return {
data: query.data,
isLoading: query.isLoading,
error: query.error,
refetch: () => { query.refetch(); },
};
}
export function useToggleWindowsPlatform() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (enabled: boolean) => toggleWindowsPlatform(enabled),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: systemSettingsKeys.windowsPlatform() });
},
});
return {
toggle: mutation.mutateAsync,
isPending: mutation.isPending,
error: mutation.error,
};
}
// ========================================
// Codex CLI Enhancement Hooks
// ========================================
export interface UseCodexCliEnhancementStatusReturn {
data: CodexCliEnhancementStatus | undefined;
isLoading: boolean;
error: Error | null;
refetch: () => void;
}
export function useCodexCliEnhancementStatus(): UseCodexCliEnhancementStatusReturn {
const query = useQuery({
queryKey: systemSettingsKeys.codexCliEnhancement(),
queryFn: fetchCodexCliEnhancementStatus,
staleTime: STALE_TIME,
retry: 1,
});
return {
data: query.data,
isLoading: query.isLoading,
error: query.error,
refetch: () => { query.refetch(); },
};
}
export function useToggleCodexCliEnhancement() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (enabled: boolean) => toggleCodexCliEnhancement(enabled),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: systemSettingsKeys.codexCliEnhancement() });
},
});
return {
toggle: mutation.mutateAsync,
isPending: mutation.isPending,
error: mutation.error,
};
}
export function useRefreshCodexCliEnhancement() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: () => refreshCodexCliEnhancement(),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: systemSettingsKeys.codexCliEnhancement() });
},
});
return {
refresh: mutation.mutateAsync,
isPending: mutation.isPending,
error: mutation.error,
};
}
// ========================================
// Aggregated Status / CCW Install Hooks
// ========================================
export interface UseCcwInstallStatusReturn {
data: CcwInstallStatus | undefined;
isLoading: boolean;
error: Error | null;
refetch: () => void;
}
export function useCcwInstallStatus(): UseCcwInstallStatusReturn {
const query = useQuery({
queryKey: systemSettingsKeys.aggregatedStatus(),
queryFn: fetchAggregatedStatus,
staleTime: 5 * 60 * 1000, // 5 minutes
retry: 1,
});
return {
data: query.data?.ccwInstall,
isLoading: query.isLoading,
error: query.error,
refetch: () => { query.refetch(); },
};
}
// ========================================
// CLI Tool Status Hooks
// ========================================
export interface UseCliToolStatusReturn {
data: Record<string, { available: boolean; path?: string; version?: string }> | undefined;
isLoading: boolean;
error: Error | null;
refetch: () => void;
}
export function useCliToolStatus(): UseCliToolStatusReturn {
const query = useQuery({
queryKey: systemSettingsKeys.cliToolStatus(),
queryFn: fetchCliToolStatus,
staleTime: 2 * 60 * 1000, // 2 minutes
retry: 1,
});
return {
data: query.data,
isLoading: query.isLoading,
error: query.error,
refetch: () => { query.refetch(); },
};
}

View File

@@ -993,22 +993,36 @@ export interface SkillsResponse {
* @param projectPath - Optional project path to filter data by workspace
*/
export async function fetchSkills(projectPath?: string): Promise<SkillsResponse> {
// Response type from backend when includeDisabled=true
interface ExtendedSkillsResponse {
skills?: Skill[];
projectSkills?: Skill[];
userSkills?: Skill[];
disabledProjectSkills?: Skill[];
disabledUserSkills?: Skill[];
}
// Helper to add location and enabled status to skills
// Backend only returns enabled skills (with SKILL.md), so we set enabled: true
const addMetadata = (skills: Skill[], location: 'project' | 'user'): Skill[] =>
const addEnabledMetadata = (skills: Skill[], location: 'project' | 'user'): Skill[] =>
skills.map(skill => ({ ...skill, location, enabled: true }));
const addDisabledMetadata = (skills: Skill[], location: 'project' | 'user'): Skill[] =>
skills.map(skill => ({ ...skill, location, enabled: false }));
const buildSkillsList = (data: ExtendedSkillsResponse): Skill[] => {
const projectSkillsEnabled = addEnabledMetadata(data.projectSkills ?? [], 'project');
const userSkillsEnabled = addEnabledMetadata(data.userSkills ?? [], 'user');
const projectSkillsDisabled = addDisabledMetadata(data.disabledProjectSkills ?? [], 'project');
const userSkillsDisabled = addDisabledMetadata(data.disabledUserSkills ?? [], 'user');
return [...projectSkillsEnabled, ...userSkillsEnabled, ...projectSkillsDisabled, ...userSkillsDisabled];
};
// Try with project path first, fall back to global on 403/404
if (projectPath) {
try {
const url = `/api/skills?path=${encodeURIComponent(projectPath)}`;
const data = await fetchApi<{ skills?: Skill[]; projectSkills?: Skill[]; userSkills?: Skill[] }>(url);
const projectSkillsWithMetadata = addMetadata(data.projectSkills ?? [], 'project');
const userSkillsWithMetadata = addMetadata(data.userSkills ?? [], 'user');
const allSkills = [...projectSkillsWithMetadata, ...userSkillsWithMetadata];
return {
skills: data.skills ?? allSkills,
};
const url = `/api/skills?path=${encodeURIComponent(projectPath)}&includeDisabled=true`;
const data = await fetchApi<ExtendedSkillsResponse>(url);
return { skills: buildSkillsList(data) };
} catch (error: unknown) {
const apiError = error as ApiError;
if (apiError.status === 403 || apiError.status === 404) {
@@ -1020,13 +1034,8 @@ export async function fetchSkills(projectPath?: string): Promise<SkillsResponse>
}
}
// Fallback: fetch global skills
const data = await fetchApi<{ skills?: Skill[]; projectSkills?: Skill[]; userSkills?: Skill[] }>('/api/skills');
const projectSkillsWithMetadata = addMetadata(data.projectSkills ?? [], 'project');
const userSkillsWithMetadata = addMetadata(data.userSkills ?? [], 'user');
const allSkills = [...projectSkillsWithMetadata, ...userSkillsWithMetadata];
return {
skills: data.skills ?? allSkills,
};
const data = await fetchApi<ExtendedSkillsResponse>('/api/skills?includeDisabled=true');
return { skills: buildSkillsList(data) };
}
/**
@@ -1074,6 +1083,38 @@ export async function fetchSkillDetail(
return fetchApi<{ skill: Skill }>(url);
}
/**
* Validate a skill folder for import
*/
export async function validateSkillImport(sourcePath: string): Promise<{
valid: boolean;
errors?: string[];
skillInfo?: { name: string; description: string; version?: string; supportingFiles?: string[] };
}> {
return fetchApi('/api/skills/validate-import', {
method: 'POST',
body: JSON.stringify({ sourcePath }),
});
}
/**
* Create/import a skill
*/
export async function createSkill(params: {
mode: 'import' | 'cli-generate';
location: 'project' | 'user';
sourcePath?: string;
skillName?: string;
description?: string;
generationType?: 'description' | 'template';
projectPath?: string;
}): Promise<{ skillName: string; path: string }> {
return fetchApi('/api/skills/create', {
method: 'POST',
body: JSON.stringify(params),
});
}
// ========== Commands API ==========
export interface Command {
@@ -5062,3 +5103,142 @@ export async function fetchExecutionLogs(
const queryString = params.toString();
return fetchApi(`/api/orchestrator/executions/${encodeURIComponent(execId)}/logs${queryString ? `?${queryString}` : ''}`);
}
// ========== System Settings API ==========
/**
* Chinese response setting status
*/
export interface ChineseResponseStatus {
enabled: boolean;
claudeEnabled: boolean;
codexEnabled: boolean;
codexNeedsMigration: boolean;
guidelinesPath: string;
guidelinesExists: boolean;
userClaudeMdExists: boolean;
userCodexAgentsExists: boolean;
}
/**
* Fetch Chinese response setting status
*/
export async function fetchChineseResponseStatus(): Promise<ChineseResponseStatus> {
return fetchApi('/api/language/chinese-response');
}
/**
* Toggle Chinese response setting
*/
export async function toggleChineseResponse(
enabled: boolean,
target: 'claude' | 'codex' = 'claude'
): Promise<{ success: boolean; enabled: boolean; target: string }> {
return fetchApi('/api/language/chinese-response', {
method: 'POST',
body: JSON.stringify({ enabled, target }),
});
}
/**
* Windows platform setting status
*/
export interface WindowsPlatformStatus {
enabled: boolean;
guidelinesPath: string;
guidelinesExists: boolean;
userClaudeMdExists: boolean;
}
/**
* Fetch Windows platform setting status
*/
export async function fetchWindowsPlatformStatus(): Promise<WindowsPlatformStatus> {
return fetchApi('/api/language/windows-platform');
}
/**
* Toggle Windows platform setting
*/
export async function toggleWindowsPlatform(
enabled: boolean
): Promise<{ success: boolean; enabled: boolean }> {
return fetchApi('/api/language/windows-platform', {
method: 'POST',
body: JSON.stringify({ enabled }),
});
}
/**
* Codex CLI Enhancement setting status
*/
export interface CodexCliEnhancementStatus {
enabled: boolean;
guidelinesPath: string;
guidelinesExists: boolean;
userCodexAgentsExists: boolean;
}
/**
* Fetch Codex CLI Enhancement setting status
*/
export async function fetchCodexCliEnhancementStatus(): Promise<CodexCliEnhancementStatus> {
return fetchApi('/api/language/codex-cli-enhancement');
}
/**
* Toggle Codex CLI Enhancement setting
*/
export async function toggleCodexCliEnhancement(
enabled: boolean
): Promise<{ success: boolean; enabled: boolean }> {
return fetchApi('/api/language/codex-cli-enhancement', {
method: 'POST',
body: JSON.stringify({ enabled }),
});
}
/**
* Refresh Codex CLI Enhancement content
*/
export async function refreshCodexCliEnhancement(): Promise<{ success: boolean; refreshed: boolean }> {
return fetchApi('/api/language/codex-cli-enhancement', {
method: 'POST',
body: JSON.stringify({ action: 'refresh' }),
});
}
/**
* CCW Install status
*/
export interface CcwInstallStatus {
installed: boolean;
workflowsInstalled: boolean;
missingFiles: string[];
installPath: string;
}
/**
* Aggregated status response
*/
export interface AggregatedStatus {
cli: Record<string, { available: boolean; path?: string; version?: string }>;
codexLens: { ready: boolean };
semantic: { available: boolean; backend: string | null };
ccwInstall: CcwInstallStatus;
timestamp: string;
}
/**
* Fetch aggregated system status (includes CCW install status)
*/
export async function fetchAggregatedStatus(): Promise<AggregatedStatus> {
return fetchApi('/api/status/all');
}
/**
* Fetch CLI tool availability status
*/
export async function fetchCliToolStatus(): Promise<Record<string, { available: boolean; path?: string; version?: string }>> {
return fetchApi('/api/cli/status');
}

View File

@@ -6,6 +6,8 @@
"cliTools": "CLI Tools",
"display": "Display Settings",
"language": "Language",
"responseLanguage": "Response Language",
"systemStatus": "System Status",
"hooks": "Git Hooks",
"rules": "Rules",
"about": "About"
@@ -48,6 +50,35 @@
"displayLanguage": "Display Language",
"chooseLanguage": "Choose your preferred language for the interface"
},
"responseLanguage": {
"title": "Response Language Settings",
"chineseClaude": "Chinese Response",
"chineseClaudeDesc": "Enable Chinese response guidelines in ~/.claude/CLAUDE.md",
"chineseCodex": "Chinese Response",
"chineseCodexDesc": "Enable Chinese response guidelines in ~/.codex/AGENTS.md",
"windowsPlatform": "Windows Platform",
"windowsPlatformDesc": "Enable Windows path format conventions in global CLAUDE.md",
"cliEnhancement": "CLI Enhancement",
"cliEnhancementDesc": "Enable multi-CLI tool invocation for Codex",
"cliEnhancementHint": "After config changes, click refresh to update content",
"refreshConfig": "Refresh Config",
"migrationWarning": "Old format detected, please disable and re-enable to migrate",
"enabled": "Enabled",
"disabled": "Disabled"
},
"systemStatus": {
"title": "System Status",
"ccwInstall": "CCW Installation",
"installed": "Installed",
"incomplete": "Incomplete",
"notInstalled": "Not Installed",
"missingFiles": "Missing Files",
"runToFix": "Run to fix",
"toolStatus": "Tool Availability",
"available": "Available",
"unavailable": "Unavailable",
"checking": "Checking..."
},
"dataRefresh": {
"title": "Data Refresh",
"autoRefresh": "Auto Refresh",

View File

@@ -65,5 +65,45 @@
"emptyState": {
"title": "No Skills Found",
"message": "No skills match your current filter."
},
"create": {
"title": "Create Skill",
"location": "Location",
"locationProject": "Project Skills",
"locationProjectHint": ".claude/skills/",
"locationUser": "Global Skills",
"locationUserHint": "~/.claude/skills/",
"mode": "Creation Mode",
"modeImport": "Import Folder",
"modeImportHint": "Import skill from existing folder",
"modeGenerate": "AI Generate",
"modeGenerateHint": "Generate skill using AI",
"sourcePath": "Source Folder Path",
"sourcePathPlaceholder": "Enter absolute path to skill folder",
"sourcePathHint": "Folder must contain a SKILL.md file",
"customName": "Custom Name",
"customNamePlaceholder": "Leave empty to use original name",
"customNameHint": "Optional, overrides default skill name",
"skillName": "Skill Name",
"skillNamePlaceholder": "Enter skill name",
"skillNameHint": "Used as the skill folder name",
"descriptionLabel": "Skill Description",
"descriptionPlaceholder": "Describe what this skill should do...",
"descriptionHint": "AI will generate skill content based on this description",
"generateInfo": "AI will use CLI tools to generate the skill",
"generateTimeHint": "Generation may take some time",
"validate": "Validate",
"import": "Import",
"generate": "Generate",
"validating": "Validating...",
"validSkill": "Validation passed",
"invalidSkill": "Validation failed",
"creating": "Creating...",
"created": "Skill \"{name}\" created successfully",
"createError": "Failed to create skill",
"sourcePathRequired": "Please enter source folder path",
"skillNameRequired": "Please enter skill name",
"descriptionRequired": "Please enter skill description",
"validateFirst": "Please validate the skill folder first"
}
}

View File

@@ -6,6 +6,8 @@
"cliTools": "CLI 工具",
"display": "显示设置",
"language": "语言",
"responseLanguage": "回复语言设置",
"systemStatus": "系统状态",
"hooks": "Git 钩子",
"rules": "规则",
"about": "关于"
@@ -48,6 +50,35 @@
"displayLanguage": "显示语言",
"chooseLanguage": "选择界面的首选语言"
},
"responseLanguage": {
"title": "回复语言设置",
"chineseClaude": "中文回复",
"chineseClaudeDesc": "在 ~/.claude/CLAUDE.md 中启用中文回复准则",
"chineseCodex": "中文回复",
"chineseCodexDesc": "在 ~/.codex/AGENTS.md 中启用中文回复准则",
"windowsPlatform": "Windows 平台规范",
"windowsPlatformDesc": "在全局 CLAUDE.md 中启用 Windows 路径格式规范",
"cliEnhancement": "CLI 调用增强",
"cliEnhancementDesc": "为 Codex 启用多 CLI 工具调用功能",
"cliEnhancementHint": "配置文件变更后,点击刷新按钮更新内容",
"refreshConfig": "刷新配置",
"migrationWarning": "检测到旧格式,请关闭后重新启用以迁移",
"enabled": "已启用",
"disabled": "已禁用"
},
"systemStatus": {
"title": "系统状态",
"ccwInstall": "CCW 安装状态",
"installed": "已安装",
"incomplete": "不完整",
"notInstalled": "未安装",
"missingFiles": "缺失文件",
"runToFix": "运行以下命令修复",
"toolStatus": "工具可用性",
"available": "可用",
"unavailable": "不可用",
"checking": "检测中..."
},
"dataRefresh": {
"title": "数据刷新",
"autoRefresh": "自动刷新",

View File

@@ -65,5 +65,45 @@
"emptyState": {
"title": "未找到技能",
"message": "没有符合当前筛选条件的技能。"
},
"create": {
"title": "创建技能",
"location": "存储位置",
"locationProject": "项目技能",
"locationProjectHint": ".claude/skills/",
"locationUser": "全局技能",
"locationUserHint": "~/.claude/skills/",
"mode": "创建方式",
"modeImport": "导入文件夹",
"modeImportHint": "从现有文件夹导入技能",
"modeGenerate": "AI 生成",
"modeGenerateHint": "使用 AI 生成技能",
"sourcePath": "源文件夹路径",
"sourcePathPlaceholder": "输入技能文件夹的绝对路径",
"sourcePathHint": "文件夹中需要包含 SKILL.md 文件",
"customName": "自定义名称",
"customNamePlaceholder": "留空则使用原始名称",
"customNameHint": "可选,用于覆盖默认技能名称",
"skillName": "技能名称",
"skillNamePlaceholder": "输入技能名称",
"skillNameHint": "用作技能文件夹名称",
"descriptionLabel": "技能描述",
"descriptionPlaceholder": "描述这个技能应该做什么...",
"descriptionHint": "AI 将根据描述生成技能内容",
"generateInfo": "AI 将使用 CLI 工具生成技能",
"generateTimeHint": "生成过程可能需要一些时间",
"validate": "验证",
"import": "导入",
"generate": "生成",
"validating": "验证中...",
"validSkill": "验证通过",
"invalidSkill": "验证失败",
"creating": "创建中...",
"created": "技能 \"{name}\" 创建成功",
"createError": "创建技能失败",
"sourcePathRequired": "请输入源文件夹路径",
"skillNameRequired": "请输入技能名称",
"descriptionRequired": "请输入技能描述",
"validateFirst": "请先验证技能文件夹"
}
}

View File

@@ -20,6 +20,7 @@ import {
Trash2,
ChevronDown,
ChevronUp,
BookmarkPlus,
} from 'lucide-react';
import { Card } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
@@ -29,20 +30,21 @@ import { McpServerDialog } from '@/components/mcp/McpServerDialog';
import { CliModeToggle, type CliMode } from '@/components/mcp/CliModeToggle';
import { CodexMcpEditableCard } from '@/components/mcp/CodexMcpEditableCard';
import { CcwToolsMcpCard } from '@/components/mcp/CcwToolsMcpCard';
import { McpTemplatesSection } from '@/components/mcp/McpTemplatesSection';
import { McpTemplatesSection, TemplateSaveDialog } from '@/components/mcp/McpTemplatesSection';
import { RecommendedMcpSection } from '@/components/mcp/RecommendedMcpSection';
import { WindowsCompatibilityWarning } from '@/components/mcp/WindowsCompatibilityWarning';
import { CrossCliCopyButton } from '@/components/mcp/CrossCliCopyButton';
import { AllProjectsTable } from '@/components/mcp/AllProjectsTable';
import { OtherProjectsSection } from '@/components/mcp/OtherProjectsSection';
import { TabsNavigation } from '@/components/ui/TabsNavigation';
import { useMcpServers, useMcpServerMutations } from '@/hooks';
import { useMcpServers, useMcpServerMutations, useNotifications } from '@/hooks';
import {
fetchCodexMcpServers,
fetchCcwMcpConfig,
updateCcwConfig,
codexRemoveServer,
codexToggleServer,
saveMcpTemplate,
type McpServer,
type CcwMcpConfig,
} from '@/lib/api';
@@ -57,9 +59,10 @@ interface McpServerCardProps {
onToggle: (serverName: string, enabled: boolean) => void;
onEdit: (server: McpServer) => void;
onDelete: (server: McpServer) => void;
onSaveAsTemplate: (server: McpServer) => void;
}
function McpServerCard({ server, isExpanded, onToggleExpand, onToggle, onEdit, onDelete }: McpServerCardProps) {
function McpServerCard({ server, isExpanded, onToggleExpand, onToggle, onEdit, onDelete, onSaveAsTemplate }: McpServerCardProps) {
const { formatMessage } = useIntl();
return (
@@ -115,6 +118,18 @@ function McpServerCard({ server, isExpanded, onToggleExpand, onToggle, onEdit, o
>
{server.enabled ? <Power className="w-4 h-4 text-green-600" /> : <PowerOff className="w-4 h-4" />}
</Button>
<Button
variant="ghost"
size="sm"
className="h-8 w-8 p-0"
onClick={(e) => {
e.stopPropagation();
onSaveAsTemplate(server);
}}
title={formatMessage({ id: 'mcp.templates.actions.saveAsTemplate' })}
>
<BookmarkPlus className="w-4 h-4 text-primary" />
</Button>
<Button
variant="ghost"
size="sm"
@@ -206,6 +221,10 @@ export function McpManagerPage() {
const [editingServer, setEditingServer] = useState<McpServer | undefined>(undefined);
const [cliMode, setCliMode] = useState<CliMode>('claude');
const [codexExpandedServers, setCodexExpandedServers] = useState<Set<string>>(new Set());
const [saveTemplateDialogOpen, setSaveTemplateDialogOpen] = useState(false);
const [serverToSaveAsTemplate, setServerToSaveAsTemplate] = useState<McpServer | undefined>(undefined);
const notifications = useNotifications();
const {
servers,
@@ -269,9 +288,22 @@ export function McpManagerPage() {
toggleServer(serverName, enabled);
};
const handleDelete = (server: McpServer) => {
const handleDelete = async (server: McpServer) => {
if (confirm(formatMessage({ id: 'mcp.deleteConfirm' }, { name: server.name }))) {
deleteServer(server.name, server.scope);
try {
await deleteServer(server.name, server.scope);
notifications.success(
formatMessage({ id: 'mcp.actions.delete' }),
server.name
);
refetch();
} catch (error) {
console.error('Failed to delete MCP server:', error);
notifications.error(
formatMessage({ id: 'mcp.actions.delete' }),
error instanceof Error ? error.message : String(error)
);
}
}
};
@@ -339,19 +371,64 @@ export function McpManagerPage() {
setDialogOpen(true);
};
const handleSaveAsTemplate = (serverName: string, config: { command: string; args: string[] }) => {
// This would open a dialog to save current server as template
// For now, just log it
console.log('Save as template:', serverName, config);
const handleSaveServerAsTemplate = (server: McpServer) => {
setServerToSaveAsTemplate(server);
setSaveTemplateDialogOpen(true);
};
const handleSaveAsTemplate = async (
name: string,
category: string,
description: string,
serverConfig: { command: string; args: string[]; env: Record<string, string> },
) => {
try {
const result = await saveMcpTemplate({
name,
description: description || undefined,
category: category || 'custom',
serverConfig: {
command: serverConfig.command,
args: serverConfig.args.length > 0 ? serverConfig.args : undefined,
env: Object.keys(serverConfig.env).length > 0 ? serverConfig.env : undefined,
},
});
if (result.success) {
notifications.success(
formatMessage({ id: 'mcp.templates.feedback.saveSuccess' }),
name
);
setSaveTemplateDialogOpen(false);
setServerToSaveAsTemplate(undefined);
} else {
notifications.error(
formatMessage({ id: 'mcp.templates.feedback.saveError' }),
result.error || ''
);
}
} catch (error) {
notifications.error(
formatMessage({ id: 'mcp.templates.feedback.saveError' }),
error instanceof Error ? error.message : String(error)
);
}
};
// Codex MCP handlers
const handleCodexRemove = async (serverName: string) => {
try {
await codexRemoveServer(serverName);
notifications.success(
formatMessage({ id: 'mcp.actions.delete' }),
serverName
);
codexQuery.refetch();
} catch (error) {
console.error('Failed to remove Codex MCP server:', error);
notifications.error(
formatMessage({ id: 'mcp.actions.delete' }),
error instanceof Error ? error.message : String(error)
);
}
};
@@ -592,6 +669,7 @@ export function McpManagerPage() {
onToggle={handleToggle}
onEdit={handleEdit}
onDelete={handleDelete}
onSaveAsTemplate={handleSaveServerAsTemplate}
/>
)
))}
@@ -646,6 +724,20 @@ export function McpManagerPage() {
onSave={handleDialogSave}
/>
)}
{/* Save as Template Dialog */}
<TemplateSaveDialog
open={saveTemplateDialogOpen}
onClose={() => {
setSaveTemplateDialogOpen(false);
setServerToSaveAsTemplate(undefined);
}}
onSave={handleSaveAsTemplate}
defaultName={serverToSaveAsTemplate?.name}
defaultCommand={serverToSaveAsTemplate?.command}
defaultArgs={serverToSaveAsTemplate?.args}
defaultEnv={serverToSaveAsTemplate?.env as Record<string, string>}
/>
</div>
);
}

View File

@@ -18,6 +18,10 @@ import {
ChevronUp,
Languages,
Plus,
MessageSquareText,
Monitor,
Terminal,
AlertTriangle,
} from 'lucide-react';
import { Card } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
@@ -29,6 +33,17 @@ import { useConfigStore, selectCliTools, selectDefaultCliTool, selectUserPrefere
import type { CliToolConfig, UserPreferences } from '@/types/store';
import { cn } from '@/lib/utils';
import { LanguageSwitcher } from '@/components/layout/LanguageSwitcher';
import {
useChineseResponseStatus,
useToggleChineseResponse,
useWindowsPlatformStatus,
useToggleWindowsPlatform,
useCodexCliEnhancementStatus,
useToggleCodexCliEnhancement,
useRefreshCodexCliEnhancement,
useCcwInstallStatus,
useCliToolStatus,
} from '@/hooks/useSystemSettings';
// ========== CLI Tool Card Component ==========
@@ -37,6 +52,7 @@ interface CliToolCardProps {
config: CliToolConfig;
isDefault: boolean;
isExpanded: boolean;
toolAvailable?: boolean;
onToggleExpand: () => void;
onToggleEnabled: () => void;
onSetDefault: () => void;
@@ -51,6 +67,7 @@ function CliToolCard({
config,
isDefault,
isExpanded,
toolAvailable,
onToggleExpand,
onToggleEnabled,
onSetDefault,
@@ -125,6 +142,12 @@ function CliToolCard({
<Badge variant="default" className="text-xs">{formatMessage({ id: 'settings.cliTools.default' })}</Badge>
)}
<Badge variant="outline" className="text-xs">{config.type}</Badge>
{toolAvailable !== undefined && (
<span className={cn(
'inline-block w-2 h-2 rounded-full',
toolAvailable ? 'bg-green-500' : 'bg-red-400'
)} title={toolAvailable ? 'Available' : 'Unavailable'} />
)}
</div>
<p className="text-xs text-muted-foreground mt-0.5">
{config.primaryModel}
@@ -345,6 +368,266 @@ function CliToolCard({
);
}
// ========== Response Language Section ==========
function ResponseLanguageSection() {
const { formatMessage } = useIntl();
const { data: chineseStatus, isLoading: chineseLoading } = useChineseResponseStatus();
const { toggle: toggleChinese, isPending: chineseToggling } = useToggleChineseResponse();
const { data: windowsStatus, isLoading: windowsLoading } = useWindowsPlatformStatus();
const { toggle: toggleWindows, isPending: windowsToggling } = useToggleWindowsPlatform();
const { data: cliEnhStatus, isLoading: cliEnhLoading } = useCodexCliEnhancementStatus();
const { toggle: toggleCliEnh, isPending: cliEnhToggling } = useToggleCodexCliEnhancement();
const { refresh: refreshCliEnh, isPending: refreshing } = useRefreshCodexCliEnhancement();
return (
<Card className="p-6">
<h2 className="text-lg font-semibold text-foreground flex items-center gap-2 mb-4">
<MessageSquareText className="w-5 h-5" />
{formatMessage({ id: 'settings.sections.responseLanguage' })}
</h2>
<div className="grid gap-4 md:grid-cols-2">
{/* Chinese Response - Claude */}
<div className="rounded-lg border border-border p-4 space-y-2">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<span className="text-sm font-medium">{formatMessage({ id: 'settings.responseLanguage.chineseClaude' })}</span>
<Badge variant="default" className="text-xs">Claude</Badge>
</div>
<Button
variant={chineseStatus?.claudeEnabled ? 'default' : 'outline'}
size="sm"
className="h-7"
disabled={chineseLoading || chineseToggling}
onClick={() => toggleChinese(!chineseStatus?.claudeEnabled, 'claude')}
>
{chineseStatus?.claudeEnabled
? formatMessage({ id: 'settings.responseLanguage.enabled' })
: formatMessage({ id: 'settings.responseLanguage.disabled' })}
</Button>
</div>
<p className="text-xs text-muted-foreground">
{formatMessage({ id: 'settings.responseLanguage.chineseClaudeDesc' })}
</p>
</div>
{/* Chinese Response - Codex */}
<div className="rounded-lg border border-border p-4 space-y-2">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<span className="text-sm font-medium">{formatMessage({ id: 'settings.responseLanguage.chineseCodex' })}</span>
<Badge variant="secondary" className="text-xs">Codex</Badge>
</div>
<Button
variant={chineseStatus?.codexEnabled ? 'default' : 'outline'}
size="sm"
className="h-7"
disabled={chineseLoading || chineseToggling}
onClick={() => toggleChinese(!chineseStatus?.codexEnabled, 'codex')}
>
{chineseStatus?.codexEnabled
? formatMessage({ id: 'settings.responseLanguage.enabled' })
: formatMessage({ id: 'settings.responseLanguage.disabled' })}
</Button>
</div>
<p className="text-xs text-muted-foreground">
{formatMessage({ id: 'settings.responseLanguage.chineseCodexDesc' })}
</p>
{chineseStatus?.codexNeedsMigration && (
<p className="text-xs text-yellow-500">
<AlertTriangle className="w-3 h-3 inline mr-1" />
{formatMessage({ id: 'settings.responseLanguage.migrationWarning' })}
</p>
)}
</div>
{/* Windows Platform */}
<div className="rounded-lg border border-border p-4 space-y-2">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Monitor className="w-4 h-4 text-muted-foreground" />
<span className="text-sm font-medium">{formatMessage({ id: 'settings.responseLanguage.windowsPlatform' })}</span>
</div>
<Button
variant={windowsStatus?.enabled ? 'default' : 'outline'}
size="sm"
className="h-7"
disabled={windowsLoading || windowsToggling}
onClick={() => toggleWindows(!windowsStatus?.enabled)}
>
{windowsStatus?.enabled
? formatMessage({ id: 'settings.responseLanguage.enabled' })
: formatMessage({ id: 'settings.responseLanguage.disabled' })}
</Button>
</div>
<p className="text-xs text-muted-foreground">
{formatMessage({ id: 'settings.responseLanguage.windowsPlatformDesc' })}
</p>
</div>
{/* CLI Enhancement - Codex */}
<div className="rounded-lg border border-border p-4 space-y-2">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Terminal className="w-4 h-4 text-muted-foreground" />
<span className="text-sm font-medium">{formatMessage({ id: 'settings.responseLanguage.cliEnhancement' })}</span>
<Badge variant="secondary" className="text-xs">Codex</Badge>
</div>
<div className="flex items-center gap-1">
{cliEnhStatus?.enabled && (
<Button
variant="ghost"
size="sm"
className="h-7 w-7 p-0"
disabled={cliEnhLoading || refreshing}
onClick={() => refreshCliEnh()}
title={formatMessage({ id: 'settings.responseLanguage.refreshConfig' })}
>
<RefreshCw className={cn('w-3.5 h-3.5', refreshing && 'animate-spin')} />
</Button>
)}
<Button
variant={cliEnhStatus?.enabled ? 'default' : 'outline'}
size="sm"
className="h-7"
disabled={cliEnhLoading || cliEnhToggling}
onClick={() => toggleCliEnh(!cliEnhStatus?.enabled)}
>
{cliEnhStatus?.enabled
? formatMessage({ id: 'settings.responseLanguage.enabled' })
: formatMessage({ id: 'settings.responseLanguage.disabled' })}
</Button>
</div>
</div>
<p className="text-xs text-muted-foreground">
{formatMessage({ id: 'settings.responseLanguage.cliEnhancementDesc' })}
</p>
{cliEnhStatus?.enabled && (
<p className="text-xs text-muted-foreground/70">
{formatMessage({ id: 'settings.responseLanguage.cliEnhancementHint' })}
</p>
)}
</div>
</div>
</Card>
);
}
// ========== System Status Section ==========
function SystemStatusSection() {
const { formatMessage } = useIntl();
const { data: ccwInstall, isLoading: installLoading } = useCcwInstallStatus();
// Don't show if installed or still loading
if (installLoading || ccwInstall?.installed) return null;
return (
<Card className="p-6 border-yellow-500/50">
<h2 className="text-lg font-semibold text-foreground flex items-center gap-2 mb-4">
<AlertTriangle className="w-5 h-5 text-yellow-500" />
{formatMessage({ id: 'settings.systemStatus.title' })}
</h2>
{/* CCW Install Status */}
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-sm font-medium">{formatMessage({ id: 'settings.systemStatus.ccwInstall' })}</span>
<Badge variant="outline" className="text-yellow-500 border-yellow-500/50">
{formatMessage({ id: 'settings.systemStatus.incomplete' })}
</Badge>
</div>
{ccwInstall && ccwInstall.missingFiles.length > 0 && (
<div className="space-y-2">
<p className="text-xs text-muted-foreground">
{formatMessage({ id: 'settings.systemStatus.missingFiles' })}:
</p>
<ul className="text-xs text-muted-foreground/70 list-disc list-inside">
{ccwInstall.missingFiles.slice(0, 5).map((file) => (
<li key={file}>{file}</li>
))}
{ccwInstall.missingFiles.length > 5 && (
<li>+{ccwInstall.missingFiles.length - 5} more...</li>
)}
</ul>
<div className="bg-muted/50 rounded-md p-3 mt-2">
<p className="text-xs font-medium mb-1">
{formatMessage({ id: 'settings.systemStatus.runToFix' })}:
</p>
<code className="text-xs bg-background px-2 py-1 rounded block font-mono">
ccw install
</code>
</div>
</div>
)}
</div>
</Card>
);
}
// ========== CLI Tools with Status Enhancement ==========
interface CliToolsWithStatusProps {
cliTools: Record<string, CliToolConfig>;
defaultCliTool: string;
expandedTools: Set<string>;
onToggleExpand: (toolId: string) => void;
onToggleEnabled: (toolId: string) => void;
onSetDefault: (toolId: string) => void;
onUpdateModel: (toolId: string, field: 'primaryModel' | 'secondaryModel', value: string) => void;
onUpdateTags: (toolId: string, tags: string[]) => void;
onUpdateAvailableModels: (toolId: string, models: string[]) => void;
onUpdateSettingsFile: (toolId: string, settingsFile: string | undefined) => void;
formatMessage: ReturnType<typeof useIntl>['formatMessage'];
}
function CliToolsWithStatus({
cliTools,
defaultCliTool,
expandedTools,
onToggleExpand,
onToggleEnabled,
onSetDefault,
onUpdateModel,
onUpdateTags,
onUpdateAvailableModels,
onUpdateSettingsFile,
formatMessage,
}: CliToolsWithStatusProps) {
const { data: toolStatus } = useCliToolStatus();
return (
<>
<p className="text-sm text-muted-foreground mb-4">
{formatMessage({ id: 'settings.cliTools.description' })} <strong className="text-foreground">{defaultCliTool}</strong>
</p>
<div className="space-y-3">
{Object.entries(cliTools).map(([toolId, config]) => {
const status = toolStatus?.[toolId];
return (
<CliToolCard
key={toolId}
toolId={toolId}
config={config}
isDefault={toolId === defaultCliTool}
isExpanded={expandedTools.has(toolId)}
toolAvailable={status?.available}
onToggleExpand={() => onToggleExpand(toolId)}
onToggleEnabled={() => onToggleEnabled(toolId)}
onSetDefault={() => onSetDefault(toolId)}
onUpdateModel={(field, value) => onUpdateModel(toolId, field, value)}
onUpdateTags={(tags) => onUpdateTags(toolId, tags)}
onUpdateAvailableModels={(models) => onUpdateAvailableModels(toolId, models)}
onUpdateSettingsFile={(settingsFile) => onUpdateSettingsFile(toolId, settingsFile)}
/>
);
})}
</div>
</>
);
}
// ========== Main Page Component ==========
export function SettingsPage() {
@@ -466,33 +749,31 @@ export function SettingsPage() {
</div>
</Card>
{/* Response Language Settings */}
<ResponseLanguageSection />
{/* System Status */}
<SystemStatusSection />
{/* CLI Tools Configuration */}
<Card className="p-6">
<h2 className="text-lg font-semibold text-foreground flex items-center gap-2 mb-4">
<Cpu className="w-5 h-5" />
{formatMessage({ id: 'settings.sections.cliTools' })}
</h2>
<p className="text-sm text-muted-foreground mb-4">
{formatMessage({ id: 'settings.cliTools.description' })} <strong className="text-foreground">{defaultCliTool}</strong>
</p>
<div className="space-y-3">
{Object.entries(cliTools).map(([toolId, config]) => (
<CliToolCard
key={toolId}
toolId={toolId}
config={config}
isDefault={toolId === defaultCliTool}
isExpanded={expandedTools.has(toolId)}
onToggleExpand={() => toggleToolExpand(toolId)}
onToggleEnabled={() => handleToggleToolEnabled(toolId)}
onSetDefault={() => handleSetDefaultTool(toolId)}
onUpdateModel={(field, value) => handleUpdateModel(toolId, field, value)}
onUpdateTags={(tags) => handleUpdateTags(toolId, tags)}
onUpdateAvailableModels={(models) => handleUpdateAvailableModels(toolId, models)}
onUpdateSettingsFile={(settingsFile) => handleUpdateSettingsFile(toolId, settingsFile)}
/>
))}
</div>
<CliToolsWithStatus
cliTools={cliTools}
defaultCliTool={defaultCliTool}
expandedTools={expandedTools}
onToggleExpand={toggleToolExpand}
onToggleEnabled={handleToggleToolEnabled}
onSetDefault={handleSetDefaultTool}
onUpdateModel={handleUpdateModel}
onUpdateTags={handleUpdateTags}
onUpdateAvailableModels={handleUpdateAvailableModels}
onUpdateSettingsFile={handleUpdateSettingsFile}
formatMessage={formatMessage}
/>
</Card>
{/* Data Refresh Settings */}

View File

@@ -38,7 +38,7 @@ import {
AlertDialogAction,
AlertDialogCancel,
} from '@/components/ui';
import { SkillCard, SkillDetailPanel } from '@/components/shared';
import { SkillCard, SkillDetailPanel, SkillCreateDialog } from '@/components/shared';
import { useSkills, useSkillMutations } from '@/hooks';
import { fetchSkillDetail } from '@/lib/api';
import { useWorkflowStore, selectProjectPath } from '@/stores/workflowStore';
@@ -118,6 +118,9 @@ export function SkillsManagerPage() {
const [confirmDisable, setConfirmDisable] = useState<{ skill: Skill; enable: boolean } | null>(null);
const [locationFilter, setLocationFilter] = useState<'project' | 'user'>('project');
// Skill create dialog state
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
// Skill detail panel state
const [selectedSkill, setSelectedSkill] = useState<Skill | null>(null);
const [isDetailLoading, setIsDetailLoading] = useState(false);
@@ -243,7 +246,7 @@ export function SkillsManagerPage() {
<RefreshCw className={cn('w-4 h-4 mr-2', isFetching && 'animate-spin')} />
{formatMessage({ id: 'common.actions.refresh' })}
</Button>
<Button>
<Button onClick={() => setIsCreateDialogOpen(true)}>
<Plus className="w-4 h-4 mr-2" />
{formatMessage({ id: 'skills.actions.install' })}
</Button>
@@ -470,6 +473,13 @@ export function SkillsManagerPage() {
onClose={handleCloseDetailPanel}
isLoading={isDetailLoading}
/>
{/* Skill Create Dialog */}
<SkillCreateDialog
open={isCreateDialogOpen}
onOpenChange={setIsCreateDialogOpen}
onCreated={() => refetch()}
/>
</div>
);
}

View File

@@ -726,13 +726,23 @@ function toggleMcpServerEnabled(projectPath: string, serverName: string, enable:
const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
const config = JSON.parse(content);
const normalizedPath = normalizeProjectPathForConfig(projectPath, config);
if (!config.projects || !config.projects[normalizedPath]) {
return { error: `Project not found: ${normalizedPath}` };
// Find matching project key by normalizing both input and config keys
const normalizedInput = normalizeProjectPathForConfig(projectPath, config);
let matchedKey: string | null = null;
if (config.projects) {
for (const key of Object.keys(config.projects)) {
if (normalizeProjectPathForConfig(key) === normalizedInput) {
matchedKey = key;
break;
}
}
}
const projectConfig = config.projects[normalizedPath];
if (!matchedKey || !config.projects[matchedKey]) {
return { error: `Project not found: ${normalizedInput}` };
}
const projectConfig = config.projects[matchedKey];
// Ensure disabledMcpServers array exists
if (!projectConfig.disabledMcpServers) {
@@ -865,11 +875,20 @@ function removeMcpServerFromProject(projectPath: string, serverName: string) {
const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
const config = JSON.parse(content);
// Get normalized path that matches existing config format
const normalizedPath = normalizeProjectPathForConfig(projectPath, config);
// Find matching project key by normalizing both input path and config keys
const normalizedInput = normalizeProjectPathForConfig(projectPath, config);
let matchedKey: string | null = null;
if (config.projects) {
for (const key of Object.keys(config.projects)) {
if (normalizeProjectPathForConfig(key) === normalizedInput) {
matchedKey = key;
break;
}
}
}
if (config.projects && config.projects[normalizedPath]) {
const projectConfig = config.projects[normalizedPath];
if (matchedKey && config.projects[matchedKey]) {
const projectConfig = config.projects[matchedKey];
if (projectConfig.mcpServers && projectConfig.mcpServers[serverName]) {
// Remove the server