* ci: install rustfmt and clippy components on every runner
Self-hosted runners have rustc preinstalled, so setup-rust skipped the
dtolnay/rust-toolchain step that added the components and the Rust
Formatting job died with 'cargo-fmt is not installed'. Add the components
to rust-toolchain.toml and run rustup component add unconditionally.
* setup: install FFmpeg development libraries on Linux and macOS
crates/ffmpeg is a default workspace member that links libav* through
ffmpeg-sys-next, so a fresh machine fails the first cargo build with
'libavutil.pc not found'. Install the libav dev packages and pkg-config
from scripts/setup.sh for every supported package manager, warn from
xtask setup when pkg-config cannot find them, and document the requirement
in the README build section.
* test: call the trash directly in delete_strategy_test
bcc7337 gave LocalDeleteStrategy::move_to_trash a JobContext parameter so
it can record where the item went; the integration test still passed one
argument and stopped every cargo test target from compiling. The two trash
cases now call ops::files::trash::trash with the same arguments the
strategy forwards, which is what they were asserting on.
* interface: clear the 30 Tauri typecheck errors
Remove the 23 unused imports and locals, apply the rename rules' serde
defaults (regex and whole_name false, start and step 1) where the modal
renders optional fields, drop the size prop ToggleGroup never accepted,
and type SourceCard on ts-client's SourceInfo so a filesystem source with
no adapter renders its data type instead. Register the /redundancy/duplicates
route the dashboard already navigates to, which is what the DuplicatesView
import was for.
* clippy: make cargo clippy --workspace -D warnings pass on Linux
sd-store names its sqlx row tuples with type aliases. sd-ffmpeg converts
with try_from and f32::from where the cast was lossless, takes raw
borrows for FFI out-pointers, resamples from an integer position, and
allows the pointer-alignment and s32-to-f32 precision casts with the
reason. sd-mobile-core sets DaemonRequest.device (None, local execution)
on the two envelopes it builds. file-opening-macos and file-opening-windows
pull their platform bindings only on that target and gate their sources,
matching sd-desktop-macos. The Tauri build script drops externalBin from
the config when no daemon sidecar exists, so a check or clippy run that
never built the daemon still passes, and the desktop binary's macOS-only
commands return on other hosts without unreachable code. Workspace
rust-version moves to 1.95, the floor gpui already imposes, so the MSRV
lint stops flagging APIs the pinned 1.97.1 toolchain uses.
* docs: make the stale doctests compile
sd-media-metadata examples still imported from the old image module and
asserted a plus code that belonged to the other example's coordinates (the
value is verified against the reference Open Location Code encoder);
MediaLocation has no Display, so the parse example compares coordinates.
The sd-task-system example unwraps dispatch and matches the (TaskId,
TaskOutput) pair Done now carries. The spacedrive-sdk sketch names types
that do not exist yet and the job-derive expansion only resolves inside
sd-core, so both are marked ignore with the reason beside them.
* build: pin bun to 1.3.4 everywhere
package.json said bun@1.3.0 while CI installed 1.3.4, and any newer bun
rewrites bun.lockb on install, so the lockfile churned on every machine.
Pin packageManager to the CI version, document it, and install with
--frozen-lockfile in the TypeScript job so a drifting lockfile fails
instead of being silently rewritten.
* status: register the CI green on sources work and the libav requirement
* docs: make the sd-core doctests compile too
Five sd-core examples referenced the crate by its old name, used an arrow
glyph in a rust fence, or called methods without the trait in scope; the
copy strategy sketch needs a running JobContext so it is marked ignore.
* ci: stop shrinking the runner's root disk before installing a toolchain
easimon/maximize-build-space moves the root filesystem's free space into an
LVM volume mounted at the workspace and leaves root with the reserve, which
on the Blacksmith runner came out at 100 MB after the swap file. rustup
installs the pinned 1.97.1 toolchain under /home/runner/.rustup on root, so
both Rust jobs died with 'No space left on device'. The runner has 82 GB
free on root, which is plenty for a clippy target directory, so the step
goes.
* ci: run clippy on the Ubuntu 24.04 Blacksmith runner; let sd-server check without bun
The Blacksmith migration wrote the runner label into the matrix's target
field and left runs-on at GitHub's ubuntu-22.04, whose FFmpeg 4.4 predates
the libav 6 API sd-ffmpeg uses (ch_layout, av_dict_iterate), so the job
could never compile sd-ffmpeg. It now runs on blacksmith-4vcpu-ubuntu-2404
with FFmpeg 6.1, the same as a developer machine on 24.04, and the target
field holds a target triple again.
sd-server's build script skipped the web build when bun was absent and
RustEmbed then failed on the missing apps/web/dist. A debug build now gets
an empty dist with a warning so check and clippy pass; a release build
without bun and without a prebuilt dist still refuses, so a server never
ships without its UI by accident.
* build: let the desktop crate compile without a built frontend
tauri::generate_context! panics when frontendDist is missing, which is how
every check or clippy run looks before bun run build. The build script now
creates an empty apps/tauri/dist for debug builds with a warning; a release
build without one still refuses.
* status: record the CI result for the sources green-up
Photos takes a focus on another device's folder and lists it through search.media. Cells keep their SdPath, so thumbnail requests go to the device that owns the files. Quick Look on a cell asks the data plane for the path on this machine: its own for a file here, answered in process, and its path inside the mounted share for one elsewhere, from files.local_path. Only the latest answer reaches the panel, so a cursor that has moved on is not pulled back. The device slug no longer holds a listing back.
Photos listed only a folder's direct children and never saw the explorer's
search, so searching from a folder of folders showed no photos.
search.media pages images and videos straight from source SQLite. Files come
out in the order the directory_path and sibling indexes already keep, so a
page reads its own rows and resumes from a (source, directory, name) cursor.
Extension, kind and hidden narrow in SQL; name, size, date and tags are
judged per row the way the store backend of search.files judges them. A
folder reaches its innermost source and any sources nested beneath it.
The navigation focus now carries the running search, and Photos lists it in
place of the folder. Folders list everything beneath them. Pages grow the
grid as they land, and tile identities name their drive's cache, so a
library-wide search across drives renders.
Opening the panel or handing it a new file loads the file before the call
returns, and the panel spins the event loop while it waits. Called from a
key action, that let gpui's main-thread tasks run while the action still
held the app, and the grid's frame watchdog panicked on the second borrow,
which aborts inside an FFI callback.
Requests now record the wanted file and the panel catches up on a later
turn of the main thread, with no gpui or RefCell borrow held across a
panel call. Posting real key events reproduced the abort on the old code
and runs clean now: Space opens, arrows follow, Esc closes, Space reopens.
Space opens the photo under the cursor in the system Quick Look panel, so
HEIC, RAW, and video open at full size straight from the file. Space or Esc
closes it.
A controller hung off the window's next responder takes control of the
panel and serves it the one file on show. Keys the panel doesn't use go
back to the gpui view, so the arrows still move the cursor and the preview
follows, and the number keys still tag in tag mode. On drop the controller
leaves the chain and the panel looks again, so it never holds a controller
that's gone.
Photos now selects the way the explorer does: click, cmd-click to toggle,
shift-click for a run, cmd-A, arrows, Esc to clear. T opens the same tag
bar the explorer has, with the library's first ten tags on the number keys.
A key takes its tag off the selection when every selected photo carries it
and puts it on all of them otherwise. Tagged tiles get dots in the corner.
The listing now carries each cell's record and tags, and the plane follows
the file rows the daemon announces. Indexing announces rows without their
tags, so a row naming none is believed only for records this window is
changing and read back with files.by_id otherwise. Tag changes queue on a
per-folder channel from the moment the folder is listed.
Nothing built spacedrive-native, so the Apps menu looked beside the desktop
binary, found nothing, and logged the error to the dev terminal only.
just dev-desktop now builds sd-native first. A failed build only warns,
since sd-native is not a default member and can trail core.
A launch that fails now shows a dialog. Photos quits when its window
closes, and launching it while it runs brings its window forward through
NSRunningApplication, which the launcher's doc already claimed it did.
sources.track skipped two steps volumes.index does. Without
ensure_restored a partition that never restored is barred from saving
over an existing snapshot, so tracking a root that already had one would
index and then fail to persist. Without clear_for_reindex, entries from a
previous pass that this one does not revisit linger in the arena as files
that no longer exist.
Also writes down how it differs from volumes.track, since the names
collide on the word rather than the meaning: volumes.track marks a medium
as belonging to a library and indexes nothing, this makes an index of
what is on one. volumes.index is the older overlap and retires once
callers move over, because it takes a fingerprint and can therefore only
ever mean a whole drive.
Photos no longer runs its own demo bake; it follows a Spacedrive explorer
window via a new navigation-focus resource and renders that window's
folder as a media grid, sourced from thumbnails baked by a new daemon-owned
thumbs service. Supporting changes: pvcache moves to a v2 format that
stores each tile's true aspect (envelope + frame) instead of forcing a
square crop, peer mounts now refresh on a generation check instead of only
at reconnect, and the archive crate's `spine` module is renamed to `record`
throughout.
apps/native runs an atlas grid over real thumbnails read through pvcache, with
sd-bake producing cells on a priority pool. Pinned to our zed fork; not in
default-members, so it stays out of the normal check.