Files
QwenClaw-with-Auth/src/jobs.ts

95 lines
2.7 KiB
TypeScript

import { readdir } from "fs/promises";
import { join } from "path";
const JOBS_DIR = join(process.cwd(), ".qwen", "qwenclaw", "jobs");
export interface Job {
name: string;
schedule: string;
prompt: string;
recurring: boolean;
notify: true | false | "error";
}
function parseFrontmatterValue(raw: string): string {
return raw.trim().replace(/^["']|["']$/g, "");
}
function parseJobFile(name: string, content: string): Job | null {
const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/);
if (!match) {
console.error(`Invalid job file format: ${name}`);
return null;
}
const frontmatter = match[1];
const prompt = match[2].trim();
const lines = frontmatter.split("\n").map((l) => l.trim());
const scheduleLine = lines.find((l) => l.startsWith("schedule:"));
if (!scheduleLine) {
return null;
}
const schedule = parseFrontmatterValue(scheduleLine.replace("schedule:", ""));
const recurringLine = lines.find((l) => l.startsWith("recurring:"));
const dailyLine = lines.find((l) => l.startsWith("daily:")); // legacy alias
const recurringRaw = recurringLine
? parseFrontmatterValue(recurringLine.replace("recurring:", "")).toLowerCase()
: dailyLine
? parseFrontmatterValue(dailyLine.replace("daily:", "")).toLowerCase()
: "";
const recurring =
recurringRaw === "true" || recurringRaw === "yes" || recurringRaw === "1";
const notifyLine = lines.find((l) => l.startsWith("notify:"));
const notifyRaw = notifyLine
? parseFrontmatterValue(notifyLine.replace("notify:", "")).toLowerCase()
: "";
const notify: true | false | "error" =
notifyRaw === "false" || notifyRaw === "no"
? false
: notifyRaw === "error"
? "error"
: true;
return { name, schedule, prompt, recurring, notify };
}
export async function loadJobs(): Promise<Job[]> {
const jobs: Job[] = [];
let files: string[];
try {
files = await readdir(JOBS_DIR);
} catch {
return jobs;
}
for (const file of files) {
if (!file.endsWith(".md")) continue;
const content = await Bun.file(join(JOBS_DIR, file)).text();
const job = parseJobFile(file.replace(/\.md$/, ""), content);
if (job) jobs.push(job);
}
return jobs;
}
export async function clearJobSchedule(jobName: string): Promise<void> {
const path = join(JOBS_DIR, `${jobName}.md`);
const content = await Bun.file(path).text();
const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/);
if (!match) return;
const filteredFrontmatter = match[1]
.split("\n")
.filter((line) => !line.trim().startsWith("schedule:"))
.join("\n")
.trim();
const body = match[2].trim();
const next = `---\n${filteredFrontmatter}\n---\n${body}\n`;
await Bun.write(path, next);
}