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 CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This is the **shelltime installation** repository - a collection of shell script

- `install.bash` - Main installation script that downloads shelltime CLI binaries and sets up shell hooks
- `cloud.bash` - Setup for Claude Code cloud environments, run from an environment's setup script with `curl -fsSL https://raw.githubusercontent.com/shelltime/installation/main/cloud.bash | bash`. Installs the Linux CLI and daemon into `~/.shelltime/bin`, runs `shelltime cc install`, and adds a Claude Code SessionStart hook (`~/.shelltime/bin/cloud-session-start.sh`, embedded in the script) that signs in and starts the daemon in each session. The token is a network secret of the environment (host `api.shelltime.xyz`, header `Authorization`, prefix `CLI`) that Anthropic's agent proxy adds to requests outside the VM, so the hook signs in with the placeholder `proxy-injected` (the CLI then sends no `Authorization` header; needs a CLI release with `model.ProxyInjectedToken`). `SHELLTIME_TOKEN` in the environment variables, for environments without network secrets, replaces the placeholder. Setup scripts get neither. It installs nothing unless `CLAUDE_CODE_REMOTE` is `true`, which cloud environments set (the setup script inherits it from `environment-manager`) and which is never true on a user's own machine. A setup script that exits non-zero stops sessions from starting, so it always exits 0 (its `EXIT` trap reports a failure instead), and nothing runs before the final `main` call, so a truncated download installs nothing. The guide that documents it is `content/blogs/track-claude-code-cloud-sessions/` in the web repo; keep the two in step
- `hooks/` - Shell-specific hook scripts that track command execution:
- `hooks/` - Shell-specific hook scripts that track command execution. They are copies of the CLI's embedded hooks (`model/hooks/` in shelltime/cli, which `shelltime hooks install` and `shelltime init` write over these), so change both together:
- `zsh.zsh` - Uses zsh's native `preexec` and `precmd` hooks
- `bash.bash` - Uses `bash-preexec` library for preexec/precmd functionality
- `fish.fish` - Uses fish's `fish_preexec` and `fish_postexec` events
Expand Down
5 changes: 4 additions & 1 deletion hooks/bash.bash
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ precmd_invoke_cmd() {
local LAST_RESULT=$?
# BASH_COMMAND in precmd is the *previous* command
local CMD="$LAST_COMMAND"
# Consume it. precmd also runs for an empty prompt (the user pressed
# enter), and leaving LAST_COMMAND set would record the same command again.
LAST_COMMAND=""
# Check if command starts with exit, logout, or reboot
if [[ "$CMD" =~ ^(exit|logout|reboot) ]]; then
return
Expand All @@ -68,4 +71,4 @@ precmd_invoke_cmd() {

# Set the functions for bash-preexec
preexec_functions+=(preexec_invoke_cmd)
precmd_functions+=(precmd_invoke_cmd)
precmd_functions+=(precmd_invoke_cmd)
8 changes: 5 additions & 3 deletions hooks/fish.fish
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
if not command -v shelltime > /dev/null
echo "Warning: shelltime CLI not found. Please install it to enable time tracking."
else
shelltime gc
# Detached from the tty: this runs while fish is still probing the terminal
# (OSC 11 / CPR / DA1) at startup, and must not sit on the input queue.
shelltime gc < /dev/null
end

# Create a timestamp for the session when the shell starts
Expand All @@ -19,7 +21,7 @@ function fish_preexec --on-event fish_preexec
return
end

shelltime track -s=fish -id=$SESSION_ID -cmd="$argv" -p=pre --ppid=$FISH_PPID > /dev/null
shelltime track -s=fish -id=$SESSION_ID -cmd="$argv" -p=pre --ppid=$FISH_PPID < /dev/null > /dev/null 2>&1
end

# Define the postexec function
Expand All @@ -29,5 +31,5 @@ function fish_postexec --on-event fish_postexec
return
end
# This event is triggered before each prompt, which is after each command
shelltime track -s=fish -id=$SESSION_ID -cmd="$argv" -p=post -r=$LAST_RESULT --ppid=$FISH_PPID > /dev/null
shelltime track -s=fish -id=$SESSION_ID -cmd="$argv" -p=post -r=$LAST_RESULT --ppid=$FISH_PPID < /dev/null > /dev/null 2>&1
end
12 changes: 11 additions & 1 deletion hooks/zsh.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ fi
# Create a timestamp for the session when the shell starts
SESSION_ID=$(date +%Y%m%d%H%M%S)

# Set by preexec and consumed by the next precmd. Empty means this prompt
# does not follow a command we tracked (shell startup, or enter on a blank
# line). fc -ln -1 would otherwise repeat the previous history entry.
typeset -g _SHELLTIME_LAST_CMD=""

# Define the preexec function
preexec() {
local CMD=$1
Expand All @@ -19,13 +24,18 @@ preexec() {
return
fi

_SHELLTIME_LAST_CMD=$CMD
shelltime track -s=zsh -id=$SESSION_ID -cmd="$CMD" -p=pre --ppid=$PPID &> /dev/null
}

# Define the postexec function (in zsh, it's called precmd)
precmd() {
local LAST_RESULT=$?
local CMD=$(fc -ln -1)
local CMD=$_SHELLTIME_LAST_CMD
_SHELLTIME_LAST_CMD=""
if [[ -z $CMD ]]; then
return
fi
# Check if command starts with exit, logout, or reboot
if [[ $CMD =~ ^(exit|logout|reboot) ]]; then
return
Expand Down
11 changes: 10 additions & 1 deletion install.bash
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,19 @@ if command_exists shelltime; then
fi
fi

# The command that reloads the user's own shell ($SHELL is the login shell, also
# under `curl | bash`), so the next steps name one file instead of three.
case "$(basename "${SHELL:-}")" in
zsh) reload_cmd="source ~/.zshrc" ;;
bash) reload_cmd="source ~/.bashrc" ;;
fish) reload_cmd="source ~/.config/fish/config.fish" ;;
*) reload_cmd="source ~/.zshrc (or ~/.bashrc / ~/.config/fish/config.fish)" ;;
esac

echo ""
echo "Installation complete!"
echo ""
echo "Next steps:"
echo " 1. Reload your shell: source ~/.zshrc (or ~/.bashrc / ~/.config/fish/config.fish)"
echo " 1. Open a new terminal, or reload this one: ${reload_cmd}"
echo " 2. Run: shelltime init"
echo ""
Loading