Commit graph

1039 commits

Author SHA1 Message Date
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
Bryan Helmkamp
2106aba53b
fix(tests): isolate CLI integration tests from repo project config
Config discovery walks from the workflow file's parent directory, so
tests using fixtures at their repo path (test/simple.fabro) would find
the repo's .fabro/project.toml. This caused settings like preserve=true
to leak into tests and break sandbox cleanup event assertions.

Add TestContext::install_fixture() which copies fixtures into the test's
temp dir. Update all CLI run/attach/start tests to use it. Remove the
now-unused example_fixture() function.

Restore preserve=true in .fabro/project.toml — tests are now isolated.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:18:19 -04:00
Bryan Helmkamp
5fa6b6e7a8
fix: resolve test failures and clippy warnings across workspace
- Remove EnvGuard and env-mutating test from fabro-auth (shared mutable state)
- Revert project.toml preserve=true that broke sandbox cleanup event tests
- Fix clippy: use is_some_and, scoped imports for StageStatus and render
- Update snapshot tests for new Run: ULID line and model_test output
- Fix preflight test assertion (name said "allows", asserted failure)
- Update cancel_queued_run test: cancelled runs now appear on board
- Add graph direction query param support to get_graph endpoint

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:02:20 -04:00
Bryan Helmkamp
de78094d7e
fix: include duration_ms in stage.failed events for sidebar display
StageFailedProps lacked duration_ms, so extract_stage_durations_from_events
only found durations from stage.completed events. Failed stages showed "0s"
in the sidebar despite the command.completed event having the real duration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:42:58 -04:00
Bryan Helmkamp
3a97c1fdd9
server 2026-04-15 10:15:33 -04:00
Bryan Helmkamp
130d76729c
fix(server): show running stage immediately via checkpoint next_node_id
The stages API used checkpoint.current_node to identify the running
stage, but current_node is the last *completed* node — always already
in completed_nodes, so the running-stage check was always false.
Switch to checkpoint.next_node_id which correctly identifies the
currently-executing stage.

Also move SSE subscription from run-detail parent layout into the
StageSidebar component with since_seq=1 to replay all events and
close the race between loader fetch and SSE connection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:03:26 -04:00
Bryan Helmkamp
75ab9965dd
feat(web): wire up non-demo run detail pages to real data
- Fix run detail status: display actual API status (submitted, running,
  succeeded, failed, etc.) instead of always showing "Working"
- Implement /runs/{id}/stages endpoint in non-demo mode, reading from
  checkpoint + events to build stage list with statuses and durations
- Fix /runs/{id}/graph to fall through to durable store when run is not
  in the live map
- Render real workflow graph SVG on overview and graph pages instead of
  hardcoded demo graph; remove unused DotDiagram component from overview
- Add dark mode CSS overrides for server-rendered SVG graphs
- Wire stage detail page to real event data: fetch from /events, filter
  by node_id, and render as system/assistant/tool blocks
- Fix stage page 500: use apiJsonOrNull for unimplemented /turns endpoint
- Filter start/exit graph control nodes from stage lists in the UI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:42:49 -04:00
Bryan Helmkamp
80cb51300b
fix(web): update demo data to use BoardColumn::Initializing
Missed in the pending → initializing rename.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:26:50 -04:00
Bryan Helmkamp
a90038f7a7
refactor(web): rename board column pending → initializing
Clarifies that Submitted/Starting runs are initializing, not just
pending. Also refactors run-detail to display the actual run status
via runStatusDisplay instead of mapping to board columns.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:22:17 -04:00
Bryan Helmkamp
e79baeab8e
fix(cli): align Run ID with other run header lines
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:20:07 -04:00
Bryan Helmkamp
abfdb9e523
fix(cli): restore Run ID in fabro run output header
Lost during the execute.rs → create.rs refactor in db3231e9.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:16:38 -04:00
Bryan Helmkamp
054dc5a85a
fix(model): use Self instead of Provider in method signature (clippy)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:14:21 -04:00
Bryan Helmkamp
6d4b26579b
fix(sandbox): wire vault DAYTONA_API_KEY through to Daytona SDK client
The Daytona SDK client was created via Client::new() which only reads
DAYTONA_API_KEY from process env vars. When the key is stored in the
fabro vault (via `fabro secret set`), it was never forwarded to the SDK,
causing "api_key or jwt_token must be provided" errors.

Thread the API key from the vault through SandboxSpec, DaytonaSandbox,
and reconnect paths so the SDK receives it via new_with_config().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:13:55 -04:00
Bryan Helmkamp
84f3c80566
refactor(api): move features flags from /auth/me to /system/info
Features like session_sandboxes and retros are server-level capability
flags, not user settings. Expose them on GET /system/info where they
belong alongside other server metadata.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 08:51:22 -04:00
Bryan Helmkamp
a12ceb0ad0
fix(web): board runs endpoint reads from store, not in-memory state
The /boards/runs endpoint was driven by the in-memory state.runs map,
which is empty after server restart. Now reads from SlateDB store so
runs persist across restarts.

