- 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)
77 lines
2.4 KiB
TypeScript
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;
|