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:
@@ -8,6 +8,12 @@ const baseOptions = {
|
||||
provider: "claude",
|
||||
};
|
||||
|
||||
const baseCron = {
|
||||
prompt: "do the thing",
|
||||
cron: "0 9 * * *",
|
||||
provider: "claude",
|
||||
};
|
||||
|
||||
describe("parseScheduleCreateInput cwd/host validation", () => {
|
||||
beforeEach(() => {
|
||||
vi.spyOn(process, "cwd").mockReturnValue("/local/project");
|
||||
@@ -60,3 +66,43 @@ describe("parseScheduleCreateInput cwd/host validation", () => {
|
||||
).toThrow(expect.objectContaining({ code: "MISSING_CWD" }));
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseScheduleCreateInput first-run timing", () => {
|
||||
test("--every with no run-now flag fires immediately on creation", () => {
|
||||
const input = parseScheduleCreateInput(baseOptions);
|
||||
expect(input.runOnCreate).toBe(true);
|
||||
});
|
||||
|
||||
test("--every with --no-run-now waits the interval", () => {
|
||||
const input = parseScheduleCreateInput({ ...baseOptions, runNow: false });
|
||||
expect(input.runOnCreate).toBe(false);
|
||||
});
|
||||
|
||||
test("--cron with no run-now flag waits for the next cron slot", () => {
|
||||
const input = parseScheduleCreateInput(baseCron);
|
||||
expect(input.runOnCreate).toBe(false);
|
||||
});
|
||||
|
||||
test("--cron with --run-now fires immediately on creation", () => {
|
||||
const input = parseScheduleCreateInput({ ...baseCron, runNow: true });
|
||||
expect(input.runOnCreate).toBe(true);
|
||||
});
|
||||
|
||||
test("--every with --run-now is rejected as redundant", () => {
|
||||
expect(() => parseScheduleCreateInput({ ...baseOptions, runNow: true })).toThrow(
|
||||
expect.objectContaining({
|
||||
code: "REDUNDANT_RUN_NOW",
|
||||
message: expect.stringContaining("--run-now is redundant with --every"),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test("--cron with --no-run-now is rejected as redundant", () => {
|
||||
expect(() => parseScheduleCreateInput({ ...baseCron, runNow: false })).toThrow(
|
||||
expect.objectContaining({
|
||||
code: "REDUNDANT_NO_RUN_NOW",
|
||||
message: expect.stringContaining("--no-run-now is redundant with --cron"),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user