feat(cron): add --account flag for multi-account delivery routing (#26284)

* feat(cron): add --account flag for multi-account delivery routing

Add support for explicit delivery account routing in cron jobs across CLI, normalization, delivery planning, and isolated delivery target resolution.

Highlights:
- Add --account <id> to cron add and cron edit
- Add optional delivery.accountId to cron types and delivery plan
- Normalize and trim delivery.accountId in cron create/update normalization
- Prefer explicit accountId over session lastAccountId and bindings fallback
- Thread accountId through isolated cron run delivery resolution
- Preserve cron edit --best-effort-deliver/--no-best-effort-deliver behavior by keeping implicit announce mode
- Expand tests for account passthrough/merge/precedence and CLI account flows

* cron: resolve rebase duplicate accountId fields

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
Marvin
2026-02-28 17:57:49 +01:00
committed by GitHub
parent e1c8094ad0
commit 5e2ef0e883
13 changed files with 218 additions and 26 deletions

View File

@@ -40,15 +40,21 @@ const { registerCronCli } = await import("./cron-cli.js");
type CronUpdatePatch = {
patch?: {
schedule?: { kind?: string; expr?: string; tz?: string; staggerMs?: number };
payload?: { message?: string; model?: string; thinking?: string };
delivery?: { mode?: string; channel?: string; to?: string; bestEffort?: boolean };
payload?: { kind?: string; message?: string; model?: string; thinking?: string };
delivery?: {
mode?: string;
channel?: string;
to?: string;
accountId?: string;
bestEffort?: boolean;
};
};
};
type CronAddParams = {
schedule?: { kind?: string; staggerMs?: number };
payload?: { model?: string; thinking?: string };
delivery?: { mode?: string };
delivery?: { mode?: string; accountId?: string };
deleteAfterRun?: boolean;
agentId?: string;
sessionTarget?: string;
@@ -246,6 +252,40 @@ describe("cron cli", () => {
expect(params?.deleteAfterRun).toBe(false);
});
it("includes --account on isolated cron add delivery", async () => {
const params = await runCronAddAndGetParams([
"--name",
"accounted add",
"--cron",
"* * * * *",
"--session",
"isolated",
"--message",
"hello",
"--account",
" coordinator ",
]);
expect(params?.delivery?.mode).toBe("announce");
expect(params?.delivery?.accountId).toBe("coordinator");
});
it("rejects --account on non-isolated/systemEvent cron add", async () => {
await expectCronCommandExit([
"cron",
"add",
"--name",
"invalid account add",
"--cron",
"* * * * *",
"--session",
"main",
"--system-event",
"tick",
"--account",
"coordinator",
]);
});
it.each([
{ command: "enable" as const, expectedEnabled: true },
{ command: "disable" as const, expectedEnabled: false },
@@ -354,6 +394,13 @@ describe("cron cli", () => {
expect(patch?.patch?.delivery?.mode).toBe("none");
});
it("updates delivery account without requiring --message on cron edit", async () => {
const patch = await runCronEditAndGetPatch(["--account", " coordinator "]);
expect(patch?.patch?.payload?.kind).toBe("agentTurn");
expect(patch?.patch?.delivery?.accountId).toBe("coordinator");
expect(patch?.patch?.delivery?.mode).toBeUndefined();
});
it("does not include undefined delivery fields when updating message", async () => {
// Update message without delivery flags - should NOT include undefined delivery fields
await runCronCommand(["cron", "edit", "job-1", "--message", "Updated message"]);