@drakulavich/oura-cli 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,40 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.5.2] - 2026-09-06
10
+
11
+ ### Fixed
12
+ - `db trends N` covers N calendar days ending today; it used to include one day more than the heading claimed. (#52)
13
+ - `report` no longer averages a day whose activity is still accumulating as if it were complete. A day counts as complete once it is over in the report timezone and the ring has uploaded past its end (the newest heart-rate sample in the cache is the proxy); activity and steps averages, the high-activity pattern and the steps recommendation stop at the last complete day, while sleep and readiness — final once they exist — still use the whole window. The partial day stays in the daily table, marked `*`, with one line explaining it. (#57)
14
+ - A 401/403 from the Oura API carries a hint (`oura-cli login` with a fresh token), like a missing token already did. (#54)
15
+
16
+ ### Changed
17
+ - `manifest`: `healthcheck.expects` lists the `error` field that `healthcheck` emits when `ok` is false. (#54)
18
+ - `report` JSON: `days[].partial`, `completeThrough`, `lastUpload` and `averages[].count` are added; nothing is removed or renamed. (#57)
19
+ - README's automation section no longer claims JSON Schemas for every output shape (they cover `fetch` and `doctor`), explains that `doctor` and `healthcheck` exit 0 with `ok: false` when the probe itself ran, and records two quirks kept for compatibility: `report --period month` returns `weekStart`/`weekEnd`, and `heartrate.day` is the date written in Oura's timestamp, UTC in practice. (#54)
20
+
21
+ ## [0.5.1] - 2026-09-05
22
+
23
+ Fixes from the 0.5.0 exploratory testing sessions: the seam between citty and the command runner, and the sync window.
24
+
25
+ ### Changed
26
+ - `sync` JSON: `import.counts` is replaced by `import.fetched` (rows the API returned per table) and `import.added` (net growth: days or samples the table did not hold before; a revised row for a day already stored counts as fetched, not new). The text summary prints `sleep 28 (+0)` in the same spirit, so a repeat run no longer looks like it imported 28 days. (#51)
27
+ - `sync --from YYYY-MM-DD [--to YYYY-MM-DD]` re-fetches an explicit window for every collection, for recovery after an interrupted run or a deliberate backfill. `--to` defaults to today and requires `--from`. (#53)
28
+
29
+ ### Fixed
30
+ - `sync` resumes every collection from its own last stored day instead of a single watermark taken from the three daily tables. A run interrupted after those tables (Ctrl-C, a crash) used to advance the watermark and leave the other six collections with a permanent gap that no later sync could fill. (#53)
31
+ - First sync fetches exactly 30 inclusive days, as documented, not 31. (#46)
32
+ - `fetch sleep-periods --day D` and `sync` no longer miss the requested day's sleep periods, and `fetch workout --from A --to B` no longer drops workouts on day B: Oura treats `start_date` as exclusive for `sleep` and `end_date` as exclusive for `workout`, and the request bounds are now shifted accordingly. (#58)
33
+ - Two `oura-cli` processes on the same cache no longer fail with `database is locked`: connections wait up to 5 s for a lock, `PRAGMA journal_mode = WAL` is only issued when the file is not already in WAL mode (that statement itself needs an exclusive lock), and a lock that does outlast the wait reports a hint naming the cause. (#56)
34
+ - `~/.oura-cli/` and a newly created cache file are created with `0700` / `0600` permissions, matching the token file; existing files are left alone. (#60)
35
+ - `doctor --offline` reports the token check as `skip` rather than `ok`. The new status keeps `ok: true` and produces no next step, but an agent gating on the JSON can now tell "not checked" from "passed"; `docs/schemas/doctor.json` lists the value. (#59)
36
+ - README: bundle size, the sync wording above, the token-missing message shape, and the `fetch sleep` pipe example, which read a readiness contributor (`hrv_balance`) off the sleep collection and printed `null` for every row. (#62)
37
+ - A token containing whitespace or a line break (for example a token file with a second line) is rejected as `TOKEN_INVALID` (exit 2) naming the source; previously it reached the API layer and came back as `UNKNOWN` with the token quoted in the message. Every error message and hint is now passed through the secret redactor. (#47)
38
+ - `DB_ERROR` (exit 4) is reachable: a corrupt cache file, an unusable `--db` path or a failing query in `db *`, `sync` and `report` now report `DB_ERROR` with a hint instead of `UNKNOWN` / exit 1. (#48)
39
+ - Errors raised before a command runs — unknown command, missing positional, no command on a pipe — use the same envelope as every other error: JSON on stderr when piped, text on a TTY, nothing on stdout, `--no-color` honoured. The commands removed in 0.5.0 (`db reset`, `db import`, `sleep|readiness|activity|hr|spo2|stress|workout …`) point at `fetch`/`sync`. `--help` and a bare `oura-cli` on a TTY still show usage, and `--version` now answers even when other flags are present (it used to exit 1 with usage unless it was the only argument), but not when it sits in another flag's value position. (#49)
40
+ - Undeclared flags and extra positionals are `BAD_ARGS` instead of being ignored, for every command including `describe`, `manifest`, `healthcheck` and `login`: `fetch sleep --dayz 7` no longer returns today's data with exit 0, and `db trends -5` no longer falls back to the 30-day default. (#50, part of #52)
41
+ - Global flags placed before the subcommand are no longer moved past a `--` separator, and `oura-cli constructor` (any `Object.prototype` name) is an unknown command instead of a silent exit 0.
42
+
9
43
  ## [0.5.0] - 2026-09-05
10
44
 
11
45
  ### Breaking
@@ -307,6 +341,9 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
307
341
  - Local SQLite cache at `~/.oura-cli/oura.db`.
308
342
  - Auth via `oura-cli login`, `OURA_TOKEN`, `OURA_TOKEN_PATH`, or `~/.oura-token`.
309
343
 
344
+ [0.5.2]: https://github.com/drakulavich/oura-cli/releases/tag/v0.5.2
345
+ [0.5.1]: https://github.com/drakulavich/oura-cli/releases/tag/v0.5.1
346
+ [0.5.0]: https://github.com/drakulavich/oura-cli/releases/tag/v0.5.0
310
347
  [0.4.4]: https://github.com/drakulavich/oura-cli/releases/tag/v0.4.4
311
348
  [0.4.3]: https://github.com/drakulavich/oura-cli/releases/tag/v0.4.3
312
349
  [0.4.2]: https://github.com/drakulavich/oura-cli/releases/tag/v0.4.2
package/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
  - **Offline-first.** Everything caches into `~/.oura-cli/oura.db` after one `oura-cli sync`. Reports keep working when your internet doesn't.
18
18
  - **Real terminal reports.** `oura-cli report` writes a weekly or monthly digest with averages, trend deltas, and "you slept poorly Tuesday" callouts. No dashboards, no logging in.
19
19
  - **Pipe-friendly.** Output auto-switches to stable JSON when stdout isn't a terminal. Analyse with `jq`, plot with `gnuplot`, or feed it into your own scripts.
20
- - **Single 100 kB binary, MIT, no telemetry.** Built on Bun; zero native dependencies.
20
+ - **Single ~110 kB binary, MIT, no telemetry.** Built on Bun; zero native dependencies.
21
21
 
22
22
  ## Install
23
23
 
@@ -50,18 +50,18 @@ Four commands get you there:
50
50
  ```bash
51
51
  oura-cli login # paste your PAT — input is hidden, nothing echoes to the terminal
52
52
  oura-cli doctor # confirm the token works and the local database is ready
53
- oura-cli sync # first sync backfills the last 30 days; later syncs are incremental
53
+ oura-cli sync # first sync fetches the last 30 days; later syncs resume from the last stored day
54
54
  oura-cli report # weekly digest in the terminal
55
55
  ```
56
56
 
57
- Subsequent `oura-cli sync` only pulls new days, and `oura-cli db today` / `oura-cli db week` read the local cache instantly, no API call.
57
+ Subsequent `oura-cli sync` re-fetches each collection from its own last stored day (Oura revises recent days, so the overlap is deliberate) and reports rows fetched (+new). `oura-cli sync --from 2026-08-01 [--to 2026-08-07]` re-fetches an explicit window for every collection instead — for example after an interrupted sync. `oura-cli db today` / `oura-cli db week` read the local cache instantly, no API call.
58
58
 
59
59
  ### If something looks wrong
60
60
 
61
61
  | What you see | What to run |
62
62
  |---|---|
63
63
  | `No Oura data is available for this report yet.` | `oura-cli sync` |
64
- | `No Oura access token at ~/.oura-token` | `oura-cli login` |
64
+ | `No Oura access token at /…/.oura-token` | `oura-cli login` |
65
65
  | `Oura API 401` | `oura-cli login` with a fresh PAT |
66
66
  | `db today` empty right after a sync | Normal — Oura publishes a day's summary after that night's sleep syncs from the ring. |
67
67
  | Anything else | `oura-cli doctor` |
@@ -96,7 +96,7 @@ oura-cli report # weekly (default)
96
96
  oura-cli report --period month # 30-day window with weekly buckets
97
97
  ```
98
98
 
99
- Reports cover daily scores, averages, deltas vs the previous window, sleep details, and a short recommendation block.
99
+ Reports cover daily scores, averages, deltas vs the previous window, sleep details, and a short recommendation block. A day whose activity is still accumulating (today, or the last day before the ring stopped syncing) is shown with a `*` and kept out of the activity averages and recommendations; the JSON says so via `days[].partial` and `completeThrough`.
100
100
 
101
101
  ### Trends and stats
102
102
 
@@ -123,7 +123,7 @@ Collections: `sleep readiness activity hr spo2 stress workout sleep-periods cv-a
123
123
  Output auto-switches to JSON the moment you pipe it:
124
124
 
125
125
  ```bash
126
- oura-cli fetch sleep --days 7 | jq '.[] | {day, score, hrv: .contributors.hrv_balance}'
126
+ oura-cli fetch sleep --days 7 | jq '.[] | {day, score, deep: .contributors.deep_sleep}'
127
127
  oura-cli db trends 90 > trends.json
128
128
  ```
129
129
 
@@ -163,17 +163,19 @@ This tool reads your personal health data — handle the token with care.
163
163
  | Sleep model | Oura V2 `sleep` | `sleep_model` |
164
164
  | Cardiovascular age | Oura V2 `cardiovascular_age` | `cardiovascular_age` |
165
165
 
166
- Runtime: [Bun](https://bun.sh). Storage: built-in `bun:sqlite`. CLI parsing: [citty](https://github.com/unjs/citty). Output styling: [chalk](https://github.com/chalk/chalk). One 100 kB `dist/index.js`, no native deps.
166
+ Runtime: [Bun](https://bun.sh). Storage: built-in `bun:sqlite`. CLI parsing: [citty](https://github.com/unjs/citty). Output styling: [chalk](https://github.com/chalk/chalk). One ~110 kB `dist/index.js`, no native deps.
167
167
 
168
168
  ## Automation (LLM agents, scripts, MCP)
169
169
 
170
170
  If you're driving the CLI from a script or LLM harness:
171
171
 
172
172
  - `oura-cli describe` — JSON manifest of every command, argument, and output schema. Agents discover capabilities without scraping `--help`.
173
- - `oura-cli healthcheck` — `{ok, version, latencyMs}` JSON for liveness probes.
173
+ - `oura-cli healthcheck` — `{ok, version, latencyMs}` JSON for liveness probes, plus `error` when `ok` is false.
174
+ - Gate on `.ok`, not on the exit code: `doctor` exits 0 with `ok: false` for any warning-level check (no data yet, stale data, Oura API unreachable), and `healthcheck` exits 0 with `ok: false` for an unusable database (the probe itself ran). `doctor --offline` skips the token-validation call, and a skipped check still counts towards `ok`.
174
175
  - Errors emit a stable JSON envelope on stderr: `{"error":{"code":"…","message":"…","hint":"…"}}`.
175
176
  - Documented exit codes: `0` success, `1` user error, `2` auth, `3` API, `4` storage.
176
- - JSON Schemas under [`docs/schemas/`](docs/schemas/) describe every output shape, semver-stable. Per-collection schemas pin the identity fields (`id`, `day`, `timestamp`) and allow the rest of the Oura record through unchanged, so new upstream fields never break validation.
177
+ - JSON Schemas under [`docs/schemas/`](docs/schemas/) cover `fetch <collection>`, `doctor` and the `describe` manifest itself, semver-stable; `describe` names the schema next to each command. Per-collection schemas pin the identity fields (`id`, `day`, `timestamp`) and allow the rest of the Oura record through unchanged, so new upstream fields never break validation. The local-data commands (`sync`, `db *`, `report`) have no schema files yet; their shapes are versioned through the CHANGELOG.
178
+ - Two contract quirks, kept for compatibility: `report --period month` returns its window as `weekStart`/`weekEnd`, and `heartrate.day` in the cache is the date written in Oura's timestamp (UTC in practice) while every `--day`/`--tz` argument is local.
177
179
 
178
180
  Plays cleanly with [OpenClaw](https://github.com/openclaw/openclaw) — `oura-cli manifest` returns the tool-registry shape. A first-party `oura-mcp` companion is on the roadmap.
179
181