@2en/clawly-plugins 1.1.1 → 1.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/index.ts CHANGED
@@ -9,6 +9,10 @@
9
9
  * - clawly.agent.send — send a message to the agent (+ optional push)
10
10
  * - clawly.agent.echo — echo-wrapped agent message (bypasses LLM)
11
11
  *
12
+ * Agent tools:
13
+ * - clawly_is_user_online — check if user's device is connected
14
+ * - clawly_send_app_push — send a push notification to user's device
15
+ *
12
16
  * Commands:
13
17
  * - /clawly_echo — echo text back without LLM
14
18
  *
@@ -17,6 +21,7 @@
17
21
  */
18
22
 
19
23
  import {registerAgentSend} from './agent-send'
24
+ import {registerIsUserOnlineTool, registerSendAppPushTool} from './tools'
20
25
  import {registerEchoCommand} from './echo'
21
26
  import {registerNotification} from './notification'
22
27
  import {registerOutboundHook, registerOutboundMethods} from './outbound'
@@ -53,6 +58,18 @@ export type PluginApi = {
53
58
  requireAuth?: boolean
54
59
  handler: (ctx: {args?: string}) => Promise<{text: string}> | {text: string}
55
60
  }) => void
61
+ registerTool: (
62
+ tool: {
63
+ name: string
64
+ description: string
65
+ parameters: Record<string, unknown>
66
+ execute: (
67
+ toolCallId: string,
68
+ params: Record<string, unknown>,
69
+ ) => Promise<{content: Array<{type: string; text: string}>; details?: unknown}>
70
+ },
71
+ opts?: {optional?: boolean},
72
+ ) => void
56
73
  }
57
74
 
58
75
  export default {
@@ -66,6 +83,8 @@ export default {
66
83
  registerPresence(api)
67
84
  registerNotification(api)
68
85
  registerAgentSend(api)
86
+ registerIsUserOnlineTool(api)
87
+ registerSendAppPushTool(api)
69
88
  api.logger.info(`Loaded ${api.id} plugin.`)
70
89
  },
71
90
  }
package/notification.ts CHANGED
@@ -19,24 +19,6 @@ const TOKEN_DIR = path.join(os.homedir(), '.openclaw', 'clawly')
19
19
  const TOKEN_FILE = path.join(TOKEN_DIR, 'expo-push-token.json')
20
20
  const EXPO_PUSH_URL = 'https://exp.host/--/api/v2/push/send'
21
21
 
22
- let pushToken: string | null = null
23
-
24
- function loadPersistedToken(api: PluginApi): void {
25
- try {
26
- if (fs.existsSync(TOKEN_FILE)) {
27
- const data = JSON.parse(fs.readFileSync(TOKEN_FILE, 'utf-8'))
28
- if (typeof data.token === 'string' && data.token) {
29
- pushToken = data.token
30
- api.logger.info(`notification: loaded persisted push token`)
31
- }
32
- }
33
- } catch (err) {
34
- api.logger.warn(
35
- `notification: failed to load persisted token: ${err instanceof Error ? err.message : String(err)}`,
36
- )
37
- }
38
- }
39
-
40
22
  function persistToken(token: string, api: PluginApi): void {
41
23
  try {
42
24
  fs.mkdirSync(TOKEN_DIR, {recursive: true})
@@ -49,14 +31,24 @@ function persistToken(token: string, api: PluginApi): void {
49
31
  }
50
32
 
51
33
  export function getPushToken(): string | null {
52
- return pushToken
34
+ try {
35
+ if (fs.existsSync(TOKEN_FILE)) {
36
+ const data = JSON.parse(fs.readFileSync(TOKEN_FILE, 'utf-8'))
37
+ if (typeof data.token === 'string' && data.token) {
38
+ return data.token
39
+ }
40
+ }
41
+ } catch {}
42
+ return null
53
43
  }
54
44
 
55
45
  export async function sendPushNotification(
56
46
  opts: {body: string; title?: string; data?: Record<string, unknown>},
57
47
  api: PluginApi,
48
+ extras?: Record<string, unknown>,
58
49
  ): Promise<boolean> {
59
- if (!pushToken) {
50
+ const token = getPushToken()
51
+ if (!token) {
60
52
  api.logger.warn('notification: no push token registered, skipping notification')
61
53
  return false
62
54
  }
@@ -66,13 +58,15 @@ export async function sendPushNotification(
66
58
  method: 'POST',
67
59
  headers: {'Content-Type': 'application/json'},
68
60
  body: JSON.stringify({
69
- to: pushToken,
61
+ to: token,
70
62
  sound: 'default',
71
63
  title: opts.title ?? 'Clawly',
72
64
  body: opts.body,
73
65
  data: opts.data,
66
+ ...extras,
74
67
  }),
75
68
  })
69
+ const json = await res.json()
76
70
 
77
71
  if (!res.ok) {
78
72
  api.logger.error(`notification: push failed — ${res.status} ${res.statusText}`)
@@ -90,8 +84,6 @@ export async function sendPushNotification(
90
84
  }
91
85
 
92
86
  export function registerNotification(api: PluginApi) {
93
- loadPersistedToken(api)
94
-
95
87
  api.registerGatewayMethod('clawly.notification.setToken', async ({params, respond}) => {
96
88
  const token = typeof params.token === 'string' ? params.token.trim() : ''
97
89
 
@@ -100,7 +92,6 @@ export function registerNotification(api: PluginApi) {
100
92
  return
101
93
  }
102
94
 
103
- pushToken = token
104
95
  persistToken(token, api)
105
96
  api.logger.info('notification: push token registered')
106
97
  respond(true, {registered: true})
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2en/clawly-plugins",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "repository": {
@@ -18,6 +18,7 @@
18
18
  "presence.ts",
19
19
  "notification.ts",
20
20
  "agent-send.ts",
21
+ "tools.ts",
21
22
  "openclaw.plugin.json"
22
23
  ],
23
24
  "publishConfig": {
package/tools.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {registerIsUserOnlineTool} from './tools/clawly-is-user-online'
2
+ export {registerSendAppPushTool} from './tools/clawly-send-app-push'