Metadata-Version: 2.4
Name: nlp2uri
Version: 0.1.2
Summary: Natural language to URI resolution and cross-platform local URI execution
Author: Semcod
Author-email: Tom Sapletta <tom@sapletta.com>
License-Expression: Apache-2.0
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0; extra == "dev"
Requires-Dist: goal>=2.1.0; extra == "dev"
Requires-Dist: costs>=0.1.20; extra == "dev"
Requires-Dist: pfix>=0.1.60; extra == "dev"
Provides-Extra: linux
Requires-Dist: dbus-python>=1.3.2; sys_platform == "linux" and extra == "linux"
Provides-Extra: windows
Requires-Dist: pywin32>=306; sys_platform == "win32" and extra == "windows"
Provides-Extra: full
Requires-Dist: psutil>=6.0; extra == "full"
Dynamic: license-file

# nlp2uri


## AI Cost Tracking

![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.1.2-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
![AI Cost](https://img.shields.io/badge/AI%20Cost-$0.49-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-2.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)

- 🤖 **LLM usage:** $0.4934 (1 commits)
- 👤 **Human dev:** ~$200 (2.0h @ $100/h, 30min dedup)

Generated on 2026-06-06 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)

---

Python library and CLI — **kompilator NL → URI → akcje OS** dla operacji desktopowych.

Wejście (naturalny język):

- „otwórz VS Code w folderze ~/projekty/nlp2uri”
- „zrób screenshot aktywnego okna przeglądarki”
- „otwórz plik invoice-2025.pdf”

Wyjście:

1. **Abstrakcyjny URI** (RFC 3986, niezależny od OS)
2. **Plan akcji** `OSAction[]` — konkretne komendy per platforma
3. (Opcjonalnie) wykonanie lub payload MCP (`text/uri-list`)

## Architektura

```mermaid
flowchart LR
    NL[Natural language] --> PARSE[parse_nl]
    PARSE --> INTENT[UriIntent + slots]
    INTENT --> BUILD[schemes/build]
    BUILD --> SPEC[UriSpec abstract URI]
    SPEC --> COMPILE[compile_uri_to_actions]
    COMPILE --> ACTIONS[OSAction plan]
    ACTIONS --> EXEC[execute_uri / MCP]
```

### Warstwy

| Warstwa | Moduł | Opis |
|---------|-------|------|
| NLP → intencja | `parse_nl` | Heurystyki EN + PL → `UriIntent` |
| Intencja → URI | `schemes/*` | Abstrakcyjne schemy OS-neutral |
| URI → OS | `compile` | `compile_uri_to_actions()` |
| Wykonanie | `runtime` | `subprocess` / dry-run |
| MCP | `mcp` | `text/uri-list`, tool payloads |

## Abstrakcyjne schemy URI

| Scheme | Przykład | Znaczenie |
|--------|----------|-----------|
| `app://` | `app://vscode/open?path=/home/tom/...` | Otwórz aplikację / IDE |
| `app://file/open` | `app://file/open?path=/tmp/x.pdf` | Otwórz plik |
| `desktop-screenshot://` | `desktop-screenshot://window?title=Chrome&mode=active` | Screenshot okna/ekranu |
| `desktop-window://` | `desktop-window://focus?name=slack` | Fokus okna |
| natywne | `vscode://`, `cursor://`, `file://`, `ms-settings:` | Passthrough do handlera OS |

Metadata `native_uri` zawiera deep-link IDE (`vscode://file/...`) gdy istnieje.

## Konfiguracja (`nlp2uri.yaml`)

Domyślne ustawienia w pliku `nlp2uri.yaml` (auto-tworzony przy pierwszym uruchomieniu):

```yaml
platform: auto          # auto | linux | darwin | windows
host_platform: linux  # ostatnio wykryty host (informacyjnie)
locale: null
dry_run: false
capture_dir: /tmp/nlp2uri-captures
```

Kolejność wyboru platformy: `--platform` → `NLP2URI_PLATFORM` → `nlp2uri.yaml` → auto-detect OS.

```bash
nlp2uri config show --json    # efektywna konfiguracja
nlp2uri config init           # zapisz domyślny nlp2uri.yaml
```

Ścieżki szukania configu: `NLP2URI_CONFIG` → `./nlp2uri.yaml` → `~/.config/nlp2uri/nlp2uri.yaml`.

## Quick start

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

# Platforma wykrywana automatycznie (bez --platform)
nlp2uri plan "otwórz vscode w folderze ~/github/semcod/nlp2uri" --json
nlp2uri resolve "zrób screenshot aktywnego okna przeglądarki" --json
nlp2uri execute "open firefox" --dry-run
```

## Python API (service facade)

```python
from nlp2uri import NLP2URIService
from nlp2uri.models import HostPlatform

svc = NLP2URIService.default()  # ładuje nlp2uri.yaml + auto-detect

plan = svc.from_prompt("otwórz vscode w folderze /tmp/foo")
print(plan.uri)                    # app://vscode/open?path=/tmp/foo
print(plan.actions[0].argv())      # ['xdg-open', 'vscode://file/tmp/foo']

payload = svc.handle_prompt("open firefox", dry_run=True)  # prompt → URI → run
```

## Adaptery i integratory (reużywalne powierzchnie)

| Warstwa | Użycie | Moduł |
|---------|--------|-------|
| **Service** | `NLP2URIService.from_prompt()` / `handle_uri()` | `nlp2uri.service` |
| **CLI** | `nlp2uri plan\|resolve\|compile\|execute` | `nlp2uri.adapters.cli` |
| **Shell** | `eval "$(nlp2uri shell export '…')"` | `nlp2uri.adapters.shell` |
| **REST** | `nlp2uri-serve --port 8766` | `nlp2uri.integrators.rest_server` |
| **MCP** | `nlp2uri-mcp` (stdio JSON-RPC) | `nlp2uri.integrators.mcp_server` |

### REST (`POST /v1/plan`)

```bash
curl -s -X POST http://127.0.0.1:8766/v1/plan \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"open firefox"}'
```

### MCP (Cursor / Windsurf)

```json
{ "mcpServers": { "nlp2uri": { "command": "nlp2uri-mcp" } } }
```

Tools: `nlp2uri_plan`, `nlp2uri_resolve`, `nlp2uri_compile`, `nlp2uri_execute`, `nlp2uri_handle`.

### Shell

```bash
eval "$(nlp2uri shell export 'open firefox')"
echo "$NLP2URI_URI"    # app://firefox/open
$nlp2uri-run           # alias do skompilowanej komendy
```

### Własny adapter

```python
from nlp2uri.adapters.base import AdapterRequest
from nlp2uri.adapters.rest import RestAdapter

response = RestAdapter().dispatch("plan", {"prompt": "capture screen", "platform": "linux"})
print(response.data["uri"])
```

## Standardy

| Standard | Rola |
|----------|------|
| [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) | Składnia URI (`scheme`, `path`, `query`) |
| [RFC 8089](https://www.rfc-editor.org/rfc/rfc8089) | `file://` |
| [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110) | `http(s)://` |
| [Freedesktop Desktop Entry](https://specifications.freedesktop.org/desktop-entry-spec/latest/) | `.desktop`, `x-scheme-handler/<scheme>` |
| [XDG Desktop Portal](https://flatpak.github.io/xdg-desktop-portal/) | Screenshot Wayland |
| Windows URI activation | `ms-settings:`, rejestracja schemów |
| macOS URL Schemes | `CFBundleURLSchemes` w `Info.plist` |
| MCP `text/uri-list` | Lista URI dla hosta / MCP Apps |

## Przydatne biblioteki

| Biblioteka | Kiedy |
|------------|-------|
| `urllib.parse`, `webbrowser`, `subprocess` | Już używane (stdlib) |
| `psutil` | PID → okno |
| `pyxdg` | Parsowanie `.desktop` |
| `dbus-python` + PyGObject | XDG Portal screenshot |
| `pywin32` | Win32 `SetForegroundWindow` |
| `pyobjc` / Quartz | macOS window ID |
| `spaCy` / `transformers` | Zamiast heurystyk regex |
| `nlp2dsl` / `nlp2cmd-intent` | IntentIR z LLM (jak `nlpshim`) |

## Testy i Docker

```bash
python -m pytest
docker compose build && docker compose run --rm nlp2uri-test
./examples/run-e2e.sh
```

Przykłady per kategoria: [examples/README.md](examples/README.md).

W Dockerze:

- unit: NLP → URI → `OSAction`
- integracja: rejestracja `testapp://` przez `.desktop` + `xdg-open` (`NLP2URI_INTEGRATION=1`)

## Relacja z ekosystemem Semcod

- **`nlpshim`** — NLP → DSL / workflow
- **`nlp2uri`** — NLP → URI → akcje desktopowe (MCP, screenshot, focus, open app)
- **`koru`** — `portal_capture.py` jako wzorzec dla Wayland screenshot

## License

Licensed under Apache-2.0.
