smartcli-toolkit 0.1.5__tar.gz → 0.1.6__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.
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/PKG-INFO +7 -7
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/README.md +6 -6
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/pyproject.toml +1 -1
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_core/__init__.py +1 -1
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_core/session.py +36 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_toolkit.egg-info/PKG-INFO +7 -7
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_toolkit.egg-info/SOURCES.txt +2 -1
- smartcli_toolkit-0.1.6/tests/test_wait_change.py +115 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/LICENSE +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/setup.cfg +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_core/__main__.py +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_core/pty_backend.py +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_core/py.typed +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_core/readiness.py +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_core/screen_model.py +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_core/snapshot.py +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_toolkit.egg-info/dependency_links.txt +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_toolkit.egg-info/requires.txt +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_toolkit.egg-info/top_level.txt +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/tests/test_char_width.py +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/tests/test_cpr_reply.py +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/tests/test_degenerate_inputs.py +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/tests/test_doc_counts.py +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/tests/test_fx_contract.py +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/tests/test_golden_frames.py +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/tests/test_readiness.py +0 -0
- {smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/tests/test_vendor_sync.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: smartcli-toolkit
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: Pluggable-PTY + pyte screen model + semantic snapshot / readiness core for driving interactive terminal programs (SmartCLI shared core).
|
|
5
5
|
Author: dwgx
|
|
6
6
|
License-Expression: MIT
|
|
@@ -195,7 +195,7 @@ backend, and dependency versions — run it and paste the output when filing a b
|
|
|
195
195
|
|
|
196
196
|
```bash
|
|
197
197
|
cd skills/cmd-art
|
|
198
|
-
python -m fx list # list all
|
|
198
|
+
python -m fx list # list all 28 effects
|
|
199
199
|
python -m fx play donut --seconds 5 # play one effect (bounded)
|
|
200
200
|
python -m fx gallery # one frame of each effect
|
|
201
201
|
python -m fx show --seq "donut:fire:3,plasma::3"
|
|
@@ -205,7 +205,7 @@ python -m fx show --seq "donut:fire:3,plasma::3"
|
|
|
205
205
|
|
|
206
206
|
```bash
|
|
207
207
|
cd skills/tui-ui
|
|
208
|
-
python -m ui widgets # list all
|
|
208
|
+
python -m ui widgets # list all 17 widgets
|
|
209
209
|
python -m ui gallery --width 100 --height 30
|
|
210
210
|
python -m ui demo table --width 80 --height 12 --theme dashboard
|
|
211
211
|
```
|
|
@@ -251,9 +251,9 @@ suite, see **[`README-USAGE.md`](README-USAGE.md)**.
|
|
|
251
251
|
## Features
|
|
252
252
|
|
|
253
253
|
**`cmd-art`** (`skills/cmd-art`) — a "living-template" effect engine: an `Effect` ABC +
|
|
254
|
-
`@register` decorator + auto-discovery. **
|
|
254
|
+
`@register` decorator + auto-discovery. **28 effects** (donut, solarsystem, fire, plasma,
|
|
255
255
|
rain, starfield, tunnel, text3d, cube, sphere, boids, life, fireworks, sparkle, decrypt,
|
|
256
|
-
gradient_text, banner_scroll, image2ascii, typewriter, julia, mandelbrot, perlin) across **8 themes** (mono, fire,
|
|
256
|
+
gradient_text, banner_scroll, image2ascii, typewriter, julia, mandelbrot, perlin, flames, water, nebula, text_flyin, text_converge, text_decrypt) across **8 themes** (mono, fire,
|
|
257
257
|
ocean, synthwave, viridis, pastel, matrix-green, rainbow). Effects are pure frame
|
|
258
258
|
producers; `play` is bounded by default and always restores the terminal.
|
|
259
259
|
|
|
@@ -285,9 +285,9 @@ cross-links. See [`knowledge/INDEX.md`](knowledge/INDEX.md).
|
|
|
285
285
|
```text
|
|
286
286
|
SmartCLI/
|
|
287
287
|
smartcli_core/ shared PTY + pyte engine (importable package)
|
|
288
|
-
skills/cmd-art/ fx effect package and CLI (
|
|
288
|
+
skills/cmd-art/ fx effect package and CLI (28 effects, 8 themes)
|
|
289
289
|
skills/drive-tui/ TUI pattern library and PTY driver CLI (8 recipes)
|
|
290
|
-
skills/tui-ui/ terminal UI layout engine and widgets (
|
|
290
|
+
skills/tui-ui/ terminal UI layout engine and widgets (17 widgets)
|
|
291
291
|
tools/screenshot/ pyte -> PNG smoke-test harness
|
|
292
292
|
tools/agentcli/ agent-CLI control validation harness
|
|
293
293
|
knowledge/ 122-note knowledge graph (see knowledge/INDEX.md)
|
|
@@ -149,7 +149,7 @@ backend, and dependency versions — run it and paste the output when filing a b
|
|
|
149
149
|
|
|
150
150
|
```bash
|
|
151
151
|
cd skills/cmd-art
|
|
152
|
-
python -m fx list # list all
|
|
152
|
+
python -m fx list # list all 28 effects
|
|
153
153
|
python -m fx play donut --seconds 5 # play one effect (bounded)
|
|
154
154
|
python -m fx gallery # one frame of each effect
|
|
155
155
|
python -m fx show --seq "donut:fire:3,plasma::3"
|
|
@@ -159,7 +159,7 @@ python -m fx show --seq "donut:fire:3,plasma::3"
|
|
|
159
159
|
|
|
160
160
|
```bash
|
|
161
161
|
cd skills/tui-ui
|
|
162
|
-
python -m ui widgets # list all
|
|
162
|
+
python -m ui widgets # list all 17 widgets
|
|
163
163
|
python -m ui gallery --width 100 --height 30
|
|
164
164
|
python -m ui demo table --width 80 --height 12 --theme dashboard
|
|
165
165
|
```
|
|
@@ -205,9 +205,9 @@ suite, see **[`README-USAGE.md`](README-USAGE.md)**.
|
|
|
205
205
|
## Features
|
|
206
206
|
|
|
207
207
|
**`cmd-art`** (`skills/cmd-art`) — a "living-template" effect engine: an `Effect` ABC +
|
|
208
|
-
`@register` decorator + auto-discovery. **
|
|
208
|
+
`@register` decorator + auto-discovery. **28 effects** (donut, solarsystem, fire, plasma,
|
|
209
209
|
rain, starfield, tunnel, text3d, cube, sphere, boids, life, fireworks, sparkle, decrypt,
|
|
210
|
-
gradient_text, banner_scroll, image2ascii, typewriter, julia, mandelbrot, perlin) across **8 themes** (mono, fire,
|
|
210
|
+
gradient_text, banner_scroll, image2ascii, typewriter, julia, mandelbrot, perlin, flames, water, nebula, text_flyin, text_converge, text_decrypt) across **8 themes** (mono, fire,
|
|
211
211
|
ocean, synthwave, viridis, pastel, matrix-green, rainbow). Effects are pure frame
|
|
212
212
|
producers; `play` is bounded by default and always restores the terminal.
|
|
213
213
|
|
|
@@ -239,9 +239,9 @@ cross-links. See [`knowledge/INDEX.md`](knowledge/INDEX.md).
|
|
|
239
239
|
```text
|
|
240
240
|
SmartCLI/
|
|
241
241
|
smartcli_core/ shared PTY + pyte engine (importable package)
|
|
242
|
-
skills/cmd-art/ fx effect package and CLI (
|
|
242
|
+
skills/cmd-art/ fx effect package and CLI (28 effects, 8 themes)
|
|
243
243
|
skills/drive-tui/ TUI pattern library and PTY driver CLI (8 recipes)
|
|
244
|
-
skills/tui-ui/ terminal UI layout engine and widgets (
|
|
244
|
+
skills/tui-ui/ terminal UI layout engine and widgets (17 widgets)
|
|
245
245
|
tools/screenshot/ pyte -> PNG smoke-test harness
|
|
246
246
|
tools/agentcli/ agent-CLI control validation harness
|
|
247
247
|
knowledge/ 122-note knowledge graph (see knowledge/INDEX.md)
|
|
@@ -30,7 +30,7 @@ build-backend = "setuptools.build_meta"
|
|
|
30
30
|
|
|
31
31
|
[project]
|
|
32
32
|
name = "smartcli-toolkit"
|
|
33
|
-
version = "0.1.
|
|
33
|
+
version = "0.1.6"
|
|
34
34
|
description = "Pluggable-PTY + pyte screen model + semantic snapshot / readiness core for driving interactive terminal programs (SmartCLI shared core)."
|
|
35
35
|
readme = "README.md"
|
|
36
36
|
license = "MIT"
|
|
@@ -20,6 +20,7 @@ Key tokens (``send_keys``) are mapped to escape bytes via :data:`KEY_MAP`.
|
|
|
20
20
|
|
|
21
21
|
from __future__ import annotations
|
|
22
22
|
|
|
23
|
+
import time
|
|
23
24
|
from typing import List, Optional, Tuple, Union, Sequence
|
|
24
25
|
|
|
25
26
|
from .pty_backend import PtyBackend, get_default_backend
|
|
@@ -295,3 +296,38 @@ class PtySession:
|
|
|
295
296
|
flags=flags,
|
|
296
297
|
)
|
|
297
298
|
return matched, snap # type: ignore[return-value]
|
|
299
|
+
|
|
300
|
+
def wait_change(
|
|
301
|
+
self,
|
|
302
|
+
baseline_hash: Optional[str] = None,
|
|
303
|
+
timeout_ms: int = 10000,
|
|
304
|
+
poll_ms: int = 30,
|
|
305
|
+
) -> Tuple[bool, Snapshot]:
|
|
306
|
+
"""Wait until the screen content changes away from ``baseline_hash``.
|
|
307
|
+
|
|
308
|
+
The precise "did my action land?" primitive: after sending input, block
|
|
309
|
+
until the screen's content hash differs from the baseline (by default,
|
|
310
|
+
the hash at the moment of the call). Returns (changed, snapshot) —
|
|
311
|
+
``changed`` is False on timeout, and the snapshot is always the latest
|
|
312
|
+
screen so the caller can inspect it either way. Complements wait_stable
|
|
313
|
+
(settle) / wait_for (a specific marker): this catches ANY change, which
|
|
314
|
+
is what you want right after acting, and it can't false-positive on a
|
|
315
|
+
screen that was already showing the target text.
|
|
316
|
+
|
|
317
|
+
This is a thin session-level poll over the existing pump + content_hash;
|
|
318
|
+
it adds no new core state.
|
|
319
|
+
"""
|
|
320
|
+
if baseline_hash is None:
|
|
321
|
+
# Baseline = the screen as it stands NOW, WITHOUT draining pending
|
|
322
|
+
# bytes first — otherwise the very output we're waiting for could be
|
|
323
|
+
# folded into the baseline and never register as a change.
|
|
324
|
+
baseline_hash = self.model.content_hash()
|
|
325
|
+
deadline = time.monotonic() + timeout_ms / 1000.0
|
|
326
|
+
poll_s = max(0.0, poll_ms / 1000.0)
|
|
327
|
+
while True:
|
|
328
|
+
self.pump()
|
|
329
|
+
if self.model.content_hash() != baseline_hash:
|
|
330
|
+
return True, self.snapshot()
|
|
331
|
+
if time.monotonic() >= deadline:
|
|
332
|
+
return False, self.snapshot()
|
|
333
|
+
time.sleep(poll_s)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: smartcli-toolkit
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: Pluggable-PTY + pyte screen model + semantic snapshot / readiness core for driving interactive terminal programs (SmartCLI shared core).
|
|
5
5
|
Author: dwgx
|
|
6
6
|
License-Expression: MIT
|
|
@@ -195,7 +195,7 @@ backend, and dependency versions — run it and paste the output when filing a b
|
|
|
195
195
|
|
|
196
196
|
```bash
|
|
197
197
|
cd skills/cmd-art
|
|
198
|
-
python -m fx list # list all
|
|
198
|
+
python -m fx list # list all 28 effects
|
|
199
199
|
python -m fx play donut --seconds 5 # play one effect (bounded)
|
|
200
200
|
python -m fx gallery # one frame of each effect
|
|
201
201
|
python -m fx show --seq "donut:fire:3,plasma::3"
|
|
@@ -205,7 +205,7 @@ python -m fx show --seq "donut:fire:3,plasma::3"
|
|
|
205
205
|
|
|
206
206
|
```bash
|
|
207
207
|
cd skills/tui-ui
|
|
208
|
-
python -m ui widgets # list all
|
|
208
|
+
python -m ui widgets # list all 17 widgets
|
|
209
209
|
python -m ui gallery --width 100 --height 30
|
|
210
210
|
python -m ui demo table --width 80 --height 12 --theme dashboard
|
|
211
211
|
```
|
|
@@ -251,9 +251,9 @@ suite, see **[`README-USAGE.md`](README-USAGE.md)**.
|
|
|
251
251
|
## Features
|
|
252
252
|
|
|
253
253
|
**`cmd-art`** (`skills/cmd-art`) — a "living-template" effect engine: an `Effect` ABC +
|
|
254
|
-
`@register` decorator + auto-discovery. **
|
|
254
|
+
`@register` decorator + auto-discovery. **28 effects** (donut, solarsystem, fire, plasma,
|
|
255
255
|
rain, starfield, tunnel, text3d, cube, sphere, boids, life, fireworks, sparkle, decrypt,
|
|
256
|
-
gradient_text, banner_scroll, image2ascii, typewriter, julia, mandelbrot, perlin) across **8 themes** (mono, fire,
|
|
256
|
+
gradient_text, banner_scroll, image2ascii, typewriter, julia, mandelbrot, perlin, flames, water, nebula, text_flyin, text_converge, text_decrypt) across **8 themes** (mono, fire,
|
|
257
257
|
ocean, synthwave, viridis, pastel, matrix-green, rainbow). Effects are pure frame
|
|
258
258
|
producers; `play` is bounded by default and always restores the terminal.
|
|
259
259
|
|
|
@@ -285,9 +285,9 @@ cross-links. See [`knowledge/INDEX.md`](knowledge/INDEX.md).
|
|
|
285
285
|
```text
|
|
286
286
|
SmartCLI/
|
|
287
287
|
smartcli_core/ shared PTY + pyte engine (importable package)
|
|
288
|
-
skills/cmd-art/ fx effect package and CLI (
|
|
288
|
+
skills/cmd-art/ fx effect package and CLI (28 effects, 8 themes)
|
|
289
289
|
skills/drive-tui/ TUI pattern library and PTY driver CLI (8 recipes)
|
|
290
|
-
skills/tui-ui/ terminal UI layout engine and widgets (
|
|
290
|
+
skills/tui-ui/ terminal UI layout engine and widgets (17 widgets)
|
|
291
291
|
tools/screenshot/ pyte -> PNG smoke-test harness
|
|
292
292
|
tools/agentcli/ agent-CLI control validation harness
|
|
293
293
|
knowledge/ 122-note knowledge graph (see knowledge/INDEX.md)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""test_wait_change.py — PtySession.wait_change regression (deterministic).
|
|
3
|
+
|
|
4
|
+
wait_change is the precise "did my action land?" primitive: block until the
|
|
5
|
+
screen content hash changes away from a baseline. This locks:
|
|
6
|
+
* baseline is the screen NOW, without draining pending bytes first (so the
|
|
7
|
+
awaited output can't be folded into the baseline and missed),
|
|
8
|
+
* a real content change returns (True, snapshot),
|
|
9
|
+
* no change within the window returns (False, latest snapshot),
|
|
10
|
+
* an explicit baseline_hash lets a caller wait for change from a known state.
|
|
11
|
+
|
|
12
|
+
Pure/in-memory: a fake backend feeds bytes on demand. No PTY, no process.
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
20
|
+
sys.path.insert(0, str(ROOT))
|
|
21
|
+
|
|
22
|
+
from smartcli_core import PtySession # noqa: E402
|
|
23
|
+
from smartcli_core.pty_backend import PtyBackend # noqa: E402
|
|
24
|
+
|
|
25
|
+
failures = 0
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def check(cond, label, detail=""):
|
|
29
|
+
global failures
|
|
30
|
+
if not cond:
|
|
31
|
+
failures += 1
|
|
32
|
+
print(f"{'PASS' if cond else 'FAIL'} {label}" + (f" -- {detail}" if detail else ""))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class FakeBackend(PtyBackend):
|
|
36
|
+
def __init__(self):
|
|
37
|
+
self._q = []
|
|
38
|
+
self._alive = True
|
|
39
|
+
|
|
40
|
+
def queue(self, data):
|
|
41
|
+
self._q.append(data)
|
|
42
|
+
|
|
43
|
+
def spawn(self, cmd, cols, rows):
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
def read_nonblocking(self, timeout=0.0):
|
|
47
|
+
return self._q.pop(0) if self._q else b""
|
|
48
|
+
|
|
49
|
+
def write(self, data):
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
def resize(self, cols, rows):
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
def is_alive(self):
|
|
56
|
+
return self._alive
|
|
57
|
+
|
|
58
|
+
def terminate(self):
|
|
59
|
+
self._alive = False
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_change_detected():
|
|
63
|
+
be = FakeBackend()
|
|
64
|
+
sess = PtySession(cols=40, rows=10, backend=be)
|
|
65
|
+
be.queue(b"hello world")
|
|
66
|
+
changed, snap = sess.wait_change(timeout_ms=2000)
|
|
67
|
+
check(changed is True, "content change is detected")
|
|
68
|
+
check("hello" in snap.to_text(), "returned snapshot shows the new content")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_no_change_times_out():
|
|
72
|
+
be = FakeBackend()
|
|
73
|
+
sess = PtySession(cols=40, rows=10, backend=be)
|
|
74
|
+
changed, snap = sess.wait_change(timeout_ms=250)
|
|
75
|
+
check(changed is False, "no change within the window -> False (timeout)")
|
|
76
|
+
check(snap is not None, "timeout still returns the latest snapshot")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_baseline_not_polluted():
|
|
80
|
+
# The bug this guards: if wait_change drained pending bytes to form the
|
|
81
|
+
# baseline, the awaited output would be in the baseline and never seen.
|
|
82
|
+
be = FakeBackend()
|
|
83
|
+
sess = PtySession(cols=40, rows=10, backend=be)
|
|
84
|
+
be.queue(b"the output I am waiting for") # already queued before the call
|
|
85
|
+
changed, _ = sess.wait_change(timeout_ms=2000)
|
|
86
|
+
check(changed is True, "pending bytes at call time still count as a change")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_explicit_baseline():
|
|
90
|
+
be = FakeBackend()
|
|
91
|
+
sess = PtySession(cols=40, rows=10, backend=be)
|
|
92
|
+
be.queue(b"first")
|
|
93
|
+
sess.wait_change(timeout_ms=2000) # consume 'first'
|
|
94
|
+
h = sess.model.content_hash()
|
|
95
|
+
be.queue(b"\x1b[2J\x1b[Hsecond") # clear + new
|
|
96
|
+
changed, snap = sess.wait_change(baseline_hash=h, timeout_ms=2000)
|
|
97
|
+
check(changed is True, "explicit baseline_hash detects change from a known state")
|
|
98
|
+
check("second" in snap.to_text(), "snapshot reflects the change")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def main():
|
|
102
|
+
test_change_detected()
|
|
103
|
+
test_no_change_times_out()
|
|
104
|
+
test_baseline_not_polluted()
|
|
105
|
+
test_explicit_baseline()
|
|
106
|
+
print()
|
|
107
|
+
if failures:
|
|
108
|
+
print(f"{failures} FAILURE(S)")
|
|
109
|
+
return 1
|
|
110
|
+
print("ALL PASS")
|
|
111
|
+
return 0
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if __name__ == "__main__":
|
|
115
|
+
sys.exit(main())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{smartcli_toolkit-0.1.5 → smartcli_toolkit-0.1.6}/smartcli_toolkit.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|