schedule: fire --every now by default, add run-once for cron-style triggers (#689)

Interval schedules used to wait the full interval before their first run, which
made `--every 1d` feel broken for fresh schedules. Now `--every` fires
immediately on creation; `--cron` keeps waiting for the next slot. `--no-run-now`
and `--run-now` override the defaults, and the parser rejects redundant combos.

Adds `paseo schedule run-once <id>` to manually trigger a single run without
advancing cadence or recomputing completion. The new `runOnCreate` field and
`schedule/run-once` RPC are additive on the WebSocket schema.
This commit is contained in:
Mohamed Boudra
2026-05-05 19:56:51 +07:00
parent f11aea3223
commit 2b6d7d4ec2
13 changed files with 387 additions and 16 deletions
@@ -388,6 +388,10 @@ type ScheduleDeletePayload = Extract<
SessionOutboundMessage,
{ type: "schedule/delete/response" }
>["payload"];
type ScheduleRunOncePayload = Extract<
SessionOutboundMessage,
{ type: "schedule/run-once/response" }
>["payload"];
export type FetchAgentTimelinePayload = FetchAgentTimelineResponseMessage["payload"];
export type FetchAgentTimelineDirection = FetchAgentTimelinePayload["direction"];
@@ -541,6 +545,7 @@ export interface CreateScheduleOptions {
};
maxRuns?: number;
expiresAt?: string;
runOnCreate?: boolean;
requestId?: string;
}
export interface InspectScheduleOptions {
@@ -3667,6 +3672,7 @@ export class DaemonClient {
...(options.name ? { name: options.name } : {}),
...(typeof options.maxRuns === "number" ? { maxRuns: options.maxRuns } : {}),
...(options.expiresAt ? { expiresAt: options.expiresAt } : {}),
...(typeof options.runOnCreate === "boolean" ? { runOnCreate: options.runOnCreate } : {}),
},
responseType: "schedule/create/response",
timeout: 10000,
@@ -3744,6 +3750,18 @@ export class DaemonClient {
});
}
async scheduleRunOnce(options: InspectScheduleOptions): Promise<ScheduleRunOncePayload> {
return this.sendCorrelatedSessionRequest({
requestId: options.requestId,
message: {
type: "schedule/run-once",
scheduleId: options.id,
},
responseType: "schedule/run-once/response",
timeout: 10000,
});
}
async loopRun(options: RunLoopOptions): Promise<LoopRunPayload> {
return this.sendCorrelatedSessionRequest({
requestId: options.requestId,