Merge remote-tracking branch 'origin/main' into feat/glm-provider
Resolved conflicts in: - Cargo.toml: kept both `ring` (JWT auth) and `prost` (protobuf) dependencies - src/onboard/wizard.rs: accepted main branch version - src/providers/mod.rs: accepted main branch version - Cargo.lock: accepted main branch version Note: The custom `glm::GlmProvider` from this PR was replaced with main's OpenAiCompatibleProvider approach for GLM, which uses base URLs. The main purpose of this PR is Windows daemon support via Task Scheduler. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
34af6a223a
269 changed files with 68574 additions and 2541 deletions
|
|
@ -453,9 +453,9 @@ fn copy_dir_recursive(src: &Path, dest: &Path) -> Result<()> {
|
|||
|
||||
/// Handle the `skills` CLI command
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub fn handle_command(command: super::SkillCommands, workspace_dir: &Path) -> Result<()> {
|
||||
pub fn handle_command(command: crate::SkillCommands, workspace_dir: &Path) -> Result<()> {
|
||||
match command {
|
||||
super::SkillCommands::List => {
|
||||
crate::SkillCommands::List => {
|
||||
let skills = load_skills(workspace_dir);
|
||||
if skills.is_empty() {
|
||||
println!("No skills installed.");
|
||||
|
|
@ -493,13 +493,13 @@ pub fn handle_command(command: super::SkillCommands, workspace_dir: &Path) -> Re
|
|||
println!();
|
||||
Ok(())
|
||||
}
|
||||
super::SkillCommands::Install { source } => {
|
||||
crate::SkillCommands::Install { source } => {
|
||||
println!("Installing skill from: {source}");
|
||||
|
||||
let skills_path = skills_dir(workspace_dir);
|
||||
std::fs::create_dir_all(&skills_path)?;
|
||||
|
||||
if source.starts_with("http") || source.contains("github.com") {
|
||||
if source.starts_with("https://") || source.starts_with("http://") {
|
||||
// Git clone
|
||||
let output = std::process::Command::new("git")
|
||||
.args(["clone", "--depth", "1", &source])
|
||||
|
|
@ -584,8 +584,24 @@ pub fn handle_command(command: super::SkillCommands, workspace_dir: &Path) -> Re
|
|||
|
||||
Ok(())
|
||||
}
|
||||
super::SkillCommands::Remove { name } => {
|
||||
crate::SkillCommands::Remove { name } => {
|
||||
// Reject path traversal attempts
|
||||
if name.contains("..") || name.contains('/') || name.contains('\\') {
|
||||
anyhow::bail!("Invalid skill name: {name}");
|
||||
}
|
||||
|
||||
let skill_path = skills_dir(workspace_dir).join(&name);
|
||||
|
||||
// Verify the resolved path is actually inside the skills directory
|
||||
let canonical_skills = skills_dir(workspace_dir)
|
||||
.canonicalize()
|
||||
.unwrap_or_else(|_| skills_dir(workspace_dir));
|
||||
if let Ok(canonical_skill) = skill_path.canonicalize() {
|
||||
if !canonical_skill.starts_with(&canonical_skills) {
|
||||
anyhow::bail!("Skill path escapes skills directory: {name}");
|
||||
}
|
||||
}
|
||||
|
||||
if !skill_path.exists() {
|
||||
anyhow::bail!("Skill not found: {name}");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue