freelancer-payment-protection-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.
Files changed (23) hide show
  1. freelancer_payment_protection_cli-0.1.0/.gitignore +50 -0
  2. freelancer_payment_protection_cli-0.1.0/LICENSE +35 -0
  3. freelancer_payment_protection_cli-0.1.0/PKG-INFO +246 -0
  4. freelancer_payment_protection_cli-0.1.0/README.md +213 -0
  5. freelancer_payment_protection_cli-0.1.0/pyproject.toml +71 -0
  6. freelancer_payment_protection_cli-0.1.0/src/freelancer_payment_protection_cli/__init__.py +6 -0
  7. freelancer_payment_protection_cli-0.1.0/src/freelancer_payment_protection_cli/api.py +89 -0
  8. freelancer_payment_protection_cli-0.1.0/src/freelancer_payment_protection_cli/auth.py +223 -0
  9. freelancer_payment_protection_cli-0.1.0/src/freelancer_payment_protection_cli/commands/__init__.py +0 -0
  10. freelancer_payment_protection_cli-0.1.0/src/freelancer_payment_protection_cli/commands/auth_cmds.py +84 -0
  11. freelancer_payment_protection_cli-0.1.0/src/freelancer_payment_protection_cli/commands/client_cmds.py +111 -0
  12. freelancer_payment_protection_cli-0.1.0/src/freelancer_payment_protection_cli/commands/escalation_cmds.py +142 -0
  13. freelancer_payment_protection_cli-0.1.0/src/freelancer_payment_protection_cli/commands/invoice_cmds.py +145 -0
  14. freelancer_payment_protection_cli-0.1.0/src/freelancer_payment_protection_cli/config.py +45 -0
  15. freelancer_payment_protection_cli-0.1.0/src/freelancer_payment_protection_cli/main.py +43 -0
  16. freelancer_payment_protection_cli-0.1.0/src/freelancer_payment_protection_cli/output.py +72 -0
  17. freelancer_payment_protection_cli-0.1.0/tests/__init__.py +0 -0
  18. freelancer_payment_protection_cli-0.1.0/tests/conftest.py +49 -0
  19. freelancer_payment_protection_cli-0.1.0/tests/test_auth.py +100 -0
  20. freelancer_payment_protection_cli-0.1.0/tests/test_auth_commands.py +48 -0
  21. freelancer_payment_protection_cli-0.1.0/tests/test_client_commands.py +88 -0
  22. freelancer_payment_protection_cli-0.1.0/tests/test_escalation_commands.py +123 -0
  23. freelancer_payment_protection_cli-0.1.0/tests/test_invoice_commands.py +132 -0
