Merge remote-tracking branch 'origin/main'

This commit is contained in:
Bryan Helmkamp 2026-04-25 19:11:44 -04:00
commit b9b7efc46b
No known key found for this signature in database
25 changed files with 99 additions and 92 deletions

View file

@ -1 +1 @@
6d97de0d9948f26d544e7a2bc35a99f53c55cbf8
cb0c39ee915896c5a3e8873180092a8bc95bbf36

View file

@ -1 +1 @@
533785cd4c107cee673825847b1f8fe3d8d14dfe
d2cc37c615894d56ef672d00004ce13ce3b328c2

View file

@ -1,39 +0,0 @@
---
status: ready
priority: p1
issue_id: "001"
tags: [rust, clippy, async-io, std-fs]
dependencies: []
---
## Problem Statement
Several Rust crates still contain `FOLLOW-UP:` markers related to blocking `std::fs` or sync I/O on async paths. The requested work is to execute the implementation plan in `~/.claude/plans/we-ll-feal-with-std-fs-jaunty-feigenbaum.md` and finish the refactors or tighten the remaining sync justifications.
## Findings
- The repo is currently on `main`, and the user explicitly approved proceeding there.
- `docs/solutions/` is not present, so there are no repo learnings to consult for this task.
- The current code matches the plan buckets across `fabro-agent`, `fabro-devcontainer`, `fabro-llm`, and `fabro-workflow`.
## Proposed Solutions
- Execute the plan in bucket order, using targeted failing checks before each production change where feasible.
- Prefer async propagation for truly async paths and `spawn_blocking` only at natural async boundaries.
- Remove or narrow `#[expect(clippy::disallowed_methods)]` annotations once the production sites are fixed.
## Recommended Action
Implement the plan directly, verify each bucket with crate-level tests or lint checks, then run the final formatting, clippy, workspace tests, and `FOLLOW-UP` sweep.
## Acceptance Criteria
- All `FOLLOW-UP:` markers under `lib/crates/` are removed.
- The planned async refactors and `spawn_blocking` boundary changes are implemented.
- Formatting and workspace clippy pass.
- Relevant crate tests pass during incremental verification.
## Work Log
- 2026-04-19: Created execution todo, confirmed branch choice with the user, and started inspecting the planned call sites.

View file

