use crate::sandbox::SandboxExecutor;
use crate::skills::Skill;
use crate::tools::Tool;
use crate::tools::shell::ShellTool;
use std::sync::Arc;
pub struct ShellSkill {
permissive: bool,
}
impl ShellSkill {
pub fn new() -> Self {
Self { permissive: false }
}
pub fn permissive() -> Self {
Self { permissive: true }
}
}
impl Default for ShellSkill {
fn default() -> Self {
Self::new()
}
}
impl Skill for ShellSkill {
fn name(&self) -> &str {
"shell"
}
fn description(&self) -> &str {
"Controlled shell command execution capability: supports file viewing, directory operations, code building (git/cargo), searching, and other safe commands"
}
fn tools(&self) -> Vec<Box<dyn Tool>> {
let tool = if self.permissive {
ShellTool::new_permissive()
} else {
ShellTool::new()
};
vec![Box::new(tool)]
}
fn tools_with_sandbox(&self, sandbox: Option<Arc<dyn SandboxExecutor>>) -> Vec<Box<dyn Tool>> {
let mut tool = if self.permissive {
ShellTool::new_permissive()
} else {
ShellTool::new()
};
if let Some(sandbox) = sandbox {
tool = tool.with_sandbox(sandbox);
}
vec![Box::new(tool)]
}
fn system_prompt_injection(&self) -> Option<String> {
Some(
"\n\n## Shell Command Capability (Shell Skill)\n\
You can use the `shell(command)` tool to execute restricted shell commands:\n\n\
**Safe (direct execution):**\n\
- File viewing: `ls`, `cat`, `head`, `tail`, `wc`, `stat`\n\
- Directory operations: `pwd`, `tree`, `find`, `du`\n\
- Code tools: `git status/log/diff/show`, `cargo check/build/test/clippy`\n\
- Search: `grep`, `rg` (ripgrep), `fd`\n\
- Text processing: `echo`, `cut`, `sort`, `uniq`, `diff`\n\n\
**Requires human approval (will show a prompt, will not execute):**\n\
- `rm`, `mv`, `cp`, `curl`, `wget`, `npm`, `pip`, etc.\n\n\
**Permanently forbidden (hard security policy):**\n\
- `sudo`, `dd`, `chmod`, `reboot`, `shutdown`, etc.\n\n\
**Note**: Only execute one command at a time; use `&&` to chain combined operations."
.to_string(),
)
}
}