fere-cli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ *.log
2
+ *.pyc
3
+ __pycache__
4
+
5
+ # Devcontainer local env (contains secrets)
6
+ .devcontainer/.env.local
7
+ .devcontainer/.env.gitpod
8
+
9
+ # Git worktrees
10
+ .worktrees/
11
+
12
+ # tmp/ — keep .gitkeep, ignore all else
13
+ tmp/*
14
+ !tmp/.gitkeep
15
+ coverage.xml
16
+
17
+ # Eval output
18
+ compare_results.json
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.4
2
+ Name: fere-cli
3
+ Version: 0.1.0
4
+ Summary: Terminal CLI for FereAI crypto trading and research
5
+ Author-email: Fere AI <info@fere.ai>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: click>=8.1
9
+ Requires-Dist: fere-sdk>=0.1.0
10
+ Requires-Dist: rich>=13.0
11
+ Provides-Extra: dev
12
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
13
+ Requires-Dist: pytest>=8.0; extra == 'dev'
14
+ Description-Content-Type: text/markdown
15
+
16
+ # FereAI CLI
17
+
18
+ Terminal-first interface for FereAI crypto trading and research. Wraps the [FereAI Gateway API](https://api.fereai.xyz) — same capabilities as the Python and TypeScript SDKs.
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ curl -fsSL https://api.fereai.xyz/install.sh | sh
24
+ ```
25
+
26
+ Or with pip:
27
+
28
+ ```bash
29
+ pip install fere-cli
30
+ ```
31
+
32
+ ## Quick Start
33
+
34
+ ```bash
35
+ # Authenticate (first-run — creates agent, generates keys)
36
+ fere auth
37
+
38
+ # Chat with the AI agent
39
+ fere chat "what is the price of ETH?"
40
+
41
+ # Interactive chat REPL
42
+ fere chat
43
+
44
+ # Stream responses in real-time
45
+ fere chat --stream "top 5 memecoins on Base"
46
+
47
+ # Check your wallets and holdings
48
+ fere wallets
49
+ fere holdings
50
+
51
+ # Execute a swap
52
+ fere swap \
53
+ --chain-in 8453 --chain-out 8453 \
54
+ --token-in 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE \
55
+ --token-out 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
56
+ --amount 1000000000000000000
57
+
58
+ # Check credits
59
+ fere credits
60
+
61
+ # View supported chains
62
+ fere chains
63
+ ```
64
+
65
+ ## JSON Output (for scripts & AI agents)
66
+
67
+ Every command supports `--json` for machine-readable output:
68
+
69
+ ```bash
70
+ fere --json credits
71
+ # {"ok": true, "data": {"credits_available": 150.0}}
72
+
73
+ fere --json holdings
74
+ # {"ok": true, "data": {...}}
75
+ ```
76
+
77
+ Streaming chat in JSON mode outputs NDJSON (one event per line):
78
+
79
+ ```bash
80
+ fere --json chat --stream "price of SOL"
81
+ ```
82
+
83
+ ## Commands
84
+
85
+ | Command | Description |
86
+ |---------|-------------|
87
+ | `fere auth` | Authenticate and register agent |
88
+ | `fere whoami` | Show agent identity and wallets |
89
+ | `fere credits` | Check credit balance |
90
+ | `fere chat [QUERY]` | Chat with AI (one-shot or REPL) |
91
+ | `fere threads` | List chat threads |
92
+ | `fere swap` | Execute token swap |
93
+ | `fere limit-order create` | Create limit order |
94
+ | `fere limit-order list` | List limit orders |
95
+ | `fere limit-order cancel ID` | Cancel limit order |
96
+ | `fere hooks set` | Set stop-loss / take-profit |
97
+ | `fere wallets` | Show wallet addresses |
98
+ | `fere holdings` | Show token holdings |
99
+ | `fere notifications` | Show notifications |
100
+ | `fere earn info` | Show APY and vault info |
101
+ | `fere earn deposit` | Deposit USDC |
102
+ | `fere earn withdraw` | Withdraw USDC |
103
+ | `fere earn positions` | Show yield positions |
104
+ | `fere chains` | List supported chains |
105
+ | `fere status` | Check API connectivity |
106
+ | `fere config` | Show/edit CLI config |
107
+
108
+ ## Global Flags
109
+
110
+ | Flag | Env Var | Description |
111
+ |------|---------|-------------|
112
+ | `--json` | — | Machine-readable JSON output |
113
+ | `--quiet` | — | Minimal output |
114
+ | `--agent NAME` | `FERE_AGENT_NAME` | Agent name override |
115
+ | `--base-url URL` | `FERE_BASE_URL` | API URL override |
116
+
117
+ ## Configuration
118
+
119
+ Config is stored at `~/.fere/config.json`. Keys are stored at `~/.fere/keys.json` (managed by the SDK).
120
+
121
+ ```bash
122
+ fere config # Show current config
123
+ fere config set agent_name my-bot # Change agent name
124
+ fere config set base_url http://localhost:8003 # Point to local gateway
125
+ ```
126
+
127
+ ## Agent-Friendly
128
+
129
+ - Exit codes: 0 success, 1 error
130
+ - Non-interactive when stdin is not a TTY (all prompts skipped)
131
+ - `--json` output: `{"ok": true, "data": {...}}` or `{"ok": false, "error": "..."}`
132
+ - Streaming JSON: NDJSON format
133
+ - No ANSI colors when piped
@@ -0,0 +1,118 @@
1
+ # FereAI CLI
2
+
3
+ Terminal-first interface for FereAI crypto trading and research. Wraps the [FereAI Gateway API](https://api.fereai.xyz) — same capabilities as the Python and TypeScript SDKs.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ curl -fsSL https://api.fereai.xyz/install.sh | sh
9
+ ```
10
+
11
+ Or with pip:
12
+
13
+ ```bash
14
+ pip install fere-cli
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```bash
20
+ # Authenticate (first-run — creates agent, generates keys)
21
+ fere auth
22
+
23
+ # Chat with the AI agent
24
+ fere chat "what is the price of ETH?"
25
+
26
+ # Interactive chat REPL
27
+ fere chat
28
+
29
+ # Stream responses in real-time
30
+ fere chat --stream "top 5 memecoins on Base"
31
+
32
+ # Check your wallets and holdings
33
+ fere wallets
34
+ fere holdings
35
+
36
+ # Execute a swap
37
+ fere swap \
38
+ --chain-in 8453 --chain-out 8453 \
39
+ --token-in 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE \
40
+ --token-out 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
41
+ --amount 1000000000000000000
42
+
43
+ # Check credits
44
+ fere credits
45
+
46
+ # View supported chains
47
+ fere chains
48
+ ```
49
+
50
+ ## JSON Output (for scripts & AI agents)
51
+
52
+ Every command supports `--json` for machine-readable output:
53
+
54
+ ```bash
55
+ fere --json credits
56
+ # {"ok": true, "data": {"credits_available": 150.0}}
57
+
58
+ fere --json holdings
59
+ # {"ok": true, "data": {...}}
60
+ ```
61
+
62
+ Streaming chat in JSON mode outputs NDJSON (one event per line):
63
+
64
+ ```bash
65
+ fere --json chat --stream "price of SOL"
66
+ ```
67
+
68
+ ## Commands
69
+
70
+ | Command | Description |
71
+ |---------|-------------|
72
+ | `fere auth` | Authenticate and register agent |
73
+ | `fere whoami` | Show agent identity and wallets |
74
+ | `fere credits` | Check credit balance |
75
+ | `fere chat [QUERY]` | Chat with AI (one-shot or REPL) |
76
+ | `fere threads` | List chat threads |
77
+ | `fere swap` | Execute token swap |
78
+ | `fere limit-order create` | Create limit order |
79
+ | `fere limit-order list` | List limit orders |
80
+ | `fere limit-order cancel ID` | Cancel limit order |
81
+ | `fere hooks set` | Set stop-loss / take-profit |
82
+ | `fere wallets` | Show wallet addresses |
83
+ | `fere holdings` | Show token holdings |
84
+ | `fere notifications` | Show notifications |
85
+ | `fere earn info` | Show APY and vault info |
86
+ | `fere earn deposit` | Deposit USDC |
87
+ | `fere earn withdraw` | Withdraw USDC |
88
+ | `fere earn positions` | Show yield positions |
89
+ | `fere chains` | List supported chains |
90
+ | `fere status` | Check API connectivity |
91
+ | `fere config` | Show/edit CLI config |
92
+
93
+ ## Global Flags
94
+
95
+ | Flag | Env Var | Description |
96
+ |------|---------|-------------|
97
+ | `--json` | — | Machine-readable JSON output |
98
+ | `--quiet` | — | Minimal output |
99
+ | `--agent NAME` | `FERE_AGENT_NAME` | Agent name override |
100
+ | `--base-url URL` | `FERE_BASE_URL` | API URL override |
101
+
102
+ ## Configuration
103
+
104
+ Config is stored at `~/.fere/config.json`. Keys are stored at `~/.fere/keys.json` (managed by the SDK).
105
+
106
+ ```bash
107
+ fere config # Show current config
108
+ fere config set agent_name my-bot # Change agent name
109
+ fere config set base_url http://localhost:8003 # Point to local gateway
110
+ ```
111
+
112
+ ## Agent-Friendly
113
+
114
+ - Exit codes: 0 success, 1 error
115
+ - Non-interactive when stdin is not a TTY (all prompts skipped)
116
+ - `--json` output: `{"ok": true, "data": {...}}` or `{"ok": false, "error": "..."}`
117
+ - Streaming JSON: NDJSON format
118
+ - No ANSI colors when piped
@@ -0,0 +1,114 @@
1
+ #!/bin/sh
2
+ # FereAI CLI Installer
3
+ # Usage: curl -fsSL https://api.fereai.xyz/install.sh | sh
4
+ #
5
+ # Installs the `fere` CLI tool via pipx (recommended) or pip.
6
+ # Supports macOS and Linux.
7
+
8
+ set -e
9
+
10
+ VERSION="0.1.0"
11
+ PACKAGE="fere-cli"
12
+
13
+ # Colors (disabled if not a TTY)
14
+ if [ -t 1 ]; then
15
+ RED='\033[0;31m'
16
+ GREEN='\033[0;32m'
17
+ YELLOW='\033[0;33m'
18
+ DIM='\033[2m'
19
+ RESET='\033[0m'
20
+ else
21
+ RED=''
22
+ GREEN=''
23
+ YELLOW=''
24
+ DIM=''
25
+ RESET=''
26
+ fi
27
+
28
+ info() { printf "${DIM}%s${RESET}\n" "$1"; }
29
+ success() { printf "${GREEN}%s${RESET}\n" "$1"; }
30
+ warn() { printf "${YELLOW}%s${RESET}\n" "$1"; }
31
+ error() { printf "${RED}Error: %s${RESET}\n" "$1" >&2; exit 1; }
32
+
33
+ # Detect OS
34
+ OS="$(uname -s)"
35
+ case "$OS" in
36
+ Darwin) OS_NAME="macOS" ;;
37
+ Linux) OS_NAME="Linux" ;;
38
+ *) error "Unsupported OS: $OS. Use pip install $PACKAGE instead." ;;
39
+ esac
40
+
41
+ info "Installing FereAI CLI v${VERSION} on ${OS_NAME}..."
42
+
43
+ # Check Python 3.10+
44
+ check_python() {
45
+ for cmd in python3 python; do
46
+ if command -v "$cmd" >/dev/null 2>&1; then
47
+ ver=$("$cmd" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null)
48
+ major=$(echo "$ver" | cut -d. -f1)
49
+ minor=$(echo "$ver" | cut -d. -f2)
50
+ if [ "$major" -ge 3 ] && [ "$minor" -ge 10 ]; then
51
+ echo "$cmd"
52
+ return 0
53
+ fi
54
+ fi
55
+ done
56
+ return 1
57
+ }
58
+
59
+ PYTHON=$(check_python) || error "Python 3.10+ is required. Install it from https://python.org"
60
+ info "Found Python: $($PYTHON --version)"
61
+
62
+ # Prefer pipx for isolated installs
63
+ install_with_pipx() {
64
+ if command -v pipx >/dev/null 2>&1; then
65
+ info "Installing with pipx..."
66
+ pipx install "$PACKAGE" || pipx upgrade "$PACKAGE"
67
+ return 0
68
+ fi
69
+ return 1
70
+ }
71
+
72
+ install_pipx() {
73
+ info "Installing pipx..."
74
+ if command -v brew >/dev/null 2>&1; then
75
+ brew install pipx
76
+ elif [ "$OS" = "Linux" ]; then
77
+ $PYTHON -m pip install --user pipx 2>/dev/null || \
78
+ $PYTHON -m ensurepip --default-pip 2>/dev/null && \
79
+ $PYTHON -m pip install --user pipx
80
+ else
81
+ $PYTHON -m pip install --user pipx
82
+ fi
83
+ pipx ensurepath 2>/dev/null || true
84
+ }
85
+
86
+ install_with_pip() {
87
+ info "Installing with pip..."
88
+ $PYTHON -m pip install --user "$PACKAGE"
89
+ }
90
+
91
+ # Try pipx first, then install pipx, then fall back to pip
92
+ if install_with_pipx; then
93
+ : # success
94
+ elif install_pipx && install_with_pipx; then
95
+ : # success
96
+ else
97
+ warn "pipx not available, falling back to pip..."
98
+ install_with_pip
99
+ fi
100
+
101
+ # Verify installation
102
+ if command -v fere >/dev/null 2>&1; then
103
+ success "FereAI CLI installed successfully!"
104
+ echo ""
105
+ info "Get started:"
106
+ echo " fere auth # Set up your agent"
107
+ echo " fere chat \"hello\" # Chat with the AI"
108
+ echo " fere --help # See all commands"
109
+ else
110
+ warn "Installation complete, but 'fere' is not in PATH."
111
+ warn "You may need to restart your shell or add ~/.local/bin to PATH:"
112
+ echo ""
113
+ echo " export PATH=\"\$HOME/.local/bin:\$PATH\""
114
+ fi
@@ -0,0 +1,26 @@
1
+ [project]
2
+ name = "fere-cli"
3
+ version = "0.1.0"
4
+ description = "Terminal CLI for FereAI crypto trading and research"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = "MIT"
8
+ authors = [{ name = "Fere AI", email = "info@fere.ai" }]
9
+ dependencies = [
10
+ "fere-sdk>=0.1.0",
11
+ "click>=8.1",
12
+ "rich>=13.0",
13
+ ]
14
+
15
+ [project.scripts]
16
+ fere = "fere_cli.main:cli"
17
+
18
+ [project.optional-dependencies]
19
+ dev = ["pytest>=8.0", "pytest-asyncio>=0.24"]
20
+
21
+ [build-system]
22
+ requires = ["hatchling"]
23
+ build-backend = "hatchling.build"
24
+
25
+ [tool.hatch.build.targets.wheel]
26
+ packages = ["src/fere_cli"]
@@ -0,0 +1,3 @@
1
+ """FereAI CLI — terminal interface for crypto trading and research."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,63 @@
1
+ """Async bridge utilities for the CLI.
2
+
3
+ Click commands are synchronous; the SDK is async. This module
4
+ bridges the two with a thin ``run_async`` wrapper and a
5
+ ``get_client`` factory.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import asyncio
11
+ import sys
12
+ from functools import wraps
13
+ from typing import Any, Callable
14
+
15
+ import click
16
+ from fere_sdk import FereClient
17
+
18
+ from .config import load_config
19
+
20
+
21
+ def run_async(coro):
22
+ """Run an async coroutine from synchronous context."""
23
+ return asyncio.run(coro)
24
+
25
+
26
+ def async_command(f: Callable) -> Callable:
27
+ """Decorator: wraps an async function for use as a Click command."""
28
+
29
+ @wraps(f)
30
+ def wrapper(*args, **kwargs):
31
+ return run_async(f(*args, **kwargs))
32
+
33
+ return wrapper
34
+
35
+
36
+ async def get_client(ctx: click.Context) -> FereClient:
37
+ """Create an authenticated FereClient from config + CLI overrides.
38
+
39
+ Raises click.ClickException if no agent name is configured.
40
+ """
41
+ cfg = load_config()
42
+
43
+ # CLI flag overrides
44
+ agent_name = ctx.obj.get("agent_override") or cfg.get("agent_name")
45
+ base_url = ctx.obj.get("base_url_override") or cfg.get("base_url")
46
+ key_path = cfg.get("key_path")
47
+
48
+ if not agent_name:
49
+ raise click.ClickException(
50
+ "No agent configured. Run 'fere auth' first "
51
+ "or pass --agent NAME."
52
+ )
53
+
54
+ return await FereClient.create(
55
+ agent_name=agent_name,
56
+ base_url=base_url,
57
+ key_path=key_path,
58
+ )
59
+
60
+
61
+ def is_tty() -> bool:
62
+ """Check if stdin is a TTY (interactive terminal)."""
63
+ return sys.stdin.isatty()
@@ -0,0 +1,23 @@
1
+ """ASCII art banner for the Fere CLI."""
2
+
3
+ from . import __version__
4
+
5
+ # Simplified spiral motif + stylized "FERE AI" text
6
+ # The spiral evokes the Fere AI logo's concentric swirl pattern
7
+ # Kept under 70 chars wide for comfortable 80-col terminal display
8
+ LOGO = r"""
9
+ . · .
10
+ · · _____ _____ ____ _____ _ ___
11
+ · . · . · | ___| ___| _ \| ____| / \ |_ _|
12
+ · · · · | |_ | |_ | |_) | _| / _ \ | |
13
+ · · . · · | _| | _| | _ <| |___ / ___ \ | |
14
+ · · · · |_| |___|_|_| \_\_____| /_/ \_\___|
15
+ · · . · ·
16
+ · ·
17
+ · . ·
18
+ """
19
+
20
+
21
+ def get_banner() -> str:
22
+ """Return the full banner string with version."""
23
+ return f"{LOGO}\n v{__version__} — crypto trading & research from your terminal\n"
File without changes
@@ -0,0 +1,108 @@
1
+ """Auth commands: fere auth, fere whoami, fere credits."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import click
6
+ from fere_sdk import FereClient
7
+ from rich.console import Console
8
+
9
+ from ..async_util import async_command, get_client, is_tty, run_async
10
+ from ..config import load_config, save_config
11
+ from ..output import print_error, print_success
12
+
13
+ console = Console()
14
+
15
+
16
+ @click.command()
17
+ @click.option("--name", prompt=False, default=None, help="Agent name.")
18
+ @click.pass_context
19
+ @async_command
20
+ async def auth(ctx, name: str | None):
21
+ """Authenticate and register a new agent (first-run setup)."""
22
+ cfg = load_config()
23
+
24
+ agent_name = (
25
+ ctx.obj.get("agent_override")
26
+ or name
27
+ or cfg.get("agent_name")
28
+ )
29
+ if not agent_name:
30
+ if is_tty():
31
+ agent_name = click.prompt("Agent name")
32
+ else:
33
+ raise click.ClickException(
34
+ "Agent name required. Pass --name or --agent."
35
+ )
36
+
37
+ base_url = ctx.obj.get("base_url_override") or cfg.get("base_url")
38
+ key_path = cfg.get("key_path")
39
+
40
+ try:
41
+ client = await FereClient.create(
42
+ agent_name=agent_name,
43
+ base_url=base_url,
44
+ key_path=key_path,
45
+ )
46
+
47
+ # Persist agent name to config
48
+ cfg["agent_name"] = agent_name
49
+ save_config(cfg)
50
+
51
+ user = await client.get_user()
52
+ await client.close()
53
+
54
+ print_success(
55
+ {
56
+ "status": "authenticated",
57
+ "agent_name": agent_name,
58
+ "user": user,
59
+ },
60
+ quiet_value=agent_name,
61
+ )
62
+ except Exception as e:
63
+ print_error(f"Authentication failed: {e}")
64
+ raise SystemExit(1)
65
+
66
+
67
+ @click.command()
68
+ @click.pass_context
69
+ @async_command
70
+ async def whoami(ctx):
71
+ """Show current agent identity and wallet addresses."""
72
+ try:
73
+ client = await get_client(ctx)
74
+ user = await client.get_user()
75
+ wallets_data = await client.get_wallets()
76
+ await client.close()
77
+
78
+ result = {**user}
79
+ if wallets_data:
80
+ result["wallets"] = wallets_data
81
+
82
+ print_success(result)
83
+ except click.ClickException:
84
+ raise
85
+ except Exception as e:
86
+ print_error(str(e))
87
+ raise SystemExit(1)
88
+
89
+
90
+ @click.command()
91
+ @click.pass_context
92
+ @async_command
93
+ async def credits(ctx):
94
+ """Show available credit balance."""
95
+ try:
96
+ client = await get_client(ctx)
97
+ balance = await client.get_credits()
98
+ await client.close()
99
+
100
+ print_success(
101
+ {"credits_available": balance},
102
+ quiet_value=str(balance),
103
+ )
104
+ except click.ClickException:
105
+ raise
106
+ except Exception as e:
107
+ print_error(str(e))
108
+ raise SystemExit(1)