Commit graph

2283 commits

Author SHA1 Message Date
Bryan Helmkamp
2d8d72717d
refactor(release): simplify pre-release channel to nightly only
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>
2026-04-17 11:39:19 -04:00
Bryan Helmkamp
18a551f076
feat(release): smoke-test release mode before tagging
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>
2026-04-17 10:14:10 -04:00
Bryan Helmkamp
3d2c586eda
Bump version to 0.205.0-beta.2 2026-04-17 10:12:06 -04:00
Bryan Helmkamp
a1776b7beb
fix(test): skip write-key sender assertions when CI bakes the key in
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>
2026-04-17 10:05:39 -04:00
Bryan Helmkamp
8ce451869f
Bump version to 0.205.0-beta.1 2026-04-17 09:21:20 -04:00
Bryan Helmkamp
7bf0c6678e
feat(cli): add fabro docs to landing Set up section
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>
2026-04-17 09:03:40 -04:00
Bryan Helmkamp
afcbb0628a
refactor(cli): tighten landing footer and drop sandbox cp/preview
- 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>
2026-04-17 09:03:08 -04:00
Bryan Helmkamp
ae2efaabf9
refactor(cli): regroup landing output around lifecycle stages
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>
2026-04-17 09:01:08 -04:00
Bryan Helmkamp
a4159f7bb6
feat(cli): show curated landing output for bare fabro
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>
2026-04-17 08:59:03 -04:00
Bryan Helmkamp
1e147c0d88
fix(cli): prevent telemetry from recreating ~/.fabro after uninstall
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>
2026-04-17 08:40:04 -04:00
Bryan Helmkamp
dd49ec51fd
ci(release): run tests with nextest to match rust.yml
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>
2026-04-17 08:15:17 -04:00
Bryan Helmkamp
ae35cb114c
ci: publish fabro-beta Homebrew formula on pre-release tags
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>
2026-04-17 08:12:53 -04:00
Bryan Helmkamp
297a591fd2
ci: run nextest with --profile ci for looser timeouts on CI runners
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>
2026-04-17 08:09:54 -04:00
Bryan Helmkamp
ad8db228db
ci: pass --status-level slow to nextest to cut log noise
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>
2026-04-17 08:04:40 -04:00
Bryan Helmkamp
bdc3e50a6c
ci: bump oven-sh/setup-bun to v2.2.0 for Node 24 runtime
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>
2026-04-17 07:57:53 -04:00
Bryan Helmkamp
5946047202
deps: bump rand 0.8 → 0.9 (#163)
## Summary
- Bumps `rand` from 0.8 to 0.9 to resolve Dependabot alert #16 (low
severity: "Rand is unsound with a custom logger using rand::rng()",
fixed in 0.9.3).
- Migrates call sites to the renamed 0.9 APIs.

## API changes applied
- `rand::thread_rng()` → `rand::rng()`
- `Rng::gen_range(..)` → `Rng::random_range(..)`
- `Rng::gen::<T>()` → `Rng::random::<T>()`
- `OsRng.fill_bytes(..)` → `OsRng.try_fill_bytes(..).expect("OS RNG")` —
in 0.9 `OsRng` implements `TryRngCore` instead of `RngCore` directly.

