openclaw-scheduler 0.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.
Files changed (70) hide show
  1. package/AGENTS.md +302 -0
  2. package/BEST-PRACTICES.md +506 -0
  3. package/CHANGELOG.md +82 -0
  4. package/CODE_OF_CONDUCT.md +22 -0
  5. package/CONTEXT.md +26 -0
  6. package/CONTRIBUTING.md +73 -0
  7. package/IMPLEMENTATION_SPEC.md +170 -0
  8. package/INSTALL-ADDITIONAL-HOST.md +333 -0
  9. package/INSTALL-LINUX.md +419 -0
  10. package/INSTALL-WINDOWS.md +305 -0
  11. package/INSTALL.md +364 -0
  12. package/JOB-QUICK-REF.md +222 -0
  13. package/LICENSE +21 -0
  14. package/QUICK-START.md +256 -0
  15. package/README.md +2170 -0
  16. package/SECURITY.md +34 -0
  17. package/UNINSTALL.md +129 -0
  18. package/UPGRADING.md +436 -0
  19. package/agents.js +67 -0
  20. package/approval.js +107 -0
  21. package/backup.js +390 -0
  22. package/bin/openclaw-scheduler.js +138 -0
  23. package/cli.js +1083 -0
  24. package/db.js +122 -0
  25. package/dispatch/529-recovery.mjs +204 -0
  26. package/dispatch/README.md +372 -0
  27. package/dispatch/config.example.json +24 -0
  28. package/dispatch/deliver-watcher.sh +57 -0
  29. package/dispatch/hooks.mjs +171 -0
  30. package/dispatch/index.mjs +1836 -0
  31. package/dispatch/watcher.mjs +1396 -0
  32. package/dispatch-queue.js +112 -0
  33. package/dispatcher-approvals.js +96 -0
  34. package/dispatcher-delivery.js +43 -0
  35. package/dispatcher-maintenance.js +242 -0
  36. package/dispatcher-shell.js +29 -0
  37. package/dispatcher-strategies.js +1280 -0
  38. package/dispatcher-utils.js +81 -0
  39. package/dispatcher.js +855 -0
  40. package/docs/adr-schedule-ownership.md +73 -0
  41. package/docs/gateway-contract.md +904 -0
  42. package/docs/plans/2026-03-09-fix-typescript-types.md +91 -0
  43. package/docs/plans/2026-03-09-test-coverage-gaps.md +83 -0
  44. package/docs/plans/2026-03-10-dispatcher-refactor.md +801 -0
  45. package/docs/trust-architecture.md +266 -0
  46. package/gateway.js +473 -0
  47. package/idempotency.js +119 -0
  48. package/index.d.ts +864 -0
  49. package/index.js +17 -0
  50. package/jobs.js +1224 -0
  51. package/messages.js +357 -0
  52. package/migrate-consolidate.js +694 -0
  53. package/migrate.js +125 -0
  54. package/package.json +130 -0
  55. package/paths.js +79 -0
  56. package/prompt-context.js +94 -0
  57. package/retrieval.js +176 -0
  58. package/runs.js +270 -0
  59. package/scheduler-schema.js +101 -0
  60. package/schema.sql +480 -0
  61. package/scripts/dispatch-cli-utils.mjs +65 -0
  62. package/scripts/inbox-consumer.mjs +288 -0
  63. package/scripts/stuck-detector.sh +18 -0
  64. package/scripts/stuck-run-detector.mjs +333 -0
  65. package/scripts/telegram-webhook-check.mjs +238 -0
  66. package/setup.mjs +724 -0
  67. package/shell-result.js +214 -0
  68. package/task-tracker.js +300 -0
  69. package/team-adapter.js +335 -0
  70. package/v02-runtime.js +599 -0
