@drakulavich/oura-cli 0.1.3 → 0.2.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 +24 -0
- package/README.md +16 -0
- package/dist/index.js +33 -15
- package/docs/schemas/describe.json +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,29 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.2.0] - 2026-05-13
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- **BREAKING (typescript only):** `ErrorCode` is now a closed union of the
|
|
13
|
+
documented codes (`BAD_ARGS`, `TOKEN_MISSING`, `TOKEN_INVALID`, `API_ERROR`,
|
|
14
|
+
`DB_ERROR`, `UNKNOWN`). External code constructing `CliError` with a custom
|
|
15
|
+
string code will fail to compile. Runtime behaviour for already-built code
|
|
16
|
+
is unchanged. (#1, item 5)
|
|
17
|
+
- `exitCodeFor` is now an exhaustive `switch` over the closed union; future
|
|
18
|
+
additions to `ErrorCode` require a corresponding branch.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- `describe` manifest now includes `compatManifestCommand: "oura-cli manifest"`
|
|
22
|
+
so agents can discover the OpenClaw-compatible second manifest. (#1, item 6)
|
|
23
|
+
- README documents the two-manifest split under "Manifest formats".
|
|
24
|
+
- `getGlobalOpts(command)` helper in `src/commands/helpers.ts` walks the
|
|
25
|
+
commander parent chain to the root program; api-command.ts and others now
|
|
26
|
+
use it instead of `command.parent!.parent!.opts()`. (#1, item 7)
|
|
27
|
+
|
|
28
|
+
### Security
|
|
29
|
+
- API error messages now redact `Bearer <token>` and `"token":"<value>"`
|
|
30
|
+
patterns and truncate bodies past 200 chars before printing. (#1, item 18)
|
|
31
|
+
|
|
9
32
|
## [0.1.3] - 2026-05-13
|
|
10
33
|
|
|
11
34
|
### Fixed
|
|
@@ -63,6 +86,7 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
63
86
|
- Local SQLite cache at `~/.oura-cli/oura.db`.
|
|
64
87
|
- Auth via `oura-cli login`, `OURA_TOKEN`, `OURA_TOKEN_PATH`, or `~/.oura-token`.
|
|
65
88
|
|
|
89
|
+
[0.2.0]: https://github.com/drakulavich/oura-cli/releases/tag/v0.2.0
|
|
66
90
|
[0.1.3]: https://github.com/drakulavich/oura-cli/releases/tag/v0.1.3
|
|
67
91
|
[0.1.2]: https://github.com/drakulavich/oura-cli/releases/tag/v0.1.2
|
|
68
92
|
[0.1.1]: https://github.com/drakulavich/oura-cli/releases/tag/v0.1.1
|
package/README.md
CHANGED
|
@@ -90,6 +90,22 @@ oura-cli healthcheck # JSON: {ok, version, latencyMs}
|
|
|
90
90
|
| 3 | API or network error |
|
|
91
91
|
| 4 | database or local storage error |
|
|
92
92
|
|
|
93
|
+
## Manifest formats
|
|
94
|
+
|
|
95
|
+
Two manifest commands, two audiences:
|
|
96
|
+
|
|
97
|
+
- **`oura-cli describe`** — neutral, agent-friendly. Lists every command, its
|
|
98
|
+
args, output schema refs, and exit-code semantics. Use this when integrating
|
|
99
|
+
with generic LLM harnesses, MCP wrappers, or your own custom scripts.
|
|
100
|
+
- **`oura-cli manifest`** — [OpenClaw](https://github.com/openclaw/openclaw)
|
|
101
|
+
`tool-registry` shape. Strictly smaller, optimised for OpenClaw's skill
|
|
102
|
+
discovery and health-aggregation flow. Use this only if you're plugging
|
|
103
|
+
oura-cli into an OpenClaw gateway.
|
|
104
|
+
|
|
105
|
+
Both return JSON. `describe` references `manifest` via the
|
|
106
|
+
`compatManifestCommand` field so an agent can discover the second format
|
|
107
|
+
without prior knowledge.
|
|
108
|
+
|
|
93
109
|
## What's Inside
|
|
94
110
|
|
|
95
111
|
| Endpoint | Source | Cached table |
|
package/dist/index.js
CHANGED
|
@@ -2647,17 +2647,25 @@ class CliError extends Error {
|
|
|
2647
2647
|
this.name = "CliError";
|
|
2648
2648
|
}
|
|
2649
2649
|
}
|
|
2650
|
-
var EXIT_CODE_BY_CODE = {
|
|
2651
|
-
BAD_ARGS: 1,
|
|
2652
|
-
TOKEN_MISSING: 2,
|
|
2653
|
-
TOKEN_INVALID: 2,
|
|
2654
|
-
API_ERROR: 3,
|
|
2655
|
-
DB_ERROR: 4
|
|
2656
|
-
};
|
|
2657
2650
|
function exitCodeFor(err) {
|
|
2658
|
-
if (err instanceof CliError)
|
|
2659
|
-
return
|
|
2660
|
-
|
|
2651
|
+
if (!(err instanceof CliError))
|
|
2652
|
+
return 1;
|
|
2653
|
+
switch (err.code) {
|
|
2654
|
+
case "BAD_ARGS":
|
|
2655
|
+
return 1;
|
|
2656
|
+
case "TOKEN_MISSING":
|
|
2657
|
+
case "TOKEN_INVALID":
|
|
2658
|
+
return 2;
|
|
2659
|
+
case "API_ERROR":
|
|
2660
|
+
return 3;
|
|
2661
|
+
case "DB_ERROR":
|
|
2662
|
+
return 4;
|
|
2663
|
+
case "UNKNOWN":
|
|
2664
|
+
return 1;
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
function redactSecrets(s) {
|
|
2668
|
+
return s.replace(/Bearer\s+[A-Za-z0-9._\-]{8,}/g, "Bearer [REDACTED]").replace(/"token"\s*:\s*"[^"]{8,}"/g, '"token":"[REDACTED]"');
|
|
2661
2669
|
}
|
|
2662
2670
|
function formatError(err, format) {
|
|
2663
2671
|
const code = err instanceof CliError ? err.code : "UNKNOWN";
|
|
@@ -2706,7 +2714,9 @@ class OuraClient {
|
|
|
2706
2714
|
headers: { Authorization: `Bearer ${this.token}` }
|
|
2707
2715
|
});
|
|
2708
2716
|
if (!response.ok) {
|
|
2709
|
-
const
|
|
2717
|
+
const rawBody = await response.text();
|
|
2718
|
+
const redacted = redactSecrets(rawBody);
|
|
2719
|
+
const body = redacted.length > 200 ? redacted.slice(0, 200) + "\u2026 (truncated)" : redacted;
|
|
2710
2720
|
if (response.status === 401 || response.status === 403) {
|
|
2711
2721
|
throw new CliError("TOKEN_INVALID", `Oura API ${response.status}: ${body}`);
|
|
2712
2722
|
}
|
|
@@ -2752,6 +2762,13 @@ function resolveDefaultTimezone() {
|
|
|
2752
2762
|
}
|
|
2753
2763
|
|
|
2754
2764
|
// src/commands/helpers.ts
|
|
2765
|
+
function getGlobalOpts(command) {
|
|
2766
|
+
let node = command;
|
|
2767
|
+
while (node?.parent) {
|
|
2768
|
+
node = node.parent;
|
|
2769
|
+
}
|
|
2770
|
+
return node?.opts() ?? {};
|
|
2771
|
+
}
|
|
2755
2772
|
function getClient(opts) {
|
|
2756
2773
|
return new OuraClient(opts.token ? { token: opts.token } : {});
|
|
2757
2774
|
}
|
|
@@ -2770,19 +2787,19 @@ function dateRange(days, timezone) {
|
|
|
2770
2787
|
function createApiCommand(name, description, endpoint) {
|
|
2771
2788
|
const cmd = new Command(name).description(description);
|
|
2772
2789
|
cmd.command("today").description(`Today's ${name} data`).action(async (_, command) => {
|
|
2773
|
-
const opts = command
|
|
2790
|
+
const opts = getGlobalOpts(command);
|
|
2774
2791
|
const client = getClient(opts);
|
|
2775
2792
|
const data = await client.fetch(endpoint, todayDate(), todayDate());
|
|
2776
2793
|
console.log(JSON.stringify(data, null, 2));
|
|
2777
2794
|
});
|
|
2778
2795
|
cmd.command("date <day>").description(`${name} data for specific date (YYYY-MM-DD)`).action(async (day, _, command) => {
|
|
2779
|
-
const opts = command
|
|
2796
|
+
const opts = getGlobalOpts(command);
|
|
2780
2797
|
const client = getClient(opts);
|
|
2781
2798
|
const data = await client.fetch(endpoint, day, day);
|
|
2782
2799
|
console.log(JSON.stringify(data, null, 2));
|
|
2783
2800
|
});
|
|
2784
2801
|
cmd.command("week").description(`Last 7 days of ${name} data`).action(async (_, command) => {
|
|
2785
|
-
const opts = command
|
|
2802
|
+
const opts = getGlobalOpts(command);
|
|
2786
2803
|
const client = getClient(opts);
|
|
2787
2804
|
const { start, end } = dateRange(7);
|
|
2788
2805
|
const data = await client.fetch(endpoint, start, end);
|
|
@@ -3723,6 +3740,7 @@ function buildManifest(version) {
|
|
|
3723
3740
|
return {
|
|
3724
3741
|
name: "oura-cli",
|
|
3725
3742
|
version,
|
|
3743
|
+
compatManifestCommand: "oura-cli manifest",
|
|
3726
3744
|
auth: {
|
|
3727
3745
|
envVars: ["OURA_TOKEN", "OURA_TOKEN_PATH"],
|
|
3728
3746
|
tokenFile: "~/.oura-token",
|
|
@@ -3858,7 +3876,7 @@ function describeCommand(version) {
|
|
|
3858
3876
|
}
|
|
3859
3877
|
|
|
3860
3878
|
// src/index.ts
|
|
3861
|
-
var VERSION = "0.
|
|
3879
|
+
var VERSION = "0.2.0";
|
|
3862
3880
|
if (process.argv.includes("--no-color") || process.env.NO_COLOR) {
|
|
3863
3881
|
source_default.level = 0;
|
|
3864
3882
|
}
|
package/package.json
CHANGED