Metadata-Version: 2.3
Name: pieui
Version: 0.1.15
Summary: CLI client for PieUI.
Author: butusk0, DELTA37
Author-email: butusk0 <kirill.butusov@romanticai.com>, DELTA37 <gg_plastt@mail.ru>
Requires-Dist: jinja2>=3.1.0
Requires-Dist: adaptix>=3.0.0b12
Requires-Dist: dataclasses>=0.8
Requires-Dist: dataclasses-json>=0.6.7
Requires-Dist: fastapi>=0.136.0
Requires-Dist: httpx>=0.28.1
Requires-Dist: openai-agents>=0.14.2
Requires-Dist: python-dotenv>=1.2.2
Requires-Dist: cent>=5.2.0
Requires-Dist: fastapi-socketio>=0.0.10
Requires-Dist: jsonpatch>=1.33
Requires-Dist: dataclasses-jsonschema>=2.16.0
Requires-Dist: aiohttp>=3.13.5
Requires-Dist: stringcase>=1.2.0
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# pie

Python CLI and runtime helpers for PieUI applications.

The installed console script is `pie` and its entrypoint is `pie.__main__:main`.
Commands are grouped by area:

```text
pie web ...
pie card ...
pie card remote ...
pie page ...
pie create ...
pie login
```

## Setup

```bash
uv sync --python 3.14
```

Run commands from this repository with:

```bash
uv run pie --help
```

The project requires Python `>=3.14`.

## Configuration

The CLI loads `.env` through `python-dotenv` and reads these variables:

```text
PIE_USER_ID=default-user
PIE_PROJECT=default-project
PIE_PROJECT_SLUG=default-project
PIE_COMPONENTS_DIR=pages/components
PIE_API_KEY=dev-master-key
```

Notes:

- `PIE_COMPONENTS_DIR` defaults to `pages/components`.
- `PIE_PROJECT` wins over `PIE_PROJECT_SLUG`; if both are absent, the current directory name is used.
- `PIE_API_KEY` is sent to `pieui-storage` as the `x-api-key` header.
- The storage API base URL is currently `https://cdn-pieui.swarm.ing/api`.

## Create A Project

Create a new project, install `pieui`, write the starter files, and start a dev server on port `8008`:

```bash
uv run pie create my-app
```

Generated layout:

```text
my-app/
  web.py
  pages/
    main.py
    components/
```

The command runs:

```bash
uv init my-app
uv add pieui
uv run uvicorn web:app --port 8008
```

## Web Commands

Load a `Web` object from `module:attribute`:

```bash
uv run pie web web:web
```

Verify that every page has a `fields` attribute:

```bash
uv run pie web web:web verify
```

Build static JSON from page fields into `build.json`:

```bash
uv run pie web web:web build
```

## Card Commands

### Add

Create a Python card file in `PIE_COMPONENTS_DIR`.

```bash
uv run pie card add simple MyCard
uv run pie card add complex MyCard
uv run pie card add container MyCard
uv run pie card add complex-container MyCard
```

Optional template modifiers:

```bash
uv run pie card add simple MyCard --io
uv run pie card add simple MyCard --ajax
uv run pie card add simple MyCard --io --ajax
```

Names are normalized to a Python class and snake-case filename. For example:

```text
MyCard -> MyCard -> pages/components/my_card.py
trade widget -> TradeWidget -> pages/components/trade_widget_card.py
```

If the target file already exists, the command prints the existing path and does not overwrite it.

### List

Scan `PIE_COMPONENTS_DIR` recursively for Python classes inheriting `Card` or `InputCard`:

```bash
uv run pie card list
```

The table includes inferred card type, Ajax support, IO support, and file path.

### View

Print a plain-text report for one card:

```bash
uv run pie card view MyCard
```

The command reads the expected file from `PIE_COMPONENTS_DIR`, parses the class, and prints:

```text
Name
File
Props
Ajax
IO
Events
```

### List Events

Print events returned by `get_supported_events()`:

```bash
uv run pie card list-events MyCard
```

If the card file or events are absent, the command prints `No events found for MyCard.`

### Add Event

This command exists in the CLI, but Python source editing is not implemented:

```bash
uv run pie card add-event MyCard alert
```

