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>
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>
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.
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.
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>
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.
Add a cargo dev generator for the CLI reference and gate the generated docs in CI. The generator reads the fabro clap command tree through a narrow public reference surface so CLI docs drift is caught without exposing runtime command internals.
Persist dev-token credentials in auth.json alongside OAuth entries so CLI targets resolve credentials consistently across TCP and Unix socket flows.
Move install-time token minting to runtime storage, add auth login --dev-token, and refresh the embedded SPA after updating the stale dev-token hint.
Wrap root CLI errors at the main boundary so fatal diagnostics use miette's styled renderer while preserving existing telemetry, exit codes, and auth help hints.
Move secret redaction and DisplaySafeUrl into fabro-redact so credential handling has a narrow ownership boundary. Update direct consumers and docs to depend on fabro_redact instead of fabro_util::redact.
Add DisplaySafeUrl under fabro-util::redact so URL Display and Debug output redact credentials by default. Migrate token-bearing GitHub, OAuth, server, LLM, sandbox, and workflow paths to use the wrapper at logging/error boundaries while keeping raw URLs explicit for wire and shell transit.
Color the install URL and add a separate block that prints the install
token on its own line so users can copy it without parsing the query
string. The token block shows in both the URL and reverse-proxy branches.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add fabro-static::EnvVars as the shared registry for fixed environment variable names and migrate env reads, clap env bindings, and subprocess/test allowlists to use it.
Add clippy bans for raw std::env lookup APIs so future dynamic env facades must be documented explicitly.
Rewind now creates a resumable replacement run from the selected checkpoint, archives the source run, and records run.superseded_by for auditability. Fork, rewind, and timeline listing now share server-backed git-store plumbing, with generated API clients and docs updated for the new contract.
Reuse the existing merge strategy type across CLI/API/GitHub paths, consolidate repeated PR command setup, and serialize server-side PR creation per run to avoid duplicate external work.
The "Anthropic uses x-api-key header, everyone else uses Bearer" logic
was written three times: env_source (env-based construction), resolve
(vault-based construction), and provider_auth (CLI key validation).
Any future header rename would need three edits.
Add ApiCredential::from_api_key(provider, key) as a canonical
constructor. Each callsite now builds via the helper and overrides only
the fields specific to its path (env base URLs, vault-sourced org/project
IDs, codex mode, etc.).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
build_pr_body and maybe_open_pull_request now take the two things they
actually need — run_store: &RunStoreHandle and llm_source: &dyn
CredentialSource — instead of services: &RunServices. The workflow
PULL_REQUEST phase decomposes services at the callsite; the standalone
fabro pr create command passes its own directly.
This removes RunServices::for_cli, a stub constructor that fabricated
an emitter, sandbox, and provider just to satisfy the RunServices type
for two fields it cared about. The "leaky fake" is gone.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Abandoning `fabro pr list`. Deletes:
- lib/crates/fabro-cli/src/commands/pr/list.rs
- lib/crates/fabro-cli/tests/it/cmd/pr_list.rs
- PrListArgs struct + PrCommand::List variant + dispatch arm + name
- The `client()` accessor + `client` field on ServerSummaryLookup
(`pr list` was the only consumer)
- `### fabro pr list` section in docs/reference/cli.mdx
- `list` row + alias from the `fabro pr --help` snapshot test
Server side untouched: there was no `/pull_requests` endpoint to
remove. Historical changelog and plan docs left as-is — they record
when the command shipped, not its current existence.
Verified: workspace fmt clean, clippy --all-targets -D warnings clean,
cargo nextest run --workspace 4581 passed (down from 4584 by the
3 deleted pr_list tests), 182 skipped.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three cleanups in one pass:
1. Bundle GitHub creds + base URL into a GitHubContext<'_>:
Defined in fabro-github and threaded through create_pull_request,
enable_auto_merge, get_pull_request, merge_pull_request, and
close_pull_request (plus their _with_client variants). Each function
loses its trailing `base_url: &str` and replaces `creds:
&GitHubCredentials` with `ctx: GitHubContext<'_>`. Bundle propagates
into OpenPullRequestRequest as a single `github` field instead of
the prior split `creds` + `github_api_base_url`.
2. Delete dead CommandContext::storage_dir() and ::server_settings():
Origin added these for client-side PR commands that no longer exist
after the server-side migration. Field `server_settings` removed
from CommandContext (only the deleted method read it). Same field
pruned from ResolvedCommandSettings; one test that verified the
underlying loader behavior was rewired to read LoadedSettings
directly via load_resolved_settings_from_toml.
3. Audit *_error helpers in fabro-server: no remaining single-use
factories. The previous inlining pass left a tidy surface. No diff.
Verified: workspace fmt clean, clippy --all-targets -D warnings clean,
cargo nextest run --workspace 4587 passed, 182 skipped.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two surface cleanups:
1. maybe_open_pull_request now takes one OpenPullRequestRequest<'_>
struct instead of 12 positional args. The struct lives next to the
function (matches *Options pattern in pipeline/types.rs); fields are
named so call sites read top-down — eliminates the wall of
strings/bools that the workflow pipeline, server handler, and tests
were passing positionally. Renamed `base_url` -> `github_api_base_url`
so it doesn't read like a sibling of `base_branch`.
2. transport_error in cli/exec.rs replaced two substring matches
(`message.contains("fabro auth login") || message.contains(
"Authentication required.")`) with `exit::exit_class_for(err) ==
Some(ExitClass::AuthRequired)` — refresh_access_token already attaches
ExitClass::AuthRequired via .classify(), and main.rs uses the same
structural check.
Verified: workspace fmt clean, clippy --all-targets -D warnings clean,
cargo nextest run --workspace 4587 passed, 182 skipped.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reconciles 61 origin commits (settings/config architectural reshape:
sparse layers → dense snapshots via builders, WorkflowSettings rename,
RunLayer/CliLayer moves, workflow builders, drop of public load wrappers)
with our LLM credential + RunServices refactor.
Our architecture preserved where it conflicted with origin's:
- RunServices / EngineServices stay (services.rs does not exist on
origin, which inlined the fields onto Initialized). Origin's new
Initialized fields (inputs, run_store, emitter, sandbox, registry,
env, dry_run, llm_client, provider) are absorbed through RunServices
and EngineServices instead of being inlined.
- llm_source: Arc<dyn CredentialSource> stays on AppState and
RunServices. Origin had a parallel ProviderCredentials struct in
fabro-server; our CredentialSource trait is more general and
complies with docs-internal/llm-client-resolution.md. Point-of-use
Client::from_source(...) rebuild preserves OAuth refresh.
- CommandContext.llm_source() uses self.storage_dir (origin's direct
field) instead of self.machine_settings (our side's field, removed
by origin).
- standalone_llm_source in fabro-agent drops the dead Result wrap and
uses fabro_config::user::default_storage_dir (origin's entrypoint)
instead of the removed load_settings_user/resolve_storage_root.
Absorbed from origin wholesale:
- SettingsLayer → WorkflowSettings rename everywhere
- Dense run settings: RunOptions.settings is WorkflowSettings, inputs
read via settings.run.inputs directly (not Option<RunLayer>)
- AppState.manifest_run_defaults / manifest_run_settings
- fabro_config re-exports of CliLayer/RunLayer/CliOutputLayer/etc.
- Lifecycle terminal-event changes, finalize dedup, list_events
consolidation — already brought in on the previous merge, kept
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merge origin's fabro-config types boundary refactor (dense settings
migration: WorkflowSettings/UserSettings/ServerSettings moved to
fabro-types; SettingsLayer made pub(crate) inside fabro-config) into
local PR-refactor branch.
Conflict resolution intent:
- lib/crates/fabro-cli/src/commands/pr/{create,mod}.rs — kept HEAD's
server-side PR command implementations; origin still carried the
pre-refactor client-side helpers (build_github_credentials,
load_pr_record, branch_exists pre-check) that local commits had
already migrated to the server.
- lib/crates/fabro-cli/src/user_config.rs — took origin's resolution
(load_resolved_settings_from_toml + storage_dir_from_document tests),
which implements the same dead-storage_dir-wrapper cleanup local had
done via local_server::storage_dir.
- lib/crates/fabro-server/src/server.rs — kept HEAD's PullRequestRecord
import alongside origin's added ServerSettings; rewrote test helpers
github_token_settings + create_github_token_app_state to use origin's
ServerSettingsBuilder + AppStateConfig dense-settings shape (replaces
HEAD's parse_settings_layer + Arc<RwLock<SettingsLayer>>); switched
RunSpec.settings fixture from SettingsLayer::default() to
WorkflowSettings::default() per origin's RunSpec retype.
- Suppressed dead_code on CommandContext::storage_dir() and
::server_settings() (added by origin for use by client-side PR
commands that no longer exist after local's server-side migration);
gated load_resolved_settings_from_toml on cfg(test).
Verified post-merge: workspace fmt clean, clippy --all-targets
-D warnings clean, cargo nextest run --workspace 4587 passed,
182 skipped.
The `sleep_inhibitor` feature pulled in 20 pedantic/nightly lints that
CI (default features) never exercised. Narrow all `pub` items in the
module to `pub(crate)`/`pub(super)`, replace the `use
super::iokit_bindings::*` wildcard with explicit imports, use `&raw
mut` for FFI pointer borrows, drop the always-`Some` wrapping in
`DummySleepInhibitor::acquire`, and bring `crate::sleep_inhibitor`
into scope at the three call sites so they don't trip
`clippy::absolute_paths`.
Verified: `cargo +nightly-2026-04-14 clippy --workspace --all-targets
--all-features -- -D warnings` clean, `cargo nextest run --workspace
--all-features` 4563 tests passed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reconciles origin's "emit terminal event from FINALIZE" refactor
(41c47dbe1, e8a89ac39, 904c8842f) with the local RunServices refactor.
finalize() now performs origin's single list_events walk for stage
durations + artifact count, origin's compute_final_patch, deduped
stages/billing via billing_from_checkpoint, and origin's terminal event
emission — but reads run_store/sandbox/emitter from the shared
RunServices instead of individual Retroed fields. services.emitter.notice
replaces origin's local emit_run_notice helper.
test_support's execute_and_emit_terminal (added by origin) now accesses
run_store/emitter via executed.engine.run.* since Executed bundles
EngineServices. execute/tests.rs drops the terminal-event status
assertion origin deleted — status is no longer set at EXECUTE end.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move PullRequestDetail, PullRequestGithubDetail, PullRequestUser,
PullRequestRef, and MergeMethod into fabro-types. Register them as
fabro-api with_replacement targets so the OpenAPI client and the server
share one canonical type per concept.
PullRequestDetail composes a stored PullRequestRecord with a flattened
PullRequestGithubDetail mirroring GitHub's REST payload, removing the
hand-rolled pull_request_detail_json builder in the server. Change the
PullRequestRef wire field from `ref_name` to `ref` so the same Rust
type round-trips through both GitHub and our API without aliases.
The server now uses fabro_api::types::{Create,Merge,Close}* directly,
deleting the hand-defined request/response shadows and the
`body.method.parse::<...>()` call (the typed MergeMethod enum drives
deserialization). Drops fabro-cli's `i64::try_from(record.number)`
panic path and the AutoMergeMethod enum (replaced by MergeMethod).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Integrates origin's worker-JWT-auth work (commits 8a6f83bb0..c847a828d)
with the config-boundary refactor that landed locally. Conflicts
resolved:
- commands/dump.rs: take origin's removal of the 500-line in-process
test block (replaced by real-server integration coverage).
- commands/run/runner.rs: keep local's dense WorkflowSettings import,
drop dead SettingsLayer import, pull in origin's ActorRef.
- manifest_builder.rs: adopt origin's lifted working_directory
resolution (fixes#159 - manifest git detection in nested repos),
but via local's resolve_working_directory_from_run API that takes
the dense RunNamespace. Update the regression test's
ManifestBuildInput literal to local's run_overrides/cli_overrides
field shape.
- server.rs: keep origin's jwt_auth_mode/jwt_auth_state/
test_user_subject/issue_test_user_jwt/issue_test_worker_token/
create_run_with_bearer/bearer_request test helpers, adapt
jwt_auth_state to local's create_test_app_state_with_session_key
signature (ServerSettings + RunLayer), keep local's dense
canonical_origin_settings that returns ServerSettings via
server_settings_from_toml. Rewrite
build_app_state_requires_session_secret_for_worker_tokens against
the dense AppStateConfig (resolved_settings +
resolved_runtime_settings_for_tests).
Post-merge verification: workspace builds clean, cargo +nightly
fmt --check all clean, cargo +nightly clippy --workspace
--all-targets -- -D warnings clean, cargo nextest run --workspace
4560 tests passed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three test modules drifted to non-canonical style during the post-merge
CI fixup; reformatting brings them back in line with the pinned nightly
rustfmt config so `cargo +nightly-2026-04-14 fmt --check --all` is clean
again.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Parallelize `pr list` discovery loop via buffer_unordered; thread RunId
through the stream to drop the run_id.parse().expect(...) panic path.
- Skip computing the default model in create_run_pull_request when the
request already supplies one (common path from `fabro pr create`).
- Delete the dead user_config::storage_dir wrapper (test-only, zero
callers, stale deprecation note); point its tests at
local_server::storage_dir directly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
FINALIZE loaded the run event log twice: once via build_conclusion_from_store
for stage durations, then again to count ArtifactCaptured events. Merged into
a single walk feeding both the conclusion and the artifact count.
Collapsed six near-identical pipeline::execute + emit_terminal + flush blocks
in test_support into one execute_and_emit_terminal helper. Also trimmed
narrative comments that described caller ordering, control flow, or the fix
commit rather than non-obvious invariants.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>