Metadata-Version: 2.4
Name: morning-cli
Version: 0.2.0
Summary: Agent-native CLI for the morning invoicing REST API (API v2) — OAuth 2.0 auth, JSON envelopes, sandbox-first, built by JangoAI.
Home-page: https://github.com/jango-ai-com/morning-cli
Author: JangoAI
Author-email: hello@jango-ai.com
License: MIT
Project-URL: Homepage, https://jango-ai.com
Project-URL: Source, https://github.com/jango-ai-com/morning-cli
Project-URL: Tracker, https://github.com/jango-ai-com/morning-cli/issues
Project-URL: morning API docs, https://developers.morning.co
Keywords: morning,green-invoice,greeninvoice,invoicing,israel,rest-api,cli,agent,cli-anything,jangoai
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: Hebrew
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial :: Accounting
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.1
Requires-Dist: httpx>=0.27
Requires-Dist: prompt-toolkit>=3.0
Requires-Dist: rich>=13.0
Provides-Extra: test
Requires-Dist: pytest>=7; extra == "test"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: project-url
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

<p align="center">
  <img src="https://capsule-render.vercel.app/api?type=waving&color=0:2563eb,50:7c3aed,100:06b6d4&height=220&section=header&text=morning-cli&fontSize=70&fontColor=ffffff&animation=fadeIn&fontAlignY=35&desc=Agent-native%20CLI%20for%20the%20morning%20invoicing%20API&descSize=18&descAlignY=55&descAlign=50" alt="morning-cli banner" width="100%"/>
</p>

<p align="center">
  <a href="https://pypi.org/project/morning-cli/"><img src="https://img.shields.io/pypi/v/morning-cli?style=for-the-badge&logo=pypi&logoColor=white&label=PyPI&color=3775A9" alt="PyPI version"/></a>
  <a href="https://pypi.org/project/morning-cli/"><img src="https://img.shields.io/pypi/pyversions/morning-cli?style=for-the-badge&logo=python&logoColor=white&color=3776AB" alt="Python versions"/></a>
  <a href="https://github.com/Jango-AI-com/morning-cli/actions"><img src="https://img.shields.io/github/actions/workflow/status/Jango-AI-com/morning-cli/ci.yml?style=for-the-badge&logo=github-actions&logoColor=white&label=CI" alt="CI status"/></a>
  <a href="https://github.com/Jango-AI-com/morning-cli/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Jango-AI-com/morning-cli?style=for-the-badge&color=22c55e" alt="License"/></a>
  <a href="https://pypi.org/project/morning-cli/"><img src="https://img.shields.io/pypi/dm/morning-cli?style=for-the-badge&logo=pypi&logoColor=white&color=blueviolet&label=downloads" alt="Downloads"/></a>
</p>

<p align="center">
  <b>morning API v2</b> &nbsp;|&nbsp; <b>OAuth 2.0 auth</b> &nbsp;|&nbsp; <b>Interactive REPL</b> &nbsp;|&nbsp; <b>Onboarding wizard</b> &nbsp;|&nbsp; <b>JSON envelopes for AI agents</b> &nbsp;|&nbsp; <b>Hebrew error messages</b>
</p>

<p align="center">
  <sub>Built by <a href="https://jango-ai.com"><b>JangoAI</b></a> using the <a href="https://github.com/HKUDS/CLI-Anything">cli-anything</a> methodology &nbsp;|&nbsp; <a href="https://github.com/Jango-AI-com/morning-cli/blob/main/README.he.md">README בעברית</a></sub>
</p>

---

## Why this exists

I'm Maor, a solo developer running [JangoAI](https://jango-ai.com) — a small AI automation studio in Israel. I use morning's API daily for my own business and my clients', and I got tired of writing the same `httpx` + JWT boilerplate in every project. So I built a proper CLI around it.

This started as a personal tool, but there's no reason to keep it private — if you work with morning's API, you'll save time with this. I'm sharing it with the Israeli dev community because I think we deserve better tooling for our local platforms. If it helps you, I'd love to hear about it.

