From b388050269bcda253ca610872fa313c5fabb93ce Mon Sep 17 00:00:00 2001 From: ignaciocanosa Date: Mon, 31 Aug 2026 15:06:00 -0300 Subject: [PATCH] fix(cli): make --canary-bot reachable on init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The closing checklist init prints tells the user to re-run it with --canary-bot=[bot] to enable the weekly canary, but the flag was missing from validateLocalFlags's allowlist in cli.mjs (and from the value-taking list, and from the global help text). The documented command failed with "Unknown option: --canary-bot" before init() ever ran, so the canary stays on its default forever and the watchtower reports that as a healthy skip rather than a misconfiguration. Added init to the allowlist and value-taking list for the init command, and to the help text. Added two tests: one renders init with --canary-bot=my-app[bot] and asserts it lands in facility-crew.yml (and the default does not leak in), the other asserts a valueless --canary-bot still errors and that global help documents the flag. Reverted the fix locally and reran: both fail with exactly the reported error; reapplied it, both pass. Ran the full packages/cli suite: no new failures. 12 tests already fail on a clean checkout of main on this machine (chmod semantics, fixtures needing infra this environment doesn't have) — confirmed via the same suite on an unmodified checkout, unrelated to this change. Fixes #229 --- packages/cli/src/cli.mjs | 3 +++ packages/cli/test/init.test.mjs | 34 +++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/packages/cli/src/cli.mjs b/packages/cli/src/cli.mjs index ae34d0c3..84058ab1 100644 --- a/packages/cli/src/cli.mjs +++ b/packages/cli/src/cli.mjs @@ -93,6 +93,7 @@ function help() { item(dim(' --build-model= --review-model= --plan-model=')); item(dim(' --codex-build-model= --codex-plan-model= --org= --project=')); item(dim(' --preview-image= --preview-command= --preview-port= --preview-readiness-path= --preview-ttl-hours=')); + item(dim(" --canary-bot=[bot]")); item(dim("Run facility --help for precise usage.")); item(dim("Global platform flags: --profile --json --timeout ")); console.log(""); @@ -215,6 +216,7 @@ function validateLocalFlags(command, flags) { "preview-port", "preview-readiness-path", "preview-ttl-hours", + "canary-bot", "help", ]), add: new Set(["dir", "help"]), @@ -277,6 +279,7 @@ function validateLocalFlags(command, flags) { "preview-port", "preview-readiness-path", "preview-ttl-hours", + "canary-bot", ] : ["dir"]; for (const name of valueNames) { diff --git a/packages/cli/test/init.test.mjs b/packages/cli/test/init.test.mjs index b33e245b..20034028 100644 --- a/packages/cli/test/init.test.mjs +++ b/packages/cli/test/init.test.mjs @@ -463,6 +463,40 @@ test("init installs the method end to end", async (t) => { assert.ok(again.stdout.includes("left untouched"), "second init should skip existing files"); }); +// Regression coverage for #229: the closing checklist tells the user to +// "re-run init with --canary-bot=[bot]", but the flag was missing +// from validateLocalFlags's allowlist, so that documented command failed +// before init() ever ran. https://github.com/theam/facility/issues/229 +test("init accepts --canary-bot and renders it into the crew workflow", async (t) => { + const dir = makeTargetRepo(); + t.after(() => rmSync(dir, { recursive: true, force: true })); + + const result = runCli( + ["init", "--yes", `--dir=${dir}`, "--provision=npm run setup", "--canary-bot=my-app[bot]"], + dir, + ); + assert.equal(result.status, 0, result.stdout + result.stderr); + + const crew = readFileSync(join(dir, ".github/workflows/facility-crew.yml"), "utf8"); + assert.ok(crew.includes("my-app[bot]"), "custom canary bot login must be rendered"); + assert.ok( + !crew.includes("facility-canary[bot]"), + "default canary bot login must not leak in once overridden", + ); +}); + +test("init rejects a valueless --canary-bot and documents the flag in help", () => { + const dir = makeTargetRepo(); + const rejected = runCli(["init", "--yes", `--dir=${dir}`, "--canary-bot"], dir); + assert.equal(rejected.status, 1); + assert.match(rejected.stderr, /--canary-bot requires a value/); + rmSync(dir, { recursive: true, force: true }); + + const help = runCli(["help"]); + assert.equal(help.status, 0); + assert.match(help.stdout, /--canary-bot=\[bot\]/, "global help must document --canary-bot"); +}); + test("init renders every supported Anthropic authentication mode consistently", async (t) => { const expectations = { "api-key": "anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}",