Files
Kigi-CLI/crates/codegen/kigi-tui/src/memory_cmd.rs
T
ZacharyZhang-NY a02b555e66 docs(comments): rewrite comments across all crates to the guidelines
Sweep every first-party crate source (1956 .rs files) to the project comment
guidelines: delete redundant restatements, decorative banners, change
narration, and end-of-line comments; keep and tighten the crucial ones
(invariants, bug rationale, SAFETY blocks, ported-source attribution).

No functional code changed. Every edit is proven comment-only against the
prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a
separate doctest-fence check. Where removing a comment made rustfmt or clippy
want to re-lay-out adjacent code, the minimal triggering comment is restored so
code tokens stay byte-identical.

Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy
--workspace --all-targets (0 warnings).

Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for
these guidelines (flags banners, end-of-line comments, change narration, and
commented-out code).
2026-07-23 16:55:39 -04:00

134 lines
3.6 KiB
Rust

use std::io::Write;
use std::path::PathBuf;
use anyhow::Result;
use clap::Subcommand;
use kigi_shell::session::memory::storage::MemoryStorage;
#[derive(Debug, clap::Args, Clone)]
pub struct MemoryArgs {
#[command(subcommand)]
pub command: MemoryCommand,
}
#[derive(Debug, Subcommand, Clone)]
pub enum MemoryCommand {
/// Clear memory files (workspace by default)
Clear {
/// Clear workspace-scoped memory (MEMORY.md, sessions/, index.sqlite)
#[arg(long, group = "scope")]
workspace: bool,
/// Clear global MEMORY.md
#[arg(long, group = "scope")]
global: bool,
/// Clear both workspace and global memory
#[arg(long, group = "scope")]
all: bool,
/// Skip confirmation prompt
#[arg(long, short = 'y')]
yes: bool,
},
}
struct ClearTarget {
label: &'static str,
path: PathBuf,
clear: fn(&MemoryStorage) -> std::io::Result<bool>,
}
fn workspace_target(storage: &MemoryStorage) -> ClearTarget {
ClearTarget {
label: "workspace memory",
path: storage.workspace_dir().to_path_buf(),
clear: |s| s.clear_workspace(),
}
}
fn global_target(storage: &MemoryStorage) -> ClearTarget {
ClearTarget {
label: "global MEMORY.md",
path: storage.global_memory_file(),
clear: |s| s.clear_global(),
}
}
pub fn run(args: MemoryArgs) -> Result<()> {
match args.command {
MemoryCommand::Clear {
global, all, yes, ..
} => {
let cwd = std::env::current_dir().unwrap_or_else(|_| ".".into());
let storage = MemoryStorage::new(&cwd, None);
let targets = if all {
vec![workspace_target(&storage), global_target(&storage)]
} else if global {
vec![global_target(&storage)]
} else {
vec![workspace_target(&storage)]
};
run_clear(&storage, &targets, yes)
}
}
}
fn run_clear(storage: &MemoryStorage, targets: &[ClearTarget], skip_confirm: bool) -> Result<()> {
let existing: Vec<_> = targets.iter().filter(|t| t.path.exists()).collect();
if existing.is_empty() {
println!("Nothing to clear \u{2014} no memory files found.");
return Ok(());
}
println!("The following will be deleted:");
for t in &existing {
println!(" {}: {}", t.label, t.path.display());
}
if !skip_confirm {
print!("\nAre you sure? [y/N] ");
std::io::stdout().flush()?;
let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
if !matches!(input.trim().to_ascii_lowercase().as_str(), "y" | "yes") {
println!("Cancelled.");
return Ok(());
}
}
let mut cleared = false;
let mut errors: Vec<String> = Vec::new();
for t in targets {
match (t.clear)(storage) {
Ok(true) => {
cleared = true;
println!(" Cleared: {}", t.label);
}
// Nothing to clear for this scope.
Ok(false) => {}
Err(e) => {
errors.push(format!("{}: {e}", t.label));
}
}
}
if cleared && errors.is_empty() {
println!("Memory cleared.");
} else if cleared {
println!("Memory partially cleared. Errors:");
for e in &errors {
eprintln!(" {e}");
}
} else if !errors.is_empty() {
eprintln!("Failed to clear memory:");
for e in &errors {
eprintln!(" {e}");
}
return Err(anyhow::anyhow!("clear failed"));
}
Ok(())
}