@2en/clawly-plugins 1.3.0 → 1.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2en/clawly-plugins",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "repository": {
@@ -12,6 +12,7 @@
12
12
  "zx": "npm:zx@8.8.5-lite"
13
13
  },
14
14
  "files": [
15
+ "tools",
15
16
  "index.ts",
16
17
  "channel.ts",
17
18
  "cron-hook.ts",
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Agent tool: clawly_is_user_online — check if the user's mobile
3
+ * device is currently connected to the OpenClaw gateway.
4
+ *
5
+ */
6
+
7
+ import type {PluginApi} from '../index'
8
+ import {isClientOnline} from '../presence'
9
+
10
+ const TOOL_NAME = 'clawly_is_user_online'
11
+
12
+ const parameters: Record<string, unknown> = {
13
+ type: 'object',
14
+ properties: {
15
+ host: {
16
+ type: 'string',
17
+ description: 'Presence host identifier (default: "openclaw-ios")',
18
+ },
19
+ },
20
+ }
21
+
22
+ export function registerIsUserOnlineTool(api: PluginApi) {
23
+ api.registerTool({
24
+ name: TOOL_NAME,
25
+ description: "Check if the user's mobile device is currently online.",
26
+ parameters,
27
+ async execute(_toolCallId, params) {
28
+ const host = typeof params.host === 'string' ? params.host : undefined
29
+ const isOnline = await isClientOnline(host)
30
+ return {content: [{type: 'text', text: JSON.stringify({isOnline})}]}
31
+ },
32
+ })
33
+
34
+ api.logger.info(`tool: registered ${TOOL_NAME} agent tool`)
35
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Agent tool: clawly_send_app_push — send a push notification to
3
+ * the user's phone from the LLM agent during a conversation.
4
+ *
5
+ * Expo push API reference:
6
+ * https://docs.expo.dev/push-notifications/sending-notifications/
7
+ */
8
+
9
+ import type {PluginApi} from '../index'
10
+ import {sendPushNotification} from '../notification'
11
+
12
+ const TOOL_NAME = 'clawly_send_app_push'
13
+
14
+ const parameters: Record<string, unknown> = {
15
+ type: 'object',
16
+ required: ['body'],
17
+ properties: {
18
+ body: {type: 'string', description: 'Notification message'},
19
+ title: {type: 'string', description: 'Title (default: "Clawly")'},
20
+ subtitle: {type: 'string', description: 'iOS subtitle'},
21
+ sound: {
22
+ type: ['string', 'null'],
23
+ description: 'Sound name (default: "default")',
24
+ },
25
+ badge: {type: 'number', description: 'iOS badge count'},
26
+ data: {type: 'object', description: 'Custom JSON payload'},
27
+ ttl: {type: 'number', description: 'Seconds to keep for redelivery'},
28
+ expiration: {type: 'number', description: 'Unix timestamp expiry'},
29
+ priority: {
30
+ type: 'string',
31
+ enum: ['default', 'normal', 'high'],
32
+ description: 'Delivery priority',
33
+ },
34
+ channelId: {type: 'string', description: 'Android notification channel'},
35
+ categoryId: {type: 'string', description: 'Notification category'},
36
+ interruptionLevel: {
37
+ type: 'string',
38
+ enum: ['active', 'critical', 'passive', 'time-sensitive'],
39
+ description: 'iOS interruption level',
40
+ },
41
+ mutableContent: {type: 'boolean', description: 'iOS mutable content'},
42
+ richContent: {
43
+ type: 'object',
44
+ description: 'Rich content (e.g. {image: url})',
45
+ },
46
+ },
47
+ }
48
+
49
+ export function registerSendAppPushTool(api: PluginApi) {
50
+ api.registerTool({
51
+ name: TOOL_NAME,
52
+ description: "Send a push notification to the user's phone.",
53
+ parameters,
54
+ async execute(_toolCallId, params) {
55
+ const body = typeof params.body === 'string' ? params.body.trim() : ''
56
+ if (!body) {
57
+ return {content: [{type: 'text', text: JSON.stringify({error: 'body is required'})}]}
58
+ }
59
+
60
+ const title = typeof params.title === 'string' ? params.title : undefined
61
+ const data =
62
+ typeof params.data === 'object' && params.data !== null
63
+ ? (params.data as Record<string, unknown>)
64
+ : undefined
65
+
66
+ // Collect Expo-specific extras (everything except body/title/data)
67
+ const {body: _body, title: _title, data: _data, ...extras} = params
68
+ const hasExtras = Object.keys(extras).length > 0
69
+
70
+ const sent = await sendPushNotification(
71
+ {body, title, data},
72
+ api,
73
+ hasExtras ? extras : undefined,
74
+ )
75
+ return {content: [{type: 'text', text: JSON.stringify({sent})}]}
76
+ },
77
+ })
78
+
79
+ api.logger.info(`tool: registered ${TOOL_NAME} agent tool`)
80
+ }