feat(minga): minga-vfs — proyecta el repo como filesystem FUSE

minga-vfs deja de ser un stub: monta el repositorio direccionado por
contenido como un filesystem FUSE de sólo lectura. roots/<hash> da el
código fuente reconstruido (formato normalizado) de cada raíz del MST;
cas/<hash> resuelve cualquier hash bajo demanda como S-expression.

Capas separadas: render (SemanticNode→texto, puro) + source (contrato
NodeSource, backends sled/memoria) + fs (único módulo con fuser).
Nuevo subcomando `minga mount <punto>`. Dep fuser 0.15 sin libfuse-dev
(default-features = false). 14 tests nuevos, sin regresión en minga-cli.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-22 13:23:44 +00:00
parent 762bf95dfd
commit e77a32f4d6
15 changed files with 1094 additions and 14 deletions
@@ -5,7 +5,7 @@ use std::process::ExitCode;
use clap::{Parser, Subcommand};
use minga_cli::{
cmd_ingest, cmd_init, cmd_listen, cmd_status, cmd_sync, cmd_watch, CliError,
cmd_ingest, cmd_init, cmd_listen, cmd_mount, cmd_status, cmd_sync, cmd_watch, CliError,
};
#[derive(Parser)]
@@ -59,6 +59,14 @@ enum Command {
/// Directorio a vigilar.
dir: PathBuf,
},
/// Monta el repositorio como filesystem FUSE de sólo lectura.
/// Cada hash del store se vuelve un archivo navegable con
/// `ls`/`cat`. Bloquea hasta `fusermount -u <punto>`.
Mount {
/// Punto de montaje: un directorio existente.
point: PathBuf,
},
}
fn main() -> ExitCode {
@@ -116,6 +124,16 @@ fn run() -> Result<(), CliError> {
.map_err(|e| CliError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))?;
rt.block_on(cmd_watch(&cli.repo, &pass, &dir))?;
}
Command::Mount { point } => {
let pass = prompt_passphrase()?;
println!(
"Montando {} en {}. `fusermount -u {}` para desmontar.",
cli.repo.display(),
point.display(),
point.display()
);
cmd_mount(&cli.repo, &pass, &point)?;
}
}
Ok(())
}