> **v0.2.0 — API v2 ready.** morning rewrote their developer docs at
> [developers.morning.co](https://developers.morning.co) (OpenAPI 2.0.0): OAuth 2.0
> token endpoint on dedicated IDP hosts, a new presigned-S3 expense upload flow,
> Basic-auth partners endpoints, and reference data staying on the shared cache
> host. This release tracks all of it, with automatic fallback to the legacy
> token endpoint where the new IDP isn't deployed. See the [CHANGELOG](https://github.com/Jango-AI-com/morning-cli/blob/main/CHANGELOG.md).

---

## Install

```bash
pip install morning-cli
```

## Get started in 30 seconds

```bash
# 1. Run the interactive wizard — connects your morning account
morning-cli auth init

# 2. Start the REPL
morning-cli

# 3. Or use one-shot commands
morning-cli --json auth whoami
morning-cli --json document types --lang he
morning-cli --json client search
```

<details>
<summary><b>What does <code>auth init</code> look like?</b></summary>

```
  ╭──────────────────────────────────────────────────╮
  │       morning-cli                                │
  │       setup wizard                               │
  │                                                  │
  │       Connect your morning account.              │
  │       You'll be up and running in under a minute.│
  ╰──────────────────────────────────────────────────╯

  >>  Step 1/4  Choose environment
  ╭──────────────────────────────────────────────────╮
  │ Where do you want to connect?                    │
  │   [1]  sandbox      Safe testing, no real money  │
  │   [2]  production   Live business data           │
  ╰──────────────────────────────────────────────────╯
  Enter 1 or 2 [1]:

  OK  Step 1/4  Choose environment
  >>  Step 2/4  Get your API keys
  ╭─ Open in browser ────────────────────────────────╮
  │ https://app.greeninvoice.co.il/settings/developers/api
  │ Settings > Advanced > Developers > Create API Key│
  ╰──────────────────────────────────────────────────╯

  >>  Step 3/4  Enter credentials
    API Key ID:     xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    API Key Secret: (hidden as you type)

  >>  Step 4/4  Verify connection
  Connecting to morning API...

  ╭─ All set ────────────────────────────────────────╮
  │  Connected successfully!                         │
  │  Business   Your Business Name                   │
  │  Env        SANDBOX                              │
  │  Saved to   ~/.greeninvoice/credentials.json     │
  ╰──────────────────────────────────────────────────╯
```

</details>

---

## Commands

<table>
<tr>
<th>Group</th>
<th>Endpoints</th>
<th>Highlights</th>
</tr>
<tr><td><b>auth</b></td><td>local</td><td><code>init</code> (wizard), <code>login</code>, <code>logout</code>, <code>whoami</code>, <code>refresh</code></td></tr>
<tr><td><b>session</b></td><td>local</td><td><code>show</code>, <code>reset</code>, <code>history</code></td></tr>
<tr><td><b>business</b></td><td>10 (legacy)</td><td><code>list</code>, <code>current</code>, <code>get</code>, <code>update</code>, numbering, footer, types, file-upload — removed from the v2 docs, still served</td></tr>
<tr><td><b>client</b></td><td>8</td><td><code>add</code>, <code>get</code>, <code>update</code>, <code>delete</code>, <code>search</code>, <code>assoc</code>, <code>merge</code>, <code>balance</code></td></tr>
<tr><td><b>supplier</b></td><td>6</td><td><code>add</code>, <code>get</code>, <code>update</code>, <code>delete</code>, <code>search</code>, <code>merge</code></td></tr>
<tr><td><b>item</b></td><td>5</td><td><code>add</code>, <code>get</code>, <code>update</code>, <code>delete</code>, <code>search</code></td></tr>
<tr><td><b>document</b></td><td>13</td><td><code>create</code>, <code>preview</code>, <code>get</code>, <code>search</code>, <code>close</code>, <code>open</code>, <code>download</code>, types, statuses</td></tr>
<tr><td><b>expense</b></td><td>13</td><td>CRUD + <code>open</code>/<code>close</code> + <code>upload</code> (presigned-S3 flow) + <code>drafts-search</code>/<code>draft-delete</code></td></tr>
<tr><td><b>payment</b></td><td>3</td><td><code>form</code>, <code>tokens-search</code>, <code>charge</code></td></tr>
<tr><td><b>partner</b></td><td>3</td><td><code>users</code>, <code>connect</code>, <code>disconnect</code> (HTTP Basic)</td></tr>
<tr><td><b>tools</b></td><td>4</td><td><code>occupations</code>, <code>countries</code>, <code>cities</code>, <code>currencies</code> — shared cache host, no auth</td></tr>
</table>

---

## Usage examples

### Create a proforma invoice (חשבון עסקה)

```bash
cat > /tmp/proforma.json <<'JSON'
{
  "description": "ריטיינר חודשי",
  "type": 300,
  "lang": "he",
  "currency": "ILS",
  "vatType": 0,
  "client": {"name": "Acme Ltd", "emails": ["ap@acme.com"], "country": "IL"},
  "income": [
    {"description": "שירותי ייעוץ", "quantity": 10, "price": 300, "currency": "ILS", "vatType": 0}
  ]
}
JSON
morning-cli --json document create --file /tmp/proforma.json
```

### Search recent clients

```bash
morning-cli --json client search --data '{"page":1,"pageSize":10}'
```

### Get PDF download link for a document

```bash
morning-cli --json document download <document_id>
```

### Upload an expense receipt (API v2 presigned-S3 flow)

```bash
morning-cli --json expense upload receipt.pdf          # new expense draft
morning-cli --json expense upload receipt.pdf --id <expense_id>   # attach to expense
morning-cli --json expense drafts-search               # parsed draft appears here
```

---

## JSON output for AI agents

Every `--json` command returns a consistent envelope:

```json
{"ok": true, "op": "document.create", "data": {"id": "...", "number": 12345}}
```

Errors include the morning `errorCode` and Hebrew `errorMessage`:

```json
{"ok": false, "op": "document.create", "error": {"code": 1110, "message": "מחיר לא תקין.", "http_status": 400}}
```

| Exit code | Meaning |
|---|---|
| `0` | Success |
| `1` | Unexpected internal error / aborted confirmation |
| `2` | Usage error, local config error (e.g. missing credentials), or API error (4xx) |
| `3` | Server error (5xx) / network failure |

Success envelopes go to **stdout**; error envelopes go to **stderr** (agents:
capture both streams).

<details>
<summary><b>Common morning API error codes</b></summary>

| Code | Meaning |
|---|---|
| `401` | Token expired (CLI auto-refreshes) |
| `1003` | No active business in the account |
| `1006` | Subscription expired |
| `1007` | Missing permission |
| `1012` | Feature requires a higher plan |
| `1110` | Invalid price in a line item |
| `2002` | Wrong email or password |
| `2102` | Can't add more businesses on this plan |
| `2403` | Document type not supported for this business type |

</details>

---

## Environment variables

| Variable | Purpose | Default |
|---|---|---|
| `MORNING_API_KEY_ID` | API key ID | — |
| `MORNING_API_KEY_SECRET` | API key secret | — |
| `MORNING_ENV` | `sandbox` or `production` | `sandbox` |
| `MORNING_BASE_URL` | Override the core REST base URL | auto |
| `MORNING_GATEWAY_URL` | Override the OAuth IDP + file-upload hosts (proxies/custom deploys) | auto |
| `MORNING_AUTH_MODE` | `auto` (OAuth with legacy fallback), `oauth` (no fallback), `legacy` (skip IDP) | `auto` |

**How auth works (v0.2.0+):** the CLI obtains a 1-hour access token via OAuth 2.0
`client_credentials` from the morning IDP (`POST /idp/v1/oauth/token` on
`api.morning.co` / `api.sandbox.morning.dev`), and falls back to the legacy
`POST /account/token` automatically if the IDP isn't available for your
environment. Refresh on 401 is automatic either way. Reference data (`tools`
group) is served from the shared `cache.greeninvoice.co.il` host, no auth needed.

---

<details>
<summary><b>Tests</b> — 85 tests, including 23 live E2E (sandbox or production via <code>MORNING_E2E_ENV</code>)</summary>

```bash
pip install -e ".[test]"

# Unit tests — no network
pytest cli_anything/greeninvoice/tests/test_core.py -v

# Full suite with live sandbox
export MORNING_SANDBOX_ID=<your-id>
export MORNING_SANDBOX_SECRET=<your-secret>
CLI_ANYTHING_FORCE_INSTALLED=1 pytest cli_anything/greeninvoice/tests/ -v
```

**Coverage:**
- 52 unit tests — credentials + per-service host resolution, OAuth token
  acquisition (camelCase/snake_case shapes, legacy fallback, unreachable-host
  fallback, TLS errors surfaced, no-fallback on bad keys, `MORNING_AUTH_MODE`
  overrides, RFC 6749 error strings), wizard verification (gateway override,
  core-API rejection propagates), Basic-auth partners, presigned-S3 upload
  flow (field ordering, no-auth on S3), session locking, payload parsing
- 10 offline E2E — help, version, error envelopes, `--json auth init` stream purity, REPL smoke, env-var CI path
- 23 live sandbox E2E — read-only smoke per resource group, paginated
  searches, item/supplier mutation round-trips, invoice lifecycle, proforma
  preview with Hebrew content, expense file upload
- **3 real bugs caught** during development (late-binding, type 305 gate, Tools host/locale)

</details>

<details>
<summary><b>For AI agents</b> — SKILL.md auto-discovery</summary>

`morning-cli` ships a [SKILL.md](https://github.com/Jango-AI-com/morning-cli/blob/main/cli_anything/greeninvoice/skills/SKILL.md) file
auto-discovered by the REPL banner and Claude Code / Cursor. It contains:

- Full command reference with examples
- Error code table
- Agent-specific guidance (always use `--json`, sandbox defaults, token refresh)
- Non-interactive `auth init` for CI

If you're an agent reading this, start with the SKILL.md.

</details>

<details>
<summary><b>Methodology</b> — cli-anything 7-phase SOP</summary>

Built following the [cli-anything](https://github.com/HKUDS/CLI-Anything) 7-phase pipeline:

1. **Codebase analysis** — parsed the Apiary spec into a 66-endpoint map
2. **Architecture** — REPL-first, `--json` envelopes, session locking, sandbox-first
3. **Implementation** — PEP 420 namespace package `cli_anything.greeninvoice`
4. **Test planning** — TEST.md written before tests
5. **Test implementation** — unit + live E2E
6. **Test documentation** — results appended to TEST.md
7. **PyPI publishing** — `pip install morning-cli`

Full SOP: [GREENINVOICE.md](https://github.com/Jango-AI-com/morning-cli/blob/main/GREENINVOICE.md)

</details>

---

## Contributing

PRs welcome! Run the tests before submitting:

```bash
pip install -e ".[test]"
pytest cli_anything/greeninvoice/tests/test_core.py -v
```

See [open issues](https://github.com/Jango-AI-com/morning-cli/issues) for good first contributions.

---

<div align="center">

**[JangoAI](https://jango-ai.com)** — AI automation for Israeli businesses

[Website](https://jango-ai.com) · [GitHub](https://github.com/Jango-AI-com) · [morning API docs](https://developers.morning.co)

<sub>MIT License · morning-cli is a community project and is not officially affiliated with morning Ltd.</sub>

</div>

<p align="center">
  <img src="https://capsule-render.vercel.app/api?type=waving&color=0:2563eb,50:7c3aed,100:06b6d4&height=100&section=footer" alt="" width="100%"/>
</p>
