Skip to content

kud/ding-cli

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TypeScript Node.js npm MIT

A tiny macOS alarm/timer CLI — set a relative or absolute time, get a notification and a sound when it fires

FeaturesQuick StartCLI ReferenceDevelopment

Originally built to remember when Claude's usage quota resets — ding 5h "quota is back" and forget about it.


🌟 Features

  • Relative and absolute times5h, 90m, 1h30m, 30s, 14:30, 2:30pm, 9am; absolute times already past today roll to tomorrow
  • 🔔 Desktop notifications — zero-dependency setup; ships with node-notifier which vendors its own terminal-notifier, no brew install required
  • 🔊 Built-in alarm presets — six synthesised sounds (beep, digital, radar, bell, siren, chime), macOS Clock ringtones (e.g. Radial, Daybreak, Arpeggio), macOS system sounds, or any audio file via afplay
  • 🧙 Interactive wizardding with no arguments launches a tabbed TUI (When · Message · Sound · Notify · Mode · Review); press Space on the Sound step to preview before choosing
  • 🔗 Click-to-open notifications--open https://claude.ai makes the notification banner a shortcut to any URL
  • 🖥 Foreground and detached modes — live countdown with progress bar by default; --detach backgrounds the process and returns the prompt immediately

🚀 Quick Start

Install globally:

npm install -g @kud/ding-cli

Or run without installing:

npx @kud/ding-cli 5h "quota is back"

Set a timer and watch the countdown:

$ ding 90m "tea is ready"
ding → 16:37:22 · tea is ready
01:29:58 ▸ tea is ready

When it fires, the terminal rings (loops the alarm) until you press any key to dismiss, and a desktop notification pops up.


📖 CLI Reference

ding <time> [message] [options]

Time formats

Format Example Meaning
Relative — hours 5h 5 hours from now
Relative — minutes 90m 90 minutes from now
Relative — seconds 30s 30 seconds from now
Relative — compound 1h30m 1 hour 30 minutes from now
Bare number 45 45 minutes from now
24-hour clock 14:30 fires at 14:30 today (or tomorrow if past)
12-hour clock 2:30pm fires at 14:30
Hour only 9am fires at 09:00

Options

Flag Alias Description
--detach -d Background the process; prints fire time then returns the prompt
--sound <value> -s Alarm preset (beep digital radar bell siren chime), macOS Clock ringtone name (e.g. Daybreak; quote names with spaces like "Milky Way"), macOS system sound name (e.g. Glass), or path to an audio file. Default: bell
--no-sound Disable alarm sound entirely
--no-notify Disable desktop notification
--title <text> Notification title (default: ding)
--subtitle <text> Notification subtitle
--icon <path> Absolute path to a custom notification icon image
--open <url> URL to open when the notification banner is clicked
--notify-sound <name> Notification banner sound (e.g. Glass, Ping) — distinct from --sound, which plays via afplay
--icons <mode> Icon set: nerd (default, requires Nerd Font), emoji, or ascii. Also set via DING_ICONS env var
-i / --interactive Force-launch the interactive wizard
--help -h Show help
--version -V Show version

Examples

# Relative timer with a message
ding 90m "tea is ready"

# Absolute time
ding 14:30 "stand-up"

# Fires at 9 am — rolls to tomorrow if 9 am has already passed
ding 9am

# Open claude.ai when the notification is clicked
ding 5h "quota is back" --open https://claude.ai --subtitle "Anthropic"

# Background the process, return the prompt immediately
ding 5h "quota is back" --detach

# Silent notification (no alarm sound)
ding 30m "check the oven" --no-sound

# macOS Clock alarm ringtone (played locally via afplay; quote names with spaces)
ding 5h "wake" --sound Daybreak
ding 5h "wake" --sound "Milky Way"

# Notification banner's own macOS sound (separate from the afplay alarm)
ding 30m "stand-up" --notify-sound Glass

# Custom audio file
ding 20m "deploy done" --sound ~/Downloads/alert.aiff

# Use emoji icons (no Nerd Font required)
ding 5m "test" --icons emoji

# Or set permanently in your shell profile
export DING_ICONS=emoji

Recipe: ring when Claude's usage quota resets

ding was born to time Claude's 5-hour usage window — but instead of guessing 5h, read the exact reset time from ccusage, which parses Claude Code's local logs. Pipe its active-block remainingMinutes straight into ding:

mins=$(ccusage blocks --active --json --offline | node -e 'const {blocks=[]}=JSON.parse(require("node:fs").readFileSync(0));const a=blocks.find(b=>b.isActive);process.stdout.write(String(a?.projection?.remainingMinutes??""))')
[ -n "$mins" ] && ding "${mins}m" "Claude quota is back 🎉"

--offline keeps it fast (no network), and remainingMinutes is already relative, so there is no timezone maths to get wrong.

Interactive wizard

Running ding with no time argument (or with -i) launches a tabbed wizard:

ding  When · Message · Sound · Notify · Mode · Review

Navigate between tabs with / . On the Sound step, use / to browse presets, macOS Clock ringtones, and system sounds, and press Space to preview a sound before confirming with .

Icon sets

The countdown display and fired state use glyphs from the active icon set:

Mode Activate Requires
nerd default a Nerd Font-patched terminal font
emoji --icons emoji or DING_ICONS=emoji any modern terminal
ascii --icons ascii or DING_ICONS=ascii nothing

--icons takes precedence over DING_ICONS. If your font is not Nerd Font-patched, add export DING_ICONS=emoji to your shell profile.

Foreground mode (default)

Without --detach, the terminal renders a live countdown. When the timer fires it rings continuously until you press any key:

$ ding 5m "quota is back"
ding → 16:42:00 · quota is back
04:59:58 ▸ quota is back

Detach mode

$ ding 5h "quota is back" --detach
ding → 21:00:00 (detached)
$

The process runs silently in the background and fires the notification and alarm at the target time — no terminal required.


🔧 Development

ding-cli/
├── src/
│   ├── index.ts          # CLI entry point and argument definitions
│   ├── countdown.ts      # Foreground countdown rendering loop
│   ├── detach.ts         # Background process spawning
│   ├── icons.ts          # Icon sets (nerd / emoji / ascii)
│   ├── notify.ts         # Desktop notification wrapper
│   ├── parse-time.ts     # Relative and absolute time parsing
│   ├── preview-sound.ts  # Sound preview during wizard
│   ├── sounds.ts         # Alarm presets (WAV synthesis) + system sound resolution
│   ├── ui/               # TUI primitives (tabs, footer hints)
│   └── wizard/           # Interactive wizard (Ink/React)
└── dist/                 # Compiled output (tsup → ESM)

Scripts

Command Description
npm run dev Run from TypeScript source via tsx
npm run build Compile to dist/ with tsup
npm run build:watch Watch mode compilation
npm run typecheck TypeScript type-check without emitting
npm run lint ESLint
npm run format Prettier

Setup

git clone https://github.com/kud/ding-cli.git
cd ding-cli
npm install
npm run dev -- 5s "test alarm"

After npm link, the ding binary resolves to the compiled dist/index.js (run npm run build first).


🏗 Tech Stack

Package Role
ink React renderer for the terminal
@inkjs/ui Text input and select components
citty CLI argument parsing
node-notifier macOS desktop notifications (vendors terminal-notifier)
chalk Terminal colour output
tsup ESM build
tsx TypeScript execution for development

MIT © kud — Made with ❤️

About

A tiny macOS alarm/timer CLI — set a relative or absolute time, get a notification and a sound when it fires

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors