Commit graph

1680 commits

Author SHA1 Message Date
Bryan Helmkamp
be9d9284be
feat(dev): add bench-tests command for capturing per-test timing CSV
Runs the workspace test suite N times via `cargo nextest run --no-fail-fast`
and appends one row per testcase to a CSV (git_sha, run_index, started_at,
binary, package, classname, test_name, status, duration_ms). Group ≈ package
is derived from the JUnit testsuite name.

The lenient `[profile.bench]` (with junit.path) is synthesized at runtime to
target/bench-tests/nextest-tool.toml and passed via `--tool-config-file`, so
nothing needs to be added to .config/nextest.toml.

Intended use: collect samples on the current checkout, switch SHAs, collect
again, then diff/aggregate externally to hunt slowdowns.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 09:18:00 -07:00
Bryan Helmkamp
3f027be220
refactor: route --in-place through worktree_mode override
Drop --allow-no-checkpoints and the paired ManifestArgs in_place /
allow_no_checkpoints fields. The CLI now translates --in-place into a
single ManifestArgs.worktree_mode = "never" signal that flows through
the existing args→layer pipeline as run.sandbox.local.worktree_mode =
Never. The server computes prepared.in_place from the resolved settings
once, replacing the trio of bail!s and the sandbox-default fixup.
2026-04-28 08:44:54 -07:00
Bryan Helmkamp
b24c67acef
fix: handle non-git local sandbox runs
Skip worktree checkpoint setup when a local sandbox is not backed by a git repository, and keep the API contract aligned with RunSpec serialization for omitted labels.
2026-04-28 08:22:58 -07:00
Bryan Helmkamp
ab9b28875b
fix: close sandbox-native metadata gaps
Ensure local runs use the worktree checkpoint path by default, expose source and sandbox paths in API/web surfaces, and remove dead fork/rewind push controls. Update docs for clone-based sandboxes and durable checkpoint timelines.
2026-04-28 08:05:18 -07:00
Bryan Helmkamp
80aad30f73
fix: close sandbox-native git metadata gaps
Add shared sandbox git validation for checkpoint paths, preserve forked run projection state, and record CLI remote mismatches explicitly. Refresh the API/client docs for durable run-store timeline and structured run specs.
2026-04-28 07:31:01 -07:00
Bryan Helmkamp
0543c5c8fe
chore: simplify sandbox-native git metadata code
- Reuse fabro_sandbox::shell_quote in sandbox_metadata.rs and sandbox_git.rs
  (CLAUDE.md mandates the shared helper, not local reimplementations).
- Skip git_diff call on first checkpoint when prev SHA equals new SHA;
  previously diffed a SHA against itself, costing one sandbox round-trip.
- Drop tuple-match theatre in write_snapshot cleanup.
- Type LEVEL_COLOR as Record<LogLevel, string> so the lookup is exhaustive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 06:39:01 -07:00
Justin Abrahms
c7851f4e08
fix: resolve @path references relative to workflow file, not CWD
`normalize_logical_path()` silently dropped leading `..` components
because `PathBuf::pop()` on an empty buffer is a no-op. For user-global
workflows (~/.fabro/workflows/) invoked from an unrelated CWD, the
manifest builder produces logical paths with leading `..` segments, but
the BundleFileResolver normalized them differently during lookup —
stripping the `..` — causing a key mismatch and leaving `@` references
unresolved.

Preserve `..` when there is no normal component to collapse.

Closes #175

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 09:33:13 +02:00
Bryan Helmkamp
cdd46b4fa8
Make git metadata sandbox-native 2026-04-27 21:43:15 -07:00
Bryan Helmkamp
fd1087fe2d
feat(api): expose workflow graph source as raw DOT
Add GET /api/v1/runs/{id}/graph/source returning text/vnd.graphviz so
the run graph can be inspected as the original Graphviz DOT in addition
to the rendered SVG. Refactor get_graph to share DOT loading with the
new handler. The web run-graph view gains a Graph | Source toggle that
lazy-loads and displays the DOT with a copy button.
2026-04-27 16:24:17 -07:00
Bryan Helmkamp
ca854f9033
chore: rename run span field run_id to id
The span name "run" already namespaces the field, so `run{id=...}` reads
cleaner than `run{run_id=...}` in log output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 16:09:54 -07:00
Bryan Helmkamp
69d4ac5b9b
Merge remote-tracking branch 'origin/main'
Some checks are pending
Rust / Format (push) Waiting to run
Rust / Clippy (push) Waiting to run
Rust / Generated Docs (push) Waiting to run
Rust / Test (Linux) (push) Waiting to run
Rust / Test (macOS) (push) Waiting to run
TypeScript / Build (push) Waiting to run
TypeScript / Typecheck (push) Waiting to run
TypeScript / Test (push) Waiting to run
2026-04-27 15:27:05 -07:00
Bryan Helmkamp
2460ffc37a
feat(install): add sandbox provider step to web install wizard
Operators choose Docker (default, zero-config) or Daytona (validated
via Daytona SDK) during browser install. Selection is captured in
settings.toml under [run.sandbox] -- explicitly even for Docker, so the
choice is locked in. Daytona keys land in the vault as DAYTONA_API_KEY
(Environment secret). Step always runs after object_store and before
the LLM step.

