@drakulavich/oura-cli 0.1.1 → 0.1.3
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 +35 -0
- package/README.md +96 -46
- package/dist/index.js +151 -29
- package/docs/schemas/describe.json +11 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,39 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.1.3] - 2026-05-13
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- `--token <pat>` global flag now uses the value as an inline token instead of
|
|
13
|
+
trying to read it as a file path (#1, item 1).
|
|
14
|
+
- `--no-color` is now wired through to chalk and honors the `NO_COLOR` env
|
|
15
|
+
variable; it was previously advertised in the `describe` manifest but never
|
|
16
|
+
took effect (#1, item 2).
|
|
17
|
+
- `todayDate()` and `dateRange()` now use the configured/system timezone via
|
|
18
|
+
`todayLocal(resolveDefaultTimezone())` instead of UTC-only `.toISOString()`,
|
|
19
|
+
so users in non-UTC timezones get the correct "today" near midnight (#1,
|
|
20
|
+
item 3).
|
|
21
|
+
- Single-day `start == end` API calls verified safe: `oura-cli sleep today`
|
|
22
|
+
(which calls `client.fetch(endpoint, today, today)`) returns data correctly.
|
|
23
|
+
No change needed to `api-command.ts` (#1, item 4).
|
|
24
|
+
|
|
25
|
+
### Note
|
|
26
|
+
- Several smells covered in the audit issue (#1) remain open for v0.2+:
|
|
27
|
+
closed `ErrorCode` union, manifest documentation, commander chain helper,
|
|
28
|
+
schema-validated test fixtures.
|
|
29
|
+
|
|
30
|
+
## [0.1.2] - 2026-05-13
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- `oura-cli describe` now reports the real CLI surface. Data commands
|
|
34
|
+
(sleep, readiness, activity, hr, spo2, stress, workout) advertise their
|
|
35
|
+
`today | date <day> | week` subcommands instead of fictional `--start/--end`
|
|
36
|
+
flags. `db` and `report` likewise list their real subcommands.
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
- `ManifestCommand.subcommands` field in the describe manifest, with a sibling
|
|
40
|
+
`$def` in `docs/schemas/describe.json`.
|
|
41
|
+
|
|
9
42
|
## [0.1.1] - 2026-05-13
|
|
10
43
|
|
|
11
44
|
### Added
|
|
@@ -30,5 +63,7 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
30
63
|
- Local SQLite cache at `~/.oura-cli/oura.db`.
|
|
31
64
|
- Auth via `oura-cli login`, `OURA_TOKEN`, `OURA_TOKEN_PATH`, or `~/.oura-token`.
|
|
32
65
|
|
|
66
|
+
[0.1.3]: https://github.com/drakulavich/oura-cli/releases/tag/v0.1.3
|
|
67
|
+
[0.1.2]: https://github.com/drakulavich/oura-cli/releases/tag/v0.1.2
|
|
33
68
|
[0.1.1]: https://github.com/drakulavich/oura-cli/releases/tag/v0.1.1
|
|
34
69
|
[0.1.0]: https://github.com/drakulavich/oura-cli/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -1,54 +1,110 @@
|
|
|
1
|
-
|
|
1
|
+
<h1 align="center">oura-cli</h1>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://github.com/drakulavich/oura-cli/actions/workflows/ci.yml"><img src="https://github.com/drakulavich/oura-cli/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
5
|
+
<a href="https://www.npmjs.com/package/@drakulavich/oura-cli"><img src="https://img.shields.io/npm/v/@drakulavich/oura-cli" alt="npm version"></a>
|
|
6
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
|
|
7
|
+
<a href="https://bun.sh"><img src="https://img.shields.io/badge/runtime-Bun-f9f1e1?logo=bun" alt="Bun"></a>
|
|
8
|
+
</p>
|
|
5
9
|
|
|
6
|
-
|
|
10
|
+
<p align="center"><b>Own your Oura Ring data.</b> Local CLI that pulls your biometrics from the Oura Cloud API, caches them in SQLite, and serves both your terminal and your AI agent from the same binary.</p>
|
|
7
11
|
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
+
- **Two audiences, one binary** — pretty tables when you're at a terminal, stable JSON when stdout is piped to a parent process
|
|
13
|
+
- **Self-describing** — `oura-cli describe` emits a JSON manifest of every command, argument, and output schema. Agents discover capabilities without scraping `--help`
|
|
14
|
+
- **Local-first** — everything lives in `~/.oura-cli/oura.db` after `oura-cli sync`. Query and report offline, no Oura mobile app required
|
|
15
|
+
- **Documented contract** — JSON Schemas under `docs/schemas/`, semver-versioned, plus machine-readable errors and exit codes (0–4) for clean error handling in scripts and agents
|
|
12
16
|
|
|
13
|
-
##
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
Runtime: **[Bun](https://bun.sh)** >= 1.0.
|
|
14
20
|
|
|
15
21
|
```bash
|
|
16
|
-
|
|
22
|
+
curl -fsSL https://bun.sh/install | bash # skip if Bun is already installed
|
|
23
|
+
|
|
24
|
+
bun add -g @drakulavich/oura-cli
|
|
25
|
+
oura-cli login # paste your Personal Access Token (one-time)
|
|
26
|
+
oura-cli sync # backfill recent days into ~/.oura-cli/oura.db
|
|
27
|
+
oura-cli report weekly # weekly summary with trends and recommendations
|
|
17
28
|
```
|
|
18
29
|
|
|
19
|
-
|
|
30
|
+
Get a Personal Access Token at <https://cloud.ouraring.com/personal-access-tokens>.
|
|
20
31
|
|
|
21
32
|
## For humans
|
|
22
33
|
|
|
34
|
+
Output format auto-detects: tables in your terminal, JSON when piped.
|
|
35
|
+
|
|
23
36
|
```bash
|
|
24
|
-
oura-cli
|
|
25
|
-
oura-cli
|
|
26
|
-
oura-cli
|
|
37
|
+
oura-cli sync # pull the latest from Oura Cloud
|
|
38
|
+
oura-cli db today # today's summary
|
|
39
|
+
oura-cli db date 2026-05-10 # any specific day
|
|
40
|
+
oura-cli db week # last 7 days
|
|
41
|
+
oura-cli db trends 30 # score trends across last 30 days
|
|
42
|
+
oura-cli db stats # row counts, date range, personal bests
|
|
43
|
+
oura-cli report weekly # narrative weekly summary
|
|
27
44
|
```
|
|
28
45
|
|
|
29
|
-
|
|
46
|
+
Pipe a result to your favourite JSON tool — `--format` is auto-detected, no flag needed:
|
|
30
47
|
|
|
31
|
-
|
|
48
|
+
```bash
|
|
49
|
+
oura-cli sleep week | jq '.[] | {day, score, hrv: .contributors.hrv_balance}'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Per-endpoint fetches mirror Oura's V2 API one-to-one and share the same subcommand shape:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
oura-cli sleep today # daily_sleep, today
|
|
56
|
+
oura-cli readiness date 2026-05-10 # daily_readiness, specific day
|
|
57
|
+
oura-cli activity week # daily_activity, last 7 days
|
|
58
|
+
oura-cli hr week # heartrate samples
|
|
59
|
+
oura-cli spo2 week # daily_spo2
|
|
60
|
+
oura-cli stress week # daily_stress
|
|
61
|
+
oura-cli workout week # workouts
|
|
62
|
+
```
|
|
32
63
|
|
|
33
64
|
## For agents
|
|
34
65
|
|
|
66
|
+
Designed for child-process invocation by LLM harnesses (Claude Code, Codex, generic MCP wrappers).
|
|
67
|
+
|
|
35
68
|
```bash
|
|
36
|
-
export OURA_TOKEN="…"
|
|
37
|
-
oura-cli describe
|
|
38
|
-
oura-cli sleep
|
|
69
|
+
export OURA_TOKEN="…" # no file or interactive flow needed
|
|
70
|
+
oura-cli describe # JSON manifest of commands, args, schemas
|
|
71
|
+
oura-cli sleep today # JSON (stdout is non-TTY for child processes)
|
|
72
|
+
oura-cli healthcheck # JSON: {ok, version, latencyMs}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Stable JSON I/O contract.** Output shapes are versioned with the package; breaking changes are major semver bumps. Schemas live in `docs/schemas/`.
|
|
76
|
+
|
|
77
|
+
**Machine-readable errors.** When format resolves to `json`, every error emits a single line to stderr:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{"error":{"code":"TOKEN_MISSING","message":"…","hint":"Run `oura-cli login` or set OURA_TOKEN."}}
|
|
39
81
|
```
|
|
40
82
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
83
|
+
**Exit codes:**
|
|
84
|
+
|
|
85
|
+
| Code | Meaning |
|
|
86
|
+
|------|---------|
|
|
87
|
+
| 0 | success |
|
|
88
|
+
| 1 | user error (bad arguments) |
|
|
89
|
+
| 2 | auth error (missing or invalid token) |
|
|
90
|
+
| 3 | API or network error |
|
|
91
|
+
| 4 | database or local storage error |
|
|
44
92
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
93
|
+
## What's Inside
|
|
94
|
+
|
|
95
|
+
| Endpoint | Source | Cached table |
|
|
96
|
+
|------------|-------------------------------------|-----------------------|
|
|
97
|
+
| Sleep | Oura V2 `daily_sleep` | `daily_sleep` |
|
|
98
|
+
| Readiness | Oura V2 `daily_readiness` | `daily_readiness` |
|
|
99
|
+
| Activity | Oura V2 `daily_activity` | `daily_activity` |
|
|
100
|
+
| Heart rate | Oura V2 `heartrate` | `heartrate` |
|
|
101
|
+
| SpO₂ | Oura V2 `daily_spo2` | `daily_spo2` |
|
|
102
|
+
| Stress | Oura V2 `daily_stress` | `daily_stress` |
|
|
103
|
+
| Workouts | Oura V2 `workout` | `workouts` |
|
|
104
|
+
| Sleep model | Oura V2 `sleep` | `sleep_model` |
|
|
105
|
+
| Cardiovascular age | Oura V2 `cardiovascular_age` | `cardiovascular_age` |
|
|
106
|
+
|
|
107
|
+
Runtime: [Bun](https://bun.sh). Storage: built-in `bun:sqlite`. CLI parsing: [Commander](https://github.com/tj/commander.js). Output styling: [chalk](https://github.com/chalk/chalk). Zero native dependencies, single 142 kB `dist/index.js`.
|
|
52
108
|
|
|
53
109
|
## Configuration
|
|
54
110
|
|
|
@@ -60,27 +116,21 @@ oura-cli sleep --start 2026-05-01 # JSON (since stdout is non-TTY for child pro
|
|
|
60
116
|
| Timezone | `--tz` | `OURA_TZ` | system timezone, else `UTC` |
|
|
61
117
|
| Output format | `--format` | | auto-detect (TTY → table) |
|
|
62
118
|
|
|
63
|
-
##
|
|
119
|
+
## Integrations
|
|
64
120
|
|
|
65
|
-
|
|
121
|
+
- **OpenClaw** — drop into your LLM agent as an [OpenClaw skill](https://github.com/openclaw/openclaw). `oura-cli manifest` and `oura-cli healthcheck` report back in the tool-registry shape, so the agent can discover the binary and audit its DB health automatically.
|
|
122
|
+
- **MCP** — `oura-cli describe` returns enough metadata to autogenerate an MCP server wrapper. A first-party `oura-mcp` companion is on the roadmap.
|
|
66
123
|
|
|
67
|
-
|
|
68
|
-
- `describe` — emit JSON manifest (for agents)
|
|
69
|
-
- `sleep | readiness | activity | hr | spo2 | stress | workout [--start YYYY-MM-DD] [--end YYYY-MM-DD]` — fetch from Oura API
|
|
70
|
-
- `sync` — sync all collections into the local SQLite cache
|
|
71
|
-
- `db <subcommand>` — query the local cache
|
|
72
|
-
- `report --week | --month` — render a summary
|
|
124
|
+
## Requirements
|
|
73
125
|
|
|
74
|
-
|
|
126
|
+
- [Bun](https://bun.sh) >= 1.0
|
|
127
|
+
- macOS, Linux, or Windows (WSL)
|
|
128
|
+
- An [Oura Personal Access Token](https://cloud.ouraring.com/personal-access-tokens)
|
|
75
129
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
bun install
|
|
80
|
-
bun test
|
|
81
|
-
bun run dev describe # run from source
|
|
82
|
-
```
|
|
130
|
+
## Contributing
|
|
131
|
+
|
|
132
|
+
Bug reports and pull requests welcome at [drakulavich/oura-cli/issues](https://github.com/drakulavich/oura-cli/issues).
|
|
83
133
|
|
|
84
134
|
## License
|
|
85
135
|
|
|
86
|
-
|
|
136
|
+
Made with 💍🤖 under MIT License.
|
package/dist/index.js
CHANGED
|
@@ -2142,11 +2142,6 @@ var {
|
|
|
2142
2142
|
Help
|
|
2143
2143
|
} = import__.default;
|
|
2144
2144
|
|
|
2145
|
-
// src/api/client.ts
|
|
2146
|
-
import { readFileSync } from "fs";
|
|
2147
|
-
import { resolve } from "path";
|
|
2148
|
-
import { homedir } from "os";
|
|
2149
|
-
|
|
2150
2145
|
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
2151
2146
|
var ANSI_BACKGROUND_OFFSET = 10;
|
|
2152
2147
|
var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
|
|
@@ -2636,6 +2631,11 @@ var chalk = createChalk();
|
|
|
2636
2631
|
var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
2637
2632
|
var source_default = chalk;
|
|
2638
2633
|
|
|
2634
|
+
// src/api/client.ts
|
|
2635
|
+
import { readFileSync } from "fs";
|
|
2636
|
+
import { resolve } from "path";
|
|
2637
|
+
import { homedir } from "os";
|
|
2638
|
+
|
|
2639
2639
|
// src/lib/errors.ts
|
|
2640
2640
|
class CliError extends Error {
|
|
2641
2641
|
code;
|
|
@@ -2717,16 +2717,52 @@ class OuraClient {
|
|
|
2717
2717
|
}
|
|
2718
2718
|
}
|
|
2719
2719
|
|
|
2720
|
+
// src/lib/time.ts
|
|
2721
|
+
function nowUtc() {
|
|
2722
|
+
return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
2723
|
+
}
|
|
2724
|
+
function formatLocal(utcStr, timezone) {
|
|
2725
|
+
const dt = new Date(utcStr);
|
|
2726
|
+
const parts = new Intl.DateTimeFormat("sv-SE", {
|
|
2727
|
+
timeZone: timezone,
|
|
2728
|
+
year: "numeric",
|
|
2729
|
+
month: "2-digit",
|
|
2730
|
+
day: "2-digit",
|
|
2731
|
+
hour: "2-digit",
|
|
2732
|
+
minute: "2-digit",
|
|
2733
|
+
hour12: false
|
|
2734
|
+
}).formatToParts(dt);
|
|
2735
|
+
const get = (type) => parts.find((p) => p.type === type)?.value ?? "";
|
|
2736
|
+
return `${get("year")}-${get("month")}-${get("day")} ${get("hour")}:${get("minute")}`;
|
|
2737
|
+
}
|
|
2738
|
+
function formatLocalDate(utcStr, timezone) {
|
|
2739
|
+
return formatLocal(utcStr, timezone).split(" ")[0];
|
|
2740
|
+
}
|
|
2741
|
+
function todayLocal(timezone) {
|
|
2742
|
+
return formatLocalDate(nowUtc(), timezone);
|
|
2743
|
+
}
|
|
2744
|
+
function resolveDefaultTimezone() {
|
|
2745
|
+
if (process.env.OURA_TZ)
|
|
2746
|
+
return process.env.OURA_TZ;
|
|
2747
|
+
try {
|
|
2748
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
2749
|
+
} catch {
|
|
2750
|
+
return "UTC";
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2720
2754
|
// src/commands/helpers.ts
|
|
2721
2755
|
function getClient(opts) {
|
|
2722
|
-
return new OuraClient(opts.token ? {
|
|
2756
|
+
return new OuraClient(opts.token ? { token: opts.token } : {});
|
|
2723
2757
|
}
|
|
2724
|
-
function todayDate() {
|
|
2725
|
-
return
|
|
2758
|
+
function todayDate(timezone) {
|
|
2759
|
+
return todayLocal(timezone ?? resolveDefaultTimezone());
|
|
2726
2760
|
}
|
|
2727
|
-
function dateRange(days) {
|
|
2728
|
-
const
|
|
2729
|
-
const
|
|
2761
|
+
function dateRange(days, timezone) {
|
|
2762
|
+
const tz = timezone ?? resolveDefaultTimezone();
|
|
2763
|
+
const end = todayLocal(tz);
|
|
2764
|
+
const startMs = new Date(`${end}T00:00:00Z`).getTime() - (days - 1) * 86400000;
|
|
2765
|
+
const start = new Date(startMs).toISOString().slice(0, 10);
|
|
2730
2766
|
return { start, end };
|
|
2731
2767
|
}
|
|
2732
2768
|
|
|
@@ -3683,10 +3719,6 @@ function loginCommand() {
|
|
|
3683
3719
|
}
|
|
3684
3720
|
|
|
3685
3721
|
// src/commands/describe.ts
|
|
3686
|
-
var DATE_ARGS = [
|
|
3687
|
-
{ name: "--start", type: "date", format: "YYYY-MM-DD", required: false, description: "Range start (inclusive)" },
|
|
3688
|
-
{ name: "--end", type: "date", format: "YYYY-MM-DD", required: false, description: "Range end (inclusive)" }
|
|
3689
|
-
];
|
|
3690
3722
|
function buildManifest(version) {
|
|
3691
3723
|
return {
|
|
3692
3724
|
name: "oura-cli",
|
|
@@ -3716,19 +3748,106 @@ function buildManifest(version) {
|
|
|
3716
3748
|
{ name: "--path", type: "string", required: false, description: "Override token file path" }
|
|
3717
3749
|
] },
|
|
3718
3750
|
{ name: "describe", description: "Emit a machine-readable manifest of commands, args, and outputs.", args: [] },
|
|
3719
|
-
{
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3751
|
+
{
|
|
3752
|
+
name: "sleep",
|
|
3753
|
+
description: "Fetch daily sleep scores from Oura API. Pick a subcommand: today | date <day> | week.",
|
|
3754
|
+
args: [],
|
|
3755
|
+
outputSchema: "docs/schemas/sleep.json",
|
|
3756
|
+
subcommands: [
|
|
3757
|
+
{ name: "today", description: "Today's sleep data.", args: [] },
|
|
3758
|
+
{ name: "date", description: "Sleep data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3759
|
+
{ name: "week", description: "Last 7 days of sleep data.", args: [] }
|
|
3760
|
+
]
|
|
3761
|
+
},
|
|
3762
|
+
{
|
|
3763
|
+
name: "readiness",
|
|
3764
|
+
description: "Fetch daily readiness scores from Oura API. Pick a subcommand: today | date <day> | week.",
|
|
3765
|
+
args: [],
|
|
3766
|
+
outputSchema: "docs/schemas/readiness.json",
|
|
3767
|
+
subcommands: [
|
|
3768
|
+
{ name: "today", description: "Today's readiness data.", args: [] },
|
|
3769
|
+
{ name: "date", description: "Readiness data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3770
|
+
{ name: "week", description: "Last 7 days of readiness data.", args: [] }
|
|
3771
|
+
]
|
|
3772
|
+
},
|
|
3773
|
+
{
|
|
3774
|
+
name: "activity",
|
|
3775
|
+
description: "Fetch daily activity scores from Oura API. Pick a subcommand: today | date <day> | week.",
|
|
3776
|
+
args: [],
|
|
3777
|
+
outputSchema: "docs/schemas/activity.json",
|
|
3778
|
+
subcommands: [
|
|
3779
|
+
{ name: "today", description: "Today's activity data.", args: [] },
|
|
3780
|
+
{ name: "date", description: "Activity data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3781
|
+
{ name: "week", description: "Last 7 days of activity data.", args: [] }
|
|
3782
|
+
]
|
|
3783
|
+
},
|
|
3784
|
+
{
|
|
3785
|
+
name: "hr",
|
|
3786
|
+
description: "Fetch heart rate samples from Oura API. Pick a subcommand: today | date <day> | week.",
|
|
3787
|
+
args: [],
|
|
3788
|
+
outputSchema: "docs/schemas/hr.json",
|
|
3789
|
+
subcommands: [
|
|
3790
|
+
{ name: "today", description: "Today's heart rate data.", args: [] },
|
|
3791
|
+
{ name: "date", description: "Heart rate data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3792
|
+
{ name: "week", description: "Last 7 days of heart rate data.", args: [] }
|
|
3793
|
+
]
|
|
3794
|
+
},
|
|
3795
|
+
{
|
|
3796
|
+
name: "spo2",
|
|
3797
|
+
description: "Fetch blood oxygen (SpO2) data from Oura API. Pick a subcommand: today | date <day> | week.",
|
|
3798
|
+
args: [],
|
|
3799
|
+
outputSchema: "docs/schemas/spo2.json",
|
|
3800
|
+
subcommands: [
|
|
3801
|
+
{ name: "today", description: "Today's SpO2 data.", args: [] },
|
|
3802
|
+
{ name: "date", description: "SpO2 data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3803
|
+
{ name: "week", description: "Last 7 days of SpO2 data.", args: [] }
|
|
3804
|
+
]
|
|
3805
|
+
},
|
|
3806
|
+
{
|
|
3807
|
+
name: "stress",
|
|
3808
|
+
description: "Fetch daily stress data from Oura API. Pick a subcommand: today | date <day> | week.",
|
|
3809
|
+
args: [],
|
|
3810
|
+
outputSchema: "docs/schemas/stress.json",
|
|
3811
|
+
subcommands: [
|
|
3812
|
+
{ name: "today", description: "Today's stress data.", args: [] },
|
|
3813
|
+
{ name: "date", description: "Stress data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3814
|
+
{ name: "week", description: "Last 7 days of stress data.", args: [] }
|
|
3815
|
+
]
|
|
3816
|
+
},
|
|
3817
|
+
{
|
|
3818
|
+
name: "workout",
|
|
3819
|
+
description: "Fetch workout data from Oura API. Pick a subcommand: today | date <day> | week.",
|
|
3820
|
+
args: [],
|
|
3821
|
+
outputSchema: "docs/schemas/workout.json",
|
|
3822
|
+
subcommands: [
|
|
3823
|
+
{ name: "today", description: "Today's workout data.", args: [] },
|
|
3824
|
+
{ name: "date", description: "Workout data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3825
|
+
{ name: "week", description: "Last 7 days of workout data.", args: [] }
|
|
3826
|
+
]
|
|
3827
|
+
},
|
|
3726
3828
|
{ name: "sync", description: "Sync all Oura collections into the local database.", args: [] },
|
|
3727
|
-
{
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3829
|
+
{
|
|
3830
|
+
name: "db",
|
|
3831
|
+
description: "Query and manage the local SQLite cache. Pick a subcommand.",
|
|
3832
|
+
args: [],
|
|
3833
|
+
subcommands: [
|
|
3834
|
+
{ name: "today", description: "Today's summary from local DB.", args: [] },
|
|
3835
|
+
{ name: "date", description: "Summary for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3836
|
+
{ name: "week", description: "Last 7 days from local DB.", args: [] },
|
|
3837
|
+
{ name: "trends", description: "Score and metric trends over N days (default 30).", args: [{ name: "[days]", type: "number", required: false, description: "Window size in days." }] },
|
|
3838
|
+
{ name: "stats", description: "Row counts, date range, record highs.", args: [] },
|
|
3839
|
+
{ name: "import", description: "Sync new data from Oura API into the local DB.", args: [] },
|
|
3840
|
+
{ name: "reset", description: "Destroy and rebuild the database from exported CSVs.", args: [] }
|
|
3841
|
+
]
|
|
3842
|
+
},
|
|
3843
|
+
{
|
|
3844
|
+
name: "report",
|
|
3845
|
+
description: "Render a narrative health report. Pick a subcommand.",
|
|
3846
|
+
args: [],
|
|
3847
|
+
subcommands: [
|
|
3848
|
+
{ name: "weekly", description: "Weekly health summary with trends and recommendations.", args: [] }
|
|
3849
|
+
]
|
|
3850
|
+
}
|
|
3732
3851
|
]
|
|
3733
3852
|
};
|
|
3734
3853
|
}
|
|
@@ -3739,9 +3858,12 @@ function describeCommand(version) {
|
|
|
3739
3858
|
}
|
|
3740
3859
|
|
|
3741
3860
|
// src/index.ts
|
|
3742
|
-
var VERSION = "0.1.
|
|
3861
|
+
var VERSION = "0.1.3";
|
|
3862
|
+
if (process.argv.includes("--no-color") || process.env.NO_COLOR) {
|
|
3863
|
+
source_default.level = 0;
|
|
3864
|
+
}
|
|
3743
3865
|
var program2 = new Command;
|
|
3744
|
-
program2.name("oura-cli").description("Oura Ring CLI \u2014 query and analyze Oura Ring health data. Designed for humans and agents.").version(VERSION).option("--format <format>", "Output format: table | json (default auto-detect by TTY)").option("--token <pat>", "Inline access token (prefer env vars or `oura-cli login`)").option("--db <path>", "Path to SQLite database file (env: OURA_DB_PATH)").option("--tz <timezone>", "Display timezone (env: OURA_TZ; default auto-detect)");
|
|
3866
|
+
program2.name("oura-cli").description("Oura Ring CLI \u2014 query and analyze Oura Ring health data. Designed for humans and agents.").version(VERSION).option("--format <format>", "Output format: table | json (default auto-detect by TTY)").option("--token <pat>", "Inline access token (prefer env vars or `oura-cli login`)").option("--db <path>", "Path to SQLite database file (env: OURA_DB_PATH)").option("--tz <timezone>", "Display timezone (env: OURA_TZ; default auto-detect)").option("--no-color", "Disable ANSI colors in human output (also honors NO_COLOR env)");
|
|
3745
3867
|
program2.addCommand(loginCommand());
|
|
3746
3868
|
program2.addCommand(describeCommand(VERSION));
|
|
3747
3869
|
program2.addCommand(createApiCommand("sleep", "Fetch daily sleep scores from Oura API.", "daily_sleep"));
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
"name": { "type": "string" },
|
|
38
38
|
"description": { "type": "string" },
|
|
39
39
|
"args": { "type": "array", "items": { "$ref": "#/$defs/arg" } },
|
|
40
|
-
"outputSchema": { "type": "string" }
|
|
40
|
+
"outputSchema": { "type": "string" },
|
|
41
|
+
"subcommands": { "type": "array", "items": { "$ref": "#/$defs/subcommand" } }
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
}
|
|
@@ -54,6 +55,15 @@
|
|
|
54
55
|
"description": { "type": "string" },
|
|
55
56
|
"values": { "type": "array", "items": { "type": "string" } }
|
|
56
57
|
}
|
|
58
|
+
},
|
|
59
|
+
"subcommand": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"required": ["name", "description", "args"],
|
|
62
|
+
"properties": {
|
|
63
|
+
"name": { "type": "string" },
|
|
64
|
+
"description": { "type": "string" },
|
|
65
|
+
"args": { "type": "array", "items": { "$ref": "#/$defs/arg" } }
|
|
66
|
+
}
|
|
57
67
|
}
|
|
58
68
|
}
|
|
59
69
|
}
|
package/package.json
CHANGED