openclaw-scheduler 0.2.9 → 0.2.11

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/setup.mjs CHANGED
@@ -19,7 +19,7 @@ import os from 'os';
19
19
  import { execSync } from 'child_process';
20
20
 
21
21
  import { fileURLToPath } from 'url';
22
- import { ensureSchedulerDbParent, resolveSchedulerDbPath } from './paths.js';
22
+ import { ensureSchedulerDbParent, resolveSchedulerDbPath, resolveServiceWorkingDirectory } from './paths.js';
23
23
  import { createJob } from './jobs.js';
24
24
  import { initDb } from './db.js';
25
25
 
@@ -152,7 +152,8 @@ print();
152
152
  // --- Step 1: Paths ------------------------------------------------------------
153
153
 
154
154
  print('-- Step 1: Paths ---------------------------------------');
155
- const schedulerPath = __dirname;
155
+ const schedulerInstallRoot = __dirname;
156
+ const serviceWorkingDirectory = resolveServiceWorkingDirectory({ env: process.env, moduleDir: schedulerInstallRoot });
156
157
  const defaultWorkspace = path.join(os.homedir(), '.openclaw', 'workspace');
157
158
  const workspacePath = await ask('Workspace path', defaultWorkspace);
158
159
  const defaultGateway = 'http://127.0.0.1:18789';
@@ -162,10 +163,11 @@ const schedulerDbPath = resolveSchedulerDbPath({ env: process.env });
162
163
  if (schedulerDbPath !== ':memory:') ensureSchedulerDbParent(schedulerDbPath);
163
164
 
164
165
  print();
165
- print(` Scheduler: ${schedulerPath}`);
166
- print(` Workspace: ${workspacePath}`);
167
- print(` Gateway: ${gatewayUrl}`);
168
- print(` Deliver to: ${deliverTo || '(none -- skipping job creation)'}`);
166
+ print(` Scheduler install root: ${schedulerInstallRoot}`);
167
+ print(` Service working dir: ${serviceWorkingDirectory}`);
168
+ print(` Workspace: ${workspacePath}`);
169
+ print(` Gateway: ${gatewayUrl}`);
170
+ print(` Deliver to: ${deliverTo || '(none -- skipping job creation)'}`);
169
171
  print();
170
172
 
171
173
  // --- Preflight: npm install behavior -----------------------------------------
@@ -193,9 +195,9 @@ print();
193
195
 
194
196
  print('-- Step 2: Database migrations -------------------------');
