@2en/clawly-plugins 1.23.1 → 1.24.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
@@ -27,9 +27,11 @@
27
27
  * - before_tool_call — enforces delivery fields on cron.create
28
28
  * - agent_end — sends push notification when client is offline
29
29
  * - gateway_start — auto-approves device pairing for Clawly mobile clients (clientId: openclaw-ios)
30
+ * - gateway_start — registers auto-update cron job (0 3 * * *) for clawly-plugins
30
31
  */
31
32
 
32
33
  import {registerAutoPair} from './auto-pair'
34
+ import {registerAutoUpdate} from './internal/hooks/auto-update'
33
35
  import {registerCalendar} from './calendar'
34
36
  import {registerCommands} from './command'
35
37
  import {setupConfig} from './config-setup'
@@ -186,6 +188,7 @@ export default {
186
188
  setupConfig(api)
187
189
  registerGateway(api)
188
190
  registerAutoPair(api)
191
+ registerAutoUpdate(api)
189
192
 
190
193
  // Email & calendar (optional — requires skillGatewayBaseUrl + skillGatewayToken in config)
191
194
  const gw = getGatewayConfig(api)
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Registers a cron job (0 3 * * *) on gateway_start that
3
+ * checks user presence and auto-updates clawly-plugins when offline.
4
+ */
5
+ import {$} from 'zx'
6
+
7
+ import type {PluginApi} from '../../index'
8
+
9
+ $.verbose = false
10
+
11
+ // ── Types ──────────────────────────────────────────────────────
12
+
13
+ interface CronJobEntry {
14
+ id: string
15
+ name: string
16
+ description: string
17
+ enabled: boolean
18
+ schedule: {kind: 'cron'; expr: string; tz?: string} | {kind: string}
19
+ sessionTarget: string
20
+ wakeMode: string
21
+ payload: {kind: string; message?: string}
22
+ delivery: {mode: string}
23
+ }
24
+
25
+ interface JobConfig {
26
+ description: string
27
+ cron: string
28
+ session: 'main' | 'isolated'
29
+ wake: 'now' | 'next-heartbeat'
30
+ deliver: boolean
31
+ message: string
32
+ }
33
+
34
+ // ── Config ─────────────────────────────────────────────────────
35
+
36
+ const JOB_NAME = 'Clawly Plugins Auto-Update'
37
+
38
+ const JOB_CONFIG: JobConfig = {
39
+ description: 'Auto-update clawly-plugins when user is offline',
40
+ cron: '0 3 * * *',
41
+ session: 'isolated',
42
+ wake: 'now',
43
+ deliver: false,
44
+ message: [
45
+ 'Auto-update check for clawly-plugins.',
46
+ '',
47
+ 'Steps:',
48
+ '1. Call the clawly_is_user_online tool to check if the user is online.',
49
+ '2. If the user IS online, stop — do nothing.',
50
+ '3. If the user is NOT online, run this exact command in terminal:',
51
+ ` openclaw gateway call clawly.plugins.update --json --params '${JSON.stringify({pluginId: 'clawly-plugins', npmPkgName: '@2en/clawly-plugins', strategy: 'force', restart: true})}'`,
52
+ '',
53
+ 'Do not send any messages to the user. Just execute the steps silently.',
54
+ ].join('\n'),
55
+ }
56
+
57
+ // ── Helpers ────────────────────────────────────────────────────
58
+
59
+ function configToArgs(config: JobConfig): string[] {
60
+ const args = [
61
+ '--description',
62
+ config.description,
63
+ '--cron',
64
+ config.cron,
65
+ '--session',
66
+ config.session,
67
+ '--wake',
68
+ config.wake,
69
+ '--message',
70
+ config.message,
71
+ ]
72
+ if (!config.deliver) args.push('--no-deliver')
73
+ return args
74
+ }
75
+
76
+ function needsUpdate(job: CronJobEntry, config: JobConfig): boolean {
77
+ if (job.description !== config.description) return true
78
+ if (job.schedule.kind !== 'cron' || (job.schedule as {expr: string}).expr !== config.cron)
79
+ return true
80
+ if (job.sessionTarget !== config.session) return true
81
+ if (job.wakeMode !== config.wake) return true
82
+ if (job.payload.message !== config.message) return true
83
+ const wantMode = config.deliver ? 'announce' : 'none'
84
+ if (job.delivery.mode !== wantMode) return true
85
+ return false
86
+ }
87
+
88
+ async function findJob(): Promise<CronJobEntry | null> {
89
+ try {
90
+ const {stdout} = await $`openclaw cron list --json`
91
+ const parsed = JSON.parse(stdout)
92
+ const jobs: unknown[] = parsed?.jobs ?? parsed ?? []
93
+ if (!Array.isArray(jobs)) return null
94
+ return (jobs.find((j: any) => j.name === JOB_NAME) as CronJobEntry) ?? null
95
+ } catch {
96
+ return null
97
+ }
98
+ }
99
+
100
+ // ── Registration ───────────────────────────────────────────────
101
+
102
+ export function registerAutoUpdate(api: PluginApi) {
103
+ api.on('gateway_start', async () => {
104
+ try {
105
+ const existing = await findJob()
106
+
107
+ if (existing) {
108
+ if (!needsUpdate(existing, JOB_CONFIG)) {
109
+ api.logger.info('auto-update: cron job up to date')
110
+ return
111
+ }
112
+ await $`openclaw cron edit ${[existing.id, ...configToArgs(JOB_CONFIG)]}`
113
+ api.logger.info('auto-update: updated cron job')
114
+ } else {
115
+ await $`openclaw cron add ${['--name', JOB_NAME, ...configToArgs(JOB_CONFIG)]}`
116
+ api.logger.info('auto-update: registered cron job')
117
+ }
118
+ } catch (err) {
119
+ api.logger.warn(`auto-update: failed to register cron job: ${String(err)}`)
120
+ }
121
+ })
122
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2en/clawly-plugins",
3
- "version": "1.23.1",
3
+ "version": "1.24.0",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "repository": {
@@ -26,7 +26,8 @@
26
26
  "outbound.ts",
27
27
  "model-gateway-setup.ts",
28
28
  "skill-command-restore.ts",
29
- "openclaw.plugin.json"
29
+ "openclaw.plugin.json",
30
+ "internal"
30
31
  ],
31
32
  "publishConfig": {
32
33
  "access": "public"