Also makes board columns dynamic from the API response instead of
hardcoded in the frontend. Real mode returns: pending, running, waiting,
succeeded, failed. Demo mode returns: working, pending, review, merge.

Board layout changed from fixed 3-column grid to horizontal scroll.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 08:36:55 -04:00
Bryan Helmkamp
57e0385c98
fix(workflow): use configured providers for default models
Derive configured providers from env and vault when choosing default
models during run creation and materialization, and thread the resolved
run provider through execution handlers instead of recomputing it.

Also return a user-facing error when fabro-agent cannot infer a default
model for the selected provider.
2026-04-15 08:19:04 -04:00
Bryan Helmkamp
a147fecc00
feat(slatedb): add disk_cache setting for S3-backed deployments
When `disk_cache = true` in `[server.slatedb]`, Fabro enables SlateDB's
object-store cache at `<storage_root>/cache/slatedb`, caching raw S3
bytes on local disk to reduce read latency. All cache parameters use
SlateDB defaults (16 GB max, 4 MB parts). A warning is emitted if
enabled with `provider = "local"` since the cache adds overhead when
the object store is already on the local filesystem.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 08:02:46 -04:00
Bryan Helmkamp
549d85aaa7
fix(web): board layout, column config, and 501 error handling
- Forward route handle to React Router so wide:true works on /runs
- Switch board view to CSS grid for full-width columns
- Remove Verify column, rename Merge to Complete
- Use apiJsonOrNull in workflows/workflow-detail loaders to handle 501

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 07:48:50 -04:00
Bryan Helmkamp
d42d175408
feat(secret): accept secret value via stdin or interactive prompt
`fabro secret set` now supports three ways to provide the value: as a
positional arg (existing), piped via --value-stdin, or interactively
when stdin is a TTY (obscured with dialoguer::Password). Diagnostics
remediation messages drop the <value> placeholder to encourage
interactive input.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 07:34:33 -04:00
Bryan Helmkamp
696427d10d
fix(doctor): simplify LLM provider detail lines
Drop redundant "connectivity" word from doctor check output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 07:31:15 -04:00
Bryan Helmkamp
66f7f8d6b3
refactor(store): introduce SlateKey type with null-byte separator
Replace stringly-typed key construction with a SlateKey builder that
encapsulates the segment separator. Switches from '#' to '\0' so the
separator cannot collide with key segment values.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 07:04:16 -04:00
Bryan Helmkamp
ad192fcbed
feat(install): show auth method and dev token in install output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 07:02:08 -04:00
Bryan Helmkamp
d6b4161bfd
feat(doctor): show server location URL in doctor output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 06:57:17 -04:00
Bryan Helmkamp
95ad4b1cfe
fix(web): redirect to /runs instead of /start after login
All three login paths (root redirect, dev token, GitHub OAuth callback)
now send users to /runs on first visit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 06:57:07 -04:00
Bryan Helmkamp
378073c13a
fix(tests): satisfy clippy in system api test 2026-04-14 23:36:05 -04:00
Bryan Helmkamp
f84be383ee
fmt 2026-04-14 23:23:22 -04:00
Bryan Helmkamp
4217d67659
feat(install): add github-only reconfiguration command
Add `fabro install github` for reconfiguring GitHub auth on an
existing install without rerunning full setup.