195
197
  try {
196
- const { setDbPath } = await import(path.join(schedulerPath, 'db.js'));
198
+ const { setDbPath } = await import(path.join(schedulerInstallRoot, 'db.js'));
197
199
  setDbPath(schedulerDbPath);
198
- const migrate = (await import(path.join(schedulerPath, 'migrate-consolidate.js'))).default;
200
+ const migrate = (await import(path.join(schedulerInstallRoot, 'migrate-consolidate.js'))).default;
199
201
  const ran = migrate();
200
202
  if (ran) {
201
203
  ok(`Migrations applied -> ${schedulerDbPath}`);
@@ -213,9 +215,9 @@ print();
213
215
  print('-- Step 3: Agent memory files --------------------------');
214
216
 
215
217
  const memoryMd = path.join(workspacePath, 'MEMORY.md');
216
- const memoryEntry = `- **Scheduler Queue Pattern:** Use \`node ${schedulerPath}/cli.js msg send <from> <to> "body"\` for signal-only queue entries.
217
- Inbox Consumer (\`${schedulerPath}/scripts/inbox-consumer.mjs\`) drains pending queue messages to Telegram.
218
- Stuck Run Detector (\`${schedulerPath}/scripts/stuck-run-detector.mjs\`) alerts on stale \`running\` runs.`;
218
+ const memoryEntry = `- **Scheduler Queue Pattern:** Use \`node ${schedulerInstallRoot}/cli.js msg send <from> <to> "body"\` for signal-only queue entries.
219
+ Inbox Consumer (\`${schedulerInstallRoot}/scripts/inbox-consumer.mjs\`) drains pending queue messages to Telegram.
220
+ Stuck Run Detector (\`${schedulerInstallRoot}/scripts/stuck-run-detector.mjs\`) alerts on stale \`running\` runs.`;
219
221
 
220
222
  const memResult = appendIfMissing(memoryMd, 'Scheduler Queue Pattern', memoryEntry);
221
223
  if (memResult === true) ok('Appended scheduler queue entry -> MEMORY.md');
@@ -228,10 +230,10 @@ const indexSection = `### Scheduler & Dispatch
228
230
 
229
231
  | File | Covers | Load |
230
232
  |------|--------|------|
231
- | \`${schedulerPath}/\` | Standalone SQLite scheduler. CLI: \`node cli.js\`. launchd service: \`ai.openclaw.scheduler\`. | Any scheduler/cron work |
232
- | \`${schedulerPath}/cli.js\` | Queue + run operations: \`msg send\`, \`msg inbox\`, \`runs running\`, \`runs stale\`. | Day-to-day scheduler operations |
233
- | \`${schedulerPath}/scripts/inbox-consumer.mjs\` | Drains queue messages for one agent and delivers to Telegram. | Queue/inbox consumption |
234
- | \`${schedulerPath}/scripts/stuck-run-detector.mjs\` | Detects stale \`running\` runs and exits non-zero for alerts. | Run health monitoring |`;
233
+ | \`${schedulerInstallRoot}/\` | Standalone SQLite scheduler. CLI: \`node cli.js\`. launchd service: \`ai.openclaw.scheduler\`. | Any scheduler/cron work |
234
+ | \`${schedulerInstallRoot}/cli.js\` | Queue + run operations: \`msg send\`, \`msg inbox\`, \`runs running\`, \`runs stale\`. | Day-to-day scheduler operations |
235
+ | \`${schedulerInstallRoot}/scripts/inbox-consumer.mjs\` | Drains queue messages for one agent and delivers to Telegram. | Queue/inbox consumption |
236
+ | \`${schedulerInstallRoot}/scripts/stuck-run-detector.mjs\` | Detects stale \`running\` runs and exits non-zero for alerts. | Run health monitoring |`;
235
237
 
236
238
  // Try inserting before a common section header, fall back to append.
237
239
  // NOTE: the link emoji anchors must match the actual markdown heading in
@@ -278,7 +280,7 @@ if (!deliverTo) {
278
280
  const existingNames = listJobs().map(r => r.name);
279
281
 
280
282
  // Inbox Consumer
281
- const icScript = path.join(schedulerPath, 'scripts', 'inbox-consumer.mjs');
283
+ const icScript = path.join(schedulerInstallRoot, 'scripts', 'inbox-consumer.mjs');
282
284
  const icName = 'Inbox Consumer';
283
285
  if (existingNames.includes(icName)) {
284
286
  skip(`"${icName}" job already exists`);
@@ -304,7 +306,7 @@ if (!deliverTo) {
304
306
 
305
307
  // Stuck Run Detector
306
308
  const srdName = 'Stuck Run Detector';
307
- const srdScript = path.join(schedulerPath, 'scripts', 'stuck-run-detector.mjs');
309
+ const srdScript = path.join(schedulerInstallRoot, 'scripts', 'stuck-run-detector.mjs');
308
310
  const srdCmd = `node ${srdScript} --threshold-min 45`; // coding tasks regularly take 30m+
309
311
  if (existingNames.includes(srdName)) {
310
312
  skip(`"${srdName}" job already exists`);
@@ -338,7 +340,7 @@ print();
338
340
 
339
341
  const platform = process.platform;
340
342
  const nodePath = process.execPath;
341
- const indexPath = path.join(schedulerPath, 'dispatcher.js');
343
+ const indexPath = path.join(schedulerInstallRoot, 'dispatcher.js');
342
344
  const logPath = platform === 'win32'
343
345
  ? path.join(os.tmpdir(), 'openclaw-scheduler.log')
344
346
  : '/tmp/openclaw-scheduler.log';
@@ -457,7 +459,7 @@ if (platform === 'darwin') {
457
459
  <string>${xmlEscape(indexPath)}</string>
458
460
  </array>
459
461
  ${userXml} <key>WorkingDirectory</key>
460
- <string>${xmlEscape(schedulerPath)}</string>
462
+ <string>${xmlEscape(serviceWorkingDirectory)}</string>
461
463
  <key>EnvironmentVariables</key>
462
464
  <dict>
463
465
  <key>HOME</key>
@@ -565,7 +567,7 @@ After=network.target
565
567
 
566
568
  [Service]
567
569
  Type=simple
568
- WorkingDirectory=${schedulerPath}
570
+ WorkingDirectory=${serviceWorkingDirectory}
569
571
  ExecStart=${nodePath} --no-warnings ${indexPath}
570
572
  Environment=OPENCLAW_GATEWAY_URL=${gatewayUrl}${gatewayToken ? `\nEnvironment="OPENCLAW_GATEWAY_TOKEN=${gatewayToken.replace(/"/g, '\\"')}"` : ''}
571
573
  Environment=SCHEDULER_DB=${schedulerDbPath}
@@ -612,7 +614,7 @@ WantedBy=default.target
612
614
  if (install) {
613
615
  try {
614
616
  execSync(
615
- `pm2 start "${indexPath}" --name "${pm2Name}" --cwd "${schedulerPath}" ` +
617
+ `pm2 start "${indexPath}" --name "${pm2Name}" --cwd "${serviceWorkingDirectory}" ` +
616
618
  `--log "${logPath}"`,
617
619
  {
618
620
  stdio: 'inherit',
@@ -652,7 +654,7 @@ WantedBy=default.target
652
654
  print(' Setup steps:');
653
655
  print(' 1. Install WSL2: wsl --install (in PowerShell as Admin)');
654
656
  print(' 2. Open your WSL terminal and run this wizard again from there:');
655
- print(` cd ${schedulerPath.replace(/\\/g, '/')}`);
657
+ print(` cd ${schedulerInstallRoot.replace(/\\/g, '/')}`);
656
658
  print(' node setup.mjs');
657
659
  print();
658
660
  print(' WSL2 with systemd enabled gives the best experience (auto-start on login).');