feat: open the file manager in the user's home directory

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
redteaandClaude Opus 5.5 committed 2026-10-13 20:31:41 +03:00
1 parent 5e5718b397
commit 201d63ee1e
2 files changed
+48 -1

No files matched your search

+39
View File
@@ -9,7 +9,9 @@ import (
"io" "io"
"os" "os"
"os/exec" "os/exec"
"os/user"
"path/filepath" "path/filepath"
"runtime"
"sort" "sort"
"strings" "strings"
"unicode/utf8" "unicode/utf8"
@@ -79,8 +81,18 @@ func fsList(path string) (proto.FSListResult, error) {
if path == "" { if path == "" {
path = "/" path = "/"
} }
// "~" / "~name" is where the file manager starts: the home directory, or
// the root when there is none to open.
home := strings.HasPrefix(path, "~") && !strings.Contains(path, "/")
if home {
path = homeDir(path[1:])
}
abs, _ := filepath.Abs(path) abs, _ := filepath.Abs(path)
entries, err := os.ReadDir(abs) entries, err := os.ReadDir(abs)
if err != nil && home && abs != "/" {
abs = "/"
entries, err = os.ReadDir(abs)
}
if err != nil { if err != nil {
return proto.FSListResult{}, err return proto.FSListResult{}, err
} }
@@ -222,3 +234,30 @@ func fsZip(paths []string, dest string) (any, error) {
} }
return map[string]string{"dest": dest}, nil return map[string]string{"dest": dest}, nil
} }
// homeDir returns the home directory of the named user ("" = the user the
// agent runs as), or "/" when it cannot be told.
func homeDir(name string) string {
if name != "" {
if validUserName(name) {
if u, err := user.Lookup(name); err == nil && u.HomeDir != "" {
return u.HomeDir
}
}
return "/"
}
if u, err := user.Current(); err == nil && u.HomeDir != "" {
return u.HomeDir
}
if h := os.Getenv("HOME"); h != "" {
return h
}
// A root service often has neither a passwd entry we can read nor $HOME.
if os.Geteuid() == 0 {
if runtime.GOOS == "darwin" {
return "/var/root"
}
return "/root"
}
return "/"
}
+9 -1
View File
@@ -282,7 +282,15 @@
['dragleave','drop'].forEach(x => drop.addEventListener(x, e => { e.preventDefault(); if(x!=='drop')drop.classList.remove('drag'); })); ['dragleave','drop'].forEach(x => drop.addEventListener(x, e => { e.preventDefault(); if(x!=='drop')drop.classList.remove('drag'); }));
drop.addEventListener('drop', e => { drop.classList.remove('drag'); if (e.dataTransfer.files.length) uploadFiles(e.dataTransfer.files); }); drop.addEventListener('drop', e => { drop.classList.remove('drag'); if (e.dataTransfer.files.length) uploadFiles(e.dataTransfer.files); });
load('/'); // Start in the home directory of the machine's user; an agent too old to
// know "~" fails that listing, so fall back to the root.
(async () => {
const r = await api('list', {path: '~' + {{.Agent.LoginUser}}});
if (!r.ok) { load('/'); return; }
cwd = r.data.path; entries = r.data.entries || []; selected.clear();
$('path').value = cwd;
render();
})();
})(); })();
</script> </script>
</body> </body>