## Test plan
- [x] `cargo build --workspace`
- [x] `cargo nextest run -p fabro-util -p fabro-server -p fabro-workflow
-p fabro-oauth` (1270 passed)
- [x] `cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D
warnings`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 07:57:10 -04:00
Bryan Helmkamp
31b4bd801e
Bump version to 0.205.0-beta.0 2026-04-17 07:55:47 -04:00
Bryan Helmkamp
4c835c95b0
fix(test): make release-mode unit tests pass workspace-wide
- 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>
2026-04-17 07:48:08 -04:00
Bryan Helmkamp
7fda2ee25b
fix(test): update snapshots for version and --prerelease flag
- 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>
2026-04-17 07:31:40 -04:00
Bryan Helmkamp
0b16993b30
Bump version to 0.204.0-beta.1
Some checks are pending
Rust / Clippy (push) Waiting to run
Rust / Test (Linux) (push) Waiting to run
Rust / Test (macOS) (push) Waiting to run
Rust / Format (push) Waiting to run
TypeScript / Typecheck (push) Waiting to run
TypeScript / Test (push) Waiting to run
TypeScript / Build (push) Waiting to run
2026-04-16 20:20:37 -04:00
Bryan Helmkamp
0b77a3efa2
feat(cli): add --prerelease to fabro upgrade
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>
2026-04-16 20:20:14 -04:00
Bryan Helmkamp
60cbdc97c2
ci: bump GitHub Actions to Node 24 runtimes
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>
2026-04-16 20:11:25 -04:00
Bryan Helmkamp
fa0c1616f2
Bump version to 0.204.0-beta.0 2026-04-16 20:02:45 -04:00
Bryan Helmkamp
4c1d2e44f7
cleanup 2026-04-16 20:02:24 -04:00
Bryan Helmkamp
3ed65d3728
fix(test): consume stdin in render_graph RENDER_ERROR fake subprocess
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>
2026-04-16 19:51:59 -04:00
Bryan Helmkamp
4e7026413a
deps: bump aws-lc-rs 1.16.1 → 1.16.3 (pulls aws-lc-sys 0.40.0)
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>
2026-04-16 19:18:10 -04:00
Bryan Helmkamp
1c9ebba945
chore: delete stale apps/fabro-web/Dockerfile
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>
2026-04-16 19:15:21 -04:00
Bryan Helmkamp
f3bf40ac83
deps: delete stale apps/fabro-web/package-lock.json
The project uses bun (bun.lock); the npm lockfile was vestigial and the
source of 7 Dependabot alerts (vite, lodash, path-to-regexp, picomatch).
2026-04-16 19:14:14 -04:00
Bryan Helmkamp
def772ae6f
deps: bump rustls-webpki 0.103.9 → 0.103.12
Resolves Dependabot alerts #7, #17, #18 (name constraint handling).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 19:13:32 -04:00
Bryan Helmkamp
1048534e2c
ci: switch clippy to pinned nightly, clean up workspace lints
- 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>
2026-04-16 18:59:11 -04:00
Bryan Helmkamp
eb596c057d
clippy 2026-04-16 18:20:37 -04:00
Bryan Helmkamp
6e670e8b54
fix: unblock clippy and nextest on main
- 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>
2026-04-16 18:16:06 -04:00
Bryan Helmkamp
329fe4cd4b
ci: gate releases on fresh fabro-spa assets
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>
2026-04-16 18:02:42 -04:00
Bryan Helmkamp
44e7cbcaa7
Update SPA 2026-04-16 17:35:37 -04:00
Bryan Helmkamp
1dd59ceea5
wip 2026-04-16 13:13:09 -04:00
Bryan Helmkamp
74578c22bc
feat(web): add empty state to runs page and fix logo link
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>
2026-04-16 08:02:18 -04:00
Bryan Helmkamp
5570ff3bc0
docs: update changelog and docs for Apr 14–16 changes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 08:01:59 -04:00
Bryan Helmkamp
77c8ac8ed3
feat(cli): add server restart command
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>
2026-04-16 07:49:16 -04:00
Bryan Helmkamp
c24b78d18d
plans 2026-04-16 07:43:01 -04:00
Bryan Helmkamp
67baf8b4d8
feat(cli): add --watch-web flag to server start (debug builds only)
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>
2026-04-16 07:42:54 -04:00
Bryan Helmkamp
a79f9ae43f
fix(install): use consistent web URL for GitHub App callback and generated settings
--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>
2026-04-16 07:29:48 -04:00
Bryan Helmkamp
2d6742d416
feat(cli): show Web UI URL and auth methods in server start output
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>
2026-04-16 07:21:55 -04:00
Bryan Helmkamp
1830724fa4
fix(cli): improve device code login readability with blank line spacing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 07:20:57 -04:00
Bryan Helmkamp
c8be2068f6
fix(web): show both GitHub and dev-token login when both auth methods enabled
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>
2026-04-16 07:20:45 -04:00
Bryan Helmkamp
b6c643b0ca
gitignore 2026-04-15 15:00:32 -04:00
Bryan Helmkamp
1b7c449262
fix(web): strip leading markdown heading markers from run goal
Some checks are pending
Rust / Format (push) Waiting to run
Rust / Clippy (push) Waiting to run
Rust / Test (Linux) (push) Waiting to run
Rust / Test (macOS) (push) Waiting to run
TypeScript / Typecheck (push) Waiting to run
TypeScript / Test (push) Waiting to run
TypeScript / Build (push) Waiting to run
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 12:04:50 -04:00
Bryan Helmkamp
5c03fb2e41
fix(web): truncate run goal to first line, max 100 chars with ellipsis
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 12:04:14 -04:00
Bryan Helmkamp
e4f2208255
fix(tests): stabilize graph path snapshots and skip LLM preflight for non-LLM graphs
- 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>
2026-04-15 11:41:17 -04:00
Bryan Helmkamp
79fee95c97
fix(ci): stabilize snapshot test and double CLI test timeout
- 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>
2026-04-15 11:39:06 -04:00
Bryan Helmkamp
af408dc66c
fix(tests): make bulk_skip model test independent of local credentials
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>
2026-04-15 11:22:02 -04:00