- Add parse_date_arg() to utils.py supporting YYYY-MM-DD, MM-DD, and
DD-MM formats with either - or / as separator
- Add AmbiguousDateError for two-part dates valid as both MM-DD and DD-MM
- Replace --day flag with a positional optional argument (defaults to today)
- Remove old _parse_date() helper from cli.py
- Add joplin.py with fetch_week_note() that walks Work > Timesheets > YYYY
and returns the body of the matching YYYY-WNN note via joppy ClientApi
- Add filter_rows_by_date() to parser.py to extract only rows belonging
to a specific day based on '# ... YYYY-MM-DD' headings in the document
- Update cli.py: input and --joplin are now a mutually exclusive required
group; add --token flag with JOPLIN_TOKEN env var fallback; --date is
parsed into a real date object used for both output and day filtering
- Add joppy as a runtime dependency (lazy-imported in cli.py)
- Add tests for filter_rows_by_date and full mocked coverage of joplin.py
- Update AGENTS.md with Joplin usage, notebook structure, and test rules
The actual Joplin structure has notes directly inside the year notebook
(Work > Timesheets > YYYY), not in per-week sub-notebooks as initially
assumed. fetch_week_note() reflects this flat structure.
- Add extract_table_blocks() to split a document into contiguous table
blocks, ignoring prose, headings, and blank lines between them
- Add parse_document() as the new top-level entry point that runs
extract_table_blocks + detect_has_duration_column + parse_table per
block and returns a combined flat list of rows
- Guard against empty End cells (e.g. in-progress rows) by validating
the end field before calculating duration
- Update cli.py to use parse_document() instead of the manual
detect + parse combo
- Add tests for extract_table_blocks and parse_document, including two
smoke tests against the real 2026-W21 weekly timesheet file