channels: find_daemon path walking, consistent pane_id, auto-start
find_daemon() replaces daemon_sock() — walks the dot-delimited channel path from most-specific to least looking for a daemon socket, and auto-starts via the supervisor if none is found. All channel tools (recv, send, open, close) use the same resolution path. Fix tmux daemon to use pane_id consistently for both pipe-pane and send-keys (send-keys -t <label> doesn't work, needs the %N pane id). Store label→pane_id mapping in State instead of bare label vec. Gracefully handle missing tmux.json5 — start with empty pane list since panes are added dynamically via the open RPC. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
c9b19dc3d7
commit
2a84fb325d
3 changed files with 103 additions and 33 deletions
|
|
@ -42,17 +42,22 @@ fn load_config() -> Config {
|
|||
let path = dirs::home_dir()
|
||||
.unwrap_or_default()
|
||||
.join(".consciousness/channels/tmux.json5");
|
||||
let text = std::fs::read_to_string(&path)
|
||||
.unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display()));
|
||||
json5::from_str(&text)
|
||||
.unwrap_or_else(|e| panic!("failed to parse {}: {e}", path.display()))
|
||||
match std::fs::read_to_string(&path) {
|
||||
Ok(text) => json5::from_str(&text)
|
||||
.unwrap_or_else(|e| panic!("failed to parse {}: {e}", path.display())),
|
||||
Err(_) => {
|
||||
info!("no tmux.json5, starting with no pre-configured panes");
|
||||
Config { panes: vec![] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── State ─────────────────────────────────────────────────────
|
||||
|
||||
struct State {
|
||||
channel_logs: BTreeMap<String, ChannelLog>,
|
||||
pane_labels: Vec<String>,
|
||||
/// label → pane_id (e.g. "ktest" → "%0")
|
||||
panes: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
type SharedState = Rc<RefCell<State>>;
|
||||
|
|
@ -61,7 +66,9 @@ impl State {
|
|||
fn new(config: &Config) -> Self {
|
||||
Self {
|
||||
channel_logs: BTreeMap::new(),
|
||||
pane_labels: config.panes.iter().map(|p| p.label.clone()).collect(),
|
||||
panes: config.panes.iter()
|
||||
.map(|p| (p.label.clone(), p.pane_id.clone()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -172,10 +179,10 @@ impl channel_server::Server for ChannelServerImpl {
|
|||
|
||||
// Send to tmux pane via send-keys
|
||||
let label = channel.strip_prefix("tmux.").unwrap_or(&channel);
|
||||
let has_pane = self.state.borrow().pane_labels.iter().any(|l| l == label);
|
||||
if has_pane {
|
||||
let pane_id = self.state.borrow().panes.get(label).cloned();
|
||||
if let Some(pane_id) = pane_id {
|
||||
let _ = std::process::Command::new("tmux")
|
||||
.args(["send-keys", "-t", label, &message, "Enter"])
|
||||
.args(["send-keys", "-t", &pane_id, &message, "Enter"])
|
||||
.output();
|
||||
|
||||
let channel_key = format!("tmux.{}", label);
|
||||
|
|
@ -195,7 +202,7 @@ impl channel_server::Server for ChannelServerImpl {
|
|||
mut results: channel_server::ListResults,
|
||||
) -> Promise<(), capnp::Error> {
|
||||
let s = self.state.borrow();
|
||||
let channels: Vec<_> = s.pane_labels.iter().map(|label| {
|
||||
let channels: Vec<_> = s.panes.keys().map(|label| {
|
||||
let key = format!("tmux.{}", label);
|
||||
let unread = s.channel_logs.get(&key).map_or(0, |l| l.unread());
|
||||
(key, true, unread)
|
||||
|
|
@ -230,7 +237,7 @@ impl channel_server::Server for ChannelServerImpl {
|
|||
// Check if already open
|
||||
{
|
||||
let s = self.state.borrow();
|
||||
if s.pane_labels.contains(&label) {
|
||||
if s.panes.contains_key(&label) {
|
||||
return Promise::ok(());
|
||||
}
|
||||
}
|
||||
|
|
@ -247,7 +254,7 @@ impl channel_server::Server for ChannelServerImpl {
|
|||
// Register in state
|
||||
{
|
||||
let mut s = self.state.borrow_mut();
|
||||
s.pane_labels.push(label.clone());
|
||||
s.panes.insert(label.clone(), pane_id.clone());
|
||||
}
|
||||
|
||||
// Start pipe-pane reader
|
||||
|
|
@ -270,17 +277,14 @@ impl channel_server::Server for ChannelServerImpl {
|
|||
let label = channel.strip_prefix("tmux.").unwrap_or(&channel).to_string();
|
||||
|
||||
let mut s = self.state.borrow_mut();
|
||||
if let Some(pos) = s.pane_labels.iter().position(|l| *l == label) {
|
||||
if let Some(pane_id) = s.panes.remove(&label) {
|
||||
info!("closing channel tmux.{}", label);
|
||||
s.pane_labels.remove(pos);
|
||||
s.channel_logs.remove(&format!("tmux.{}", label));
|
||||
|
||||
// Disconnect pipe-pane — find the pane ID
|
||||
if let Some(pane_id) = find_pane_by_name(&label) {
|
||||
let _ = std::process::Command::new("tmux")
|
||||
.args(["pipe-pane", "-t", &pane_id])
|
||||
.output();
|
||||
}
|
||||
// Disconnect pipe-pane
|
||||
let _ = std::process::Command::new("tmux")
|
||||
.args(["pipe-pane", "-t", &pane_id])
|
||||
.output();
|
||||
}
|
||||
|
||||
Promise::ok(())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue