oomi-ai 0.3.6 → 0.3.7

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.
@@ -279,3 +279,19 @@ Rules:
279
279
  - Never present stale HealthKit values as current values.
280
280
  - Do not infer unavailable health fields.
281
281
  - Do not request HealthKit directly from the phone; the Oomi mobile app owns permission prompts and syncs approved data to the backend.
282
+
283
+ ## Phone Notifications
284
+
285
+ To reach the user on their phone when they are not in the conversation, send a push notification:
286
+
287
+ ```bash
288
+ oomi notify "Your 7-day plan is ready. Want to look now?" --title "Fitness" --json
289
+ ```
290
+
291
+ Rules:
292
+
293
+ - Notify only for things worth interrupting the user for: a reminder they asked for, a finished task, or something time-sensitive. Say everything else in chat.
294
+ - Keep the message short and specific. The title defaults to your agent name.
295
+ - Tapping the notification opens the Oomi app to the conversation, so follow up in chat.
296
+ - If `notification.status` is `skipped`, tell the user `notification.guidance` instead of retrying.
297
+ - If the request is rate limited, do not retry until `retryAfterSeconds` has passed.
package/bin/oomi-ai.js CHANGED
@@ -239,6 +239,10 @@ Commands:
239
239
  Request the linked Oomi mobile app to sync fresh HealthKit context.
240
240
  Use --wait to poll until fresh context is uploaded or the timeout expires.
241
241
 
242
+ notify "<message>" [--title TITLE]
243
+ Send the linked user a push notification on their phone. Use it for things worth
244
+ interrupting them for; say everything else in chat. Limited per hour.
245
+
242
246
  Common flags:
243
247
  --agents-file PATH Override AGENTS.md path
244
248
  --workspace PATH Override OpenClaw workspace root
@@ -572,6 +576,16 @@ async function handleContextHealthCommand(flags = {}) {
572
576
  printStructuredResult(payload, isTruthyFlag(flags.json));
573
577
  }
574
578
 
579
+ async function handleNotifyCommand(message, flags = {}) {
580
+ const client = createCliPersonaApiClient(flags);
581
+ const payload = await client.sendNotification({
582
+ body: message,
583
+ title: typeof flags.title === 'string' ? flags.title : undefined,
584
+ kind: typeof flags.kind === 'string' ? flags.kind : undefined,
585
+ });
586
+ printStructuredResult(payload, isTruthyFlag(flags.json));
587
+ }
588
+
575
589
  async function handleContextFinanceCommand(_flags = {}) {
576
590
  throw new Error("oomi context finance is off until Gate A. Use the signed-in web Finance persona-app. Do not read bank balances from the connected OpenClaw shell.");
577
591
  }
@@ -4429,6 +4443,17 @@ async function main() {
4429
4443
  return;
4430
4444
  }
4431
4445
 
4446
+ if (command === 'notify') {
4447
+ // parseArgs reads the first word as a subcommand, so the message is everything after `notify`.
4448
+ const message = [subcommand, ...args.positionals].filter(Boolean).join(' ').trim()
4449
+ || (typeof args.flags.body === 'string' ? args.flags.body.trim() : '');
4450
+ if (!message) {
4451
+ throw new Error('A message is required. Usage: oomi notify "<message>" [--title <title>]');
4452
+ }
4453
+ await handleNotifyCommand(message, args.flags);
4454
+ return;
4455
+ }
4456
+
4432
4457
  console.error(`Unknown command: ${command} ${subcommand || ''}`.trim());
4433
4458
  usage();
4434
4459
  process.exit(1);
@@ -171,5 +171,24 @@ export function createPersonaApiClient({
171
171
  },
172
172
  });
173
173
  },
174
+
175
+ sendNotification({ body, title, kind } = {}) {
176
+ const safeBody = trimString(body);
177
+ if (!safeBody) {
178
+ throw new Error('Notification body is required.');
179
+ }
180
+
181
+ return postJson({
182
+ fetchImpl,
183
+ backendUrl: resolvedBackendUrl,
184
+ deviceToken: resolvedDeviceToken,
185
+ path: '/v1/notifications',
186
+ body: {
187
+ body: safeBody,
188
+ title: trimString(title) || undefined,
189
+ kind: trimString(kind) || undefined,
190
+ },
191
+ });
192
+ },
174
193
  };
175
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oomi-ai",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "Managed Oomi channel, bridge, voice, and persona app API tooling for OpenClaw",
5
5
  "bin": {
6
6
  "oomi": "bin/oomi-ai.js"
@@ -127,6 +127,21 @@ Rules:
127
127
  - never present stale HealthKit values as current values
128
128
  - do not ask HealthKit directly; the Oomi mobile app syncs approved HealthKit data to the backend
129
129
 
130
+ ## Phone Notifications
131
+
132
+ To reach the user on their phone when they are not in the conversation:
133
+
134
+ ```bash
135
+ oomi notify "Your 7-day plan is ready. Want to look now?" --title "Fitness" --json
136
+ ```
137
+
138
+ Rules:
139
+ - notify only for things worth interrupting the user for (a reminder they asked for, a finished task, something time-sensitive); say everything else in chat
140
+ - keep it short and specific; the title defaults to your agent name
141
+ - tapping it opens the Oomi app to the conversation, so follow up in chat
142
+ - if `notification.status` is `skipped`, tell the user `notification.guidance` instead of retrying
143
+ - if rate limited, wait `retryAfterSeconds` before trying again
144
+
130
145
  ## Hidden Speech Payload
131
146
 
132
147
  Managed voice can carry a hidden TTS-only speech sidecar alongside the normal assistant message.