Skip to content

pfei/tomate-cli

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

78 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ… tomate-cli

A robust Pomodoro timer for the terminal β€” built with TypeScript and Ink (React for TUI).

screenshot


Features

  • Reactive TUI β€” built with Ink (React component tree rendering to the terminal)
  • Pomodoro cycles with short/long breaks, fully configurable
  • Keyboard-driven config menu β€” no prompts, pure arrow-key navigation
  • Task labeling: tag sessions with --task <name> to track time per project
  • Time report grouped by task (--report, or --report-json pipeable to jq)
  • Session statistics: total Pomodoros, average durations, break times
  • Desktop notifications via notify-send (Linux, optional)
  • Sound notifications via ffplay (optional, graceful fallback if unavailable)
  • tmux bell on session end β€” works headless, no display required
  • Persistent config and metrics (JSON files, paths configurable)
  • Tested core logic with Vitest (48 tests)

Quick Start

Requirements

  • Node.js v18+
  • Unix-like shell (Linux, macOS, or WSL2 on Windows)
  • notify-send (optional, for desktop notifications β€” libnotify-bin on Debian/Ubuntu)
  • ffplay (optional, for sound β€” ffmpeg package)

Install

git clone https://github.com/pfei/tomate-cli.git
cd tomate-cli
npm install
npm run build

Run

node ./dist/main.js
# or with a task label:
node ./dist/main.js --task myproject

To install globally:

npm install -g .
tomate --task myproject

Controls

Key Action
p or space Pause / Resume
s (Γ—2) Skip current session (no metrics recorded)
c Open config menu
q Quit

CLI Reference

Usage: tomate [options]

Options:
  --help                    Show help and exit
  --task <name>             Label sessions for time tracking
  --stats                   Show productivity stats
  --report                  Show time report grouped by task
  --report-json             JSON report, pipeable to jq
  --reset-config            Reset config to defaults
  --config-path <path>      Custom config file path
  --metrics-path <path>     Custom metrics file path
  --show-paths              Print config and metrics paths

Examples

# Start a labeled session
tomate --task myproject

# View stats
tomate --stats

# View task report
tomate --report

# JSON report sorted by time spent
tomate --report-json | jq '
  to_entries
  | sort_by(-.value.totalDecimalHours)
  | map({task: .key, sessions: .value.sessions, duration: .value.totalTimeHours})
'

Configuration

Config and metrics are stored as JSON in ~/.config/tomate-cli/ by default.

# Use custom paths
tomate --config-path ~/myconfigs/tomate-config.json \
       --metrics-path ~/myconfigs/tomate-metrics.json

# Persist custom paths across sessions
tomate --set-config-path ~/myconfigs/tomate-config.json
tomate --set-metrics-path ~/myconfigs/tomate-metrics.json

Useful for syncing config/metrics with cloud storage or keeping multiple profiles.


VPS / Headless usage

tomate-cli works on headless servers (no display required):

  • Sound and desktop notifications are automatically skipped when $DISPLAY and $WAYLAND_DISPLAY are unset
  • tmux bell fires on session end β€” configure tmux to flash the status bar:
# ~/.tmux.conf
set -g visual-bell on
set -g bell-action any

Windows

This project uses Unix shell commands in its build scripts (rm -rf, etc.). Windows users must use WSL2 β€” native Windows shells are not supported.


Development

npm test              # run tests (48 tests, Vitest)
npm run coverage      # test coverage
npm run lint          # ESLint
npm run format        # Prettier
npm run build         # compile TypeScript -> dist/
npm run bundle        # build + ncc single-file bundle -> bundle/

Architecture

src/
β”œβ”€β”€ main.ts              # CLI entry point β€” flag parsing, render(<App>)
β”œβ”€β”€ core/
β”‚   └── state.ts         # shared timer state (closure pattern)
β”œβ”€β”€ ui/
β”‚   β”œβ”€β”€ App.tsx          # root component β€” screen routing (timer/config/timeup)
β”‚   β”œβ”€β”€ TimerScreen.tsx  # countdown, keyboard input, live state sync
β”‚   β”œβ”€β”€ ConfigScreen.tsx # keyboard-driven config menu (ink-select-input)
β”‚   └── TimeUpScreen.tsx # session-end screen with tmux bell
└── utils/
    β”œβ”€β”€ config.ts        # load/save config (Zod validation)
    β”œβ”€β”€ metrics.ts       # session recording and aggregation
    β”œβ”€β”€ sound.ts         # ffplay wrapper with headless fallback
    └── notifications.ts # notify-send wrapper with headless fallback

State management: a single _state object lives in a closure in core/state.ts. Ink components hold local React state (useState) for rendering, and sync from _state via a polling interval. This keeps the React component tree decoupled from the global timer state.


Dependencies

Package Purpose
ink React renderer for terminal UI
react Component model and state management
ink-select-input Keyboard-driven select menu
zod Config schema validation
chalk Terminal colors
boxen Boxed output for stats display
date-fns Date formatting for metrics

Author

Pierre Feilles β€” github.com/pfei


License

MIT

About

πŸ… A robust Pomodoro CLI timer with session labeling, detailed metrics, and customizable configuration. Built with TypeScript and Vitest.

Topics

Resources

License

Stars

Watchers

Forks

Contributors