OpenClawDashboard/bridge/src/routes/cron.ts
Manohar a65902edf9 feat(bridge): Telegram polling, file-based tasks/projects, cron/keys/deploy routes
- routes/notify.ts: Telegram delivery endpoint POST /tiger/notify
- routes/tasks-file.ts: TASKS.md/PROJECTS.md reader (JSON block parser — P0 fix)
  Parser reads only from TASKS_JSON fenced block; returns 502 if block absent
- routes/cron.ts: GET /tiger/cron + POST /tiger/cron/:id/run
- routes/keys.ts: GET /tiger/keys (key presence map, no values exposed)
- routes/agents-activity.ts: GET /tiger/agents/:id/files
- routes/route-task.ts: POST /tiger/route-task (LLM router)
- routes/deploy.ts: POST /tiger/deploy-dashboard (path: OpenClawDashboard)
- db.ts: comment Reserved telegram columns (future task-from-Telegram)
2026-05-02 20:09:43 +00:00

77 lines
2.4 KiB
TypeScript

import { Router, Request, Response } from "express";
import { execInSandbox } from "../tiger.js";
const router = Router();
// cron/jobs.json lives inside the container at a known path.
// We read it directly — openclaw cron list --json requires an active gateway
// WebSocket which may not always be up.
const CRON_JOBS_PATH = "/home/node/.openclaw/cron/jobs.json";
function formatCronJobs(raw: any): any[] {
const jobs = raw?.jobs ?? [];
return jobs.map((j: any) => ({
id: j.id,
name: j.name ?? j.id,
schedule: j.schedule?.expr ?? "",
tz: j.schedule?.tz ?? "UTC",
enabled: j.enabled ?? true,
agentId: j.agentId ?? "main",
lastRun: j.state?.lastRunAtMs
? {
at: new Date(j.state.lastRunAtMs).toISOString(),
status: j.state.lastRunStatus ?? j.state.lastStatus ?? "unknown",
durationMs: j.state.lastDurationMs,
errors: j.state.consecutiveErrors ?? 0,
lastError: j.state.lastError ?? null,
}
: null,
nextRun: j.state?.nextRunAtMs
? new Date(j.state.nextRunAtMs).toISOString()
: null,
message: j.payload?.message?.slice(0, 120) ?? "",
}));
}
// GET /tiger/cron — list cron jobs directly from jobs.json
router.get("/", async (_req: Request, res: Response) => {
try {
const { stdout } = await execInSandbox(`cat ${CRON_JOBS_PATH} 2>/dev/null || echo '{}'`);
let raw: any = {};
try { raw = JSON.parse(stdout.trim() || "{}"); } catch { raw = {}; }
const jobs = formatCronJobs(raw);
// Scheduler meta: enabled + nextWakeAt (from first job with nextRunAtMs)
const nextWake = jobs.find((j) => j.nextRun)?.nextRun ?? null;
const hasErrors = jobs.some((j) => (j.lastRun?.errors ?? 0) > 0);
res.json({
ok: true,
jobs,
status: {
enabled: true,
jobCount: jobs.length,
nextWake,
hasErrors,
},
});
} catch (err: any) {
res.status(500).json({ ok: false, error: err.message });
}
});
// POST /tiger/cron/:id/run — trigger a cron job immediately via gateway
router.post("/:id/run", async (req: Request, res: Response) => {
const { id } = req.params;
try {
const { stdout, stderr } = await execInSandbox(
`openclaw cron run ${id} 2>&1 || true`
);
res.json({ ok: true, output: (stdout || stderr).slice(0, 500) });
} catch (err: any) {
res.status(500).json({ ok: false, error: err.message });
}
});
export default router;