Resolve ~ to /root in explicit mount targets
Previously only derived targets (when no target was specified) got
tilde expansion. Explicit targets like `target "~/downloads"` passed
through raw, which Docker cannot expand. Now both paths go through
resolve_container_tilde, backed by a CONTAINER_HOME constant that
documents the /root assumption.

Assisted-by: Claude Opus 4.6 via pi
change ulwqzqovuvwpvlnxrpzxsnvlpxkllymp
commit f2900881f6a057c406a0aac28dd47b7c4545e871
author Alpha Chen <alpha@kejadlen.dev>
date
parent yvtyompu
diff --git a/src/config.rs b/src/config.rs
index 6dde657..82afd47 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -164,8 +164,8 @@ impl Mount {
         }
 
         let target = match &self.target {
-            Some(t) => t.clone(),
-            None => tilde_to_root(&self.source),
+            Some(t) => resolve_container_tilde(t),
+            None => resolve_container_tilde(&self.source),
         };
 
         Some(ResolvedMount {
@@ -196,12 +196,17 @@ impl ResolvedMount {
     }
 }
 
-/// Replace a leading `~` with `/root` to derive a container path.
-fn tilde_to_root(path: &str) -> String {
+/// Home directory inside the agent container. The ramekin Dockerfile runs
+/// everything as root, so `~` in container target paths maps here. If the
+/// image ever switches to a non-root user, update this constant.
+const CONTAINER_HOME: &str = "/root";
+
+/// Replace a leading `~` with the container home directory.
+fn resolve_container_tilde(path: &str) -> String {
     if let Some(rest) = path.strip_prefix("~/") {
-        format!("/root/{rest}")
+        format!("{CONTAINER_HOME}/{rest}")
     } else if path == "~" {
-        "/root".to_string()
+        CONTAINER_HOME.to_string()
     } else {
         path.to_string()
     }
@@ -266,18 +271,21 @@ mod tests {
     }
 
     #[test]
-    fn tilde_to_root_with_subpath() {
-        assert_eq!(tilde_to_root("~/.config/git"), "/root/.config/git");
+    fn resolve_container_tilde_with_subpath() {
+        assert_eq!(
+            resolve_container_tilde("~/.config/git"),
+            "/root/.config/git"
+        );
     }
 
     #[test]
-    fn tilde_to_root_bare() {
-        assert_eq!(tilde_to_root("~"), "/root");
+    fn resolve_container_tilde_bare() {
+        assert_eq!(resolve_container_tilde("~"), "/root");
     }
 
     #[test]
-    fn tilde_to_root_absolute_unchanged() {
-        assert_eq!(tilde_to_root("/some/path"), "/some/path");
+    fn resolve_container_tilde_absolute_unchanged() {
+        assert_eq!(resolve_container_tilde("/some/path"), "/some/path");
     }
 
     #[test]
@@ -303,6 +311,17 @@ mod tests {
         assert!(!resolved.writable);
     }
 
+    #[test]
+    fn resolve_expands_tilde_in_explicit_target() {
+        let mount = Mount {
+            source: "/tmp".into(),
+            target: Some("~/downloads".into()),
+            writable: true,
+        };
+        let resolved = mount.resolve().unwrap();
+        assert_eq!(resolved.target, "/root/downloads");
+    }
+
     #[test]
     fn resolve_derives_target_from_source_when_no_tilde() {
         let mount = Mount {