diff --git a/crates/maestro-daemon/src/dirlist.rs b/crates/maestro-daemon/src/dirlist.rs index 4c423d4..b66e729 100644 --- a/crates/maestro-daemon/src/dirlist.rs +++ b/crates/maestro-daemon/src/dirlist.rs @@ -28,7 +28,7 @@ pub const MAX_ENTRIES: usize = 1000; /// List the immediate subdirectories of `requested`, expanding it against /// `home_dir` first. Returns directory **names** only (not full paths), sorted -/// case-insensitively, with hidden entries included. +/// case-insensitively. Hidden directories (dotfiles) are excluded. pub fn list_dir(home_dir: &str, requested: &str) -> Result { let dir = resolve(home_dir, requested); @@ -36,8 +36,14 @@ pub fn list_dir(home_dir: &str, requested: &str) -> Result = Vec::new(); for entry in read.flatten() { + let name = entry.file_name().to_string_lossy().into_owned(); + // Skip hidden directories — the spawn form rarely targets dotfile dirs + // and they only clutter the completion list. + if name.starts_with('.') { + continue; + } if is_dir(&entry) { - entries.push(entry.file_name().to_string_lossy().into_owned()); + entries.push(name); } } // Case-insensitive sort so `Projects` and `projects` interleave the way a @@ -124,12 +130,13 @@ mod tests { } #[test] - fn lists_dirs_only_sorted_case_insensitively_including_hidden() { + fn lists_visible_dirs_only_sorted_case_insensitively() { let tmp = fixture(); let home = tmp.path().to_string_lossy(); let listing = list_dir(&home, "").unwrap(); - // The file is excluded; dirs (incl. hidden + symlinked dir) are present. - assert!(listing.entries.contains(&".config".to_string())); + // Files and hidden dirs are excluded; visible dirs (incl. a symlinked + // dir) are present. + assert!(!listing.entries.contains(&".config".to_string())); assert!(listing.entries.contains(&"projects".to_string())); assert!(listing.entries.contains(&"Downloads".to_string())); assert!(!listing.entries.contains(&"notes.txt".to_string())); diff --git a/crates/maestro-protocol/src/lib.rs b/crates/maestro-protocol/src/lib.rs index 22a0603..cccc23f 100644 --- a/crates/maestro-protocol/src/lib.rs +++ b/crates/maestro-protocol/src/lib.rs @@ -77,7 +77,7 @@ pub struct DirListing { pub path: PathBuf, /// Immediate subdirectory names (not full paths), sorted case-insensitively. /// Directories only — the spawn form's targets are always dirs. Hidden - /// entries (dotfiles) are included, matching shell completion. + /// directories (dotfiles) are excluded. pub entries: Vec, /// True when `entries` was truncated at the daemon's cap; the client can /// surface "narrow your search" rather than implying the dir is small. diff --git a/docs/superpowers/specs/2026-06-15-spawn-dir-autocomplete-design.md b/docs/superpowers/specs/2026-06-15-spawn-dir-autocomplete-design.md index 2981262..0f809b1 100644 --- a/docs/superpowers/specs/2026-06-15-spawn-dir-autocomplete-design.md +++ b/docs/superpowers/specs/2026-06-15-spawn-dir-autocomplete-design.md @@ -33,7 +33,7 @@ The daemon lists **one directory's immediate subdirectories**; the web caches the result per `(daemonId, dir)` and filters the trailing path segment client-side, re-querying only when the user crosses a `/`. Fewer round-trips, instant filtering, still live. Directories only (cwd / base-repo are always -dirs); hidden dirs included (shell parity); sorted case-insensitively; capped. +dirs); hidden dirs excluded; sorted case-insensitively; capped. ### Wire protocol (`maestro-protocol`) @@ -92,7 +92,7 @@ machinery, so older peers degrade gracefully. - Protocol: serde round-trip for the four new variants + `DirListing`, and an unknown-variant decode (already covered generically). -- Daemon `dirlist`: temp-dir listing (dirs-only, hidden included, sorted), `~` +- Daemon `dirlist`: temp-dir listing (dirs-only, hidden excluded, sorted), `~` and relative + empty expansion, and `not_found` / `not_a_directory` codes. - Daemon `broker`: `forward_list_dir` round-trip + fail-fast-while-disconnected, mirroring the existing forward_create/kill tests. diff --git a/worktrees/linear/nap-256-tmux-async b/worktrees/linear/nap-256-tmux-async new file mode 160000 index 0000000..5ea8d0f --- /dev/null +++ b/worktrees/linear/nap-256-tmux-async @@ -0,0 +1 @@ +Subproject commit 5ea8d0fa59e17a9afdec12297b4fd03ef4b9cd82 diff --git a/worktrees/linear/nap-257-web-proxy-caps b/worktrees/linear/nap-257-web-proxy-caps new file mode 160000 index 0000000..b077493 --- /dev/null +++ b/worktrees/linear/nap-257-web-proxy-caps @@ -0,0 +1 @@ +Subproject commit b0774934e8d85e1a87649295bf639efa7ca4ae72 diff --git a/worktrees/linear/nap-258-aba-deregister b/worktrees/linear/nap-258-aba-deregister new file mode 160000 index 0000000..599f3ed --- /dev/null +++ b/worktrees/linear/nap-258-aba-deregister @@ -0,0 +1 @@ +Subproject commit 599f3ed17804169a6c3def94f7c2c16af2885c0a diff --git a/worktrees/linear/nap-260-create-rollback b/worktrees/linear/nap-260-create-rollback new file mode 160000 index 0000000..2f4dde8 --- /dev/null +++ b/worktrees/linear/nap-260-create-rollback @@ -0,0 +1 @@ +Subproject commit 2f4dde85acbf9576a241433e59d7d5c5140286fc diff --git a/worktrees/linear/nap-263-broker-backpressure b/worktrees/linear/nap-263-broker-backpressure new file mode 160000 index 0000000..ae37759 --- /dev/null +++ b/worktrees/linear/nap-263-broker-backpressure @@ -0,0 +1 @@ +Subproject commit ae3775946de5e1aeed846327774ca693020405ad diff --git a/worktrees/linear/nap-265-broker-dial b/worktrees/linear/nap-265-broker-dial new file mode 160000 index 0000000..ae588b7 --- /dev/null +++ b/worktrees/linear/nap-265-broker-dial @@ -0,0 +1 @@ +Subproject commit ae588b76d58bce87f18c8822d39ecf4a1c2d67af diff --git a/worktrees/linear/nap-266-jwt-binding b/worktrees/linear/nap-266-jwt-binding new file mode 160000 index 0000000..939d676 --- /dev/null +++ b/worktrees/linear/nap-266-jwt-binding @@ -0,0 +1 @@ +Subproject commit 939d67615aa9b9d38fb53edf5e30a31ca0957e62 diff --git a/worktrees/linear/nap-270-perimeter-tests b/worktrees/linear/nap-270-perimeter-tests new file mode 160000 index 0000000..f3f6967 --- /dev/null +++ b/worktrees/linear/nap-270-perimeter-tests @@ -0,0 +1 @@ +Subproject commit f3f696790cf6dabaca95ff7599b469fb7f8f17bd diff --git a/worktrees/linear/nap-272-typed-perimeter b/worktrees/linear/nap-272-typed-perimeter new file mode 160000 index 0000000..eb6aeb4 --- /dev/null +++ b/worktrees/linear/nap-272-typed-perimeter @@ -0,0 +1 @@ +Subproject commit eb6aeb42415d859025f593beebb21364b34d6b1d diff --git a/worktrees/linear/nap-273a-urlencoder b/worktrees/linear/nap-273a-urlencoder new file mode 160000 index 0000000..4a00868 --- /dev/null +++ b/worktrees/linear/nap-273a-urlencoder @@ -0,0 +1 @@ +Subproject commit 4a008684f688947aaa0d17b7e1f0e3fbb7763e49