@drakulavich/oura-cli 0.4.5 → 0.5.0
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 +65 -0
- package/README.md +44 -17
- package/dist/index.js +1290 -1063
- package/docs/schemas/activity.json +15 -4
- package/docs/schemas/cv-age.json +26 -0
- package/docs/schemas/describe.json +1 -0
- package/docs/schemas/doctor.json +25 -0
- package/docs/schemas/hr.json +10 -3
- package/docs/schemas/readiness.json +15 -4
- package/docs/schemas/sleep-periods.json +26 -0
- package/docs/schemas/sleep.json +15 -4
- package/docs/schemas/spo2.json +15 -4
- package/docs/schemas/stress.json +15 -4
- package/docs/schemas/workout.json +15 -4
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,71 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.5.0] - 2026-09-05
|
|
10
|
+
|
|
11
|
+
### Breaking
|
|
12
|
+
- Per-collection API commands replaced by `fetch <collection>`; `db reset` and `db import` removed. See "Changed" and "Removed" below.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- `sync` fetches heartrate over the same window as every other collection (from the last synced day, or 30 days back on first sync) instead of today only, in pieces of at most 30 × 24 hours because the heartrate endpoint rejects longer ranges; consecutive pieces do not share a boundary instant, so no sample is fetched twice. Days the ring synced while `oura-cli sync` did not run are no longer skipped; the unique `(timestamp, source)` index keeps re-fetched samples from duplicating.
|
|
16
|
+
- README "First five minutes" now leads with a concrete report sample,
|
|
17
|
+
documents `login` → `doctor` → `sync` → `report` as the onboarding path,
|
|
18
|
+
states plainly that `login` hides the token as you type, and adds a
|
|
19
|
+
symptom → command recovery table.
|
|
20
|
+
- Text formatters moved from the repo root into `src/render/` (internal).
|
|
21
|
+
- Every data command runs through one runner that resolves the output format, opens and always closes the database, creates the API client and maps errors to exit codes. `sync` progress lines are printed together with the summary instead of streaming. `--no-color` now takes effect before any output (internal).
|
|
22
|
+
- Token resolution lives in `src/api/token.ts` and is shared by the API client and `doctor`; the two SQLite wrappers merged into `src/db/open.ts` (internal). A whitespace-only token is now rejected as missing instead of being sent as an empty bearer token.
|
|
23
|
+
- Every Oura collection is described once in `src/collections/`; table DDL, inserts and the sync loop derive from it. A test proves the derived DDL matches the shipped migrations (internal).
|
|
24
|
+
- **Breaking:** the seven per-collection commands (`sleep`, `readiness`, `activity`, `hr`, `spo2`, `stress`, `workout` × `today|date|week`) are replaced by `oura-cli fetch <collection> [--day D | --from A --to B | --days N]`. `sleep-periods` and `cv-age` are now fetchable too.
|
|
25
|
+
- `describe` and `manifest` are generated from the registered command tree, so they can no longer drift from the CLI; `manifest` examples that referenced a non-existent `--start` flag are gone.
|
|
26
|
+
- `docs/schemas/<collection>.json` are generated (`bun run schemas`) and checked by a test; added `sleep-periods.json` and `cv-age.json`.
|
|
27
|
+
|
|
28
|
+
### Removed
|
|
29
|
+
- `db reset` and the CSV importer it relied on (it read a hard-coded personal directory), and the `db import` alias of `sync`.
|
|
30
|
+
- `vo2max` no longer appears in `db stats`; the table was never populated. `db stats` now lists tables in registry order (`heartrate` fourth, `cardiovascular_age` last); key by `table`, not position.
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
- `oura-cli doctor` diagnoses token resolution (honoring `--token` like every
|
|
34
|
+
other command), live token validity (skippable with `--offline`), local
|
|
35
|
+
database health, and data freshness across sleep/readiness/activity in one
|
|
36
|
+
pass. `ok` is true only when every check is clean — a warning is enough to
|
|
37
|
+
clear "everything looks healthy". `nextStep` is the first non-ok check's
|
|
38
|
+
fix, so it never recommends a command (like `sync`) that would just hit the
|
|
39
|
+
same root cause (like an unreachable API) a check upstream already found.
|
|
40
|
+
Both `table` and `json` output are supported; the JSON shape is published
|
|
41
|
+
as `docs/schemas/doctor.json`.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
- `fetch --day/--from/--to` and `db date` reject calendar-invalid dates such as `2026-02-30` with `BAD_ARGS` instead of sending them to the API or querying nothing. `db trends <days>` rejects anything but a positive integer instead of failing with `UNKNOWN` (`abc`) or silently returning nothing (`0`).
|
|
45
|
+
- An unknown `--format` is rejected for `fetch` too (it used to be silently accepted); `fetch` errors now render as text on a TTY and as JSON when piped.
|
|
46
|
+
- An unknown `--tz` / `OURA_TZ` is reported as `BAD_ARGS` with a hint instead of an `UNKNOWN` error from the date formatter.
|
|
47
|
+
- `fetch hr` and the heartrate step of `sync` now send `start_datetime`/`end_datetime` (UTC instants covering the requested local days in `OURA_TZ`), which is what the Oura heartrate endpoint takes; every other collection keeps `start_date`/`end_date`. Previously heartrate was queried with date parameters the endpoint does not define.
|
|
48
|
+
- The API client follows `next_token` and returns every page, so ranges longer than one page (heartrate over several days) are no longer silently truncated.
|
|
49
|
+
- Local-day boundaries are computed at local midnight instead of noon, so `fetch hr --day` on a DST transition day covers the whole 23- or 25-hour day rather than shifting by an hour (internal `localDateToUtcRange`, previously unused).
|
|
50
|
+
- Interactive `oura-cli login` now hides the Personal Access Token while it is
|
|
51
|
+
typed and explains how to use `--token` safely in non-interactive contexts.
|
|
52
|
+
- `oura-cli report` now explains when no data is available and directs new
|
|
53
|
+
users to run `oura-cli sync`, instead of showing an all-empty report table.
|
|
54
|
+
- Reports containing only sleep-detail data are no longer mistaken for empty
|
|
55
|
+
reports and continue to show the available sleep metrics.
|
|
56
|
+
- `oura-cli db today` and `oura-cli db week` now explain when the local cache
|
|
57
|
+
has no data for the requested range and point at `oura-cli sync`, instead of
|
|
58
|
+
showing an all-dash table. JSON output is unchanged.
|
|
59
|
+
- `oura-cli sync` now says explicitly when it is a first sync backfilling the
|
|
60
|
+
default 30 days, names the resolved date range for both first and
|
|
61
|
+
incremental syncs, and prints a per-collection import count summary in
|
|
62
|
+
table mode. JSON output gains an additive `import.isFirstSync` boolean.
|
|
63
|
+
- `OuraStressDay.day_summary`, `OuraWorkout.label` and `OuraSleepModel.type` are
|
|
64
|
+
now typed `?: string | null`, matching the Oura OpenAPI spec (checked against
|
|
65
|
+
1.37), which marks all three nullable and omits them from `required`. The
|
|
66
|
+
declared types claimed a value is always present, so code reading them could
|
|
67
|
+
assume one that never arrives. `importDaily` now maps an absent value to
|
|
68
|
+
`NULL` explicitly instead of relying on `bun:sqlite` silently coercing
|
|
69
|
+
`undefined`.
|
|
70
|
+
- `db week`, `db trends`, `db stats`, `report` and `sync` now compute "today"
|
|
71
|
+
and every window boundary in the configured timezone (`--tz` / `OURA_TZ`);
|
|
72
|
+
previously they used UTC and disagreed with `db today` around midnight.
|
|
73
|
+
|
|
9
74
|
## [0.4.5] - 2026-07-18
|
|
10
75
|
|
|
11
76
|
### Removed
|
package/README.md
CHANGED
|
@@ -26,17 +26,45 @@ curl -fsSL https://bun.sh/install | bash # if you don't have Bun yet
|
|
|
26
26
|
bun add -g @drakulavich/oura-cli
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
You'll also need a [Personal Access Token from Oura](https://cloud.ouraring.com/personal-access-tokens).
|
|
29
|
+
You'll also need a [Personal Access Token from Oura](https://cloud.ouraring.com/personal-access-tokens). Run `oura-cli login` once — it hides the token as you type (nothing is echoed to the terminal) and saves it to `~/.oura-token` with `0600` perms.
|
|
30
30
|
|
|
31
31
|
## First five minutes
|
|
32
32
|
|
|
33
|
+
Five minutes from now you'll have your week of sleep, readiness and activity in a terminal digest like this:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Oura Weekly Report
|
|
37
|
+
2026-08-24 — 2026-08-30
|
|
38
|
+
|
|
39
|
+
Last 7 Days:
|
|
40
|
+
────────────────────────────────────────────────────
|
|
41
|
+
Day Sleep Ready Active Steps
|
|
42
|
+
────────────────────────────────────────────────────
|
|
43
|
+
Mon 24/08 87 74 68 9,668
|
|
44
|
+
Tue 25/08 82 79 74 11,204
|
|
45
|
+
...
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Four commands get you there:
|
|
49
|
+
|
|
33
50
|
```bash
|
|
34
|
-
oura-cli login
|
|
35
|
-
oura-cli
|
|
36
|
-
oura-cli
|
|
51
|
+
oura-cli login # paste your PAT — input is hidden, nothing echoes to the terminal
|
|
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
|
|
54
|
+
oura-cli report # weekly digest in the terminal
|
|
37
55
|
```
|
|
38
56
|
|
|
39
|
-
|
|
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.
|
|
58
|
+
|
|
59
|
+
### If something looks wrong
|
|
60
|
+
|
|
61
|
+
| What you see | What to run |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `No Oura data is available for this report yet.` | `oura-cli sync` |
|
|
64
|
+
| `No Oura access token at ~/.oura-token` | `oura-cli login` |
|
|
65
|
+
| `Oura API 401` | `oura-cli login` with a fresh PAT |
|
|
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
|
+
| Anything else | `oura-cli doctor` |
|
|
40
68
|
|
|
41
69
|
## Daily use
|
|
42
70
|
|
|
@@ -58,7 +86,7 @@ oura-cli db date 2026-05-10
|
|
|
58
86
|
|
|
59
87
|
```bash
|
|
60
88
|
oura-cli db week # local cache summary, no API hit
|
|
61
|
-
oura-cli sleep
|
|
89
|
+
oura-cli fetch sleep --days 7 # fresh sleep details direct from Oura
|
|
62
90
|
```
|
|
63
91
|
|
|
64
92
|
### Reports
|
|
@@ -77,26 +105,25 @@ oura-cli db trends 30 # score trends across the last 30 days
|
|
|
77
105
|
oura-cli db stats # row counts, date range, personal bests
|
|
78
106
|
```
|
|
79
107
|
|
|
80
|
-
###
|
|
108
|
+
### Raw API records
|
|
81
109
|
|
|
82
|
-
|
|
110
|
+
`fetch` returns one collection straight from the Oura API as JSON, without touching the local cache.
|
|
83
111
|
|
|
84
112
|
```bash
|
|
85
|
-
oura-cli sleep today
|
|
86
|
-
oura-cli
|
|
87
|
-
oura-cli
|
|
88
|
-
oura-cli
|
|
89
|
-
oura-cli spo2 week
|
|
90
|
-
oura-cli stress week
|
|
91
|
-
oura-cli workout week
|
|
113
|
+
oura-cli fetch sleep # today
|
|
114
|
+
oura-cli fetch hr --days 7 # last 7 days
|
|
115
|
+
oura-cli fetch workout --from 2026-05-01 --to 2026-05-31
|
|
116
|
+
oura-cli fetch sleep-periods --day 2026-06-01 | jq '.[] | {day, type, average_hrv}'
|
|
92
117
|
```
|
|
93
118
|
|
|
119
|
+
Collections: `sleep readiness activity hr spo2 stress workout sleep-periods cv-age`.
|
|
120
|
+
|
|
94
121
|
### Piping to other tools
|
|
95
122
|
|
|
96
123
|
Output auto-switches to JSON the moment you pipe it:
|
|
97
124
|
|
|
98
125
|
```bash
|
|
99
|
-
oura-cli sleep
|
|
126
|
+
oura-cli fetch sleep --days 7 | jq '.[] | {day, score, hrv: .contributors.hrv_balance}'
|
|
100
127
|
oura-cli db trends 90 > trends.json
|
|
101
128
|
```
|
|
102
129
|
|
|
@@ -146,7 +173,7 @@ If you're driving the CLI from a script or LLM harness:
|
|
|
146
173
|
- `oura-cli healthcheck` — `{ok, version, latencyMs}` JSON for liveness probes.
|
|
147
174
|
- Errors emit a stable JSON envelope on stderr: `{"error":{"code":"…","message":"…","hint":"…"}}`.
|
|
148
175
|
- Documented exit codes: `0` success, `1` user error, `2` auth, `3` API, `4` storage.
|
|
149
|
-
- JSON Schemas under [`docs/schemas/`](docs/schemas/) describe every output shape, semver-stable.
|
|
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.
|
|
150
177
|
|
|
151
178
|
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.
|
|
152
179
|
|