Skip to content

Commit a1ec52d

Browse files
committed
feat: init cli
0 parents  commit a1ec52d

25 files changed

Lines changed: 2735 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
permissions:
9+
contents: write
10+
11+
concurrency:
12+
group: release-${{ github.ref }}
13+
cancel-in-progress: false
14+
15+
jobs:
16+
test:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
with:
21+
fetch-depth: 0
22+
23+
- uses: actions/setup-go@v5
24+
with:
25+
go-version-file: go.mod
26+
27+
- name: Format check
28+
run: |
29+
if [ -n "$(gofmt -l .)" ]; then
30+
echo "Code is not formatted"
31+
exit 1
32+
fi
33+
34+
- name: Vet
35+
run: go vet ./...
36+
37+
- name: Test
38+
run: go test ./...
39+
40+
release:
41+
needs: test
42+
runs-on: ubuntu-latest
43+
timeout-minutes: 30
44+
steps:
45+
- uses: actions/checkout@v4
46+
with:
47+
fetch-depth: 0
48+
49+
- uses: actions/setup-go@v5
50+
with:
51+
go-version-file: go.mod
52+
53+
- name: Verify tag is on main
54+
run: |
55+
git fetch origin main
56+
if ! git merge-base --is-ancestor ${{ github.sha }} origin/main; then
57+
echo "Tag must be on main branch"
58+
exit 1
59+
fi
60+
61+
- name: Run GoReleaser
62+
uses: goreleaser/goreleaser-action@v6
63+
with:
64+
version: "~> v2"
65+
args: release --clean
66+
env:
67+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/test.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
test:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- uses: actions/setup-go@v5
19+
with:
20+
go-version-file: go.mod
21+
22+
- name: Format check
23+
run: |
24+
if [ -n "$(gofmt -l .)" ]; then
25+
echo "Code is not formatted. Run 'make fmt'"
26+
gofmt -d .
27+
exit 1
28+
fi
29+
30+
- name: Vet
31+
run: go vet ./...
32+
33+
- name: Test
34+
run: go test ./...
35+
36+
- name: Build
37+
run: make build

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
bin/
2+
dist/
3+
*.exe
4+
.DS_Store

.goreleaser.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
version: 2
2+
3+
builds:
4+
- main: ./cmd/lpagent
5+
binary: lpagent
6+
env:
7+
- CGO_ENABLED=0
8+
flags:
9+
- -trimpath
10+
ldflags:
11+
- -s -w
12+
- -X github.com/lpagent/cli/internal/version.Version={{.Version}}
13+
- -X github.com/lpagent/cli/internal/version.Commit={{.ShortCommit}}
14+
- -X github.com/lpagent/cli/internal/version.Date={{.Date}}
15+
goos:
16+
- darwin
17+
- linux
18+
- windows
19+
goarch:
20+
- amd64
21+
- arm64
22+
23+
archives:
24+
- format: tar.gz
25+
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
26+
format_overrides:
27+
- goos: windows
28+
format: zip
29+
30+
checksum:
31+
name_template: checksums.txt
32+
algorithm: sha256
33+
34+
changelog:
35+
sort: asc
36+
filters:
37+
exclude:
38+
- "^docs:"
39+
- "^test:"
40+
- "^ci:"
41+
42+
release:
43+
github:
44+
owner: lpagent
45+
name: cli
46+
prerelease: auto

Makefile

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
BINARY := lpagent
2+
MODULE := github.com/lpagent/cli
3+
VERSION_PKG := $(MODULE)/internal/version
4+
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
5+
COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "none")
6+
DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
7+
8+
LDFLAGS := -s -w \
9+
-X $(VERSION_PKG).Version=$(VERSION) \
10+
-X $(VERSION_PKG).Commit=$(COMMIT) \
11+
-X $(VERSION_PKG).Date=$(DATE)
12+
13+
.PHONY: build install test fmt vet lint clean
14+
15+
build:
16+
CGO_ENABLED=0 go build -trimpath -ldflags '$(LDFLAGS)' -o bin/$(BINARY) ./cmd/lpagent
17+
18+
install:
19+
CGO_ENABLED=0 go install -trimpath -ldflags '$(LDFLAGS)' ./cmd/lpagent
20+
21+
test:
22+
go test ./...
23+
24+
fmt:
25+
gofmt -w .
26+
27+
vet:
28+
go vet ./...
29+
30+
lint: vet
31+
@which golangci-lint >/dev/null 2>&1 || echo "Install golangci-lint: https://golangci-lint.run/usage/install/"
32+
golangci-lint run ./...
33+
34+
clean:
35+
rm -rf bin/
36+
37+
check: fmt vet test
38+
@echo "All checks passed."

