use anyhow::Result;
use lowfat_core::config::RunfConfig;
use lowfat_plugin::discovery::discover_plugins;
use std::collections::BTreeSet;
const BUILTIN_COMMANDS: &[&str] = &["docker", "git", "ls"];
fn collect_commands() -> Vec<String> {
let mut cmds: BTreeSet<String> = BUILTIN_COMMANDS.iter().map(|s| s.to_string()).collect();
let config = RunfConfig::resolve();
let plugins = discover_plugins(&config.plugin_dir);
for plugin in &plugins {
for cmd in &plugin.manifest.plugin.commands {
cmds.insert(cmd.clone());
}
}
for cmd in config.pipelines.keys() {
cmds.insert(cmd.clone());
}
cmds.into_iter().collect()
}
pub fn run(shell: &str) -> Result<()> {
match shell {
"zsh" | "bash" => print_posix_init(),
"fish" => print_fish_init(),
_ => {
eprintln!("lowfat: unsupported shell: {shell} (supported: bash, zsh, fish)");
}
}
Ok(())
}
fn print_posix_init() {
let commands = collect_commands();
println!("# lowfat shell init — auto-wrap commands for LLM token savings");
println!("# Usage: eval \"$(lowfat shell-init zsh)\"");
println!();
println!("if [[ \"$CLAUDECODE\" == \"1\" ]] || [[ -n \"$CODEX_ENV\" ]] || [[ \"$LOWFAT_AUTO\" == \"1\" ]]; then");
for cmd in &commands {
println!(" {cmd}() {{ command lowfat \"${{FUNCNAME[0]:-{cmd}}}\" \"$@\"; }}");
}
println!("fi");
println!();
println!("if [[ \"${{LOWFAT_SESSION:-1}}\" == \"1\" ]]; then");
println!(" _lowfat_session_exit() {{");
println!(" command lowfat status 2>/dev/null || true");
println!(" }}");
println!(" trap '_lowfat_session_exit' EXIT");
println!("fi");
}
fn print_fish_init() {
let commands = collect_commands();
println!("# lowfat shell init for fish");
println!();
println!("if test \"$CLAUDECODE\" = 1; or test -n \"$CODEX_ENV\"; or test \"$LOWFAT_AUTO\" = 1");
for cmd in &commands {
println!(" function {cmd}; command lowfat {cmd} $argv; end");
}
println!("end");
}