package/SECURITY.md ADDED
@@ -0,0 +1,34 @@
1
+ # Security Policy
2
+
3
+ ## Reporting
4
+
5
+ Report security issues privately to the maintainers instead of opening a public issue.
6
+
7
+ Preferred channel:
8
+
9
+ - GitHub private vulnerability reporting: https://github.com/amittell/openclaw-scheduler/security/advisories/new
10
+
11
+ Include:
12
+
13
+ - affected version
14
+ - deployment mode
15
+ - reproduction steps
16
+ - impact
17
+ - suggested mitigation if known
18
+
19
+ ## Scope
20
+
21
+ Security-sensitive areas include:
22
+
23
+ - shell job execution
24
+ - gateway credential handling
25
+ - delivery adapters
26
+ - approval flows
27
+ - installation and service configuration
28
+
29
+ Please report unsafe defaults, credential leaks, or privilege boundary issues.
30
+
31
+ ## Response Timeline
32
+
33
+ - **Acknowledgment:** within 7 days of receipt.
34
+ - **Resolution:** within 30--90 days depending on severity and complexity.
package/UNINSTALL.md ADDED
@@ -0,0 +1,129 @@
1
+ # Uninstalling OpenClaw Scheduler
2
+
3
+ Two levels of removal:
4
+
5
+ 1. **Stop the scheduler** and re-enable OpenClaw's built-in cron/heartbeat — reversible
6
+ 2. **Full removal** — delete all scheduler files and data — irreversible
7
+
8
+ ---
9
+
10
+ ## Step 1: Stop the Scheduler Service
11
+
12
+ ### macOS
13
+
14
+ Remove the launchd mode you actually used:
15
+
16
+ **LaunchAgent**
17
+
18
+ ```bash
19
+ launchctl bootout gui/$UID/ai.openclaw.scheduler
20
+ rm ~/Library/LaunchAgents/ai.openclaw.scheduler.plist
21
+ ```
22
+
23
+ **LaunchDaemon**
24
+
25
+ ```bash
26
+ sudo launchctl bootout system/ai.openclaw.scheduler
27
+ sudo rm /Library/LaunchDaemons/ai.openclaw.scheduler.plist
28
+ ```
29
+
30
+ ### Linux
31
+
32
+ ```bash
33
+ systemctl --user stop openclaw-scheduler
34
+ systemctl --user disable openclaw-scheduler
35
+ rm ~/.config/systemd/user/openclaw-scheduler.service
36
+ systemctl --user daemon-reload
37
+ ```
38
+
39
+ ### Windows (PM2)
40
+
41
+ ```powershell
42
+ pm2 stop openclaw-scheduler
43
+ pm2 delete openclaw-scheduler
44
+ pm2 save # persist the removal
45
+ ```
46
+
47
+ ---
48
+
49
+ ## Step 2: Re-enable OpenClaw Built-ins
50
+
51
+ ### Re-enable cron (if you had OC cron jobs before)
52
+
53
+ ```bash
54
+ openclaw config set cron.enabled true
55
+ openclaw cron list
56
+ openclaw cron edit <job-id> --enable # repeat for each job you want back
57
+ ```
58
+
59
+ Also remove `OPENCLAW_SKIP_CRON=1` from your OpenClaw gateway service environment, then restart the gateway.
60
+
61
+ ### Re-enable heartbeat (if you had one)
62
+
63
+ ```bash
64
+ openclaw config set agents.defaults.heartbeat.every "5m"
65
+ # If you had per-agent heartbeat overrides, restore those too:
66
+ # agents.list[].heartbeat.every = "5m"
67
+ openclaw gateway restart
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Step 3: Full Removal (optional)
73
+
74
+ > ⚠️ **This permanently deletes your job definitions, run history, log files, and all scheduler data. This cannot be undone.**
75
+
76
+ **Export your jobs first (optional):**
77
+
78
+ ```bash
79
+ node ~/.openclaw/scheduler/cli.js jobs list > ~/scheduler-jobs-backup.txt
80
+ ```
81
+
82
+ **Remove the scheduler directory:**
83
+
84
+ ```bash
85
+ # macOS / Linux
86
+ rm -rf ~/.openclaw/scheduler/
87
+
88
+ # Windows (PowerShell)
89
+ Remove-Item -Recurse -Force "$env:USERPROFILE\.openclaw\scheduler"
90
+ ```
91
+
92
+ **Remove log files:**
93
+
94
+ ```bash
95
+ # macOS / Linux
96
+ rm -f /tmp/openclaw-scheduler.log
97
+ ```
98
+
99
+ On Windows, PM2 stores logs in `~/.pm2/logs/`. Remove if desired:
100
+
101
+ ```powershell
102
+ Remove-Item -Force "$env:USERPROFILE\.pm2\logs\openclaw-scheduler-out.log"
103
+ Remove-Item -Force "$env:USERPROFILE\.pm2\logs\openclaw-scheduler-error.log"
104
+ ```
105
+
106
+ ---
107
+
108
+ ## About the Chat Completions Endpoint
109
+
110
+ The scheduler enabled the OpenClaw gateway's chat completions endpoint (`/v1/chat/completions`). This endpoint is also used by Claude Code, other AI tools, and the OpenClaw API. **You probably want to leave it enabled.**
111
+
112
+ If you specifically want to disable it:
113
+
114
+ ```bash
115
+ openclaw config set gateway.http.endpoints.chatCompletions.enabled false
116
+ openclaw gateway restart
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Linger (Linux only)
122
+
123
+ If you enabled linger to keep the service running without a login session, you can disable it:
124
+
125
+ ```bash
126
+ loginctl disable-linger $USER
127
+ ```
128
+
129
+ This stops systemd user services from running when you're not logged in. Only do this if you don't need other user services running persistently.
package/UPGRADING.md ADDED
@@ -0,0 +1,436 @@
1
+ # Upgrading OpenClaw Scheduler
2
+
3
+ How to update an existing OpenClaw Scheduler installation to the latest version.
4
+
5
+ This guide covers both git-clone and npm-based installs. Each host is independent -- upgrade them one at a time and verify before moving on.
6
+
7
+ ---
8
+
9
+ ## Quick Reference
10
+
11
+ ### macOS (launchd, git-clone install)
12
+
13
+ ```bash
14
+ cd ~/.openclaw/scheduler
15
+ git pull
16
+ npm install
17
+ SCHEDULER_DB=:memory: node test.js
18
+ launchctl kickstart -k gui/$(id -u)/ai.openclaw.scheduler
19
+ sleep 3 && tail -5 /tmp/openclaw-scheduler.log
20
+ node cli.js status
21
+ ```
22
+
23
+ ### Linux / Windows WSL2 (systemd, git-clone install)
24
+
25
+ ```bash
26
+ cd ~/.openclaw/scheduler
27
+ git pull
28
+ npm install
29
+ SCHEDULER_DB=:memory: node test.js
30
+ systemctl --user restart openclaw-scheduler
31
+ sleep 3 && systemctl --user --no-pager --full status openclaw-scheduler
32
+ node cli.js status
33
+ ```
34
+
35
+ ### Windows native (PM2, git-clone install)
36
+
37
+ ```powershell
38
+ cd $env:USERPROFILE\.openclaw\scheduler
39
+ git pull
40
+ npm install
41
+ $env:SCHEDULER_DB=":memory:"; node test.js
42
+ pm2 restart openclaw-scheduler
43
+ Start-Sleep 3
44
+ pm2 logs openclaw-scheduler --lines 5 --nostream
45
+ node cli.js status
46
+ ```
47
+
48
+ That is the whole process for a routine update. The rest of this document explains each step, covers edge cases, and documents both git-clone and npm install paths.
49
+
50
+ ---
51
+
52
+ ## Before You Start
53
+
54
+ 1. **Check the [CHANGELOG](CHANGELOG.md)** for breaking changes or new schema migrations.
55
+ 2. **Check current version:**
56
+ ```bash
57
+ cd ~/.openclaw/scheduler
58
+ node -e "console.log(JSON.parse(require('fs').readFileSync('package.json','utf8')).version)"
59
+ # or for npm installs:
60
+ npm ls --prefix ~/.openclaw/scheduler openclaw-scheduler
61
+ ```
62
+ 3. **Check current schema version:**
63
+ ```bash
64
+ node -e "const db=require('better-sqlite3')('scheduler.db');console.log(db.prepare('SELECT MAX(version) as v FROM schema_migrations').get());db.close()"
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Step 1: Pull or Install the Update
70
+
71
+ ### Git-clone installs
72
+
73
+ #### macOS / Linux / Windows WSL2
74
+
75
+ ```bash
76
+ cd ~/.openclaw/scheduler
77
+ git pull
78
+ ```
79
+
80
+ #### Windows native (PowerShell)
81
+
82
+ ```powershell
83
+ cd $env:USERPROFILE\.openclaw\scheduler
84
+ git pull
85
+ ```
86
+
87
+ If you have local modifications, stash them first:
88
+ ```bash
89
+ git stash
90
+ git pull
91
+ git stash pop
92
+ ```
93
+
94
+ ### npm installs
95
+
96
+ #### macOS / Linux / Windows WSL2
97
+
98
+ ```bash
99
+ npm install --prefix ~/.openclaw/scheduler openclaw-scheduler@latest
100
+ ```
101
+
102
+ #### Windows native (PowerShell)
103
+
104
+ ```powershell
105
+ npm install --prefix $env:USERPROFILE\.openclaw\scheduler openclaw-scheduler@latest
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Step 2: Install Dependencies
111
+
112
+ ### macOS / Linux / Windows WSL2
113
+
114
+ ```bash
115
+ cd ~/.openclaw/scheduler
116
+ npm install
117
+ ```
118
+
119
+ ### Windows native (PowerShell)
120
+
121
+ ```powershell
122
+ cd $env:USERPROFILE\.openclaw\scheduler
123
+ npm install
124
+ ```
125
+
126
+ If you upgraded Node.js since the last install, also rebuild the native module:
127
+
128
+ ```bash
129
+ npm rebuild better-sqlite3
130
+ ```
131
+
132
+ Common triggers for needing a rebuild:
133
+ - `brew upgrade node` on macOS
134
+ - Switching Node major versions with `nvm`, `fnm`, or `asdf`
135
+ - Distro package upgrades that replace the Node binary
136
+
137
+ ---
138
+
139
+ ## Step 3: Run Tests
140
+
141
+ ### macOS / Linux / Windows WSL2
142
+
143
+ ```bash
144
+ cd ~/.openclaw/scheduler
145
+ SCHEDULER_DB=:memory: node test.js
146
+ ```
147
+
148
+ ### Windows native (PowerShell)
149
+
150
+ ```powershell
151
+ cd $env:USERPROFILE\.openclaw\scheduler
152
+ $env:SCHEDULER_DB=":memory:"; node test.js
153
+ ```
154
+
155
+ All tests must pass before restarting the service. If tests fail, do not restart -- investigate the failure first and check the CHANGELOG for any required manual steps.
156
+
157
+ ---
158
+
159
+ ## Step 4: Schema Migrations
160
+
161
+ The dispatcher runs pending schema migrations automatically on startup. No manual migration step is needed.
162
+
163
+ Note: `migrate.js` is the OC cron importer (for importing jobs from the old OC cron system), not the schema migrator. Do not run it expecting schema changes.
164
+
165
+ To verify the current schema version:
166
+
167
+ ### macOS / Linux / Windows WSL2
168
+
169
+ ```bash
170
+ cd ~/.openclaw/scheduler
171
+ node -e "const db=require('better-sqlite3')('scheduler.db');console.log(db.prepare('SELECT MAX(version) as v FROM schema_migrations').get());db.close()"
172
+ ```
173
+
174
+ ### Windows native (PowerShell)
175
+
176
+ ```powershell
177
+ cd $env:USERPROFILE\.openclaw\scheduler
178
+ node -e "const db=require('better-sqlite3')('scheduler.db');console.log(db.prepare('SELECT MAX(version) as v FROM schema_migrations').get());db.close()"
179
+ ```
180
+
181
+ ---
182
+
183
+ ## Step 5: Restart the Service
184
+
185
+ ### macOS (launchd)
186
+
187
+ ```bash
188
+ # LaunchAgent (most common)
189
+ launchctl kickstart -k gui/$(id -u)/ai.openclaw.scheduler
190
+
191
+ # LaunchDaemon (headless hosts)
192
+ sudo launchctl kickstart -k system/ai.openclaw.scheduler
193
+ ```
194
+
195
+ ### Linux (systemd)
196
+
197
+ ```bash
198
+ systemctl --user restart openclaw-scheduler
199
+ # or if running as a system service:
200
+ sudo systemctl restart openclaw-scheduler
201
+ ```
202
+
203
+ ### Windows WSL2 (systemd inside WSL)
204
+
205
+ ```bash
206
+ systemctl --user restart openclaw-scheduler
207
+ ```
208
+
209
+ ### Windows native (PM2)
210
+
211
+ ```powershell
212
+ pm2 restart openclaw-scheduler
213
+ ```
214
+
215
+ ---
216
+
217
+ ## Step 6: Verify
218
+
219
+ ### macOS (launchd)
220
+
221
+ ```bash
222
+ launchctl list | grep ai.openclaw.scheduler
223
+ tail -10 /tmp/openclaw-scheduler.log
224
+ cd ~/.openclaw/scheduler && node cli.js status
225
+ ```
226
+
227
+ ### Linux / Windows WSL2 (systemd)
228
+
229
+ ```bash
230
+ systemctl --user --no-pager --full status openclaw-scheduler
231
+ journalctl --user -u openclaw-scheduler -n 20 --no-pager
232
+ cd ~/.openclaw/scheduler && node cli.js status
233
+ ```
234
+
235
+ ### Windows native (PM2)
236
+
237
+ ```powershell
238
+ pm2 status
239
+ pm2 logs openclaw-scheduler --lines 20 --nostream
240
+ cd $env:USERPROFILE\.openclaw\scheduler
241
+ node cli.js status
242
+ ```
243
+
244
+ A healthy startup log looks like:
245
+
246
+ ```
247
+ [scheduler] [info] Starting OpenClaw Scheduler v0.2.0 {"tickMs":10000,...}
248
+ [scheduler] [info] Database initialized
249
+ [scheduler] [info] Pruned old runs + messages
250
+ ```
251
+
252
+ If you see `Gateway unreachable`, isolated agent jobs will be deferred until the gateway is back. Shell jobs and main-session jobs continue unaffected.
253
+
254
+ ---
255
+
256
+ ## Upgrading Multiple Hosts
257
+
258
+ Each host has its own independent SQLite database and service. Upgrade hosts one at a time:
259
+
260
+ 1. Upgrade the first host following the steps above.
261
+ 2. Verify it is healthy (`node cli.js status`, check logs).
262
+ 3. Move on to the next host.
263
+
264
+ There is no required upgrade order. Hosts do not share state and can run different versions temporarily. However, keeping all hosts on the same version avoids confusion.
265
+
266
+ ### Remote upgrade examples
267
+
268
+ #### macOS host over SSH
269
+
270
+ ```bash
271
+ HOST=youruser@your-mac-host.lan
272
+
273
+ ssh $HOST "cd ~/.openclaw/scheduler && git pull && npm install"
274
+ ssh $HOST "cd ~/.openclaw/scheduler && SCHEDULER_DB=:memory: node test.js" 2>&1 | tail -5
275
+ ssh $HOST "launchctl kickstart -k gui/\$(id -u)/ai.openclaw.scheduler"
276
+ sleep 3
277
+ ssh $HOST "tail -5 /tmp/openclaw-scheduler.log && cd ~/.openclaw/scheduler && node cli.js status"
278
+ ```
279
+
280
+ #### Linux / Windows WSL2 host over SSH
281
+
282
+ ```bash
283
+ HOST=youruser@your-linux-host.lan
284
+
285
+ ssh $HOST "cd ~/.openclaw/scheduler && git pull && npm install"
286
+ ssh $HOST "cd ~/.openclaw/scheduler && SCHEDULER_DB=:memory: node test.js" 2>&1 | tail -5
287
+ ssh $HOST "systemctl --user restart openclaw-scheduler"
288
+ sleep 3
289
+ ssh $HOST "systemctl --user --no-pager --full status openclaw-scheduler && cd ~/.openclaw/scheduler && node cli.js status"
290
+ ```
291
+
292
+ #### Windows native host via PowerShell Remoting
293
+
294
+ ```powershell
295
+ $HOST = "your-windows-host"
296
+
297
+ Invoke-Command -ComputerName $HOST -ScriptBlock {
298
+ cd $env:USERPROFILE\.openclaw\scheduler
299
+ git pull
300
+ npm install
301
+ $env:SCHEDULER_DB=":memory:"
302
+ node test.js
303
+ pm2 restart openclaw-scheduler
304
+ Start-Sleep 3
305
+ pm2 logs openclaw-scheduler --lines 5 --nostream
306
+ node cli.js status
307
+ }
308
+ ```
309
+
310
+ ---
311
+
312
+ ## Rollback
313
+
314
+ If the new version causes problems:
315
+
316
+ ### Git-clone installs
317
+
318
+ #### macOS (launchd)
319
+
320
+ ```bash
321
+ cd ~/.openclaw/scheduler
322
+ git log --oneline -5 # find the previous good commit
323
+ git checkout <commit-hash> # revert to it
324
+ npm install # restore matching dependencies
325
+ launchctl kickstart -k gui/$(id -u)/ai.openclaw.scheduler
326
+ ```
327
+
328
+ #### Linux / Windows WSL2 (systemd)
329
+
330
+ ```bash
331
+ cd ~/.openclaw/scheduler
332
+ git log --oneline -5
333
+ git checkout <commit-hash>
334
+ npm install
335
+ systemctl --user restart openclaw-scheduler
336
+ ```
337
+
338
+ #### Windows native (PM2)
339
+
340
+ ```powershell
341
+ cd $env:USERPROFILE\.openclaw\scheduler
342
+ git log --oneline -5
343
+ git checkout <commit-hash>
344
+ npm install
345
+ pm2 restart openclaw-scheduler
346
+ ```
347
+
348
+ ### npm installs
349
+
350
+ #### macOS (launchd)
351
+
352
+ ```bash
353
+ npm install --prefix ~/.openclaw/scheduler openclaw-scheduler@<previous-version>
354
+ launchctl kickstart -k gui/$(id -u)/ai.openclaw.scheduler
355
+ ```
356
+
357
+ #### Linux / Windows WSL2 (systemd)
358
+
359
+ ```bash
360
+ npm install --prefix ~/.openclaw/scheduler openclaw-scheduler@<previous-version>
361
+ systemctl --user restart openclaw-scheduler
362
+ ```
363
+
364
+ #### Windows native (PM2)
365
+
366
+ ```powershell
367
+ npm install --prefix $env:USERPROFILE\.openclaw\scheduler openclaw-scheduler@<previous-version>
368
+ pm2 restart openclaw-scheduler
369
+ ```
370
+
371
+ **Schema rollback:** Downgrading the code does not undo schema migrations. New columns added by migrations are ignored by older code -- they use `DEFAULT` values and do not cause errors. If a migration added a new table, older code simply does not reference it. In practice, schema changes are forward-compatible and do not require manual rollback.
372
+
373
+ ---
374
+
375
+ ## Provider plugins (v0.2)
376
+
377
+ If you use provider-backed identity, authorization, or proof verification, set
378
+ `SCHEDULER_PROVIDER_PATH` to a directory containing your provider `*.js` files.
379
+ This is a high-trust boundary: every file in that directory is dynamically imported
380
+ at scheduler startup. The directory must not be world-writable. See
381
+ `docs/gateway-contract.md` for the full provider plugin contract.
382
+
383
+ ### Adopting jobs under agentcli
384
+
385
+ If you install agentcli after upgrading, you can adopt existing scheduler jobs
386
+ into declarative manifests. See [AGENTS.md](AGENTS.md#adding-agentcli-later-adopting-existing-jobs)
387
+ for the adoption flow and [README.md](README.md#adopting-existing-scheduler-jobs)
388
+ for detailed examples.
389
+
390
+ ---
391
+
392
+ ## Troubleshooting
393
+
394
+ ### Tests fail after update
395
+
396
+ - Check the CHANGELOG for breaking changes or new prerequisites.
397
+ - Make sure `npm install` completed without errors.
398
+ - If `better-sqlite3` fails to load, run `npm rebuild better-sqlite3`.
399
+
400
+ ### Service won't start after update
401
+
402
+ - Check the error log: `tail -20 /tmp/openclaw-scheduler.log`
403
+ - If the error is a missing module, run `npm install` again.
404
+ - If the error is a database issue, check the schema version matches what the new code expects.
405
+
406
+ ### Gateway unreachable after update
407
+
408
+ The scheduler update does not affect the OpenClaw gateway. If the gateway is down, that is a separate issue. The scheduler logs `Gateway unreachable` on startup but continues running shell and main-session jobs.
409
+
410
+ ### Node version changed
411
+
412
+ If Node was upgraded alongside the scheduler (e.g., `brew upgrade` updated both), the native `better-sqlite3` module needs rebuilding:
413
+
414
+ ### macOS (launchd)
415
+
416
+ ```bash
417
+ cd ~/.openclaw/scheduler
418
+ npm rebuild better-sqlite3
419
+ launchctl kickstart -k gui/$(id -u)/ai.openclaw.scheduler
420
+ ```
421
+
422
+ ### Linux / Windows WSL2 (systemd)
423
+
424
+ ```bash
425
+ cd ~/.openclaw/scheduler
426
+ npm rebuild better-sqlite3
427
+ systemctl --user restart openclaw-scheduler
428
+ ```
429
+
430
+ ### Windows native (PM2)
431
+
432
+ ```powershell
433
+ cd $env:USERPROFILE\.openclaw\scheduler
434
+ npm rebuild better-sqlite3
435
+ pm2 restart openclaw-scheduler
436
+ ```
package/agents.js ADDED
@@ -0,0 +1,67 @@
1
+ // Agent registry -- track agent status and capabilities
2
+ import { getDb } from './db.js';
3
+
4
+ /**
5
+ * Register or update an agent.
6
+ */
7
+ export function upsertAgent(id, opts = {}) {
8
+ if (!id || typeof id !== 'string') throw new Error('Agent id must be a non-empty string');
9
+ const db = getDb();
10
+ db.prepare(`
11
+ INSERT INTO agents (id, name, status, session_key, capabilities)
12
+ VALUES (?, ?, ?, ?, ?)
13
+ ON CONFLICT(id) DO UPDATE SET
14
+ name = COALESCE(excluded.name, agents.name),
15
+ status = COALESCE(excluded.status, agents.status),
16
+ session_key = COALESCE(excluded.session_key, agents.session_key),
17
+ capabilities = COALESCE(excluded.capabilities, agents.capabilities),
18
+ last_seen_at = datetime('now')
19
+ `).run(
20
+ id,
21
+ opts.name || null,
22
+ opts.status || 'idle',
23
+ opts.session_key || null,
24
+ opts.capabilities ? JSON.stringify(opts.capabilities) : null
25
+ );
26
+ return getAgent(id);
27
+ }
28
+
29
+ /**
30
+ * Get an agent by ID.
31
+ */
32
+ export function getAgent(id) {
33
+ const agent = getDb().prepare('SELECT * FROM agents WHERE id = ?').get(id);
34
+ if (agent && agent.capabilities) {
35
+ try { agent.capabilities = JSON.parse(agent.capabilities); } catch (e) { process.stderr.write('Warning: failed to parse capabilities JSON: ' + e.message + '\n'); }
36
+ }
37
+ return agent;
38
+ }
39
+
40
+ /**
41
+ * List all agents.
42
+ */
43
+ export function listAgents() {
44
+ return getDb().prepare('SELECT * FROM agents ORDER BY id').all().map(a => {
45
+ if (a.capabilities) try { a.capabilities = JSON.parse(a.capabilities); } catch (e) { process.stderr.write('Warning: failed to parse capabilities JSON: ' + e.message + '\n'); }
46
+ return a;
47
+ });
48
+ }
49
+
50
+ /**
51
+ * Update agent status.
52
+ */
53
+ export function setAgentStatus(id, status, sessionKey) {
54
+ getDb().prepare(`
55
+ UPDATE agents SET status = ?, session_key = ?, last_seen_at = datetime('now')
56
+ WHERE id = ?
57
+ `).run(status, sessionKey || null, id);
58
+ }
59
+
60
+ /**
61
+ * Mark agent as seen (heartbeat).
62
+ */
63
+ export function touchAgent(id) {
64
+ getDb().prepare(`
65
+ UPDATE agents SET last_seen_at = datetime('now') WHERE id = ?
66
+ `).run(id);
67
+ }