Commit graph

577 commits

Author SHA1 Message Date
Bryan Helmkamp
a4e63ec897
feat(api): expose aggregate +/- diff stats on run files response
Adds `meta.stats: DiffStats` (required) to `PaginatedRunFileList` so the
Files Changed toolbar can render `+387 −104` next to the file count.

Server: refactors `list_binary_paths` into `list_diff_numstat`, which
returns the binary-path set plus aggregate `+/-` totals from a single
`git diff --numstat` invocation. The degraded patch-only response
populates the same field by counting `+`/`-` line prefixes in the
filtered patch (excluding `+++`/`---` file headers).

UI: `Toolbar` accepts `additions` / `deletions` and renders them as
mono-tabular `+387 −104` to the right of the file count. The block is
elided when the diff has 0 changes (e.g. binary-only or empty runs) so
the empty case stays clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:38:02 -04:00
Bryan Helmkamp
11be286fa1
refactor(dev): simplify generated docs tooling
Share the real CLI parser with reference generation, reuse option metadata flattening, and centralize dev command execution helpers.
2026-04-24 18:41:00 -04:00
Bryan Helmkamp
12ea5341bb
feat(dev): generate options reference
Add a settings reference generator backed by OptionsMetadata on the sparse config layer structs. The generated user-configuration page is fenced and checked in CI alongside the CLI reference.
2026-04-24 16:49:16 -04:00
Bryan Helmkamp
0f3c28db87
feat(dev): generate CLI reference
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.
2026-04-24 16:35:06 -04:00
Bryan Helmkamp
fc7382ce79
feat(options): add options metadata derive 2026-04-24 16:13:32 -04:00
Bryan Helmkamp
f52ef5aa07
feat(dev): port SPA asset tooling 2026-04-24 16:05:29 -04:00
Bryan Helmkamp
a03c689a44
feat(dev): port release automation 2026-04-24 16:00:25 -04:00
Bryan Helmkamp
0daf4d7b5c
feat(dev): port docker build workflow 2026-04-24 15:55:03 -04:00
Bryan Helmkamp
99257846d1
feat(dev): enforce CLI boundary with cargo dev 2026-04-24 15:50:01 -04:00
Bryan Helmkamp
99d2adb216
feat(dev): add fabro-dev scaffold
Introduce the internal fabro-dev CLI shell and cargo dev alias so follow-up units can port development scripts behind typed clap subcommands.
2026-04-24 15:43:30 -04:00
Bryan Helmkamp
7e64bf8b69
feat(cli): render fatal errors with miette
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.
2026-04-24 15:35:57 -04:00
Bryan Helmkamp
89bf987457
test(snapshot): share JSON snapshot helper
Promote fabro_json_snapshot! into fabro-test so integration tests use one workspace helper with shared JSON normalizations.
2026-04-24 15:14:06 -04:00
Bryan Helmkamp
56de394e01
refactor(redact): extract redaction into dedicated crate
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.
2026-04-24 15:02:23 -04:00
Bryan Helmkamp
92566d430f
Merge remote-tracking branch 'origin/main' 2026-04-24 13:39:42 -04:00
Bryan Helmkamp
828a8c4429
refactor(redact): make credentialed URL logging safe
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.
2026-04-24 13:39:34 -04:00
Bryan Helmkamp
637eb8ba1c
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-server/src/install.rs
2026-04-24 13:25:21 -04:00
Bryan Helmkamp
68214575e3 docs: refresh changelog and setup docs
Add dated changelog entries for recent user-facing changes and update server setup docs for the object-store installer flow.
2026-04-24 13:00:15 -04:00
Bryan Helmkamp
533785cd4c fix(install): expose local object store root 2026-04-24 12:38:04 -04:00
Bryan Helmkamp
80de5ca616 refactor(static): centralize env var names
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.
2026-04-24 12:29:51 -04:00
Bryan Helmkamp
6d97de0d99 docs(quick-start): document supported platforms
Add a Supported platforms table to the quick-start so Intel Mac and
Windows users learn they're unsupported before running the installer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 12:25:40 -04:00
Bryan Helmkamp
e4e5eb08d7
plan 2026-04-24 11:45:23 -04:00
Bryan Helmkamp
76c7124be7
plan: adopt six engineering patterns from uv
New deep plan covering DisplaySafeUrl (fabro-redacted), EnvVars
registry (fabro-static), expanded snapshot helpers, miette CLI
diagnostics, fabro-dev unified CLI, and OptionsMetadata-driven docs
generation. Six phases, thirteen implementation units, ships as
independent PRs.