Ensure app/token switches replace stale settings and secrets, and
cover the new flow with CLI and integration tests.
2026-04-14 23:23:06 -04:00
Bryan Helmkamp
62a9d9438d
fix(install): restart the server after install
Restart the local server at the end of fabro install so new config and
server.env values take effect immediately. Skip fabro doctor when the
restart fails, and keep targeted unit coverage around the restart and
secret-persistence lifecycle.
2026-04-14 21:45:49 -04:00
Bryan Helmkamp
bdbfcd9d81
refactor(server): simplify AppState construction
Replace the internal positional AppState builder with an AppStateConfig
and route both production and test setup through the new config-backed
path. Preserve the in-process test helper behavior while fixing the
ignored max_concurrent_runs argument with a regression test.
2026-04-14 21:35:55 -04:00
Bryan Helmkamp
bf9f4f9353
feat(cli): add ls alias for list subcommands
Adds `#[command(alias = "ls")]` to workflow, pr, and artifact list
subcommands for consistency with secret list which already had it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:19:18 -04:00
Bryan Helmkamp
3be7916fbc
fix(server): decouple server.env path from vault path in AppState construction
build_app_state_with_path derived the server.env path from the vault
path's parent directory, causing it to look in vaults/default/ instead
of the storage root. This made fabro doctor report missing GitHub App
credentials even though fabro install saved them correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:06:05 -04:00
Bryan Helmkamp
8f26a080cf
feat(store): enable Zstd compression for SlateDB
Reduces S3 storage cost and read latency for run data by compressing
SST blocks with Zstd. Existing uncompressed data remains readable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 20:09:30 -04:00
Bryan Helmkamp
d863b54ac0
fix(server): embed git SHA and build date in server binary
The server used option_env!() for FABRO_GIT_SHA and FABRO_BUILD_DATE,
but no build.rs set them — so `fabro version` always showed "unknown".
Add a build.rs to fabro-server (matching fabro-cli's) and remove the
Sandbox line from `fabro system info`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 20:08:45 -04:00
Bryan Helmkamp
a3320809ab
feat(install): prompt for GitHub token when gh CLI is unavailable
When the gh CLI is not installed or not authenticated, the install
wizard now shows "Personal Access Token" (without the gh reference)
and prompts the user to enter their token directly instead of failing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 19:32:05 -04:00
Bryan Helmkamp
1ab1327f96
fix(ci): stabilize graphviz Rust checks
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
Keep the render-graph CLI integration test explicitly documented for
synchronous stdio subprocess usage, and make the garbage-stdout server
test drain stdin before returning invalid output so the Linux test path
stays deterministic.
2026-04-14 19:31:01 -04:00
Bryan Helmkamp
3e9683b6a0 refactor(graphviz): extract graphviz-sys into fabro-sh/graphviz-sys
Move the vendored Graphviz FFI crate to its own repo so it can be
reused independently and reduce this repo's footprint (~250 C/H files).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 19:03:01 -04:00
Bryan Helmkamp
8c361afc51 Merge remote-tracking branch 'origin/main' 2026-04-14 18:38:49 -04:00
Bryan Helmkamp
27583aa13e fix(graphviz): satisfy clippy for subprocess renderer 2026-04-14 18:23:15 -04:00
Bryan Helmkamp
286eee7efa fix(graphviz): isolate rendering in a subprocess
Run Graphviz through an internal fabro subprocess so renderer failures no
longer share process fate with the server. Keep expected DOT parse failures
on the 400 path via an explicit stdout protocol, and treat child crashes or
protocol violations as 500s.
2026-04-14 18:15:23 -04:00
Bryan Helmkamp
fa73407b35 feat(cli): add fabro version command
Add a server-targeted `fabro version` command for checking client and
server build identity without reading local storage directly.

This also removes version data from `/health`, moves doctor parity checks
to diagnostics, and updates the API spec, docs, generated client, and
coverage for the new contract.
2026-04-14 16:30:53 -04:00
Bryan Helmkamp
d6ed6b3cda fix(ci): fix vendored Graphviz build on Linux
Three issues prevented the vendored Graphviz C source from working on
Linux:

1. Missing _GNU_SOURCE: with -std=c11, strdup is not declared on
   glibc. The compiler assumes it returns int, truncating the 64-bit
   return value on aarch64 and causing a SIGSEGV in gvplugin_install.

2. Circular static library dependency: common/emit.c references
   gvevent symbols from gvc, but gvc depends on common. The Linux
   single-pass linker cannot resolve this cycle. Fixed by merging all
   archives into one combined archive using GNU ar's MRI script mode.

3. HAVE_MEMRCHR: with _GNU_SOURCE, glibc declares memrchr, which
   conflicts with Graphviz's own static definition. Fixed by defining
   HAVE_MEMRCHR on Linux to use the glibc declaration instead.

Also fixes: clippy borrow_as_ptr warning, disallowed_methods in
build.rs, and resolves a pre-existing merge conflict in serve.rs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:56:07 -04:00
Bryan Helmkamp
bf5da76678 Merge remote-tracking branch 'origin/main' 2026-04-14 15:45:01 -04:00
Bryan Helmkamp
ce26f66846 feat(release): support prerelease builds
Add prerelease-aware release automation and keep default install and upgrade
paths pinned to the latest stable tag unless an explicit prerelease version is
requested.
2026-04-14 15:43:00 -04:00
Bryan Helmkamp
09dc823e15 Fix clippy absolute_paths warnings in install command
Import fabro_util::path and use path::contract_tilde instead of
fully-qualified fabro_util::path::contract_tilde calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:37:06 -04:00
Bryan Helmkamp
be748a880d Show fabro secret set command in doctor remediation output
Doctor warnings for Sandbox and Brave Search now display the exact
command needed to configure the secret. Backtick-delimited text in
remediation strings renders in bold cyan, matching the conventional
CLI command styling used elsewhere.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:22:25 -04:00
Bryan Helmkamp
e366e4e761 Remove "Generating secrets and auth material..." status line
Secret generation is fast enough that the progress message is unnecessary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:16:49 -04:00
Bryan Helmkamp
2ba84be748 Improve install command output ordering and path display
Reorder output so file-write confirmations appear immediately after
secret generation, move "To start Fabro" call-to-action to the end,
collapse duplicate blank line, shorten home-dir paths with ~, and
style the `fabro server start` command with bold cyan.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:16:21 -04:00
Bryan Helmkamp
4f521b96a6 Run doctor in non-verbose mode after install
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:15:00 -04:00