Server adds POST /install/sandbox/test (validates Daytona key via
client.list) and PUT /install/sandbox; both reuse the install-token
auth and InstallSecret redaction patterns established by object-store.
A resolve_install_sandbox_state helper preserves a saved Daytona key
when the operator revisits the step without re-entering it. The
in-memory api_key is dropped from PendingInstall after finish, matching
the manual_credentials cleanup for S3 access keys.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:59:17 -07:00
Bryan Helmkamp
f1b68204d8
refactor: simplify sandbox init failure paths and middleware
Extract a fail_init helper on DockerSandbox/DaytonaSandbox to collapse
~15 copy-pasted 8-line InitializeFailed emit-and-return blocks. Convert
Error::message(format!(\"...{e}\")) to Error::context for the .map_err
sites whose source implements std::error::Error, preserving cause
chains. Drop the redundant no_store_default middleware (security_headers
already sets the default) and skip path allocation in
http_log_middleware for /assets/ requests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 12:09:51 -07:00
Bryan Helmkamp
af56b38e55
fix(lints): resolve clippy errors after error-chain refactor
Update test sites to call .to_string() before .contains() since the
sandbox Error enum no longer dereferences to String, add use statements
to satisfy clippy::absolute_paths, and inline the redundant
sandbox_error helpers in fabro-agent to clear needless_pass_by_value.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 11:37:09 -07:00
Bryan Helmkamp
c224a4517f
fix(docker): grant server access to mounted socket
When the packaged container starts as root, map the mounted Docker socket's group into the container and add the unprivileged fabro user before dropping privileges. This lets Docker sandboxes work with socket mounts from OrbStack, Docker Desktop, and Linux daemons whose socket GID varies by host.
2026-04-27 11:12:44 -07:00
Bryan Helmkamp
b61f69fd6e
fix(server): tighten routing middleware behavior
Keep demo dispatch scoped to API requests, add no-store defaults for install responses, and update the server test sandbox mock for typed sandbox errors.
2026-04-27 10:49:53 -07:00
Bryan Helmkamp
50847ebc6f
fix(sandbox): preserve error chains
Introduce typed sandbox errors and carry source causes through workflow events, persisted failure summaries, and API/CLI string boundaries so Docker client failures keep the actionable underlying cause.
2026-04-27 10:41:39 -07:00
Bryan Helmkamp
f0d34f6e87
Make Rust tests independent of SPA assets 2026-04-27 08:17:37 -07:00
Bryan Helmkamp
d2d962f201
Merge remote-tracking branch 'origin/main' 2026-04-27 07:01:53 -07:00
Bryan Helmkamp
44d1d7f5e2
refactor(api): reuse run summary domain type 2026-04-26 23:28:04 -04:00
Bryan Helmkamp
cb0bab233a
refactor(types): use trait conversions directly
Remove redundant as_str/from helper methods on provider, reasoning, model-test, safe URL, and interview types. Migrate call sites to Display, IntoStaticStr, and FromStr while keeping wire-format coverage in tests.
2026-04-26 21:36:24 -04:00
Bryan Helmkamp
5765547f51
feat(dev): gitignore embedded spa assets 2026-04-26 21:31:11 -04:00
Bryan Helmkamp
54c5f30586
docs: move published docs under docs/public
Relocate the Mintlify tree to docs/public and consolidate internal docs under docs/internal. Update build scripts, tests, CI filters, README references, and local docs skills to follow the new layout.
2026-04-26 21:19:46 -04:00
Bryan Helmkamp
498242f4f7
refactor(sandbox): drop dead helpers and tidy clone-based code
- Delete unused `detect_clone_params` and `GitCloneParams` (the clone-based refactor sources clone params from the run spec, not the worker cwd).
- Add `DaytonaSandbox::repo_cloned()` accessor mirroring Docker; replace five inline `OnceCell` reads.
- Inline `sanitize_origin_url` one-liner wrapper in `manifest_builder`.
- Drop unused `pub` on `docker::WORKING_DIRECTORY`.
- Convert `cleanup` early-return to `let-else` and remove a `Some(...).expect(...)` round-trip in `decide_clone`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 19:16:46 -04:00
Bryan Helmkamp
8365a28e7c
test(cli): update attach snapshot for docker defaults 2026-04-26 19:16:02 -04:00
Bryan Helmkamp
3a8e1a0517
refactor(sandbox): make Docker clone-based by default
Switch Docker sandboxes from host bind mounts to per-run clone-based containers with structured run metadata, reconnect validation, archive-based file transfer, and Docker resource defaults.

Extend run config/API surfaces so Docker image and clone settings flow through manifests, server preflight, workflow startup, and generated clients.

Update docs and tests for the new default Docker provider path.
2026-04-26 18:21:02 -04:00
Bryan Helmkamp
9587b83cfe
Merge remote-tracking branch 'origin/main' 2026-04-26 18:00:53 -04:00
Bryan Helmkamp
583fa1e9d1
refactor(config): share log destination resolution
Move FABRO_LOG_DESTINATION parsing into fabro-config so CLI and server worker startup use the same validation behavior. Worker startup now exports one canonical resolved destination instead of relying on a generic env allowlist path.
2026-04-26 17:47:22 -04:00
Bryan Helmkamp
7ecd8df32e
refactor(web): simplify run logs view
Drop unjustified useMemo around byteCount, add void to mutate(), let
errorMessage return undefined for non-Error values so the description
doesn't duplicate the retry button label, and reuse formatBytes (hoisted
to lib/format.ts from insights-editor) so log size renders as "1.23 MB"
instead of "1,234,567 bytes".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 17:47:10 -04:00
Bryan Helmkamp
4e9d3774ef
feat(web): add run logs view
Add a "Run Logs" entry to the run detail sidebar that fetches the
worker tracing log via GET /api/v1/runs/{id}/logs and renders it with
auto-refresh while the run is live. Refreshes the embedded SPA bundle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 17:38:22 -04:00
Bryan Helmkamp
e6ca9eba87
refactor(cli): rename ServerLogSink to LogSink
The Server prefix is redundant -- the type is used by both Server and
Worker variants of InternalLogSink, and the helper that builds it from a
runtime directory is renamed to log_sink to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 17:36:03 -04:00
Bryan Helmkamp
7abc11adc9
feat(server): route worker logs to the same destination as the parent
Workers are an internal implementation detail; operators should not need
to know about them. When the server runs in stdout mode (FABRO_LOG_DESTINATION=stdout,
e.g. inside containers), workers now also stream their tracing to stdout
so all server-level logs land on the same destination.

The parent propagates its resolved destination to each worker via
FABRO_LOG_DESTINATION and inherits the worker's stdout when the parent is
in stdout mode (so worker stdout flows through to docker logs). The
per-run log at <scratch>/runtime/server.log stays a file regardless --
it is read back by the run UI.

A CLI-side ServerLogSink::{File(PathBuf),Stdout} replaces Option<PathBuf>
so the file/stdout intent is explicit at the type level for both the
Server and Worker sinks. LogDestination gains strum::IntoStaticStr so
the parent can stringify it for the worker env without a hand-written map.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 17:16:03 -04:00
Bryan Helmkamp
3a6ef48e56
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	docs-internal/logging-strategy.md
#	lib/crates/fabro-cli/src/logging.rs
#	lib/crates/fabro-cli/src/main.rs
#	lib/crates/fabro-static/src/env_vars.rs
2026-04-26 16:29:54 -04:00
Bryan Helmkamp
126819a6c6
refactor(cli): collapse ServerLogDestination into LogDestination
The CLI-side ServerLogDestination enum duplicated the domain
LogDestination from fabro-types and only existed to bundle a PathBuf.
Replace InternalLogSink::Server { destination: ServerLogDestination }
with { log_path: Option<PathBuf> }, drop the server_log_destination
adapter, and let prepare_foreground_server_log derive the log path
from runtime_directory internally.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:06:38 -04:00
Bryan Helmkamp
a97b151593
refactor: simplify per-run logs client and handler
Use the generated progenitor builder for client.get_run_logs, return raw
bytes end-to-end, and drop the no-op file.flush() in BufferedFileGuard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:06:23 -04:00
Bryan Helmkamp
4b09b8f8fe
feat(server): add per-run worker logs
Mirror worker tracing into run-scoped runtime/server.log files, expose them through the run logs API, and include run.log in dump exports when available.
2026-04-26 14:53:03 -04:00
Bryan Helmkamp
d07596ca80
feat(server): support stdout log destination
Add configurable server log destinations with an environment override so containers can stream foreground server logs to stdout while local installs keep file logging by default. Validate configured log filters at load time and reject stdout logging for daemon mode.
2026-04-26 14:52:15 -04:00
Bryan Helmkamp
9f61c942cb
fix(server): redirect web requests to canonical host
Keep browser-facing web and auth flows on server.web.url so OAuth state cookies and redirect_uri use the same authority, while preserving API, webhook, health, and CLI token routes without cross-host redirects.
2026-04-26 12:27:27 -04:00
Bryan Helmkamp
bbe4d3c68c
refactor(dev): align cargo dev command modules
Some checks are pending
Rust / Format (push) Waiting to run
Rust / Clippy (push) Waiting to run
Rust / Generated Docs (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
2026-04-25 19:50:31 -04:00
Bryan Helmkamp
d37f75a878
feat(dev): group cargo dev spa and docs commands 2026-04-25 19:40:59 -04:00
Bryan Helmkamp
05e5623b2b
chore(dev): default docker-build tag to fabro-sh/fabro
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 19:40:59 -04:00
Bryan Helmkamp
b9b7efc46b
Merge remote-tracking branch 'origin/main' 2026-04-25 19:11:44 -04:00
Bryan Helmkamp
97f533c643
refactor(install): drop trivial wrappers and dead branches
Inline the one-line `validate_canonical_url` wrapper at its single
caller, collapse `check_config`'s repeated `is_empty()` branches into
one if/else, and remove an unreachable default in
`wildcard_public_url_details` (the function returns early when
`bad_urls` is empty, so `bad_urls[0]` always exists).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 19:11:35 -04:00
Bryan Helmkamp
c28b040c6f
fix(install): reject wildcard public URLs
Normalize bind-address wildcards before presenting install URLs, reject wildcard public origins at CLI and server install boundaries, and surface recovery guidance in the installer and doctor output.
2026-04-25 18:58:00 -04:00
Bryan Helmkamp
a4c04a296e
chore: move docker-context/ staging dir under tmp/
Keeps the repo root tidy. The staged Linux musl binaries used by
the Dockerfile and the release pipeline now live at
tmp/docker-context/<arch>/fabro instead of docker-context/<arch>/fabro.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 12:37:45 -04:00
Bryan Helmkamp
cb0c39ee91
fix(server): style web OAuth state-failure error page
Render the OAuth callback state-validation error through the same
dark-themed browser shell used by the CLI auth flow instead of the bare
"<p>{body}</p>" fallback. Extract the shell into a shared
auth/browser_shell module so both flows reuse one definition.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 12:23:59 -04:00
Bryan Helmkamp
858f40d134
fix(test): extend CLI helper timeout in CI 2026-04-25 11:52:27 -04:00
Bryan Helmkamp
d1b0548197
fix(web): unbox file tree sidebar
Drop the border, rounding, and background from the FileTree wrapper
(and its empty state) so the tree sits directly on the sidebar
container.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 09:43:12 -04:00
Bryan Helmkamp
40fa088410
refactor(web): redesign settings page as titled panels
Replace the raw JSON dump with three panels (Server, Access & Capacity,
Integrations & Artifacts), each rendering a small set of curated rows.
Each row uses an aligned two-column layout — title and help on the
left, a typed value renderer on the right (toggle dot, mono path,
URL link, badge, tabular-nums count, listen/object-store summaries).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 09:37:55 -04:00
Bryan Helmkamp
be63bda5c8
fix(web): stabilize run files sidebar interactions
Reserve the desktop file-tree column while files and the lazy sidebar load, and make the custom changed-files filter drive the rendered tree directly.
2026-04-25 09:34:40 -04:00