Metadata-Version: 2.4
Name: paperang-cli
Version: 0.2.1
Summary: Standalone CLI for Paperang thermal printers
Author: wyrtensi
License-Expression: MIT
Project-URL: Homepage, https://github.com/wyrtensi/paperang-cli
Project-URL: Documentation, https://github.com/wyrtensi/paperang-cli/tree/main/docs
Project-URL: Issues, https://github.com/wyrtensi/paperang-cli/issues
Project-URL: Source, https://github.com/wyrtensi/paperang-cli
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
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: Programming Language :: Python :: 3.14
Classifier: Topic :: System :: Hardware :: Hardware Drivers
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: bleak>=0.22.0
Requires-Dist: click>=8.1.7
Requires-Dist: numpy>=1.26.0
Requires-Dist: Pillow>=10.1.0
Requires-Dist: paperang-p2-lib>=0.4.0rc3
Requires-Dist: scikit-image>=0.20.0
Requires-Dist: scipy>=1.11.0
Requires-Dist: numba>=0.58.0
Requires-Dist: pilkit>=2.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
Requires-Dist: tomli>=2.0.0; python_version < "3.11" and extra == "dev"
Provides-Extra: release
Requires-Dist: build>=1.2.2; extra == "release"
Requires-Dist: twine>=6.0.0; extra == "release"
Dynamic: license-file

# paperang-cli