Includes deepening-pass revisions and reviewer feedback:

- Clippy enforcement reframed as workspace-wide bans with crate-level
  #![allow] opt-outs (clippy.toml has no per-crate scoping).
- Phase 4 (miette) narrowed: fancy rendering + help: footer only; no
  source-highlighting promise since no fabro error type carries spans.
  main() retains its telemetry/shutdown lifecycle.
- Phase 6 split into 6.2 (cli.mdx) and 6.3 (user-configuration.mdx)
  with fenced-region commitment upfront; resolves the previously
  orphaned user-configuration drift problem.
- Phase 2 gains an explicit allow/deny list for DisplaySafeUrl use
  and neutralizes the .to_string() trap via explicit .redacted_string()
  / .raw_string() methods plus a clippy deny on the implicit path.
  install.rs:1227,1546 and fabro-cli/commands/server/mod.rs:266-270
  are explicitly kept as raw String (Location headers, user-facing
  install URLs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:45:23 -04:00
Bryan Helmkamp
4215ed3c16
refactor(workflow): make rewind fork and archive
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.
2026-04-24 11:42:37 -04:00
Bryan Helmkamp
baa20ca375
Merge remote-tracking branch 'origin/main' 2026-04-24 11:23:34 -04:00
Bryan Helmkamp
ac4f306cc6
Merge pull request #168 from fkukuck/fix/auto-pr-resolved-client
fix(workflow): reuse resolved llm client for auto-pr
2026-04-24 11:10:25 -04:00
Bryan Helmkamp
94471a6a3d
docs: fix Mintlify MDX parsing 2026-04-24 10:59:25 -04:00
Bryan Helmkamp
aa82ef6da6
plan: resolve second-review findings and expand unit 2 scope
Apply the five findings from the external review: reject archived sources
with 409 (was contradictory); emit RunSupersededBy only on archive success
(was self-contradicting with the ordering rationale); look up working_directory
from the run's RunSpec instead of hand-waving AppState.repo_path; plumb
superseded_by through RunSummary + OpenAPI to honor the 'helps fabro ps' claim;
reconcile test scenarios to the archive-first ordering.

Also add GET /runs/{id}/timeline to Unit 2 so --list display moves server-side
alongside the mutating rewind call (web-UI parity). Normalize all status
codes from 412 to 409 to match fabro-server's CONFLICT convention.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:28:36 -04:00
Bryan Helmkamp
24fc4d77b7
plan: apply unit 2 adversarial review decisions
Record the five decisions from the targeted Unit 2 review: 207 Multi-Status
for archive-failure partial success, graceful-degradation mapping for TOCTOU
precondition races, archive-first event ordering, accept-orphan retry posture,
and a new superseded_by projection field. Also add spawn_blocking and
operations-layer composite guidance from the review's autofixes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:28:36 -04:00
Bryan Helmkamp
3a6a00f439
plan: converge rewind into fork with server-side endpoint
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:28:36 -04:00
Bryan Helmkamp
336553e30f
remove(cli): drop pr list command entirely
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>
2026-04-24 08:56:07 -04:00
Bryan Helmkamp
4e9dd6fb52
Merge origin/main (preserving RunServices architecture)
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>
2026-04-24 00:10:01 -04:00
Bryan Helmkamp
600720423c
Merge remote-tracking branch 'origin/main'
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.
2026-04-24 00:01:09 -04:00
Bryan Helmkamp
0bf2dd30ef
refactor(server): collapse 409 conflict into standard ApiError
Replace hand-built 409 response that inlined {errors,pull_request} with
a regular ApiError::with_code(CONFLICT, ..., "pull_request_exists") and
drop the optional pull_request field that had been added to the
ErrorResponse OpenAPI schema solely to carry the existing record.

Clients receiving a 409 can GET /runs/{id}/pull_request to retrieve the
stored record when they need it — the detail string still includes the
existing html_url, which is the field most clients branch on.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 22:45:29 -04:00
Bryan Helmkamp
b9911fc6e7
Merge origin/main
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>
2026-04-23 21:46:24 -04:00
Bryan Helmkamp
f46803b367
refactor(api): unify PR detail types via with_replacement
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>
2026-04-23 21:41:11 -04:00
Bryan Helmkamp
099dd881a8
merge origin/main into local main
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>
2026-04-23 21:13:28 -04:00
Bryan Helmkamp
f8e5192fb3
fix(pr): address review feedback on PR refactor
- Return the existing PullRequestRecord on 409 from POST /runs/{id}/pull_request
  so structured clients can recover the URL/number without a follow-up call.
  The response now includes both the error envelope and a pull_request field
  (same shape precedent as /install/finish's leftover_env_keys).
- Add server tests for merge/close error paths: 404 no_stored_record, 400
  unsupported_host, 503 integration_unavailable, 400 invalid_merge_method, 502
  github_not_found.
- Add a dedicated regression test proving the PR handlers use the
  github_api_base_url captured at AppState construction, not a request-time
  env read (SSRF defense invariant from the plan).
- Add an upgrade hint on unstructured 404s from the new PR client methods so
  a new CLI against an old server sees "Upgrade the fabro server" instead of
  an opaque failure.
- Refresh the stale CLI docs paragraph so it describes server-side GitHub
  credentials, matching the post-refactor reality.
- Regenerate the TypeScript API client (had fallen behind the prior OpenAPI
  schema additions) and add PullRequestRecord to ErrorResponse as an optional
  field for the 409 case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 20:34:18 -04:00
Bryan Helmkamp
6fc7251471
close config boundary audit and settings snapshot naming 2026-04-23 19:30:30 -04:00
Bryan Helmkamp
ddd961ddcc
refactor(pr): move pull request commands server-side 2026-04-23 19:23:52 -04:00
Bryan Helmkamp
cb14dc43d1
refactor(llm): use credential sources and split run services 2026-04-23 18:54:27 -04:00
Bryan Helmkamp
6c6368e287
plan 2026-04-23 18:38:46 -04:00
Bryan Helmkamp
ab2060820d
plan 2026-04-23 17:54:02 -04:00
Bryan Helmkamp
235b25750b
fix(docs): point Get Started button to docs.fabro.sh introduction
Was linking to https://fabro.dev/getting-started/quick-start (wrong
domain, 404). Use relative /getting-started/introduction so it resolves
correctly on docs.fabro.sh.

Fixes #167

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 16:33:32 -04:00
Bryan Helmkamp
b2bcf0d5a8
refactor settings builders and dense run snapshots 2026-04-23 11:35:21 -04:00
Bryan Helmkamp
519f46038d
refactor(auth): use per-run worker JWTs for subprocesses 2026-04-23 11:04:45 -04:00
Bryan Helmkamp
44296f233e
plan 2026-04-23 11:02:26 -04:00
Bryan Helmkamp
e4b6d626a2
plan 2026-04-23 10:39:39 -04:00
Bryan Helmkamp
e210fe9fed
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-cli/src/command_context.rs
#	lib/crates/fabro-cli/src/main.rs
2026-04-23 08:56:40 -04:00
Bryan Helmkamp
a770eb8e12
Merge remote-tracking branch 'origin/main' 2026-04-23 08:52:44 -04:00
Bryan Helmkamp
da9453cbd1
refactor(config): move settings combine into types 2026-04-23 08:42:19 -04:00