From 38df11510da3d114f72c1478761e273209a4bd8a Mon Sep 17 00:00:00 2001
From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com>
Date: Tue, 7 Oct 2025 12:47:52 +0200
Subject: [PATCH 01/11] Add bot account authentication support and refactor
related functions
---
cmd/auth/create/create.go | 48 +++++++----
cmd/auth/login/login.go | 10 +--
cmd/auth/logout/logout.go | 2 +-
cmd/auth/status/status.go | 22 ++---
core/auth.go | 112 ++++++++++++++++----------
core/auth_test.go | 46 +++++------
core/keyring.go | 66 +++++++++++----
core/serviceprogram/serviceprogram.go | 16 ++--
core/stream.go | 2 +-
go.mod | 2 +-
go.sum | 12 +--
11 files changed, 199 insertions(+), 139 deletions(-)
diff --git a/cmd/auth/create/create.go b/cmd/auth/create/create.go
index 962b576..b306b0a 100644
--- a/cmd/auth/create/create.go
+++ b/cmd/auth/create/create.go
@@ -20,8 +20,8 @@ func NewCreateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create",
- Short: "Create a new account",
- Long: "Create a new Anytype account with a generated mnemonic phrase. The mnemonic is your master key for account recovery.",
+ Short: "Create a new bot account",
+ Long: "Create a new Anytype bot account with a generated account key. The account key is your credential for bot authentication.",
RunE: func(cmd *cobra.Command, args []string) error {
if name == "" {
output.Print("Enter account name: ")
@@ -34,33 +34,47 @@ func NewCreateCmd() *cobra.Command {
}
}
- mnemonic, accountId, err := core.CreateWallet(name, rootPath, apiAddr)
+ botAccountKey, accountId, err := core.CreateBotWallet(name, rootPath, apiAddr)
if err != nil {
return output.Error("failed to create account: %w", err)
}
- output.Success("Account created successfully!")
+ output.Success("Bot account created successfully!")
- output.Warning("IMPORTANT: Save your mnemonic phrase in a secure location.")
- output.Info(" This is the ONLY way to recover your account if you lose access.")
+ output.Warning("IMPORTANT: Save your bot account key in a secure location.")
+ output.Info(" This is the ONLY way to authenticate your bot account.")
- words := strings.Split(mnemonic, " ")
output.Print("")
- output.Print("╔════════════════════════════════════════════════════════╗")
- output.Print("║ MNEMONIC PHRASE ║")
- output.Print("╠════════════════════════════════════════════════════════╣")
- output.Print("║ %-52s ║", strings.Join(words[0:6], " "))
- output.Print("║ %-52s ║", strings.Join(words[6:12], " "))
- output.Print("╚════════════════════════════════════════════════════════╝")
+ keyLen := len(botAccountKey)
+ boxWidth := keyLen + 4 // 2 spaces padding on each side
+ if boxWidth < 24 { // Minimum width for "BOT ACCOUNT KEY" title
+ boxWidth = 24
+ }
+
+ topBorder := "╔" + strings.Repeat("═", boxWidth) + "╗"
+ midBorder := "╠" + strings.Repeat("═", boxWidth) + "╣"
+ botBorder := "╚" + strings.Repeat("═", boxWidth) + "╝"
+
+ title := "BOT ACCOUNT KEY"
+ titlePadding := (boxWidth - len(title)) / 2
+ titleLine := "║" + strings.Repeat(" ", titlePadding) + title + strings.Repeat(" ", boxWidth-titlePadding-len(title)) + "║"
+
+ keyLine := fmt.Sprintf("║ %s ║", botAccountKey)
+
+ output.Print(topBorder)
+ output.Print(titleLine)
+ output.Print(midBorder)
+ output.Print(keyLine)
+ output.Print(botBorder)
output.Print("")
- output.Print("📋 Account Details:")
+ output.Print("📋 Bot Account Details:")
output.Print(" Name: %s", name)
- output.Print(" Id: %s", accountId)
+ output.Print(" Account Id: %s", accountId)
output.Print("")
- output.Success("You are now logged in to your new account.")
- output.Success("Mnemonic saved to keychain.")
+ output.Success("You are now logged in to your new bot account.")
+ output.Success("Bot account key saved to keychain.")
return nil
},
diff --git a/cmd/auth/login/login.go b/cmd/auth/login/login.go
index 763debc..bc511a4 100644
--- a/cmd/auth/login/login.go
+++ b/cmd/auth/login/login.go
@@ -13,14 +13,14 @@ import (
func NewLoginCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "login",
- Short: "Log in to your account",
- Long: "Authenticate using your mnemonic phrase to access your Anytype account and stored data.",
+ Short: "Log in to your bot account",
+ Long: "Authenticate using your bot account key to access your Anytype bot account and stored data.",
RunE: func(cmd *cobra.Command, args []string) error {
- mnemonic, _ := cmd.Flags().GetString("mnemonic")
+ accountKey, _ := cmd.Flags().GetString("account-key")
rootPath, _ := cmd.Flags().GetString("path")
apiAddr, _ := cmd.Flags().GetString("api-addr")
- if err := core.Login(mnemonic, rootPath, apiAddr); err != nil {
+ if err := core.LoginBot(accountKey, rootPath, apiAddr); err != nil {
return output.Error("failed to log in: %w", err)
}
output.Success("Successfully logged in")
@@ -29,7 +29,7 @@ func NewLoginCmd() *cobra.Command {
},
}
- cmd.Flags().String("mnemonic", "", "Provide mnemonic (12 words) for authentication")
+ cmd.Flags().String("account-key", "", "Provide bot account key for authentication")
cmd.Flags().String("path", "", "Provide custom root path for wallet recovery")
cmd.Flags().String("api-addr", "", fmt.Sprintf("API listen address (default: %s)", config.DefaultAPIAddress))
diff --git a/cmd/auth/logout/logout.go b/cmd/auth/logout/logout.go
index 39adbcb..adac261 100644
--- a/cmd/auth/logout/logout.go
+++ b/cmd/auth/logout/logout.go
@@ -11,7 +11,7 @@ func NewLogoutCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "logout",
Short: "Log out and clear stored credentials",
- Long: "End your current session and remove stored authentication tokens and mnemonic from the system keychain.",
+ Long: "End your current session and remove stored authentication tokens and bot account key from the system keychain.",
RunE: func(cmd *cobra.Command, args []string) error {
if err := core.Logout(); err != nil {
return output.Error("failed to log out: %w", err)
diff --git a/cmd/auth/status/status.go b/cmd/auth/status/status.go
index f6dc20e..f727861 100644
--- a/cmd/auth/status/status.go
+++ b/cmd/auth/status/status.go
@@ -18,9 +18,9 @@ func NewStatusCmd() *cobra.Command {
Short: "Show authentication status",
Long: "Display current authentication status, including account information, server status, and stored credentials.",
RunE: func(cmd *cobra.Command, args []string) error {
- hasMnemonic := false
- if _, err := core.GetStoredMnemonic(); err == nil {
- hasMnemonic = true
+ hasBotKey := false
+ if _, err := core.GetStoredBotAccountKey(); err == nil {
+ hasBotKey = true
}
hasToken := false
@@ -43,19 +43,19 @@ func NewStatusCmd() *cobra.Command {
serverRunning = err == nil
// If server is running and we have a token, we're logged in
- // (server auto-logs in on restart using stored mnemonic)
+ // (server auto-logs in on restart using stored bot account key)
isLoggedIn := serverRunning && hasToken
// Display status based on priority: server -> credentials -> login
if !serverRunning {
output.Print("Server is not running. Run 'anytype serve' to start the server.")
- if hasMnemonic || hasToken || accountId != "" {
+ if hasBotKey || hasToken || accountId != "" {
output.Print("Credentials are stored in keychain.")
}
return nil
}
- if !hasMnemonic && !hasToken && accountId == "" {
+ if !hasBotKey && !hasToken && accountId == "" {
output.Print("Not authenticated. Run 'anytype auth login' to authenticate or 'anytype auth create' to create a new account.")
return nil
}
@@ -64,7 +64,7 @@ func NewStatusCmd() *cobra.Command {
if isLoggedIn && accountId != "" {
output.Print(" ✓ Logged in to account \033[1m%s\033[0m (keychain)", accountId)
- } else if hasToken || hasMnemonic {
+ } else if hasToken || hasBotKey {
output.Print(" ✗ Not logged in (credentials stored in keychain)")
if !isLoggedIn && hasToken {
output.Print(" Note: Server is not running or session expired. Run 'anytype serve' to start server.")
@@ -75,15 +75,15 @@ func NewStatusCmd() *cobra.Command {
output.Print(" - Active session: \033[1m%v\033[0m", isLoggedIn)
- if hasMnemonic {
- output.Print(" - Mnemonic: \033[1mstored\033[0m")
+ if hasBotKey {
+ output.Print(" - Bot Account Key: \033[1mstored\033[0m")
}
if hasToken {
if len(token) > 8 {
- output.Print(" - Token: \033[1m%s****\033[0m", token[:8])
+ output.Print(" - Session Token: \033[1m%s****\033[0m", token[:8])
} else {
- output.Print(" - Token: \033[1mstored\033[0m")
+ output.Print(" - Session Token: \033[1mstored\033[0m")
}
}
diff --git a/core/auth.go b/core/auth.go
index 341be37..890f053 100644
--- a/core/auth.go
+++ b/core/auth.go
@@ -43,8 +43,8 @@ func getDefaultWorkDir() string {
}
}
-// LoginAccount performs the common steps for logging in with a given mnemonic and root path.
-func LoginAccount(mnemonic, rootPath, apiAddr string) error {
+// LoginBotAccount performs the login steps for a bot account using a bot account key.
+func LoginBotAccount(botAccountKey, rootPath, apiAddr string) error {
if rootPath == "" {
rootPath = getDefaultDataPath()
}
@@ -55,7 +55,7 @@ func LoginAccount(mnemonic, rootPath, apiAddr string) error {
var sessionToken string
err := GRPCCallNoAuth(func(ctx context.Context, client service.ClientCommandsClient) error {
- _, err := client.InitialSetParameters(ctx, &pb.RpcInitialSetParametersRequest{
+ resp, err := client.InitialSetParameters(ctx, &pb.RpcInitialSetParametersRequest{
Platform: runtime.GOOS,
Version: Version,
Workdir: getDefaultWorkDir(),
@@ -63,24 +63,33 @@ func LoginAccount(mnemonic, rootPath, apiAddr string) error {
if err != nil {
return fmt.Errorf("failed to set initial parameters: %w", err)
}
+ if resp.Error.Code != pb.RpcInitialSetParametersResponseError_NULL {
+ return fmt.Errorf("failed to set initial parameters: %s", resp.Error.Description)
+ }
- _, err = client.WalletRecover(ctx, &pb.RpcWalletRecoverRequest{
- Mnemonic: mnemonic,
- RootPath: rootPath,
+ resp2, err := client.WalletRecover(ctx, &pb.RpcWalletRecoverRequest{
+ AccountKey: botAccountKey,
+ RootPath: rootPath,
})
if err != nil {
return fmt.Errorf("wallet recovery failed: %w", err)
}
+ if resp2.Error.Code != pb.RpcWalletRecoverResponseError_NULL {
+ return fmt.Errorf("wallet recovery failed: %s", resp2.Error.Description)
+ }
- resp, err := client.WalletCreateSession(ctx, &pb.RpcWalletCreateSessionRequest{
- Auth: &pb.RpcWalletCreateSessionRequestAuthOfMnemonic{
- Mnemonic: mnemonic,
+ resp3, err := client.WalletCreateSession(ctx, &pb.RpcWalletCreateSessionRequest{
+ Auth: &pb.RpcWalletCreateSessionRequestAuthOf{
+ AppKey: botAccountKey,
},
})
if err != nil {
return fmt.Errorf("failed to create session: %w", err)
}
- sessionToken = resp.Token
+ if resp3.Error.Code != pb.RpcWalletCreateSessionResponseError_NULL {
+ return fmt.Errorf("failed to create session: %s", resp3.Error.Description)
+ }
+ sessionToken = resp3.Token
return nil
})
@@ -150,49 +159,47 @@ func LoginAccount(mnemonic, rootPath, apiAddr string) error {
return nil
}
-func ValidateMnemonic(mnemonic string) error {
- if mnemonic == "" {
- return fmt.Errorf("mnemonic cannot be empty")
+func ValidateAccountKey(accountKey string) error {
+ if accountKey == "" {
+ return fmt.Errorf("bot account key cannot be empty")
}
-
- words := strings.Fields(mnemonic)
- if len(words) != 12 {
- return fmt.Errorf("mnemonic must be exactly 12 words, got %d", len(words))
+ // Bot account keys are typically base64 encoded strings
+ if len(accountKey) < 20 {
+ return fmt.Errorf("invalid bot account key format")
}
return nil
}
-func Login(mnemonic, rootPath, apiAddr string) error {
- usedStoredMnemonic := false
- if mnemonic == "" {
- storedMnemonic, err := GetStoredMnemonic()
- if err == nil && storedMnemonic != "" {
- mnemonic = storedMnemonic
- output.Info("Using stored mnemonic from keychain.")
- usedStoredMnemonic = true
+func LoginBot(accountKey, rootPath, apiAddr string) error {
+ usedStoredKey := false
+ if accountKey == "" {
+ storedKey, err := GetStoredBotAccountKey()
+ if err == nil && storedKey != "" {
+ accountKey = storedKey
+ output.Info("Using stored bot account key from keychain.")
+ usedStoredKey = true
} else {
- output.Print("Enter mnemonic (12 words): ")
+ output.Print("Enter bot account key: ")
reader := bufio.NewReader(os.Stdin)
- mnemonic, _ = reader.ReadString('\n')
- mnemonic = strings.TrimSpace(mnemonic)
+ accountKey, _ = reader.ReadString('\n')
+ accountKey = strings.TrimSpace(accountKey)
}
}
- if err := ValidateMnemonic(mnemonic); err != nil {
+ if err := ValidateAccountKey(accountKey); err != nil {
return err
}
- err := LoginAccount(mnemonic, rootPath, apiAddr)
- if err != nil {
- return fmt.Errorf("failed to log in: %w", err)
+ if err := LoginBotAccount(accountKey, rootPath, apiAddr); err != nil {
+ return err
}
- if !usedStoredMnemonic {
- if err := SaveMnemonic(mnemonic); err != nil {
- output.Warning("failed to save mnemonic in keychain: %v", err)
+ if !usedStoredKey {
+ if err := SaveBotAccountKey(accountKey); err != nil {
+ output.Warning("failed to save bot account key in keychain: %v", err)
} else {
- output.Success("Mnemonic saved to keychain.")
+ output.Success("Bot account key saved to keychain.")
}
}
@@ -231,8 +238,8 @@ func Logout() error {
return err
}
- if err := DeleteStoredMnemonic(); err != nil {
- return fmt.Errorf("failed to delete stored mnemonic: %w", err)
+ if err := DeleteStoredBotAccountKey(); err != nil {
+ return fmt.Errorf("failed to delete stored bot account key: %w", err)
}
if err := DeleteStoredToken(); err != nil {
@@ -249,8 +256,9 @@ func Logout() error {
return nil
}
-// CreateWallet creates a new wallet with the given root path and returns the mnemonic and account Id
-func CreateWallet(name, rootPath, apiAddr string) (string, string, error) {
+// CreateBotWallet creates a new bot wallet with the given root path and returns the bot account key and account Id
+// This creates a regular wallet but exports a bot-specific account key for authentication
+func CreateBotWallet(name, rootPath, apiAddr string) (string, string, error) {
if rootPath == "" {
rootPath = getDefaultDataPath()
}
@@ -258,8 +266,8 @@ func CreateWallet(name, rootPath, apiAddr string) (string, string, error) {
apiAddr = config.DefaultAPIAddress
}
- var mnemonic string
var sessionToken string
+ var mnemonic string
err := GRPCCallNoAuth(func(ctx context.Context, client service.ClientCommandsClient) error {
_, err := client.InitialSetParameters(ctx, &pb.RpcInitialSetParametersRequest{
@@ -341,7 +349,25 @@ func CreateWallet(name, rootPath, apiAddr string) (string, string, error) {
return "", "", err
}
- _ = SaveMnemonic(mnemonic)
+ var botAccountKey string
+ err = GRPCCall(func(ctx context.Context, client service.ClientCommandsClient) error {
+ resp, err := client.WalletExportBot(ctx, &pb.RpcWalletExportBotRequest{
+ Mnemonic: mnemonic,
+ Index: 0, // Use index 0 for the first bot account
+ })
+ if err != nil {
+ return fmt.Errorf("failed to export bot account key: %w", err)
+ }
+ botAccountKey = resp.AccountKey
+ return nil
+ })
+ if err != nil {
+ return "", "", err
+ }
+
+ if err := SaveBotAccountKey(botAccountKey); err != nil {
+ output.Warning("failed to save bot account key: %v", err)
+ }
configMgr := config.GetConfigManager()
if err := configMgr.Load(); err != nil {
@@ -356,5 +382,5 @@ func CreateWallet(name, rootPath, apiAddr string) (string, string, error) {
}
}
- return mnemonic, accountId, nil
+ return botAccountKey, accountId, nil
}
diff --git a/core/auth_test.go b/core/auth_test.go
index 73eb7af..3c0d5f6 100644
--- a/core/auth_test.go
+++ b/core/auth_test.go
@@ -97,60 +97,54 @@ func TestGetDefaultWorkDir(t *testing.T) {
}
}
-func TestValidateMnemonic(t *testing.T) {
+func TestValidateAccountKey(t *testing.T) {
tests := []struct {
name string
- mnemonic string
+ accountKey string
wantErr bool
errContains string
}{
{
- name: "valid 12 word mnemonic",
- mnemonic: "word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12",
- wantErr: false,
+ name: "valid bot account key",
+ accountKey: "somevalidbase64encodedkeythatislongenough",
+ wantErr: false,
},
{
- name: "valid 12 words with extra spaces",
- mnemonic: "word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12",
- wantErr: false,
- },
- {
- name: "invalid 11 word mnemonic",
- mnemonic: "word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11",
+ name: "empty account key",
+ accountKey: "",
wantErr: true,
- errContains: "must be exactly 12 words, got 11",
+ errContains: "bot account key cannot be empty",
},
{
- name: "invalid 13 word mnemonic",
- mnemonic: "word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12 word13",
+ name: "too short account key",
+ accountKey: "shortkey",
wantErr: true,
- errContains: "must be exactly 12 words, got 13",
+ errContains: "invalid bot account key format",
},
{
- name: "empty mnemonic",
- mnemonic: "",
- wantErr: true,
- errContains: "cannot be empty",
+ name: "minimum valid length key",
+ accountKey: "12345678901234567890", // exactly 20 chars
+ wantErr: false,
},
{
- name: "whitespace only",
- mnemonic: " ",
+ name: "just under minimum length",
+ accountKey: "1234567890123456789", // 19 chars
wantErr: true,
- errContains: "must be exactly 12 words, got 0",
+ errContains: "invalid bot account key format",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- err := ValidateMnemonic(tt.mnemonic)
+ err := ValidateAccountKey(tt.accountKey)
if (err != nil) != tt.wantErr {
- t.Errorf("ValidateMnemonic() error = %v, wantErr %v", err, tt.wantErr)
+ t.Errorf("ValidateAccountKey() error = %v, wantErr %v", err, tt.wantErr)
}
if err != nil && tt.errContains != "" {
if !strings.Contains(err.Error(), tt.errContains) {
- t.Errorf("ValidateMnemonic() error = %q, want to contain %q", err.Error(), tt.errContains)
+ t.Errorf("ValidateAccountKey() error = %q, want to contain %q", err.Error(), tt.errContains)
}
}
})
diff --git a/core/keyring.go b/core/keyring.go
index 59686e8..5416015 100644
--- a/core/keyring.go
+++ b/core/keyring.go
@@ -1,33 +1,67 @@
package core
-import "github.com/zalando/go-keyring"
+import (
+ "encoding/base64"
+ "strings"
+
+ "github.com/anyproto/anytype-cli/core/output"
+ "github.com/zalando/go-keyring"
+)
const (
- keyringService = "anytype-cli"
- keyringMnemonicUser = "mnemonic"
- keyringTokenUser = "session-token"
+ keyringService = "anytype-cli"
+ keyringTokenUser = "session-token"
+ keyringBotAccountUser = "bot-account-key"
)
-func SaveMnemonic(mnemonic string) error {
- return keyring.Set(keyringService, keyringMnemonicUser, mnemonic)
+func SaveToken(token string) error {
+ return keyring.Set(keyringService, keyringTokenUser, token)
}
-func GetStoredMnemonic() (string, error) {
- return keyring.Get(keyringService, keyringMnemonicUser)
+func GetStoredToken() (string, error) {
+ token, err := keyring.Get(keyringService, keyringTokenUser)
+ if err != nil {
+ return "", err
+ }
+ output.Info("Retrieved token from keyring %q", token)
+ // Handle go-keyring base64 encoding that may be added on some platforms
+ if strings.HasPrefix(token, "go-keyring-base64:") {
+ encoded := strings.TrimPrefix(token, "go-keyring-base64:")
+ decoded, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return "", err
+ }
+ token = string(decoded)
+ }
+ return token, nil
}
-func DeleteStoredMnemonic() error {
- return keyring.Delete(keyringService, keyringMnemonicUser)
+func DeleteStoredToken() error {
+ return keyring.Delete(keyringService, keyringTokenUser)
}
-func SaveToken(token string) error {
- return keyring.Set(keyringService, keyringTokenUser, token)
+func SaveBotAccountKey(accountKey string) error {
+ return keyring.Set(keyringService, keyringBotAccountUser, accountKey)
}
-func GetStoredToken() (string, error) {
- return keyring.Get(keyringService, keyringTokenUser)
+func GetStoredBotAccountKey() (string, error) {
+ key, err := keyring.Get(keyringService, keyringBotAccountUser)
+ if err != nil {
+ return "", err
+ }
+ output.Info("Retrieved key from keyring %q", key)
+ // Handle go-keyring base64 encoding that may be added on some platforms
+ if strings.HasPrefix(key, "go-keyring-base64:") {
+ encoded := strings.TrimPrefix(key, "go-keyring-base64:")
+ decoded, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return "", err
+ }
+ key = string(decoded)
+ }
+ return key, nil
}
-func DeleteStoredToken() error {
- return keyring.Delete(keyringService, keyringTokenUser)
+func DeleteStoredBotAccountKey() error {
+ return keyring.Delete(keyringService, keyringBotAccountUser)
}
diff --git a/core/serviceprogram/serviceprogram.go b/core/serviceprogram/serviceprogram.go
index a8f8075..32bf4c2 100644
--- a/core/serviceprogram/serviceprogram.go
+++ b/core/serviceprogram/serviceprogram.go
@@ -89,25 +89,25 @@ func (p *Program) run() {
}
func (p *Program) attemptAutoLogin() {
- mnemonic, err := core.GetStoredMnemonic()
- if err != nil || mnemonic == "" {
- output.Info("No stored mnemonic found, skipping auto-login")
+ botAccountKey, err := core.GetStoredBotAccountKey()
+ if err != nil || botAccountKey == "" {
+ output.Info("No stored bot account key found, skipping auto-login")
return
}
- output.Info("Found stored mnemonic, attempting auto-login...")
+ output.Info("Found stored bot account key, attempting auto-login...")
maxRetries := 5
for i := 0; i < maxRetries; i++ {
- if err := core.LoginAccount(mnemonic, "", ""); err != nil {
+ if err := core.LoginBotAccount(botAccountKey, "", ""); err != nil {
if i < maxRetries-1 {
time.Sleep(2 * time.Second)
continue
}
- output.Info("Failed to auto-login after %d attempts: %v", maxRetries, err)
+ output.Info("Failed to auto-login with bot key after %d attempts: %v", maxRetries, err)
} else {
- output.Success("Successfully logged in using stored mnemonic")
- break
+ output.Success("Successfully logged in using stored bot account key")
+ return
}
}
}
diff --git a/core/stream.go b/core/stream.go
index 37c4fce..dcd04f1 100644
--- a/core/stream.go
+++ b/core/stream.go
@@ -74,7 +74,7 @@ func (er *EventReceiver) receiveLoop(ctx context.Context) {
for {
event, err := er.stream.Recv()
if errors.Is(err, io.EOF) {
- output.Info("🔄 Event stream ended")
+ output.Info("Event stream ended")
return
}
if err != nil {
diff --git a/go.mod b/go.mod
index ac1d9e7..7a9d410 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.24.6
require (
github.com/anyproto/any-sync v0.10.3-0.20250924192345-ac39daeebf86
- github.com/anyproto/anytype-heart v0.48.18-hotfix-1.0.20250924191541-b7d0a25cfa2e
+ github.com/anyproto/anytype-heart v0.48.18-hotfix-1.0.20250924201504-831824ca3128
github.com/cheggaaa/mb/v3 v3.0.2
github.com/chzyer/readline v1.5.1
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
diff --git a/go.sum b/go.sum
index 1248c20..2a6e9a4 100644
--- a/go.sum
+++ b/go.sum
@@ -40,18 +40,10 @@ github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kk
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/anyproto/any-store v0.3.8 h1:s499vEwfAUVHZ0NpN/AliG94g2QwqUHTCrbSl27VXRk=
github.com/anyproto/any-store v0.3.8/go.mod h1:P9CnoL9Q06eh051DwtcvCiiWCwdXO7AbEILcnD6yrss=
-github.com/anyproto/any-sync v0.9.9-0.20250818132859-04a7b1bd8146 h1:kqYWSraI/8msZDQN71bSDqG/WJkgNiObgr0aDZTKDZ4=
-github.com/anyproto/any-sync v0.9.9-0.20250818132859-04a7b1bd8146/go.mod h1:ITG3xpDnFTOZ0lRnKdmQdggHv78fTyX9aNHXa+G+17U=
-github.com/anyproto/any-sync v0.10.2 h1:na1g2iAVX5/tef9+qjyRz+skVe6LoSvYmWV3YecareI=
-github.com/anyproto/any-sync v0.10.2/go.mod h1:kSAW2IXIeDSUabu9jMKJirgFCyM4a99lM6URR8GCH6A=
github.com/anyproto/any-sync v0.10.3-0.20250924192345-ac39daeebf86 h1:UzxlCEshfjtFmAh6hoKHCXNDZg94/EoO4xvYuzflLq4=
github.com/anyproto/any-sync v0.10.3-0.20250924192345-ac39daeebf86/go.mod h1:cRDgI+U2nXZC2PXXSCKS2FCHWEBurH7TyELOOkgDblQ=
-github.com/anyproto/anytype-heart v0.44.0-rc07 h1:kNE2gTB5BatFnXnKMsd4ufaYZojej7V7+jxCcgy98FE=
-github.com/anyproto/anytype-heart v0.44.0-rc07/go.mod h1:AH56ESbHjVJiqncPLucuUKuybx9GXW/N5S2U0gltP9o=
-github.com/anyproto/anytype-heart v0.48.18-hotfix-1 h1:DESNrdKrI80t4dl2pWZqaIz7rbm5fk4WnumdBZQ2Lig=
-github.com/anyproto/anytype-heart v0.48.18-hotfix-1/go.mod h1:SkiQ5c/fc/QamGkkSf+nFVWtODmnsqVERrGMlb0lhMQ=
-github.com/anyproto/anytype-heart v0.48.18-hotfix-1.0.20250924191541-b7d0a25cfa2e h1:6E/UbB+wR7o/lln1Ihgf1Gg2rn66i1VFQyWLB3KnFug=
-github.com/anyproto/anytype-heart v0.48.18-hotfix-1.0.20250924191541-b7d0a25cfa2e/go.mod h1:Uq9G8qiHekx/B41a1HYCXxZQEaNen43ac/mvh8oiSvc=
+github.com/anyproto/anytype-heart v0.48.18-hotfix-1.0.20250924201504-831824ca3128 h1:dXTF3Oj/JYqavxYWD6/nAHf9WATQeaBpEfbNze2HE4s=
+github.com/anyproto/anytype-heart v0.48.18-hotfix-1.0.20250924201504-831824ca3128/go.mod h1:Uq9G8qiHekx/B41a1HYCXxZQEaNen43ac/mvh8oiSvc=
github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20250716122732-cdcfe3a126bb h1:X1os44y0QWf1mYGj8BOoYKlXwY5xb94xTQIw1IIKJbY=
github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20250716122732-cdcfe3a126bb/go.mod h1:OzzODq4OigiRVD2lSOX1iHAoLcxhJDRbZb8n5PLG3WE=
github.com/anyproto/anytype-push-server/pushclient v0.0.0-20250801122506-553f6c085a23 h1:jXAjKY4g9ec7lDtayIlzM9u0/b3xGS9YgGA6JtRhHfU=
From 2705ae54eedf3f8d1a20e3bc60103d26a6f72d24 Mon Sep 17 00:00:00 2001
From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com>
Date: Tue, 7 Oct 2025 12:49:55 +0200
Subject: [PATCH 02/11] Add run configurations for 'anytype' and 'anytype
serve'
---
.run/anytype serve.run.xml | 19 +++++++++++++++++++
.run/anytype.run.xml | 21 +++++++++++++++++++++
2 files changed, 40 insertions(+)
create mode 100644 .run/anytype serve.run.xml
create mode 100644 .run/anytype.run.xml
diff --git a/.run/anytype serve.run.xml b/.run/anytype serve.run.xml
new file mode 100644
index 0000000..a1b3410
--- /dev/null
+++ b/.run/anytype serve.run.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/anytype.run.xml b/.run/anytype.run.xml
new file mode 100644
index 0000000..d9cca43
--- /dev/null
+++ b/.run/anytype.run.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
From 890f2f7d98009a6f92a27085c2ec6ae49af4c90a Mon Sep 17 00:00:00 2001
From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com>
Date: Tue, 28 Oct 2025 16:45:36 +0100
Subject: [PATCH 03/11] Support changed AccountKey auth protocol
---
cmd/auth/create/create.go | 6 +-
cmd/auth/status/status.go | 2 +-
core/auth.go | 42 ++----
core/keyring.go | 44 +------
core/serviceprogram/serviceprogram.go | 2 +-
go.mod | 57 ++++-----
go.sum | 178 ++++++++++----------------
7 files changed, 118 insertions(+), 213 deletions(-)
diff --git a/cmd/auth/create/create.go b/cmd/auth/create/create.go
index b306b0a..f135253 100644
--- a/cmd/auth/create/create.go
+++ b/cmd/auth/create/create.go
@@ -34,7 +34,7 @@ func NewCreateCmd() *cobra.Command {
}
}
- botAccountKey, accountId, err := core.CreateBotWallet(name, rootPath, apiAddr)
+ accountKey, accountId, err := core.CreateBotWallet(name, rootPath, apiAddr)
if err != nil {
return output.Error("failed to create account: %w", err)
}
@@ -45,7 +45,7 @@ func NewCreateCmd() *cobra.Command {
output.Info(" This is the ONLY way to authenticate your bot account.")
output.Print("")
- keyLen := len(botAccountKey)
+ keyLen := len(accountKey)
boxWidth := keyLen + 4 // 2 spaces padding on each side
if boxWidth < 24 { // Minimum width for "BOT ACCOUNT KEY" title
boxWidth = 24
@@ -59,7 +59,7 @@ func NewCreateCmd() *cobra.Command {
titlePadding := (boxWidth - len(title)) / 2
titleLine := "║" + strings.Repeat(" ", titlePadding) + title + strings.Repeat(" ", boxWidth-titlePadding-len(title)) + "║"
- keyLine := fmt.Sprintf("║ %s ║", botAccountKey)
+ keyLine := fmt.Sprintf("║ %s ║", accountKey)
output.Print(topBorder)
output.Print(titleLine)
diff --git a/cmd/auth/status/status.go b/cmd/auth/status/status.go
index f727861..1f772dd 100644
--- a/cmd/auth/status/status.go
+++ b/cmd/auth/status/status.go
@@ -19,7 +19,7 @@ func NewStatusCmd() *cobra.Command {
Long: "Display current authentication status, including account information, server status, and stored credentials.",
RunE: func(cmd *cobra.Command, args []string) error {
hasBotKey := false
- if _, err := core.GetStoredBotAccountKey(); err == nil {
+ if _, err := core.GetStoredAccountKey(); err == nil {
hasBotKey = true
}
diff --git a/core/auth.go b/core/auth.go
index 890f053..bf55b8d 100644
--- a/core/auth.go
+++ b/core/auth.go
@@ -44,7 +44,7 @@ func getDefaultWorkDir() string {
}
// LoginBotAccount performs the login steps for a bot account using a bot account key.
-func LoginBotAccount(botAccountKey, rootPath, apiAddr string) error {
+func LoginBotAccount(accountKey, rootPath, apiAddr string) error {
if rootPath == "" {
rootPath = getDefaultDataPath()
}
@@ -68,7 +68,7 @@ func LoginBotAccount(botAccountKey, rootPath, apiAddr string) error {
}
resp2, err := client.WalletRecover(ctx, &pb.RpcWalletRecoverRequest{
- AccountKey: botAccountKey,
+ AccountKey: accountKey,
RootPath: rootPath,
})
if err != nil {
@@ -79,8 +79,8 @@ func LoginBotAccount(botAccountKey, rootPath, apiAddr string) error {
}
resp3, err := client.WalletCreateSession(ctx, &pb.RpcWalletCreateSessionRequest{
- Auth: &pb.RpcWalletCreateSessionRequestAuthOf{
- AppKey: botAccountKey,
+ Auth: &pb.RpcWalletCreateSessionRequestAuthOfAccountKey{
+ AccountKey: accountKey,
},
})
if err != nil {
@@ -174,7 +174,7 @@ func ValidateAccountKey(accountKey string) error {
func LoginBot(accountKey, rootPath, apiAddr string) error {
usedStoredKey := false
if accountKey == "" {
- storedKey, err := GetStoredBotAccountKey()
+ storedKey, err := GetStoredAccountKey()
if err == nil && storedKey != "" {
accountKey = storedKey
output.Info("Using stored bot account key from keychain.")
@@ -196,7 +196,7 @@ func LoginBot(accountKey, rootPath, apiAddr string) error {
}
if !usedStoredKey {
- if err := SaveBotAccountKey(accountKey); err != nil {
+ if err := SaveAccountKey(accountKey); err != nil {
output.Warning("failed to save bot account key in keychain: %v", err)
} else {
output.Success("Bot account key saved to keychain.")
@@ -238,7 +238,7 @@ func Logout() error {
return err
}
- if err := DeleteStoredBotAccountKey(); err != nil {
+ if err := DeleteStoredAccountKey(); err != nil {
return fmt.Errorf("failed to delete stored bot account key: %w", err)
}
@@ -267,7 +267,7 @@ func CreateBotWallet(name, rootPath, apiAddr string) (string, string, error) {
}
var sessionToken string
- var mnemonic string
+ var accountKey string
err := GRPCCallNoAuth(func(ctx context.Context, client service.ClientCommandsClient) error {
_, err := client.InitialSetParameters(ctx, &pb.RpcInitialSetParametersRequest{
@@ -285,11 +285,11 @@ func CreateBotWallet(name, rootPath, apiAddr string) (string, string, error) {
if err != nil {
return fmt.Errorf("wallet creation failed: %w", err)
}
- mnemonic = createResp.Mnemonic
+ accountKey = createResp.AccountKey
sessionResp, err := client.WalletCreateSession(ctx, &pb.RpcWalletCreateSessionRequest{
- Auth: &pb.RpcWalletCreateSessionRequestAuthOfMnemonic{
- Mnemonic: mnemonic,
+ Auth: &pb.RpcWalletCreateSessionRequestAuthOfAccountKey{
+ AccountKey: accountKey,
},
})
if err != nil {
@@ -349,23 +349,7 @@ func CreateBotWallet(name, rootPath, apiAddr string) (string, string, error) {
return "", "", err
}
- var botAccountKey string
- err = GRPCCall(func(ctx context.Context, client service.ClientCommandsClient) error {
- resp, err := client.WalletExportBot(ctx, &pb.RpcWalletExportBotRequest{
- Mnemonic: mnemonic,
- Index: 0, // Use index 0 for the first bot account
- })
- if err != nil {
- return fmt.Errorf("failed to export bot account key: %w", err)
- }
- botAccountKey = resp.AccountKey
- return nil
- })
- if err != nil {
- return "", "", err
- }
-
- if err := SaveBotAccountKey(botAccountKey); err != nil {
+ if err := SaveAccountKey(accountKey); err != nil {
output.Warning("failed to save bot account key: %v", err)
}
@@ -382,5 +366,5 @@ func CreateBotWallet(name, rootPath, apiAddr string) (string, string, error) {
}
}
- return botAccountKey, accountId, nil
+ return accountKey, accountId, nil
}
diff --git a/core/keyring.go b/core/keyring.go
index 5416015..92df1f0 100644
--- a/core/keyring.go
+++ b/core/keyring.go
@@ -1,17 +1,13 @@
package core
import (
- "encoding/base64"
- "strings"
-
- "github.com/anyproto/anytype-cli/core/output"
"github.com/zalando/go-keyring"
)
const (
keyringService = "anytype-cli"
keyringTokenUser = "session-token"
- keyringBotAccountUser = "bot-account-key"
+ keyringBotAccountUser = "account-key"
)
func SaveToken(token string) error {
@@ -19,49 +15,21 @@ func SaveToken(token string) error {
}
func GetStoredToken() (string, error) {
- token, err := keyring.Get(keyringService, keyringTokenUser)
- if err != nil {
- return "", err
- }
- output.Info("Retrieved token from keyring %q", token)
- // Handle go-keyring base64 encoding that may be added on some platforms
- if strings.HasPrefix(token, "go-keyring-base64:") {
- encoded := strings.TrimPrefix(token, "go-keyring-base64:")
- decoded, err := base64.StdEncoding.DecodeString(encoded)
- if err != nil {
- return "", err
- }
- token = string(decoded)
- }
- return token, nil
+ return keyring.Get(keyringService, keyringTokenUser)
}
func DeleteStoredToken() error {
return keyring.Delete(keyringService, keyringTokenUser)
}
-func SaveBotAccountKey(accountKey string) error {
+func SaveAccountKey(accountKey string) error {
return keyring.Set(keyringService, keyringBotAccountUser, accountKey)
}
-func GetStoredBotAccountKey() (string, error) {
- key, err := keyring.Get(keyringService, keyringBotAccountUser)
- if err != nil {
- return "", err
- }
- output.Info("Retrieved key from keyring %q", key)
- // Handle go-keyring base64 encoding that may be added on some platforms
- if strings.HasPrefix(key, "go-keyring-base64:") {
- encoded := strings.TrimPrefix(key, "go-keyring-base64:")
- decoded, err := base64.StdEncoding.DecodeString(encoded)
- if err != nil {
- return "", err
- }
- key = string(decoded)
- }
- return key, nil
+func GetStoredAccountKey() (string, error) {
+ return keyring.Get(keyringService, keyringBotAccountUser)
}
-func DeleteStoredBotAccountKey() error {
+func DeleteStoredAccountKey() error {
return keyring.Delete(keyringService, keyringBotAccountUser)
}
diff --git a/core/serviceprogram/serviceprogram.go b/core/serviceprogram/serviceprogram.go
index 32bf4c2..02d3431 100644
--- a/core/serviceprogram/serviceprogram.go
+++ b/core/serviceprogram/serviceprogram.go
@@ -89,7 +89,7 @@ func (p *Program) run() {
}
func (p *Program) attemptAutoLogin() {
- botAccountKey, err := core.GetStoredBotAccountKey()
+ botAccountKey, err := core.GetStoredAccountKey()
if err != nil || botAccountKey == "" {
output.Info("No stored bot account key found, skipping auto-login")
return
diff --git a/go.mod b/go.mod
index 7a9d410..dcf78f8 100644
--- a/go.mod
+++ b/go.mod
@@ -3,8 +3,8 @@ module github.com/anyproto/anytype-cli
go 1.24.6
require (
- github.com/anyproto/any-sync v0.10.3-0.20250924192345-ac39daeebf86
- github.com/anyproto/anytype-heart v0.48.18-hotfix-1.0.20250924201504-831824ca3128
+ github.com/anyproto/any-sync v0.11.2-0.20251028122509-60b4b25dd9f1
+ github.com/anyproto/anytype-heart v0.44.7-0.20251028140914-4ac7e6ade68d
github.com/cheggaaa/mb/v3 v3.0.2
github.com/chzyer/readline v1.5.1
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
@@ -13,14 +13,13 @@ require (
github.com/kardianos/service v1.2.4
github.com/spf13/cobra v1.9.1
github.com/zalando/go-keyring v0.2.6
- google.golang.org/grpc v1.74.2
+ google.golang.org/grpc v1.75.0
)
require (
al.essio.dev/pkg/shellescape v1.6.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/JohannesKaufmann/html-to-markdown v1.6.0 // indirect
- github.com/Jorropo/jsync v1.0.1 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/goquery v1.10.2 // indirect
github.com/VividCortex/ewma v1.2.0 // indirect
@@ -28,7 +27,7 @@ require (
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect
github.com/andybalholm/cascadia v1.3.3 // indirect
- github.com/anyproto/any-store v0.3.8 // indirect
+ github.com/anyproto/any-store v0.4.2 // indirect
github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20250716122732-cdcfe3a126bb // indirect
github.com/anyproto/anytype-push-server/pushclient v0.0.0-20250801122506-553f6c085a23 // indirect
github.com/anyproto/go-chash v0.1.0 // indirect
@@ -76,7 +75,8 @@ require (
github.com/ethereum/go-ethereum v1.13.15 // indirect
github.com/flopp/go-findfont v0.1.0 // indirect
github.com/fogleman/gg v1.3.0 // indirect
- github.com/gabriel-vasile/mimetype v1.4.9 // indirect
+ github.com/gabriel-vasile/mimetype v1.4.10 // indirect
+ github.com/gammazero/chanqueue v1.1.1 // indirect
github.com/gammazero/deque v1.1.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.10.0 // indirect
@@ -131,13 +131,15 @@ require (
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/ipfs/bbloom v0.0.4 // indirect
- github.com/ipfs/boxo v0.34.0 // indirect
+ github.com/ipfs/boxo v0.35.0 // indirect
github.com/ipfs/go-bitfield v1.1.0 // indirect
- github.com/ipfs/go-block-format v0.2.2 // indirect
+ github.com/ipfs/go-block-format v0.2.3 // indirect
github.com/ipfs/go-cid v0.5.0 // indirect
- github.com/ipfs/go-datastore v0.8.3 // indirect
+ github.com/ipfs/go-cidutil v0.1.0 // indirect
+ github.com/ipfs/go-datastore v0.9.0 // indirect
github.com/ipfs/go-ds-flatfs v0.5.5 // indirect
- github.com/ipfs/go-ipld-format v0.6.2 // indirect
+ github.com/ipfs/go-dsqueue v0.0.5 // indirect
+ github.com/ipfs/go-ipld-format v0.6.3 // indirect
github.com/ipfs/go-ipld-legacy v0.2.2 // indirect
github.com/ipfs/go-log v1.0.5 // indirect
github.com/ipfs/go-log/v2 v2.8.1 // indirect
@@ -155,9 +157,7 @@ require (
github.com/kovidgoyal/imaging v1.6.4 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
- github.com/libp2p/go-libp2p v0.43.0 // indirect
- github.com/libp2p/go-libp2p-record v0.3.1 // indirect
- github.com/libp2p/go-libp2p-routing-helpers v0.7.5 // indirect
+ github.com/libp2p/go-libp2p v0.44.0 // indirect
github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
@@ -198,7 +198,7 @@ require (
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.17.0 // indirect
- github.com/quic-go/quic-go v0.54.0 // indirect
+ github.com/quic-go/quic-go v0.55.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rs/cors v1.11.0 // indirect
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect
@@ -232,28 +232,27 @@ require (
go.abhg.dev/goldmark/wikilink v0.6.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
- go.opentelemetry.io/otel v1.37.0 // indirect
- go.opentelemetry.io/otel/metric v1.37.0 // indirect
- go.opentelemetry.io/otel/trace v1.37.0 // indirect
+ go.opentelemetry.io/otel v1.38.0 // indirect
+ go.opentelemetry.io/otel/metric v1.38.0 // indirect
+ go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
- go.uber.org/mock v0.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
golang.org/x/arch v0.8.0 // indirect
- golang.org/x/crypto v0.42.0 // indirect
- golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
+ golang.org/x/crypto v0.43.0 // indirect
+ golang.org/x/exp v0.0.0-20250911091902-df9299821621 // indirect
golang.org/x/image v0.27.0 // indirect
- golang.org/x/mod v0.28.0 // indirect
- golang.org/x/net v0.44.0 // indirect
- golang.org/x/oauth2 v0.30.0 // indirect
+ golang.org/x/mod v0.29.0 // indirect
+ golang.org/x/net v0.46.0 // indirect
+ golang.org/x/oauth2 v0.31.0 // indirect
golang.org/x/sync v0.17.0 // indirect
- golang.org/x/sys v0.36.0 // indirect
- golang.org/x/text v0.29.0 // indirect
- golang.org/x/time v0.13.0 // indirect
- golang.org/x/tools v0.37.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect
- google.golang.org/protobuf v1.36.9 // indirect
+ golang.org/x/sys v0.37.0 // indirect
+ golang.org/x/text v0.30.0 // indirect
+ golang.org/x/time v0.14.0 // indirect
+ golang.org/x/tools v0.38.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
+ google.golang.org/protobuf v1.36.10 // indirect
gopkg.in/Graylog2/go-gelf.v2 v2.0.0-20191017102106-1550ee647df0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index 2a6e9a4..aea289a 100644
--- a/go.sum
+++ b/go.sum
@@ -7,8 +7,6 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/Jorropo/jsync v1.0.1 h1:6HgRolFZnsdfzRUj+ImB9og1JYOxQoReSywkHOGSaUU=
-github.com/Jorropo/jsync v1.0.1/go.mod h1:jCOZj3vrBCri3bSU3ErUYvevKlnbssrXeCivybS5ABQ=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
@@ -38,12 +36,12 @@ github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5/go.mod h
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
-github.com/anyproto/any-store v0.3.8 h1:s499vEwfAUVHZ0NpN/AliG94g2QwqUHTCrbSl27VXRk=
-github.com/anyproto/any-store v0.3.8/go.mod h1:P9CnoL9Q06eh051DwtcvCiiWCwdXO7AbEILcnD6yrss=
-github.com/anyproto/any-sync v0.10.3-0.20250924192345-ac39daeebf86 h1:UzxlCEshfjtFmAh6hoKHCXNDZg94/EoO4xvYuzflLq4=
-github.com/anyproto/any-sync v0.10.3-0.20250924192345-ac39daeebf86/go.mod h1:cRDgI+U2nXZC2PXXSCKS2FCHWEBurH7TyELOOkgDblQ=
-github.com/anyproto/anytype-heart v0.48.18-hotfix-1.0.20250924201504-831824ca3128 h1:dXTF3Oj/JYqavxYWD6/nAHf9WATQeaBpEfbNze2HE4s=
-github.com/anyproto/anytype-heart v0.48.18-hotfix-1.0.20250924201504-831824ca3128/go.mod h1:Uq9G8qiHekx/B41a1HYCXxZQEaNen43ac/mvh8oiSvc=
+github.com/anyproto/any-store v0.4.2 h1:1ljcAogeZxQ6QmSpBy40InokgKBRB/fnAilDDFPUpYE=
+github.com/anyproto/any-store v0.4.2/go.mod h1:P9CnoL9Q06eh051DwtcvCiiWCwdXO7AbEILcnD6yrss=
+github.com/anyproto/any-sync v0.11.2-0.20251028122509-60b4b25dd9f1 h1:OwuaA0i4yUKqWk3TLV6kFB25EjCa3xEjj3O14+HHp1k=
+github.com/anyproto/any-sync v0.11.2-0.20251028122509-60b4b25dd9f1/go.mod h1:fX0zyqrV9h7LFxH4eYPEAAdTfll+55hWJzx81qgBbh8=
+github.com/anyproto/anytype-heart v0.44.7-0.20251028140914-4ac7e6ade68d h1:9NN6EpxFjE65uhjmUSL/UH+RAEkkkfY7IOfMHvtm21A=
+github.com/anyproto/anytype-heart v0.44.7-0.20251028140914-4ac7e6ade68d/go.mod h1:yzDgR58Yt61nnRQCumVsPvqNq2sDHck9l7cgwh9kDLU=
github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20250716122732-cdcfe3a126bb h1:X1os44y0QWf1mYGj8BOoYKlXwY5xb94xTQIw1IIKJbY=
github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20250716122732-cdcfe3a126bb/go.mod h1:OzzODq4OigiRVD2lSOX1iHAoLcxhJDRbZb8n5PLG3WE=
github.com/anyproto/anytype-push-server/pushclient v0.0.0-20250801122506-553f6c085a23 h1:jXAjKY4g9ec7lDtayIlzM9u0/b3xGS9YgGA6JtRhHfU=
@@ -235,19 +233,15 @@ github.com/filecoin-project/go-clock v0.1.0 h1:SFbYIM75M8NnFm1yMHhN9Ahy3W5bEZV9g
github.com/filecoin-project/go-clock v0.1.0/go.mod h1:4uB/O4PvOjlx1VCMdZ9MyDZXRm//gkj1ELEbxfI1AZs=
github.com/flopp/go-findfont v0.1.0 h1:lPn0BymDUtJo+ZkV01VS3661HL6F4qFlkhcJN55u6mU=
github.com/flopp/go-findfont v0.1.0/go.mod h1:wKKxRDjD024Rh7VMwoU90i6ikQRCr+JTHB5n4Ejkqvw=
-github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
-github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
-github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
-github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
-github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
+github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
+github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gammazero/chanqueue v1.1.1 h1:n9Y+zbBxw2f7uUE9wpgs0rOSkP/I/yhDLiNuhyVjojQ=
github.com/gammazero/chanqueue v1.1.1/go.mod h1:fMwpwEiuUgpab0sH4VHiVcEoji1pSi+EIzeG4TPeKPc=
github.com/gammazero/deque v1.1.0 h1:OyiyReBbnEG2PP0Bnv1AASLIYvyKqIFN5xfl1t8oGLo=
@@ -402,8 +396,6 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
-github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
@@ -486,24 +478,28 @@ github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
-github.com/ipfs/boxo v0.34.0 h1:pMP9bAsTs4xVh8R0ZmxIWviV7kjDa60U24QrlGgHb1g=
-github.com/ipfs/boxo v0.34.0/go.mod h1:kzdH/ewDybtO3+M8MCVkpwnIIc/d2VISX95DFrY4vQA=
+github.com/ipfs/boxo v0.35.0 h1:3Mku5arSbAZz0dvb4goXRsQuZkFkPrGr5yYdu0YM1pY=
+github.com/ipfs/boxo v0.35.0/go.mod h1:uhaF0DGnbgEiXDTmD249jCGbxVkMm6+Ew85q6Uub7lo=
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
-github.com/ipfs/go-block-format v0.2.2 h1:uecCTgRwDIXyZPgYspaLXoMiMmxQpSx2aq34eNc4YvQ=
-github.com/ipfs/go-block-format v0.2.2/go.mod h1:vmuefuWU6b+9kIU0vZJgpiJt1yicQz9baHXE8qR+KB8=
+github.com/ipfs/go-block-format v0.2.3 h1:mpCuDaNXJ4wrBJLrtEaGFGXkferrw5eqVvzaHhtFKQk=
+github.com/ipfs/go-block-format v0.2.3/go.mod h1:WJaQmPAKhD3LspLixqlqNFxiZ3BZ3xgqxxoSR/76pnA=
github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg=
github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk=
-github.com/ipfs/go-datastore v0.8.3 h1:z391GsQyGKUIUof2tPoaZVeDknbt7fNHs6Gqjcw5Jo4=
-github.com/ipfs/go-datastore v0.8.3/go.mod h1:raxQ/CreIy9L6MxT71ItfMX12/ASN6EhXJoUFjICQ2M=
+github.com/ipfs/go-cidutil v0.1.0 h1:RW5hO7Vcf16dplUU60Hs0AKDkQAVPVplr7lk97CFL+Q=
+github.com/ipfs/go-cidutil v0.1.0/go.mod h1:e7OEVBMIv9JaOxt9zaGEmAoSlXW9jdFZ5lP/0PwcfpA=
+github.com/ipfs/go-datastore v0.9.0 h1:WocriPOayqalEsueHv6SdD4nPVl4rYMfYGLD4bqCZ+w=
+github.com/ipfs/go-datastore v0.9.0/go.mod h1:uT77w/XEGrvJWwHgdrMr8bqCN6ZTW9gzmi+3uK+ouHg=
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
+github.com/ipfs/go-dsqueue v0.0.5 h1:TUOk15TlCJ/NKV8Yk2W5wgkEjDa44Nem7a7FGIjsMNU=
+github.com/ipfs/go-dsqueue v0.0.5/go.mod h1:i/jAlpZjBbQJLioN+XKbFgnd+u9eAhGZs9IrqIzTd9g=
github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=
github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
github.com/ipfs/go-ipfs-pq v0.0.3 h1:YpoHVJB+jzK15mr/xsWC574tyDLkezVrDNeaalQBsTE=
github.com/ipfs/go-ipfs-pq v0.0.3/go.mod h1:btNw5hsHBpRcSSgZtiNm/SLj5gYIZ18AKtv3kERkRb4=
-github.com/ipfs/go-ipld-format v0.6.2 h1:bPZQ+A05ol0b3lsJSl0bLvwbuQ+HQbSsdGTy4xtYUkU=
-github.com/ipfs/go-ipld-format v0.6.2/go.mod h1:nni2xFdHKx5lxvXJ6brt/pndtGxKAE+FPR1rg4jTkyk=
+github.com/ipfs/go-ipld-format v0.6.3 h1:9/lurLDTotJpZSuL++gh3sTdmcFhVkCwsgx2+rAh4j8=
+github.com/ipfs/go-ipld-format v0.6.3/go.mod h1:74ilVN12NXVMIV+SrBAyC05UJRk0jVvGqdmrcYZvCBk=
github.com/ipfs/go-ipld-legacy v0.2.2 h1:DThbqCPVLpWBcGtU23KDLiY2YRZZnTkXQyfz8aOfBkQ=
github.com/ipfs/go-ipld-legacy v0.2.2/go.mod h1:hhkj+b3kG9b2BcUNw8IFYAsfeNo8E3U7eYlWeAOPyDU=
github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8=
@@ -512,8 +508,10 @@ github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6
github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY=
github.com/ipfs/go-peertaskqueue v0.8.2 h1:PaHFRaVFdxQk1Qo3OKiHPYjmmusQy7gKQUaL8JDszAU=
github.com/ipfs/go-peertaskqueue v0.8.2/go.mod h1:L6QPvou0346c2qPJNiJa6BvOibxDfaiPlqHInmzg0FA=
-github.com/ipfs/go-test v0.2.2 h1:1yjYyfbdt1w93lVzde6JZ2einh3DIV40at4rVoyEcE8=
-github.com/ipfs/go-test v0.2.2/go.mod h1:cmLisgVwkdRCnKu/CFZOk2DdhOcwghr5GsHeqwexoRA=
+github.com/ipfs/go-test v0.2.3 h1:Z/jXNAReQFtCYyn7bsv/ZqUwS6E7iIcSpJ2CuzCvnrc=
+github.com/ipfs/go-test v0.2.3/go.mod h1:QW8vSKkwYvWFwIZQLGQXdkt9Ud76eQXRQ9Ao2H+cA1o=
+github.com/ipfs/go-unixfsnode v1.10.2 h1:TREegX1J4X+k1w4AhoDuxxFvVcS9SegMRvrmxF6Tca8=
+github.com/ipfs/go-unixfsnode v1.10.2/go.mod h1:ImDPTSiKZ+2h4UVdkSDITJHk87bUAp7kX/lgifjRicg=
github.com/ipld/go-codec-dagpb v1.7.0 h1:hpuvQjCSVSLnTnHXn+QAMR0mLmb1gA6wl10LExo2Ts0=
github.com/ipld/go-codec-dagpb v1.7.0/go.mod h1:rD3Zg+zub9ZnxcLwfol/OTQRVjaLzXypgy4UqHQvilM=
github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
@@ -588,20 +586,18 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
github.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784=
github.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo=
-github.com/libp2p/go-libp2p v0.43.0 h1:b2bg2cRNmY4HpLK8VHYQXLX2d3iND95OjodLFymvqXU=
-github.com/libp2p/go-libp2p v0.43.0/go.mod h1:IiSqAXDyP2sWH+J2gs43pNmB/y4FOi2XQPbsb+8qvzc=
+github.com/libp2p/go-libp2p v0.44.0 h1:5Gtt8OrF8yiXmH+Mx4+/iBeFRMK1TY3a8OrEBDEqAvs=
+github.com/libp2p/go-libp2p v0.44.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc=
github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
github.com/libp2p/go-libp2p-record v0.3.1 h1:cly48Xi5GjNw5Wq+7gmjfBiG9HCzQVkiZOUZ8kUl+Fg=
github.com/libp2p/go-libp2p-record v0.3.1/go.mod h1:T8itUkLcWQLCYMqtX7Th6r7SexyUJpIyPgks757td/E=
-github.com/libp2p/go-libp2p-routing-helpers v0.7.5 h1:HdwZj9NKovMx0vqq6YNPTh6aaNzey5zHD7HeLJtq6fI=
-github.com/libp2p/go-libp2p-routing-helpers v0.7.5/go.mod h1:3YaxrwP0OBPDD7my3D0KxfR89FlcX/IEbxDEDfAmj98=
github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=
github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg=
github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=
github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=
-github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8=
-github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE=
+github.com/libp2p/go-netroute v0.3.0 h1:nqPCXHmeNmgTJnktosJ/sIef9hvwYCrsLxXmfNks/oc=
+github.com/libp2p/go-netroute v0.3.0/go.mod h1:Nkd5ShYgSMS5MUKy/MU2T57xFoOKvvLR92Lic48LEyA=
github.com/libp2p/go-yamux/v5 v5.0.1 h1:f0WoX/bEF2E8SbE4c/k1Mo+/9z0O4oC/hWEA+nfYRSg=
github.com/libp2p/go-yamux/v5 v5.0.1/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
@@ -738,44 +734,6 @@ github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o=
-github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M=
-github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk=
-github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE=
-github.com/pion/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E=
-github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU=
-github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4=
-github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw=
-github.com/pion/interceptor v0.1.40 h1:e0BjnPcGpr2CFQgKhrQisBU7V3GXK6wrfYrGYaU6Jq4=
-github.com/pion/interceptor v0.1.40/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic=
-github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI=
-github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90=
-github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
-github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
-github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
-github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
-github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=
-github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0=
-github.com/pion/rtp v1.8.19 h1:jhdO/3XhL/aKm/wARFVmvTfq0lC/CvN1xwYKmduly3c=
-github.com/pion/rtp v1.8.19/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk=
-github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE=
-github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE=
-github.com/pion/sdp/v3 v3.0.13 h1:uN3SS2b+QDZnWXgdr69SM8KB4EbcnPnPf2Laxhty/l4=
-github.com/pion/sdp/v3 v3.0.13/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E=
-github.com/pion/srtp/v3 v3.0.6 h1:E2gyj1f5X10sB/qILUGIkL4C2CqK269Xq167PbGCc/4=
-github.com/pion/srtp/v3 v3.0.6/go.mod h1:BxvziG3v/armJHAaJ87euvkhHqWe9I7iiOy50K2QkhY=
-github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
-github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
-github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw=
-github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU=
-github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q=
-github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E=
-github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0=
-github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
-github.com/pion/turn/v4 v4.0.2 h1:ZqgQ3+MjP32ug30xAbD6Mn+/K4Sxi3SdNOTFf+7mpps=
-github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7IToA1zs=
-github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54=
-github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -820,12 +778,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
-github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
-github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
-github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
-github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
-github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssklE09bA70=
-github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao=
+github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
+github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
@@ -941,8 +895,6 @@ github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSD
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E=
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8=
-github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
-github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
@@ -980,16 +932,16 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
-go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
-go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
-go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
-go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
-go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
-go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
-go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
-go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
-go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
-go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
+go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
+go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
+go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
+go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
+go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
+go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
+go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
+go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
+go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
+go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -1036,13 +988,13 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
-golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
-golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
+golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
+golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
-golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
-golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
+golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU=
+golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -1065,8 +1017,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
-golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
+golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
+golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1110,13 +1062,13 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
-golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
-golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
+golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
+golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
-golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
+golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo=
+golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1187,8 +1139,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
-golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
+golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1211,12 +1163,12 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
-golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
-golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
+golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
+golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
-golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
+golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
+golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1241,12 +1193,14 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
-golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
+golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
+golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
+gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1260,8 +1214,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -1277,8 +1231,8 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
-google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
+google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
+google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1289,8 +1243,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
-google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
+google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
+google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
From 06ec57fd96f7ae17b58e65c052c5b74bacda845b Mon Sep 17 00:00:00 2001
From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com>
Date: Thu, 30 Oct 2025 23:42:38 +0100
Subject: [PATCH 04/11] Improve error messages on exactArgs requirement
---
cmd/auth/apikey/create/create.go | 3 ++-
cmd/auth/apikey/revoke/revoke.go | 3 ++-
cmd/cmdutil/args.go | 19 +++++++++++++++++++
cmd/config/set/set.go | 6 ++++--
cmd/space/join/join.go | 7 ++++---
cmd/space/leave/leave.go | 3 ++-
6 files changed, 33 insertions(+), 8 deletions(-)
create mode 100644 cmd/cmdutil/args.go
diff --git a/cmd/auth/apikey/create/create.go b/cmd/auth/apikey/create/create.go
index b32d375..8bbe46f 100644
--- a/cmd/auth/apikey/create/create.go
+++ b/cmd/auth/apikey/create/create.go
@@ -3,6 +3,7 @@ package create
import (
"github.com/spf13/cobra"
+ "github.com/anyproto/anytype-cli/cmd/cmdutil"
"github.com/anyproto/anytype-cli/core"
"github.com/anyproto/anytype-cli/core/output"
)
@@ -12,7 +13,7 @@ func NewCreateCmd() *cobra.Command {
Use: "create [name]",
Short: "Create a new API key",
Long: "Create a new API key for programmatic access to Anytype",
- Args: cobra.ExactArgs(1),
+ Args: cmdutil.ExactArgs(1, "cannot create API key: name argument required"),
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
diff --git a/cmd/auth/apikey/revoke/revoke.go b/cmd/auth/apikey/revoke/revoke.go
index b8aad78..780a492 100644
--- a/cmd/auth/apikey/revoke/revoke.go
+++ b/cmd/auth/apikey/revoke/revoke.go
@@ -3,6 +3,7 @@ package revoke
import (
"github.com/spf13/cobra"
+ "github.com/anyproto/anytype-cli/cmd/cmdutil"
"github.com/anyproto/anytype-cli/core"
"github.com/anyproto/anytype-cli/core/output"
)
@@ -12,7 +13,7 @@ func NewRevokeCmd() *cobra.Command {
Use: "revoke ",
Short: "Revoke an API key",
Long: "Revoke an API key by its Id",
- Args: cobra.ExactArgs(1),
+ Args: cmdutil.ExactArgs(1, "cannot revoke API key: Id argument required"),
RunE: func(cmd *cobra.Command, args []string) error {
appId := args[0]
diff --git a/cmd/cmdutil/args.go b/cmd/cmdutil/args.go
new file mode 100644
index 0000000..76ffd3f
--- /dev/null
+++ b/cmd/cmdutil/args.go
@@ -0,0 +1,19 @@
+package cmdutil
+
+import (
+ "fmt"
+
+ "github.com/spf13/cobra"
+)
+
+func ExactArgs(n int, msg string) cobra.PositionalArgs {
+ return func(cmd *cobra.Command, args []string) error {
+ if len(args) > n {
+ return fmt.Errorf("too many arguments")
+ }
+ if len(args) < n {
+ return fmt.Errorf("%s", msg)
+ }
+ return nil
+ }
+}
diff --git a/cmd/config/set/set.go b/cmd/config/set/set.go
index 09a90f4..114a6a6 100644
--- a/cmd/config/set/set.go
+++ b/cmd/config/set/set.go
@@ -1,9 +1,11 @@
package set
import (
+ "github.com/spf13/cobra"
+
+ "github.com/anyproto/anytype-cli/cmd/cmdutil"
"github.com/anyproto/anytype-cli/core/config"
"github.com/anyproto/anytype-cli/core/output"
- "github.com/spf13/cobra"
)
func NewSetCmd() *cobra.Command {
@@ -11,7 +13,7 @@ func NewSetCmd() *cobra.Command {
Use: "set ",
Short: "Set a configuration value",
Long: `Set a specific configuration value`,
- Args: cobra.ExactArgs(2),
+ Args: cmdutil.ExactArgs(2, "cannot set config: key and value arguments required"),
RunE: func(cmd *cobra.Command, args []string) error {
key := args[0]
value := args[1]
diff --git a/cmd/space/join/join.go b/cmd/space/join/join.go
index 0506cbe..fb6f846 100644
--- a/cmd/space/join/join.go
+++ b/cmd/space/join/join.go
@@ -1,14 +1,15 @@
package join
import (
- "github.com/anyproto/anytype-cli/core/config"
- "github.com/anyproto/anytype-cli/core/output"
"net/url"
"strings"
"github.com/spf13/cobra"
+ "github.com/anyproto/anytype-cli/cmd/cmdutil"
"github.com/anyproto/anytype-cli/core"
+ "github.com/anyproto/anytype-cli/core/config"
+ "github.com/anyproto/anytype-cli/core/output"
)
func NewJoinCmd() *cobra.Command {
@@ -22,7 +23,7 @@ func NewJoinCmd() *cobra.Command {
Use: "join ",
Short: "Join a space",
Long: "Join a space using an invite link (https://invite.any.coop/...)",
- Args: cobra.ExactArgs(1),
+ Args: cmdutil.ExactArgs(1, "cannot join space: invite-link argument required"),
RunE: func(cmd *cobra.Command, args []string) error {
input := args[0]
var spaceId string
diff --git a/cmd/space/leave/leave.go b/cmd/space/leave/leave.go
index e710088..6412708 100644
--- a/cmd/space/leave/leave.go
+++ b/cmd/space/leave/leave.go
@@ -3,6 +3,7 @@ package leave
import (
"github.com/spf13/cobra"
+ "github.com/anyproto/anytype-cli/cmd/cmdutil"
"github.com/anyproto/anytype-cli/core"
"github.com/anyproto/anytype-cli/core/output"
)
@@ -12,7 +13,7 @@ func NewLeaveCmd() *cobra.Command {
Use: "leave ",
Short: "Leave a space",
Long: "Leave a space and stop sharing it",
- Args: cobra.ExactArgs(1),
+ Args: cmdutil.ExactArgs(1, "cannot leave space: space-id argument required"),
RunE: func(cmd *cobra.Command, args []string) error {
spaceId := args[0]
From 398d77bff6130226eeb960c8167b8ad9646ad567 Mon Sep 17 00:00:00 2001
From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com>
Date: Fri, 31 Oct 2025 00:07:40 +0100
Subject: [PATCH 05/11] Refactor authentication commands to use listen address
and default to localhost
---
cmd/auth/create/create.go | 8 ++++----
cmd/auth/create/create_test.go | 4 ++--
cmd/auth/login/login.go | 18 ++++++++----------
cmd/space/join/join.go | 6 +++---
core/auth.go | 2 --
core/config/constants.go | 5 ++---
6 files changed, 19 insertions(+), 24 deletions(-)
diff --git a/cmd/auth/create/create.go b/cmd/auth/create/create.go
index f135253..f10717e 100644
--- a/cmd/auth/create/create.go
+++ b/cmd/auth/create/create.go
@@ -16,7 +16,7 @@ import (
func NewCreateCmd() *cobra.Command {
var name string
var rootPath string
- var apiAddr string
+ var listenAddress string
cmd := &cobra.Command{
Use: "create",
@@ -34,7 +34,7 @@ func NewCreateCmd() *cobra.Command {
}
}
- accountKey, accountId, err := core.CreateBotWallet(name, rootPath, apiAddr)
+ accountKey, accountId, err := core.CreateBotWallet(name, rootPath, listenAddress)
if err != nil {
return output.Error("failed to create account: %w", err)
}
@@ -81,8 +81,8 @@ func NewCreateCmd() *cobra.Command {
}
cmd.Flags().StringVar(&name, "name", "", "Account name")
- cmd.Flags().StringVar(&rootPath, "root-path", "", "Custom root path for storing account data")
- cmd.Flags().StringVar(&apiAddr, "api-addr", "", fmt.Sprintf("Custom API address (default: %s)", config.DefaultAPIAddress))
+ cmd.Flags().StringVar(&rootPath, "root-path", "", "Root path for account data")
+ cmd.Flags().StringVar(&listenAddress, "listen-address", config.DefaultAPIAddress, "API listen address in `host:port` format")
return cmd
}
diff --git a/cmd/auth/create/create_test.go b/cmd/auth/create/create_test.go
index 1780954..bc53fae 100644
--- a/cmd/auth/create/create_test.go
+++ b/cmd/auth/create/create_test.go
@@ -18,8 +18,8 @@ func TestCreateCommand(t *testing.T) {
if cmd.Flag("root-path") == nil {
t.Error("root-path flag not found")
}
- if cmd.Flag("api-addr") == nil {
- t.Error("api-addr flag not found")
+ if cmd.Flag("listen-address") == nil {
+ t.Error("listen-address flag not found")
}
}
diff --git a/cmd/auth/login/login.go b/cmd/auth/login/login.go
index bc511a4..5901d65 100644
--- a/cmd/auth/login/login.go
+++ b/cmd/auth/login/login.go
@@ -1,8 +1,6 @@
package login
import (
- "fmt"
-
"github.com/spf13/cobra"
"github.com/anyproto/anytype-cli/core"
@@ -11,16 +9,16 @@ import (
)
func NewLoginCmd() *cobra.Command {
+ var accountKey string
+ var rootPath string
+ var listenAddress string
+
cmd := &cobra.Command{
Use: "login",
Short: "Log in to your bot account",
Long: "Authenticate using your bot account key to access your Anytype bot account and stored data.",
RunE: func(cmd *cobra.Command, args []string) error {
- accountKey, _ := cmd.Flags().GetString("account-key")
- rootPath, _ := cmd.Flags().GetString("path")
- apiAddr, _ := cmd.Flags().GetString("api-addr")
-
- if err := core.LoginBot(accountKey, rootPath, apiAddr); err != nil {
+ if err := core.LoginBot(accountKey, rootPath, listenAddress); err != nil {
return output.Error("failed to log in: %w", err)
}
output.Success("Successfully logged in")
@@ -29,9 +27,9 @@ func NewLoginCmd() *cobra.Command {
},
}
- cmd.Flags().String("account-key", "", "Provide bot account key for authentication")
- cmd.Flags().String("path", "", "Provide custom root path for wallet recovery")
- cmd.Flags().String("api-addr", "", fmt.Sprintf("API listen address (default: %s)", config.DefaultAPIAddress))
+ cmd.Flags().StringVar(&accountKey, "account-key", "", "Bot account key for authentication")
+ cmd.Flags().StringVar(&rootPath, "path", "", "Root path for account data")
+ cmd.Flags().StringVar(&listenAddress, "listen-address", config.DefaultAPIAddress, "API listen address in `host:port` format")
return cmd
}
diff --git a/cmd/space/join/join.go b/cmd/space/join/join.go
index fb6f846..e10f5ce 100644
--- a/cmd/space/join/join.go
+++ b/cmd/space/join/join.go
@@ -69,9 +69,9 @@ func NewJoinCmd() *cobra.Command {
},
}
- cmd.Flags().StringVar(&networkId, "network", "", "Network Id (optional, defaults to Anytype network address)")
- cmd.Flags().StringVar(&inviteCid, "invite-cid", "", "Invite Cid (optional, extracted from invite link if provided)")
- cmd.Flags().StringVar(&inviteFileKey, "invite-key", "", "Invite file key (optional, extracted from invite link if provided)")
+ cmd.Flags().StringVar(&networkId, "network", "", "Network `id` to join")
+ cmd.Flags().StringVar(&inviteCid, "invite-cid", "", "Invite `cid` (extracted from invite link if not provided)")
+ cmd.Flags().StringVar(&inviteFileKey, "invite-key", "", "Invite file `key` (extracted from invite link if not provided)")
return cmd
}
diff --git a/core/auth.go b/core/auth.go
index bf55b8d..f03a565 100644
--- a/core/auth.go
+++ b/core/auth.go
@@ -53,7 +53,6 @@ func LoginBotAccount(accountKey, rootPath, apiAddr string) error {
}
var sessionToken string
-
err := GRPCCallNoAuth(func(ctx context.Context, client service.ClientCommandsClient) error {
resp, err := client.InitialSetParameters(ctx, &pb.RpcInitialSetParametersRequest{
Platform: runtime.GOOS,
@@ -92,7 +91,6 @@ func LoginBotAccount(accountKey, rootPath, apiAddr string) error {
sessionToken = resp3.Token
return nil
})
-
if err != nil {
return err
}
diff --git a/core/config/constants.go b/core/config/constants.go
index 3220619..fa6b8d5 100644
--- a/core/config/constants.go
+++ b/core/config/constants.go
@@ -2,8 +2,7 @@ package config
const (
// Default addresses
- DefaultBindAddress = "0.0.0.0"
- LocalhostIP = "127.0.0.1"
+ LocalhostIP = "127.0.0.1"
// Port configuration
GRPCPort = "31007"
@@ -13,7 +12,7 @@ const (
// Full addresses
DefaultGRPCAddress = LocalhostIP + ":" + GRPCPort
DefaultGRPCWebAddress = LocalhostIP + ":" + GRPCWebPort
- DefaultAPIAddress = DefaultBindAddress + ":" + APIPort
+ DefaultAPIAddress = LocalhostIP + ":" + APIPort
// URLs
GRPCDNSAddress = "dns:///" + DefaultGRPCAddress
From 5c9be9e2ce4243d33fb1bc84f4ccc4a51b0e976c Mon Sep 17 00:00:00 2001
From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com>
Date: Fri, 31 Oct 2025 12:24:49 +0100
Subject: [PATCH 06/11] Add Heart version information to version output
---
cmd/auth/create/create.go | 4 ++--
core/version.go | 19 +++++++++++++++++--
2 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/cmd/auth/create/create.go b/cmd/auth/create/create.go
index f10717e..061693d 100644
--- a/cmd/auth/create/create.go
+++ b/cmd/auth/create/create.go
@@ -46,8 +46,8 @@ func NewCreateCmd() *cobra.Command {
output.Print("")
keyLen := len(accountKey)
- boxWidth := keyLen + 4 // 2 spaces padding on each side
- if boxWidth < 24 { // Minimum width for "BOT ACCOUNT KEY" title
+ boxWidth := keyLen + 4
+ if boxWidth < 24 {
boxWidth = 24
}
diff --git a/core/version.go b/core/version.go
index 8967d12..47dbe24 100644
--- a/core/version.go
+++ b/core/version.go
@@ -3,6 +3,7 @@ package core
import (
"fmt"
"runtime"
+ "runtime/debug"
"strings"
"github.com/anyproto/anytype-cli/core/config"
@@ -25,8 +26,8 @@ func GetVersionVerbose() string {
if buildTime == "" {
buildTime = "unknown"
}
- return fmt.Sprintf("anytype-cli %s\nCommit: %s\nBuilt: %s\nGo: %s\nOS/Arch: %s/%s\nURL: %s",
- GetVersion(), commit, buildTime, runtime.Version(), runtime.GOOS, runtime.GOARCH, GetReleaseURL())
+ return fmt.Sprintf("anytype-cli %s\nCommit: %s\nBuilt: %s\nGo: %s\nOS/Arch: %s/%s\nHeart: %s\nURL: %s",
+ GetVersion(), commit, buildTime, runtime.Version(), runtime.GOOS, runtime.GOARCH, GetHeartVersion(), GetReleaseURL())
}
func GetVersionBrief() string {
@@ -53,3 +54,17 @@ func GetReleaseURL() string {
}
return config.GitHubReleaseURL + Version
}
+
+func GetHeartVersion() string {
+ info, ok := debug.ReadBuildInfo()
+ if !ok {
+ return "unknown"
+ }
+
+ for _, dep := range info.Deps {
+ if dep.Path == "github.com/anyproto/anytype-heart" {
+ return dep.Version
+ }
+ }
+ return "unknown"
+}
From 9550a5ebd54d35ead200a98d1ecaebd12cbdcc88 Mon Sep 17 00:00:00 2001
From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com>
Date: Fri, 31 Oct 2025 12:43:13 +0100
Subject: [PATCH 07/11] Remove system-wide installation in favor of user
service
---
CLAUDE.md | 20 ++++++++++----------
Makefile | 24 ++++--------------------
README.md | 26 ++++++++++----------------
cmd/service/service.go | 8 ++++----
4 files changed, 28 insertions(+), 50 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index 01c0c4c..0c70b7e 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -12,11 +12,11 @@ This is the Anytype CLI, a Go-based command-line interface for interacting with
# Build the CLI (includes embedded server, downloads tantivy library automatically)
make build
-# Install system-wide
+# Install to ~/.local/bin (user installation)
make install
-# Install user-local (~/.local/bin)
-make install-local
+# Uninstall from ~/.local/bin
+make uninstall
# Clean tantivy libraries
make clean-tantivy
@@ -51,8 +51,8 @@ make build-windows-amd64
```bash
# Run server interactively (for development)
./dist/anytype serve
-
- # Or install as system service
+
+ # Or install as user service
./dist/anytype service install
./dist/anytype service start
```
@@ -86,7 +86,7 @@ make build-windows-amd64
## Architecture Overview
### Embedded Server Architecture
-The CLI embeds the anytype-heart gRPC server directly, creating a self-contained binary. This eliminates the need for separate server installation or management. The server runs either interactively (`anytype serve`) or as a system service.
+The CLI embeds the anytype-heart gRPC server directly, creating a self-contained binary. This eliminates the need for separate server installation or management. The server runs either interactively (`anytype serve`) or as a user service.
### Command Structure (`/cmd/`)
- Uses Cobra framework for CLI commands
@@ -119,13 +119,13 @@ The CLI embeds the anytype-heart gRPC server directly, creating a self-contained
- `google.golang.org/grpc v1.74.2`: gRPC client-server communication
- `github.com/zalando/go-keyring v0.2.6`: Secure credential storage in system keyring
- `github.com/cheggaaa/mb/v3 v3.0.2`: Message batching queue for event handling
-- `github.com/kardianos/service v1.2.4`: Cross-platform system service management
+- `github.com/kardianos/service v1.2.4`: Cross-platform user service management
- `github.com/anyproto/tantivy-go v1.0.4`: Full-text search capabilities (requires CGO)
## Important Notes
-1. **Service Architecture**: The CLI includes an embedded gRPC server that runs as a system service or interactively
-2. **Cross-Platform Service**: Works on Windows (Service), macOS (launchd), Linux (systemd/upstart/sysv)
+1. **Service Architecture**: The CLI includes an embedded gRPC server that runs as a user service or interactively
+2. **Cross-Platform Service**: Works on Windows (User Service), macOS (User Agent/launchd), Linux (systemd user service)
3. **Keyring Integration**: Authentication tokens are stored securely in the system keyring
4. **Port Configuration**:
- gRPC: localhost:31007
@@ -196,7 +196,7 @@ func NewConfigCmd() *cobra.Command {
### Working with the Service
- Service is managed via the `anytype service` command
- Service program implementation is in `core/serviceprogram/`
-- Supports both interactive mode (`anytype serve`) and system service installation
+- Supports both interactive mode (`anytype serve`) and user service installation
- Service logs are written to log files in the user's home directory (~/.anytype/logs/)
### Error Handling
diff --git a/Makefile b/Makefile
index 1fa7518..a6334fa 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: all build install install-local uninstall uninstall-local clean clean-tantivy download-tantivy lint lint-fix install-linter
+.PHONY: all build install uninstall clean clean-tantivy download-tantivy lint lint-fix install-linter
all: download-tantivy build
@@ -94,18 +94,8 @@ download-tantivy: ## Download tantivy library for current platform
##@ Installation
-install: build ## Install to /usr/local/bin (may require sudo)
+install: build ## Install to ~/.local/bin (user installation)
@echo "Installing anytype-cli..."
- @cp dist/anytype /usr/local/bin/anytype 2>/dev/null || sudo cp dist/anytype /usr/local/bin/anytype
- @ln -sf /usr/local/bin/anytype /usr/local/bin/any 2>/dev/null || sudo ln -sf /usr/local/bin/anytype /usr/local/bin/any
- @echo "Installed to /usr/local/bin/ (available as 'anytype' and 'any')"
- @echo ""
- @echo "Usage:"
- @echo " anytype serve # Run server in foreground"
- @echo " anytype service install # Install as system service"
-
-install-local: build ## Install to ~/.local/bin (user installation)
- @echo "Installing anytype-cli to local..."
@mkdir -p $$HOME/.local/bin
@cp dist/anytype $$HOME/.local/bin/anytype
@ln -sf $$HOME/.local/bin/anytype $$HOME/.local/bin/any
@@ -114,16 +104,10 @@ install-local: build ## Install to ~/.local/bin (user installation)
@echo ""
@echo "Usage:"
@echo " anytype serve # Run server in foreground"
- @echo " anytype service install # Install as system service"
+ @echo " anytype service install # Install as user service"
-uninstall: ## Uninstall from /usr/local/bin
+uninstall: ## Uninstall from ~/.local/bin
@echo "Uninstalling anytype-cli..."
- @rm -f /usr/local/bin/anytype 2>/dev/null || sudo rm -f /usr/local/bin/anytype
- @rm -f /usr/local/bin/any 2>/dev/null || sudo rm -f /usr/local/bin/any
- @echo "Uninstalled from /usr/local/bin/"
-
-uninstall-local: ## Uninstall from ~/.local/bin
- @echo "Uninstalling anytype-cli from local..."
@rm -f $$HOME/.local/bin/anytype
@rm -f $$HOME/.local/bin/any
@echo "Uninstalled from $$HOME/.local/bin/"
diff --git a/README.md b/README.md
index e42320d..90bddb1 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ Install the latest release with a single command:
# Run the Anytype server
anytype serve
-# Or install as a system service
+# Or install as a user service
anytype service install
anytype service start
@@ -35,7 +35,7 @@ anytype [flags]
Commands:
auth Manage authentication and accounts
serve Run anytype in foreground
- service Manage anytype as a system service
+ service Manage anytype as a user service
shell Start interactive shell mode
space Manage spaces
update Update to the latest version
@@ -43,7 +43,7 @@ Commands:
Examples:
anytype serve # Run in foreground
- anytype service install # Install as system service
+ anytype service install # Install as user service
anytype service start # Start the service
anytype auth login # Log in to your account
anytype auth create # Create a new account
@@ -62,9 +62,9 @@ anytype serve
```
This runs the server in the foreground with logs output to stdout, similar to `ollama serve`.
-#### 2. System Service (for production)
+#### 2. User Service (for production)
```bash
-# Install as system service
+# Install as user service
anytype service install
# Start the service
@@ -81,9 +81,9 @@ anytype service uninstall
```
The service management works across platforms:
-- **macOS**: Uses launchd
-- **Linux**: Uses systemd/upstart/sysv
-- **Windows**: Uses Windows Service
+- **macOS**: Uses User Agent (launchd)
+- **Linux**: Uses systemd user service
+- **Windows**: Uses Windows User Service
### Authentication
@@ -171,12 +171,9 @@ cd anytype-cli
# Build the CLI (automatically downloads tantivy library)
make build
-# Install system-wide (may require sudo)
+# Install to ~/.local/bin (user installation)
make install
-# Install to ~/.local/bin (no sudo required)
-make install-local
-
# Run tests
go test ./...
@@ -190,11 +187,8 @@ make cross-compile
#### Uninstall
```bash
-# Remove system-wide installation
+# Remove installation from ~/.local/bin
make uninstall
-
-# Remove user-local installation
-make uninstall-local
```
## Contribution
diff --git a/cmd/service/service.go b/cmd/service/service.go
index f8669b0..ed8258d 100644
--- a/cmd/service/service.go
+++ b/cmd/service/service.go
@@ -40,19 +40,19 @@ func getService() (service.Service, error) {
func NewServiceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "service",
- Short: "Manage anytype as a system service",
- Long: "Install, uninstall, start, stop, and check status of anytype running as a system service.",
+ Short: "Manage anytype as a user service",
+ Long: "Install, uninstall, start, stop, and check status of anytype running as a user service.",
}
cmd.AddCommand(
&cobra.Command{
Use: "install",
- Short: "Install as a system service",
+ Short: "Install as a user service",
RunE: installService,
},
&cobra.Command{
Use: "uninstall",
- Short: "Uninstall the system service",
+ Short: "Uninstall the user service",
RunE: uninstallService,
},
&cobra.Command{
From 799ef07df9cb7f72db1a4f31aad5e6c80bea5c7f Mon Sep 17 00:00:00 2001
From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com>
Date: Fri, 31 Oct 2025 15:40:43 +0100
Subject: [PATCH 08/11] Enhance account key validation to check for mnemonics
and base64 format
---
CLAUDE.md | 2 +-
core/auth.go | 20 +++++++++++++++++---
core/auth_test.go | 36 ++++++++++++++++++++++++------------
3 files changed, 42 insertions(+), 16 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index 0c70b7e..6e349ed 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -77,7 +77,7 @@ make build-windows-amd64
go test ./cmd/...
# Run specific test
- go test -run TestValidateMnemonic ./core
+ go test -run TestValidateAccountKey ./core
# Run tests with verbose output
go test -v ./...
diff --git a/core/auth.go b/core/auth.go
index f03a565..f9324f1 100644
--- a/core/auth.go
+++ b/core/auth.go
@@ -3,6 +3,7 @@ package core
import (
"bufio"
"context"
+ "encoding/base64"
"fmt"
"os"
"path/filepath"
@@ -161,9 +162,22 @@ func ValidateAccountKey(accountKey string) error {
if accountKey == "" {
return fmt.Errorf("bot account key cannot be empty")
}
- // Bot account keys are typically base64 encoded strings
- if len(accountKey) < 20 {
- return fmt.Errorf("invalid bot account key format")
+
+ // Check if this looks like a mnemonic (space-separated words) instead of an account key
+ words := strings.Fields(accountKey)
+ if len(words) >= 12 {
+ return fmt.Errorf("this appears to be a mnemonic phrase, not an account key - the CLI only supports bot accounts created via 'anytype auth create'")
+ }
+
+ // Validate base64 format by attempting to decode
+ decoded, err := base64.StdEncoding.DecodeString(accountKey)
+ if err != nil {
+ return fmt.Errorf("invalid bot account key format: must be valid base64")
+ }
+
+ // Basic sanity check: key should be at least 32 bytes
+ if len(decoded) < 32 {
+ return fmt.Errorf("invalid bot account key format: insufficient key material")
}
return nil
diff --git a/core/auth_test.go b/core/auth_test.go
index 3c0d5f6..f278d48 100644
--- a/core/auth_test.go
+++ b/core/auth_test.go
@@ -105,32 +105,44 @@ func TestValidateAccountKey(t *testing.T) {
errContains string
}{
{
- name: "valid bot account key",
- accountKey: "somevalidbase64encodedkeythatislongenough",
+ name: "valid 64-byte account key (real example)",
+ accountKey: "bNYSkBlOzNMKpDupAgL3g31Hnq7JpeX45O6MCpUqNdt16Avbgy5T5oQECKvAoy3+E4wHGPpCRCVWZQQCXRh7xw==",
+ wantErr: false,
+ },
+ {
+ name: "valid 32-byte account key (minimum)",
+ accountKey: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
wantErr: false,
},
{
name: "empty account key",
accountKey: "",
wantErr: true,
- errContains: "bot account key cannot be empty",
+ errContains: "cannot be empty",
},
{
- name: "too short account key",
- accountKey: "shortkey",
+ name: "mnemonic instead of account key",
+ accountKey: "word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12",
wantErr: true,
- errContains: "invalid bot account key format",
+ errContains: "appears to be a mnemonic phrase",
},
{
- name: "minimum valid length key",
- accountKey: "12345678901234567890", // exactly 20 chars
- wantErr: false,
+ name: "not valid base64",
+ accountKey: "this-is-not-valid-base64!!!",
+ wantErr: true,
+ errContains: "must be valid base64",
+ },
+ {
+ name: "base64 but insufficient key material",
+ accountKey: "QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ==", // 30 bytes decoded
+ wantErr: true,
+ errContains: "insufficient key material",
},
{
- name: "just under minimum length",
- accountKey: "1234567890123456789", // 19 chars
+ name: "very short base64",
+ accountKey: "YWJj", // "abc" decoded (3 bytes)
wantErr: true,
- errContains: "invalid bot account key format",
+ errContains: "insufficient key material",
},
}
From 6f21f81a4955914dbbfaf9145f987dec8ba4e43b Mon Sep 17 00:00:00 2001
From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com>
Date: Sun, 2 Nov 2025 12:58:02 +0100
Subject: [PATCH 09/11] Refactor terminology to replace "bot account key" with
"account key"
---
cmd/auth/create/create.go | 4 ++--
cmd/auth/login/login.go | 4 ++--
cmd/auth/logout/logout.go | 2 +-
core/auth.go | 20 ++++++++++----------
core/serviceprogram/serviceprogram.go | 10 +++++-----
5 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/cmd/auth/create/create.go b/cmd/auth/create/create.go
index 061693d..1d73959 100644
--- a/cmd/auth/create/create.go
+++ b/cmd/auth/create/create.go
@@ -41,7 +41,7 @@ func NewCreateCmd() *cobra.Command {
output.Success("Bot account created successfully!")
- output.Warning("IMPORTANT: Save your bot account key in a secure location.")
+ output.Warning("IMPORTANT: Save your account key in a secure location.")
output.Info(" This is the ONLY way to authenticate your bot account.")
output.Print("")
@@ -74,7 +74,7 @@ func NewCreateCmd() *cobra.Command {
output.Print("")
output.Success("You are now logged in to your new bot account.")
- output.Success("Bot account key saved to keychain.")
+ output.Success("Account key saved to keychain.")
return nil
},
diff --git a/cmd/auth/login/login.go b/cmd/auth/login/login.go
index 5901d65..861eec9 100644
--- a/cmd/auth/login/login.go
+++ b/cmd/auth/login/login.go
@@ -16,7 +16,7 @@ func NewLoginCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "login",
Short: "Log in to your bot account",
- Long: "Authenticate using your bot account key to access your Anytype bot account and stored data.",
+ Long: "Authenticate using your account key to access your Anytype bot account and stored data.",
RunE: func(cmd *cobra.Command, args []string) error {
if err := core.LoginBot(accountKey, rootPath, listenAddress); err != nil {
return output.Error("failed to log in: %w", err)
@@ -27,7 +27,7 @@ func NewLoginCmd() *cobra.Command {
},
}
- cmd.Flags().StringVar(&accountKey, "account-key", "", "Bot account key for authentication")
+ cmd.Flags().StringVar(&accountKey, "account-key", "", "Account key for authentication")
cmd.Flags().StringVar(&rootPath, "path", "", "Root path for account data")
cmd.Flags().StringVar(&listenAddress, "listen-address", config.DefaultAPIAddress, "API listen address in `host:port` format")
diff --git a/cmd/auth/logout/logout.go b/cmd/auth/logout/logout.go
index adac261..7589240 100644
--- a/cmd/auth/logout/logout.go
+++ b/cmd/auth/logout/logout.go
@@ -11,7 +11,7 @@ func NewLogoutCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "logout",
Short: "Log out and clear stored credentials",
- Long: "End your current session and remove stored authentication tokens and bot account key from the system keychain.",
+ Long: "End your current session and remove stored authentication tokens and account key from the system keychain.",
RunE: func(cmd *cobra.Command, args []string) error {
if err := core.Logout(); err != nil {
return output.Error("failed to log out: %w", err)
diff --git a/core/auth.go b/core/auth.go
index f9324f1..e1941c3 100644
--- a/core/auth.go
+++ b/core/auth.go
@@ -160,7 +160,7 @@ func LoginBotAccount(accountKey, rootPath, apiAddr string) error {
func ValidateAccountKey(accountKey string) error {
if accountKey == "" {
- return fmt.Errorf("bot account key cannot be empty")
+ return fmt.Errorf("account key cannot be empty")
}
// Check if this looks like a mnemonic (space-separated words) instead of an account key
@@ -172,12 +172,12 @@ func ValidateAccountKey(accountKey string) error {
// Validate base64 format by attempting to decode
decoded, err := base64.StdEncoding.DecodeString(accountKey)
if err != nil {
- return fmt.Errorf("invalid bot account key format: must be valid base64")
+ return fmt.Errorf("invalid account key format: must be valid base64")
}
// Basic sanity check: key should be at least 32 bytes
if len(decoded) < 32 {
- return fmt.Errorf("invalid bot account key format: insufficient key material")
+ return fmt.Errorf("invalid account key format: insufficient key material")
}
return nil
@@ -189,10 +189,10 @@ func LoginBot(accountKey, rootPath, apiAddr string) error {
storedKey, err := GetStoredAccountKey()
if err == nil && storedKey != "" {
accountKey = storedKey
- output.Info("Using stored bot account key from keychain.")
+ output.Info("Using stored account key from keychain.")
usedStoredKey = true
} else {
- output.Print("Enter bot account key: ")
+ output.Print("Enter account key: ")
reader := bufio.NewReader(os.Stdin)
accountKey, _ = reader.ReadString('\n')
accountKey = strings.TrimSpace(accountKey)
@@ -209,9 +209,9 @@ func LoginBot(accountKey, rootPath, apiAddr string) error {
if !usedStoredKey {
if err := SaveAccountKey(accountKey); err != nil {
- output.Warning("failed to save bot account key in keychain: %v", err)
+ output.Warning("failed to save account key in keychain: %v", err)
} else {
- output.Success("Bot account key saved to keychain.")
+ output.Success("Account key saved to keychain.")
}
}
@@ -251,7 +251,7 @@ func Logout() error {
}
if err := DeleteStoredAccountKey(); err != nil {
- return fmt.Errorf("failed to delete stored bot account key: %w", err)
+ return fmt.Errorf("failed to delete stored account key: %w", err)
}
if err := DeleteStoredToken(); err != nil {
@@ -268,7 +268,7 @@ func Logout() error {
return nil
}
-// CreateBotWallet creates a new bot wallet with the given root path and returns the bot account key and account Id
+// CreateBotWallet creates a new bot wallet with the given root path and returns the account key and account Id
// This creates a regular wallet but exports a bot-specific account key for authentication
func CreateBotWallet(name, rootPath, apiAddr string) (string, string, error) {
if rootPath == "" {
@@ -362,7 +362,7 @@ func CreateBotWallet(name, rootPath, apiAddr string) (string, string, error) {
}
if err := SaveAccountKey(accountKey); err != nil {
- output.Warning("failed to save bot account key: %v", err)
+ output.Warning("failed to save account key: %v", err)
}
configMgr := config.GetConfigManager()
diff --git a/core/serviceprogram/serviceprogram.go b/core/serviceprogram/serviceprogram.go
index 02d3431..1006f56 100644
--- a/core/serviceprogram/serviceprogram.go
+++ b/core/serviceprogram/serviceprogram.go
@@ -91,22 +91,22 @@ func (p *Program) run() {
func (p *Program) attemptAutoLogin() {
botAccountKey, err := core.GetStoredAccountKey()
if err != nil || botAccountKey == "" {
- output.Info("No stored bot account key found, skipping auto-login")
+ output.Info("No stored account key found, skipping auto-login")
return
}
- output.Info("Found stored bot account key, attempting auto-login...")
+ output.Info("Found stored account key, attempting auto-login...")
- maxRetries := 5
+ maxRetries := 3
for i := 0; i < maxRetries; i++ {
if err := core.LoginBotAccount(botAccountKey, "", ""); err != nil {
if i < maxRetries-1 {
time.Sleep(2 * time.Second)
continue
}
- output.Info("Failed to auto-login with bot key after %d attempts: %v", maxRetries, err)
+ output.Info("Failed to auto-login with account key after %d attempts: %v", maxRetries, err)
} else {
- output.Success("Successfully logged in using stored bot account key")
+ output.Success("Successfully logged in using stored account key")
return
}
}
From 56a41c7dd8ef97e99d8b52c50e28f47cd249b965 Mon Sep 17 00:00:00 2001
From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com>
Date: Sun, 2 Nov 2025 13:41:26 +0100
Subject: [PATCH 10/11] Improve auth status output
---
cmd/auth/status/status.go | 36 +++++++++++++++++++++---------------
1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/cmd/auth/status/status.go b/cmd/auth/status/status.go
index 1f772dd..db57e46 100644
--- a/cmd/auth/status/status.go
+++ b/cmd/auth/status/status.go
@@ -18,9 +18,11 @@ func NewStatusCmd() *cobra.Command {
Short: "Show authentication status",
Long: "Display current authentication status, including account information, server status, and stored credentials.",
RunE: func(cmd *cobra.Command, args []string) error {
- hasBotKey := false
- if _, err := core.GetStoredAccountKey(); err == nil {
- hasBotKey = true
+ hasAccountKey := false
+ accountKey := ""
+ if ak, err := core.GetStoredAccountKey(); err == nil && ak != "" {
+ hasAccountKey = true
+ accountKey = ak
}
hasToken := false
@@ -35,27 +37,27 @@ func NewStatusCmd() *cobra.Command {
cfg := configMgr.Get()
accountId := cfg.AccountId
- serverRunning := false
+ isServerRunning := false
err := core.GRPCCallNoAuth(func(ctx context.Context, client service.ClientCommandsClient) error {
_, err := client.AppGetVersion(ctx, &pb.RpcAppGetVersionRequest{})
return err
})
- serverRunning = err == nil
+ isServerRunning = err == nil
// If server is running and we have a token, we're logged in
- // (server auto-logs in on restart using stored bot account key)
- isLoggedIn := serverRunning && hasToken
+ // (server auto-logs in on restart using stored account key)
+ isLoggedIn := isServerRunning && hasToken
// Display status based on priority: server -> credentials -> login
- if !serverRunning {
- output.Print("Server is not running. Run 'anytype serve' to start the server.")
- if hasBotKey || hasToken || accountId != "" {
+ if !isServerRunning {
+ output.Print("Server is not running. Start it with 'anytype service start' or 'anytype serve' (foreground mode).")
+ if hasAccountKey || hasToken || accountId != "" {
output.Print("Credentials are stored in keychain.")
}
return nil
}
- if !hasBotKey && !hasToken && accountId == "" {
+ if !hasAccountKey && !hasToken && accountId == "" {
output.Print("Not authenticated. Run 'anytype auth login' to authenticate or 'anytype auth create' to create a new account.")
return nil
}
@@ -64,10 +66,10 @@ func NewStatusCmd() *cobra.Command {
if isLoggedIn && accountId != "" {
output.Print(" ✓ Logged in to account \033[1m%s\033[0m (keychain)", accountId)
- } else if hasToken || hasBotKey {
+ } else if hasToken || hasAccountKey {
output.Print(" ✗ Not logged in (credentials stored in keychain)")
if !isLoggedIn && hasToken {
- output.Print(" Note: Server is not running or session expired. Run 'anytype serve' to start server.")
+ output.Print(" Note: Server is not running or session expired. Start it with 'anytype service start' or 'anytype serve' (foreground mode).")
}
} else {
output.Print(" ✗ Not logged in")
@@ -75,8 +77,12 @@ func NewStatusCmd() *cobra.Command {
output.Print(" - Active session: \033[1m%v\033[0m", isLoggedIn)
- if hasBotKey {
- output.Print(" - Bot Account Key: \033[1mstored\033[0m")
+ if hasAccountKey {
+ if len(accountKey) > 8 {
+ output.Print(" - Account Key: \033[1m%s****\033[0m", accountKey[:8])
+ } else {
+ output.Print(" - Account Key: \033[1mstored\033[0m")
+ }
}
if hasToken {
From 4c5dfe2547731a57f5d3684fe8862fb8ac38339c Mon Sep 17 00:00:00 2001
From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com>
Date: Sun, 2 Nov 2025 13:41:49 +0100
Subject: [PATCH 11/11] Enhance service installation checks
---
cmd/service/service.go | 27 ++++++++++++++++++++++++++-
core/auth.go | 1 -
core/serviceprogram/serviceprogram.go | 6 +++---
3 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/cmd/service/service.go b/cmd/service/service.go
index ed8258d..825e4df 100644
--- a/cmd/service/service.go
+++ b/cmd/service/service.go
@@ -1,6 +1,7 @@
package service
import (
+ "errors"
"os"
"path/filepath"
@@ -122,6 +123,14 @@ func startService(cmd *cobra.Command, args []string) error {
return output.Error("failed to create service: %w", err)
}
+ // Check if service is installed first
+ _, err = s.Status()
+ if err != nil && errors.Is(err, service.ErrNotInstalled) {
+ output.Warning("anytype service is not installed")
+ output.Info("Run 'anytype service install' to install it first")
+ return nil
+ }
+
err = s.Start()
if err != nil {
return output.Error("failed to start service: %w", err)
@@ -137,6 +146,14 @@ func stopService(cmd *cobra.Command, args []string) error {
return output.Error("failed to create service: %w", err)
}
+ // Check if service is installed first
+ _, err = s.Status()
+ if err != nil && errors.Is(err, service.ErrNotInstalled) {
+ output.Warning("anytype service is not installed")
+ output.Info("Run 'anytype service install' to install it first")
+ return nil
+ }
+
err = s.Stop()
if err != nil {
return output.Error("failed to stop service: %w", err)
@@ -152,6 +169,14 @@ func restartService(cmd *cobra.Command, args []string) error {
return output.Error("failed to create service: %w", err)
}
+ // Check if service is installed first
+ _, err = s.Status()
+ if err != nil && errors.Is(err, service.ErrNotInstalled) {
+ output.Warning("anytype service is not installed")
+ output.Info("Run 'anytype service install' to install it first")
+ return nil
+ }
+
err = s.Restart()
if err != nil {
return output.Error("failed to restart service: %w", err)
@@ -169,7 +194,7 @@ func statusService(cmd *cobra.Command, args []string) error {
status, err := s.Status()
if err != nil {
- if err == service.ErrNotInstalled {
+ if errors.Is(err, service.ErrNotInstalled) {
output.Info("anytype service is not installed")
output.Info("Run 'anytype service install' to install it")
return nil
diff --git a/core/auth.go b/core/auth.go
index e1941c3..5fc0887 100644
--- a/core/auth.go
+++ b/core/auth.go
@@ -269,7 +269,6 @@ func Logout() error {
}
// CreateBotWallet creates a new bot wallet with the given root path and returns the account key and account Id
-// This creates a regular wallet but exports a bot-specific account key for authentication
func CreateBotWallet(name, rootPath, apiAddr string) (string, string, error) {
if rootPath == "" {
rootPath = getDefaultDataPath()
diff --git a/core/serviceprogram/serviceprogram.go b/core/serviceprogram/serviceprogram.go
index 1006f56..e2cf270 100644
--- a/core/serviceprogram/serviceprogram.go
+++ b/core/serviceprogram/serviceprogram.go
@@ -89,8 +89,8 @@ func (p *Program) run() {
}
func (p *Program) attemptAutoLogin() {
- botAccountKey, err := core.GetStoredAccountKey()
- if err != nil || botAccountKey == "" {
+ accountKey, err := core.GetStoredAccountKey()
+ if err != nil || accountKey == "" {
output.Info("No stored account key found, skipping auto-login")
return
}
@@ -99,7 +99,7 @@ func (p *Program) attemptAutoLogin() {
maxRetries := 3
for i := 0; i < maxRetries; i++ {
- if err := core.LoginBotAccount(botAccountKey, "", ""); err != nil {
+ if err := core.LoginBotAccount(accountKey, "", ""); err != nil {
if i < maxRetries-1 {
time.Sleep(2 * time.Second)
continue