It exits with:

```text
[pie] Error: add-event requires TypeScript AST editing and is not implemented
```

### Remote Push

Upload one local Python card file to `pieui-storage` through the language batch API:

```bash
uv run pie card remote push MyCard
```

For `MyCard`, the CLI uploads:

```text
pages/components/my_card.py
```

Remote key shape:

```text
PIE_USER_ID/PIE_PROJECT/MyCard/python/my_card.py
```

The file request uses:

```text
PUT /api/components/{user_id}/{project_slug}/{component_name}/batch/python
```

Each successful push produces a new revision on the server. The CLI fetches
`GET /api/components/{user_id}/{project_slug}/{component_name}/revisions` and
prints the latest revision number (e.g. `MyCard@3`) so you can later pull that
exact snapshot.

The command also uploads component capability metadata to `eventSchema`:

```json
{
  "component": "MyCard",
  "input": false,
  "ajax": false,
  "io": false
}
```

Flags are inferred from the Python class:

- `input`: the class inherits `InputCard`.
- `ajax`: the class declares any of `pathname`, `deps_names`, or `kwargs`.
- `io`: the class declares any of `use_socketio_support`, `use_centrifuge_support`, `use_mitt_support`, or `centrifuge_channel`.

`PIE_USER_ID` is required for storage writes. `PIE_PROJECT` or `PIE_PROJECT_SLUG` selects the project.

### Remote List

List remote components for a user/project:

```bash
uv run pie card remote list
uv run pie card remote list --user alice
uv run pie card remote list --user alice --project demo
```

Without flags, the command uses `PIE_USER_ID` and `PIE_PROJECT` / `PIE_PROJECT_SLUG`.

### Remote Pull

Pull a component from the configured `PIE_USER_ID` and project:

```bash
uv run pie card remote pull MyCard
uv run pie card remote pull MyCard@3
uv run pie card remote pull other-project/MyCard
uv run pie card remote pull other-project/MyCard@3
```

Reference formats:

```text
Name
Name@revision
project/Name
project/Name@revision
```

Without a project prefix, the current `PIE_PROJECT` / `PIE_PROJECT_SLUG` is
used. `project/Name` pulls from another project of the same `PIE_USER_ID`.

Without a suffix, the latest version is fetched. `Name@<revision>` or
`project/Name@<revision>` downloads the given revision snapshot from
`GET /api/components/{user_id}/{project_slug}/{component_name}/revisions/{revision}`.
Downloaded Python files are written under `PIE_COMPONENTS_DIR`.

### Remote History

Show component revision history and file diffs from storage:

```bash
uv run pie card remote history MyCard
uv run pie card remote history other-project/MyCard --page 2 --per-page 5
uv run pie card remote history MyCard --from 3 --to 7
```

Without a prefix, the current `PIE_PROJECT` / `PIE_PROJECT_SLUG` is used.
`project/Name` reads history from another project of the same configured
`PIE_USER_ID`.

The CLI calls:

```text
GET /api/components/{user_id}/{project_slug}/{component_name}/history
```

It prints a git-like patch view:

```text
component remote-user/other-project/TradeCard
page 2 per-page 3 total-revisions 9
range 4..6

revision TradeCard@6
date 2026-04-24T12:00:00+00:00
mutation update
previous 5

diff --git a/trade_card.py b/trade_card.py
modified +2 -1 trade_card.py
@@ -1 +1 @@
-old
+new
```

For binary files, the file block prints `Binary files differ`. For deleted
components, revision blocks include `deleted true`.

### Remote Public

Publish a component under a project-less public alias:

```bash
uv run pie card remote public MyCard
uv run pie card remote public other-project/MyCard
```

Without a prefix, the current `PIE_PROJECT` / `PIE_PROJECT_SLUG` is used.
`project/Name` publishes a component from another project of the same configured
`PIE_USER_ID`.

The command does not upload files. Push the component first with
`pie card remote push`, then publish it.

The CLI calls:

```text
PUT /api/components/{user_id}/{project_slug}/{component_name}/public
```

After publication, the component is readable through:

```text
GET /api/public-components/{user_id}/{component_name}
GET /{user_id}/{registry_slug}.json
GET /{user_id}/{component_name}/skill.md
```

