plexi-sdk 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plexi_sdk-0.1.4/.gitignore +67 -0
- plexi_sdk-0.1.4/PKG-INFO +117 -0
- plexi_sdk-0.1.4/README.md +97 -0
- plexi_sdk-0.1.4/plexi_sdk/__init__.py +71 -0
- plexi_sdk-0.1.4/plexi_sdk/_app.py +1516 -0
- plexi_sdk-0.1.4/plexi_sdk/_constants.py +41 -0
- plexi_sdk-0.1.4/plexi_sdk/_emitter.py +1920 -0
- plexi_sdk-0.1.4/plexi_sdk/_pipe.py +92 -0
- plexi_sdk-0.1.4/plexi_sdk/_protocol.py +48 -0
- plexi_sdk-0.1.4/plexi_sdk/_render_context.py +1094 -0
- plexi_sdk-0.1.4/plexi_sdk/_state.py +47 -0
- plexi_sdk-0.1.4/plexi_sdk/_theme.py +150 -0
- plexi_sdk-0.1.4/plexi_sdk/_types.py +145 -0
- plexi_sdk-0.1.4/plexi_sdk/midi.py +222 -0
- plexi_sdk-0.1.4/plexi_sdk/py.typed +1 -0
- plexi_sdk-0.1.4/plexi_sdk/templates/__init__.py +0 -0
- plexi_sdk-0.1.4/plexi_sdk/templates/agent_init.py +49 -0
- plexi_sdk-0.1.4/plexi_sdk/templates/app_init.py +38 -0
- plexi_sdk-0.1.4/plexi_sdk/testing.py +574 -0
- plexi_sdk-0.1.4/plexi_sdk/ui.py +2128 -0
- plexi_sdk-0.1.4/plexi_sdk/widgets/__init__.py +27 -0
- plexi_sdk-0.1.4/plexi_sdk/widgets/button.py +63 -0
- plexi_sdk-0.1.4/plexi_sdk/widgets/keymap.py +51 -0
- plexi_sdk-0.1.4/plexi_sdk/widgets/list_view.py +170 -0
- plexi_sdk-0.1.4/plexi_sdk/widgets/scroll.py +100 -0
- plexi_sdk-0.1.4/plexi_sdk/widgets/text_area.py +219 -0
- plexi_sdk-0.1.4/plexi_sdk/widgets/text_buffer.py +337 -0
- plexi_sdk-0.1.4/plexi_sdk/widgets/text_input.py +70 -0
- plexi_sdk-0.1.4/pyproject.toml +45 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Build
|
|
2
|
+
/target/
|
|
3
|
+
deps/egui_term/target/
|
|
4
|
+
|
|
5
|
+
# Scratch docs
|
|
6
|
+
docs/scratch/
|
|
7
|
+
|
|
8
|
+
# IDE
|
|
9
|
+
.idea/
|
|
10
|
+
.vscode/
|
|
11
|
+
|
|
12
|
+
# AI tool configs (local only)
|
|
13
|
+
.claude/settings.local.json
|
|
14
|
+
.claude/*.lock
|
|
15
|
+
.kiro/
|
|
16
|
+
/skills-lock.json
|
|
17
|
+
|
|
18
|
+
# OS
|
|
19
|
+
.DS_Store
|
|
20
|
+
Thumbs.db
|
|
21
|
+
|
|
22
|
+
# Environment
|
|
23
|
+
.env
|
|
24
|
+
.env.local
|
|
25
|
+
|
|
26
|
+
# Generated bundle assets (cargo bundle generates its own from Cargo.toml)
|
|
27
|
+
assets/Info.plist
|
|
28
|
+
|
|
29
|
+
# Bundled Python runtime (fetched by `just fetch-python-runtime` at build time)
|
|
30
|
+
assets/python/
|
|
31
|
+
|
|
32
|
+
# Channel (per-worktree, not shared)
|
|
33
|
+
.channel
|
|
34
|
+
|
|
35
|
+
# Misc
|
|
36
|
+
*.log
|
|
37
|
+
*.swp
|
|
38
|
+
*.swo
|
|
39
|
+
here.md
|
|
40
|
+
NEXT.md
|
|
41
|
+
examples/*/target/
|
|
42
|
+
sdk/*/target/
|
|
43
|
+
worktrees/
|
|
44
|
+
|
|
45
|
+
# Python
|
|
46
|
+
__pycache__/
|
|
47
|
+
*.pyc
|
|
48
|
+
*.pyo
|
|
49
|
+
sdk/python/**/__pycache__/
|
|
50
|
+
sdk/python/*.egg-info/
|
|
51
|
+
|
|
52
|
+
# Local config
|
|
53
|
+
.plexi/
|
|
54
|
+
.plexi-alpha/
|
|
55
|
+
.plexi-beta/
|
|
56
|
+
.plexi-pr-*/
|
|
57
|
+
.superpowers/
|
|
58
|
+
|
|
59
|
+
# Claude agent memory (local, not shared)
|
|
60
|
+
.claude/agent-memory/
|
|
61
|
+
|
|
62
|
+
# MemPalace (local semantic memory index)
|
|
63
|
+
.mempalace/
|
|
64
|
+
|
|
65
|
+
# MemPalace per-project files (issue #185)
|
|
66
|
+
mempalace.yaml
|
|
67
|
+
entities.json
|
plexi_sdk-0.1.4/PKG-INFO
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: plexi-sdk
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: Python SDK for building Plexi apps via the PGAP v3 protocol
|
|
5
|
+
Project-URL: Homepage, https://github.com/ianjamesburke/PLEXI
|
|
6
|
+
Project-URL: Repository, https://github.com/ianjamesburke/PLEXI
|
|
7
|
+
Project-URL: Documentation, https://github.com/ianjamesburke/PLEXI/tree/main/sdk/python
|
|
8
|
+
Author-email: Ian Burke <ianjamesburke@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: apps,pgap,plexi,sdk,tiling,window-manager
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# plexi-sdk
|
|
22
|
+
|
|
23
|
+
Python SDK v2 for building Plexi PGAP apps.
|
|
24
|
+
|
|
25
|
+
SDK v2 is the Python authoring API. PGAP v3 (`pgap/3`) is the host/app wire protocol the SDK speaks.
|
|
26
|
+
|
|
27
|
+
Full API reference: `plexi_sdk/__init__.py` and `docs/sdk-v2.md`.
|
|
28
|
+
|
|
29
|
+
## Install For SDK Development
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
uv pip install -e ./sdk/python
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Run from the repo root. `uv` creates `.venv` automatically if needed. Changes to `sdk/python/plexi_sdk/` take effect immediately in that environment.
|
|
36
|
+
|
|
37
|
+
Apps running inside Plexi use the SDK copy injected by the host on `PYTHONPATH`; the editable install is for type checking, tests, and local development.
|
|
38
|
+
|
|
39
|
+
Verify the install:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
source .venv/bin/activate
|
|
43
|
+
python3 -c "from plexi_sdk import App; print('ok')"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## App Pattern
|
|
47
|
+
|
|
48
|
+
Normal apps implement `view()` and return a component tree:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from plexi_sdk import App
|
|
52
|
+
from plexi_sdk.ui import AppBar, Column, FooterKeys, Label, Spacer
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class CounterApp(App):
|
|
56
|
+
def on_init(self) -> None:
|
|
57
|
+
self.count = self.state.get("count", 0)
|
|
58
|
+
|
|
59
|
+
def view(self):
|
|
60
|
+
return Column([
|
|
61
|
+
AppBar("Counter"),
|
|
62
|
+
Spacer(grow=True),
|
|
63
|
+
Label(str(self.count), bold=True),
|
|
64
|
+
Spacer(grow=True),
|
|
65
|
+
FooterKeys([("+", "increment"), ("-", "decrement")]),
|
|
66
|
+
])
|
|
67
|
+
|
|
68
|
+
def on_key(self, key: str, mods: dict) -> None:
|
|
69
|
+
if key in ("plus", "equals"):
|
|
70
|
+
self.count += 1
|
|
71
|
+
elif key == "minus":
|
|
72
|
+
self.count -= 1
|
|
73
|
+
self.state.save({"count": self.count})
|
|
74
|
+
self.emit.schedule_render()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
CounterApp().run()
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Use `on_render(ctx)` only for games, animations, realtime visualizations, or other pixel-control apps.
|
|
81
|
+
|
|
82
|
+
## Keyboard Conventions
|
|
83
|
+
|
|
84
|
+
Keys arrive in `on_key(self, key, mods)` as lowercase canonical strings.
|
|
85
|
+
|
|
86
|
+
| Physical key | `key` string |
|
|
87
|
+
|---|---|
|
|
88
|
+
| Enter / Return | `"return"` |
|
|
89
|
+
| Escape | `"escape"` |
|
|
90
|
+
| Backspace | `"backspace"` |
|
|
91
|
+
| Tab | `"tab"` |
|
|
92
|
+
| Space | `"space"` |
|
|
93
|
+
| Arrow keys | `"up"` / `"down"` / `"left"` / `"right"` |
|
|
94
|
+
|
|
95
|
+
Use `"return"`, not `"Enter"`. Use `"escape"`, not `"Escape"`.
|
|
96
|
+
|
|
97
|
+
Common list bindings:
|
|
98
|
+
|
|
99
|
+
| Key | Action |
|
|
100
|
+
|---|---|
|
|
101
|
+
| `j` / `"down"` | Move selection down |
|
|
102
|
+
| `k` / `"up"` | Move selection up |
|
|
103
|
+
| `"return"` | Open selected item |
|
|
104
|
+
| `"escape"` | Exit list or go back |
|
|
105
|
+
|
|
106
|
+
## State And Host I/O
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
self.state.get("key", default)
|
|
110
|
+
self.state.save({"key": value})
|
|
111
|
+
self.emit.schedule_render()
|
|
112
|
+
await self.emit.http_get(url)
|
|
113
|
+
await self.emit.secret_get("API_KEY")
|
|
114
|
+
await self.emit.ai_query("low", system, messages)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Declare capabilities in `manifest.toml` before using brokered host powers.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# plexi-sdk
|
|
2
|
+
|
|
3
|
+
Python SDK v2 for building Plexi PGAP apps.
|
|
4
|
+
|
|
5
|
+
SDK v2 is the Python authoring API. PGAP v3 (`pgap/3`) is the host/app wire protocol the SDK speaks.
|
|
6
|
+
|
|
7
|
+
Full API reference: `plexi_sdk/__init__.py` and `docs/sdk-v2.md`.
|
|
8
|
+
|
|
9
|
+
## Install For SDK Development
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
uv pip install -e ./sdk/python
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Run from the repo root. `uv` creates `.venv` automatically if needed. Changes to `sdk/python/plexi_sdk/` take effect immediately in that environment.
|
|
16
|
+
|
|
17
|
+
Apps running inside Plexi use the SDK copy injected by the host on `PYTHONPATH`; the editable install is for type checking, tests, and local development.
|
|
18
|
+
|
|
19
|
+
Verify the install:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
source .venv/bin/activate
|
|
23
|
+
python3 -c "from plexi_sdk import App; print('ok')"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## App Pattern
|
|
27
|
+
|
|
28
|
+
Normal apps implement `view()` and return a component tree:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from plexi_sdk import App
|
|
32
|
+
from plexi_sdk.ui import AppBar, Column, FooterKeys, Label, Spacer
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class CounterApp(App):
|
|
36
|
+
def on_init(self) -> None:
|
|
37
|
+
self.count = self.state.get("count", 0)
|
|
38
|
+
|
|
39
|
+
def view(self):
|
|
40
|
+
return Column([
|
|
41
|
+
AppBar("Counter"),
|
|
42
|
+
Spacer(grow=True),
|
|
43
|
+
Label(str(self.count), bold=True),
|
|
44
|
+
Spacer(grow=True),
|
|
45
|
+
FooterKeys([("+", "increment"), ("-", "decrement")]),
|
|
46
|
+
])
|
|
47
|
+
|
|
48
|
+
def on_key(self, key: str, mods: dict) -> None:
|
|
49
|
+
if key in ("plus", "equals"):
|
|
50
|
+
self.count += 1
|
|
51
|
+
elif key == "minus":
|
|
52
|
+
self.count -= 1
|
|
53
|
+
self.state.save({"count": self.count})
|
|
54
|
+
self.emit.schedule_render()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
CounterApp().run()
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Use `on_render(ctx)` only for games, animations, realtime visualizations, or other pixel-control apps.
|
|
61
|
+
|
|
62
|
+
## Keyboard Conventions
|
|
63
|
+
|
|
64
|
+
Keys arrive in `on_key(self, key, mods)` as lowercase canonical strings.
|
|
65
|
+
|
|
66
|
+
| Physical key | `key` string |
|
|
67
|
+
|---|---|
|
|
68
|
+
| Enter / Return | `"return"` |
|
|
69
|
+
| Escape | `"escape"` |
|
|
70
|
+
| Backspace | `"backspace"` |
|
|
71
|
+
| Tab | `"tab"` |
|
|
72
|
+
| Space | `"space"` |
|
|
73
|
+
| Arrow keys | `"up"` / `"down"` / `"left"` / `"right"` |
|
|
74
|
+
|
|
75
|
+
Use `"return"`, not `"Enter"`. Use `"escape"`, not `"Escape"`.
|
|
76
|
+
|
|
77
|
+
Common list bindings:
|
|
78
|
+
|
|
79
|
+
| Key | Action |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `j` / `"down"` | Move selection down |
|
|
82
|
+
| `k` / `"up"` | Move selection up |
|
|
83
|
+
| `"return"` | Open selected item |
|
|
84
|
+
| `"escape"` | Exit list or go back |
|
|
85
|
+
|
|
86
|
+
## State And Host I/O
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
self.state.get("key", default)
|
|
90
|
+
self.state.save({"key": value})
|
|
91
|
+
self.emit.schedule_render()
|
|
92
|
+
await self.emit.http_get(url)
|
|
93
|
+
await self.emit.secret_get("API_KEY")
|
|
94
|
+
await self.emit.ai_query("low", system, messages)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Declare capabilities in `manifest.toml` before using brokered host powers.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Python SDK v2 for Plexi PGAP apps.
|
|
2
|
+
|
|
3
|
+
Normal apps implement ``view()`` and return a component tree:
|
|
4
|
+
|
|
5
|
+
from plexi_sdk import App
|
|
6
|
+
from plexi_sdk.ui import AppBar, Column, FooterKeys, Label, Spacer
|
|
7
|
+
|
|
8
|
+
class CounterApp(App):
|
|
9
|
+
def on_init(self) -> None:
|
|
10
|
+
self.count = self.state.get("count", 0)
|
|
11
|
+
|
|
12
|
+
def view(self):
|
|
13
|
+
return Column([
|
|
14
|
+
AppBar("Counter"),
|
|
15
|
+
Spacer(grow=True),
|
|
16
|
+
Label(str(self.count), bold=True),
|
|
17
|
+
Spacer(grow=True),
|
|
18
|
+
FooterKeys([("+", "increment"), ("-", "decrement")]),
|
|
19
|
+
])
|
|
20
|
+
|
|
21
|
+
def on_key(self, key: str, mods: dict) -> None:
|
|
22
|
+
if key in ("plus", "equals"):
|
|
23
|
+
self.count += 1
|
|
24
|
+
elif key == "minus":
|
|
25
|
+
self.count -= 1
|
|
26
|
+
self.state.save({"count": self.count})
|
|
27
|
+
self.emit.schedule_render()
|
|
28
|
+
|
|
29
|
+
CounterApp().run()
|
|
30
|
+
|
|
31
|
+
Use ``on_render(ctx)`` only for games, animations, realtime visualizations, or
|
|
32
|
+
other pixel-control apps. Never override both ``view()`` and ``on_render(ctx)``.
|
|
33
|
+
|
|
34
|
+
Host-brokered actions live on ``self.emit``:
|
|
35
|
+
|
|
36
|
+
await self.emit.http_get(url) # requires net.http
|
|
37
|
+
await self.emit.secret_get("KEY") # requires secrets.get
|
|
38
|
+
await self.emit.ai_query("low", system, messages) # requires ai.query
|
|
39
|
+
|
|
40
|
+
Capabilities gate PGAP host APIs. Python apps are native subprocesses, not a
|
|
41
|
+
process sandbox.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
__version__ = "0.5.0"
|
|
45
|
+
SDK_ID = f"plexi-sdk-py/{__version__}"
|
|
46
|
+
|
|
47
|
+
from ._constants import (
|
|
48
|
+
TITLE, HEADING, BODY, CAPTION, HINT, MONO_BODY, MONO_SMALL,
|
|
49
|
+
PAD, PAD_TIGHT, HEADER_H, STATUS_H,
|
|
50
|
+
PRIORITY_LOW, PRIORITY_NORMAL, PRIORITY_HIGH, PRIORITY_CRITICAL,
|
|
51
|
+
rgba, dim,
|
|
52
|
+
)
|
|
53
|
+
from ._types import (
|
|
54
|
+
CapabilityDeniedError, VideoHandle,
|
|
55
|
+
RectCommand, TextCommand, BadgeCommand, TextInputSpec, ShortcutPair, NotifyOption,
|
|
56
|
+
)
|
|
57
|
+
from ._protocol import AiResponse, MidiPortInfo, MidiDeviceList, AudioDeviceInfo, AudioDeviceList, PROTOCOL_VERSION
|
|
58
|
+
from ._emitter import Emitter, _emit, _make_async_queue, _LOCK
|
|
59
|
+
from ._pipe import Pipe
|
|
60
|
+
from ._render_context import RenderContext, COMPACT_DEFAULT, REGULAR_DEFAULT
|
|
61
|
+
from ._app import App, Arg
|
|
62
|
+
from ._state import State as State
|
|
63
|
+
from .ui import (
|
|
64
|
+
Tabs as Tabs,
|
|
65
|
+
Grid as Grid,
|
|
66
|
+
Toggle as Toggle,
|
|
67
|
+
Clickable as Clickable,
|
|
68
|
+
ProgressBar as ProgressBar,
|
|
69
|
+
TextEdit as TextEdit,
|
|
70
|
+
)
|
|
71
|
+
from ._theme import theme, Theme, AppPalette
|