20 Commits
Author SHA1 Message Date
skkeyeandClaude Opus 5.5 253d72221b Mark times on the day before a work day as -1
A time on the day after its work day shows "+1" (a night shift ending at
04:10 +1). A time on the day before, which a start backdated across
midnight can produce, showed "+-1". It now shows "-1", on the Days
screen and in Markdown reports.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 00:25:36 -04:00
skkeyeandClaude Opus 5.5 ae9e1b1f08 Show session lengths in ten categories
The Focus view grouped sessions into six buckets, too coarse to see a
rhythm. There are now ten: under 5m, 5-15m, 15-25m, 25-45m, 45m-1h,
1h-1h30m, 1h30m-2h, 2-3h, 3-4h and 4h or more. 25 minutes is a classic
pomodoro, and the long end separates 3-4h stretches from 4h+ hyperfocus.

Ten labelled columns don't fit side by side, so the chart is now drawn
with horizontal bars: every label stays readable at any width.

The buckets are one constant (analysis::focus::SESSION_BUCKETS); a new
test pins down where sessions land, including an exact boundary.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 00:25:14 -04:00
skkeyeandClaude Opus 5.5 49e14b820a Add paid pomodoro breaks
Some jobs pay for breaks, so a pomodoro break shouldn't take time off
the workday. By default (new setting `paid_breaks`, in [reminders]), b
on the Tracker, zb anywhere or :break starts a pomodoro break WITHOUT
pausing the shift: the break stays in your worked time and the data
file isn't touched. b (or s) brings you back to focus. With the setting
off, b pauses the shift like p. p and e always stop the clock.

For the rhythm, a paid break still counts as a break: reminders::PaidBreaks
keeps them in memory and pomodoro() cuts them out of the focus stretches,
the same way as a pause. Stopping the shift ends a paid break, and
closing the work day forgets them.

The Tracker shows "on a paid break" and the paid break's progress, and
the nudges name the right key (b or p/s).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 00:06:26 -04:00
skkeyeandClaude Opus 5.5 fe5e2d9a7f Accept date shortcuts in the Work day field
Adding work to a day you forgot to track meant typing its full date.
The Work day field now also takes 09-14 (this year), today, yesterday,
-3 (three days ago) and weekday names like mon or friday (the most
recent one). The editor shows the date it understood next to the field.

The parsing lives in time::format::parse_date, next to parse_time.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 00:02:43 -04:00
skkeyeandClaude Opus 5.5 9257181a77 Fix added work landing on the wrong day
When another date was typed in the segment editor's Work day field, the
segment was filed under that date but its times were still placed around
the original day (usually today). A segment filed under Sep 14 could run
on Sep 24.

The editor now reads the Work day field first and places the typed times
on that day: next to its existing work, or around noon on an empty day.
Moving an existing segment to another work day moves its times with it,
keeping the same clock times.

The test helper also learns <Tab> and <BS>, and a regression test adds
work both from the Days list and by typing another date.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 00:01:40 -04:00
skkeyeandClaude Opus 5.5 38f14fa453 Keep LF line endings on every OS
The same repository is used on Windows, Void and Fedora; .gitattributes
stops Git from converting files to CRLF on Windows checkouts.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:35 -04:00
skkeyeandClaude Opus 5.5 c21b720eea Add cargo linux to build a static Linux binary from any OS
Builds for x86_64-unknown-linux-musl with rust-lld. The result is fully
static, so the same file runs on Void (glibc or musl) and Fedora. The
linker is set inside the alias, not globally, so native builds on
Void-musl keep their usual linker.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:23 -04:00
skkeyeandClaude Opus 5.5 235c4f0ad5 Add a README: building, everyday keys, files and code map
How to build on Windows, Void and Fedora, the keys to know, how work
days behave past midnight, where the files are, and how the code is
organized (with the two most common changes: keys and settings).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:23 -04:00
skkeyeandClaude Opus 5.5 89c5279f52 Add the app core and the real entry point
app.rs holds everything and runs the loop: keys become commands, the
screen turns them into actions, and App::apply is the only place data
changes. Journal edits happen on a copy, are undoable, saved atomically
and rolled back if saving fails. It also runs the reminders and picks
up outside edits of shifts.toml every second.

main.rs loads the settings, takes the lock, makes the daily backup and
starts the UI; --config, --paths, --help and --version.

The tests drive the whole app with fake key presses and draw every
screen and popup at several sizes in an in-memory terminal.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:23 -04:00
skkeyeandClaude Opus 5.5 57ea9403b6 Add the Tracker, Days, Insights and Settings screens
- Tracker: big running timer, pomodoro line, clickable buttons, today's
  progress and timeline, this week.
- Days: work days grouped by week, the selected day's details, timeline
  and segments to edit, add, delete and copy.
- Insights: overview cards and charts, calendar heatmap, weekday x hour
  rhythm, session lengths and breaks.
- Settings: generated from the settings table; expert settings are
  folded away (za).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:22 -04:00
skkeyeandClaude Opus 5.5 255dcd1392 Add popups: segment editor, copy menu, export, help and command line
- segment_editor: type start/end times; the exact moments they mean are
  shown live, and invalid edits keep the popup open.