[![CI](https://img.shields.io/github/actions/workflow/status/wyrtensi/paperang-cli/ci.yml?branch=main&label=CI)](https://github.com/wyrtensi/paperang-cli/actions/workflows/ci.yml)
[![PyPI version](https://img.shields.io/pypi/v/paperang-cli?cacheSeconds=300)](https://pypi.org/project/paperang-cli/)
[![npm version](https://img.shields.io/npm/v/paperang-cli)](https://www.npmjs.com/package/paperang-cli)
[![Python versions](https://img.shields.io/pypi/pyversions/paperang-cli?cacheSeconds=300)](https://pypi.org/project/paperang-cli/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
![Hardware tested on Windows](https://img.shields.io/badge/hardware_tested-Windows-0078D6?logo=windows11&logoColor=white)

`paperang-cli` is a standalone command-line tool and Python package for working with Paperang thermal printers.

It provides a small, script-friendly CLI for discovering a printer, checking its status, and printing text or images with explicit safety gates. JSON output is available for automation and agent-driven workflows.

The package also exposes a model-aware Python API surface. Today that means supported `PaperangP1` and `PaperangP2` facades plus a read-only API catalog for inspecting each shipped model contract.

## Current Support

The current release ships two supported models with different validation levels:

| Printer | Transport | Status |
| --- | --- | --- |
| Paperang P1 | Bluetooth Low Energy (BLE) | Supported |
| Paperang P2 | Bluetooth Low Energy (BLE, FF00/A5) | Supported and physically validated on Windows |
| Paperang P2 | USB | Experimental software path; not physically validated in this repo yet |

Local, cable, and USB data transports are not supported for Paperang P1 in this package.

Real printer communication and physical printing have been tested only on Windows for validated paths. CI runs compatibility checks on Linux and macOS, but those checks do not prove BLE, USB, or printer behavior on those platforms.

## Features

- Discover supported Paperang printers over BLE, or detect a connected P2 over the experimental USB path
- Select named P1/P2 printer profiles with `--printer NAME` from one shared config
- Check battery level, Bluetooth MAC address, and live printer status
- Print short text or wrapped paragraphs
- Print local images with sticker and photo conversion presets
- Configure default print styling through JSON config, including font family and 90-degree text or image orientation
- Compose text and an image into one print job
- Preview every print path with `--dry-run`
- Emit machine-readable JSON with `--json`
- Use explicit allow flags before any paper-consuming operation
- Use the `PaperangP1` and `PaperangP2` Python facades for library-style automation
- Inspect model-specific API availability with `paperang api list`

Image and composed printing are available, but remain experimental until you validate physical output on your printer.

## Installation

Python `3.10` or newer is required.

Install the published package from PyPI:

```powershell
python -m pip install paperang-cli
```

```bash
# macOS / Linux
pip install paperang-cli
```

For local development, clone the repository and install it in editable mode:

```powershell
git clone https://github.com/wyrtensi/paperang-cli.git
Set-Location "paperang-cli"
python -m pip install -e ".[dev]"
python -m pytest
```

```bash
# macOS / Linux
git clone https://github.com/wyrtensi/paperang-cli.git
cd paperang-cli
pip install -e ".[dev]"
python -m pytest
```

The package installs two equivalent commands:

- `paperang`
- `paperang-cli`

Use `paperang` by default. Use `paperang-cli` if the shorter command conflicts with another executable on your system.

An npm wrapper is also maintained under `npm/`. Install it globally with:

```powershell
npm install --global paperang-cli
```

```bash
# macOS / Linux
npm install --global paperang-cli
```

The npm wrapper installs the matching Python package from PyPI and exposes the same two commands. Python `3.10` or newer is still required.

The published dependency set includes the upstream `paperang-p2-lib` runtime for the experimental P2 USB path and for P2 units that expose the upstream NUS BLE profile. P2 units advertising as `Paperang_P2` with the FF00/A5 BLE profile are supported directly by this package.

The npm wrapper uses a `postinstall` lifecycle script to run `pip install` for the matching Python package version. See the [security policy](SECURITY.md#npm-postinstall-behavior) for details and an `--ignore-scripts` audit path.

## Cross-Platform Compatibility

| Printer | Transport | Windows | macOS | Linux |
| --- | --- | --- | --- | --- |
| Paperang P1 | BLE | ✅ Tested (Python 3.14) | ⚠️ Untested (software only) | ⚠️ Untested (software only) |
| Paperang P2 | BLE FF00/A5 | ✅ Tested (Python 3.14) | ⚠️ Untested | ⚠️ Untested |
| Paperang P2 | USB | ⚠️ Experimental software path (libusb/WinUSB) | ⚠️ Untested | ⚠️ Untested |

> **Honest validation:** CI runs on all 3 OS, but real BLE printing has been tested only on Windows.
> macOS and Linux support is software-only and requires manual user validation.
> See [PLATFORMS.md](docs/PLATFORMS.md) for the full support matrix.

## Agent Skill

This repository includes a portable [Agent Skill](https://agentskills.io/) at `skills/paperang-cli/` and a synchronized repository-local copy at `.agents/skills/paperang-cli/`.

GitHub Copilot discovers it automatically when working from a repository checkout. The same skill can be installed as a personal skill for Codex, Claude Code, GitHub Copilot, and other Agent Skills-compatible clients.

With GitHub CLI `2.90.0` or newer, preview the skill before installation:

```powershell
gh skill preview wyrtensi/paperang-cli paperang-cli
gh skill install wyrtensi/paperang-cli paperang-cli --agent universal --scope user
```

GitHub CLI may note that one hidden skill was excluded. That is expected: `.agents/skills/paperang-cli/` is the synchronized checkout-local copy, while `skills/paperang-cli/` is the public installation source.

GitHub CLI supports host-specific installation for many editors and coding agents. Replace `universal` with a value such as `codex`, `claude-code`, `github-copilot`, `cursor`, `antigravity`, `gemini-cli`, `windsurf`, or another value listed by `gh skill install --help`.

Skills installed through GitHub CLI include source metadata, so they can be checked and updated later:

```powershell
gh skill update paperang-cli --dry-run
gh skill update --all
```

The repository also includes a small Python fallback installer for common personal locations. From a cloned repository:

```powershell
python scripts/install-agent-skill.py --target all
```

Install directly from GitHub on Windows PowerShell:

```powershell
irm https://raw.githubusercontent.com/wyrtensi/paperang-cli/main/scripts/install-agent-skill.py | py -3 - --source github --target all
```

Install directly from GitHub on Linux or macOS:

```bash
curl -fsSL https://raw.githubusercontent.com/wyrtensi/paperang-cli/main/scripts/install-agent-skill.py | python3 - --source github --target all
```

Use `--target codex`, `--target claude`, `--target copilot`, `--target cursor`, `--target windsurf`, `--target opencode`, `--target antigravity`, `--target gemini`, or `--target agents` to install only one personal copy. `--target all` installs the complete skill directory into all nine personal locations, even when a matching editor is not currently installed. Existing copies are preserved unless `--force` is provided. Restart the agent client after installation.

You can also ask an agent:

```text
Install the paperang-cli Agent Skill from:
https://github.com/wyrtensi/paperang-cli/tree/main/skills/paperang-cli
```

The skill is available on all operating systems. Real BLE communication and physical printing remain tested only on Windows.

## Safe First Run

Start with commands that do not consume paper:

```powershell
paperang --json config show
paperang --json discover
paperang --json probe
paperang --json battery
```

```bash
# macOS / Linux
paperang --json config show
paperang --json discover
paperang --json probe
paperang --json battery
```

Before a real print, run the matching command with `--dry-run`:

```powershell
paperang --json print text "Hello from Paperang" --dry-run
```

```bash
# macOS / Linux
paperang --json print text "Hello from Paperang" --dry-run
```

After checking the result, explicitly allow paper use:

```powershell
paperang --json print text "Hello from Paperang" --allow-paper-use
```

```bash
# macOS / Linux
paperang --json print text "Hello from Paperang" --allow-paper-use
```

Keep the content, image, layout, conversion mode, font size, min-font-size, font-fit mode, font family, orientation, autofit intent, and feed options the same between dry-run and the real print.

## Smart Layout Presets

The CLI can load a per-invocation JSON payload with `--style-json`. That payload can select a built-in preset and add structured overrides without changing your saved config.

For human-oriented workflows, treat built-in scenarios as reusable bases, not fixed modes. Start from the nearest scenario when one fits, then override only the fields needed for the current task. Reserve persistent `print_defaults` changes for explicit requests to make that behavior the default for future jobs.

For text, paragraph, and compose jobs, set `"font_fit": "largest-fitting"` and omit or clear `font_size` to let the renderer start large and shrink to the biggest fitting size automatically.

`break_long_words` is now opt-in. Leave it `false` to keep wrapping on whole words and let `largest-fitting` shrink a long token onto one line; set it to `true` only when you want forced character-chunk splitting.

As a practical rule, labels and tags often benefit from `largest-fitting`, while notes and lists usually read better with ordinary whole-word wrapping. If you are driving the CLI through an agent, the agent should explain the choice in human terms such as readability, glanceability, and approximate strip length.

Ready-to-copy copies of these payloads ship in `skills/paperang-cli/examples/` inside this repository, and the installed Agent Skill bundle carries the same files under `examples/` next to `SKILL.md`.

Useful ordinary home scenarios now include broader note presets like `fridge-note` and `chore-list`, plus label-style presets such as `pantry-label`, `cable-tag`, and `storage-bin`.

Address label example:

```json
{
	"preset": "address-label",
	"paragraph": {
		"font_size": null,
		"min_font_size": 14,
		"font_fit": "largest-fitting",
		"max_length_mm": 75.0,
		"overflow_policy": "shrink-to-fit",
		"break_long_words": false
	}
}
```

```powershell
paperang --json print paragraph "221B Baker Street London" --dry-run --style-json .\address-label.json
```

Home pantry label example:

```json
{
	"preset": "pantry-label",
	"paragraph": {
		"max_length_mm": 65.0,
		"overflow_policy": "shrink-to-fit",
		"break_long_words": false
	}
}
```

```powershell
paperang --json print paragraph "PASTA" --dry-run --style-json .\pantry-label.json
```

General fridge note example:

```json
{
	"preset": "fridge-note",
	"paragraph": {
		"font_size": null,
		"min_font_size": 14,
		"font_fit": "largest-fitting",
		"max_length_mm": 120.0,
		"line_spacing_px": 2,
		"overflow_policy": "shrink-to-fit",
		"break_long_words": false
	}
}
```

```powershell
paperang --json print paragraph "Buy milk\nFruit\nBread" --dry-run --style-json .\fridge-note.json
```

Long logo strip example:

```json
{
	"preset": "logo-strip",
	"image": {
		"fit_mode": "fit-within-length",
		"max_length_mm": 70.0
	}
}
```

```powershell
paperang --json print image .\banner.png --dry-run --style-json .\logo-strip.json
```

Composed badge example:

```json
{
	"compose": {
		"font_family": "mono",
		"font_size": null,
		"min_font_size": 14,
		"font_fit": "largest-fitting",
		"layout": "image-above",
		"image_mode": "photo",
		"max_length_mm": 55.0,
		"overflow_policy": "report-only",
		"break_long_words": false
	}
}
```

```powershell
paperang --json print compose "Product title" .\badge.png --dry-run --style-json .\product-style.json
```

When a dry-run uses length-aware styling, the JSON result can include `estimated_length_mm`, `max_length_mm`, and `fits_length_limit` so you can decide whether to print before consuming paper.

## Python API

`paperang-cli` also ships model-aware Python facades for `PaperangP1` and `PaperangP2`.

```python
from paperang_cli import PaperangP1, PaperangP2

p1 = PaperangP1(address="AA:BB:CC:DD:EE:FF")
p2 = PaperangP2(transport="ble", address="01:54:8D:17:B3:F2")

p1.connect()
status = p2.get_status()
preview = p2.print_text("Hello from Paperang", dry_run=True)
```

See [Paperang P1 Python API](docs/usage/p1-api.md) for the P1 facade and [Paperang P2 Python API](docs/usage/p2-api.md) for transport selection, supported methods, safety semantics, and current parity gaps versus `paperang-p2-lib`.

Use the installed CLI to inspect what is actually available in the current package version:

```powershell
paperang --json api list
paperang --json api p1
paperang --json api p2
```

## Printing

### Text

```powershell
paperang --json print text "Shipping label" --dry-run
paperang --json print text "Shipping label" --allow-paper-use
```

Use rotated label rendering when you want text to run along the paper path:

```powershell
paperang --json print text "Long shipping label" --dry-run --orientation rotate-90-cw --font-family mono --autofit
```

### Paragraph

```powershell
paperang --json print paragraph "A longer wrapped note for the printer." --dry-run
paperang --json print paragraph "A longer wrapped note for the printer." --allow-paper-use
```

Preset-driven label flow:

```powershell
paperang --json print paragraph "221B Baker Street London" --dry-run --style-json .\address-label.json
```

### Image

Use `--mode sticker` for logos, icons, and line art:

```powershell
paperang --json print image ".\sample.png" --dry-run --mode sticker
paperang --json print image ".\sample.png" --allow-paper-use --mode sticker
```

Use `--mode photo` as a starting point for photographs and smoother grayscale content:

```powershell
paperang --json print image ".\photo.jpg" --dry-run --mode photo
```

You can also rotate an image 90 degrees before it is fit to the P1 width:

```powershell
paperang --json print image ".\label.png" --dry-run --orientation rotate-90-ccw
```

For long banners or logo strips, pair a preset with a physical length budget:

```powershell
paperang --json print image ".\banner.png" --dry-run --style-json .\logo-strip.json
```

Image quality depends on the source file and printer. A successful dry-run validates conversion and packaging, not the final paper output.

### Compose

`print compose` combines wrapped text and an image in one vertical layout:

```powershell
paperang --json print compose "Product label" ".\sample.png" --dry-run --mode sticker
paperang --json print compose "Product label" ".\sample.png" --allow-paper-use --mode sticker
```

Use `--layout image-above` when the image should be printed before the text:

```powershell
paperang --json print compose "Product label" ".\sample.png" --dry-run --layout image-above
```

The same command can be driven by a JSON payload when you want a repeatable composed layout profile:

```powershell
paperang --json print compose "Product label" ".\sample.png" --dry-run --style-json .\product-style.json
```

Compose printing uses the same experimental image conversion pipeline as `print image`.

Rotated compose printing is not implemented yet. `print compose` still uses the ordinary vertical layout path in the current release.

### Built-In Self-Test

The printer self-test consumes substantially more paper than an ordinary print. Use it only when you explicitly want the printer's built-in diagnostic page:

```powershell
paperang --json print self-test --dry-run
paperang --json print self-test --allow-large-paper-use
```

The self-test dry-run only validates the CLI path and warning payload. It does not query hidden hardware state.

## Commands

| Command | Purpose |
| --- | --- |
| `paperang discover` | Scan for nearby supported printers |
| `paperang api list` | List known model-specific Python API entries and their availability |
| `paperang api p1` | Show the supported `PaperangP1` Python API contract |
| `paperang api p2` | Show the supported `PaperangP2` Python API contract |
| `paperang battery` | Query the current battery percentage |
| `paperang mac` | Query the printer-reported Bluetooth MAC address |
| `paperang status` | Query live printer information |
| `paperang probe` | Return a combined readiness summary |
| `paperang print text` | Print a short text block |
| `paperang print paragraph` | Print wrapped text |
| `paperang print image` | Print a local image |
| `paperang print compose` | Print text and an image as one job |
| `paperang print self-test` | Print the built-in diagnostic page |
| `paperang config show` | Show the resolved config and active settings |
| `paperang config path` | Show the resolved config path |
| `paperang config init` | Write an example config file |

Run `paperang --help` or `paperang <command> --help` for the available options.

## Configuration

Inspect the active config:

```powershell
paperang --json config show
paperang --json --printer p2-main config show
```

```bash
# macOS / Linux
paperang --json config show
```

Create an example config:

```powershell
paperang config init
```

```bash
# macOS / Linux
paperang config init
```

Configuration is resolved in this order:

1. `--config PATH`
2. `PAPERANG_CLI_CONFIG`
3. the per-user default config path
4. built-in defaults

Default paths:

- Windows: `%APPDATA%\paperang-cli\paperang-cli.config.json`
- macOS: `~/Library/Application Support/paperang-cli/paperang-cli.config.json`
- Linux: `$XDG_CONFIG_HOME/paperang-cli/paperang-cli.config.json`, or `~/.config/paperang-cli/paperang-cli.config.json`

See [Configuration](docs/usage/configuration.md) for the full schema.

When one config manages multiple printers, define `printers` and `default_printer`, then select a target with global `--printer NAME` for diagnostics, dry-runs, and real prints.

## Documentation

- [Documentation index](docs/index.md)
- [Installation guide](docs/installation.md)
- [Command reference](docs/usage/commands.md)
- [Paperang P1 Python API](docs/usage/p1-api.md)
- [Configuration](docs/usage/configuration.md)
- [Troubleshooting](docs/troubleshooting.md)
- [Agent contract](docs/agents/cli-contract.md)
- [Portable Agent Skill](skills/paperang-cli/SKILL.md)
- [Publishing runbook for agents](docs/agents/publishing.md)
- [Security policy](SECURITY.md)

### Cross-Platform Status

Live platform validation status is available at **https://wyrtensi.github.io/paperang-cli/**.

To verify your local installation:

```bash
python scripts/check-cross-platform.py
```

## Project History And Acknowledgements

The Paperang P1 logic in this standalone CLI builds on earlier reverse engineering and printer-control work by:

- `ihc童鞋@提不起劲`
- `BroncoTc`

Paperang P2 BLE FF00/A5 support is implemented directly in this repository and has been physically validated on Windows. The USB path still uses `mdj2812/paperang-p2-lib` and references `mdj2812/paperang-p2-usb`; treat that USB path as experimental until hardware validation is completed.

The current P2 planning calibration uses `advance_mm_per_px=0.08472`, measured from an approximately `61 mm` printed marker distance over `720 px` on the P2 BLE calibration strip.

The current `paperang-cli` package is maintained by `wyrtensi`.

## License

This package is available under the [MIT License](LICENSE).
