agencycore-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.
- agencycore_cli-0.1.0/.claude/rules/code-patterns.md +43 -0
- agencycore_cli-0.1.0/.claude/rules/project-structure.md +75 -0
- agencycore_cli-0.1.0/.claude/rules/testing.md +32 -0
- agencycore_cli-0.1.0/.github/workflows/publish.yml +42 -0
- agencycore_cli-0.1.0/.gitignore +6 -0
- agencycore_cli-0.1.0/CLAUDE.md +72 -0
- agencycore_cli-0.1.0/LICENSE +21 -0
- agencycore_cli-0.1.0/PKG-INFO +131 -0
- agencycore_cli-0.1.0/README.md +98 -0
- agencycore_cli-0.1.0/pyproject.toml +55 -0
- agencycore_cli-0.1.0/src/ac_cli/__init__.py +0 -0
- agencycore_cli-0.1.0/src/ac_cli/client.py +81 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/__init__.py +0 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/auth.py +102 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/crm/__init__.py +172 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/crm/activities.py +193 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/crm/communications.py +377 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/crm/companies.py +145 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/crm/deals.py +201 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/crm/imports.py +74 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/crm/lists.py +206 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/crm/people.py +154 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/envoy/__init__.py +33 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/envoy/dashboard.py +27 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/envoy/outbox.py +186 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/envoy/recipients.py +87 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/envoy/sequences.py +200 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/envoy/steps.py +131 -0
- agencycore_cli-0.1.0/src/ac_cli/commands/health.py +31 -0
- agencycore_cli-0.1.0/src/ac_cli/config.py +50 -0
- agencycore_cli-0.1.0/src/ac_cli/formatting.py +45 -0
- agencycore_cli-0.1.0/src/ac_cli/main.py +26 -0
- agencycore_cli-0.1.0/tests/__init__.py +0 -0
- agencycore_cli-0.1.0/tests/conftest.py +52 -0
- agencycore_cli-0.1.0/tests/test_crm_activities.py +100 -0
- agencycore_cli-0.1.0/tests/test_crm_communications.py +357 -0
- agencycore_cli-0.1.0/tests/test_crm_companies.py +100 -0
- agencycore_cli-0.1.0/tests/test_crm_dashboard.py +71 -0
- agencycore_cli-0.1.0/tests/test_crm_deals.py +107 -0
- agencycore_cli-0.1.0/tests/test_crm_imports.py +67 -0
- agencycore_cli-0.1.0/tests/test_crm_lists.py +136 -0
- agencycore_cli-0.1.0/tests/test_crm_people.py +86 -0
- agencycore_cli-0.1.0/tests/test_crm_search.py +50 -0
- agencycore_cli-0.1.0/tests/test_envoy_dashboard.py +30 -0
- agencycore_cli-0.1.0/tests/test_envoy_outbox.py +132 -0
- agencycore_cli-0.1.0/tests/test_envoy_recipients.py +69 -0
- agencycore_cli-0.1.0/tests/test_envoy_sequences.py +120 -0
- agencycore_cli-0.1.0/tests/test_envoy_steps.py +97 -0
- agencycore_cli-0.1.0/tests/test_formatting.py +49 -0
- agencycore_cli-0.1.0/tests/test_token_refresh.py +151 -0
- agencycore_cli-0.1.0/uv.lock +1759 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "src/**/*.py"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Code Patterns
|
|
7
|
+
|
|
8
|
+
## Environment Selection
|
|
9
|
+
- `ac login` defaults to staging (`STAGING_*` constants in `config.py`)
|
|
10
|
+
- `ac login --dev` uses local dev (`DEV_*` constants in `config.py`)
|
|
11
|
+
- Explicit `--api-url`, `--supabase-url`, `--supabase-anon-key` flags override environment defaults
|
|
12
|
+
|
|
13
|
+
## Command Structure
|
|
14
|
+
- Each command group is a `typer.Typer()` sub-app registered via `app.add_typer()` in `main.py`
|
|
15
|
+
- CRM commands use `_api_request()` helper for HTTP calls with built-in error handling
|
|
16
|
+
- Use `_build_body()` helper to construct request bodies from non-None fields (handles tags splitting)
|
|
17
|
+
- IDs are positional `typer.Argument()`, optional fields are `typer.Option(None, ...)`
|
|
18
|
+
- Tags: accept comma-separated string on CLI, `_build_body` splits to list automatically
|
|
19
|
+
- Dates: ISO format strings (`2026-03-15`)
|
|
20
|
+
|
|
21
|
+
## API Route Prefix
|
|
22
|
+
- CRM routes use the `_CRM` constant from `crm/__init__.py` (currently `/api/v1/crm`)
|
|
23
|
+
- Envoy routes use the `_ENVOY` constant from `envoy/__init__.py` (currently `/api/v1/envoy`)
|
|
24
|
+
- Both domains share `_api_request()` and `_build_body()` from `crm/__init__.py`
|
|
25
|
+
- Non-versioned routes (`/whoami`, `/health`) use root paths directly
|
|
26
|
+
- No trailing slashes on API paths
|
|
27
|
+
|
|
28
|
+
## Error Handling
|
|
29
|
+
- `_api_request()` catches both `httpx.HTTPStatusError` (API errors) and `httpx.HTTPError` (connection errors)
|
|
30
|
+
- `_handle_error()` extracts detail from API error responses and exits with code 1
|
|
31
|
+
- Non-CRM/Envoy commands (auth, health) handle errors directly in the command function
|
|
32
|
+
|
|
33
|
+
## Output
|
|
34
|
+
- Rich output by default via `formatting.py` helpers (`print_table`, `print_detail`)
|
|
35
|
+
- `--json` flag outputs raw JSON to stdout for piping/scripting
|
|
36
|
+
- `--json` is a global option on both the `crm` and `envoy` app group callbacks, passed via `typer.Context`
|
|
37
|
+
- Access in subcommands: add `ctx: typer.Context` parameter, read `ctx.obj["json"]`
|
|
38
|
+
|
|
39
|
+
## Delete Commands
|
|
40
|
+
- Always require `--yes` / `-y` flag or interactive `typer.confirm()` prompt
|
|
41
|
+
|
|
42
|
+
## Create Commands
|
|
43
|
+
- Fetch `organization_id` from `/whoami` before creating resources
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Project Structure
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
ac-cli/
|
|
5
|
+
├── src/ac_cli/
|
|
6
|
+
│ ├── main.py # Entry point, registers all sub-apps
|
|
7
|
+
│ ├── client.py # Authenticated httpx client from stored config
|
|
8
|
+
│ ├── config.py # Load/save ~/.agencycore/config.json, environment constants (STAGING_*, DEV_*)
|
|
9
|
+
│ ├── formatting.py # Shared output: print_table, print_detail, print_json
|
|
10
|
+
│ └── commands/
|
|
11
|
+
│ ├── auth.py # login, logout, whoami
|
|
12
|
+
│ ├── health.py # health check (no auth)
|
|
13
|
+
│ ├── crm/ # CRM subcommands (package)
|
|
14
|
+
│ │ ├── __init__.py # app, shared helpers (_CRM, _api_request, _build_body, _handle_error), search, dashboard
|
|
15
|
+
│ │ ├── companies.py # companies_app: list, get, create, update, delete
|
|
16
|
+
│ │ ├── people.py # people_app: list, get, create, update, delete
|
|
17
|
+
│ │ ├── deals.py # deals_app: list, get, create, update, move, order, delete
|
|
18
|
+
│ │ ├── activities.py # activities_app: list, get, create, update, complete, delete
|
|
19
|
+
│ │ ├── communications.py # communications_app: list, get, thread, unread, mark-read, delete, delete-thread, update, archive, unarchive, contact-by-email, resolve-contact, draft-email, generate-draft, unread-thread-ids
|
|
20
|
+
│ │ ├── lists.py # lists_app: list, get, create, update, members, add-member, remove-member, delete
|
|
21
|
+
│ │ └── imports.py # imports_app: preview, commit
|
|
22
|
+
│ └── envoy/ # Envoy outreach subcommands (package)
|
|
23
|
+
│ ├── __init__.py # app, _ENVOY prefix, envoy_callback, registers sub-apps
|
|
24
|
+
│ ├── sequences.py # sequences_app: list, get, create, update, delete, launch, pause, resume
|
|
25
|
+
│ ├── steps.py # steps_app: create, update, delete, reorder, stats
|
|
26
|
+
│ ├── recipients.py # recipients_app: list, add, remove
|
|
27
|
+
│ ├── outbox.py # outbox_app: pending, sent, step-drafts, update-draft, approve, reject, regenerate
|
|
28
|
+
│ └── dashboard.py # dashboard_command (standalone command, not sub-app)
|
|
29
|
+
├── tests/
|
|
30
|
+
│ ├── conftest.py # Shared fixtures (mock_api, mock_config, invoke)
|
|
31
|
+
│ ├── test_formatting.py
|
|
32
|
+
│ ├── test_crm_search.py
|
|
33
|
+
│ ├── test_crm_companies.py
|
|
34
|
+
│ ├── test_crm_people.py
|
|
35
|
+
│ ├── test_crm_deals.py
|
|
36
|
+
│ ├── test_crm_activities.py
|
|
37
|
+
│ ├── test_crm_communications.py
|
|
38
|
+
│ ├── test_crm_dashboard.py
|
|
39
|
+
│ ├── test_crm_lists.py
|
|
40
|
+
│ ├── test_crm_imports.py
|
|
41
|
+
│ ├── test_envoy_sequences.py
|
|
42
|
+
│ ├── test_envoy_steps.py
|
|
43
|
+
│ ├── test_envoy_recipients.py
|
|
44
|
+
│ ├── test_envoy_outbox.py
|
|
45
|
+
│ ├── test_envoy_dashboard.py
|
|
46
|
+
│ └── test_token_refresh.py
|
|
47
|
+
├── pyproject.toml
|
|
48
|
+
└── uv.lock
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Adding New CRM Subcommand Groups
|
|
52
|
+
1. Create `src/ac_cli/commands/crm/<group>.py` with `<group>_app = typer.Typer(help="...")`
|
|
53
|
+
2. Import shared helpers: `from ac_cli.commands.crm import _CRM, _api_request, _build_body`
|
|
54
|
+
3. Add `ctx: typer.Context` as first parameter to commands that need `--json` output
|
|
55
|
+
4. Use `_api_request("get", ...)` for API calls and `_build_body(...)` for request bodies
|
|
56
|
+
5. Read JSON flag via `ctx.obj["json"]`
|
|
57
|
+
6. Register in `crm/__init__.py`: import the app and call `app.add_typer(<group>_app, name="<group>")`
|
|
58
|
+
|
|
59
|
+
## Adding Envoy Subcommand Groups
|
|
60
|
+
1. Create `src/ac_cli/commands/envoy/<group>.py` with `<group>_app = typer.Typer(help="...")`
|
|
61
|
+
2. Import shared helpers: `from ac_cli.commands.crm import _api_request, _build_body`
|
|
62
|
+
3. Import envoy prefix: `from ac_cli.commands.envoy import _ENVOY`
|
|
63
|
+
4. Add `ctx: typer.Context` as first parameter to commands that need `--json` output
|
|
64
|
+
5. Read JSON flag via `ctx.obj["json"]`
|
|
65
|
+
6. Register in `envoy/__init__.py`: import the app and call `app.add_typer(<group>_app, name="<group>")`
|
|
66
|
+
|
|
67
|
+
## Adding Non-CRM/Envoy Command Groups
|
|
68
|
+
1. Create `src/ac_cli/commands/<group>.py` (or package) with `app = typer.Typer(help="...")`
|
|
69
|
+
2. Import and register in `main.py`: `app.add_typer(<group>.app, name="<group>")`
|
|
70
|
+
|
|
71
|
+
## API Endpoints
|
|
72
|
+
- CRM commands hit `/api/v1/crm/*` — the `_CRM` constant in `crm/__init__.py` holds this prefix
|
|
73
|
+
- Envoy commands hit `/api/v1/envoy/*` — the `_ENVOY` constant in `envoy/__init__.py` holds this prefix
|
|
74
|
+
- Both share `_api_request()` and `_build_body()` helpers from `crm/__init__.py`
|
|
75
|
+
- The API base URL is stored in `~/.agencycore/config.json` (set during `ac login`). Environment constants live in `config.py`: `STAGING_*` (default) and `DEV_*` (used with `ac login --dev`).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "tests/**/*.py"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Testing
|
|
7
|
+
|
|
8
|
+
## Stack
|
|
9
|
+
- **pytest** for test runner
|
|
10
|
+
- **respx** for mocking httpx requests (cleaner than pytest-httpx for sync client)
|
|
11
|
+
- **typer.testing.CliRunner** for invoking CLI commands
|
|
12
|
+
|
|
13
|
+
## Fixtures (in `tests/conftest.py`)
|
|
14
|
+
- `cli_runner` — CliRunner instance
|
|
15
|
+
- `mock_config` — patches `load_config()` to return valid auth config
|
|
16
|
+
- `mock_api` — respx mock router intercepting httpx calls to API base URL
|
|
17
|
+
- `invoke` — convenience function combining all three: `invoke(["crm", "companies", "list"])`
|
|
18
|
+
|
|
19
|
+
## What to Test Per Command
|
|
20
|
+
- **Happy path**: correct API call made, response rendered (table or JSON)
|
|
21
|
+
- **`--json` flag**: output is valid JSON (parse with `json.loads`)
|
|
22
|
+
- **Error handling**: API returns 404/422/500 → CLI prints error, exits code 1
|
|
23
|
+
- **`--yes` on delete**: skips confirmation prompt
|
|
24
|
+
- **Abort on delete**: `input="n\n"` → exits code 1
|
|
25
|
+
|
|
26
|
+
## Running
|
|
27
|
+
```bash
|
|
28
|
+
uv run pytest # All tests (165 tests)
|
|
29
|
+
uv run pytest tests/test_crm_deals.py # Single CRM test file
|
|
30
|
+
uv run pytest tests/test_envoy_outbox.py # Single Envoy test file
|
|
31
|
+
uv run pytest -k "test_companies" # By name pattern
|
|
32
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
id-token: write
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: astral-sh/setup-uv@v4
|
|
19
|
+
with:
|
|
20
|
+
version: "latest"
|
|
21
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
22
|
+
run: uv python install ${{ matrix.python-version }}
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: uv sync --all-extras --python ${{ matrix.python-version }}
|
|
25
|
+
- name: Run tests
|
|
26
|
+
run: uv run pytest
|
|
27
|
+
|
|
28
|
+
publish:
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
needs: test
|
|
31
|
+
environment:
|
|
32
|
+
name: pypi
|
|
33
|
+
url: https://pypi.org/p/agencycore-cli
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
- uses: astral-sh/setup-uv@v4
|
|
37
|
+
with:
|
|
38
|
+
version: "latest"
|
|
39
|
+
- name: Build package
|
|
40
|
+
run: uv build
|
|
41
|
+
- name: Publish to PyPI
|
|
42
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# ac-cli
|
|
2
|
+
|
|
3
|
+
Python CLI for AgencyCore. Built with Typer + httpx + Rich + Supabase auth.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv sync # Install all dependencies
|
|
9
|
+
uv sync --all-extras # Install with dev dependencies (pytest, respx)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Commands
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
ac login / logout / whoami # Auth commands
|
|
16
|
+
ac health check # API health (no auth)
|
|
17
|
+
|
|
18
|
+
# CRM
|
|
19
|
+
ac crm search <query> # Search companies, contacts, deals
|
|
20
|
+
ac crm companies list|get|create|update|delete
|
|
21
|
+
ac crm people list|get|create|update|delete
|
|
22
|
+
ac crm deals list|get|create|update|move|order|delete
|
|
23
|
+
ac crm activities list|get|create|update|complete|delete
|
|
24
|
+
ac crm comms list|get|thread|unread|mark-read|delete|delete-thread|update|archive|unarchive|contact-by-email|resolve-contact|draft-email|generate-draft|unread-thread-ids
|
|
25
|
+
ac crm dashboard [--period N]
|
|
26
|
+
ac crm lists list|get|create|update|members|add-member|remove-member|delete
|
|
27
|
+
ac crm import preview|commit
|
|
28
|
+
|
|
29
|
+
# Envoy (outreach)
|
|
30
|
+
ac envoy sequences list|get|create|update|delete|launch|pause|resume
|
|
31
|
+
ac envoy steps create|update|delete|reorder|stats
|
|
32
|
+
ac envoy recipients list|add|remove
|
|
33
|
+
ac envoy outbox pending|sent|step-drafts|update-draft|approve|reject|regenerate
|
|
34
|
+
ac envoy dashboard
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
All CRM and Envoy commands support `--json` flag for scripting (set on `ac crm --json` or `ac envoy --json`). The flag is passed via `typer.Context`.
|
|
38
|
+
|
|
39
|
+
## Running Checks
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
uv run pytest # Run all tests (165 tests)
|
|
43
|
+
uv run pytest tests/test_crm_companies.py -v # Single test file
|
|
44
|
+
uv run python -m ac_cli.main --help # Verify CLI loads
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Dependency Management
|
|
48
|
+
|
|
49
|
+
Uses **uv** for dependency management. Both `pyproject.toml` and `uv.lock` must stay in sync.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
uv add <package> # Add a dependency
|
|
53
|
+
uv add --dev <package> # Add a dev dependency
|
|
54
|
+
uv lock # Regenerate lockfile after manual pyproject.toml edits
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Config
|
|
58
|
+
|
|
59
|
+
Credentials stored in `~/.agencycore/config.json` (file mode 0600).
|
|
60
|
+
|
|
61
|
+
### Environments
|
|
62
|
+
|
|
63
|
+
`ac login` defaults to **staging**. Use `--dev` for local development:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
ac login # Staging (api.agencycore.dev)
|
|
67
|
+
ac login --dev # Local dev (localhost:8008 + local Supabase)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Environment constants (URLs, anon keys) are defined in `config.py`:
|
|
71
|
+
- `STAGING_*` — staging API + Supabase
|
|
72
|
+
- `DEV_*` — localhost API + local Supabase (`127.0.0.1:54321`)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 AlterityNetwork
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agencycore-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AgencyCore CLI — manage your CRM, outreach, and more from the terminal
|
|
5
|
+
Project-URL: Homepage, https://github.com/AlterityNetwork/ac-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/AlterityNetwork/ac-cli
|
|
7
|
+
Project-URL: Issues, https://github.com/AlterityNetwork/ac-cli/issues
|
|
8
|
+
Author-email: AlterityNetwork <dev@agencycore.dev>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agencycore,cli,crm,pipeline,sales
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Office/Business
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: httpx>=0.27
|
|
25
|
+
Requires-Dist: rich>=13.0
|
|
26
|
+
Requires-Dist: socksio>=1.0.0
|
|
27
|
+
Requires-Dist: supabase>=2.0
|
|
28
|
+
Requires-Dist: typer>=0.9
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: respx>=0.22; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# AgencyCore CLI
|
|
35
|
+
|
|
36
|
+
Command-line interface for [AgencyCore](https://agencycore.dev) — manage your CRM, outreach sequences, and pipeline from the terminal.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install agencycore-cli
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or with [uv](https://docs.astral.sh/uv/):
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
uv pip install agencycore-cli
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Requires Python 3.10+.
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Log in (connects to AgencyCore staging by default)
|
|
56
|
+
ac login
|
|
57
|
+
|
|
58
|
+
# Use --dev for local development
|
|
59
|
+
ac login --dev
|
|
60
|
+
|
|
61
|
+
# Check your identity
|
|
62
|
+
ac whoami
|
|
63
|
+
|
|
64
|
+
# Check API health
|
|
65
|
+
ac health check
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## CRM Commands
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Companies
|
|
72
|
+
ac crm companies list
|
|
73
|
+
ac crm companies get <id>
|
|
74
|
+
ac crm companies create --name "Acme Corp" --industry Technology
|
|
75
|
+
|
|
76
|
+
# People (Contacts)
|
|
77
|
+
ac crm people list
|
|
78
|
+
ac crm people create --email jane@acme.com --full-name "Jane Smith"
|
|
79
|
+
|
|
80
|
+
# Deals
|
|
81
|
+
ac crm deals list
|
|
82
|
+
ac crm deals create --name "Enterprise Deal" --stage qualified --amount 50000
|
|
83
|
+
ac crm deals move <id> --stage negotiation
|
|
84
|
+
|
|
85
|
+
# Activities
|
|
86
|
+
ac crm activities list --status pending
|
|
87
|
+
ac crm activities create --type call --title "Follow up" --due-date 2026-03-20
|
|
88
|
+
|
|
89
|
+
# Communications
|
|
90
|
+
ac crm comms unread
|
|
91
|
+
ac crm comms draft-email --contact-id <id> --subject "Hello" --content "..."
|
|
92
|
+
|
|
93
|
+
# Search & Dashboard
|
|
94
|
+
ac crm search "acme"
|
|
95
|
+
ac crm dashboard --period 30
|
|
96
|
+
|
|
97
|
+
# Lists & Import
|
|
98
|
+
ac crm lists list
|
|
99
|
+
ac crm import preview --file contacts.json
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Envoy (Outreach)
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
ac envoy sequences list
|
|
106
|
+
ac envoy outbox pending
|
|
107
|
+
ac envoy dashboard
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Output Modes
|
|
111
|
+
|
|
112
|
+
All commands support rich table output (default) or JSON for scripting:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
ac crm deals list # Pretty tables
|
|
116
|
+
ac crm --json deals list # Raw JSON
|
|
117
|
+
ac crm --json deals list | jq '.[].name' # Pipe to jq
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Development
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
git clone https://github.com/AlterityNetwork/ac-cli.git
|
|
124
|
+
cd ac-cli
|
|
125
|
+
uv sync --all-extras
|
|
126
|
+
uv run pytest
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# AgencyCore CLI
|
|
2
|
+
|
|
3
|
+
Command-line interface for [AgencyCore](https://agencycore.dev) — manage your CRM, outreach sequences, and pipeline from the terminal.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install agencycore-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or with [uv](https://docs.astral.sh/uv/):
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv pip install agencycore-cli
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Requires Python 3.10+.
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Log in (connects to AgencyCore staging by default)
|
|
23
|
+
ac login
|
|
24
|
+
|
|
25
|
+
# Use --dev for local development
|
|
26
|
+
ac login --dev
|
|
27
|
+
|
|
28
|
+
# Check your identity
|
|
29
|
+
ac whoami
|
|
30
|
+
|
|
31
|
+
# Check API health
|
|
32
|
+
ac health check
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## CRM Commands
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Companies
|
|
39
|
+
ac crm companies list
|
|
40
|
+
ac crm companies get <id>
|
|
41
|
+
ac crm companies create --name "Acme Corp" --industry Technology
|
|
42
|
+
|
|
43
|
+
# People (Contacts)
|
|
44
|
+
ac crm people list
|
|
45
|
+
ac crm people create --email jane@acme.com --full-name "Jane Smith"
|
|
46
|
+
|
|
47
|
+
# Deals
|
|
48
|
+
ac crm deals list
|
|
49
|
+
ac crm deals create --name "Enterprise Deal" --stage qualified --amount 50000
|
|
50
|
+
ac crm deals move <id> --stage negotiation
|
|
51
|
+
|
|
52
|
+
# Activities
|
|
53
|
+
ac crm activities list --status pending
|
|
54
|
+
ac crm activities create --type call --title "Follow up" --due-date 2026-03-20
|
|
55
|
+
|
|
56
|
+
# Communications
|
|
57
|
+
ac crm comms unread
|
|
58
|
+
ac crm comms draft-email --contact-id <id> --subject "Hello" --content "..."
|
|
59
|
+
|
|
60
|
+
# Search & Dashboard
|
|
61
|
+
ac crm search "acme"
|
|
62
|
+
ac crm dashboard --period 30
|
|
63
|
+
|
|
64
|
+
# Lists & Import
|
|
65
|
+
ac crm lists list
|
|
66
|
+
ac crm import preview --file contacts.json
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Envoy (Outreach)
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
ac envoy sequences list
|
|
73
|
+
ac envoy outbox pending
|
|
74
|
+
ac envoy dashboard
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Output Modes
|
|
78
|
+
|
|
79
|
+
All commands support rich table output (default) or JSON for scripting:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
ac crm deals list # Pretty tables
|
|
83
|
+
ac crm --json deals list # Raw JSON
|
|
84
|
+
ac crm --json deals list | jq '.[].name' # Pipe to jq
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Development
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
git clone https://github.com/AlterityNetwork/ac-cli.git
|
|
91
|
+
cd ac-cli
|
|
92
|
+
uv sync --all-extras
|
|
93
|
+
uv run pytest
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agencycore-cli"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "AgencyCore CLI — manage your CRM, outreach, and more from the terminal"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "AlterityNetwork", email = "dev@agencycore.dev" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["crm", "cli", "agencycore", "sales", "pipeline"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Intended Audience :: End Users/Desktop",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Topic :: Office/Business",
|
|
28
|
+
]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"typer>=0.9",
|
|
31
|
+
"httpx>=0.27",
|
|
32
|
+
"supabase>=2.0",
|
|
33
|
+
"rich>=13.0",
|
|
34
|
+
"socksio>=1.0.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
dev = [
|
|
39
|
+
"pytest>=8.0",
|
|
40
|
+
"respx>=0.22",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
Homepage = "https://github.com/AlterityNetwork/ac-cli"
|
|
45
|
+
Repository = "https://github.com/AlterityNetwork/ac-cli"
|
|
46
|
+
Issues = "https://github.com/AlterityNetwork/ac-cli/issues"
|
|
47
|
+
|
|
48
|
+
[tool.hatch.build.targets.wheel]
|
|
49
|
+
packages = ["src/ac_cli"]
|
|
50
|
+
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
testpaths = ["tests"]
|
|
53
|
+
|
|
54
|
+
[project.scripts]
|
|
55
|
+
ac = "ac_cli.main:app"
|
|
File without changes
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Authenticated httpx client for the AgencyCore API."""
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
from ac_cli.config import load_config, save_config
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _refresh_access_token(cfg: dict) -> str:
|
|
10
|
+
"""Use stored refresh_token to obtain a new access_token from Supabase.
|
|
11
|
+
|
|
12
|
+
Persists the new tokens to config. Returns the new access_token.
|
|
13
|
+
Raises typer.Exit on failure.
|
|
14
|
+
"""
|
|
15
|
+
from supabase import create_client
|
|
16
|
+
|
|
17
|
+
supabase_url = cfg.get("supabase_url")
|
|
18
|
+
supabase_anon_key = cfg.get("supabase_anon_key")
|
|
19
|
+
refresh_token = cfg.get("refresh_token")
|
|
20
|
+
|
|
21
|
+
if not supabase_url or not supabase_anon_key or not refresh_token:
|
|
22
|
+
typer.echo("Session expired. Run `ac login` to re-authenticate.")
|
|
23
|
+
raise typer.Exit(code=1)
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
sb = create_client(supabase_url, supabase_anon_key)
|
|
27
|
+
response = sb.auth.refresh_session(refresh_token)
|
|
28
|
+
except Exception as exc:
|
|
29
|
+
typer.echo(f"Token refresh failed: {exc}\nRun `ac login` to re-authenticate.")
|
|
30
|
+
raise typer.Exit(code=1) from exc
|
|
31
|
+
|
|
32
|
+
session = response.session
|
|
33
|
+
if not session:
|
|
34
|
+
typer.echo("Token refresh returned no session. Run `ac login` to re-authenticate.")
|
|
35
|
+
raise typer.Exit(code=1)
|
|
36
|
+
|
|
37
|
+
cfg["access_token"] = session.access_token
|
|
38
|
+
cfg["refresh_token"] = session.refresh_token
|
|
39
|
+
save_config(cfg)
|
|
40
|
+
return session.access_token
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class _AuthClient(httpx.Client):
|
|
44
|
+
"""httpx.Client that auto-refreshes expired Supabase tokens on 401."""
|
|
45
|
+
|
|
46
|
+
def __init__(self, cfg: dict, **kwargs: object) -> None:
|
|
47
|
+
self._cfg = cfg
|
|
48
|
+
super().__init__(**kwargs)
|
|
49
|
+
|
|
50
|
+
def send(self, request: httpx.Request, **kwargs: object) -> httpx.Response:
|
|
51
|
+
response = super().send(request, **kwargs)
|
|
52
|
+
|
|
53
|
+
if response.status_code == 401:
|
|
54
|
+
new_token = _refresh_access_token(self._cfg)
|
|
55
|
+
request.headers["Authorization"] = f"Bearer {new_token}"
|
|
56
|
+
self.headers["Authorization"] = f"Bearer {new_token}"
|
|
57
|
+
response = super().send(request, **kwargs)
|
|
58
|
+
|
|
59
|
+
return response
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_api_client() -> httpx.Client:
|
|
63
|
+
"""Return an httpx.Client with base URL and auth header from stored config.
|
|
64
|
+
|
|
65
|
+
The client auto-refreshes the Supabase access token on 401 responses.
|
|
66
|
+
Raises typer.Exit if not logged in.
|
|
67
|
+
"""
|
|
68
|
+
cfg = load_config()
|
|
69
|
+
access_token = cfg.get("access_token")
|
|
70
|
+
api_url = cfg.get("api_url")
|
|
71
|
+
|
|
72
|
+
if not access_token or not api_url:
|
|
73
|
+
typer.echo("Not logged in. Run `ac login` first.")
|
|
74
|
+
raise typer.Exit(code=1)
|
|
75
|
+
|
|
76
|
+
return _AuthClient(
|
|
77
|
+
cfg=cfg,
|
|
78
|
+
base_url=api_url,
|
|
79
|
+
headers={"Authorization": f"Bearer {access_token}"},
|
|
80
|
+
timeout=30.0,
|
|
81
|
+
)
|
|
File without changes
|