Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "corgea"
version = "1.8.8"
version = "1.9.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
18 changes: 18 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pub struct Config {
pub(crate) url: String,
pub(crate) debug: i8,
pub(crate) token: String,
#[serde(default)]
pub(crate) default_agent: Option<String>,
}

impl Config {
Expand Down Expand Up @@ -34,6 +36,7 @@ impl Config {
url: "https://www.corgea.app".to_string(),
debug: 0,
token: "".to_string(),
default_agent: None,
};

let toml = toml::to_string(&config).expect("Failed to serialize config");
Expand Down Expand Up @@ -100,4 +103,19 @@ impl Config {

self.debug
}

pub fn set_default_agent(&mut self, agent: String) -> io::Result<()> {
self.default_agent = Some(agent);
self.save()
}

pub fn get_default_agent(&self) -> Option<String> {
if let Ok(agent) = env::var("CORGEA_DEFAULT_AGENT") {
if !agent.trim().is_empty() {
return Some(agent);
}
}

self.default_agent.clone()
}
}
67 changes: 67 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod list;
mod log;
mod scan;
mod setup_hooks;
mod skill;
mod wait;
mod scanners {
pub mod blast;
Expand Down Expand Up @@ -194,13 +195,57 @@ enum Commands {
)]
default_config: bool,
},
/// Manage agent skills from the Corgea registry
Skill {
#[command(subcommand)]
command: SkillCommands,
},
/// Offline dependency inventory: scan, graph, explain, diff, sbom, policy
Deps {
#[command(subcommand)]
command: corgea::deps::run::DepsSubcommand,
},
}

#[derive(Subcommand, Debug)]
enum SkillCommands {
/// Install an approved skill into your agent's skills directory
Install {
#[arg(help = "Skill name, optionally with a version: name or name@version")]
name: String,

#[arg(
long,
help = "Agent to install for (e.g. cursor, claude-code, codex). Defaults to the configured default agent."
)]
agent: Option<String>,

#[arg(
long,
default_value = "project",
help = "Installation scope: project or user."
)]
scope: String,

#[arg(
long,
help = "Install to a custom directory (overrides --agent and --scope)."
)]
dir: Option<String>,

#[arg(
long,
help = "Persist the provided --agent as the default for future installs."
)]
set_default: bool,
},
/// Configure the default agent used when --agent is not provided
SetDefaultAgent {
#[arg(help = "Agent id (e.g. cursor, claude-code, codex).")]
agent: String,
},
}

#[derive(Subcommand, Debug, Clone, PartialEq)]
enum Scanner {
Snyk,
Expand Down Expand Up @@ -500,6 +545,28 @@ fn main() {
Some(Commands::SetupHooks { default_config }) => {
setup_hooks::setup_pre_commit_hook(*default_config);
}
Some(Commands::Skill { command }) => match command {
SkillCommands::Install {
name,
agent,
scope,
dir,
set_default,
} => {
verify_token_and_exit_when_fail(&corgea_config);
skill::run_install(
&mut corgea_config,
name,
agent.clone(),
scope,
dir.clone(),
*set_default,
);
}
SkillCommands::SetDefaultAgent { agent } => {
skill::run_set_default_agent(&mut corgea_config, agent);
}
},
Some(Commands::Deps { command }) => {
// Offline: no token / network. Exit code propagates fail-on policy.
std::process::exit(i32::from(corgea::deps::run::run(command.clone())));
Expand Down
30 changes: 14 additions & 16 deletions src/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,22 +322,18 @@ pub fn upload_scan(
Ok(res) => {
if !res.status().is_success() {
true
} else {
if let Some(server_offset) = res.headers().get("Upload-Offset") {
let expected_offset = offset + chunk.len();
if let Ok(server_offset_str) = server_offset.to_str() {
if let Ok(server_offset_val) = server_offset_str.parse::<usize>() {
if server_offset_val != expected_offset {
log::error!(
"Upload offset mismatch on chunk {}/{}: server has {} bytes but expected {}. \
This may indicate that chunks are being routed to different server instances. \
Please contact support.",
index + 1, total_chunks, server_offset_val, expected_offset
);
true
} else {
false
}
} else if let Some(server_offset) = res.headers().get("Upload-Offset") {
let expected_offset = offset + chunk.len();
if let Ok(server_offset_str) = server_offset.to_str() {
if let Ok(server_offset_val) = server_offset_str.parse::<usize>() {
if server_offset_val != expected_offset {
log::error!(
"Upload offset mismatch on chunk {}/{}: server has {} bytes but expected {}. \
This may indicate that chunks are being routed to different server instances. \
Please contact support.",
index + 1, total_chunks, server_offset_val, expected_offset
);
true
} else {
false
}
Expand All @@ -347,6 +343,8 @@ pub fn upload_scan(
} else {
false
}
} else {
false
}
}
Err(_) => true,
Expand Down
Loading
Loading