Install the three Claude Code skills — one zip, no git, no pip
curl -LO https://github.com/dwgx/SmartCLI/releases/latest/download/smartcli-skills.zip
unzip smartcli-skills.zip -d ~/.claude/skills/
309 KiB. cmd-art and tui-ui then run on CPython 3.10+ with no third-party
packages at all (verified on a bare virtualenv: 30 effects, 17 widgets).
drive-tui also needs pyte — pip install smartcli-toolkit.
Or the library / CLI / MCP server: pip install smartcli-toolkit
A control-plane concurrency release. The headline is a security fix that v0.2.2
did not carry: the daemon's serial accept loop let any local process — with no
credential at all — deny service for ~18s at a time, and pip install smartcli-toolkit
still had that. It also removes a second block that was one layer in: a long wait
kept a concurrent snapshot waiting behind it.
Fixed
- One connection could stall the daemon for every other caller. The accept loop
was serial with the UNAUTHENTICATED transport read inline, so any local process
could connect, send bytes with no newline, and head-of-line block every other
caller — measured at ~18s of denial from nine held connections, repeatable and
needing no credential. Now the accept thread only accepts, a per-connection reader
performs the unauthenticated work (read, parse, constant-time token check) so a
silent peer burns only its own 2s budget, and a single worker thread is the only
thread that touches the session. Measured after: an authenticated request is served
in 0.00s under the same attack. A previous release note described this as bounded
30x but not fixed; it is now fixed. - A long wait blocked unrelated fast verbs. A
wait-regex --timeout-ms 60000
occupied the session worker, so a concurrentsnapshotwaited behind it (8.00s,
measured).smartcli_core's four wait loops andPtySession's six wait methods
gained an optionalon_pollhook, invoked in the idle gap on the waiting
thread, so a fast verb is answered without a second thread ever entering the
session —PtySessionis not thread-safe (visual_hash()clearsscreen.dirty
as a side effect,pump()is read-modify-write,resize()mutates four fields in
sequence). DefaultNone, so every existing caller behaves identically. On a live
PTY:snapshotin 0.13s during a 20swait-regex. A second LONG wait still queues
behind the first — one session owns one PTY child, so that is inherent.
resizeis deliberately NOT answered mid-wait: it re-dimensions the pyte screen and
therefore changes the content hash, which would make a caller blocked in
wait-changeconclude its own keystroke had landed.
Added
tests/test_daemon_concurrency.py— drives the real accept loop against a fake
session (no PTY, no child process) and locks: an authenticated request is served
whilelistenbacklog + 1 silent peers hold connections; a 200 KB request spanning
manyrecv()calls still succeeds; auth is still enforced with no screen leak; a
fast verb is answered during a long wait; and session access provably stays on one
thread. Suite is 44 entries.tools/mcp_stdio_smoke.py, run bydocker.ymlagainst the built image — the check
an MCP directory performs (start the container with no arguments, speak JSON-RPC).
The image had shipped withCMD ["mcp"]for three releases with no test ever
running it.
Changed
test_perf_contractdeclines to measure timing ceilings when a tracer is attached
(coverage runs it under one), because the number measured there describes the
tracer. Raising the ceiling instead would have destroyed the 2000x regression window
the gate exists to protect.test_doc_countsgates README's quoteddrive_vimoutput against the example's
step()literals, and the four localized READMEs gained the 30-second quickstart
and thedrive_vimcomparison.