fix: add session-heartbeat and session-end CLI commands for hooks

- Add top-level `session-heartbeat` command (silent, touches session file)
- Add top-level `session-end` command (silent, removes session file)
- Add `Heartbeat` variant to SessionCommands enum
- Required by global Claude Code hooks in ~/.claude/settings.json

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Eric Garcia 2026-01-30 10:03:31 -05:00
parent 9170c20c15
commit 607b5ce07c

View file

@ -133,6 +133,14 @@ enum Commands {
#[arg(long)]
tool: Option<String>,
},
/// Session heartbeat (silent, used by hooks)
#[command(name = "session-heartbeat")]
SessionHeartbeat,
/// Session end (silent, used by hooks)
#[command(name = "session-end")]
SessionEnd,
}
#[derive(Subcommand)]
@ -328,6 +336,9 @@ enum SessionCommands {
/// Show session status
Status,
/// Record session heartbeat (used by hooks)
Heartbeat,
}
#[derive(Subcommand)]
@ -533,6 +544,24 @@ async fn main() -> Result<()> {
Some(Commands::Guard { path, tool }) => {
handle_guard_command(&path, tool.as_deref()).await?;
}
Some(Commands::SessionHeartbeat) => {
// Silent heartbeat - touch session file if it exists
let cwd = std::env::current_dir()?;
let session_file = cwd.join(".blue").join("session");
if session_file.exists() {
if let Ok(content) = std::fs::read_to_string(&session_file) {
let _ = std::fs::write(&session_file, content);
}
}
}
Some(Commands::SessionEnd) => {
// Silent session end - remove session file if it exists
let cwd = std::env::current_dir()?;
let session_file = cwd.join(".blue").join("session");
if session_file.exists() {
let _ = std::fs::remove_file(&session_file);
}
}
}
Ok(())
@ -1253,6 +1282,20 @@ async fn handle_session_command(command: SessionCommands) -> Result<()> {
}
}
}
SessionCommands::Heartbeat => {
// Silent heartbeat - just touch the session file to update activity
let cwd = std::env::current_dir()?;
let session_file = cwd.join(".blue").join("session");
if session_file.exists() {
// Touch file by reading and writing back (updates mtime)
if let Ok(content) = std::fs::read_to_string(&session_file) {
let _ = std::fs::write(&session_file, content);
}
}
// Silent success - no output for hooks
}
}
Ok(())