@ -1,4 +1,4 @@
*
!docker/entrypoint.sh
!docker/settings.toml
!docker-context/**
!tmp/docker-context/**

View file

@ -8,9 +8,6 @@ MINIMAX_API_KEY=
OPENAI_API_KEY=
ZAI_API_KEY=
FABRO_JWT_PRIVATE_KEY=
FABRO_JWT_PUBLIC_KEY=
SESSION_SECRET=
GITHUB_APP_CLIENT_SECRET=
GITHUB_APP_WEBHOOK_SECRET=

View file

@ -188,9 +188,9 @@ jobs:
x86_64-*) arch=amd64 ;;
aarch64-*) arch=arm64 ;;
esac
mkdir -p "docker-context/$arch"
mkdir -p "tmp/docker-context/$arch"
tar -xzf "target/distrib/fabro-${target}.tar.gz" -C target/distrib
cp "target/distrib/fabro-${target}/fabro" "docker-context/$arch/fabro"
cp "target/distrib/fabro-${target}/fabro" "tmp/docker-context/$arch/fabro"
done
- uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0

1
.gitignore vendored
View file

@ -1,5 +1,4 @@
target
docker-context/
.env
.entire
node_modules

View file

@ -25,7 +25,7 @@ macOS note: if `cargo nextest run` fails with `Too many open files (os error 24)
- `cargo dev refresh-spa` — **run this before committing any TypeScript change in `apps/fabro-web/` or `lib/packages/fabro-api-client/`**. It runs the production build and then copies `dist/` into `lib/crates/fabro-spa/assets/` (which is tracked in git). CI's TypeScript `Build` job reruns this command and then `git diff --exit-code -- lib/crates/fabro-spa/assets` — if the committed bundle drifts from source (e.g. content-hashed filenames like `entry-<hash>.js` change), the check fails. `bun run build` on its own is not enough.
### Docker image
- `cargo dev docker-build` — builds the local Docker image from the current tree using the release pipeline's cargo-zigbuild approach. Honors `--arch amd64|arm64`, `--tag <name>` (default `fabro`), `--compile-only` (stages `docker-context/<arch>/fabro` without `docker build`), and `--dry-run` (prints the Docker commands without running them). Prefer this over writing a throwaway Dockerfile; the release pipeline, `Dockerfile`, and this command share the same binary layout.
- `cargo dev docker-build` — builds the local Docker image from the current tree using the release pipeline's cargo-zigbuild approach. Honors `--arch amd64|arm64`, `--tag <name>` (default `fabro`), `--compile-only` (stages `tmp/docker-context/<arch>/fabro` without `docker build`), and `--dry-run` (prints the Docker commands without running them). Prefer this over writing a throwaway Dockerfile; the release pipeline, `Dockerfile`, and this command share the same binary layout.
- Refresh the embedded SPA before rebuilding the image after any `apps/fabro-web` change: `cargo dev refresh-spa` runs the bun build and copies `dist/` into `lib/crates/fabro-spa/assets/`. Skipping this step produces a Docker image whose Rust binary embeds a stale SPA bundle.
### Release automation
@ -102,7 +102,7 @@ When working on Rust crates, read the relevant strategy doc **before** making ch
- **`docs-internal/logging-strategy.md`** — read when adding `tracing` calls (`info!`, `debug!`, `warn!`, `error!`), working on error handling paths, or adding new operations that should be observable
- **`docs-internal/events-strategy.md`** — read when adding or modifying `Event` variants, touching `Emitter`/`emit()`, changing `progress.jsonl` output, or adding new workflow stage types
- **`files-internal/testing-strategy.md`** — read when adding or reorganizing tests, choosing between unit vs `tests/it`, deciding whether a test belongs in `cmd` vs `workflow` vs `scenario`, or deciding how to structure snapshots and fixtures
- **`docs-internal/testing-strategy.md`** — read when adding or reorganizing tests, choosing between unit vs `tests/it`, deciding whether a test belongs in `cmd` vs `workflow` vs `scenario`, or deciding how to structure snapshots and fixtures
- **`docs-internal/server-secrets-strategy.md`** — read when adding or changing server-level secrets, startup validation, install-time secret persistence, or subprocess env inheritance/scrubbing
## Shell quoting in sandbox code

View file

@ -3,8 +3,8 @@
# Runtime image for the Fabro server.
#
# Binaries are supplied pre-built via the release workflow:
# docker-context/amd64/fabro (x86_64-unknown-linux-musl)
# docker-context/arm64/fabro (aarch64-unknown-linux-musl)
# tmp/docker-context/amd64/fabro (x86_64-unknown-linux-musl)
# tmp/docker-context/arm64/fabro (aarch64-unknown-linux-musl)
#
# The image serves the HTTP API (with embedded web UI) on $PORT (default
# 32276), persists state to /storage, and runs as the unprivileged `fabro`
@ -26,7 +26,7 @@ RUN apk add --no-cache \
&& adduser -S -u 1000 -G fabro -h /var/fabro -s /sbin/nologin fabro \
&& install -d -o fabro -g fabro -m 0755 /var/fabro /storage
COPY --chmod=0755 docker-context/${TARGETARCH}/fabro /usr/local/bin/fabro
COPY --chmod=0755 tmp/docker-context/${TARGETARCH}/fabro /usr/local/bin/fabro
COPY --chmod=0755 docker/entrypoint.sh /usr/local/bin/fabro-entrypoint

View file

@ -1,15 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
openssl genpkey -algorithm Ed25519 -out fabro-jwt-private.pem
openssl pkey -in fabro-jwt-private.pem -pubout -out fabro-jwt-public.pem
echo ""
echo "Generated:"
echo " fabro-jwt-private.pem (private key — for fabro-web / FABRO_JWT_PRIVATE_KEY)"
echo " fabro-jwt-public.pem (public key — for fabro-workflow / FABRO_JWT_PUBLIC_KEY)"
echo ""
echo "Set env vars with the PEM contents (including header/footer lines):"
echo ""
echo ' export FABRO_JWT_PRIVATE_KEY="$(cat fabro-jwt-private.pem)"'
echo ' export FABRO_JWT_PUBLIC_KEY="$(cat fabro-jwt-public.pem)"'

View file

@ -34,7 +34,9 @@ This starts the server on a Unix socket at `~/.fabro/fabro.sock` by default. Use
### First run: web install wizard
If `~/.fabro/settings.toml` does not yet exist, `fabro server start` enters **install mode**: it prints an install URL, attempts to open the URL in your default browser, and serves a web wizard that walks you through configuring your server URL, shared object store, LLM provider, and GitHub integration.
If `~/.fabro/settings.toml` does not yet exist, `fabro server start` enters **install mode**: it prints an install URL and a one-time install token, attempts to open the URL in your default browser, and serves a web wizard that walks you through configuring your server URL, shared object store, LLM provider, and GitHub integration.
When Fabro can construct a direct install URL, the token is embedded in the URL and also printed on its own line for copying. If you open the server root through a reverse proxy or another machine, paste the printed install token when prompted.
The `Object store` step offers two wizard-managed modes:
@ -87,6 +89,8 @@ The web UI connects to the API server and provides:
- **Runs board** — Monitor all active runs organized by status
- **Run detail** — Real-time stage progress, event stream, diffs, and usage stats
- **Files Changed** — Browse changed files with a searchable tree, per-file status, aggregate diff stats, and split or stacked diffs
- **Settings** — Inspect server configuration, enabled integrations, storage, auth, and capacity settings
- **Start new run** — Submit workflows from the browser
- **Human-in-the-loop** — Answer agent questions through the web interface
- **Workflows** — Browse available workflows, view their graphs, and see run history
@ -145,6 +149,12 @@ Or use the `--server` flag:
fabro model list --server https://fabro.example.com/api/v1
```
For dev-token servers, save the token in the CLI auth store instead of exporting it for every command:
```bash
fabro auth login --server https://fabro.example.com/api/v1 --dev-token fabro_dev_...
```
`fabro model list` and `fabro model test` honor `[cli.target]` by default unless you explicitly pass `--storage-dir`. `fabro exec` remains a local agent session and only uses the server when you pass `--server`.
See [User Configuration](/reference/user-configuration#cli-target-section) for the full connection options, including client certificates for proxy-terminated HTTPS endpoints.

View file

@ -1,5 +1,5 @@
---
title: "Server-backed rewind and fork"
title: "Server-backed rewind, setup polish, and diff stats"
date: "2026-04-24"
---
@ -28,27 +28,50 @@ The source run records which run superseded it, so archived run history keeps a
`fabro fork`, `fabro rewind`, and their `--list` modes now use the server API. The server must be able to read the run's recorded working directory. Timeline listing no longer rebuilds a missing metadata branch; if the metadata branch is gone, the timeline is empty until metadata is restored.
## Smoother setup and local auth
Self-hosted setup is easier to complete from the browser and the CLI. The install wizard now works from the server root, exposes the local object store root, treats the AWS access key ID as readable text, and the server start banner prints the install token on its own copyable line.
Dev-token credentials are now stored in the same auth store as OAuth credentials, so CLI targets resolve credentials consistently whether the server is reached through TCP or a Unix socket.
```bash
fabro auth login --dev-token
```
## More
<Accordion title="API">
- New `POST /api/v1/runs/{id}/rewind` endpoint creates the replacement run and archives the source run
- New `POST /api/v1/runs/{id}/fork` endpoint forks a run from the server-side run record
- New `GET /api/v1/runs/{id}/timeline` endpoint returns checkpoint timeline entries from run metadata
- `GET /api/v1/runs/{id}/files` responses now include aggregate additions and deletions in `meta.stats`
- Install prefill and object-store responses now include local object store root details
- Run summaries now include `superseded_by` data for rewound source runs
</Accordion>
<Accordion title="CLI">
- Removed the obsolete `fabro pr list` command
- `fabro fork`, `fabro rewind`, and timeline listing now call the server API
- Fatal CLI errors now use styled diagnostics while preserving exit codes, telemetry, and auth help hints
- Server start output now prints the install token on a separate copyable line
- Added `fabro auth login --dev-token` for saving dev-token credentials in the auth store
</Accordion>
<Accordion title="Workflows">
- Disabled git signing for sandbox checkpoint commits so local signing configuration does not block workflow bookkeeping
</Accordion>
<Accordion title="Improvements">
- Run Files now shows aggregate `+/-` diff stats beside the file count
- Run Files now uses a PR-style header with captured time, refresh, and Split/Stacked controls in one row
- Credentials embedded in URLs are redacted in logs and error output
- CLI and user-configuration reference docs are generated and checked for drift
- Updated the quick start with supported platform details
- Fixed Mintlify MDX parsing in planning docs
- Simplified server-side pull request creation plumbing around run and GitHub context loading
</Accordion>
<Accordion title="Fixes">
- Fixed the install wizard not mounting at the root route
- Fixed the local object store root missing from install wizard configuration
- Changed the AWS access key ID field to a readable text input
- Changed the install wizard token field to a single-line input
- Refreshed the embedded web assets for the rewind and install UI changes
</Accordion>

View file

@ -0,0 +1,28 @@
---
title: "Files Changed sidebar and settings panels"
date: "2026-04-25"
---
## Files Changed sidebar
Large diffs are easier to navigate from the run detail page. The Files Changed tab now has a GitHub-style file tree sidebar that lists only changed files, shows each file's git status, supports search, and keeps selection tied to the existing `#file=<path>` deep-link behavior.
Clicking a file in the tree scrolls and focuses the matching diff, while mobile layouts keep the stacked diff view uncluttered. The tree lazy-loads on desktop and reserves its column while loading, so the diff layout no longer jumps as sidebar data arrives.
## Settings panels
The Settings page now presents server configuration as curated panels instead of a raw JSON dump. Server, access, integration, and artifact values are rendered with typed controls and readable summaries, so operators can scan what matters without parsing the full settings payload.
## More
<Accordion title="Improvements">
- Added the captured commit short SHA to the Files Changed freshness label
- Unboxed the Files Changed tree so it sits directly in the sidebar layout
- Styled web OAuth callback state-validation errors with the same browser shell as the CLI auth flow
</Accordion>
<Accordion title="Fixes">
- Fixed aggregate diff stats counting sensitive, binary, symlink, and submodule entries that are not visible in the diff
- Fixed Files Changed tree selection so it only targets valid file paths after filtering or reloads
- Fixed sidebar loading and filtering behavior to keep the desktop layout stable
</Accordion>

View file

@ -252,6 +252,7 @@
"group": "April 2026",
"icon": "clock-rotate-left",
"pages": [
"changelog/2026-04-25",
"changelog/2026-04-24",
"changelog/2026-04-23",
"changelog/2026-04-22",

View file

@ -39,6 +39,8 @@ The commit message follows a structured format:
The `Fabro-Checkpoint` trailer links each run branch commit to its metadata branch commit, so you can navigate from file changes to the full execution state and back.
Fabro disables Git commit and tag signing for checkpoint commits created inside a sandbox. Your personal or repository-level signing settings can stay enabled, but sandbox bookkeeping does not need access to your signing key.
### Metadata branch
The metadata branch (`fabro/meta/{run_id}`) is an orphan branch that stores structured run data using Git's object storage directly (via `git2`). It is initialized at run start with:

View file

@ -96,7 +96,7 @@ No billing / usage / reporting site reads `is_terminal()` — those roll up from
No `docs/solutions/` entries exist in this repo; the institutional-knowledge base is empty. Substitute docs to follow:
- `docs-internal/events-strategy.md` (the 7-step event checklist)
- `files-internal/testing-strategy.md` (layering: `cmd/*` for single-command CLI tests, `scenario/*` for cross-command lifecycle)
- `docs-internal/testing-strategy.md` (layering: `cmd/*` for single-command CLI tests, `scenario/*` for cross-command lifecycle)
- `AGENTS.md` §"API workflow" (OpenAPI source-of-truth and regen sequence) and §"Rust import style" (types by name, functions via parent module)
### External References
@ -554,7 +554,7 @@ flowchart TB
- **Origin document:** [docs/brainstorms/2026-04-19-run-archived-status-requirements.md](../brainstorms/2026-04-19-run-archived-status-requirements.md)
- **Events strategy:** [docs-internal/events-strategy.md](../../docs-internal/events-strategy.md)
- **Testing strategy:** [files-internal/testing-strategy.md](../../files-internal/testing-strategy.md)
- **Testing strategy:** [docs-internal/testing-strategy.md](../../docs-internal/testing-strategy.md)
- **API workflow convention:** `AGENTS.md` §"API workflow"
- **Bulk-by-ID CLI template:** `lib/crates/fabro-cli/src/commands/runs/rm.rs`
- **Actor-carrying event precedent:** `lib/crates/fabro-workflow/src/event.rs:93-96` (`RunCancelRequested`)

View file

@ -64,7 +64,7 @@ Those behaviors were survivable when the CLI and server were assumed to live on
### Institutional Learnings
- No `docs/solutions/` directory exists in this repository, so there are no institutional learnings to carry forward from that source.
- `files-internal/testing-strategy.md` reinforces the right split for this work:
- `docs-internal/testing-strategy.md` reinforces the right split for this work:
- connection/auth selection logic should get crate-level tests
- single-command contract regressions should stay in `tests/it/cmd`
- cross-command auth or exec narratives should stay in `tests/it/scenario`
@ -322,7 +322,7 @@ flowchart TB
- Update docs/help copy anywhere it still implies that explicit `--server` may inherit local daemon identity or local dev-token convenience.
**Patterns to follow:**
- `files-internal/testing-strategy.md` placement rules for crate-level vs `cmd/*` vs `scenario/*`
- `docs-internal/testing-strategy.md` placement rules for crate-level vs `cmd/*` vs `scenario/*`
- existing real auth harness organization in `lib/crates/fabro-cli/tests/it/support/auth_harness.rs`
**Test scenarios:**
@ -386,4 +386,4 @@ flowchart TB
- `lib/crates/fabro-cli/tests/it/scenario/auth.rs`
- `lib/crates/fabro-cli/tests/it/support/auth_harness.rs`
- Repo guidance:
- `files-internal/testing-strategy.md`
- `docs-internal/testing-strategy.md`

View file

@ -96,7 +96,7 @@ These were all reasonable while the client had exactly one caller. They prevent
- No `docs/solutions/` directory in this repo — no prior captured learnings apply. Historical plans in `docs/plans/` around CLI/server boundary (`2026-04-02-001-feat-server-daemon-management-plan.md`, `2026-04-05-cli-deglobalize-server-url-and-storage-dir-plan.md`, `2026-04-20-001-fix-cli-server-same-host-assumptions-plan.md`) have tightened the target-resolution contract progressively. This plan's `fabro-client` extraction is the next step in that direction: after target resolution became disciplined, pull the pure client *out* of the CLI and make its purity enforceable by the crate graph.
- `CLAUDE.md` reminds: "We want the simplest change possible. We don't care about migration. Code readability matters most, and we're happy to make bigger changes to achieve it." We lean on this for the `ServerTarget` canonicalization change and the "delete the alias" step in the `Client` rename we just finished.
- `files-internal/testing-strategy.md` — most existing CLI tests exercise the client through CLI-level commands; those tests continue to live in `fabro-cli` and don't need to migrate. Tests of internal helpers (auth-store round-trips, `ServerTargetKey` canonicalization, loopback classification, SSE parsing, dev-token resolution) fall into three buckets: (a) auth-store/SSE/loopback/ServerTarget tests migrate to `fabro-client`; (b) dev-token resolution tests stay in `fabro-cli`; (c) server-client unit tests for refresh-token transport checks migrate.
- `docs-internal/testing-strategy.md` — most existing CLI tests exercise the client through CLI-level commands; those tests continue to live in `fabro-cli` and don't need to migrate. Tests of internal helpers (auth-store round-trips, `ServerTargetKey` canonicalization, loopback classification, SSE parsing, dev-token resolution) fall into three buckets: (a) auth-store/SSE/loopback/ServerTarget tests migrate to `fabro-client`; (b) dev-token resolution tests stay in `fabro-cli`; (c) server-client unit tests for refresh-token transport checks migrate.
### External References

View file

@ -51,7 +51,7 @@ That mismatch leaks implementation history into the domain model and makes every
- `lib/crates/fabro-workflow/src/lifecycle/git.rs` and `lib/crates/fabro-workflow/src/pipeline/finalize.rs` still use phase-specific `RunDump` constructors and a `checkpoint.json`-oriented metadata helper.
- `lib/crates/fabro-workflow/src/operations/{fork.rs,rewind.rs,rebuild_meta.rs}` plus `lib/crates/fabro-cli/src/commands/run/rewind.rs` are the critical metadata readers/writers that must switch from standalone `checkpoint.json` and `start.json` reads to projection reads.
- `lib/crates/fabro-types/src/stage_id.rs` already defines `Display` as `{node_id}@{visit}`, which should become the on-disk stage directory name.
- `files-internal/testing-strategy.md` says CLI integration tests should remain command-driven and black-box; layout-specific assertions belong in the right layer rather than by planting run internals by hand.
- `docs-internal/testing-strategy.md` says CLI integration tests should remain command-driven and black-box; layout-specific assertions belong in the right layer rather than by planting run internals by hand.
### Institutional Learnings
@ -95,7 +95,7 @@ That mismatch leaks implementation history into the domain model and makes every
- Exact helper names for the new metadata commit writer (`write_snapshot`, `write_projection_commit`, etc.). The plan fixes the API shape and intent, but the final Rust name can be chosen during implementation.
- Whether the shared export builder stays in `lib/crates/fabro-workflow/src/run_dump.rs` or moves to a nearby module. The key constraint is one authoritative layout builder, not a specific file name.
- Whether any low-value tests should move layers while being updated. Follow `files-internal/testing-strategy.md` if implementation reveals a better layer, but do not turn this refactor into a broad test reorganization.
- Whether any low-value tests should move layers while being updated. Follow `docs-internal/testing-strategy.md` if implementation reveals a better layer, but do not turn this refactor into a broad test reorganization.
## High-Level Technical Design
@ -299,11 +299,11 @@ Durable event store
**Approach:**
- Update retro agent instructions and sandbox uploads so the agent reads `run.json` projection data plus `graph.fabro` and stage files instead of `checkpoint.json` and `start.json`.
- Rename or replace tests that currently assert `conclusion.json` or old `nodes/...` layouts so they assert conclusion presence inside `run.json` and stage files under `stages/`.
- Keep CLI integration tests black-box per `files-internal/testing-strategy.md`; layout assertions should come from public command behavior or crate-level tests, not hand-planted run internals.
- Keep CLI integration tests black-box per `docs-internal/testing-strategy.md`; layout assertions should come from public command behavior or crate-level tests, not hand-planted run internals.
- Review snapshot diffs before accepting them because this refactor intentionally changes many file paths and exported filenames.
**Patterns to follow:**
- Snapshot discipline in `files-internal/testing-strategy.md`
- Snapshot discipline in `docs-internal/testing-strategy.md`
- Existing retro upload flow in `lib/crates/fabro-retro/src/retro_agent.rs`
**Test scenarios:**
@ -351,4 +351,4 @@ Durable event store
- `lib/crates/fabro-checkpoint/src/metadata.rs`
- `lib/crates/fabro-workflow/src/operations/{fork.rs,rewind.rs,rebuild_meta.rs}`
- `lib/crates/fabro-cli/src/commands/{store/dump.rs,store/run_export.rs,run/rewind.rs}`
- Related guidance: `files-internal/testing-strategy.md`
- Related guidance: `docs-internal/testing-strategy.md`

View file

@ -132,7 +132,7 @@ behavior and avoids turning `CommandContext` into a new god object.
`lib/crates/fabro-cli/src/commands/provider/mod.rs` — the clearest
examples of raw `process_local_json` still being threaded despite the
rest of the state already belonging to the invocation.
- `files-internal/testing-strategy.md` — CLI integration tests should
- `docs-internal/testing-strategy.md` — CLI integration tests should
stay command-driven and black-box, with implementation-facing behavior
covered by unit tests near the code.
- `lib/crates/fabro-cli/src/commands/sandbox/mod.rs` — the real public
@ -828,7 +828,7 @@ command tree is consistently aligned on `CommandContext`.
`lib/crates/fabro-cli/src/commands/auth/mod.rs`
`lib/crates/fabro-cli/src/commands/provider/mod.rs`
`lib/crates/fabro-cli/src/commands/system/mod.rs`
- Testing guidance: `files-internal/testing-strategy.md`
- Testing guidance: `docs-internal/testing-strategy.md`
- Related history:
`93b6577cd simplify: drop duplicate settings plumbing from cli/server refactor`
`367fd9302 refactor(cli): centralize command settings and server access`

View file

@ -987,7 +987,7 @@ impl fabro_options_metadata::OptionsMetadata for RunArgs {
- **fabro strategy docs:**
- `docs-internal/logging-strategy.md` (Phase 2 alignment)
- `docs-internal/server-secrets-strategy.md` (Phase 1 constraint: no env mutation)
- `files-internal/testing-strategy.md` (Phase 3 guidance)
- `docs-internal/testing-strategy.md` (Phase 3 guidance)
- **AGENTS.md:** `/Users/bhelmkamp/p/fabro-sh/fabro-3/AGENTS.md` (nightly clippy, strum, insta workflow, refresh-spa mandate).
- **External docs:**
- `miette`: https://docs.rs/miette/

View file

@ -346,7 +346,7 @@ Install-mode failures report to Sentry via `fabro-telemetry` with the existing a
## Testing strategy
Per `files-internal/testing-strategy.md` (re-read before implementing).
Per `docs-internal/testing-strategy.md` (re-read before implementing).
### Unit tests (`fabro-install` crate)

View file

@ -117,7 +117,7 @@ impl DockerBuildPlan {
if self.compile_only {
println!(
"Staged docker-context/{}/fabro (skipping docker build per --compile-only).",
"Staged tmp/docker-context/{}/fabro (skipping docker build per --compile-only).",
self.arch
);
return Ok(());
@ -135,7 +135,7 @@ impl DockerBuildPlan {
self.extract_command().to_shell_line(),
];
if self.compile_only {
lines.push(format!("staged docker-context/{}/fabro", self.arch));
lines.push(format!("staged tmp/docker-context/{}/fabro", self.arch));
} else {
lines.push(self.image_build_command().to_shell_line());
}
@ -202,12 +202,13 @@ impl DockerBuildPlan {
fn context_dir(&self) -> PathBuf {
self.workspace_root
.join("tmp")
.join("docker-context")
.join(self.arch.to_string())
}
fn relative_context_dir(&self) -> String {
format!("docker-context/{}", self.arch)
format!("tmp/docker-context/{}", self.arch)
}
}

View file

@ -83,7 +83,7 @@ fn dry_run_compile_only_skips_image_build() {
let stdout = output_text(&output.stdout);
assert!(
stdout.contains("docker-context/arm64/fabro"),
stdout.contains("tmp/docker-context/arm64/fabro"),
"dry-run compile-only should print staged binary path:\n{stdout}"
);
assert!(