diff --git a/README.md b/README.md index 4ed2371..0a2ee2d 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,14 @@ A Neovim plugin for automatic coding activity tracking. Works with the ShellTime ## Features - **Automatic Time Tracking** - Passively monitors coding activity -- **Language Detection** - Auto-detects programming language from filetype +- **Language Detection** - Uses the buffer's filetype, falling back to the file extension - **Project Analytics** - Tracks time per project/workspace - **Git Integration** - Records activity by git branch -- **Event Debouncing** - Efficient heartbeat batching (30s cooldown per file) -- **Offline Support** - Queues heartbeats when daemon unavailable +- **Debug Detection** - Marks activity as `debugging` while an nvim-dap session is active +- **Debouncing & Batching** - At most one heartbeat per file every 30s (saves always count), sent in batches every 2 minutes +- **Offline Support** - Keeps heartbeats in memory and retries them when the daemon is unavailable +- **Flush on Exit** - Sends pending heartbeats when Neovim quits, so short sessions aren't lost +- **CLI Update Check** - Warns once per session when your ShellTime CLI is out of date ## Prerequisites @@ -44,7 +47,7 @@ This will: ### 3. Enable Code Tracking -Add the following to your ShellTime config (`~/.shelltime/config.yaml`): +Make sure your ShellTime config (`~/.shelltime/config.yaml`) contains: ```yaml codeTracking: @@ -58,10 +61,14 @@ Or in TOML format (`~/.shelltime/config.toml`): enabled = true ``` +Configs created by `shelltime init` already include this; older configs may not. The daemon ignores editor heartbeats unless it is `true`, and it reads the setting at startup, so restart the daemon after changing it (for example with `shelltime daemon reinstall`). + ## Requirements -- Neovim >= 0.10.0 +- Neovim >= 0.10.0 (Neovim only; classic Vim isn't supported) +- ShellTime daemon running (see [Prerequisites](#prerequisites)) - Git (optional, for branch tracking) +- `curl` (optional, for the CLI update check) ## Installation @@ -92,12 +99,14 @@ use { Plug 'shelltime/coding-extension-vim' ``` -Then add to your `init.lua`: +Then add to your `init.lua` (or `lua require("shelltime").setup()` to `init.vim`): ```lua require("shelltime").setup() ``` +Calling `setup()` is required: loading the plugin only registers its commands. With lazy.nvim, `opts = {}` calls it for you. + ## Quick Start 1. **Complete the [Prerequisites](#prerequisites)** - Install CLI, authenticate, and enable code tracking @@ -120,22 +129,28 @@ require("shelltime").setup({ }) ``` +`config` is the only `setup()` option. The plugin reads just this one YAML file: not `config.toml`, `config.yml` or `config.local.*`. If the file is missing, it uses the defaults below. The file is re-read whenever it changes, so most settings apply without restarting Neovim (`heartbeatInterval` needs a restart). + ### Config File Options | Option | Type | Default | Description | |--------|------|---------|-------------| | `socketPath` | string | `/tmp/shelltime.sock` | Unix socket path for daemon | -| `codeTracking.enabled` | boolean | `true` | Enable/disable tracking | +| `codeTracking.enabled` | boolean | `true` | Enable/disable tracking in the plugin. The daemon also requires it to be `true` (see [Prerequisites](#3-enable-code-tracking)) | | `debug` | boolean | `false` | Enable debug logging | +| `heartbeatInterval` | number | `120000` | How often pending heartbeats are sent, in ms | +| `debounceInterval` | number | `30000` | Minimum time between heartbeats for the same file, in ms | +| `apiEndpoint` | string | - | ShellTime API URL used for the CLI update check (written by `shelltime init`) | +| `webEndpoint` | string | - | ShellTime web URL used in the update command (written by `shelltime init`) | ## Commands | Command | Description | |---------|-------------| -| `:ShellTimeStatus` | Show daemon connection status and pending heartbeats | +| `:ShellTimeStatus` | Show daemon connection status (version, uptime, platform) and pending heartbeats | | `:ShellTimeFlush` | Manually flush pending heartbeats to daemon | -| `:ShellTimeEnable` | Enable tracking | -| `:ShellTimeDisable` | Disable tracking | +| `:ShellTimeEnable` | Enable tracking for this session (needs `setup()`; doesn't override `codeTracking.enabled: false`) | +| `:ShellTimeDisable` | Flush pending heartbeats and disable tracking for this session | ## How It Works @@ -143,15 +158,19 @@ The plugin monitors these Neovim events: | Event | Trigger | |-------|---------| -| `BufEnter` | Opening a file | +| `BufEnter` | Opening or switching to a file | | `TextChanged` / `TextChangedI` | Editing text | | `BufWritePost` | Saving a file | | `CursorMoved` / `CursorMovedI` | Moving cursor | +Only regular files are tracked. Special buffers (help, terminal, quickfix, etc.), unnamed buffers, files inside `.git/`, and non-`file://` URLs such as `oil://` or `fugitive://` are skipped. + Heartbeats are: +- **Deduplicated**: Buffer and cursor events at the same file and cursor position as the last event are skipped (edits always count) - **Debounced**: Max 1 heartbeat per file per 30 seconds (except saves) -- **Batched**: Sent to daemon every 2 minutes -- **Queued**: Stored locally if daemon is unavailable +- **Batched**: Sent to the daemon over its Unix socket every 2 minutes +- **Flushed on exit**: Pending heartbeats are sent on `VimLeavePre` (Neovim waits up to 1.5s) +- **Queued**: Kept in memory and retried on the next flush if the daemon is unavailable (up to 5,000; oldest dropped first). They are not written to disk, so they are lost if Neovim exits while the daemon is down ### Data Tracked @@ -161,7 +180,13 @@ Each heartbeat includes: - **Project info**: Name, root path, git branch - **Editor info**: Neovim version, plugin version - **System info**: Hostname, OS, OS version -- **Activity**: Timestamp, whether it was a save event +- **Activity**: Timestamp, whether it was a save event, category (`coding` or `debugging`) + +The project root is the nearest parent directory containing `.git`, `package.json`, `Cargo.toml`, `go.mod`, `pyproject.toml`, `setup.py`, `Makefile`, `CMakeLists.txt`, `.project` or `.root` (otherwise the file's directory). The project name is its last two path segments, e.g. `code/my-app`. + +### CLI Update Check + +On startup, if the daemon is reachable, the plugin asks `/api/v1/cli/version-check` (via `curl`) whether the daemon's CLI version is the latest. If not, it shows a warning once per session with the update command (`curl -sSL /i | bash`) and copies that command to the `+` register when a clipboard is available. The check is skipped when `apiEndpoint` or `webEndpoint` is not set. ## Troubleshooting @@ -169,8 +194,8 @@ Each heartbeat includes: 1. Check if daemon is running: ```bash - ls -la /tmp/shelltime.sock - # If not present, run: shelltime init + shelltime daemon status # socket, running state, and whether Code Tracking is enabled + # If not running, run: shelltime init ``` 2. Verify config file exists: @@ -178,7 +203,7 @@ Each heartbeat includes: cat ~/.shelltime/config.yaml ``` -3. Enable debug mode in config: +3. Enable debug mode in config (messages are shown via `vim.notify`): ```yaml debug: true ``` @@ -191,8 +216,9 @@ Each heartbeat includes: ### Heartbeats not sending Run `:ShellTimeStatus` to check: -- If "Disconnected", ensure daemon is running +- If "Disconnected", ensure daemon is running and `socketPath` matches the daemon's socket - If pending heartbeats > 0, try `:ShellTimeFlush` +- If "Connected" and flushes succeed but no activity shows up, check that `codeTracking.enabled` is `true` for the daemon and restart it. The daemon drops heartbeats otherwise, and the plugin can't tell ## License