cubesys/cubecli: session note/message-save-path (notes) — WordFlags-tagged CZYX note log (doc_type=note, per-session owner + created_at day), store_note/list/search/show + note_command dispatcher, durable CubeStore+WAL+checkpoint; cube note add|list|search|show. New cubesys::notes module w/ 3 tests; workspace check green.
This commit is contained in:
+53
-7
@@ -62,9 +62,33 @@ fn is_command_word(w: &str) -> bool {
|
||||
| "rollback"
|
||||
| "stats"
|
||||
| "audit"
|
||||
| "note"
|
||||
| "notes"
|
||||
)
|
||||
}
|
||||
|
||||
/// Open (or create) the durable session-note store. Notes persist across CLI
|
||||
/// invocations and sessions — the CUBE "message save path" — via the WAL +
|
||||
/// checkpoint store. The directory is `$CUBE_NOTES_DIR` (`~/.cubelinux-notes`).
|
||||
fn open_notes_store() -> cubesys::store::ConcurrentStore {
|
||||
let dir = std::env::var("CUBE_NOTES_DIR").unwrap_or_else(|_| {
|
||||
format!(
|
||||
"{}/.cubelinux-notes",
|
||||
std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string())
|
||||
)
|
||||
});
|
||||
cubesys::store::ConcurrentStore::open(
|
||||
&format!("{dir}/notes.store"),
|
||||
&format!("{dir}/notes.wal"),
|
||||
&format!("{dir}/recovery.log"),
|
||||
cubesys::store::DurabilityConfig::default(),
|
||||
)
|
||||
.unwrap_or_else(|e| {
|
||||
eprintln!("error: cannot open notes store {dir}: {e}");
|
||||
std::process::exit(1);
|
||||
})
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
match args.get(1).map(|s| s.as_str()) {
|
||||
@@ -75,12 +99,29 @@ fn main() {
|
||||
// the coordinate-addressed API a real CLI surface the OS can call.
|
||||
Some(word) if is_command_word(word) => {
|
||||
let line = args[1..].join(" ");
|
||||
let mut session = Session::new();
|
||||
match session.exec(&line) {
|
||||
Ok(out) => println!("{out}"),
|
||||
Err(e) => {
|
||||
eprintln!("error: {e}");
|
||||
std::process::exit(1);
|
||||
// Session notes live in their own DURABLE store so a note written
|
||||
// in one session is reviewable in the next (the message save path).
|
||||
if word == "note" || word == "notes" {
|
||||
let store = open_notes_store();
|
||||
let res = cubesys::notes::note_command(&store, &line);
|
||||
// Force a durable flush/checkpoint before exiting so the note is
|
||||
// persisted even though this process (the CLI) is short-lived.
|
||||
store.checkpoint();
|
||||
match res {
|
||||
Ok(out) => println!("{out}"),
|
||||
Err(e) => {
|
||||
eprintln!("error: {e}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let mut session = Session::new();
|
||||
match session.exec(&line) {
|
||||
Ok(out) => println!("{out}"),
|
||||
Err(e) => {
|
||||
eprintln!("error: {e}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,6 +185,11 @@ fn print_help() {
|
||||
stat <path> getattr via cubefs\n \
|
||||
seal <path> <K.Z.Y.X|auto> <tf> encrypt a record (tf: none|gcm|chacha|xts)\n \
|
||||
open <path> <K.Z.Y.X|auto> <tf> decrypt + decode + run a sealed record\n \
|
||||
keyinit ensure the OS Null-space keystore exists\n"
|
||||
keyinit ensure the OS Null-space keystore exists\n \
|
||||
note <text> add a session note (durable, WordFlags-tagged)\n \
|
||||
note list [session] list notes (default: today's session)\n \
|
||||
note search <text> search notes across sessions\n \
|
||||
note show <C.Z.Y.X> show one note\n \
|
||||
notes alias for `note list`\n"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user