Skip to main content

kaish_tool_api/
backend.rs

1//! The `KernelBackend` trait — kaish's abstract I/O and tool-dispatch layer.
2//!
3//! The trait lives here (not in `kaish-types`) because it is async and refers
4//! to [`ToolCtx`](crate::ToolCtx). Its data types (errors, results, ops) and
5//! the concrete implementations (`LocalBackend`, overlay, …) live elsewhere —
6//! the data in `kaish-types::backend`, the impls in `kaish-kernel`.
7
8use std::path::{Path, PathBuf};
9
10use async_trait::async_trait;
11
12use kaish_types::backend::{
13    BackendResult, MountInfo, PatchOp, ReadRange, ToolInfo, ToolResult, WriteMode,
14};
15use kaish_types::{DirEntry, ToolArgs};
16
17use crate::ctx::ToolCtx;
18
19/// Abstract backend interface for file operations and tool dispatch.
20///
21/// Implementations select where a path resolves and how tools are dispatched:
22/// - `LocalBackend` — VfsRouter-backed local filesystem (the default).
23/// - `KaijutsuBackend` — CRDT-backed blocks when embedded in kaijutsu.
24#[async_trait]
25pub trait KernelBackend: Send + Sync {
26    // ═══════════════════════════════════════════════════════════════════════
27    // File Operations
28    // ═══════════════════════════════════════════════════════════════════════
29
30    /// Read file contents, optionally with a range specification.
31    async fn read(&self, path: &Path, range: Option<ReadRange>) -> BackendResult<Vec<u8>>;
32
33    /// Write content to a file with the specified mode.
34    async fn write(&self, path: &Path, content: &[u8], mode: WriteMode) -> BackendResult<()>;
35
36    /// Append content to a file.
37    async fn append(&self, path: &Path, content: &[u8]) -> BackendResult<()>;
38
39    /// Apply a sequence of patch operations to a file.
40    ///
41    /// Operations apply in order to one snapshot of the file, and the result
42    /// is written once. If an operation fails — a CAS `expected` mismatch, an
43    /// offset or line number past the end — the batch stops before the write
44    /// and the file keeps every byte it had. A caller holding an error never
45    /// has to work out how much of the batch survived.
46    ///
47    /// The snapshot accumulates, so each operation sees the edits before it:
48    /// offsets and line numbers are relative to the content as patched so far,
49    /// not to the file as it was on entry. An insert at line 1 shifts the line
50    /// numbers every later operation in the same batch uses.
51    ///
52    /// The promise covers the operations, not the write that follows them.
53    /// Persisting the result is `write`'s business, with whatever crash,
54    /// concurrency, and I/O-error behavior the implementation gives it — a
55    /// write that fails partway through can still leave a partial file.
56    async fn patch(&self, path: &Path, ops: &[PatchOp]) -> BackendResult<()>;
57
58    /// List a directory's entries.
59    async fn list(&self, path: &Path) -> BackendResult<Vec<DirEntry>>;
60
61    /// Stat a path (following symlinks).
62    async fn stat(&self, path: &Path) -> BackendResult<DirEntry>;
63
64    /// Create a directory.
65    async fn mkdir(&self, path: &Path) -> BackendResult<()>;
66
67    /// Set the modification time of an existing path.
68    ///
69    /// Read-only or purely-virtual mounts reject rather than silently
70    /// succeeding — `touch` on an existing file must route through here, never
71    /// escape to the host via `resolve_real_path`.
72    async fn set_mtime(&self, path: &Path, mtime: std::time::SystemTime) -> BackendResult<()>;
73
74    /// Remove a file or directory.
75    async fn remove(&self, path: &Path, recursive: bool) -> BackendResult<()>;
76
77    /// Rename/move a path.
78    async fn rename(&self, from: &Path, to: &Path) -> BackendResult<()>;
79
80    /// Whether a path exists.
81    async fn exists(&self, path: &Path) -> bool;
82
83    /// Stat a path without following symlinks.
84    async fn lstat(&self, path: &Path) -> BackendResult<DirEntry>;
85
86    /// Read a symlink's target.
87    async fn read_link(&self, path: &Path) -> BackendResult<PathBuf>;
88
89    /// Create a symlink.
90    async fn symlink(&self, target: &Path, link: &Path) -> BackendResult<()>;
91
92    // ═══════════════════════════════════════════════════════════════════════
93    // Tool Dispatch
94    // ═══════════════════════════════════════════════════════════════════════
95
96    /// Call a tool by name with the given arguments and execution context.
97    ///
98    /// For local backends, this executes the tool directly via ToolRegistry.
99    /// For remote backends (e.g. kaijutsu), this may serialize the call and
100    /// forward it to the parent process.
101    async fn call_tool(
102        &self,
103        name: &str,
104        args: ToolArgs,
105        ctx: &mut dyn ToolCtx,
106    ) -> BackendResult<ToolResult>;
107
108    /// List available external tools.
109    async fn list_tools(&self) -> BackendResult<Vec<ToolInfo>>;
110
111    /// Get information about a specific tool.
112    async fn get_tool(&self, name: &str) -> BackendResult<Option<ToolInfo>>;
113
114    // ═══════════════════════════════════════════════════════════════════════
115    // Backend Information
116    // ═══════════════════════════════════════════════════════════════════════
117
118    /// Returns true if this backend is read-only.
119    fn read_only(&self) -> bool;
120
121    /// Returns the backend type identifier (e.g. "local", "kaijutsu").
122    fn backend_type(&self) -> &str;
123
124    /// List all mount points.
125    fn mounts(&self) -> Vec<MountInfo>;
126
127    /// Resolve a VFS path to a real filesystem path.
128    ///
129    /// Returns `Some(path)` if the VFS path maps to a real filesystem (like
130    /// LocalFs), or `None` if the path is virtual (like MemoryFs). Tools like
131    /// `git` that hand paths to external C libraries need the real path.
132    fn resolve_real_path(&self, path: &Path) -> Option<PathBuf>;
133}