Drops `alpha` / `beta` / `rc` as accepted pre-release labels in
bin/dev/release.sh. `nightly` is now the only pre-release descriptor,
in preparation for automated nightly tags.
Renames the Homebrew tap formula from `fabro-beta` to `fabro-nightly`:
- installer/fabro-beta.rb.template -> installer/fabro-nightly.rb.template
(class renamed FabroBeta -> FabroNightly, desc updated).
- `update-homebrew-beta` job in release.yml is now
`update-homebrew-nightly` with matching file paths and commit message.
Breaking for existing `brew install fabro-sh/tap/fabro-beta` users: the
old formula file stays in the tap for now (removed in a follow-up once
fabro-nightly is populated) and stops receiving updates. Users should
switch to `brew install fabro-sh/tap/fabro-nightly` once the new
formula is published by the next pre-release tag.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a verify_release_tests step to bin/dev/release.sh that runs the
same nextest invocation the CI release workflow uses -- workspace,
--release, --profile ci -- with SEGMENT_WRITE_KEY baked in so
telemetry-active code paths are actually exercised. Runs before the
version bump/tag, so regressions that only show up under --release
plus a compiled-in write key (e.g. telemetry recreating ~/.fabro,
sender tests that assume no key) fail locally in ~5 min instead of
~60 min on a tagged release run.
`--skip-tests` for when you've already run it yourself.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two fabro-telemetry sender tests assert that upload/upload_blocking
return an error with "SEGMENT_WRITE_KEY not set" -- a claim that only
holds when SEGMENT_WRITE_KEY is absent at compile time. The release
workflow sets the secret at build time, so these tests now fail under
`cargo nextest run --workspace` in release CI (newly exercised after
switching the release workflow from `cargo test` to nextest).
Guard each assertion with an early return when SEGMENT_WRITE_KEY is
compiled in so the test passes in release CI while still verifying the
no-key path for every other build.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Surfaces the docs website shortcut alongside the other onboarding
commands so new users can find the web docs without hunting through
`fabro help`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Replace the three-line "help along the way" trio with a Discord
callout in the style of qlty's landing: one line pointing at per-
command --help, one inviting users to the Fabro Discord.
- New final line uses qlty's dim/cyan split: "For a full list of
commands, run `fabro help`."
- Drop `sandbox cp` and `sandbox preview` from the curated list;
`sandbox ssh` stays. Both are still reachable via `fabro help`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Moves `server start` and `secret set` into Set up so the first section
covers everything a user does once before they have a working install.
Drops `secret list` from the landing — `fabro --help` still surfaces it.
Merges the run-inspection commands (`logs`, `sandbox ssh`, `sandbox
preview`, `sandbox cp`) under a single "Inspect runs" heading, since
they all answer "what happened in this run?".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Running `fabro` with no subcommand now prints a short, colorized guide
highlighting the most important commands (install, doctor, repo init,
validate, preflight, run, logs, server start, secret set/list, sandbox
ssh/preview/cp) instead of clap's full --help dump.
`fabro --help` and `fabro help` still render clap's comprehensive
reference unchanged. The CLI makes the root subcommand optional and
intercepts the None case in main_inner before telemetry or logging
init; the empty command name also suppresses the "CLI Executed"
tracking event for this pseudo-command.
Includes an inline-snapshot IT test covering the full landing body and
updates four pre-existing usage-line snapshots (<COMMAND> → [COMMAND])
that reflect the now-optional subcommand.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
In release builds with SEGMENT_WRITE_KEY baked in (i.e. CI), the
post-command telemetry flush calls spawn_fabro_subcommand, which in turn
does create_dir_all(~/.fabro/tmp) and writes a JSONL event file. That
silently undoes the directory removal that `fabro uninstall --yes` just
performed — leaving a stray ~/.fabro/tmp/ behind and breaking the
uninstall integration tests on CI release runs.
Fixes:
- run_uninstall calls fabro_telemetry::shutdown() before removal so the
buffered "CLI Executed" track in main() can't be queued or flushed,
and the background thread can't spawn the sender subprocess.
- TestContext::command() exports FABRO_TELEMETRY=off so test subprocesses
never initialise telemetry at all, as a belt-and-suspenders guard.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aligns the release workflow's per-target test step with the regular CI
test workflow: uses cargo-nextest with --status-level slow and the ci
profile so release runs get the same timeout headroom and quieter output.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a sibling Homebrew formula so users can opt into pre-releases with
`brew install fabro-sh/tap/fabro-beta`. Pre-release tags (v*-*) update
Formula/fabro-beta.rb in the tap; stable tags still only touch
Formula/fabro.rb. The two formulae declare conflicts_with each other
since they both install the fabro binary.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a ci nextest profile (30s slow-timeout, terminate-after 4, 2s leak-
timeout) and wires rust.yml's test and test-macos jobs to use it. Local
invocations keep using the tight default profile.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Default nextest emits a PASS line per test, which scrolls thousands of
lines in CI. `slow` shows only slow/failing tests plus the summary.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous pin (v2 @ 3d267786...) runs on Node 20, which GitHub Actions
is deprecating on Sept 16, 2026. v2.2.0 switches to Node 24.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- server_start::help: correct --watch-web description indent from 14 to 10 spaces
in the stripping regex so the filter matches in debug builds where the flag
is present in --help output.
- fabro-telemetry: split telemetry_level default test into debug/release
variants. The function's default depends on cfg!(debug_assertions), so the
prior single test panicked under cargo test --release.
Verified: cargo nextest run --workspace (debug) → 3990 passed; cargo test
--workspace --release → all 69 test binaries pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Update VERSION filter regex to handle prerelease suffixes (e.g., 0.204.0-beta.1)
- Add VERSION filter to JSON snapshots in fabro_json_snapshot macro
- Fix attach test to use [VERSION] placeholder instead of hardcoded version
- Update upgrade help snapshot to include new --prerelease flag
- Change fake version in upgrade test from v0.176.3 to v999.0.0 to avoid collision
- Strip --watch-web from server start help (debug-only flag, varies by build)
- Gate test_panic module with #[cfg(debug_assertions)] (debug-only command)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Widens the candidate set to include prereleases, picks max semver across
stable + prereleases. Falls back to /releases/latest if no parseable
non-draft tag is returned. Conflicts with --version. Background
auto-upgrade notice remains stable-only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
actions/checkout v4 → v6.0.2, actions/upload-artifact v4 → v7.0.1,
actions/download-artifact v4 → v8.0.1. Silences the Node 20 deprecation
warnings ahead of the June 2026 forced cutover. All pins are full
commit SHAs with version comments.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The fake /bin/sh script in the render_error protocol test printed and
exited without reading stdin, which raced the parent's write_all on
Linux — EPIPE would surface as ChildCrashed (500) instead of the
RenderFailed path (400) the test asserts. macOS pipe buffering masked
the race. Adding `cat >/dev/null` mirrors the sibling
protocol_violation test and makes the child consume the DOT input
before printing the RENDER_ERROR line.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves Dependabot alerts #4, #5 (aws-lc-sys CRL scope check and X.509
name-constraint bypass; both fixed in 0.39.0+).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
References npm/package-lock.json and an `npm run start` script that no
longer exists. Nothing in CI or compose configs references it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- rust.yml: move clippy to nightly-2026-04-14 (was stable); also pin
fmt to the same nightly date for consistency. Both jobs now use the
dated nightly and the run-step uses `cargo +nightly-2026-04-14 ...`.
- AGENTS.md: update developer commands to match CI.
- Duration constructors: replace `Duration::from_secs(N * 60)` /
`Duration::from_millis(N * 1000)` with `from_mins` / `from_secs` /
`from_hours` across the workspace to satisfy clippy's new
`duration_suboptimal_units` lint. std::time::Duration only — custom
`settings::duration::Duration` sites kept on `from_secs`.
- map/unwrap_or cleanup: `.map(f).unwrap_or(v)` → `.map_or(v, f)`,
`.map(f).unwrap_or(false)` on Result → `.is_ok_and(f)`, per
`clippy::map_unwrap_or`.
- Misc lints: collapse nested `if` into match guard in
handler/llm/api.rs and run_state.rs; replace `columns.len() > 0`
with `!columns.is_empty()`; switch a pair of `sort_by` calls to
`sort_by_key`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- serve.rs: annotate debug-only `bun run dev` spawn with
#[expect(clippy::disallowed_methods, ...)] and add the missing
watch_web field to three ServeArgs test fixtures.
- install.rs: replace absolute `fabro_server::serve::DEFAULT_TCP_PORT`
path with `serve::DEFAULT_TCP_PORT` (use is already imported) to
satisfy clippy::absolute_paths.
- pagination test: request an explicit page[limit]=100 for the
"fits in one page" case instead of relying on the server default,
so the test stays robust as the built-in model catalog grows.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a verify-spa job to the release workflow that rebuilds the SPA
and fails if committed assets are stale, and add the same check to
bin/dev/release.sh so tagging fails before anything is pushed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Show a getting-started empty state with quick start commands and
resource links (docs, Discord) when there are zero runs. Link the
logo to /runs in non-demo mode instead of /start.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stops any running server then starts a fresh one, passing through all
the same flags as `server start` (--watch-web, --foreground, etc.).
Works even if no server is currently running.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Spawns `bun run dev` in apps/fabro-web as a child of the server process,
so a single command starts both the API server and the web asset watcher.
The flag is gated behind #[cfg(debug_assertions)] and does not exist in
release builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
--web-url defaulted to http://localhost:3000 but merge_server_settings
hardcoded http://127.0.0.1:32276, causing GitHub OAuth redirect_uri
mismatch. Now both derive from the same --web-url flag (default:
http://127.0.0.1:32276 via DEFAULT_TCP_PORT).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Print the HTTP URL (cyan) and enabled auth methods after server start,
so users can see at a glance how to access the server and what login
methods are available.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously the login page used an either/or conditional, hiding the
GitHub button whenever dev-token was in the methods list. Now GitHub
is the primary action and dev-token collapses behind a "Use a dev
token instead" toggle.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Update 5 more dry_run_examples snapshots to use [GRAPH_PATH] filter
- Skip LLM preflight check when graph has no LLM nodes (fixes
preflight_allows_pull_request_enabled_without_github_credentials)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add [GRAPH_PATH] filter to run_output_filters so dry_run_simple
snapshot is path-independent
- Double fabro-cli slow-timeout (3s → 6s) to prevent ps test timeouts
- Preserve cloud sandboxes; bump snapshot to fabro-v7 with 8 CPU / 16GB
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The snapshot was overfit to local env — it hardcoded Anthropic models
passing because the server inherited ANTHROPIC_API_KEY from the test
runner. On CI with no API keys, all models are skipped and the snapshot
diverged.
Replace the snapshot with targeted assertions: exit code 0 and "Skipped"
appears in stderr. This works regardless of which credentials are
available in the test environment.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>