Skip to content

v0.2.3 — control-plane concurrency

Latest

Choose a tag to compare

@dwgx dwgx released this 09 Aug 03:45
· 7 commits to main since this release

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 pytepip 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 concurrent snapshot waited behind it (8.00s,
    measured). smartcli_core's four wait loops and PtySession's six wait methods
    gained an optional on_poll hook, invoked in the idle gap on the waiting
    thread
    , so a fast verb is answered without a second thread ever entering the
    session — PtySession is not thread-safe (visual_hash() clears screen.dirty
    as a side effect, pump() is read-modify-write, resize() mutates four fields in
    sequence). Default None, so every existing caller behaves identically. On a live
    PTY: snapshot in 0.13s during a 20s wait-regex. A second LONG wait still queues
    behind the first — one session owns one PTY child, so that is inherent.
    resize is 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-change conclude 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
    while listen backlog + 1 silent peers hold connections; a 200 KB request spanning
    many recv() 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 by docker.yml against the built image — the check
    an MCP directory performs (start the container with no arguments, speak JSON-RPC).
    The image had shipped with CMD ["mcp"] for three releases with no test ever
    running it.

Changed

  • test_perf_contract declines 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_counts gates README's quoted drive_vim output against the example's
    step() literals, and the four localized READMEs gained the 30-second quickstart
    and the drive_vim comparison.