`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>
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>
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>
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>
Keep the changed-files tree selection aligned to valid file paths, avoid mobile and initial-reset overhead, and lazy-load the tree bundle. Refresh the embedded SPA assets to match.
Adds a GitHub-style left sidebar to /runs/:id/files using @pierre/trees.
Lists only the modified files, shows git status per row, and wires
selection into the existing #file=<path> deep-link flow so clicking a
row scrolls and focuses the matching diff. Uses the @pierre/theme
pierre-dark Shiki theme for visual parity with @pierre/diffs.
Configured read-only (no drag-and-drop, no rename), flattens empty
directory chains, defaults to standard icons and default density, and
filters via hide-non-matches search. Hidden below the md breakpoint to
match where the diff style is forced to unified.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`useFreshness` now appends the GitHub-style 7-char prefix of `meta.to_sha`
to the captured/fetched timestamp, e.g. `Captured 2m ago · a1b2c3d`.
The OpenAPI pattern guarantees at least 7 hex chars when present;
degraded responses with no captured commit gracefully omit the SHA.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds four tests for the degraded-fallback line-stats path:
- aggregates_across_multiple_files: sums +/- across multiple file
sections.
- ignores_hunk_headers_and_no_newline_marker: pins that `@@` and
`\ No newline at end of file` lines never count.
- zero_for_empty_patch: boundary on empty input.
- after_strip_denylisted_ignores_sensitive_section: integration with
`strip_denylisted_sections` — the `# sensitive file omitted: <path>`
placeholder it leaves behind contributes 0 to the totals.
The existing tests already covered basic counting, header exclusion,
and symlink/submodule mode-line skipping.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Track numstat by path so sensitive, binary, symlink, and submodule entries do not inflate aggregate line counts, and clean generated client whitespace churn from the API update.
Replace React Router loader/action state paths with SWR query and mutation hooks.
Add targeted run and board EventSource managers that invalidate SWR keys, and refresh embedded SPA assets.
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>
Consolidate workspace_root, PlannedCommand, shell_arg, markdown_cell, and
replace_generated_region into commands/mod.rs; unify fabro_dev/output_text/
write_file/read_file into tests/it/main.rs. Drop the abandoned check-boundary
subcommand.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
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.