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
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: CI

on:
push:
branches: [main, feat/*]
pull_request:
branches: [main]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
- run: uv sync --dev
- run: uv run ruff check src/ tests/
- run: uv run ruff format --check src/ tests/

test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
python-version: ${{ matrix.python-version }}
- run: uv sync --dev
- run: uv run pytest --no-header -q
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
__pycache__/
*.pyc
.venv/
*.egg-info/
dist/
build/
.eggs/
uv.lock
14 changes: 14 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
repos:
- repo: local
hooks:
- id: ruff-check
name: "Run ruff check"
language: system
entry: uv run ruff check . --fix --force-exclude
types: [python]

- id: ruff-format
name: "Run ruff format"
language: system
entry: uv run ruff format --force-exclude
types: [python]
189 changes: 189 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# DualEntry CLI

Command-line interface for the DualEntry accounting API.

## Install

**Production** (default — connects to `api.dualentry.com`):

```bash
uv tool install git+https://github.com/dualentry/dualentry-cli.git
```

**Development** (connects to `api-dev.dualentry.com`):

```bash
uv tool install git+https://github.com/dualentry/dualentry-cli.git
dualentry config set-env dev
```

### Prerequisites

- Python >= 3.11
- [uv](https://docs.astral.sh/uv/) or [pipx](https://pipx.pypa.io/)

### Upgrade

```bash
uv tool upgrade dualentry-cli
```

### Uninstall

```bash
uv tool uninstall dualentry-cli
```

## Authentication

### Browser login (OAuth)

```bash
dualentry auth login
```

Opens a browser window for WorkOS AuthKit authentication. Tokens are stored in your system keychain.

### API key (environment variable)

For dev/CI environments, you can skip OAuth and use an API key directly:

```bash
export X_API_KEY=your_api_key
dualentry invoices list
```

Combine with a dev API URL:

```bash
export X_API_KEY=your_api_key
export DUALENTRY_API_URL=https://api-dev.dualentry.com
dualentry invoices list
```

### Check status

```bash
dualentry auth status
dualentry auth logout
```

## Configuration

```bash
# Show current config
dualentry config show

# Switch to dev environment
dualentry config set-env dev

# Switch back to prod
dualentry config set-env prod

# Set a custom API URL
dualentry config set-url https://my-staging.example.com
```

**Environment variables** (override config file):

| Variable | Description |
|----------|-------------|
| `DUALENTRY_API_URL` | API base URL (overrides config) |
| `X_API_KEY` | API key (skips OAuth) |

**Config file** is stored at `~/.dualentry/config.toml`.

## Usage

### Common options

All `list` commands support:

| Flag | Short | Description |
|------|-------|-------------|
| `--limit` | `-l` | Max items to return (default: 20) |
| `--offset` | | Offset for pagination |
| `--all` | `-a` | Fetch all pages |
| `--search` | `-s` | Free text search |
| `--status` | | Filter by status (draft, posted, archived) |
| `--start-date` | | Filter from date (YYYY-MM-DD) |
| `--end-date` | | Filter to date (YYYY-MM-DD) |
| `--format` | `-o` | Output format: `human` or `json` |

### Examples

```bash
# List invoices
dualentry invoices list

# Get a specific invoice by number
dualentry invoices get 1001

# Search with filters
dualentry invoices list --status posted --start-date 2025-01-01 --format json

# Fetch all pages
dualentry bills list --all

# Create from JSON file
dualentry invoices create --file invoice.json
```

### Available resources

**Money-in:** invoices, sales-orders, customer-payments, customer-credits, customer-prepayments, customer-prepayment-applications, customer-deposits, customer-refunds, cash-sales

**Money-out:** bills, purchase-orders, vendor-payments, vendor-credits, vendor-prepayments, vendor-prepayment-applications, vendor-refunds, direct-expenses

**Accounting:** accounts, journal-entries, bank-transfers, fixed-assets, depreciation-books

**Entities:** customers, vendors, items, companies, classifications

**Recurring:** recurring invoices, recurring bills, recurring journal-entries

**Other:** contracts, budgets, workflows

Each resource supports `list` and `get`. Most also support `create` and `update`.

## Development

### Development setup

```bash
uv sync --extra dev
```

### Pre-commit hooks

```bash
uv run pre-commit install
```

Hooks run `ruff check --fix` and `ruff format` on each commit.

### Linting

```bash
uv run ruff check .
uv run ruff format --check .
```

### Tests

Unit tests (mocked, no API needed):

```bash
uv run pytest
```

Integration tests (requires running API server):

```bash
X_API_KEY=your_key DUALENTRY_API_URL=https://api-dev.dualentry.com uv run pytest tests/test_integration.py -v
```

With coverage:

```bash
uv run pytest --cov=dualentry_cli --cov-report=term-missing
```
28 changes: 28 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail

# DualEntry CLI installer
# Usage: curl -sSL <raw-url>/install.sh | bash

REPO="git+https://github.com/dualentry/dualentry-cli.git"
TOOL_NAME="dualentry-cli"

echo "Installing DualEntry CLI..."

# Prefer uv, fall back to pipx
if command -v uv &>/dev/null; then
echo "Using uv..."
uv tool install "$REPO"
elif command -v pipx &>/dev/null; then
echo "Using pipx..."
pipx install "$REPO"
else
echo "Error: requires uv or pipx"
echo ""
echo "Install uv: curl -LsSf https://astral.sh/uv/install.sh | sh"
echo "Install pipx: brew install pipx && pipx ensurepath"
exit 1
fi

echo ""
echo "Installed! Run: dualentry auth login"
Loading
Loading