feat(hh): /pw command, RAM-only direnv autostart, robust lets-hack; coven→clergy

- add /pw (alias /password): reveal this room's password locally (never
  broadcast); surfaced in the F1 help overlay and the join hint
- direnv-autostart/: cd-to-launch a single real-user session via direnv;
  password is minted in memory at launch (never written to disk, matching the
  RAM-only model) and scoped to the child process. setup.sh installs direnv,
  hooks bash/zsh, and `direnv allow`s the dir
- lets-hack.sh: boot a FRESH server by default (replacing any live one) with a
  --reuse opt-out; add -h/--help/-help; guard against killing the tmux session
  you're attached to; switch-client into the coven when run inside tmux
- rename coven→clergy across rust/python/scripts; tests/test_coven.py→test_clergy.py
- snapshots in-progress hack-house client work (sandbox, themes, net, ui)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
leetcrypt
2026-05-31 22:29:17 -07:00
parent 8e6365a649
commit 5de493e895
21 changed files with 1058 additions and 91 deletions
+37
View File
@@ -2,9 +2,14 @@
//! occult-monochrome: black ground, white/grey ink, ⛧ accents. Override with a
//! TOML file via `--theme <path>`.
use anyhow::Context;
use ratatui::style::Color;
use serde::Deserialize;
/// Where the bundled `*.toml` vestments live, so `/theme <name>` can resolve a
/// bare name to a file at runtime (mirrors sbx.rs's script path const).
pub const THEMES_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/themes");
#[derive(Debug, Clone, Deserialize)]
#[serde(default)]
pub struct Theme {
@@ -18,8 +23,14 @@ pub struct Theme {
pub system: Color,
pub input: Color,
pub roster_me: Color,
/// Panel/background fill. `Reset` = the terminal's own background (no fill);
/// a solid colour lifts the text onto a contrasting surface for legibility.
pub bg: Color,
/// Width of the roster column.
pub roster_width: u16,
/// Glyph flanking the "hack-house" title (and used for occult accents).
/// Defaults to ⛧ (inverted pentagram); themes can pick their own sigil.
pub sigil: String,
}
impl Default for Theme {
@@ -37,7 +48,9 @@ impl Default for Theme {
system: Color::Rgb(0xb4, 0x6c, 0xff), // system / occult = purple
input: Color::Rgb(0x39, 0xff, 0x14),
roster_me: Color::Rgb(0xff, 0x39, 0xc0), // you / owner = hot magenta
bg: Color::Reset, // ride the terminal's own black
roster_width: 22,
sigil: "".into(), // inverted pentagram
}
}
}
@@ -47,6 +60,30 @@ impl Theme {
let s = std::fs::read_to_string(path)?;
Ok(toml::from_str(&s)?)
}
/// Resolve a bare vestment name (e.g. "neon") to a bundled `themes/<name>.toml`.
/// Used by the in-session `/theme` command for live switching.
pub fn by_name(name: &str) -> anyhow::Result<Self> {
let path = format!("{THEMES_DIR}/{name}.toml");
Self::load(&path).with_context(|| format!("theme '{name}' ({path})"))
}
/// Names of the bundled vestments, sorted, for `/theme` with no argument.
pub fn available() -> Vec<String> {
let mut names: Vec<String> = std::fs::read_dir(THEMES_DIR)
.into_iter()
.flatten()
.flatten()
.filter_map(|e| {
e.file_name()
.to_str()
.and_then(|f| f.strip_suffix(".toml"))
.map(str::to_string)
})
.collect();
names.sort();
names
}
}
#[cfg(test)]