P2 slice 8: the viewer's menu, setup, no confinement (D-32)

No Landlock, no seccomp, no helper: isolation is "same_user
(advisory)". The lease socket keeps two intents (close, format-upgrade
consent). The viewer holds the books open while it runs and gains a
Books menu: New books, Back up now, Restore (preview, then confirm),
Close, Connect Claude Code / Codex. New commands `wanderbooks books
back-up` and `wanderbooks connect claude|codex`. The scaffold
(`new`/`init` and its templates) is gone; install.sh needs no sudo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
This commit is contained in:
swaitsandClaude Opus 5.5 committed 2026-10-20 11:14:22 -06:00
1 parent 019d8d76a3
commit 3cf359a0cd
28 files changed
+1976 -1931

No files matched your search

+35
View File
@@ -490,6 +490,41 @@ impl Books {
confirmed,
expect_head,
} => self.restore(id, source, replace, confirmed, expect_head),
Request::BackUpNow { id, new_disk } => {
let id = match BookId::parse(&id) {
Ok(id) => id,
Err(e) => return refused(e),
};
let backups = match self.held().get(id.as_str()) {
Some(Book::Open { backups, .. }) => backups.clone(),
Some(Book::Failed(why)) => {
return Response::Refused(format!("those books didn't open: {why}"));
}
None => {
return Response::Refused(format!(
"there are no books called {:?}",
id.as_str()
));
}
};
let rt = tokio::runtime::Handle::current();
match rt.block_on(backups.run_with("asked", new_disk)) {
Ok(status) => Response::BackedUp {
head_seq: status.head_seq,
targets: status
.targets
.into_iter()
.map(|t| admin::BackedUpTarget {
target: t.target,
at: t.at,
through_seq: t.through_seq,
problem: t.last_error,
})
.collect(),
},
Err(why) => Response::Refused(self.hide(why)),
}
}
Request::Adopt {
id,
source,