Make BoardColumnDefinition.id reference the existing BoardColumn schema and carry that typed contract through generated TypeScript, server responses, demo data, and the runs board UI.
Submitted and Queued lifecycle statuses now live in a dedicated Queued
column rendered to the left of Initializing; Starting stays in
Initializing. The column is omitted from the board when it has no items
so day-to-day boards stay compact.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Routes the two reqwest clients in the Daytona credential probe through
fabro_http (system-proxy) in production and fabro_test::test_http_client
(no_proxy) in tests, by threading an http_client parameter through
check_daytona_api_key_with and build_api_keys_configuration. Bumps the
daytona-sdk-rust pin to 314ffd9, which exposes DaytonaConfig::http_client
and ships on reqwest 0.13.
Drops the three credential-probe unit tests from >1s SLOW to ~0.5s by
skipping macOS proxy discovery on the localhost httpmock requests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Use a lightweight basic probe target for preflight instead of fabricating catalog models, run configured model probes with bounded concurrency, and keep expensive model choices opt-in for defaults and live tests.
Use join_all to fan out provider probes instead of awaiting them
sequentially, and reuse fabro_util::error::collect_chain for the chain
rendering. Carry Provider through ProviderFailure instead of stringifying
it at construction.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`fabro_llm::Error`'s Display only renders the top-level message field for
`Network`/`Stream`/`Configuration`/`RequestTimeout` variants — the
`#[source]` chain is dropped. Walk the chain at the rendering boundary
so connectivity failures (DNS, connection refused, TLS) surface their
underlying cause in `fabro doctor` output.
Per docs/internal/error-handling-strategy.md, CLI surfaces should render
the full cause chain. Adds a regression test that walks `err.source()`
on a typed Network error with an inner io::Error.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`fabro doctor` now classifies LLM provider connectivity and auth probe
failures as `CheckStatus::Error` (so the command exits non-zero) and
surfaces the actual probe error text — truncated to one short line per
provider — instead of the generic "Connectivity issues with: <provider>".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Use BilledTokenCounts::default() for the non-LLM branch, hoist the
by-model stage count and hasLlmStages predicate out of JSX, and drop
the in-test for-loop in favor of iterator-based assertions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Include completed stages without LLM usage in run billing responses so command-only runs still show runtime rows. Keep token and model aggregates scoped to billed LLM usage, and render placeholder values in the web billing table.
Delegate to the existing AppState::canonical_origin helper instead of
re-resolving server.web.url and re-checking emptiness inline. The helper
already validates the URL via validate_public_url, so a misconfigured
non-http(s) origin no longer leaks through into run_web_url's output.
Also pass web_url into create_run_input directly rather than constructing
with None and immediately patching the field at the call site.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
So that CLI and other API consumers can surface a clickable link to the
run's web UI page instead of guessing route shapes or probing settings.
The server populates `web_url` from `server.web.enabled` and
`server.web.url`, returns it on `RunStatusResponse` (create plus all
lifecycle transitions), and persists it on the `run.created` event so
attach replays the same link without re-deriving it.
CLI: prints `Web UI: <url>` as a run-header info line, driven off the
replayed event so fresh runs and `attach` share one code path. Absent
when the UI is disabled.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Probe the Daytona API at install, `fabro secret set DAYTONA_API_KEY`,
and `fabro doctor` time to confirm the configured key carries the
snapshot/sandbox scopes Fabro needs. Operators now see a precise scope
error against the control plane instead of a generic sandbox-create
failure at first run.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tighten auth state to remove impossible identity branches and stringly error codes.
Route worker JWTs by header metadata, avoid unnecessary auth context cloning, and reuse shared helpers across tests and Slack payload handling.
Carry typed timeout actor metadata through failures instead of deriving it from display text.
Replace hand-built RequestAuthContext literals in github_webhook with the
existing ::invalid()/::authenticated() constructors, collapse the duplicate
demo/real principal layers into a single cloneable layer, and forward the
_with_anyhow error constructors to their _with_source twins to drop the
duplicated cause-collection bodies. refresh_credential_from_headers now
reuses jwt_auth::bearer_token_from_headers for Authorization parsing.
test_support shares one TEST_DEV_TOKEN-derived bearer header instead of a
hand-pasted literal. Replace for-loops in principal/cli_flow tests with
per-variant cases to honor the no-loops-in-tests rule.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extract run_artifact_entry_from / artifact_entry_from in fabro-server so
the two list-artifact handlers share a single conversion site. Push the
?retry=... query append into stage_artifacts_url in fabro-client so
upload callers don't repeat it. Replace required_filename and
required_retry with one generic required_query_param<T> helper.
(From impls were the cleaner shape but the orphan rule blocks them:
NodeArtifact lives in fabro-store, RunArtifactEntry in fabro-api,
neither is in fabro-server. Free fns achieve the same dedup without
adding a fabro-store -> fabro-api coupling.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Keep typed transport and provider errors intact through API, GitHub, OAuth, install, diagnostics, and artifact paths. Add regression coverage for cloned shared errors and communication error chains.
Reframe the deployment docs around the actual product story: Fabro
runs as a server, and the only deployment question is where that
server runs (laptop vs self-hosted Docker). Drop the Render, Fly.io,
and DigitalOcean guides and their config files; keep Railway as the
managed shortcut.
- New: administration/deployment.mdx (overview, two-mode framing)
- New: administration/self-host-docker.mdx (compose-first how-to)
- Move: administration/deploy-server.mdx -> reference/server-operations.mdx
(it was operational reference, not deploy guidance)
- Delete: deploy-render.mdx, deploy-fly-io.mdx, deploy-digital-ocean.mdx
- Delete: render.yaml, fly.toml, railway.toml, Dockerfile.deploy
- docker-compose.yaml: load .env if present so users can drive the
stack from a single env file end-to-end
- Update internal links and the docs-test that pinned the old path
Represent command termination explicitly across sandbox results, events,
run projections, API types, and the run stage UI. This removes the fake
-1 exit code path for timeout/cancel and lets consumers tell cancelled
commands apart from timed-out commands.
Persist command stdout/stderr through scratch logs and finalized CAS refs, expose byte-offset tailing through the API, and render separate streaming panels in the web run view.
Resolve command output blob refs for execution-time consumers such as edge routing and retros, and make Docker streaming timeout/cancel drain output before returning.
Add configured to the model API contract and server responses so clients can see whether provider credential material exists before testing. Use that signal in bulk model tests to skip unconfigured providers before printing progress and treat post-list skips as race failures.
Move favicon, logo, logotype, and PNG icons from /public/ root to
/public/images/ so the HTTP log middleware can drop them by path
prefix. Extends the existing /assets/ skip in http_log_middleware to
cover /images/ as well, removing favicon/logo entries from the server
log without filtering by extension (which would risk muting future
extension-suffixed API routes).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per-request "worker token accepted" line is high-frequency request
chatter; INFO should be lifecycle-only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Share ACTIVE_STAGE_STATES/SUCCEEDED_STAGE_STATES across stage-sidebar and
run-overview, collapse the nested match in active_stage_state_from_events,
and drop a few WHAT-comments that narrated the recent rename.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The bail!("Validation failed") was nested inside `if !quiet`, so
`fabro run --detach` and `fabro run create` (both pass quiet=true)
silently created runs from invalid workflows. Move the bail outside the
gate; only the workflow summary print remains gated on !quiet.
Also simplifies the surrounding preflight code:
- Extract `cyan_spinner` helper in fabro-cli's shared utilities;
collapse three copy-pasted 13-line spinner setups in preflight.rs,
doctor.rs, and install.rs.
- Add `SandboxProvider::is_clone_based()`; replace the local
`is_clone_based_provider` helper and two inline
`matches!(_, Docker | Daytona)` sites in run_manifest.rs.
- Promote `fabro_sandbox::redact::redact_auth_url` to pub and reuse it;
delete the duplicate `redact_remote_output` in run_manifest.rs.
- Inline the one-liner `preflight_docker_config` /
`preflight_daytona_config` helpers and drop their dedicated tests.
- Type the `prepared_and_resolved_for_sandbox` test helper with
`SandboxProvider` instead of `&str`.
- Drop git ls-remote preflight timeout from 30s to 10s.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>