openclaw-scheduler 0.2.2 → 0.2.3
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/CHANGELOG.md +10 -0
- package/INSTALL-ADDITIONAL-HOST.md +1 -1
- package/INSTALL-LINUX.md +1 -1
- package/INSTALL-WINDOWS.md +1 -1
- package/INSTALL.md +1 -1
- package/README.md +3 -3
- package/cli.js +54 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.2.3] -- 2026-04-16
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- fix(cli): harden runtime DB path resolution so installed package layouts prefer `~/.openclaw/scheduler/scheduler.db` instead of a repo-local checkout DB
|
|
9
|
+
- fix(cli): refuse validation-only commands (`jobs validate`, `jobs add --dry-run`) when a source checkout detects an existing runtime DB mismatch
|
|
10
|
+
- test(cli): add installed-package and repo/runtime mismatch coverage for DB path hardening
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- docs: bump minimum supported Node.js version from 20 to 22 to match the package engine requirement
|
|
14
|
+
|
|
5
15
|
## [0.2.2] -- 2026-04-15
|
|
6
16
|
|
|
7
17
|
### Fixed
|
|
@@ -12,7 +12,7 @@ This guide is for setting up the scheduler on a **second or additional OpenClaw
|
|
|
12
12
|
| Requirement | Notes |
|
|
13
13
|
|-------------|-------|
|
|
14
14
|
| macOS or Linux | Tested on macOS arm64 |
|
|
15
|
-
| Node.js >=
|
|
15
|
+
| Node.js >= 22 | `node --version` (use full path if needed: `/opt/homebrew/bin/node --version`) |
|
|
16
16
|
| OpenClaw gateway running | With auth token |
|
|
17
17
|
| Git or SCP access | To clone/copy the repo |
|
|
18
18
|
|
package/INSTALL-LINUX.md
CHANGED
|
@@ -12,7 +12,7 @@ Step-by-step guide to deploy the scheduler on a Linux host running OpenClaw.
|
|
|
12
12
|
|
|
13
13
|
| Requirement | Notes |
|
|
14
14
|
|-------------|-------|
|
|
15
|
-
| Node.js >=
|
|
15
|
+
| Node.js >= 22 | Install via [nvm](https://github.com/nvm-sh/nvm) or [NodeSource](https://github.com/nodesource/distributions) |
|
|
16
16
|
| build-essential | `sudo apt install build-essential python3` — required for `better-sqlite3` native compile |
|
|
17
17
|
| OpenClaw gateway running | With auth token |
|
|
18
18
|
| Git | `sudo apt install git` |
|
package/INSTALL-WINDOWS.md
CHANGED
|
@@ -38,7 +38,7 @@ Use this path only if you can't use WSL2 — for example, if OpenClaw itself is
|
|
|
38
38
|
|
|
39
39
|
| Requirement | Install |
|
|
40
40
|
|-------------|---------|
|
|
41
|
-
| Node.js >=
|
|
41
|
+
| Node.js >= 22 | [nodejs.org](https://nodejs.org) -- use the LTS installer |
|
|
42
42
|
| pm2 | `npm install -g pm2` |
|
|
43
43
|
| OpenClaw gateway | Must be running with a valid auth token |
|
|
44
44
|
| Git for Windows | [git-scm.com](https://git-scm.com) or use GitHub Desktop |
|
package/INSTALL.md
CHANGED
|
@@ -11,7 +11,7 @@ If you just want the fastest path to a working local install, start with the npm
|
|
|
11
11
|
| Requirement | Notes |
|
|
12
12
|
|-------------|-------|
|
|
13
13
|
| macOS or Linux | Tested on macOS arm64 |
|
|
14
|
-
| Node.js >=
|
|
14
|
+
| Node.js >= 22 | `node --version` |
|
|
15
15
|
| OpenClaw gateway running | With auth token |
|
|
16
16
|
| Git or SCP access | To clone/copy the repo |
|
|
17
17
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/amittell/openclaw-scheduler/actions/workflows/ci.yml)
|
|
4
4
|
[]()
|
|
5
|
-
[](https://nodejs.org)
|
|
6
6
|
|
|
7
7
|
A durable orchestration runtime for [OpenClaw](https://openclaw.ai) agents and shell workflows. Use it when built-in cron and heartbeat stop being enough: jobs fail and disappear into logs, shell scripts depend on gateway uptime, multi-step workflows need retries and approvals, and you want a real audit trail for what ran, what failed, and what triggered what.
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ It replaces OpenClaw's built-in cron/heartbeat with a SQLite-backed scheduler th
|
|
|
11
11
|
**Repo:** `github.com/amittell/openclaw-scheduler`
|
|
12
12
|
**Default location:** `~/.openclaw/scheduler/`
|
|
13
13
|
**Service:** `ai.openclaw.scheduler` (macOS launchd: LaunchAgent or LaunchDaemon)
|
|
14
|
-
**Runtime:** Node.js
|
|
14
|
+
**Runtime:** Node.js 22+ (ESM), SQLite via `better-sqlite3`, cron parsing via `croner`
|
|
15
15
|
**Tests:** run with `npm test` (full suite, in-memory SQLite)
|
|
16
16
|
**Platform:** macOS · Linux · Windows (WSL2)
|
|
17
17
|
|
|
@@ -204,7 +204,7 @@ npm run verify:local # full local maintainer gate
|
|
|
204
204
|
npm run verify:smoke # lightweight smoke gate used by GitHub Actions
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
-
GitHub Actions runs the smoke gate plus the in-memory test suite on Linux
|
|
207
|
+
GitHub Actions runs the smoke gate plus the in-memory test suite on Linux and macOS with Node 22. Publishing uses Node 24 (npm 22+) for OIDC trusted publisher support. The full release gate still runs locally via `npm run verify:local` and is enforced again by `prepublishOnly`.
|
|
208
208
|
|
|
209
209
|
### Option C: local npm pack (simulate the published package from source)
|
|
210
210
|
|
package/cli.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Scheduler CLI -- manage jobs, runs, messages, agents
|
|
3
|
-
import { readFileSync } from 'fs';
|
|
4
|
-
import {
|
|
3
|
+
import { existsSync, readFileSync } from 'fs';
|
|
4
|
+
import { dirname, join } from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { initDb, getDb, getResolvedDbPath } from './db.js';
|
|
5
7
|
import { createJob, getJob, listJobs, updateJob, deleteJob, cancelJob, runJobNow, validateJobSpec, parseInDuration, AT_JOB_CRON_SENTINEL } from './jobs.js';
|
|
6
8
|
import { getRun, getRunsForJob, getRunningRuns, getStaleRuns, finishRun } from './runs.js';
|
|
7
9
|
import {
|
|
@@ -9,14 +11,53 @@ import {
|
|
|
9
11
|
ackMessage, listMessageReceipts, getTeamMessages,
|
|
10
12
|
} from './messages.js';
|
|
11
13
|
import { upsertAgent, getAgent, listAgents } from './agents.js';
|
|
14
|
+
import { resolveSchedulerHome } from './paths.js';
|
|
12
15
|
import { SCHEDULER_SCHEMAS } from './scheduler-schema.js';
|
|
13
16
|
|
|
17
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
18
|
const cliArgs = process.argv.slice(2);
|
|
15
19
|
const jsonFlagIndex = cliArgs.indexOf('--json');
|
|
16
20
|
const jsonMode = jsonFlagIndex >= 0;
|
|
17
21
|
if (jsonFlagIndex >= 0) cliArgs.splice(jsonFlagIndex, 1);
|
|
18
22
|
const [command, sub, ...args] = cliArgs;
|
|
19
23
|
|
|
24
|
+
function firstNonEmpty(value) {
|
|
25
|
+
if (typeof value !== 'string') return '';
|
|
26
|
+
const trimmed = value.trim();
|
|
27
|
+
return trimmed.length > 0 ? trimmed : '';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function isNodeModulesInstall(moduleDir) {
|
|
31
|
+
return /[\\/]node_modules[\\/](?:@[^\\/]+[\\/])?openclaw-scheduler(?:[\\/]|$)/.test(moduleDir);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isValidationOnlyCommand(cmd, subcommand, rest) {
|
|
35
|
+
return cmd === 'jobs' && (
|
|
36
|
+
subcommand === 'validate'
|
|
37
|
+
|| (subcommand === 'add' && rest.includes('--dry-run'))
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getDbPathMismatchNotice(env = process.env) {
|
|
42
|
+
if (firstNonEmpty(env.SCHEDULER_DB)) return null;
|
|
43
|
+
if (isNodeModulesInstall(__dirname)) return null;
|
|
44
|
+
|
|
45
|
+
const repoDbPath = join(__dirname, 'scheduler.db');
|
|
46
|
+
const resolvedDbPath = getResolvedDbPath();
|
|
47
|
+
if (resolvedDbPath !== repoDbPath) return null;
|
|
48
|
+
|
|
49
|
+
const runtimeDbPath = join(resolveSchedulerHome(env), 'scheduler.db');
|
|
50
|
+
if (runtimeDbPath === resolvedDbPath) return null;
|
|
51
|
+
if (!existsSync(runtimeDbPath)) return null;
|
|
52
|
+
|
|
53
|
+
return { resolvedDbPath, runtimeDbPath };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function formatDbPathMismatchNotice({ resolvedDbPath, runtimeDbPath }, { validation = false } = {}) {
|
|
57
|
+
const prefix = validation ? 'Refusing to run validation.' : 'Warning: source checkout CLI is using a repo-local DB.';
|
|
58
|
+
return `${prefix} repo-local=${resolvedDbPath} runtime=${runtimeDbPath}. Re-run via the installed package CLI or set SCHEDULER_DB explicitly.`;
|
|
59
|
+
}
|
|
60
|
+
|
|
20
61
|
function usage() {
|
|
21
62
|
console.log(`
|
|
22
63
|
Usage: openclaw-scheduler <command> [subcommand] [options]
|
|
@@ -119,6 +160,14 @@ Capabilities:
|
|
|
119
160
|
`);
|
|
120
161
|
}
|
|
121
162
|
|
|
163
|
+
const dbPathMismatchNotice = getDbPathMismatchNotice(process.env);
|
|
164
|
+
if (dbPathMismatchNotice) {
|
|
165
|
+
if (isValidationOnlyCommand(command, sub, args)) {
|
|
166
|
+
fail(formatDbPathMismatchNotice(dbPathMismatchNotice, { validation: true }));
|
|
167
|
+
}
|
|
168
|
+
process.stderr.write(`${formatDbPathMismatchNotice(dbPathMismatchNotice)}\n`);
|
|
169
|
+
}
|
|
170
|
+
|
|
122
171
|
await initDb();
|
|
123
172
|
|
|
124
173
|
function fmt(obj) { return JSON.stringify(obj, null, 2); }
|
|
@@ -953,6 +1002,7 @@ switch (command) {
|
|
|
953
1002
|
// -- Status ----------------------------------------------
|
|
954
1003
|
case 'status': {
|
|
955
1004
|
const db = getDb();
|
|
1005
|
+
const dbPath = getResolvedDbPath();
|
|
956
1006
|
const jobs = listJobs();
|
|
957
1007
|
const runningRuns = getRunningRuns();
|
|
958
1008
|
const stale = getStaleRuns();
|
|
@@ -982,6 +1032,7 @@ switch (command) {
|
|
|
982
1032
|
.filter(j => j.enabled && j.next_run_at)
|
|
983
1033
|
.sort((a, b) => a.next_run_at.localeCompare(b.next_run_at))[0] || null;
|
|
984
1034
|
const payload = {
|
|
1035
|
+
db_path: dbPath,
|
|
985
1036
|
jobs_total: jobs.length,
|
|
986
1037
|
jobs_enabled: jobs.filter(j => j.enabled).length,
|
|
987
1038
|
running_runs: runningRuns.length,
|
|
@@ -997,6 +1048,7 @@ switch (command) {
|
|
|
997
1048
|
};
|
|
998
1049
|
emit(payload, () => {
|
|
999
1050
|
console.log('=== OpenClaw Scheduler Status ===');
|
|
1051
|
+
console.log(`DB: ${dbPath}`);
|
|
1000
1052
|
console.log(`Jobs: ${jobs.length} total, ${jobs.filter(j => j.enabled).length} enabled`);
|
|
1001
1053
|
console.log(`Running: ${runningRuns.length}`);
|
|
1002
1054
|
console.log(`Stale: ${stale.length}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-scheduler",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "SQLite-backed job scheduler and workflow engine for OpenClaw agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"./package.json": "./package.json"
|
|
18
18
|
},
|
|
19
19
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
20
|
+
"node": ">=22"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
23
|
"start": "node dispatcher.js",
|