Scheduled and loop agents get workspaces; schedules UI speaks the user's timezone (#1909)

* fix(app): schedules UI speaks the user's timezone

* refactor(server): require explicit agent placement and bind create-agent command

* fix(server): scheduled agents get a workspace and show in the sidebar

* fix(server): loop agents get a workspace and show in the sidebar

* fix(server): preserve scheduled and loop run semantics through the create command

* fix(server): serialize all schedule record writes through the per-schedule queue

* fix(server): tighten create-agent dependency contracts

* fix(server): handle schedule restamps and loop cancellations

* fix(server): preserve scheduled and loop create semantics

* refactor(server): schedule store owns atomic mutations

* fix(server): keep schedule stamp reuse deterministic

* fix(server): handle loop workspace stamp rejection

* refactor(server): schedule store owns typed identity upsert

* fix(server): keep schedule workspace stamps server-owned

* fix(server): preserve scheduled run semantics

* refactor: required nullable workspaceId replaces placement union; pure cadence policy

* fix(server): tighten scheduled and loop agent edges

* fix(server): fail canceled scheduled runs

* fix(server): close schedule and loop cwd edges

* fix(server): refresh schedule workspace stamps

* fix(server): preserve schedule timezone on replace

* fix(server): close loop stop and cadence reset edges
This commit is contained in:
Mohamed Boudra
2026-07-07 17:13:28 +08:00
committed by GitHub
parent 783f43c580
commit d3e1fe48f6
29 changed files with 4814 additions and 1067 deletions
+29 -8
View File
@@ -85,17 +85,38 @@ describe("interval formatting", () => {
describe("describeCron", () => {
it("humanizes common fixed-time cron shapes", () => {
expect(describeCron("0 * * * *")).toBe("Every hour");
expect(describeCron("15 * * * *")).toBe("Every hour at :15");
expect(describeCron("0 9 * * *")).toBe("Daily at 09:00 UTC");
expect(describeCron("0 9 * * 1-5")).toBe("Weekdays at 09:00 UTC");
expect(describeCron("0 9 * * 0,6")).toBe("Weekends at 09:00 UTC");
expect(describeCron("0 9 * * 1")).toBe("Mondays at 09:00 UTC");
expect(describeCron({ type: "cron", expression: "0 * * * *" })).toBe("Every hour");
expect(describeCron({ type: "cron", expression: "15 * * * *" })).toBe("Every hour at :15");
expect(describeCron({ type: "cron", expression: "0 9 * * *" })).toBe("Daily at 09:00 UTC");
expect(describeCron({ type: "cron", expression: "0 9 * * 1-5" })).toBe("Weekdays at 09:00 UTC");
expect(describeCron({ type: "cron", expression: "0 9 * * 0,6" })).toBe("Weekends at 09:00 UTC");
expect(describeCron({ type: "cron", expression: "0 9 * * 1" })).toBe("Mondays at 09:00 UTC");
});
it("labels fixed-time cron cadences with their stored timezone", () => {
expect(
describeCron({
type: "cron",
expression: "0 9 * * *",
timezone: "America/New_York",
}),
).toBe("Daily at 09:00 America/New_York");
expect(
formatCadence({
type: "cron",
expression: "0 9 * * 1-5",
timezone: "Europe/Madrid",
}),
).toBe("Weekdays at 09:00 Europe/Madrid");
});
it("keeps timezone-less fixed-time cron cadences labeled as UTC", () => {
expect(formatCadence({ type: "cron", expression: "0 9 * * *" })).toBe("Daily at 09:00 UTC");
});
it("returns null for invalid or unrecognized valid cron expressions", () => {
expect(describeCron("not a cron")).toBeNull();
expect(describeCron("*/5 * * * *")).toBeNull();
expect(describeCron({ type: "cron", expression: "not a cron" })).toBeNull();
expect(describeCron({ type: "cron", expression: "*/5 * * * *" })).toBeNull();
expect(formatCadence({ type: "cron", expression: "0 9 * * *" })).toBe("Daily at 09:00 UTC");
});
});