README.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# LP Agent CLI
2+
3+
Command-line interface for the [LP Agent Open API](https://docs.lpagent.io). Manage Solana LP positions, discover pools, and generate add/remove liquidity transactions from the terminal.
4+
5+
Single binary, no runtime dependencies. Works standalone or as a Claude agent skill.
6+
7+
## Install
8+
9+
### From release binaries
10+
11+
Download the latest binary from [GitHub Releases](https://github.com/lpagent/cli/releases).
12+
13+
```bash
14+
# macOS (Apple Silicon)
15+
curl -sL https://github.com/lpagent/cli/releases/latest/download/lp-agent-cli_darwin_arm64.tar.gz | tar xz
16+
sudo mv lpagent /usr/local/bin/
17+
18+
# macOS (Intel)
19+
curl -sL https://github.com/lpagent/cli/releases/latest/download/lp-agent-cli_darwin_amd64.tar.gz | tar xz
20+
sudo mv lpagent /usr/local/bin/
21+
22+
# Linux (amd64)
23+
curl -sL https://github.com/lpagent/cli/releases/latest/download/lp-agent-cli_linux_amd64.tar.gz | tar xz
24+
sudo mv lpagent /usr/local/bin/
25+
```
26+
27+
### From source
28+
29+
```bash
30+
go install github.com/lpagent/cli/cmd/lpagent@latest
31+
```
32+
33+
### Build locally
34+
35+
```bash
36+
git clone https://github.com/lpagent/cli.git
37+
cd lp-agent-cli
38+
make build
39+
./bin/lpagent --help
40+
```
41+
42+
## Quick start
43+
44+
```bash
45+
# 1. Set your API key (get one at https://app.lpagent.io)
46+
lpagent auth set-key
47+
48+
# 2. Set a default wallet so you don't need --owner every time
49+
lpagent auth set-default-owner <wallet-address>
50+
51+
# 3. View open positions
52+
lpagent positions open -o table
53+
54+
# 4. View open positions in SOL
55+
lpagent positions open -o table --native
56+
57+
# 5. Check portfolio overview
58+
lpagent positions overview -o table --native
59+
```
60+
61+
## Commands
62+
63+
### Auth
64+
65+
```bash
66+
lpagent auth set-key # Set API key (saved to ~/.lpagent/config.json)
67+
lpagent auth status # Show current config
68+
lpagent auth set-default-owner <addr> # Set default wallet
69+
```
70+
71+
### Positions
72+
73+
```bash
74+
lpagent positions open --owner <addr> # Open positions
75+
lpagent positions historical --owner <addr> --from 2025-01-01 # Closed positions
76+
lpagent positions overview --owner <addr> # Portfolio metrics
77+
lpagent positions logs --position <id> # Transaction logs
78+
lpagent positions get --position <id> # Position details
79+
lpagent positions revenue <addr> # Revenue data
80+
```
81+
82+
### Pools
83+
84+
```bash
85+
lpagent pools discover --chain SOL --sort-by tvl # Discover pools
86+
lpagent pools info <poolId> # Pool details
87+
lpagent pools positions <poolId> --status Open # Positions in a pool
88+
lpagent pools onchain-stats <poolId> # TVL, volume, fees
89+
lpagent pools top-lpers <poolId> # Top liquidity providers
90+
lpagent pools add-tx <poolId> --owner <addr> --strategy Spot --input-sol 1 # Zap-In tx
91+
lpagent pools landing-add-tx --file signed-tx.json # Submit signed tx
92+
```
93+
94+
### Token
95+
96+
```bash
97+
lpagent token balance --owner <addr> # All token balances
98+
lpagent token balance --owner <addr> --ca <mint> # Specific tokens
99+
```
100+
101+
### Transactions (Zap-Out)
102+
103+
```bash
104+
lpagent tx decrease-quotes --id <id> --bps 10000 # Get withdrawal quotes
105+
lpagent tx decrease-tx --position-id <id> --bps 10000 --owner <addr> --slippage-bps 500
106+
lpagent tx landing-decrease-tx --file signed-tx.json # Submit signed tx
107+
```
108+
109+
### Raw API
110+
111+
```bash
112+
lpagent api get /lp-positions/opening --query "owner=<addr>"
113+
lpagent api post /position/decrease-quotes --data '{"id":"...","bps":5000}'
114+
```
115+
116+
## Output formats
117+
118+
All commands support `--output` / `-o`:
119+
120+
| Format | Description |
121+
|---------|------------------------------------|
122+
| `json` | Full JSON response (default) |
123+
| `table` | Human-readable table with colors |
124+
| `quiet` | IDs only, one per line |
125+
126+
Use `--native` on `positions open` and `positions overview` to show values in SOL instead of USD.
127+
128+
## Configuration
129+
130+
Config stored at `~/.lpagent/config.json`:
131+
132+
```json
133+
{
134+
"api_key": "your-api-key",
135+
"api_base_url": "https://api.lpagent.io/open-api/v1",
136+
"default_owner": "your-wallet-address",
137+
"output_format": "json"
138+
}
139+
```
140+
141+
### Environment variables
142+
143+
| Variable | Description |
144+
|------------------------|--------------------------------|
145+
| `LPAGENT_API_KEY` | API key (overrides config) |
146+
| `LPAGENT_API_URL` | Base URL (overrides config) |
147+
| `LPAGENT_DEFAULT_OWNER`| Default wallet (overrides config) |
148+
149+
CLI flags take highest priority, then env vars, then config file.
150+
151+
## Development
152+
153+
```bash
154+
make build # Build binary to bin/lpagent
155+
make test # Run tests
156+
make fmt # Format code
157+
make vet # Run go vet
158+
make lint # Run golangci-lint
159+
make check # All of the above
160+
make install # Install to $GOPATH/bin
161+
```
162+
163+
## Release
164+
165+
Releases are automated via GitHub Actions + GoReleaser. To create a release:
166+
167+
```bash
168+
git tag v0.1.0
169+
git push origin v0.1.0
170+
```
171+
172+
This triggers the release workflow which builds cross-platform binaries (darwin/linux/windows, amd64/arm64), creates a GitHub Release, and publishes checksums.
173+
174+
## License
175+
176+
MIT

cmd/lpagent/main.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package main
2+
3+
import "github.com/lpagent/cli/internal/cli"
4+
5+
func main() {
6+
cli.Execute()
7+
}

go.mod

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module github.com/lpagent/cli
2+
3+
go 1.26.1
4+
5+
require github.com/spf13/cobra v1.10.2
6+
7+
require (
8+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
9+
github.com/spf13/pflag v1.0.9 // indirect
10+
)

0 commit comments

Comments
 (0)