Files
openclaw/src/cli/cron-cli/trigger-options.ts
Peter Steinberger a6768d9de5 feat(cron): event triggers — polled condition-watcher scripts via code mode (#101195)
* feat(cron): add headless code-mode driver and trigger-script evaluator

Part A of cron event triggers: runCodeModeScriptHeadless runs a script
to completion (exec/settle/resume, no snapshots, no session), plus the
cron-facing evaluator with per-job tool catalog cache, semaphore, 16KB
state cap, and closed failure taxonomy.

* fix(cron): correct trigger-script bootstrap flags and cache narrowing

* feat(cron): add event triggers (polled condition-watcher scripts)

Part B: trigger field on cron jobs gated by cron.triggers.enabled;
timer evaluates the script each due tick, quiet ticks leave no run
history, fired runs append the script message to the payload; once
semantics, min-interval floor, SQLite columns, RPC/CLI/agent-tool
surfaces, and docs.

* fix(cron): propagate triggerEval through startup catch-up outcomes

* fix(cron): honor cron staggering on quiet trigger ticks; fix trigger test types

* fix(cron): reject with Error reason in trigger-script abort test

* fix(cron): regenerate protocol/docs/snapshot artifacts and break madge cycle for trigger types

CI fixes for #101195: trigger evaluator result types move to the cron
types leaf (madge cycle), cron tool schema inventory gains trigger,
Swift protocol bindings + docs map + Linux prompt snapshots regenerated.

* fix(cron): drop underscore-dangle names in trigger code sync assert

* fix(cron): adopt registerHeadlessToolSearchCatalog after tool-search symbol localization

Upstream #101831 made registerToolSearchCatalog module-private; fold the
headless ref-only catalog registration into one public seam.
2026-07-07 19:12:38 +01:00

41 lines
1.3 KiB
TypeScript

// Client-side trigger script loading for cron create/edit commands.
import fs from "node:fs/promises";
const MAX_CRON_TRIGGER_SCRIPT_BYTES = 65_536;
async function readStdin(stream: NodeJS.ReadableStream): Promise<string> {
const chunks: Buffer[] = [];
let total = 0;
for await (const chunk of stream) {
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
total += buffer.byteLength;
if (total > MAX_CRON_TRIGGER_SCRIPT_BYTES) {
throw new Error("Trigger script exceeds 65536 bytes");
}
chunks.push(buffer);
}
return Buffer.concat(chunks, total).toString("utf8");
}
/** Reads a trigger script locally before sending the cron RPC. */
export async function readCronTriggerScript(
source: string,
deps?: {
readFile?: (path: string) => Promise<string>;
stdin?: NodeJS.ReadableStream;
},
): Promise<string> {
const raw =
source === "-"
? await readStdin(deps?.stdin ?? process.stdin)
: await (deps?.readFile ?? ((path) => fs.readFile(path, "utf8")))(source);
if (Buffer.byteLength(raw, "utf8") > MAX_CRON_TRIGGER_SCRIPT_BYTES) {
throw new Error("Trigger script exceeds 65536 bytes");
}
const script = raw.trim();
if (!script) {
throw new Error("Trigger script must not be empty");
}
return script;
}