- time_prompt: "I started / paused / ended the day at...".
- copy_menu: every copy preset with a preview of what will be pasted.
- export_dialog, still_working (for sessions left running very long),
  help (generated from the key tables) and the `:` command line.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:22 -04:00
skkeyeandClaude Opus 5.5 7c8a02275e Add the UI foundation: vim keymap, widgets and the component contract
- keymap: every key sequence in vim notation (gg, yy, <C-a>,
  <Space>s), with counts (5j), per-screen overrides and which-key hints,
  all from the same tables.
- Component: the one trait for screens and popups. They only look at
  the data through a Context and answer with Actions.
- Action: everything a screen can ask the app to do.
- widgets: big digits, buttons, a day timeline, a heatmap, a text field.
- ui/mod.rs: tabs, status line and the which-key popup; terminal.rs sets
  the terminal up (and restores it after a crash).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:22 -04:00
skkeyeandClaude Opus 5.5 eff7834838 Add storage: config.toml, shifts.toml, backups and a lock
- config.toml is written from the settings table, with each help text as
  a comment; mistakes in it become warnings, never a crash.
- shifts.toml is plain, hand-editable TOML. Reading checks every journal
  rule and reports mistakes with the day and segment. Edits made while
  skyshift runs are reloaded; a broken file is never overwritten.
- Saves are atomic (temp file + rename), a copy is kept once a day, and
  a file lock stops two copies of skyshift from using the same data.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:22 -04:00
skkeyeandClaude Opus 5.5 cc8e6abc4f Add the settings catalog
Every setting is described once in FIELDS: its config.toml section and
key, label, help text, whether it's an expert setting, and how to read
and write it as text. The config file and the Settings screen are both
generated from this table, so adding a setting is one field, one
default and one table entry.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:22 -04:00
skkeyeandClaude Opus 5.5 35d55c5122 Add pomodoro-style reminders
Advice only: it reads your real Start/Pause presses and says when a
break (or getting back) fits the rhythm. Interruptions shorter than a
short break don't reset a focus stretch; every Nth completed stretch
earns a long break.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:22 -04:00
skkeyeandClaude Opus 5.5 97f834a299 Add exports: timesheet copy presets, clipboard and report files
- timesheet: copy presets (total H:MM, decimal hours, segments,
  in/out/break as tab-separated cells, custom template) with optional
  rounding to a step.
- clipboard: system clipboard (Windows, X11, Wayland), falling back to
  the terminal's OSC 52, or a custom command like wl-copy.
- csv, json, markdown: report files for a range of dates. CSV uses ';'
  when the decimal separator is ','; the Markdown report has a summary
  and one padded table per week.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:21 -04:00
skkeyeandClaude Opus 5.5 a646337339 Add analysis for the Insights views
Plain data computed from the work days, nothing about drawing:

- overview: week/month totals, balance against the daily target, weekly
  totals, and when days start and end (past 24h for night shifts).
- calendar: time worked per date, as weeks x weekdays.
- rhythm: time worked per weekday and hour, split at hour boundaries.
- focus: session lengths, long sessions (hyperfocus), breaks, days that
  went past midnight.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:21 -04:00
skkeyeandClaude Opus 5.5 3fdd635af0 Add the domain: segments, work days and the journal
The rules, with no files and no UI:

- Segment: one stretch of work; it can only be built with end > start.
- WorkDay: segments filed under one date, even past midnight.
- Journal: every work day plus what's happening now (Idle, OnBreak,
  Working). Start opens a work day that stays open until End day; a
  break longer than a setting opens a new day (the safety net for a
  forgotten End day). Segments never overlap, even across days.
- snapshot(): the days with the running session included, so analysis
  and export never special-case it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:21 -04:00
skkeyeandClaude Opus 5.5 7bbc1ee0fa Add the time module: clock, 12h/24h text and typed times
- clock: the system clock, with a time zone override (name or fixed
  offset) and a manual adjustment; Start/Pause record whole minutes so
  displayed times and totals always add up.
- format: every time, date and duration shown in the app goes through
  Formatter (12h/24h, 7h 45m / 7:45 / 7.75); parse_time reads both 12h
  and 24h input (22:30, 2230, 22h30, 10:30pm, 10p).
- resolve: turns a typed "01:30" into the moment meant, so an end time
  before the start is the next day (night shifts).
- range: date ranges (week, month, last N days).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:21 -04:00
skkeyeandClaude Opus 5.5 f646da0a8e Set up the skyshift Cargo project
A terminal app (ratatui) to track work shifts, built on stable Rust,
edition 2024.

- Cargo.toml: eight well-known crates, each with a comment saying why:
  ratatui (UI), jiff (dates and time zones), serde + toml + serde_json
  (files), directories (per-OS folders), arboard (clipboard), anyhow.
- .cargo/config.toml: static C runtime on Windows, so the .exe runs
  without the Visual C++ Redistributable; `cargo lint` alias.
- rustfmt.toml: one formatting style for `cargo fmt`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 02:59:21 -04:00