From 6981e056da4e5c95d94d22d30f7e415e63613e16 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 21:10:16 +0000 Subject: [PATCH 1/4] Initial plan From 0414801ab293a586d0bcffe56b798264c52934fc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 21:14:55 +0000 Subject: [PATCH 2/4] Add --path-root flag to set Dropbox-API-Path-Root header for team folder support Co-authored-by: neon-ninja <3378822+neon-ninja@users.noreply.github.com> --- cmd/root.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cmd/root.go b/cmd/root.go index 18da322..5143184 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -155,6 +155,7 @@ func initDbx(cmd *cobra.Command, args []string) (err error) { verbose, _ := cmd.Flags().GetBool("verbose") asMember, _ := cmd.Flags().GetString("as-member") domain, _ := cmd.Flags().GetString("domain") + pathRoot, _ := cmd.Flags().GetString("path-root") dir, err := homedir.Dir() if err != nil { @@ -197,6 +198,17 @@ func initDbx(cmd *cobra.Command, args []string) (err error) { if verbose { logLevel = dropbox.LogInfo } + + var headerGenerator func(hostType string, style string, namespace string, route string) map[string]string + if pathRoot != "" { + pathRootHeader := fmt.Sprintf(`{".tag": "namespace_id", "namespace_id": "%s"}`, pathRoot) + headerGenerator = func(_ string, _ string, _ string, _ string) map[string]string { + return map[string]string{ + "Dropbox-API-Path-Root": pathRootHeader, + } + } + } + config = dropbox.Config{ Token: tokens[tokType], LogLevel: logLevel, @@ -204,7 +216,7 @@ func initDbx(cmd *cobra.Command, args []string) (err error) { AsMemberID: asMember, Domain: domain, Client: nil, - HeaderGenerator: nil, + HeaderGenerator: headerGenerator, URLGenerator: nil, } @@ -232,6 +244,7 @@ func Execute() { func init() { RootCmd.PersistentFlags().BoolP("verbose", "v", false, "Enable verbose logging") RootCmd.PersistentFlags().String("as-member", "", "Member ID to perform action as") + RootCmd.PersistentFlags().String("path-root", "", "Namespace ID to use as the path root (for team folders; sets Dropbox-API-Path-Root header)") // This flag should only be used for testing. Marked hidden so it doesn't clutter usage etc. RootCmd.PersistentFlags().String("domain", "", "Override default Dropbox domain, useful for testing") RootCmd.PersistentFlags().MarkHidden("domain") From a6a241cda5dc7fc157d6e3d548d50126bb94d34c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 21:21:46 +0000 Subject: [PATCH 3/4] Auto-detect root namespace via GetCurrentAccount instead of manual --path-root flag Co-authored-by: neon-ninja <3378822+neon-ninja@users.noreply.github.com> --- cmd/root.go | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 5143184..05408f0 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -26,7 +26,9 @@ import ( "golang.org/x/oauth2" "github.com/dropbox/dropbox-sdk-go-unofficial/v6/dropbox" + "github.com/dropbox/dropbox-sdk-go-unofficial/v6/dropbox/common" "github.com/dropbox/dropbox-sdk-go-unofficial/v6/dropbox/files" + "github.com/dropbox/dropbox-sdk-go-unofficial/v6/dropbox/users" "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" "golang.org/x/net/context" @@ -155,7 +157,6 @@ func initDbx(cmd *cobra.Command, args []string) (err error) { verbose, _ := cmd.Flags().GetBool("verbose") asMember, _ := cmd.Flags().GetString("as-member") domain, _ := cmd.Flags().GetString("domain") - pathRoot, _ := cmd.Flags().GetString("path-root") dir, err := homedir.Dir() if err != nil { @@ -199,16 +200,6 @@ func initDbx(cmd *cobra.Command, args []string) (err error) { logLevel = dropbox.LogInfo } - var headerGenerator func(hostType string, style string, namespace string, route string) map[string]string - if pathRoot != "" { - pathRootHeader := fmt.Sprintf(`{".tag": "namespace_id", "namespace_id": "%s"}`, pathRoot) - headerGenerator = func(_ string, _ string, _ string, _ string) map[string]string { - return map[string]string{ - "Dropbox-API-Path-Root": pathRootHeader, - } - } - } - config = dropbox.Config{ Token: tokens[tokType], LogLevel: logLevel, @@ -216,10 +207,35 @@ func initDbx(cmd *cobra.Command, args []string) (err error) { AsMemberID: asMember, Domain: domain, Client: nil, - HeaderGenerator: headerGenerator, + HeaderGenerator: nil, URLGenerator: nil, } + // Auto-detect the root namespace so that team folders are accessible. + // Team manage tokens are for administrative operations and don't need + // a path root; skip auto-detection for those. + if tokType != tokenTeamManage { + usersClient := users.New(config) + account, accountErr := usersClient.GetCurrentAccount() + if accountErr != nil { + config.LogInfo("Warning: could not auto-detect root namespace (%v); team folders may not be accessible", accountErr) + } else { + var rootNamespaceID string + switch ri := account.RootInfo.(type) { + case *common.TeamRootInfo: + rootNamespaceID = ri.RootNamespaceId + case *common.UserRootInfo: + rootNamespaceID = ri.RootNamespaceId + } + if rootNamespaceID != "" { + pathRootHeader := fmt.Sprintf(`{".tag": "root", "root": "%s"}`, rootNamespaceID) + config.HeaderGenerator = func(_, _, _, _ string) map[string]string { + return map[string]string{"Dropbox-API-Path-Root": pathRootHeader} + } + } + } + } + return } @@ -244,7 +260,6 @@ func Execute() { func init() { RootCmd.PersistentFlags().BoolP("verbose", "v", false, "Enable verbose logging") RootCmd.PersistentFlags().String("as-member", "", "Member ID to perform action as") - RootCmd.PersistentFlags().String("path-root", "", "Namespace ID to use as the path root (for team folders; sets Dropbox-API-Path-Root header)") // This flag should only be used for testing. Marked hidden so it doesn't clutter usage etc. RootCmd.PersistentFlags().String("domain", "", "Override default Dropbox domain, useful for testing") RootCmd.PersistentFlags().MarkHidden("domain") From 361e7f8b933a8d5f36e550b3ea77639cd6220977 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 22:03:55 +0000 Subject: [PATCH 4/4] Fix ls / crashing with root path-root header by skipping get_metadata on root path Co-authored-by: neon-ninja <3378822+neon-ninja@users.noreply.github.com> --- cmd/ls.go | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/cmd/ls.go b/cmd/ls.go index 9ee7750..1aafc68 100644 --- a/cmd/ls.go +++ b/cmd/ls.go @@ -115,25 +115,29 @@ func ls(cmd *cobra.Command, args []string) (err error) { dbx := files.New(config) - // check if given object exists - var metaRes files.IsMetadata - metaRes, err = getFileMetadata(dbx, path) - if err != nil { - return err - } - if long { fmt.Fprint(w, "Revision\tSize\tLast modified\tPath\n") } - // handle case when path to file was given - switch f := metaRes.(type) { - case *files.FileMetadata: - if !onlyDeleted { - printItem(formatFileMetadata(f, long)) - err = w.Flush() + // Check whether the path exists and is a file rather than a folder. + // Skip this for the root path ("") since get_metadata returns an error for + // it ("The root folder is unsupported") and the root is always a folder. + if path != "" { + var metaRes files.IsMetadata + metaRes, err = getFileMetadata(dbx, path) + if err != nil { return err } + + // handle case when path to file was given + switch f := metaRes.(type) { + case *files.FileMetadata: + if !onlyDeleted { + printItem(formatFileMetadata(f, long)) + err = w.Flush() + return err + } + } } res, err := dbx.ListFolder(arg)