mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-04-30 16:03:21 +08:00
Compare commits
1 Commits
fix/openco
...
refactor/r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9a4c7cb86 |
@@ -90,7 +90,6 @@ pub async fn install_skill(
|
|||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| "main".to_string()),
|
.unwrap_or_else(|| "main".to_string()),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
skills_path: skill.skills_path.clone(), // 使用技能记录的 skills_path
|
|
||||||
};
|
};
|
||||||
|
|
||||||
service
|
service
|
||||||
|
|||||||
@@ -58,7 +58,9 @@ impl Database {
|
|||||||
pub fn get_skill_repos(&self) -> Result<Vec<SkillRepo>, AppError> {
|
pub fn get_skill_repos(&self) -> Result<Vec<SkillRepo>, AppError> {
|
||||||
let conn = lock_conn!(self.conn);
|
let conn = lock_conn!(self.conn);
|
||||||
let mut stmt = conn
|
let mut stmt = conn
|
||||||
.prepare("SELECT owner, name, branch, enabled, skills_path FROM skill_repos ORDER BY owner ASC, name ASC")
|
.prepare(
|
||||||
|
"SELECT owner, name, branch, enabled FROM skill_repos ORDER BY owner ASC, name ASC",
|
||||||
|
)
|
||||||
.map_err(|e| AppError::Database(e.to_string()))?;
|
.map_err(|e| AppError::Database(e.to_string()))?;
|
||||||
|
|
||||||
let repo_iter = stmt
|
let repo_iter = stmt
|
||||||
@@ -68,7 +70,6 @@ impl Database {
|
|||||||
name: row.get(1)?,
|
name: row.get(1)?,
|
||||||
branch: row.get(2)?,
|
branch: row.get(2)?,
|
||||||
enabled: row.get(3)?,
|
enabled: row.get(3)?,
|
||||||
skills_path: row.get(4)?,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.map_err(|e| AppError::Database(e.to_string()))?;
|
.map_err(|e| AppError::Database(e.to_string()))?;
|
||||||
@@ -84,8 +85,8 @@ impl Database {
|
|||||||
pub fn save_skill_repo(&self, repo: &SkillRepo) -> Result<(), AppError> {
|
pub fn save_skill_repo(&self, repo: &SkillRepo) -> Result<(), AppError> {
|
||||||
let conn = lock_conn!(self.conn);
|
let conn = lock_conn!(self.conn);
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"INSERT OR REPLACE INTO skill_repos (owner, name, branch, enabled, skills_path) VALUES (?1, ?2, ?3, ?4, ?5)",
|
"INSERT OR REPLACE INTO skill_repos (owner, name, branch, enabled) VALUES (?1, ?2, ?3, ?4)",
|
||||||
params![repo.owner, repo.name, repo.branch, repo.enabled, repo.skills_path],
|
params![repo.owner, repo.name, repo.branch, repo.enabled],
|
||||||
).map_err(|e| AppError::Database(e.to_string()))?;
|
).map_err(|e| AppError::Database(e.to_string()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,8 +202,8 @@ impl Database {
|
|||||||
|
|
||||||
for repo in &config.skills.repos {
|
for repo in &config.skills.repos {
|
||||||
tx.execute(
|
tx.execute(
|
||||||
"INSERT OR REPLACE INTO skill_repos (owner, name, branch, enabled, skills_path) VALUES (?1, ?2, ?3, ?4, ?5)",
|
"INSERT OR REPLACE INTO skill_repos (owner, name, branch, enabled) VALUES (?1, ?2, ?3, ?4)",
|
||||||
params![repo.owner, repo.name, repo.branch, repo.enabled, repo.skills_path],
|
params![repo.owner, repo.name, repo.branch, repo.enabled],
|
||||||
).map_err(|e| AppError::Database(format!("Migrate skill repo failed: {e}")))?;
|
).map_err(|e| AppError::Database(format!("Migrate skill repo failed: {e}")))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,6 @@ impl Database {
|
|||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
branch TEXT NOT NULL DEFAULT 'main',
|
branch TEXT NOT NULL DEFAULT 'main',
|
||||||
enabled BOOLEAN NOT NULL DEFAULT 1,
|
enabled BOOLEAN NOT NULL DEFAULT 1,
|
||||||
skills_path TEXT,
|
|
||||||
PRIMARY KEY (owner, name)
|
PRIMARY KEY (owner, name)
|
||||||
)",
|
)",
|
||||||
[],
|
[],
|
||||||
@@ -233,7 +232,7 @@ impl Database {
|
|||||||
"TEXT NOT NULL DEFAULT 'main'",
|
"TEXT NOT NULL DEFAULT 'main'",
|
||||||
)?;
|
)?;
|
||||||
Self::add_column_if_missing(conn, "skill_repos", "enabled", "BOOLEAN NOT NULL DEFAULT 1")?;
|
Self::add_column_if_missing(conn, "skill_repos", "enabled", "BOOLEAN NOT NULL DEFAULT 1")?;
|
||||||
Self::add_column_if_missing(conn, "skill_repos", "skills_path", "TEXT")?;
|
// 注意: skills_path 字段已被移除,因为现在支持全仓库递归扫描
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,12 +100,8 @@ pub struct DeepLinkImportRequest {
|
|||||||
/// Skill directory name
|
/// Skill directory name
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub directory: Option<String>,
|
pub directory: Option<String>,
|
||||||
/// Repository branch (default: "main")
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub branch: Option<String>,
|
pub branch: Option<String>,
|
||||||
/// Skills subdirectory path (e.g., "skills")
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub skills_path: Option<String>,
|
|
||||||
|
|
||||||
// ============ Config file fields (v3.8+) ============
|
// ============ Config file fields (v3.8+) ============
|
||||||
/// Base64 encoded config content
|
/// Base64 encoded config content
|
||||||
|
|||||||
@@ -143,7 +143,6 @@ fn parse_provider_deeplink(
|
|||||||
repo: None,
|
repo: None,
|
||||||
directory: None,
|
directory: None,
|
||||||
branch: None,
|
branch: None,
|
||||||
skills_path: None,
|
|
||||||
config,
|
config,
|
||||||
config_format,
|
config_format,
|
||||||
config_url,
|
config_url,
|
||||||
@@ -204,7 +203,6 @@ fn parse_prompt_deeplink(
|
|||||||
repo: None,
|
repo: None,
|
||||||
directory: None,
|
directory: None,
|
||||||
branch: None,
|
branch: None,
|
||||||
skills_path: None,
|
|
||||||
config: None,
|
config: None,
|
||||||
config_format: None,
|
config_format: None,
|
||||||
config_url: None,
|
config_url: None,
|
||||||
@@ -262,7 +260,6 @@ fn parse_mcp_deeplink(
|
|||||||
repo: None,
|
repo: None,
|
||||||
directory: None,
|
directory: None,
|
||||||
branch: None,
|
branch: None,
|
||||||
skills_path: None,
|
|
||||||
config_url: None,
|
config_url: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -287,10 +284,6 @@ fn parse_skill_deeplink(
|
|||||||
|
|
||||||
let directory = params.get("directory").cloned();
|
let directory = params.get("directory").cloned();
|
||||||
let branch = params.get("branch").cloned();
|
let branch = params.get("branch").cloned();
|
||||||
let skills_path = params
|
|
||||||
.get("skills_path")
|
|
||||||
.or_else(|| params.get("skillsPath"))
|
|
||||||
.cloned();
|
|
||||||
|
|
||||||
Ok(DeepLinkImportRequest {
|
Ok(DeepLinkImportRequest {
|
||||||
version,
|
version,
|
||||||
@@ -298,7 +291,6 @@ fn parse_skill_deeplink(
|
|||||||
repo: Some(repo),
|
repo: Some(repo),
|
||||||
directory,
|
directory,
|
||||||
branch,
|
branch,
|
||||||
skills_path,
|
|
||||||
icon: None,
|
icon: None,
|
||||||
app: Some("claude".to_string()), // Skills are Claude-only
|
app: Some("claude".to_string()), // Skills are Claude-only
|
||||||
name: None,
|
name: None,
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ pub fn import_skill_from_deeplink(
|
|||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
branch: request.branch.unwrap_or_else(|| "main".to_string()),
|
branch: request.branch.unwrap_or_else(|| "main".to_string()),
|
||||||
enabled: request.enabled.unwrap_or(true),
|
enabled: request.enabled.unwrap_or(true),
|
||||||
skills_path: request.skills_path,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Save using Database
|
// Save using Database
|
||||||
|
|||||||
@@ -142,7 +142,6 @@ fn test_build_gemini_provider_with_model() {
|
|||||||
repo: None,
|
repo: None,
|
||||||
directory: None,
|
directory: None,
|
||||||
branch: None,
|
branch: None,
|
||||||
skills_path: None,
|
|
||||||
content: None,
|
content: None,
|
||||||
description: None,
|
description: None,
|
||||||
enabled: None,
|
enabled: None,
|
||||||
@@ -189,7 +188,6 @@ fn test_build_gemini_provider_without_model() {
|
|||||||
repo: None,
|
repo: None,
|
||||||
directory: None,
|
directory: None,
|
||||||
branch: None,
|
branch: None,
|
||||||
skills_path: None,
|
|
||||||
content: None,
|
content: None,
|
||||||
description: None,
|
description: None,
|
||||||
enabled: None,
|
enabled: None,
|
||||||
@@ -231,7 +229,6 @@ fn test_parse_and_merge_config_claude() {
|
|||||||
repo: None,
|
repo: None,
|
||||||
directory: None,
|
directory: None,
|
||||||
branch: None,
|
branch: None,
|
||||||
skills_path: None,
|
|
||||||
content: None,
|
content: None,
|
||||||
description: None,
|
description: None,
|
||||||
enabled: None,
|
enabled: None,
|
||||||
@@ -275,7 +272,6 @@ fn test_parse_and_merge_config_url_override() {
|
|||||||
repo: None,
|
repo: None,
|
||||||
directory: None,
|
directory: None,
|
||||||
branch: None,
|
branch: None,
|
||||||
skills_path: None,
|
|
||||||
content: None,
|
content: None,
|
||||||
description: None,
|
description: None,
|
||||||
enabled: None,
|
enabled: None,
|
||||||
@@ -372,12 +368,11 @@ fn test_parse_mcp_deeplink() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_skill_deeplink() {
|
fn test_parse_skill_deeplink() {
|
||||||
let url = "ccswitch://v1/import?resource=skill&repo=owner/repo&directory=skills&branch=dev&skills_path=src";
|
let url = "ccswitch://v1/import?resource=skill&repo=owner/repo&directory=skills&branch=dev";
|
||||||
let request = parse_deeplink_url(&url).unwrap();
|
let request = parse_deeplink_url(&url).unwrap();
|
||||||
|
|
||||||
assert_eq!(request.resource, "skill");
|
assert_eq!(request.resource, "skill");
|
||||||
assert_eq!(request.repo.unwrap(), "owner/repo");
|
assert_eq!(request.repo.unwrap(), "owner/repo");
|
||||||
assert_eq!(request.directory.unwrap(), "skills");
|
assert_eq!(request.directory.unwrap(), "skills");
|
||||||
assert_eq!(request.branch.unwrap(), "dev");
|
assert_eq!(request.branch.unwrap(), "dev");
|
||||||
assert_eq!(request.skills_path.unwrap(), "src");
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,9 +34,6 @@ pub struct Skill {
|
|||||||
/// 分支名称
|
/// 分支名称
|
||||||
#[serde(rename = "repoBranch")]
|
#[serde(rename = "repoBranch")]
|
||||||
pub repo_branch: Option<String>,
|
pub repo_branch: Option<String>,
|
||||||
/// 技能所在的子目录路径 (可选, 如 "skills")
|
|
||||||
#[serde(rename = "skillsPath")]
|
|
||||||
pub skills_path: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 仓库配置
|
/// 仓库配置
|
||||||
@@ -50,9 +47,6 @@ pub struct SkillRepo {
|
|||||||
pub branch: String,
|
pub branch: String,
|
||||||
/// 是否启用
|
/// 是否启用
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
/// 技能所在的子目录路径 (可选, 如 "skills", "my-skills/subdir")
|
|
||||||
#[serde(rename = "skillsPath")]
|
|
||||||
pub skills_path: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 技能安装状态
|
/// 技能安装状态
|
||||||
@@ -84,21 +78,18 @@ impl Default for SkillStore {
|
|||||||
name: "awesome-claude-skills".to_string(),
|
name: "awesome-claude-skills".to_string(),
|
||||||
branch: "main".to_string(),
|
branch: "main".to_string(),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
skills_path: None, // 扫描根目录
|
|
||||||
},
|
},
|
||||||
SkillRepo {
|
SkillRepo {
|
||||||
owner: "anthropics".to_string(),
|
owner: "anthropics".to_string(),
|
||||||
name: "skills".to_string(),
|
name: "skills".to_string(),
|
||||||
branch: "main".to_string(),
|
branch: "main".to_string(),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
skills_path: None, // 扫描根目录
|
|
||||||
},
|
},
|
||||||
SkillRepo {
|
SkillRepo {
|
||||||
owner: "cexll".to_string(),
|
owner: "cexll".to_string(),
|
||||||
name: "myclaude".to_string(),
|
name: "myclaude".to_string(),
|
||||||
branch: "master".to_string(),
|
branch: "master".to_string(),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
skills_path: Some("skills".to_string()), // 扫描 skills 子目录
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -194,25 +185,8 @@ impl SkillService {
|
|||||||
})??;
|
})??;
|
||||||
let mut skills = Vec::new();
|
let mut skills = Vec::new();
|
||||||
|
|
||||||
// 确定要扫描的目录路径
|
// 扫描仓库根目录(支持全仓库递归扫描)
|
||||||
let scan_dir = if let Some(ref skills_path) = repo.skills_path {
|
let scan_dir = temp_dir.clone();
|
||||||
// 如果指定了 skillsPath,则扫描该子目录
|
|
||||||
let subdir = temp_dir.join(skills_path.trim_matches('/'));
|
|
||||||
if !subdir.exists() {
|
|
||||||
log::warn!(
|
|
||||||
"仓库 {}/{} 中指定的技能路径 '{}' 不存在",
|
|
||||||
repo.owner,
|
|
||||||
repo.name,
|
|
||||||
skills_path
|
|
||||||
);
|
|
||||||
let _ = fs::remove_dir_all(&temp_dir);
|
|
||||||
return Ok(skills);
|
|
||||||
}
|
|
||||||
subdir
|
|
||||||
} else {
|
|
||||||
// 否则扫描仓库根目录
|
|
||||||
temp_dir.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
// 递归扫描目录查找所有技能
|
// 递归扫描目录查找所有技能
|
||||||
self.scan_dir_recursive(&scan_dir, &scan_dir, repo, &mut skills)?;
|
self.scan_dir_recursive(&scan_dir, &scan_dir, repo, &mut skills)?;
|
||||||
@@ -284,11 +258,7 @@ impl SkillService {
|
|||||||
let meta = self.parse_skill_metadata(skill_md)?;
|
let meta = self.parse_skill_metadata(skill_md)?;
|
||||||
|
|
||||||
// 构建 README URL
|
// 构建 README URL
|
||||||
let readme_path = if let Some(ref skills_path) = repo.skills_path {
|
let readme_path = directory.to_string();
|
||||||
format!("{}/{}", skills_path.trim_matches('/'), directory)
|
|
||||||
} else {
|
|
||||||
directory.to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Skill {
|
Ok(Skill {
|
||||||
key: format!("{}/{}:{}", repo.owner, repo.name, directory),
|
key: format!("{}/{}:{}", repo.owner, repo.name, directory),
|
||||||
@@ -303,7 +273,6 @@ impl SkillService {
|
|||||||
repo_owner: Some(repo.owner.clone()),
|
repo_owner: Some(repo.owner.clone()),
|
||||||
repo_name: Some(repo.name.clone()),
|
repo_name: Some(repo.name.clone()),
|
||||||
repo_branch: Some(repo.branch.clone()),
|
repo_branch: Some(repo.branch.clone()),
|
||||||
skills_path: repo.skills_path.clone(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,7 +374,6 @@ impl SkillService {
|
|||||||
repo_owner: None,
|
repo_owner: None,
|
||||||
repo_name: None,
|
repo_name: None,
|
||||||
repo_branch: None,
|
repo_branch: None,
|
||||||
skills_path: None,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,16 +542,8 @@ impl SkillService {
|
|||||||
))
|
))
|
||||||
})??;
|
})??;
|
||||||
|
|
||||||
// 根据 skills_path 确定源目录路径
|
// 确定源目录路径(技能相对于仓库根目录的路径)
|
||||||
let source = if let Some(ref skills_path) = repo.skills_path {
|
let source = temp_dir.join(&directory);
|
||||||
// 如果指定了 skills_path,源路径为: temp_dir/skills_path/directory
|
|
||||||
temp_dir
|
|
||||||
.join(skills_path.trim_matches('/'))
|
|
||||||
.join(&directory)
|
|
||||||
} else {
|
|
||||||
// 否则源路径为: temp_dir/directory
|
|
||||||
temp_dir.join(&directory)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !source.exists() {
|
if !source.exists() {
|
||||||
let _ = fs::remove_dir_all(&temp_dir);
|
let _ = fs::remove_dir_all(&temp_dir);
|
||||||
|
|||||||
@@ -30,22 +30,11 @@ export function SkillConfirmation({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div>
|
||||||
<div>
|
<label className="block text-sm font-medium text-muted-foreground">
|
||||||
<label className="block text-sm font-medium text-muted-foreground">
|
{t("deeplink.skill.branch")}
|
||||||
{t("deeplink.skill.branch")}
|
</label>
|
||||||
</label>
|
<div className="mt-1 text-sm">{request.branch || "main"}</div>
|
||||||
<div className="mt-1 text-sm">{request.branch || "main"}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{request.skillsPath && (
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-muted-foreground">
|
|
||||||
{t("deeplink.skill.skillsPath")}
|
|
||||||
</label>
|
|
||||||
<div className="mt-1 text-sm">{request.skillsPath}</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-blue-600 dark:text-blue-400 text-sm bg-blue-50 dark:bg-blue-950/30 p-3 rounded border border-blue-200 dark:border-blue-800">
|
<div className="text-blue-600 dark:text-blue-400 text-sm bg-blue-50 dark:bg-blue-950/30 p-3 rounded border border-blue-200 dark:border-blue-800">
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ export function RepoManager({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [repoUrl, setRepoUrl] = useState("");
|
const [repoUrl, setRepoUrl] = useState("");
|
||||||
const [branch, setBranch] = useState("");
|
const [branch, setBranch] = useState("");
|
||||||
const [skillsPath, setSkillsPath] = useState("");
|
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
const getSkillCount = (repo: SkillRepo) =>
|
const getSkillCount = (repo: SkillRepo) =>
|
||||||
@@ -80,12 +79,10 @@ export function RepoManager({
|
|||||||
name: parsed.name,
|
name: parsed.name,
|
||||||
branch: branch || "main",
|
branch: branch || "main",
|
||||||
enabled: true,
|
enabled: true,
|
||||||
skillsPath: skillsPath.trim() || undefined, // 仅在有值时传递
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setRepoUrl("");
|
setRepoUrl("");
|
||||||
setBranch("");
|
setBranch("");
|
||||||
setSkillsPath("");
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError(e instanceof Error ? e.message : t("skills.repo.addFailed"));
|
setError(e instanceof Error ? e.message : t("skills.repo.addFailed"));
|
||||||
}
|
}
|
||||||
@@ -130,13 +127,6 @@ export function RepoManager({
|
|||||||
onChange={(e) => setBranch(e.target.value)}
|
onChange={(e) => setBranch(e.target.value)}
|
||||||
className="flex-1"
|
className="flex-1"
|
||||||
/>
|
/>
|
||||||
<Input
|
|
||||||
id="skills-path"
|
|
||||||
placeholder={t("skills.repo.pathPlaceholder")}
|
|
||||||
value={skillsPath}
|
|
||||||
onChange={(e) => setSkillsPath(e.target.value)}
|
|
||||||
className="flex-1"
|
|
||||||
/>
|
|
||||||
<Button
|
<Button
|
||||||
onClick={handleAdd}
|
onClick={handleAdd}
|
||||||
className="w-full sm:w-auto sm:px-4"
|
className="w-full sm:w-auto sm:px-4"
|
||||||
@@ -171,12 +161,6 @@ export function RepoManager({
|
|||||||
</div>
|
</div>
|
||||||
<div className="mt-1 text-xs text-muted-foreground">
|
<div className="mt-1 text-xs text-muted-foreground">
|
||||||
{t("skills.repo.branch")}: {repo.branch || "main"}
|
{t("skills.repo.branch")}: {repo.branch || "main"}
|
||||||
{repo.skillsPath && (
|
|
||||||
<>
|
|
||||||
<span className="mx-2">•</span>
|
|
||||||
{t("skills.repo.path")}: {repo.skillsPath}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<span className="ml-3 inline-flex items-center rounded-full border border-border-default px-2 py-0.5 text-[11px]">
|
<span className="ml-3 inline-flex items-center rounded-full border border-border-default px-2 py-0.5 text-[11px]">
|
||||||
{t("skills.repo.skillCount", {
|
{t("skills.repo.skillCount", {
|
||||||
count: getSkillCount(repo),
|
count: getSkillCount(repo),
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ export function RepoManagerPanel({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [repoUrl, setRepoUrl] = useState("");
|
const [repoUrl, setRepoUrl] = useState("");
|
||||||
const [branch, setBranch] = useState("");
|
const [branch, setBranch] = useState("");
|
||||||
const [skillsPath, setSkillsPath] = useState("");
|
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
const getSkillCount = (repo: SkillRepo) =>
|
const getSkillCount = (repo: SkillRepo) =>
|
||||||
@@ -67,12 +66,10 @@ export function RepoManagerPanel({
|
|||||||
name: parsed.name,
|
name: parsed.name,
|
||||||
branch: branch || "main",
|
branch: branch || "main",
|
||||||
enabled: true,
|
enabled: true,
|
||||||
skillsPath: skillsPath.trim() || undefined,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setRepoUrl("");
|
setRepoUrl("");
|
||||||
setBranch("");
|
setBranch("");
|
||||||
setSkillsPath("");
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError(e instanceof Error ? e.message : t("skills.repo.addFailed"));
|
setError(e instanceof Error ? e.message : t("skills.repo.addFailed"));
|
||||||
}
|
}
|
||||||
@@ -110,31 +107,17 @@ export function RepoManagerPanel({
|
|||||||
className="mt-2"
|
className="mt-2"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<div>
|
||||||
<div>
|
<Label htmlFor="branch" className="text-foreground">
|
||||||
<Label htmlFor="branch" className="text-foreground">
|
{t("skills.repo.branch")}
|
||||||
{t("skills.repo.branch")}
|
</Label>
|
||||||
</Label>
|
<Input
|
||||||
<Input
|
id="branch"
|
||||||
id="branch"
|
placeholder={t("skills.repo.branchPlaceholder")}
|
||||||
placeholder={t("skills.repo.branchPlaceholder")}
|
value={branch}
|
||||||
value={branch}
|
onChange={(e) => setBranch(e.target.value)}
|
||||||
onChange={(e) => setBranch(e.target.value)}
|
className="mt-2"
|
||||||
className="mt-2"
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="skills-path" className="text-foreground">
|
|
||||||
{t("skills.repo.path")}
|
|
||||||
</Label>
|
|
||||||
<Input
|
|
||||||
id="skills-path"
|
|
||||||
placeholder={t("skills.repo.pathPlaceholder")}
|
|
||||||
value={skillsPath}
|
|
||||||
onChange={(e) => setSkillsPath(e.target.value)}
|
|
||||||
className="mt-2"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{error && (
|
{error && (
|
||||||
<p className="text-sm text-red-600 dark:text-red-400">{error}</p>
|
<p className="text-sm text-red-600 dark:text-red-400">{error}</p>
|
||||||
@@ -174,12 +157,6 @@ export function RepoManagerPanel({
|
|||||||
</div>
|
</div>
|
||||||
<div className="mt-1 text-xs text-muted-foreground">
|
<div className="mt-1 text-xs text-muted-foreground">
|
||||||
{t("skills.repo.branch")}: {repo.branch || "main"}
|
{t("skills.repo.branch")}: {repo.branch || "main"}
|
||||||
{repo.skillsPath && (
|
|
||||||
<>
|
|
||||||
<span className="mx-2">•</span>
|
|
||||||
{t("skills.repo.path")}: {repo.skillsPath}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<span className="ml-3 inline-flex items-center rounded-full border border-border-default px-2 py-0.5 text-[11px]">
|
<span className="ml-3 inline-flex items-center rounded-full border border-border-default px-2 py-0.5 text-[11px]">
|
||||||
{t("skills.repo.skillCount", {
|
{t("skills.repo.skillCount", {
|
||||||
count: getSkillCount(repo),
|
count: getSkillCount(repo),
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ export interface DeepLinkImportRequest {
|
|||||||
repo?: string;
|
repo?: string;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
branch?: string;
|
branch?: string;
|
||||||
skillsPath?: string;
|
|
||||||
|
|
||||||
// Config file fields
|
// Config file fields
|
||||||
config?: string;
|
config?: string;
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ export interface Skill {
|
|||||||
repoOwner?: string;
|
repoOwner?: string;
|
||||||
repoName?: string;
|
repoName?: string;
|
||||||
repoBranch?: string;
|
repoBranch?: string;
|
||||||
skillsPath?: string; // 技能所在的子目录路径,如 "skills"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SkillRepo {
|
export interface SkillRepo {
|
||||||
@@ -18,7 +17,6 @@ export interface SkillRepo {
|
|||||||
name: string;
|
name: string;
|
||||||
branch: string;
|
branch: string;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
skillsPath?: string; // 可选:技能所在的子目录路径,如 "skills"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const skillsApi = {
|
export const skillsApi = {
|
||||||
|
|||||||
Reference in New Issue
Block a user