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.
Replace 16 inline copies of the `[cli.target] type = "http"` settings TOML across CLI integration tests with a single `set_http_target(&base_url)` method on `TestContext`. Removes a brittle format string that was maintained in ten files but only meaningfully asserted-against in one.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
The Metadata init/checkpoint/finalize lines added noise to `fabro run`
output. The underlying events still flow into progress.jsonl; only the
live rendering is removed. Failures continue to render as warnings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Promotes per-run observability events (stage start/complete, edge
selection, checkpoint, fidelity resolution, agent session, LLM stream
finish, tool calls, sandbox cleanup, PR build/create) from debug to
info so default-level operators see end-to-end run progress.
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>
Add typed metadata snapshot events around init, checkpoint, and finalize archive writes so run logs expose durable metadata timing and failures. Include snapshot accounting, CLI rendering with compatibility-notice suppression, and event documentation.
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>
`fabro preflight` blocks on a single server-side `run_preflight` call.
Without feedback the terminal sits blank until it returns. Mirror the
existing `fabro doctor` spinner (cyan braille, "Running checks...",
80ms tick), gated on `!ctx.json_output()` so JSON and piped callers
stay clean. The network calls run inside an inline async block so the
spinner is `finish_and_clear`ed before any `?`-propagated error
prints.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- classify_section now returns FileDiffChangeKind directly (unnecessary_wraps)
- collapse nested Some(...) or-pattern into single arm (unnested_or_patterns)
- replace .unwrap() with .expect() in append_completed_run_with_final_patch test helper (unwrap_used)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Return degraded run files with the same FileDiff[] shape as live responses, using nullable contents and per-file unified patches so the web sidebar and deep links work consistently.
Inline static credential-refresh failure tags instead of round-tripping
through a classifier whose substring matches always returned the
sentinel its callers prepended. Drop the dead `Error::Exec` accessors
in favor of pattern matching, and replace the redundant
`MetadataSnapshot::pushed` field with `push_error.is_none()`. Also fix
a regression in Docker `refresh_push_credentials` that was discarding
stderr and exit code on `set_url_nonzero` failures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add structured exec errors whose Display output keeps raw command output out of logs and notices while preserving stdout/stderr through explicit accessors. Stop Daytona from logging raw command strings and propagate git_push_ref errors so metadata push warnings include safe failure detail.
- Add `parent_or_dot()` helper to replace the repeated
`.parent().unwrap_or_else(|| Path::new("."))` idiom at three call sites.
- Add `From<ManifestPath> for PathBuf` and use it in
`BundleFileResolver::resolve` to drop a per-resolve `PathBuf` clone.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduce ManifestPath as the canonical in-memory key for run manifests so CLI-produced bundle keys and workflow/server consumers share the same normalization rules. Validate wire keys at the server boundary and add a CLI-to-server round-trip test for user-global @path references.
Generate a fresh UUIDv4 per request, attach it to response headers,
JSON error bodies, and HTTP response logs so client-visible failures can be
matched to server logs without trusting inbound request id headers.
GitHubAppCredentials now carries the configured app slug, so the "not
installed" error from the installation lookup links to the specific
app's install page (https://github.com/organizations/{owner}/settings/apps/{slug}/installations)
when known, instead of the generic org installations page. Threaded
through the server, workflow pipeline, and CLI runner.
Also treat docker like daytona for GitHub credential gating: both are
clone-based providers that need an installation token to fetch the repo,
so a docker run now requires credentials when daytona would.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After a successful clone, both providers run "git remote set-url origin"
to embed an authenticated URL so the engine can push back. When that
command failed, the warning logged only exit_code, leaving subsequent
push failures with no usable trace.
- docker: log redacted stderr alongside exit_code (URL contains the
installation token, so reuse redact_auth_url).
- daytona: same, plus surface the previously-swallowed Err from
execute_command, and include the origin URL on embed_token_in_url
failures.
In all three branches, point the message at the consequence ("subsequent
git push will fail") so the warning isn't read as cosmetic.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous "Failed to push git ref" warning logged only the exit code,
forcing manual reproduction in the sandbox to learn what GitHub said.
Include redacted stderr/stdout (entropy + gitleaks scrubbed via
fabro_redact::redact_string), the timed_out flag, and a short hint
keyed off well-known git/GitHub error phrases (missing credentials,
permission denied, ruleset rejection, repo-not-found, DNS failure).
Output is tail-trimmed to 2 KiB so a chatty git progress dump can't
flood the log line.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous commit added GITHUB_APP_PRIVATE_KEY to the worker env
allowlist, but the secret is in server.env / ServerSecrets, not in the
server's process env, so the allowlist couldn't see it.
Forward the value explicitly from ServerSecrets at spawn time, mirroring
how FABRO_WORKER_TOKEN is already passed. Keeps the allowlist narrow as
a fail-closed barrier against ambient env leakage and keeps ServerSecrets
as the single read site for server.env secrets.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add GITHUB_APP_PRIVATE_KEY to the worker env allowlist so the
__run-worker subprocess can mint installation tokens for git push.
Without it the worker resolves github_app=None and clone-based sandboxes
push without auth, which fails as exit-128 against any repo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Expose the configured server.web.url in system info so the empty runs quick start can show a runnable fabro auth login command instead of a placeholder.