Commit graph

468 commits

Author SHA1 Message Date
Bryan Helmkamp
54ddaa2cee
feat(install): redesign web wizard and scope dev token to PAT installs
Redesign the install wizard for clarity:
- swap the sidebar layout for a centered column and a horizontal stepper
- make completed/current stepper entries clickable links
- reorder steps so Server URL precedes LLMs
- use env-var placeholders (ANTHROPIC_API_KEY, etc.) with
  per-provider "Where do I get this?" disclosures
- replace the readonly "Validated username" input with a success pill
- drop the GitHub App name field (GitHub confirms the name anyway)
- re-label the GitHub App option and split review rows by strategy
- add a copy action to the Server URL on the review screen

Scope the dev token to PAT installs:
- only generate the dev token, write its files, and set FABRO_DEV_TOKEN
  inside the GithubInstallState::Token arm
- mark dev_token optional on InstallFinishResponse in the OpenAPI spec
- hide the Development token card on /install/finishing when absent
- add app_install_finish_omits_dev_token_and_does_not_write_it test

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:11:02 -04:00
Bryan Helmkamp
b849738a5b
plans 2026-04-19 15:18:25 -04:00
Bryan Helmkamp
5958470a11
plan 2026-04-19 15:18:22 -04:00
Bryan Helmkamp
a1c816724b
plans 2026-04-19 15:18:21 -04:00
Bryan Helmkamp
2505cb6d46
Merge remote-tracking branch 'origin/main' into feat/web-install-wizard
# Conflicts:
#	lib/crates/fabro-spa/assets/assets/entry-ez8gc920.js
#	lib/crates/fabro-spa/assets/index.html
#	lib/packages/fabro-api-client/src/.openapi-generator/FILES
#	lib/packages/fabro-api-client/src/models/index.ts
2026-04-19 15:06:12 -04:00
Bryan Helmkamp
b8af65a9c6
refactor(runs): blocked status canonicalization cleanup (#165)
## Summary

Stacked cleanup of the `canonicalize blocked run status` work (local
commit `d13cdf374`) plus reconciliation with origin's `canonicalize
paginated run list responses` (origin commit `8ab689da7`). Both efforts
ran in parallel and diverged on the column name (`blocked` vs `waiting`)
and on how the board response is shaped — this PR converges them,
keeping `blocked` as the canonical column id while adopting origin's
`column` field on `RunListItem` and `StoreRunSummary` shape.

Also fixes a production-worker regression introduced by the
canonicalization: the worker's start-precondition only accepted
`Submitted | Starting`, so once runs started transitioning through
`Queued` on the way to `Starting`, every subprocess-worker run failed
with `Precondition failed: cannot start run: status is Queued`. That
cascaded into ~90 failing CLI/server integration tests locally.

## Commits

1. `f65843168` refactor(runs): simplify blocked status follow-ups
2. `1492d956c` chore: resolve clippy warnings
3. `676fd9f44` first merge of origin/main
4. `23fc92a2f` **fix(runs): allow Queued status in start precondition**
← the cascade-fix
5. `36b507a83` refactor: simplify pause/unpause + dedupe web status
tables
6. `8d8d27748` refactor(workflow): encapsulate BlockedStateTracker
inside HumanHandler
7. `1c17fda35` second merge of origin/main — resolves waiting vs blocked
8. `4cd3ef7b1` refactor(workflow): Mutex<usize> → AtomicUsize
9. `2e5a58e8a` fix(demo): align run-4 lifecycle status with Blocked
board column

## Test plan

- [x] fmt, clippy, build, doctests all clean
- [x] `cargo nextest run --workspace` — **4092/4092 pass**
- [x] `bun test` — **26/26 pass**, typecheck + production build clean
- [x] Manual CLI repro of the Queued-precondition fix
- [x] Browser smoke test: all 5 columns render with correct
labels/colors, demo run-4 appears in Blocked lane with question text
intact

## Known follow-up (not blocking)

A "paused-while-blocked" run (status `Paused` + `blocked_reason: Some`)
lands in the `running` column because the visible status chooses
`Paused` over `Blocked`. The pending question is not prominent on the
board. Addressing it would require `board_column()` to branch on
`(status, blocked_reason)` rather than just `status` — worth a separate
ticket.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:53:46 -04:00
Bryan Helmkamp
acb6b3f9d6
refactor(install): tag GithubAppOwner with discriminated object shape
The install GitHub App manifest shape encoded owner as `"personal"` or
`"org:<slug>"` - a magic string parsed in install-app.tsx, built by
install-api.ts, and reparsed server-side. Replace with a tagged object
`{ kind: "personal" } | { kind: "org", slug }` in the OpenAPI spec, the
progenitor-generated Rust types, and the frontend.

Server-side, the internal `GitHubAppOwner` enum keeps its semantic
shape but gains a `TryFrom<GithubAppOwnerInput>` conversion and emits
the tagged JSON via `as_session_value`.

Frontend drops `buildGithubOwnerValue` in favor of
`buildInstallGithubAppOwner`, and the ready-screen renders the owner
through a small helper instead of string concatenation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:48:31 -04:00
Bryan Helmkamp
dd4e467bfc
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-server/tests/it/api/mod.rs
2026-04-19 13:36:54 -04:00
Bryan Helmkamp
e8d0f75be9
Merge remote-tracking branch 'origin/main' 2026-04-19 12:46:19 -04:00
Bryan Helmkamp
9dd792c8b8
fix(install): exclude openai-compatible from v1 setup
Restrict the browser install flow to Anthropic, OpenAI, and Gemini,
remove the unused install-time base URL surface, and reject
openai_compatible with a stable 422 response.

Also fix the finishing health poller so it only redirects after the
server comes back healthy outside install mode instead of jumping early
on transient restart failures.
2026-04-19 11:43:38 -04:00
Bryan Helmkamp
ecdfdd82d8
feat(install): add browser-based setup flow
Implement the web-first install experience across the server, CLI, API spec,
web app, and packaged SPA assets.

This also removes test-side process env mutation by pushing env-dependent
decision points behind explicit helpers and test wiring.
2026-04-19 11:20:58 -04:00
Bryan Helmkamp
6226858648
fix(runs): finish canonical run summary rollout
Complete the /runs and /boards/runs canonicalization work by fixing the
run-detail response shape, preserving lifecycle status separately from board
columns, loading all board pages in the web client, and aligning the shared
status_reason typing.
2026-04-19 11:12:58 -04:00
Bryan Helmkamp
21240e2d09
fix(server): address TLS removal review follow-ups 2026-04-19 10:48:42 -04:00
Bryan Helmkamp
914778c8a8
refactor(server): remove inbound TLS termination
Remove server-side TLS listener support so Fabro only binds plain TCP
or Unix sockets, and update docs/tests around proxy-terminated HTTPS.
This also drops the removed [server.listen.tls] config shape and the
inbound TLS-specific diagnostics, fixtures, and integration coverage.
2026-04-19 10:43:57 -04:00
Bryan Helmkamp
8ab689da78
feat(runs): canonicalize paginated run list responses
Unify /api/v1/runs and /api/v1/boards/runs around a shared
paginated summary contract with additive convenience fields.

Update the server, demo data, generated clients, CLI pagination,
and web consumers so board views become a thin projection over the
canonical run summary surface.
2026-04-19 10:37:31 -04:00
Bryan Helmkamp
224673bdf6
docs(install): address sixth review pass on web-install spec
Two fixes:

P0 — Container packaging blocks install mode. The published Dockerfile
bakes /etc/fabro/settings.toml and sets FABRO_CONFIG, which under the
explicit-config carveout means containers would never enter install
mode. v1 must change the Dockerfile: drop the baked settings file,
drop FABRO_CONFIG, set FABRO_STORAGE_DIR=/storage, and persist
~/.fabro across container restarts (recommendation: move FABRO_HOME
into a subdirectory of the /storage volume so one mount covers both
config and data). Spelled out as load-bearing v1 implementation work
under Orchestration config updates. New decision-log row #24.

P2 — Force-foreground decision was not carried through to all sections.
Two leftover references to a `__serve` daemon child contradicted the
"install mode never daemonizes" decision — one in the local-lifecycle
prose, one in the manual smoke test. Updated both to describe the
foreground process exiting cleanly. Decision-log row for #21 also
updated to reflect that the install process IS the operator's `fabro
server start` invocation under foreground mode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
d34f338e33
docs(install): address fifth review pass on web-install spec
Two fixes:

P1 — Install token surfacing in local daemon mode. Today's
`fabro server start` daemonizes by default; the daemon parent prints
its own summary but the child's stderr (where the install token would
print) is redirected to server.log. Operator wouldn't see the token
without tail-ing the log file. Decision: install mode forces foreground
regardless of how `fabro server start` was invoked; the token then
lands on the operator's terminal directly. Documented as "--foreground
is implicit during install." Daemon path is bypassed entirely for
install mode; restored on the supervisor restart.

P2 — `--no-web` contract hole. The flag is accepted by `server start`
and `server restart` but the spec didn't say what install mode does
with it. Decision: ignore during install with an explicit stderr
warning ("will be respected on next start"); respected after the
supervisor restart. Rejecting would force supervised-deployment
operators to either drop the flag or `docker exec` to run the CLI
wizard, defeating the point. Warning makes the override visible.

Added integration tests for both behaviors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
d21d9fa62f
docs(install): address fourth review pass on web-install spec
Three more fixes (all P2):

P2 — Goal wording said "using the same persistence helpers" but the
body explicitly carves out a separate install-mode vault path. Reword
to "same on-disk state, sharing the TOML/env primitives" so the
implementer isn't misled about how much of the CLI path is reused.

P2 — Summary said only `fabro server start` enters install mode but
the process model says start and restart. Reconcile: name both
commands explicitly in the summary.

P2 — Test plan covered the GitHub App `state` rejection path but not
the happy-path roundtrip (POST /install/github/app/manifest → GET
/install/github/app/redirect with stubbed conversion). Add an
integration test that covers the riskiest new path: code-exchange
wiring, session population, redirect-with-token handling, and that
the canonical-URL ordering decision actually flows through to the
manifest.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
0a576a5f74
docs(install): address third review pass on web-install spec
Three more fixes:

P0 — Local restart UX. Today's `fabro server start` does not stay
around to supervise the `__serve` child it spawns (`start.rs:318`), so
no auto-restart happens locally after `/install/finish` exits. Spec the
two cases honestly: supervised deployments rely on the supervisor;
local laptops show the operator a "run `fabro server start` to launch
your configured server" message after a 30s polling timeout. A built-in
local supervisor is named as a follow-up. Updated the manual-test
section to cover both cases and the orchestration-docs section to
detect supervised vs. local at boot time.

P1 — Auto-start callers must not enter install mode. `connect_server`
→ `connect_api_client_bundle` → `start::ensure_server_running_for_storage`
is used by `run attach`, `server runs`, etc. Add an explicit *Auto-start
callers* subsection and a new decision: only the explicit `fabro server
start` (or `restart`) command enters install mode. Auto-start callers
fail with a clear "configure first" message pointing the operator at
either `fabro server start` or `fabro install`.

P2 — Process-model rationale corrected. The previous draft claimed the
existing dispatch path "would error on missing settings.toml" but that
is false: `user.rs:77` returns defaults, `serve.rs:820-824` falls back
to a Unix socket, and `tests/it/cmd/server_start.rs:111` is a passing
test of `fabro server start` with no config. Reworded to say what is
actually true — without the fork, `fabro server start` cheerfully boots
a non-functional default server, and install mode displaces that
default. Summary line now mentions the explicit-config caveat too.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
d70bc7a166
docs(install): address second review pass on web-install spec
Five more fixes:

P0 — Reorder wizard: Server config now precedes GitHub. The GitHub
manifest bakes <canonical_url> into redirect_url and callback_urls;
creating the App with a misdetected URL is a real-world side effect we
cannot unmake on github.com.

P0 — `persist_install_outputs` cannot be reused as-is from install
mode. Its vault path goes through `connect_api_client(storage_dir)`,
which calls back into the install-mode server itself (which doesn't
mount /api/v1/*) and would 404. Add an explicit decision: install mode
writes vault secrets directly to disk via Vault::load(...).set(...),
the same pattern persist_github_install_changes already uses. TOML and
env-file helpers remain reusable.

P1 — Bootstrap fork narrowed. Install mode triggers only when no
explicit --config or FABRO_CONFIG was provided AND the default
~/.fabro/settings.toml is absent. A typo in --config must error, not
silently install on top of the wrong target. Matches the asymmetry the
existing config loader already enforces (user.rs:81-112).

P1 — Stop overpromising rollback. The existing helper restores
settings.toml on vault failure but leaves server.env in place (verified
by install.rs:2910). Spec out the actual partial-state semantics for
v1, justify why it's acceptable (env keys are deterministic and
idempotent on retry), and call atomic rollback a deliberate follow-up.

P2 — On-disk layout corrected. Vault path is
<storage_dir>/vaults/default/secrets.json (storage.rs:38), not
<storage_dir>/secrets/.... Added the home-level dev-token file the CLI
also writes (install.rs:1994-1999) so parity is real.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
7b9c652548
docs(install): address plan review on web-install spec
Five fixes against the v1 spec:

P0 — Reconcile GitHub App callback flow with the CLI's actual
mechanism: manifest `redirect_url` (not `callback_urls`) carries the
post-creation handoff via browser 302; the install endpoint is renamed
to `/install/github/app/redirect` and authorized by OAuth `state`
because GitHub strips Authorization across redirects.

P1 — Bootstrap fork moves from "precheck inside serve" to the dispatch
layer, since today's `commands::server::dispatch` loads settings before
`serve` is invoked. Spec out the install bootstrap path explicitly,
including skipping the eager dev-token / session-secret creation.

P1 — Clarify that the same `fabro-web` bundle hosts the wizard via a
server-injected `window.__FABRO_MODE__` flag in `index.html` controlling
which router tree mounts at boot. Without this, existing route loaders
that call `/api/v1/auth/*` would throw before the install UI renders.

P2 — Correct the dev-token path to `<storage_dir>/server.dev-token`
(matching `Storage::server_state().dev_token_path()`).

P2 — Resolve the dev-token "never exposed to the client" contradiction:
JWT keys and session secret stay on the server; the dev token is
returned in the `/install/finish` response so the operator can copy it.

P2 — Note that the existing OpenAPI conformance test only covers
`build_router(...)` and would silently miss install drift. Spec the
expansion: split spec iteration by `install` tag, route to the
appropriate router, and verify cross-mounting is rejected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
5520785723
docs(install): spec the web-based install wizard
Captures the design for browser-driven first-run configuration as an
alternative to `fabro install`. When `fabro server` boots without
`~/.fabro/settings.toml`, it enters install mode, prints a one-time
token, and serves a wizard from the existing `fabro-web` bundle.
Reaches the same on-disk end state as the CLI, then exits cleanly so
the supervisor restarts into normal mode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
8f48aa8b64
docs(digital-ocean): replace stub with Droplet + compose guide
App Platform has no persistent volumes, so Fabro's /storage directory
rules it out. Documents the Droplet path instead, using the existing
docker-compose.prod.yaml + Caddy setup for automatic TLS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:20:01 -04:00
Bryan Helmkamp
484a3dbc39
feat(fly): add fly.toml and full deploy guide
fly.toml points Fly directly at ghcr.io/fabro-sh/fabro:nightly (no
builder step), pins internal_port to 32276 since Fly does not inject
$PORT, declares a Volume mount at /storage, and disables autostop so
the run queue stays live under no HTTP traffic.

Replaces the deploy-fly-io.mdx stub with a CLI-first walkthrough
covering volume creation, secrets, dev token retrieval, and the
single-Machine / single-Volume caveats that apply to Fabro.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:15:13 -04:00
Bryan Helmkamp
36e51237d4
docs(render): replace stub with full deploy guide
Documents the render.yaml blueprint flow end-to-end: one-click deploy,
disk verification, env vars, dev token retrieval, and the same
single-replica / amd64-only caveats as the Railway guide.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:08:18 -04:00
Bryan Helmkamp
8da81fdf9e
fix(release): build musl targets via cargo-zigbuild to fix arm64 SIGSEGV
The shipped aarch64-unknown-linux-musl binary segfaulted at startup on
every arm64 runtime (Apple Silicon, Graviton, Ampere, Docker arm64).
Root cause: a glibc-vs-musl .init_array calling-convention mismatch --
a C static library in the dep graph has an __attribute__((constructor))
that expects (argc, argv, envp) per glibc, but musl on aarch64 calls
it with no args, so register garbage propagates into pointer arithmetic
and faults before main runs.

Switch the musl compile steps to cargo-zigbuild (zig 0.13.0). Zig's
bundled cc + lld produce working static-PIE binaries for both musl
targets, sidestepping Ubuntu musl-tools' -no-pie quirk and the
init_array ordering that triggered the crash. Drop the CARGO_TARGET_*
linker overrides and the musl-tools apt install -- zig handles both.

bin/dev/docker-build.sh mirrors the same toolchain so the local Docker
image build matches CI.

Verified by running fabro version from the resulting arm64 image on
ghcr.io/fabro-sh/dhi-alpine-base:3.23-dev, alpine:3.22, and
debian:stable-slim -- all print the version banner with exit 0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:01:45 -04:00
Bryan Helmkamp
8e4693ad8c
chore(docker): switch base to DHI Alpine, add cross-arch build support
Runtime image now builds FROM ghcr.io/fabro-sh/dhi-alpine-base (Docker
Hardened Images mirror, Alpine 3.23) instead of alpine:3.22. Same
runtime shape, CVE-minimized base. Changelog updated to reflect the
DHI migration.

bin/dev/docker-build.sh grows --arch {amd64,arm64} and --compile-only
flags so local multi-arch verification works regardless of host arch.
Cargo target cache is now per-arch to prevent arm64/amd64 artifacts
from stomping each other in one shared volume.
2026-04-18 15:42:23 -04:00
Bryan Helmkamp
184cddf8e0
feat(railway): deploy from prebuilt GHCR image instead of source build
Add Dockerfile.deploy as a thin wrapper that pulls
ghcr.io/fabro-sh/fabro:nightly, and point railway.toml at it. Railway
now skips Rust compilation entirely and deploys in seconds. The
upstream image already configures entrypoint, $PORT-aware CMD, volumes,
and the unprivileged fabro user, so nothing else is needed in the
wrapper.

Update docs/administration/deploy-railway.mdx to reflect the new flow
and call out that amd64 is the supported architecture (arm64 variant
of the image is being handled separately).

Verified locally: `docker build -f Dockerfile.deploy .` succeeds,
`fabro version` prints the expected banner, and PORT override + health
check work.
2026-04-18 15:24:22 -04:00
Bryan Helmkamp
b5e17ba082
ci(release): attest SLSA build provenance for binaries and image
Tarballs in each compile matrix and the multi-arch ghcr image now get
Sigstore-signed provenance attestations via GitHub's attest-build-provenance
action. Users can verify with `gh attestation verify` — covered in a new
docs/reference/verifying-releases.mdx.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 15:05:32 -04:00
Bryan Helmkamp
6c57e17bb3
docs: add Homebrew as a first-class install method
Add Homebrew tab to the Quick Start install tabs and simplify the
agent-driven install.md to detect Homebrew and fall back to the install
script, dropping the gh/tar manual path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:37:15 -04:00
Bryan Helmkamp
dae8b635fc
plans 2026-04-18 12:36:41 -04:00
Bryan Helmkamp
bc3dcf3505
plan 2026-04-18 10:51:43 -04:00
Bryan Helmkamp
b0349e9873
feat(cli): surface debug build profile in version output
Non-release builds now append the profile to `fabro --version`
(`x.y (sha date debug)`), `fabro version`, and `fabro system info`,
so users can tell a local build apart from a shipped release. The
API's `SystemInfoResponse` gains a `profile` field so the client
can render the server's build profile too.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 09:44:54 -04:00
Bryan Helmkamp
0d9f71d1cb
docs: add Apr 17–18 changelog entries and refresh CLI + Railway docs
Document bare `fabro` landing output in the CLI reference and remove
the now-obsolete multi-arch image caveat from the Railway deploy guide.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 09:44:54 -04:00
Bryan Helmkamp
eb3c6d5ce3
fix(docs): update billing endpoint reference in navigation
The billing refactor (6ca2833e7) renamed /api/v1/runs/{id}/usage to
/api/v1/runs/{id}/billing in the OpenAPI spec but left the stale path
in docs.json, which broke Mintlify deploys with "Failed to fetch
OpenAPI file for anchor or tab".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 01:35:59 -04:00
Bryan Helmkamp
2f2f14562d
fix(api): convert OpenAPI spec to valid 3.1 syntax
The spec declared openapi 3.1.0 but used nullable: true (3.0 idiom)
in 78 places, which Mintlify's parser rejected, breaking doc deploys.

Convert to proper 3.1 patterns (type arrays and oneOf with type: null),
switch the server conformance test from openapiv3 (3.0-only) to a
YAML-level walk so it accepts 3.1 input, and regenerate the typescript
client — it now correctly emits `| null` on nullable fields.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 01:11:19 -04:00
Bryan Helmkamp
5335f8bcb4
feat(deploy): add Railway deploy path, honor $PORT in container
Teach the Dockerfile CMD to bind 0.0.0.0:${PORT:-32276} so PaaS providers
(Railway, Fly, Render, Cloud Run) route traffic without manual port
configuration. Default 32276 preserves local docker / docker-compose
behavior.

Ship railway.toml pointing Railway at the Dockerfile with on_failure
restarts. Replace the "coming soon" stub in docs/administration/deploy-
railway.mdx with a real guide: deploy button, Volume-at-/storage setup,
env vars, dev-token retrieval, and CLI pointing. Surface the Railway
deploy button in README.md under a new "Self-host the Fabro server"
section that also links to the other deploy guides.

Locally verified: PORT env override binds the chosen port, default
falls back to 32276, and tini signal propagation still gives clean
docker stop. End-to-end Railway verification still needs a live click-
through before the template URL is finalized.
2026-04-18 00:44:15 -04:00
Bryan Helmkamp
e891cb3961
test(cli): cover Homebrew upgrade behavior end to end
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
Add process-level upgrade tests that invoke the real fabro binary from a
fake Homebrew Cellar path so current_exe() detection is exercised end to
end. Update the CLI reference and changelog to document the Homebrew-managed
upgrade path and the flags that remain self-managed-only.
2026-04-17 18:28:54 -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
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
c24b78d18d
plans 2026-04-16 07:43:01 -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
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
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
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
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
05c7fedd31 refactor(server): remove implicit dry-run fallback
Remove the server startup path that inferred dry-run from provider
availability and let run.execution.mode inherit normally from
settings.

Model tests now return skip for unconfigured providers at request
time, completions use the real error path, and the CLI/docs/tests are
updated for the removed server --dry-run flag.
2026-04-14 12:28:55 -04:00
Bryan Helmkamp
829f2ae1d2 Merge remote-tracking branch 'origin/main' 2026-04-13 23:54:13 -04:00
Bryan Helmkamp
d22be78575 fix(server): honor server.listen when bind is omitted 2026-04-13 23:54:08 -04:00
Bryan Helmkamp
b3ae342a55 Merge branch 'vendor-graphviz-sys' 2026-04-13 23:42:45 -04:00