mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-25 13:45:03 +08:00
fix(skills): prevent duplicate skill installation from different repos (#778)
- Add directory conflict detection before installation - Fix installed status check to match repo owner and name - Add i18n translations for conflict error messages
This commit is contained in:
@@ -65,10 +65,17 @@ export const SkillsPage = forwardRef<SkillsPageHandle, SkillsPageProps>(
|
||||
const addRepoMutation = useAddSkillRepo();
|
||||
const removeRepoMutation = useRemoveSkillRepo();
|
||||
|
||||
// 已安装的 directory 集合
|
||||
const installedDirs = useMemo(() => {
|
||||
// 已安装的 skill key 集合(使用 directory + repoOwner + repoName 组合判断)
|
||||
const installedKeys = useMemo(() => {
|
||||
if (!installedSkills) return new Set<string>();
|
||||
return new Set(installedSkills.map((s) => s.directory.toLowerCase()));
|
||||
return new Set(
|
||||
installedSkills.map((s) => {
|
||||
// 构建唯一 key:directory + repoOwner + repoName
|
||||
const owner = s.repoOwner?.toLowerCase() || "";
|
||||
const name = s.repoName?.toLowerCase() || "";
|
||||
return `${s.directory.toLowerCase()}:${owner}:${name}`;
|
||||
}),
|
||||
);
|
||||
}, [installedSkills]);
|
||||
|
||||
type DiscoverableSkillItem = DiscoverableSkill & { installed: boolean };
|
||||
@@ -80,12 +87,14 @@ export const SkillsPage = forwardRef<SkillsPageHandle, SkillsPageProps>(
|
||||
const installName =
|
||||
d.directory.split("/").pop()?.toLowerCase() ||
|
||||
d.directory.toLowerCase();
|
||||
// 使用 directory + repoOwner + repoName 组合判断是否已安装
|
||||
const key = `${installName}:${d.repoOwner.toLowerCase()}:${d.repoName.toLowerCase()}`;
|
||||
return {
|
||||
...d,
|
||||
installed: installedDirs.has(installName),
|
||||
installed: installedKeys.has(key),
|
||||
};
|
||||
});
|
||||
}, [discoverableSkills, installedDirs]);
|
||||
}, [discoverableSkills, installedKeys]);
|
||||
|
||||
const loading = loadingDiscoverable || fetchingDiscoverable;
|
||||
|
||||
|
||||
@@ -972,6 +972,7 @@
|
||||
"downloadTimeoutHint": "Please check network connection or retry later",
|
||||
"skillPathNotFound": "Skill path '{{path}}' not found in repository {{owner}}/{{name}}",
|
||||
"skillDirNotFound": "Skill directory not found: {{path}}",
|
||||
"directoryConflict": "Skill directory '{{directory}}' is already occupied by {{existing_repo}}, cannot install from {{new_repo}}",
|
||||
"emptyArchive": "Downloaded archive is empty",
|
||||
"downloadFailed": "Download failed: HTTP {{status}}",
|
||||
"allBranchesFailed": "All branches failed, tried: {{branches}}",
|
||||
@@ -990,7 +991,8 @@
|
||||
"retryLater": "Please retry later",
|
||||
"checkRepoUrl": "Please check repository URL and branch name",
|
||||
"checkDiskSpace": "Please check disk space",
|
||||
"checkPermission": "Please check directory permissions"
|
||||
"checkPermission": "Please check directory permissions",
|
||||
"uninstallFirst": "Please uninstall the existing skill with the same name first"
|
||||
}
|
||||
},
|
||||
"repo": {
|
||||
|
||||
@@ -972,6 +972,7 @@
|
||||
"downloadTimeoutHint": "ネットワークを確認するか、時間をおいて再試行してください",
|
||||
"skillPathNotFound": "リポジトリ {{owner}}/{{name}} にスキルパス '{{path}}' がありません",
|
||||
"skillDirNotFound": "スキルディレクトリが見つかりません: {{path}}",
|
||||
"directoryConflict": "スキルディレクトリ '{{directory}}' は既に {{existing_repo}} で使用されています。{{new_repo}} からインストールできません",
|
||||
"emptyArchive": "ダウンロードしたアーカイブが空です",
|
||||
"downloadFailed": "ダウンロードに失敗しました: HTTP {{status}}",
|
||||
"allBranchesFailed": "すべてのブランチで失敗しました。試行: {{branches}}",
|
||||
@@ -990,7 +991,8 @@
|
||||
"retryLater": "時間をおいて再試行してください",
|
||||
"checkRepoUrl": "リポジトリ URL とブランチ名を確認してください",
|
||||
"checkDiskSpace": "ディスク容量を確認してください",
|
||||
"checkPermission": "ディレクトリの権限を確認してください"
|
||||
"checkPermission": "ディレクトリの権限を確認してください",
|
||||
"uninstallFirst": "同名のスキルを先にアンインストールしてください"
|
||||
}
|
||||
},
|
||||
"repo": {
|
||||
|
||||
@@ -972,6 +972,7 @@
|
||||
"downloadTimeoutHint": "请检查网络连接或稍后重试",
|
||||
"skillPathNotFound": "仓库 {{owner}}/{{name}} 中未找到技能路径 '{{path}}'",
|
||||
"skillDirNotFound": "技能目录不存在:{{path}}",
|
||||
"directoryConflict": "技能目录 '{{directory}}' 已被 {{existing_repo}} 占用,无法从 {{new_repo}} 安装",
|
||||
"emptyArchive": "下载的压缩包为空",
|
||||
"downloadFailed": "下载失败:HTTP {{status}}",
|
||||
"allBranchesFailed": "所有分支下载失败,尝试了:{{branches}}",
|
||||
@@ -990,7 +991,8 @@
|
||||
"retryLater": "请稍后重试",
|
||||
"checkRepoUrl": "请检查仓库地址和分支名称",
|
||||
"checkDiskSpace": "请检查磁盘空间",
|
||||
"checkPermission": "请检查目录权限"
|
||||
"checkPermission": "请检查目录权限",
|
||||
"uninstallFirst": "请先卸载已安装的同名技能"
|
||||
}
|
||||
},
|
||||
"repo": {
|
||||
|
||||
@@ -35,6 +35,7 @@ function getErrorI18nKey(code: string): string {
|
||||
DOWNLOAD_TIMEOUT: "skills.error.downloadTimeout",
|
||||
DOWNLOAD_FAILED: "skills.error.downloadFailed",
|
||||
SKILL_DIR_NOT_FOUND: "skills.error.skillDirNotFound",
|
||||
SKILL_DIRECTORY_CONFLICT: "skills.error.directoryConflict",
|
||||
EMPTY_ARCHIVE: "skills.error.emptyArchive",
|
||||
GET_HOME_DIR_FAILED: "skills.error.getHomeDirFailed",
|
||||
};
|
||||
@@ -52,6 +53,7 @@ function getSuggestionI18nKey(suggestion: string): string {
|
||||
retryLater: "skills.error.suggestion.retryLater",
|
||||
checkRepoUrl: "skills.error.suggestion.checkRepoUrl",
|
||||
checkPermission: "skills.error.suggestion.checkPermission",
|
||||
uninstallFirst: "skills.error.suggestion.uninstallFirst",
|
||||
http403: "skills.error.http403",
|
||||
http404: "skills.error.http404",
|
||||
http429: "skills.error.http429",
|
||||
|
||||
Reference in New Issue
Block a user