Metadata-Version: 2.4
Name: invariant-daemon
Version: 0.1.0
Summary: Invariant local daemon for CAD integrations
Project-URL: Homepage, https://github.com/in-variant/invariantd
Project-URL: Repository, https://github.com/in-variant/invariantd
Project-URL: Issues, https://github.com/in-variant/invariantd/issues
Author: Ansh
License-Expression: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
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 :: Scientific/Engineering
Requires-Python: >=3.9
Requires-Dist: fastapi>=0.100.0
Requires-Dist: typer>=0.9.0
Requires-Dist: uvicorn[standard]>=0.22.0
Provides-Extra: ansys
Requires-Dist: ansys-mapdl-core>=0.65.0; extra == 'ansys'
Description-Content-Type: text/markdown

# Invariant

Local daemon for CAD and simulation integrations: **FastAPI** (HTTP + WebSocket), **uvicorn**, **Typer** CLI.

## Install (development)

From the repository root:

```bash
pip install -e .
# optional: live Ansys MAPDL (PyMAPDL)
pip install -e ".[ansys]"
```

## Run

```bash
invariant run
```

Optional flags and environment variables:

- `--host` / `-H` and `--port` / `-p` override bind address and port.
- `INVARIANT_HOST` and `INVARIANT_PORT` set defaults when flags are omitted.
- `--reload` enables auto-reload (development only; uses an import string so it works on Windows, Linux, and macOS).

Examples:

```bash
invariant run --port 8080
set INVARIANT_PORT=8080
invariant run
```

On Windows (cmd):

```cmd
set INVARIANT_PORT=8080
invariant run
```

On Windows (PowerShell):

```powershell
$env:INVARIANT_PORT = 8080
invariant run
```

## API

- `POST /models` — JSON body; returns `{ "modelId": "m-1" }`.
- `POST /models/{model_id}/run` — background job: mock solve if MAPDL is not connected; if live, records a MAPDL snapshot (does not start a new `/SOLU` solve).
- `GET /jobs/{job_id}/result` — `{ "status": "running" }` until complete, then the result payload.
- `GET /health` — `{ "status": "ok" }`.
- `GET /integrations` — `{ "integrations": [ { "id", "status", "label" } ] }` for the Invariant IDE sidebar and `@id` chat mentions (e.g. `@ansys`).
- `GET /integrations/{id}/context` — JSON snapshot for the IDE agent. For `ansys`, see **Ansys (MAPDL)** below.
- `GET /integrations/ansys/status` — live vs mock mode, PyMAPDL version, gRPC target.
- `WebSocket /ws` — sends a hello message; echoes text frames as JSON.

Interactive docs: `http://127.0.0.1:5000/docs` (default).

### Ansys (MAPDL via PyMAPDL)

Install the optional dependency, then start a **Mechanical APDL** session with **gRPC** on the expected port (default **50052**):

```bash
pip install "invariant-daemon[ansys]"
# or: pip install ansys-mapdl-core
```

| Environment variable | Purpose |
| --- | --- |
| `INVARIANT_ANSYS_MODE` | `auto` (default) try live MAPDL then mock, or `mock` to force synthetic data |
| `INVARIANT_MAPDL_HOST` | gRPC host (default `127.0.0.1`; falls back to `PYMAPDL_IP`) |
| `INVARIANT_MAPDL_PORT` | gRPC port (default `50052`; falls back to `PYMAPDL_PORT`) |
| `INVARIANT_MAPDL_TRANSPORT` | PyMAPDL `transport_mode`: default **`insecure`** (TCP gRPC). Use if your environment forces UDS. |
| `INVARIANT_MAPDL_CONNECT_TIMEOUT` | Seconds to wait for gRPC (default `15`) |

At startup, the daemon logs **either** a live connection line **or** a **MOCK mode** warning. `GET /integrations/ansys/context` returns `source: "mapdl_grpc"` with `/STATUS` excerpts, mesh and geometry counts, parameters, optional POST1 summaries, and an `llm_digest` string when MAPDL is connected; otherwise `source: "mock"`.

## Cross-platform notes

- Use **Python 3.9+** from [python.org](https://www.python.org/downloads/) on Windows; enable “Add Python to PATH” in the installer.
- Prefer a **virtual environment** (`python -m venv .venv`) so `pip` and the `invariant` script stay isolated.
- Binding to `127.0.0.1` (default) is appropriate for a local CAD companion; use `0.0.0.0` only if you need other machines on the LAN to reach the daemon (mind firewall rules).

## Install from PyPI

```bash
pip install invariant-daemon
# with Ansys support:
pip install "invariant-daemon[ansys]"
```

## Publishing to PyPI

The package is published as [`invariant-daemon`](https://pypi.org/project/invariant-daemon/) on PyPI.

### One-time setup

1. Create accounts on [PyPI](https://pypi.org/account/register/) and [TestPyPI](https://test.pypi.org/account/register/) if you do not have them.
2. Configure **trusted publishing** (recommended) or store credentials with a tool such as **keyring**; avoid committing tokens.
3. Install build tools: `python -m pip install --upgrade build twine`.

### Build

From the project root:

```bash
python -m build
```

This produces `dist/invariant_daemon-0.1.0-py3-none-any.whl` and `dist/invariant_daemon-0.1.0.tar.gz` (names follow your `version` in `pyproject.toml`).

### Test upload (recommended)

Upload to TestPyPI first:

```bash
python -m twine upload --repository testpypi dist/*
```

Install from TestPyPI in a clean venv:

```bash
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ invariant-daemon
```

(`--extra-index-url` pulls dependencies like FastAPI from the real PyPI.)

### Production upload

```bash
python -m twine upload dist/*
```

### Version bumps

Increase `version` in `pyproject.toml` (and keep `invariant/__init__.py` in sync if you expose `__version__`) for every new release; PyPI rejects duplicate versions.
