- 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)
86 lines
2.7 KiB
TypeScript
86 lines
2.7 KiB
TypeScript
import { Router, Request, Response } from "express";
|
|
import { readFileSync } from "fs";
|
|
|
|
const router = Router();
|
|
|
|
const OPENCLAW_CONFIG_PATH =
|
|
process.env.OPENCLAW_CONFIG_PATH ||
|
|
"/var/lib/docker/volumes/tiger_tiger-config/_data/openclaw.json";
|
|
|
|
function getBotToken(): string {
|
|
if (process.env.TELEGRAM_BOT_TOKEN?.trim()) return process.env.TELEGRAM_BOT_TOKEN.trim();
|
|
try {
|
|
const cfg = JSON.parse(readFileSync(OPENCLAW_CONFIG_PATH, "utf-8"));
|
|
return cfg?.channels?.telegram?.botToken ?? "";
|
|
} catch { return ""; }
|
|
}
|
|
|
|
function getChatId(): string {
|
|
if (process.env.TELEGRAM_CHAT_ID?.trim()) return process.env.TELEGRAM_CHAT_ID.trim();
|
|
return "";
|
|
}
|
|
|
|
/**
|
|
* POST /tiger/notify
|
|
* Body: { message: string, chatId?: string }
|
|
*
|
|
* Sends a Telegram message via the bridge's bot token.
|
|
* Called by Tiger's cron jobs (via curl from inside the container)
|
|
* since OpenClaw's native Telegram channel is disabled (bridge owns polling).
|
|
*
|
|
* curl example from inside container:
|
|
* curl -s -X POST http://172.17.0.1:3456/tiger/notify \
|
|
* -H "Content-Type: application/json" \
|
|
* -H "Authorization: Bearer $BRIDGE_TOKEN" \
|
|
* -d '{"message":"HEARTBEAT_OK"}'
|
|
*/
|
|
router.post("/", async (req: Request, res: Response) => {
|
|
const { message, chatId: overrideChatId } = req.body as {
|
|
message?: string;
|
|
chatId?: string;
|
|
};
|
|
|
|
if (!message?.trim()) {
|
|
return res.status(400).json({ ok: false, error: "message is required" });
|
|
}
|
|
|
|
const token = getBotToken();
|
|
const chatId = overrideChatId || getChatId();
|
|
|
|
if (!token) {
|
|
return res.status(503).json({ ok: false, error: "No bot token configured" });
|
|
}
|
|
if (!chatId) {
|
|
return res.status(503).json({
|
|
ok: false,
|
|
error: "No TELEGRAM_CHAT_ID in bridge .env — set it so Tiger knows where to send notifications",
|
|
});
|
|
}
|
|
|
|
try {
|
|
const tgRes = await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
chat_id: chatId,
|
|
text: message.slice(0, 4096),
|
|
parse_mode: "Markdown",
|
|
}),
|
|
signal: AbortSignal.timeout(10_000),
|
|
});
|
|
|
|
const data = await tgRes.json() as any;
|
|
if (!data.ok) {
|
|
console.error("[notify] Telegram error:", data.description);
|
|
return res.status(502).json({ ok: false, error: data.description });
|
|
}
|
|
|
|
console.log(`[notify] Sent to chat ${chatId}: ${message.slice(0, 60)}…`);
|
|
res.json({ ok: true, messageId: data.result?.message_id });
|
|
} catch (err: any) {
|
|
console.error("[notify] fetch failed:", err.message);
|
|
res.status(502).json({ ok: false, error: err.message });
|
|
}
|
|
});
|
|
|
|
export default router;
|