Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,6 @@ uffs-mcp-claude-video.mp4

# rustc ICE dumps (transient nightly "delayed bug" reports; never commit)
rustc-ice-*.txt

# docenta: local inclusion policy (the quarantine whitelist), never committed
.docentaignore
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.6.40] - 2026-08-31

### Changed

- cli: move the four pre-#436 command entry points out of main.rs

## [0.6.38] - 2026-08-24

### Added
Expand Down Expand Up @@ -2839,7 +2845,8 @@ thin clients over a unified `uffsd` process.
### Fixed
- Various MFT parsing edge cases

[Unreleased]: https://github.com/skyllc-ai/UltraFastFileSearch/compare/v0.6.38...HEAD
[Unreleased]: https://github.com/skyllc-ai/UltraFastFileSearch/compare/v0.6.40...HEAD
[0.6.40]: https://github.com/skyllc-ai/UltraFastFileSearch/compare/v0.6.38...v0.6.40
[0.6.38]: https://github.com/skyllc-ai/UltraFastFileSearch/compare/v0.6.37...v0.6.38
[0.6.37]: https://github.com/skyllc-ai/UltraFastFileSearch/compare/v0.6.36...v0.6.37
[0.6.36]: https://github.com/skyllc-ai/UltraFastFileSearch/compare/v0.6.35...v0.6.36
Expand Down
52 changes: 26 additions & 26 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 14 additions & 14 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ members = [
# Workspace Package Metadata (inherited by all crates)
# ─────────────────────────────────────────────────────────────────────────────
[workspace.package]
version = "0.6.39"
version = "0.6.40"
edition = "2024"
# No `rust-version` claim: the workspace is structurally nightly-only.
# `crates/uffs-polars` enables `polars/nightly` unconditionally, which
Expand Down Expand Up @@ -135,36 +135,36 @@ publish = false
# proposed-plan output for 12 days because `release-plz update`
# failed at `cargo package` with this very error. See
# `release-automation-baseline.md` §10 for the diagnostic trail.
uffs-polars = { path = "crates/uffs-polars", version = "0.6.39" }
uffs-security = { path = "crates/uffs-security", version = "0.6.39" }
uffs-text = { path = "crates/uffs-text", version = "0.6.39" }
uffs-time = { path = "crates/uffs-time", version = "0.6.39" }
uffs-version = { path = "crates/uffs-version", version = "0.6.39" }
uffs-statusfmt = { path = "crates/uffs-statusfmt", version = "0.6.39" }
uffs-mft = { path = "crates/uffs-mft", version = "0.6.39" }
uffs-format = { path = "crates/uffs-format", version = "0.6.39" }
uffs-core = { path = "crates/uffs-core", version = "0.6.39" }
uffs-client = { path = "crates/uffs-client", version = "0.6.39" }
uffs-polars = { path = "crates/uffs-polars", version = "0.6.40" }
uffs-security = { path = "crates/uffs-security", version = "0.6.40" }
uffs-text = { path = "crates/uffs-text", version = "0.6.40" }
uffs-time = { path = "crates/uffs-time", version = "0.6.40" }
uffs-version = { path = "crates/uffs-version", version = "0.6.40" }
uffs-statusfmt = { path = "crates/uffs-statusfmt", version = "0.6.40" }
uffs-mft = { path = "crates/uffs-mft", version = "0.6.40" }
uffs-format = { path = "crates/uffs-format", version = "0.6.40" }
uffs-core = { path = "crates/uffs-core", version = "0.6.40" }
uffs-client = { path = "crates/uffs-client", version = "0.6.40" }
# `uffs-broker-protocol` carries the wire-protocol types shared between
# `uffs-broker` (the elevated handle vendor, Windows-only binary) and
# `uffs-daemon::broker_client` (the handle consumer). Pure-logic
# Layer-0 lib — cross-platform tests run on every CI lane. Added in
# F5 (issue #205) so neither side duplicates `BROKER_PIPE_NAME` /
# wire-format byte literals.
uffs-broker-protocol = { path = "crates/uffs-broker-protocol", version = "0.6.39" }
uffs-broker-protocol = { path = "crates/uffs-broker-protocol", version = "0.6.40" }
# `uffs-winsvc` — native Windows service control (SCM query/start/stop) +
# the non-connecting broker-pipe readiness probe. Layer-0 leaf: its only
# dependency is the `windows` crate (windows-target), with non-Windows
# stubs so cross-platform consumers (uffs-update, uffs-cli) compile.
# Single source of truth for the `sc`/SCM mechanics previously duplicated
# across uffs-broker, uffs-update, and uffs-cli.
uffs-winsvc = { path = "crates/uffs-winsvc", version = "0.6.39" }
uffs-winsvc = { path = "crates/uffs-winsvc", version = "0.6.40" }
# `uffs-fetch` — hardened release-asset transport (blocking reqwest +
# rustls with retry/timeout/byte-cap, plus `SHA256SUMS` verification),
# extracted from `uffs-update` as a small public lib so external products
# can reuse it. Cross-platform pure-logic leaf; keeps the HTTP/TLS stack
# out of the lean `uffs` CLI exactly as before.
uffs-fetch = { path = "crates/uffs-fetch", version = "0.6.39" }
uffs-fetch = { path = "crates/uffs-fetch", version = "0.6.40" }
# NOTE: no `uffs-broker` workspace dependency alias on purpose —
# `uffs-broker` is a binary-only crate (the only `[lib]` it carries is
# this protocol module's now-extracted sibling); no other workspace
Expand Down
14 changes: 8 additions & 6 deletions crates/uffs-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,20 @@ path = "src/main.rs"
# Not using `.workspace = true` here: workspace inheritance cannot
# override `default-features`, so we point at the path directly. The
# version is pinned by the workspace via path dependency resolution.
# `version = "0.5.90"` is required for `cargo package` validation —
# see root `Cargo.toml`'s [workspace.dependencies] note for the full
# The explicit `version = "…"` (kept in step with the workspace version
# by the release bump) is required for `cargo package` validation — see
# root `Cargo.toml`'s [workspace.dependencies] note for the full
# rationale (R6 of `release-automation-plan.md`).
uffs-client = { path = "../uffs-client", version = "0.6.39", default-features = false }
uffs-client = { path = "../uffs-client", version = "0.6.40", default-features = false }

# Canonical CSV / parity / legacy-footer writer. Direct dep (not a
# re-export chain through `uffs-client`) so the CLI and the daemon
# hit the same `uffs_format::*` symbols without an indirection layer.
# `version = "0.5.90"` is required for `cargo package` validation —
# see root `Cargo.toml`'s [workspace.dependencies] note for the full
# The explicit `version = "…"` (kept in step with the workspace version
# by the release bump) is required for `cargo package` validation — see
# root `Cargo.toml`'s [workspace.dependencies] note for the full
# rationale (R6 of `release-automation-plan.md`).
uffs-format = { path = "../uffs-format", version = "0.6.39" }
uffs-format = { path = "../uffs-format", version = "0.6.40" }

# Typed drive-letter newtype. Direct dep so the CLI command signatures
# (`daemon_load`, `daemon_tiering`, etc.) name `DriveLetter` natively
Expand Down
25 changes: 25 additions & 0 deletions crates/uffs-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,31 @@ The "thin client" design has three concrete consequences:
CLI auto-spawns the daemon if it isn't already running; subsequent
invocations reuse the daemon over the warm socket.

### Why the fast path parses its arguments by hand

`uffs-cli` has no `clap` dependency, on purpose. The cross-tool
benchmark (`docs/research/cross-tool-benchmark-analysis.md`, §4.1.1)
measured Windows process creation at **~12 ms + ~2.7 ms per MB of
binary**: the original 52.7 MB fat client took 152 ms to start, 136 ms
of it before `main()` ran. Parsing was never the cost — a clap
`Cli::parse()` is ~1 ms — the *weight* was. So the thin client dropped
Polars, tokio, tracing and clap together and went from 52.7 MB to
~774 KB (Phase 1, v0.5.x). What is left is a handful of `--flag`
matches in `src/args.rs` and `src/commands/search/args.rs`; the real
search-grammar validation is `SearchParams::from_cli_args` in
`uffs-client`, shared with the daemon, so the CLI never re-implements
it.

clap stays where startup does not matter: `uffs-mft`, `uffs-daemon`,
`uffs-mcp` and `uffs-bench`.

To re-measure on a release box (PowerShell, elevated shell not needed):

```powershell
(Get-Item (Get-Command uffs).Source).Length / 1KB # binary size, KB
1..10 | ForEach-Object { (Measure-Command { uffs --version }).TotalMilliseconds }
```

## Install

```bash
Expand Down
19 changes: 18 additions & 1 deletion crates/uffs-cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,9 @@ pub(crate) use help::{
mod tests {
use core::error::Error as _;

use super::{DaemonAction, ParseDriveLetterError, parse_daemon_action, parse_drive_letter};
use super::{
DaemonAction, DriveLetter, ParseDriveLetterError, parse_daemon_action, parse_drive_letter,
};

/// `BadShape` carries the original input and its Display matches the
/// byte-for-byte format the previous `Result<_, String>` produced.
Expand Down Expand Up @@ -769,4 +771,19 @@ mod tests {
"two drives must be rejected",
);
}

#[test]
fn parse_drive_letter_accepts_letter_colon_and_whitespace_variants() {
assert_eq!(parse_drive_letter("c"), Ok(DriveLetter::C));
assert_eq!(parse_drive_letter("C:"), Ok(DriveLetter::C));
assert_eq!(parse_drive_letter(" d: "), Ok(DriveLetter::D));
}

#[test]
fn parse_drive_letter_rejects_invalid_values() {
parse_drive_letter("").unwrap_err();
parse_drive_letter("12").unwrap_err();
parse_drive_letter("1:").unwrap_err();
parse_drive_letter("CD").unwrap_err();
}
}
Loading
Loading