docs: consolidate design documentation and standardize crate English
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
# fs-operation
|
||||
|
||||
Provides provider-side filesystem operations, bounded search, and pure text editing. Access checks and I/O for logical paths go through the provider's `FsAccessPolicy`. Does not own Workdir identity, Runtime transport, or Tool read history.
|
||||
|
||||
## Reference index
|
||||
|
||||
- [`FsAccessPolicy`] — provider access, I/O, and resource limits.
|
||||
- [`CheckedTarget`] — checked saves retaining descriptors and identity.
|
||||
- [`run_list`] — bounded live pagination.
|
||||
- [`run_glob`] / [`run_grep`] — provider-side search.
|
||||
- [`text`] — shared argument, UTF-8 byte limit, and edit result handling.
|
||||
@@ -1,9 +1,10 @@
|
||||
//! Identity-fenced access adapter for the existing read/edit/write engine.
|
||||
//! Identity-fenced access adapter for existing read/edit/write engines.
|
||||
//!
|
||||
//! Descriptor-rooted resolution is Linux-only and symlinks/mount crossings fail
|
||||
//! closed. The final compare and atomic rename are NOT a kernel CAS against an
|
||||
//! arbitrary external editor: external editors must cooperate with provider
|
||||
//! serialization. A hostile rename in that last syscall gap is not excluded.
|
||||
//! Retains target, save-parent, and provider-root descriptors to bind authorization to I/O.
|
||||
//! Rejects unavailable Linux descriptor primitives, symlinks, and mount crossings.
|
||||
//! Revalidates names/descriptors until just before save, but the final comparison and rename
|
||||
//! are not kernel CAS. Does not guarantee against noncooperative external editors replacing
|
||||
//! entries between those syscalls, or guarantee parent-directory crash durability.
|
||||
use crate::{AtomicWriteMode, FsAccessPolicy};
|
||||
use std::fs::{File, Metadata};
|
||||
use std::io::{Seek, SeekFrom};
|
||||
@@ -41,7 +42,17 @@ pub fn identity_validator(metadata: &Metadata) -> std::io::Result<Vec<u8>> {
|
||||
}
|
||||
}
|
||||
|
||||
/// One pinned target and its save parent. Retained through the shared operation.
|
||||
/// Target, save-parent, and root descriptors retained during shared operations.
|
||||
///
|
||||
/// Validators encode device/inode and protected metadata, detecting same-content replacements
|
||||
/// independently of content hashes. Excludes atime so Read does not invalidate its own observation.
|
||||
/// Saves publish a new temporary inode by rename; updating one hard-link name does not alter
|
||||
/// other aliases of the old inode.
|
||||
///
|
||||
/// Checks named targets and parents before commit, but cannot exclude external replacements between
|
||||
/// the final check and rename. Pinned descriptors alone do not guarantee linearizability against
|
||||
/// arbitrary external editors. Failures after parent creation or save begins report `effects_possible`
|
||||
/// to callers rather than implying no effects.
|
||||
pub struct CheckedTarget<'a> {
|
||||
policy: &'a dyn FsAccessPolicy,
|
||||
root: File,
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
//! Ignore rules loaded only through the provider's authorized descriptor opens.
|
||||
//! Never use GitignoreBuilder::add/build_global: those reopen host pathnames.
|
||||
//! Ignore rules read only through provider-authorized descriptors.
|
||||
//!
|
||||
//! .ignore takes precedence over Git rules; nearer directories win within the same source class.
|
||||
//! Retains only current ancestor matchers, pruning ignored directories before enumeration or reading
|
||||
//! their own rules. Checks scope before opening rule sources; configuration discovery never expands
|
||||
//! content authority.
|
||||
//!
|
||||
//! Glob requires an authorized .git marker; Grep applies .gitignore even without one.
|
||||
//! Glob skips unavailable sources; Grep preserves existing explicit errors. Both skip scope-denied
|
||||
//! sources before opening. UTF-8, file/line/aggregate byte limit, and cancellation violations are
|
||||
//! not turned into under-filtered success. Does not follow global/ambient Git configuration or
|
||||
//! linked-worktree gitdir/commondir pointers; .git files serve only as markers.
|
||||
use crate::{FsAccessPolicy, FsError};
|
||||
use ignore::gitignore::{Gitignore, GitignoreBuilder};
|
||||
use std::io::{BufRead, BufReader, Read};
|
||||
|
||||
@@ -5,7 +5,13 @@ use ignore::WalkBuilder;
|
||||
|
||||
use crate::{FsAccessPolicy, FsError, FsPath, GlobRequest, GlobResult};
|
||||
|
||||
/// Execute a bounded glob entirely inside the provider process.
|
||||
/// Bounded Glob within the provider process.
|
||||
///
|
||||
/// Descriptor providers check scope before reading ignore rules and prune denied directories
|
||||
/// before descent. .ignore takes precedence over Git rules; Git rules require an authorized .git
|
||||
/// marker. Unavailable rule sources are skipped; byte limit or cancellation violations yield errors.
|
||||
/// Does not follow ambient/global configuration or linked-worktree management pointers.
|
||||
/// Separate from configuration discovery in regular path-backed walkers.
|
||||
pub fn run_glob(
|
||||
root: &Path,
|
||||
base: &Path,
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
//! Foundational filesystem operation contracts and provider-side search.
|
||||
//!
|
||||
//! This crate deliberately has no dependency on Workdir identity, Runtime
|
||||
//! transport, or LLM Tool implementations. Paths are logical and root-relative;
|
||||
//! providers supply host roots and access policy.
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
mod checked;
|
||||
pub use checked::{CheckedTarget, identity_validator};
|
||||
|
||||
@@ -473,6 +473,17 @@ fn list_entry_bytes(entry: &ListEntry) -> usize {
|
||||
entry.path.as_str().len().saturating_add(64)
|
||||
}
|
||||
|
||||
/// Bounded live pagination of direct children.
|
||||
///
|
||||
/// Sorts directories first, then logical paths within each group. Cursors are exclusive ordering
|
||||
/// keys and need not still exist. List applies provider read/enumeration scope, not ignore/dotfile
|
||||
/// filters. The full scan retains only limit+1 candidates within an aggregate path-byte limit.
|
||||
/// Enumeration order is unspecified, so a full page does not end scanning. Totals describe current
|
||||
/// visible entries, including those before the cursor.
|
||||
///
|
||||
/// No cross-page snapshot: insertions, removals, renames, and kind changes may omit or duplicate entries.
|
||||
/// Cancellation and traversal ceilings apply even to excluded entries; resource exhaustion is not
|
||||
/// converted into silent success.
|
||||
pub fn run_list(
|
||||
root: &Path,
|
||||
request: ListRequest,
|
||||
|
||||
@@ -220,6 +220,13 @@ struct GrepParams {
|
||||
offset: Option<usize>,
|
||||
}
|
||||
|
||||
/// Bounded Grep reading content within provider scope.
|
||||
///
|
||||
/// Typed result paths come from reports retained after offset/limit, never reverse-parsed from
|
||||
/// rendered filenames. Descriptor providers read only authorized ignore sources and apply .gitignore
|
||||
/// without requiring .git markers. Unlike Glob, unavailable/symlinked ignore opens retain existing
|
||||
/// explicit errors. Scope-denied sources are skipped before opening; global/ambient configuration
|
||||
/// is not searched. Search is request-time traversal, not a snapshot.
|
||||
pub fn run_grep(
|
||||
root: &Path,
|
||||
base: PathBuf,
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
//! Pure text-operation policy shared by filesystem providers and operation frontends.
|
||||
//! Pure text operations shared by providers and frontends.
|
||||
//!
|
||||
//! This module owns no paths, descriptors, version fences, or I/O. Limits count
|
||||
//! UTF-8 bytes, not characters, and default to unlimited.
|
||||
//! Owns argument schemas, JSON decoding, edit conditions, and result sizes, not paths, descriptors,
|
||||
//! authorization, I/O, or version fences. Providers call within existing consistency boundaries;
|
||||
//! checked edits must not be decomposed into unchecked Read–Write. Adapters own whole-text versus
|
||||
//! line-range Read selection, history, digests, and canonical multi-file commits.
|
||||
//!
|
||||
//! Edit requires a nonempty old string and a different replacement, which may be empty.
|
||||
//! Unless replace_all is set, the nonoverlapping match must be unique. Providers set UTF-8 byte limits. Arithmetic overflow and capacity are
|
||||
//! checked before allocating results. Pure validation failures have no side effects; transport
|
||||
//! failures after dispatch are not converted into validation failures here.
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, de::DeserializeOwned};
|
||||
|
||||
Reference in New Issue
Block a user