Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .run/anytype serve.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="anytype serve" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="anytype-cli" />
<working_directory value="$PROJECT_DIR$" />
<go_parameters value="-tags &quot;appdebug&quot;" />
<envs>
<env name="CGO_ENABLED" value="1" />
<env name="CGO_LDFLAGS" value="-L$PROJECT_DIR$/dist/tantivy" />
<env name="CC" value="/usr/bin/cc" />
<env name="CXX" value="/usr/bin/c++" />
</envs>
<kind value="PACKAGE" />
<package value="github.com/anyproto/anytype-cli" />
<directory value="$PROJECT_DIR$" />
<filePath value="$PROJECT_DIR$" />
<parameters value="serve" />
<method v="2" />
</configuration>
</component>
21 changes: 21 additions & 0 deletions .run/anytype.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="anytype" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="anytype-cli" />
<working_directory value="$PROJECT_DIR$" />
<go_parameters value="-tags &quot;appdebug&quot; -ldflags &quot;-X github.com/anyproto/anytype-cli/core.Version=1.0.0-dev -X github.com/anyproto/anytype-cli/core.Commit=dev -X github.com/anyproto/anytype-cli/core.BuildTime=dev -X github.com/anyproto/anytype-cli/core.GitState=clean&quot;" />
<envs>
<env name="CGO_ENABLED" value="1" />
<env name="CGO_LDFLAGS" value="-L$PROJECT_DIR$/dist/tantivy" />
<env name="CC" value="/usr/bin/cc" />
<env name="CXX" value="/usr/bin/c++" />
</envs>
<kind value="PACKAGE" />
<package value="github.com/anyproto/anytype-cli" />
<directory value="$PROJECT_DIR$" />
<filePath value="$PROJECT_DIR$" />
<parameters value="auth status" />
<output_directory value="$PROJECT_DIR$" />
<method v="2">
</method>
</configuration>
</component>
22 changes: 11 additions & 11 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
```
Expand All @@ -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 ./...
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
24 changes: 4 additions & 20 deletions Makefile
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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/"
Expand Down
26 changes: 10 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -35,15 +35,15 @@ anytype <command> <subcommand> [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
version Show version information

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
Expand All @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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 ./...

Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion cmd/auth/apikey/create/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -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]

Expand Down
3 changes: 2 additions & 1 deletion cmd/auth/apikey/revoke/revoke.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -12,7 +13,7 @@ func NewRevokeCmd() *cobra.Command {
Use: "revoke <id>",
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]

Expand Down
54 changes: 34 additions & 20 deletions cmd/auth/create/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import (
func NewCreateCmd() *cobra.Command {
var name string
var rootPath string
var apiAddr string
var listenAddress string

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: ")
Expand All @@ -34,41 +34,55 @@ func NewCreateCmd() *cobra.Command {
}
}

mnemonic, accountId, err := core.CreateWallet(name, rootPath, apiAddr)
accountKey, accountId, err := core.CreateBotWallet(name, rootPath, listenAddress)
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 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(accountKey)
boxWidth := keyLen + 4
if boxWidth < 24 {
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 ║", accountKey)

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("Account key saved to keychain.")

return nil
},
}

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
}
4 changes: 2 additions & 2 deletions cmd/auth/create/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}

Expand Down
Loading
Loading