aboutsummaryrefslogtreecommitdiff
path: root/crates/dinggerd/src/restore.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/dinggerd/src/restore.rs')
-rw-r--r--crates/dinggerd/src/restore.rs46
1 files changed, 33 insertions, 13 deletions
diff --git a/crates/dinggerd/src/restore.rs b/crates/dinggerd/src/restore.rs
index 1dca955..23d166e 100644
--- a/crates/dinggerd/src/restore.rs
+++ b/crates/dinggerd/src/restore.rs
@@ -10,8 +10,9 @@
//! pane. Everything is addressed by tmux id, so names with `.` or `:` work.
//!
//! Then, once each new shell shows its prompt: agents with a session
-//! reference are resumed (`pi --session <file>`, run), and every other
-//! saved command line is typed but not run, for the user to press Enter.
+//! reference are resumed (`pi --session <file>`, `claude --resume <id>`,
+//! run), and every other saved command line is typed but not run, for the
+//! user to press Enter.
use std::time::{Duration, Instant};
@@ -48,10 +49,20 @@ pub enum Typed {
Retype(String),
}
-/// The command that resumes an agent's session.
+/// The command that resumes an agent's session, from its session file.
+/// `None` when the file does not exist: a session that never got a message
+/// has nothing to resume (`claude --resume` would fail), so its command
+/// line is retyped instead, like any other.
fn resume_command(agent: &str, session: &str) -> Option<String> {
+ let file = std::path::Path::new(session);
+ if !file.is_file() {
+ return None;
+ }
match agent {
"pi" => Some(format!("pi --session {}", shell_quote(session))),
+ // By id, the transcript's name. It must run in the directory the
+ // session ran in (the pane's), or Claude moves the conversation.
+ "claude" => file.file_stem()?.to_str().map(|id| format!("claude --resume {}", shell_quote(id))),
_ => None,
}
}
@@ -657,18 +668,27 @@ mod tests {
assert_eq!(typed_for(&pane), Some(Typed::Retype("nvim 'my file.sh'".into())));
pane.command = Some("echo one\necho two".into());
assert_eq!(typed_for(&pane), None, "a newline would run it");
- pane.agent = Some(AgentSnap {
- agent: "pi".into(),
- name: "x".into(),
- state: "idle".into(),
- session: Some("/s/a b.jsonl".into()),
- });
- assert_eq!(typed_for(&pane), Some(Typed::Resume("pi --session '/s/a b.jsonl'".into())));
- if let Some(agent) = pane.agent.as_mut() {
- agent.session = None;
- }
+ let dir = std::env::temp_dir().join(format!("dingger-typed-{}", std::process::id()));
+ std::fs::create_dir_all(&dir).unwrap();
+ let file = |name: &str| dir.join(name).to_string_lossy().into_owned();
+ std::fs::write(file("a b.jsonl"), "").unwrap();
+ std::fs::write(file("4f1c-9e.jsonl"), "").unwrap();
+ let agent = |agent: &str, session: Option<String>| {
+ Some(AgentSnap { agent: agent.into(), name: "x".into(), state: "idle".into(), session })
+ };
pane.command = Some("pi --model x".into());
+ pane.agent = agent("pi", Some(file("a b.jsonl")));
+ assert_eq!(typed_for(&pane), Some(Typed::Resume(format!("pi --session '{}'", file("a b.jsonl")))));
+ pane.agent = agent("pi", None);
assert_eq!(typed_for(&pane), Some(Typed::Retype("pi --model x".into())), "no session: retyped");
+ pane.agent = agent("pi", Some(file("never-written.jsonl")));
+ assert_eq!(typed_for(&pane), Some(Typed::Retype("pi --model x".into())), "no session file: retyped");
+ pane.command = Some("claude --model opus".into());
+ pane.agent = agent("claude", Some(file("4f1c-9e.jsonl")));
+ assert_eq!(typed_for(&pane), Some(Typed::Resume("claude --resume 4f1c-9e".into())), "by id");
+ pane.agent = agent("claude", Some(file("no-messages.jsonl")));
+ assert_eq!(typed_for(&pane), Some(Typed::Retype("claude --model opus".into())), "no transcript: retyped");
+ std::fs::remove_dir_all(&dir).unwrap();
}
#[test]