@@ -0,0 +1,50 @@
1
+ # Dependencies
2
+ node_modules/
3
+ .pnp
4
+ .pnp.js
5
+
6
+ # Build outputs
7
+ .next/
8
+ .turbo/
9
+ dist/
10
+ build/
11
+ out/
12
+
13
+ # Environment files — NEVER commit real secrets
14
+ .env
15
+ .env.local
16
+ .env.*.local
17
+ *.env
18
+
19
+ # Python
20
+ __pycache__/
21
+ *.pyc
22
+ *.pyo
23
+ .venv/
24
+ venv/
25
+ *.egg-info/
26
+ .pytest_cache/
27
+ htmlcov/
28
+ .coverage
29
+ coverage.xml
30
+
31
+ # Local dev databases — no credentials in these
32
+ *.db
33
+ *.sqlite
34
+ *.sqlite3
35
+
36
+ # OS
37
+ .DS_Store
38
+ Thumbs.db
39
+
40
+ # IDE
41
+ .idea/
42
+ .vscode/settings.json
43
+ *.swp
44
+
45
+ # Reference docs (local strategy docs — not for public repo)
46
+ reference-docs-context/
47
+
48
+ # Generated PDFs / docs (created at runtime)
49
+ generated-docs/
50
+ tmp/
@@ -0,0 +1,35 @@
1
+ Copyright (c) 2026 Rudrendu Paul and Sourav Nandy. All rights reserved.
2
+
3
+ PROPRIETARY LICENSE
4
+
5
+ This software and associated documentation files (the "Software") are the
6
+ exclusive intellectual property of Rudrendu Paul and Sourav Nandy
7
+ ("the Owners").
8
+
9
+ RESTRICTIONS
10
+
11
+ 1. No use, copying, modification, merging, publishing, distribution,
12
+ sublicensing, or selling of this Software — in whole or in part — is
13
+ permitted without prior written approval from both Owners.
14
+
15
+ 2. Any personal, academic, commercial, or scheduled use of this Software
16
+ requires explicit written permission obtained directly from:
17
+
18
+ Rudrendu Paul — https://github.com/RudrenduPaul
19
+ Sourav Nandy — (contact via Rudrendu Paul)
20
+
21
+ 3. Unauthorized use of this Software for any purpose, including but not
22
+ limited to building competing products, white-labeling, or redistribution,
23
+ is strictly prohibited and may result in legal action.
24
+
25
+ TO REQUEST PERMISSION
26
+
27
+ Submit a written request describing your intended use to the Owners. Approval
28
+ is granted solely at the discretion of both Owners and may be subject to
29
+ additional terms or a commercial licensing agreement.
30
+
31
+ DISCLAIMER
32
+
33
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34
+ IMPLIED. IN NO EVENT SHALL THE OWNERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR
35
+ OTHER LIABILITY ARISING FROM THE USE OF OR INABILITY TO USE THE SOFTWARE.
@@ -0,0 +1,246 @@
1
+ Metadata-Version: 2.4
2
+ Name: freelancer-payment-protection-cli
3
+ Version: 0.1.0
4
+ Summary: Command-line client for freelancer-payment-protection: automated invoice escalation, legal document generation, and client risk scoring for freelancers.
5
+ Project-URL: Homepage, https://github.com/RudrenduPaul/freelancer-payment-protection
6
+ Project-URL: Repository, https://github.com/RudrenduPaul/freelancer-payment-protection
7
+ Project-URL: Bug Tracker, https://github.com/RudrenduPaul/freelancer-payment-protection/issues
8
+ Author: Rudrendu Paul, Sourav Nandy
9
+ License: Proprietary
10
+ License-File: LICENSE
11
+ Keywords: agent-native,cli,fastapi,freelance,invoice-escalation,invoicing,risk-scoring,supabase
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Office/Business :: Financial :: Accounting
22
+ Classifier: Topic :: Utilities
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: click<9,>=8.1
25
+ Requires-Dist: httpx<1,>=0.27
26
+ Provides-Extra: dev
27
+ Requires-Dist: build<2,>=1.0; extra == 'dev'
28
+ Requires-Dist: pytest-cov<7,>=5.0; extra == 'dev'
29
+ Requires-Dist: pytest<9,>=8.0; extra == 'dev'
30
+ Requires-Dist: respx<1,>=0.21; extra == 'dev'
31
+ Requires-Dist: twine<7,>=5.0; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # freelancer-payment-protection-cli
35
+
36
+ Command-line client for [freelancer-payment-protection](https://github.com/RudrenduPaul/freelancer-payment-protection):
37
+ automated invoice escalation, legal document generation, and client risk
38
+ scoring for freelancers. This package wraps the project's FastAPI backend
39
+ (`apps/api/app/routers/*.py`) so the same clients, invoices, escalations,
40
+ and risk-scoring data you'd otherwise reach through the dashboard or the
41
+ raw HTTP API is scriptable from a terminal or an agent.
42
+
43
+ ![Login and first command](../../docs/demo.gif)
44
+
45
+ ## Install
46
+
47
+ ```bash
48
+ pip install freelancer-payment-protection-cli
49
+ ```
50
+
51
+ Or with [uv](https://docs.astral.sh/uv/) / [pipx](https://pipx.pypa.io/):
52
+
53
+ ```bash
54
+ uvx freelancer-payment-protection-cli --help
55
+ pipx install freelancer-payment-protection-cli
56
+ ```
57
+
58
+ Requires Python 3.10+. The console command is installed as both `fpp`
59
+ (short form) and `freelancer-payment-protection` (full form) — they are the
60
+ same entry point.
61
+
62
+ ## Configuration
63
+
64
+ The CLI needs to know two things: which backend API to talk to, and which
65
+ Supabase project issues your login tokens.
66
+
67
+ | Variable | Purpose | Default |
68
+ |---|---|---|
69
+ | `FPP_API_URL` | Backend API base URL | `http://localhost:8000` |
70
+ | `FPP_SUPABASE_URL` (or `SUPABASE_URL`) | Your Supabase project URL | none, required for `login` |
71
+ | `FPP_SUPABASE_ANON_KEY` (or `SUPABASE_ANON_KEY`) | Your Supabase project's anon key | none, required for `login` |
72
+
73
+ The anon key is the same public key the web app's Supabase client uses —
74
+ it is not a secret, and it's the key already in `apps/web/.env.example` as
75
+ `NEXT_PUBLIC_SUPABASE_ANON_KEY`.
76
+
77
+ ## Login and authentication
78
+
79
+ ```bash
80
+ export FPP_SUPABASE_URL="https://your-project.supabase.co"
81
+ export FPP_SUPABASE_ANON_KEY="your-anon-key"
82
+ fpp login
83
+ ```
84
+
85
+ `fpp login` prompts for your email and password, then calls Supabase's own
86
+ REST auth endpoint directly:
87
+
88
+ ```
89
+ POST {SUPABASE_URL}/auth/v1/token?grant_type=password
90
+ Header: apikey: <anon key>
91
+ Body: {"email": ..., "password": ...}
92
+ ```
93
+
94
+ This is the same call the web dashboard's Supabase client makes — the CLI
95
+ never talks to a login endpoint of its own, because the backend
96
+ (`apps/api/app/middleware/auth.py`) doesn't mint tokens; it only validates
97
+ Supabase-issued JWTs. On success, the returned `access_token` and
98
+ `refresh_token` are cached to `~/.config/freelancer-payment-protection-cli/credentials.json`
99
+ (mode 600). Every later command reads the JWT's `workspace_id` claim the
100
+ same way `get_current_workspace()` does server-side, and transparently
101
+ refreshes the access token with the cached refresh token once it expires.
102
+
103
+ Run `fpp logout` to delete the cached credentials, or `fpp whoami` to see
104
+ which workspace and email the cached token resolves to.
105
+
106
+ ## Commands
107
+
108
+ Every data-returning command supports `--json` for scripting and agent use.
109
+
110
+ ```
111
+ fpp login Log in (prompts for email/password)
112
+ fpp logout Remove cached credentials
113
+ fpp whoami [--json] Show cached workspace/session info
114
+
115
+ fpp invoice list [--status] [--client-id] [--page] [--page-size] [--json]
116
+ fpp invoice create --client-id --invoice-number --amount --due-date [...] [--json]
117
+ fpp invoice show <invoice-id> [--json]
118
+ fpp invoice set-status <invoice-id> <status> [--json]
119
+
120
+ fpp escalation list [--json] Active escalations, grouped by stage
121
+ fpp escalation status <invoice-id> [--json] Current stage + full history
122
+ fpp escalation advance <invoice-id> [--json] AI-draft the next stage's email
123
+
124
+ fpp client list [--risk-level] [--search] [--page] [--page-size] [--json]
125
+ fpp client show <client-id> [--json]
126
+ fpp client risk <client-id> [--json] Compute/refresh the AI risk score
127
+ ```
128
+
129
+ Run `fpp --help` or `fpp <command> --help` for full flag references.
130
+
131
+ ![Filtering invoices, scoring a client, and checking escalation status](../../docs/usage.gif)
132
+
133
+ ### A note on `escalation advance`
134
+
135
+ The backend's escalation router (`apps/api/app/routers/escalations.py`)
136
+ exposes exactly three routes: list active escalations, draft the next
137
+ stage's email, and read history. There is no route that persists a stage
138
+ change — `draft_escalation_email` in `escalation_service.py` computes and
139
+ returns what the next stage's email would say, but never writes
140
+ `escalation_stage` back to the database. `fpp escalation advance` calls
141
+ that draft endpoint and shows you the preview; it does not claim to move
142
+ the invoice to the next stage, because the API it wraps doesn't do that
143
+ either.
144
+
145
+ ### JSON output for agents/scripts
146
+
147
+ ```bash
148
+ fpp invoice list --status overdue --json | jq '.[] | {id, invoiceNumber, daysPastDue}'
149
+ fpp client risk "$CLIENT_ID" --json | jq '.level'
150
+ ```
151
+
152
+ Field names in `--json` output match the backend's actual Pydantic response
153
+ models exactly (camelCase, e.g. `invoiceNumber`, `daysPastDue`,
154
+ `escalationStage`) since the CLI passes the API's response straight
155
+ through rather than remapping it.
156
+
157
+ ## FAQ
158
+
159
+ **What is this, and how is it different from just calling the API with curl?**
160
+ It's a typed command-line wrapper around the same backend the web
161
+ dashboard uses — invoices, escalations, and client risk scoring — with
162
+ persistent login (so you're not re-attaching a bearer token to every
163
+ request), human-readable tables by default, and a `--json` flag on every
164
+ data command for piping into `jq`, scripts, or an agent's tool-calling
165
+ loop. The differentiator versus curl is session handling (login once,
166
+ silent token refresh after) and consistent, documented output shapes
167
+ instead of hand-rolled request construction.
168
+
169
+ **What platforms and Python versions does it support?**
170
+ Python 3.10 through 3.13, on any OS `pip`/`uvx`/`pipx` runs on (Linux,
171
+ macOS, Windows). It has no compiled dependencies — the only runtime
172
+ dependencies are `click` and `httpx`, both pure-Python-installable wheels.
173
+
174
+ **How do I log in, and where are my credentials stored?**
175
+ Run `fpp login`, enter your email and password when prompted. The CLI
176
+ calls Supabase's password-grant token endpoint directly (see "Login and
177
+ authentication" above) and caches the resulting access and refresh tokens
178
+ to `~/.config/freelancer-payment-protection-cli/credentials.json` with
179
+ file mode 600 (owner read/write only). Nothing is sent anywhere except
180
+ Supabase's own auth endpoint and the backend API you configure via
181
+ `FPP_API_URL`.
182
+
183
+ **I ran a command and got `Error: Internal Server Error` — is that a CLI bug?**
184
+ Usually not. The CLI's error handling surfaces whatever the backend
185
+ returned; a 500 means the backend itself failed. Two real, backend-side
186
+ causes to check first: (1) `fpp client risk` and `fpp escalation advance`
187
+ both trigger AI calls through `packages/legal_ai/client.py` — if
188
+ `ANTHROPIC_API_KEY` isn't a real key on the server, `client risk` falls
189
+ back to a heuristic score automatically, but `escalation advance` has no
190
+ such fallback and will 500. (2) Confirm you're running a backend build
191
+ that includes the `packages/legal_ai` module-name fix and the
192
+ `risk_scoring.py` request-parameter fix — both were real bugs in this
193
+ repo (a hyphenated `packages/legal-ai` directory that the code imports as
194
+ `packages.legal_ai`, and a rate-limiter/parameter-name collision on
195
+ `/api/v1/risk/score`) that this CLI's own end-to-end testing surfaced and
196
+ this same change fixed. A plain 401 means your cached token expired and
197
+ couldn't refresh — run `fpp login` again.
198
+
199
+ **Does `fpp escalation advance` actually send the escalation email or move the invoice to the next stage?**
200
+ No. It calls the backend's `/api/v1/escalations/{id}/draft` endpoint,
201
+ which only returns an AI-drafted preview of what the next stage's email
202
+ would say. The backend has no endpoint today that persists a stage change
203
+ or sends the email — see "A note on `escalation advance`" above.
204
+
205
+ **Can I point this at a self-hosted or non-default backend?**
206
+ Yes. Set `FPP_API_URL` to your backend's base URL (default is
207
+ `http://localhost:8000`, matching the FastAPI dev server's default port).
208
+ Every command reads that variable at call time, so switching environments
209
+ is just re-exporting it.
210
+
211
+ **What's the licensing situation — can I use or modify this commercially?**
212
+ This CLI ships from the same repository as, and under the same license
213
+ as, freelancer-payment-protection itself: a proprietary license, copyright
214
+ Rudrendu Paul and Sourav Nandy, all rights reserved. Personal, academic,
215
+ commercial, or scheduled use requires explicit written permission from
216
+ both owners — see the `LICENSE` file. This is not an MIT/Apache-style
217
+ open-source license; publishing it to PyPI makes it installable, not
218
+ freely reusable.
219
+
220
+ **Why isn't there a hosted/default API URL I can just start using?**
221
+ freelancer-payment-protection is self-hosted software, not a hosted
222
+ multi-tenant SaaS with a public API endpoint today. You (or whoever
223
+ operates your workspace) runs the backend; the CLI just needs its URL.
224
+
225
+ ## Development
226
+
227
+ ```bash
228
+ cd packages/cli
229
+ python -m venv .venv && source .venv/bin/activate
230
+ pip install -e ".[dev]"
231
+ pytest
232
+ ```
233
+
234
+ All HTTP calls (to Supabase and to the backend API) are mocked in tests
235
+ with `respx` — the test suite makes no live network calls.
236
+
237
+ ## Contributing
238
+
239
+ This package lives inside the freelancer-payment-protection monorepo. See
240
+ the repository root for contribution guidelines.
241
+
242
+ ## License
243
+
244
+ Proprietary — see [`LICENSE`](./LICENSE). Contact the owners (see
245
+ `LICENSE`) before any use beyond installing and running the package as
246
+ published.
@@ -0,0 +1,213 @@
1
+ # freelancer-payment-protection-cli
2
+
3
+ Command-line client for [freelancer-payment-protection](https://github.com/RudrenduPaul/freelancer-payment-protection):
4
+ automated invoice escalation, legal document generation, and client risk
5
+ scoring for freelancers. This package wraps the project's FastAPI backend
6
+ (`apps/api/app/routers/*.py`) so the same clients, invoices, escalations,
7
+ and risk-scoring data you'd otherwise reach through the dashboard or the
8
+ raw HTTP API is scriptable from a terminal or an agent.
9
+
10
+ ![Login and first command](../../docs/demo.gif)
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pip install freelancer-payment-protection-cli
16
+ ```
17
+
18
+ Or with [uv](https://docs.astral.sh/uv/) / [pipx](https://pipx.pypa.io/):
19
+
20
+ ```bash
21
+ uvx freelancer-payment-protection-cli --help
22
+ pipx install freelancer-payment-protection-cli
23
+ ```
24
+
25
+ Requires Python 3.10+. The console command is installed as both `fpp`
26
+ (short form) and `freelancer-payment-protection` (full form) — they are the
27
+ same entry point.
28
+
29
+ ## Configuration
30
+
31
+ The CLI needs to know two things: which backend API to talk to, and which
32
+ Supabase project issues your login tokens.
33
+
34
+ | Variable | Purpose | Default |
35
+ |---|---|---|
36
+ | `FPP_API_URL` | Backend API base URL | `http://localhost:8000` |
37
+ | `FPP_SUPABASE_URL` (or `SUPABASE_URL`) | Your Supabase project URL | none, required for `login` |
38
+ | `FPP_SUPABASE_ANON_KEY` (or `SUPABASE_ANON_KEY`) | Your Supabase project's anon key | none, required for `login` |
39
+
40
+ The anon key is the same public key the web app's Supabase client uses —
41
+ it is not a secret, and it's the key already in `apps/web/.env.example` as
42
+ `NEXT_PUBLIC_SUPABASE_ANON_KEY`.
43
+
44
+ ## Login and authentication
45
+
46
+ ```bash
47
+ export FPP_SUPABASE_URL="https://your-project.supabase.co"
48
+ export FPP_SUPABASE_ANON_KEY="your-anon-key"
49
+ fpp login
50
+ ```
51
+
52
+ `fpp login` prompts for your email and password, then calls Supabase's own
53
+ REST auth endpoint directly:
54
+
55
+ ```
56
+ POST {SUPABASE_URL}/auth/v1/token?grant_type=password
57
+ Header: apikey: <anon key>
58
+ Body: {"email": ..., "password": ...}
59
+ ```
60
+
61
+ This is the same call the web dashboard's Supabase client makes — the CLI
62
+ never talks to a login endpoint of its own, because the backend
63
+ (`apps/api/app/middleware/auth.py`) doesn't mint tokens; it only validates
64
+ Supabase-issued JWTs. On success, the returned `access_token` and
65
+ `refresh_token` are cached to `~/.config/freelancer-payment-protection-cli/credentials.json`
66
+ (mode 600). Every later command reads the JWT's `workspace_id` claim the
67
+ same way `get_current_workspace()` does server-side, and transparently
68
+ refreshes the access token with the cached refresh token once it expires.
69
+
70
+ Run `fpp logout` to delete the cached credentials, or `fpp whoami` to see
71
+ which workspace and email the cached token resolves to.
72
+
73
+ ## Commands
74
+
75
+ Every data-returning command supports `--json` for scripting and agent use.
76
+
77
+ ```
78
+ fpp login Log in (prompts for email/password)
79
+ fpp logout Remove cached credentials
80
+ fpp whoami [--json] Show cached workspace/session info
81
+
82
+ fpp invoice list [--status] [--client-id] [--page] [--page-size] [--json]
83
+ fpp invoice create --client-id --invoice-number --amount --due-date [...] [--json]
84
+ fpp invoice show <invoice-id> [--json]
85
+ fpp invoice set-status <invoice-id> <status> [--json]
86
+
87
+ fpp escalation list [--json] Active escalations, grouped by stage
88
+ fpp escalation status <invoice-id> [--json] Current stage + full history
89
+ fpp escalation advance <invoice-id> [--json] AI-draft the next stage's email
90
+
91
+ fpp client list [--risk-level] [--search] [--page] [--page-size] [--json]
92
+ fpp client show <client-id> [--json]
93
+ fpp client risk <client-id> [--json] Compute/refresh the AI risk score
94
+ ```
95
+
96
+ Run `fpp --help` or `fpp <command> --help` for full flag references.
97
+
98
+ ![Filtering invoices, scoring a client, and checking escalation status](../../docs/usage.gif)
99
+
100
+ ### A note on `escalation advance`
101
+
102
+ The backend's escalation router (`apps/api/app/routers/escalations.py`)
103
+ exposes exactly three routes: list active escalations, draft the next
104
+ stage's email, and read history. There is no route that persists a stage
105
+ change — `draft_escalation_email` in `escalation_service.py` computes and
106
+ returns what the next stage's email would say, but never writes
107
+ `escalation_stage` back to the database. `fpp escalation advance` calls
108
+ that draft endpoint and shows you the preview; it does not claim to move
109
+ the invoice to the next stage, because the API it wraps doesn't do that
110
+ either.
111
+
112
+ ### JSON output for agents/scripts
113
+
114
+ ```bash
115
+ fpp invoice list --status overdue --json | jq '.[] | {id, invoiceNumber, daysPastDue}'
116
+ fpp client risk "$CLIENT_ID" --json | jq '.level'
117
+ ```
118
+
119
+ Field names in `--json` output match the backend's actual Pydantic response
120
+ models exactly (camelCase, e.g. `invoiceNumber`, `daysPastDue`,
121
+ `escalationStage`) since the CLI passes the API's response straight
122
+ through rather than remapping it.
123
+
124
+ ## FAQ
125
+
126
+ **What is this, and how is it different from just calling the API with curl?**
127
+ It's a typed command-line wrapper around the same backend the web
128
+ dashboard uses — invoices, escalations, and client risk scoring — with
129
+ persistent login (so you're not re-attaching a bearer token to every
130
+ request), human-readable tables by default, and a `--json` flag on every
131
+ data command for piping into `jq`, scripts, or an agent's tool-calling
132
+ loop. The differentiator versus curl is session handling (login once,
133
+ silent token refresh after) and consistent, documented output shapes
134
+ instead of hand-rolled request construction.
135
+
136
+ **What platforms and Python versions does it support?**
137
+ Python 3.10 through 3.13, on any OS `pip`/`uvx`/`pipx` runs on (Linux,
138
+ macOS, Windows). It has no compiled dependencies — the only runtime
139
+ dependencies are `click` and `httpx`, both pure-Python-installable wheels.
140
+
141
+ **How do I log in, and where are my credentials stored?**
142
+ Run `fpp login`, enter your email and password when prompted. The CLI
143
+ calls Supabase's password-grant token endpoint directly (see "Login and
144
+ authentication" above) and caches the resulting access and refresh tokens
145
+ to `~/.config/freelancer-payment-protection-cli/credentials.json` with
146
+ file mode 600 (owner read/write only). Nothing is sent anywhere except
147
+ Supabase's own auth endpoint and the backend API you configure via
148
+ `FPP_API_URL`.
149
+
150
+ **I ran a command and got `Error: Internal Server Error` — is that a CLI bug?**
151
+ Usually not. The CLI's error handling surfaces whatever the backend
152
+ returned; a 500 means the backend itself failed. Two real, backend-side
153
+ causes to check first: (1) `fpp client risk` and `fpp escalation advance`
154
+ both trigger AI calls through `packages/legal_ai/client.py` — if
155
+ `ANTHROPIC_API_KEY` isn't a real key on the server, `client risk` falls
156
+ back to a heuristic score automatically, but `escalation advance` has no
157
+ such fallback and will 500. (2) Confirm you're running a backend build
158
+ that includes the `packages/legal_ai` module-name fix and the
159
+ `risk_scoring.py` request-parameter fix — both were real bugs in this
160
+ repo (a hyphenated `packages/legal-ai` directory that the code imports as
161
+ `packages.legal_ai`, and a rate-limiter/parameter-name collision on
162
+ `/api/v1/risk/score`) that this CLI's own end-to-end testing surfaced and
163
+ this same change fixed. A plain 401 means your cached token expired and
164
+ couldn't refresh — run `fpp login` again.
165
+
166
+ **Does `fpp escalation advance` actually send the escalation email or move the invoice to the next stage?**
167
+ No. It calls the backend's `/api/v1/escalations/{id}/draft` endpoint,
168
+ which only returns an AI-drafted preview of what the next stage's email
169
+ would say. The backend has no endpoint today that persists a stage change
170
+ or sends the email — see "A note on `escalation advance`" above.
171
+
172
+ **Can I point this at a self-hosted or non-default backend?**
173
+ Yes. Set `FPP_API_URL` to your backend's base URL (default is
174
+ `http://localhost:8000`, matching the FastAPI dev server's default port).
175
+ Every command reads that variable at call time, so switching environments
176
+ is just re-exporting it.
177
+
178
+ **What's the licensing situation — can I use or modify this commercially?**
179
+ This CLI ships from the same repository as, and under the same license
180
+ as, freelancer-payment-protection itself: a proprietary license, copyright
181
+ Rudrendu Paul and Sourav Nandy, all rights reserved. Personal, academic,
182
+ commercial, or scheduled use requires explicit written permission from
183
+ both owners — see the `LICENSE` file. This is not an MIT/Apache-style
184
+ open-source license; publishing it to PyPI makes it installable, not
185
+ freely reusable.
186
+
187
+ **Why isn't there a hosted/default API URL I can just start using?**
188
+ freelancer-payment-protection is self-hosted software, not a hosted
189
+ multi-tenant SaaS with a public API endpoint today. You (or whoever
190
+ operates your workspace) runs the backend; the CLI just needs its URL.
191
+
192
+ ## Development
193
+
194
+ ```bash
195
+ cd packages/cli
196
+ python -m venv .venv && source .venv/bin/activate
197
+ pip install -e ".[dev]"
198
+ pytest
199
+ ```
200
+
201
+ All HTTP calls (to Supabase and to the backend API) are mocked in tests
202
+ with `respx` — the test suite makes no live network calls.
203
+
204
+ ## Contributing
205
+
206
+ This package lives inside the freelancer-payment-protection monorepo. See
207
+ the repository root for contribution guidelines.
208
+
209
+ ## License
210
+
211
+ Proprietary — see [`LICENSE`](./LICENSE). Contact the owners (see
212
+ `LICENSE`) before any use beyond installing and running the package as
213
+ published.
@@ -0,0 +1,71 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "freelancer-payment-protection-cli"
7
+ version = "0.1.0"
8
+ description = "Command-line client for freelancer-payment-protection: automated invoice escalation, legal document generation, and client risk scoring for freelancers."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "Proprietary" }
12
+ authors = [
13
+ { name = "Rudrendu Paul" },
14
+ { name = "Sourav Nandy" },
15
+ ]
16
+ keywords = ["invoicing", "freelance", "cli", "invoice-escalation", "risk-scoring", "agent-native", "supabase", "fastapi"]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Environment :: Console",
20
+ "Intended Audience :: Developers",
21
+ "Operating System :: OS Independent",
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 :: Financial :: Accounting",
28
+ "Topic :: Utilities",
29
+ ]
30
+ dependencies = [
31
+ "click>=8.1,<9",
32
+ "httpx>=0.27,<1",
33
+ ]
34
+
35
+ [project.optional-dependencies]
36
+ dev = [
37
+ "pytest>=8.0,<9",
38
+ "pytest-cov>=5.0,<7",
39
+ "respx>=0.21,<1",
40
+ "build>=1.0,<2",
41
+ "twine>=5.0,<7",
42
+ ]
43
+
44
+ [project.urls]
45
+ Homepage = "https://github.com/RudrenduPaul/freelancer-payment-protection"
46
+ Repository = "https://github.com/RudrenduPaul/freelancer-payment-protection"
47
+ "Bug Tracker" = "https://github.com/RudrenduPaul/freelancer-payment-protection/issues"
48
+
49
+ [project.scripts]
50
+ fpp = "freelancer_payment_protection_cli.main:main"
51
+ freelancer-payment-protection = "freelancer_payment_protection_cli.main:main"
52
+
53
+ [tool.hatch.build]
54
+ # This package lives in a subdirectory (packages/cli/) of a larger
55
+ # monorepo whose .git directory is at the repo root, alongside Node/
56
+ # Turborepo config that has nothing to do with this Python package.
57
+ ignore-vcs = true
58
+
59
+ [tool.hatch.build.targets.wheel]
60
+ packages = ["src/freelancer_payment_protection_cli"]
61
+
62
+ [tool.hatch.build.targets.sdist]
63
+ only-include = [
64
+ "src/freelancer_payment_protection_cli",
65
+ "tests",
66
+ "README.md",
67
+ "LICENSE",
68
+ ]
69
+
70
+ [tool.pytest.ini_options]
71
+ testpaths = ["tests"]
@@ -0,0 +1,6 @@
1
+ """freelancer-payment-protection-cli — command-line client for the
2
+ freelancer-payment-protection API (invoice escalation, legal document
3
+ generation, and client risk scoring for freelancers).
4
+ """
5
+
6
+ __version__ = "0.1.0"