@rickybloomfield/ouraclaw 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ricky Bloomfield
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # OuraClaw
2
+
3
+ Oura Ring plugin and skill for [OpenClaw](https://github.com/nickarora/openclaw). Brings your sleep, readiness, activity, and stress data into your agent conversations.
4
+
5
+ ## Features
6
+
7
+ - **Agent tool** (`oura_data`) — lets the agent fetch Oura Ring data on your behalf
8
+ - **Skill** — teaches the agent how to interpret scores, format summaries, and answer health questions
9
+ - **Scheduled summaries** — optional morning and evening health recaps delivered to your preferred channel
10
+ - **Background token refresh** — keeps your Oura connection alive without manual intervention
11
+
12
+ ## Prerequisites
13
+
14
+ - [OpenClaw](https://github.com/nickarora/openclaw) installed and configured
15
+ - An [Oura Ring](https://ouraring.com) account with data
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ # From npm
21
+ npm install -g @rickybloomfield/ouraclaw
22
+ openclaw plugins install @rickybloomfield/ouraclaw
23
+
24
+ # Or from source
25
+ git clone https://github.com/rickybloomfield/OuraClaw.git
26
+ cd OuraClaw && npm install && npm run build
27
+ openclaw plugins install -l .
28
+ ```
29
+
30
+ ## Setup
31
+
32
+ Run the interactive setup wizard:
33
+
34
+ ```bash
35
+ openclaw ouraclaw setup
36
+ ```
37
+
38
+ The wizard will walk you through:
39
+
40
+ 1. **Create an Oura application**
41
+ - Go to [https://developer.ouraring.com](https://developer.ouraring.com)
42
+ - Navigate to "My Applications" and create a new app
43
+ - Set the redirect URI to `http://localhost:9876/callback`
44
+
45
+ 2. **Enter credentials** — paste your Client ID and Client Secret
46
+
47
+ 3. **Authorize** — a browser window opens to complete the OAuth flow
48
+
49
+ 4. **Choose delivery channel** — pick iMessage, Slack, Discord, Telegram, or use the default active channel
50
+
51
+ 5. **Set schedule** — configure morning and evening summary times and timezone, or skip scheduled messages
52
+
53
+ ## Usage
54
+
55
+ Once set up, just ask your agent about your health data:
56
+
57
+ - "How did I sleep last night?"
58
+ - "What's my readiness score?"
59
+ - "How active was I today?"
60
+ - "Show me my sleep trends for the past week"
61
+ - "Give me a full health summary"
62
+
63
+ ## CLI Commands
64
+
65
+ ```bash
66
+ openclaw ouraclaw setup # Run the setup wizard
67
+ openclaw ouraclaw status # Show connection status and config
68
+ openclaw ouraclaw test # Fetch today's data to verify the connection
69
+ ```
70
+
71
+ ## Scheduled Summaries
72
+
73
+ If enabled during setup, OuraClaw creates two cron jobs:
74
+
75
+ - **Morning** (default 7:00 AM) — sleep score, readiness, stress, and a personalized note
76
+ - **Evening** (default 9:00 PM) — activity summary, readiness, stress, sleep recap, and a wind-down note
77
+
78
+ Manage them with:
79
+
80
+ ```bash
81
+ openclaw cron list # See all cron jobs
82
+ openclaw cron run ouraclaw-morning --force # Manually trigger morning summary
83
+ ```
84
+
85
+ Re-running `openclaw ouraclaw setup` replaces existing cron jobs without duplication.
86
+
87
+ ## Development
88
+
89
+ ```bash
90
+ npm install
91
+ npm run build # Compile TypeScript
92
+ npm run dev # Watch mode
93
+ ```
94
+
95
+ ## License
96
+
97
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function registerCli(api: any): void;
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AA+IA,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,QAwBnC"}
package/dist/cli.js ADDED
@@ -0,0 +1,330 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerCli = registerCli;
7
+ const readline_1 = __importDefault(require("readline"));
8
+ const child_process_1 = require("child_process");
9
+ const oauth_1 = require("./oauth");
10
+ const token_store_1 = require("./token-store");
11
+ const cron_setup_1 = require("./cron-setup");
12
+ const oura_client_1 = require("./oura-client");
13
+ function createPromptInterface() {
14
+ return readline_1.default.createInterface({
15
+ input: process.stdin,
16
+ output: process.stdout,
17
+ });
18
+ }
19
+ function ask(rl, question, defaultValue) {
20
+ const suffix = defaultValue ? ` (${defaultValue})` : "";
21
+ return new Promise((resolve) => {
22
+ rl.question(`${question}${suffix} `, (answer) => {
23
+ resolve(answer.trim() || defaultValue || "");
24
+ });
25
+ });
26
+ }
27
+ function confirm(rl, question, defaultYes = true) {
28
+ const hint = defaultYes ? "[Y/n]" : "[y/N]";
29
+ return new Promise((resolve) => {
30
+ rl.question(`${question} ${hint} `, (answer) => {
31
+ const a = answer.trim().toLowerCase();
32
+ if (a === "")
33
+ resolve(defaultYes);
34
+ else
35
+ resolve(a === "y" || a === "yes");
36
+ });
37
+ });
38
+ }
39
+ function select(rl, question, choices, defaultIndex) {
40
+ return new Promise((resolve) => {
41
+ console.log(question);
42
+ choices.forEach((c, i) => {
43
+ const marker = defaultIndex === i ? " *" : "";
44
+ console.log(` ${i + 1}. ${c}${marker}`);
45
+ });
46
+ const defaultHint = defaultIndex !== undefined ? ` (${defaultIndex + 1})` : "";
47
+ rl.question(`Choose [1-${choices.length}]${defaultHint}: `, (answer) => {
48
+ if (answer.trim() === "" && defaultIndex !== undefined) {
49
+ resolve(choices[defaultIndex]);
50
+ return;
51
+ }
52
+ const idx = parseInt(answer.trim(), 10) - 1;
53
+ resolve(choices[idx] || choices[defaultIndex ?? 0]);
54
+ });
55
+ });
56
+ }
57
+ function openUrl(url) {
58
+ const cmd = process.platform === "darwin"
59
+ ? `open "${url}"`
60
+ : process.platform === "win32"
61
+ ? `start "${url}"`
62
+ : `xdg-open "${url}"`;
63
+ (0, child_process_1.exec)(cmd);
64
+ }
65
+ function withProgress(message, fn) {
66
+ process.stdout.write(`${message}...`);
67
+ try {
68
+ const result = fn();
69
+ if (result instanceof Promise) {
70
+ return result.then((val) => {
71
+ process.stdout.write(" done.\n");
72
+ return val;
73
+ }).catch((err) => {
74
+ process.stdout.write(" failed.\n");
75
+ throw err;
76
+ });
77
+ }
78
+ process.stdout.write(" done.\n");
79
+ return result;
80
+ }
81
+ catch (err) {
82
+ process.stdout.write(" failed.\n");
83
+ throw err;
84
+ }
85
+ }
86
+ function getChannelConfig(channelId) {
87
+ try {
88
+ const output = (0, child_process_1.execFileSync)("openclaw", ["config", "get", `channels.${channelId}`], {
89
+ encoding: "utf-8",
90
+ timeout: 10_000,
91
+ });
92
+ return JSON.parse(output);
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ }
98
+ function getConfiguredChannelTargets() {
99
+ // First, get the list of configured channels
100
+ let channelIds = [];
101
+ try {
102
+ const output = (0, child_process_1.execSync)("openclaw channels list --json --no-usage", {
103
+ encoding: "utf-8",
104
+ timeout: 10_000,
105
+ });
106
+ const data = JSON.parse(output);
107
+ const chat = data?.chat;
108
+ if (chat && typeof chat === "object") {
109
+ channelIds = Object.keys(chat);
110
+ }
111
+ }
112
+ catch {
113
+ return [];
114
+ }
115
+ // Then read each channel's config to get allowFrom targets
116
+ const targets = [];
117
+ for (const channelId of channelIds) {
118
+ const config = getChannelConfig(channelId);
119
+ if (!config)
120
+ continue;
121
+ const allowFrom = config.allowFrom || [];
122
+ for (const contact of allowFrom) {
123
+ targets.push({
124
+ label: `${channelId} → ${contact}`,
125
+ channel: channelId,
126
+ target: contact,
127
+ });
128
+ }
129
+ }
130
+ return targets;
131
+ }
132
+ function registerCli(api) {
133
+ api.registerCli(({ program }) => {
134
+ const ouraclaw = program
135
+ .command("ouraclaw")
136
+ .description("OuraClaw — Oura Ring integration");
137
+ ouraclaw
138
+ .command("setup")
139
+ .description("Set up Oura Ring connection and scheduled summaries")
140
+ .action(() => setupCommand());
141
+ ouraclaw
142
+ .command("status")
143
+ .description("Show current OuraClaw connection status")
144
+ .action(() => statusCommand());
145
+ ouraclaw
146
+ .command("test")
147
+ .description("Fetch today's Oura data to verify connection")
148
+ .action(() => testCommand());
149
+ }, { commands: ["ouraclaw"] });
150
+ }
151
+ async function setupCommand() {
152
+ const rl = createPromptInterface();
153
+ const existing = (0, token_store_1.readConfig)();
154
+ const isRerun = !!(existing.clientId || existing.accessToken);
155
+ try {
156
+ console.log("\n=== OuraClaw Setup ===\n");
157
+ if (isRerun) {
158
+ console.log("Existing configuration detected. Press Enter to keep current values or enter different values.\n");
159
+ }
160
+ else {
161
+ console.log("Before proceeding, create an Oura application:");
162
+ console.log(" 1. Go to https://developer.ouraring.com");
163
+ console.log(' 2. Navigate to "My Applications"');
164
+ console.log(" 3. Create a new application");
165
+ console.log(" 4. Set the redirect URI to: http://localhost:9876/callback");
166
+ console.log("");
167
+ }
168
+ // Step 1: Credentials
169
+ const clientId = await ask(rl, "Oura Client ID:", existing.clientId);
170
+ const clientSecret = await ask(rl, "Oura Client Secret:", existing.clientSecret);
171
+ withProgress("Saving credentials", () => (0, token_store_1.updateConfig)({ clientId, clientSecret }));
172
+ // Step 2: OAuth flow
173
+ let skipOAuth = false;
174
+ if (isRerun && existing.accessToken) {
175
+ skipOAuth = !(await confirm(rl, "Re-authorize with Oura? (only needed if tokens are broken)", false));
176
+ }
177
+ if (!skipOAuth) {
178
+ const authorizeUrl = (0, oauth_1.buildAuthorizeUrl)(clientId);
179
+ console.log("\nOpening browser to authorize OuraClaw...");
180
+ openUrl(authorizeUrl);
181
+ console.log("Waiting for OAuth callback on http://localhost:9876/callback ...");
182
+ const code = await (0, oauth_1.captureOAuthCallback)();
183
+ await withProgress("Exchanging code for tokens", async () => {
184
+ const tokenResponse = await (0, oauth_1.exchangeCodeForTokens)(clientId, clientSecret, code);
185
+ (0, token_store_1.saveTokens)(tokenResponse);
186
+ });
187
+ console.log("");
188
+ }
189
+ else {
190
+ console.log("Skipping OAuth — keeping existing tokens.\n");
191
+ }
192
+ // Step 3: Channel + target preference
193
+ const availableTargets = withProgress("Loading configured channels", () => getConfiguredChannelTargets());
194
+ let channel = "default";
195
+ let channelTarget;
196
+ if (availableTargets.length === 0) {
197
+ console.log("No messaging channels configured. Using default (active channel at delivery time).");
198
+ }
199
+ else {
200
+ const choices = [
201
+ "default (active channel at delivery time)",
202
+ ...availableTargets.map((t) => t.label),
203
+ ];
204
+ // Find the existing selection to use as default
205
+ let defaultIdx = 0;
206
+ if (isRerun && existing.preferredChannel && existing.preferredChannelTarget) {
207
+ const existingLabel = availableTargets.find((t) => t.channel === existing.preferredChannel && t.target === existing.preferredChannelTarget)?.label;
208
+ if (existingLabel) {
209
+ const idx = choices.indexOf(existingLabel);
210
+ if (idx >= 0)
211
+ defaultIdx = idx;
212
+ }
213
+ }
214
+ else if (isRerun && existing.preferredChannel === "default") {
215
+ defaultIdx = 0;
216
+ }
217
+ const chosen = await select(rl, "Deliver summaries to:", choices, defaultIdx);
218
+ if (!chosen.startsWith("default")) {
219
+ const match = availableTargets.find((t) => t.label === chosen);
220
+ if (match) {
221
+ channel = match.channel;
222
+ channelTarget = match.target;
223
+ }
224
+ }
225
+ }
226
+ (0, token_store_1.updateConfig)({
227
+ preferredChannel: channel,
228
+ preferredChannelTarget: channelTarget,
229
+ });
230
+ // Step 4: Schedule
231
+ const enableScheduled = await confirm(rl, "Enable scheduled morning & evening summaries?", existing.scheduledMessages !== false);
232
+ if (enableScheduled) {
233
+ const morningTime = await ask(rl, "Morning summary time (HH:MM):", existing.morningTime || "07:00");
234
+ const eveningTime = await ask(rl, "Evening summary time (HH:MM):", existing.eveningTime || "21:00");
235
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
236
+ console.log(` Timezone: ${timezone} (detected from system)`);
237
+ (0, token_store_1.updateConfig)({
238
+ scheduledMessages: true,
239
+ morningTime,
240
+ eveningTime,
241
+ timezone,
242
+ });
243
+ withProgress("\nScheduling daily summaries", () => (0, cron_setup_1.createCronJobs)((0, token_store_1.readConfig)()));
244
+ }
245
+ else {
246
+ (0, token_store_1.updateConfig)({ scheduledMessages: false });
247
+ const config = (0, token_store_1.readConfig)();
248
+ if (config.morningCronJobId || config.eveningCronJobId) {
249
+ withProgress("Removing existing cron jobs", () => (0, cron_setup_1.removeCronJobs)(config));
250
+ }
251
+ }
252
+ // Summary
253
+ const finalConfig = (0, token_store_1.readConfig)();
254
+ console.log("\n=== Setup Complete ===");
255
+ console.log(` Client ID: ${finalConfig.clientId}`);
256
+ console.log(` Token expires: ${new Date(finalConfig.tokenExpiresAt).toLocaleString()}`);
257
+ console.log(` Channel: ${finalConfig.preferredChannel || "default"}`);
258
+ if (finalConfig.preferredChannelTarget) {
259
+ console.log(` Channel target: ${finalConfig.preferredChannelTarget}`);
260
+ }
261
+ if (finalConfig.scheduledMessages) {
262
+ console.log(` Morning summary: ${finalConfig.morningTime} ${finalConfig.timezone}`);
263
+ console.log(` Evening summary: ${finalConfig.eveningTime} ${finalConfig.timezone}`);
264
+ }
265
+ else {
266
+ console.log(" Scheduled messages: disabled");
267
+ }
268
+ console.log("\nYou can now ask your agent about your Oura data!");
269
+ console.log('Try: "How did I sleep last night?"\n');
270
+ }
271
+ finally {
272
+ rl.close();
273
+ }
274
+ }
275
+ async function statusCommand() {
276
+ const config = (0, token_store_1.readConfig)();
277
+ console.log("\n=== OuraClaw Status ===\n");
278
+ if (!config.accessToken) {
279
+ console.log(" Status: Not connected");
280
+ console.log(' Run "openclaw ouraclaw setup" to get started.\n');
281
+ return;
282
+ }
283
+ console.log(" Status: Connected");
284
+ console.log(` Client ID: ${config.clientId || "not set"}`);
285
+ if (config.tokenExpiresAt) {
286
+ const expiry = new Date(config.tokenExpiresAt);
287
+ const now = new Date();
288
+ const hoursLeft = Math.round((expiry.getTime() - now.getTime()) / (1000 * 60 * 60));
289
+ console.log(` Token expires: ${expiry.toLocaleString()} (${hoursLeft}h from now)`);
290
+ }
291
+ console.log(` Channel: ${config.preferredChannel || "default"}`);
292
+ if (config.preferredChannelTarget) {
293
+ console.log(` Channel target: ${config.preferredChannelTarget}`);
294
+ }
295
+ if (config.scheduledMessages) {
296
+ console.log(` Morning summary: ${config.morningTime} ${config.timezone}`);
297
+ console.log(` Evening summary: ${config.eveningTime} ${config.timezone}`);
298
+ console.log(` Morning job ID: ${config.morningCronJobId || "none"}`);
299
+ console.log(` Evening job ID: ${config.eveningCronJobId || "none"}`);
300
+ }
301
+ else {
302
+ console.log(" Scheduled messages: disabled");
303
+ }
304
+ console.log("");
305
+ }
306
+ async function testCommand() {
307
+ const config = (0, token_store_1.readConfig)();
308
+ if (!config.accessToken) {
309
+ console.log('Not connected. Run "openclaw ouraclaw setup" first.');
310
+ return;
311
+ }
312
+ console.log("\nFetching today's Oura data...\n");
313
+ const today = new Date().toISOString().split("T")[0];
314
+ const tomorrow = new Date(Date.now() + 86_400_000).toISOString().split("T")[0];
315
+ try {
316
+ const sleep = await (0, oura_client_1.fetchOuraData)(config.accessToken, "daily_sleep", today, tomorrow);
317
+ console.log(`Daily Sleep: ${JSON.stringify(sleep, null, 2)}\n`);
318
+ const readiness = await (0, oura_client_1.fetchOuraData)(config.accessToken, "daily_readiness", today, tomorrow);
319
+ console.log(`Daily Readiness: ${JSON.stringify(readiness, null, 2)}\n`);
320
+ const activity = await (0, oura_client_1.fetchOuraData)(config.accessToken, "daily_activity", today, tomorrow);
321
+ console.log(`Daily Activity: ${JSON.stringify(activity, null, 2)}\n`);
322
+ console.log("Connection test successful!");
323
+ }
324
+ catch (err) {
325
+ console.log(`Error fetching data: ${err.message}`);
326
+ console.log('You may need to re-run "openclaw ouraclaw setup" to refresh your token.');
327
+ }
328
+ console.log("");
329
+ }
330
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { OuraConfig } from "./types";
2
+ export declare function createCronJobs(config: OuraConfig): void;
3
+ export declare function removeCronJobs(config: OuraConfig): void;
4
+ //# sourceMappingURL=cron-setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-setup.d.ts","sourceRoot":"","sources":["../src/cron-setup.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AA6BrC,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CA4FvD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAyBvD"}
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCronJobs = createCronJobs;
4
+ exports.removeCronJobs = removeCronJobs;
5
+ const child_process_1 = require("child_process");
6
+ const token_store_1 = require("./token-store");
7
+ function timeToCron(time) {
8
+ const [hours, minutes] = time.split(":").map(Number);
9
+ return `${minutes} ${hours} * * *`;
10
+ }
11
+ function runOpenclaw(args) {
12
+ return (0, child_process_1.execFileSync)("openclaw", args, { encoding: "utf-8" }).trim();
13
+ }
14
+ function listAllJobs() {
15
+ try {
16
+ const output = runOpenclaw(["cron", "list", "--json"]);
17
+ const data = JSON.parse(output);
18
+ return Array.isArray(data) ? data : data?.jobs || [];
19
+ }
20
+ catch {
21
+ return [];
22
+ }
23
+ }
24
+ const OURACLAW_JOB_NAMES = [
25
+ "OuraClaw Morning Summary",
26
+ "OuraClaw Evening Summary",
27
+ "ouraclaw-morning",
28
+ "ouraclaw-evening",
29
+ ];
30
+ function createCronJobs(config) {
31
+ const timezone = config.timezone || "UTC";
32
+ const morningTime = config.morningTime || "07:00";
33
+ const eveningTime = config.eveningTime || "21:00";
34
+ // Single list call to find all jobs to remove
35
+ const existingJobs = listAllJobs();
36
+ const idsToRemove = new Set();
37
+ // By stored UUID
38
+ if (config.morningCronJobId)
39
+ idsToRemove.add(config.morningCronJobId);
40
+ if (config.eveningCronJobId)
41
+ idsToRemove.add(config.eveningCronJobId);
42
+ // By name (handles upgrades from older naming or missing UUIDs)
43
+ for (const job of existingJobs) {
44
+ if (OURACLAW_JOB_NAMES.includes(job.name)) {
45
+ idsToRemove.add(job.id);
46
+ }
47
+ }
48
+ for (const id of idsToRemove) {
49
+ try {
50
+ runOpenclaw(["cron", "remove", id]);
51
+ }
52
+ catch {
53
+ // Job may already be gone
54
+ }
55
+ }
56
+ // Create morning job
57
+ const morningMsg = [
58
+ "Fetch my Oura Ring data for this morning's summary.",
59
+ "Use the oura_data tool to get daily_sleep, sleep (detailed periods), daily_readiness, daily_activity, and daily_stress for today.",
60
+ "Also fetch yesterday's daily_activity as a fallback in case today's isn't ready yet.",
61
+ "Format the results as a morning health summary using the oura skill's morning template.",
62
+ "Remember: 8-10 lines max, include date, use emoji sparingly, warm but not cheesy, no app links.",
63
+ ].join(" ");
64
+ const morningArgs = [
65
+ "cron", "add",
66
+ "--name", "OuraClaw Morning Summary",
67
+ "--cron", timeToCron(morningTime),
68
+ "--tz", timezone,
69
+ "--session", "isolated",
70
+ "--message", morningMsg,
71
+ "--deliver",
72
+ ];
73
+ if (config.preferredChannel && config.preferredChannel !== "default") {
74
+ morningArgs.push("--channel", config.preferredChannel);
75
+ if (config.preferredChannelTarget) {
76
+ morningArgs.push("--to", config.preferredChannelTarget);
77
+ }
78
+ }
79
+ runOpenclaw(morningArgs);
80
+ // Create evening job
81
+ const eveningMsg = [
82
+ "Fetch my Oura Ring data for this evening's summary.",
83
+ "Use the oura_data tool to get daily_activity, daily_readiness, daily_stress, and daily_sleep for today.",
84
+ "Format the results as an evening health summary using the oura skill's evening template.",
85
+ "Remember: 6-8 lines max, include date, focus on activity, mention last night's sleep as a recap, end with a warm wind-down nudge, no app links.",
86
+ ].join(" ");
87
+ const eveningArgs = [
88
+ "cron", "add",
89
+ "--name", "OuraClaw Evening Summary",
90
+ "--cron", timeToCron(eveningTime),
91
+ "--tz", timezone,
92
+ "--session", "isolated",
93
+ "--message", eveningMsg,
94
+ "--deliver",
95
+ ];
96
+ if (config.preferredChannel && config.preferredChannel !== "default") {
97
+ eveningArgs.push("--channel", config.preferredChannel);
98
+ if (config.preferredChannelTarget) {
99
+ eveningArgs.push("--to", config.preferredChannelTarget);
100
+ }
101
+ }
102
+ runOpenclaw(eveningArgs);
103
+ // Single list call to look up both new UUIDs
104
+ const newJobs = listAllJobs();
105
+ const morningJob = newJobs.find((j) => j.name === "OuraClaw Morning Summary");
106
+ const eveningJob = newJobs.find((j) => j.name === "OuraClaw Evening Summary");
107
+ (0, token_store_1.updateConfig)({
108
+ morningCronJobId: morningJob?.id || undefined,
109
+ eveningCronJobId: eveningJob?.id || undefined,
110
+ });
111
+ }
112
+ function removeCronJobs(config) {
113
+ const existingJobs = listAllJobs();
114
+ const idsToRemove = new Set();
115
+ if (config.morningCronJobId)
116
+ idsToRemove.add(config.morningCronJobId);
117
+ if (config.eveningCronJobId)
118
+ idsToRemove.add(config.eveningCronJobId);
119
+ for (const job of existingJobs) {
120
+ if (OURACLAW_JOB_NAMES.includes(job.name)) {
121
+ idsToRemove.add(job.id);
122
+ }
123
+ }
124
+ for (const id of idsToRemove) {
125
+ try {
126
+ runOpenclaw(["cron", "remove", id]);
127
+ }
128
+ catch {
129
+ // Job may already be gone
130
+ }
131
+ }
132
+ (0, token_store_1.updateConfig)({
133
+ morningCronJobId: undefined,
134
+ eveningCronJobId: undefined,
135
+ });
136
+ }
137
+ //# sourceMappingURL=cron-setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-setup.js","sourceRoot":"","sources":["../src/cron-setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export default function ouraclaw(api: any): void;
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,GAAG,QAOxC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = ouraclaw;
4
+ const tool_1 = require("./tool");
5
+ const cli_1 = require("./cli");
6
+ function ouraclaw(api) {
7
+ // Register the oura_data agent tool
8
+ const tool = (0, tool_1.defineOuraDataTool)();
9
+ api.registerTool(tool);
10
+ // Register CLI commands (openclaw ouraclaw setup|status|test)
11
+ (0, cli_1.registerCli)(api);
12
+ }
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAGA,2BAOC;AAVD,iCAA4C;AAC5C,+BAAoC;AAEpC,SAAwB,QAAQ,CAAC,GAAQ;IACvC,oCAAoC;IACpC,MAAM,IAAI,GAAG,IAAA,yBAAkB,GAAE,CAAC;IAClC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAEvB,8DAA8D;IAC9D,IAAA,iBAAW,EAAC,GAAG,CAAC,CAAC;AACnB,CAAC"}