If the public alias or registry slug collides with an existing public route, the
storage API returns `409` and the CLI prints the API error.

### Remote Private

Remove the public alias and make a component private again:

```bash
uv run pie card remote private MyCard
uv run pie card remote private other-project/MyCard
```

Without a prefix, the current `PIE_PROJECT` / `PIE_PROJECT_SLUG` is used.
`project/Name` targets another project of the same configured `PIE_USER_ID`.

The CLI calls:

```text
DELETE /api/components/{user_id}/{project_slug}/{component_name}/public
```

After this, public URLs under `/api/public-components/{user_id}/{component_name}`
and `/{user_id}/{registry_slug}.json` stop resolving without credentials.

### Pull

Unified pull shorthand:

```bash
uv run pie card pull MyCard
uv run pie card pull other-project/MyCard
uv run pie card pull r/delta37/YetAnotherComponent
```

Rules:

- `MyCard`: pulls from the current `PIE_PROJECT` / `PIE_PROJECT_SLUG`
- `project/MyCard`: pulls from another project of the same configured `PIE_USER_ID`
- `r/user/MyCard`: pulls a public component through
  `GET /api/public-components/{user_id}/{component_name}`

Downloaded Python files are written under `PIE_COMPONENTS_DIR`.

Revision suffixes are supported for private refs:

```bash
uv run pie card pull MyCard@3
uv run pie card pull other-project/MyCard@3
```

Public refs do not accept a revision suffix.

### Remote Remove

Delete a component from storage for the configured `PIE_USER_ID` and project:

```bash
uv run pie card remote remove MyCard
```

## Page Commands

### Add

Create a page module under the parent directory of `PIE_COMPONENTS_DIR` and register it in `web.py`:

```bash
uv run pie page add dashboard
uv run pie page add admin/users
```

With the default `PIE_COMPONENTS_DIR=pages/components`, page files are written to `pages/`.

Examples:

```text
dashboard -> pages/dashboard.py -> route "dashboard"
admin/users -> pages/admin_users.py -> route "admin/users"
```

`web.py` must exist next to the `pages/` directory and contain a `web = Web({...})` assignment with a literal pages dictionary.

### View

Import a page module and print page details:

```bash
uv run pie page view dashboard
```

The report includes:

```text
Page
Module
Path
is_typed
Form process
Ajax
```

## Login

Start the browser login flow:

```bash
uv run pie login
```

The command:

1. Generates a one-time code.
2. Opens `https://pieui.swarm.ing/connect?code=...`.
3. Polls `https://api-pieui.swarm.ing/api/external/credentials`.
4. Saves the returned config to `.pie/config.json`.
5. Appends `PIE_USER_ID`, `PIE_PROJECT`, and `PIE_API_KEY` to `.env`.

The returned config must contain these keys:

```text
user_id
project
api_key
```

## Current Command Reference

```text
pie --help
pie web MODULE:ATTR [verify|build]
pie card add {simple,complex,container,complex-container} NAME [--io] [--ajax]
pie card list
pie card pull REF
pie card view NAME
pie card list-events NAME
pie card add-event NAME EVENT_NAME
pie card remote list [--user USER_ID] [--project SLUG]
pie card remote push NAME
pie card remote pull REF
pie card remote history REF [--page N] [--per-page N] [--from N] [--to N]
pie card remote public REF
pie card remote private REF
pie card remote remove NAME
pie page add NAME
pie page view NAME
pie create NAME
pie login
```

## Code Layout

```text
pie/__main__.py                 CLI argument parsing and dispatch
pie/config.py                   environment-backed settings
pie/code/card_add.py            card template generation
pie/code/card_list.py           local card discovery
pie/code/card_inspect.py        card view and event inspection
pie/code/card_remote.py         PieUI storage: remote push/pull/history/public/private/remove/list
pie/code/page_create.py         page generation, web.py registration, page view
pie/code/create.py              project scaffolding
pie/code/login.py               PieUI login flow
pie/code/web.py                 Web loader and verifier
pie/code/build.py               build.json generation
pie/code/services/storage.py    pieui-storage API client
pie/code/services/models.py     storage response models
```
