Skip to content

Releases: chipmates/cctap

Release list

v0.1.6

Choose a tag to compare

@github-actions github-actions released this 04 Aug 03:43

An audit of 0.1.5 across six angles, with every serious finding handed to a second
reader whose job was to disprove it. What survived is fixed here. Two of them could
remove files that were never cctap's, so if you set CCTAP_DIR to a directory you
also keep other things in, this is the release to take.

Security

  • --purge no longer empties bin/ and spool/ wholesale. It removes the names
    cctap actually writes, which is the three bundles it copied, the temp file an
    interrupted copy leaves, the spool and its rotated segments. Anything else in those
    directories stays, and the directory stays with it. Before this, pointing
    CCTAP_DIR at a directory that already held binaries and purging took every one of
    them, and the run then said everything cctap put there was gone, which was not what
    had happened. The daemon's permission repair had the same reach and would clamp
    files it did not write to 0600 on every start. It is on the same list now.
  • The purge also stops at what a purge is for. The socket is removed only when a
    socket is what sits at that path, because the socket path is configurable and
    moving it out of the tree is the documented answer to a long CCTAP_DIR. A config
    naming a regular file used to have the purge delete that file.
  • A value form of a boolean flag is refused instead of ignored. --dry-run=1 passed
    validation and then read as absent everywhere that decides anything, so the run
    told to change nothing performed the whole real thing and reported success.
    uninstall-hooks --purge --dry-run=yes really did purge. Both exit 2 now and touch
    nothing.
  • The last-resort scan for a payload too damaged to parse recovers the session id and
    the event name and nothing else. It matched a key anywhere in the text, so it could
    not tell a top-level field from a tool argument of the same name, and a tool
    argument called source reached the socket and the spool on disk. The privacy
    promise is written to match what the code does, not the other way round.
  • cctap stop checks the daemon it is about to signal by the paths cctap launches,
    not by the file name alone. A recycled pid running any other project's daemon.mjs
    was accepted, signalled, and reported as ours.
  • A CCTAP_DIR that reaches your home directory or the filesystem root by another
    name, through a symlink or a /private prefix, is refused like the plain spelling.

Fixed

  • A session can no longer be pinned to the board forever. If Claude Code dies in the
    first moments of a hook, the forwarder is reparented onto pid 1 and recorded that,
    and pid 1 always answers alive, so the session never aged out. One stuck at a
    permission prompt then sorted ahead of every real one, and the jump key went to a
    terminal that no longer existed, every press, silently. Such a session in a state
    file written by 0.1.5 heals on the next daemon start.
  • cctap simulate writes its demo repositories where --purge could not see them,
    so a purge after a simulate could never finish and blamed the leftovers on you.
    Both halves are fixed: the directory is removed, and a purge that does leave
    something behind now lists what it is instead of characterizing it.
  • A settings file that is a symlink whose target is not in place yet, which is what a
    dotfiles setup looks like between cloning and stowing, is written through instead
    of replaced. The link survives.
  • The ascii theme stays inside its character set. The separator before the daemon
    marker and the hint was a middle dot whatever the theme, and the marker for a
    truncated field was an ellipsis, both in the one mode chosen precisely because the
    terminal cannot draw them.
  • The strip's own messages fit the space they are given. The daemon-down line and the
    empty-board line ignored the width budget and could wrap the status bar they sit
    in. Each now steps down to a shorter form rather than being cut.
  • top keeps the daemon-down marker and the count of hidden rows on a short
    terminal, ahead of the key legend, and a SIGCONT that follows no stop no longer
    re-enters the screen or stacks a second handler.

Changed

  • CCTAP_MOTION=0 and the motion and blink config keys are documented where the
    other settings are, rather than only in this file.
  • The privacy document lists every path cctap writes, including the config, the keys
    journal, its own copied bundles and the simulate repositories.
  • CCTAP_NO_EXEC says what it does. Nothing outside cctap runs under it, its own
    daemon aside, which was always the behavior.

v0.1.5

Choose a tag to compare

@github-actions github-actions released this 03 Aug 20:21

The sanitation release. Six independent security reviews of 0.1.4 were read, every
claim verified against the code, and everything confirmed is fixed here, along with
the sharpest bug of the round, which no review found.

Security

  • Nothing hostile reaches your terminal anymore. Directory names, branch names and
    hook text are stripped of control bytes once, at the daemon boundary, so an escape
    sequence hiding in a branch name can no longer repaint the screen from inside the
    status line. Width is measured in terminal columns on grapheme clusters, so a CJK
    or emoji label can neither wrap the strip nor be cut through the middle of a glyph.
  • The salvage path for a malformed hook payload now recovers identifying fields only.
    A truncated payload could previously leak nested free text, up to a tool's message
    body, onto the socket and into the on-disk spool.
  • --purge never issues a recursive delete of the cctap directory root. It removes
    exactly the children cctap created and then an rmdir, so a mistyped CCTAP_DIR
    pointing at a real directory survives with everything foreign intact. CCTAP_DIR
    itself now expands ~, must be absolute, and is refused outright at / or at the
    home directory. A keys journal that exists but cannot be read refuses the purge
    instead of silently disarming that guard.
  • The daemon only ever unlinks its socket path after checking the path is actually a
    socket, and cctap stop verifies the recorded pid is really a cctap daemon before
    signalling it, so a recycled pid or a misconfigured socket path can no longer take
    down or delete something that was never cctap's.
  • Everything cctap writes that a shell later re-parses is POSIX single-quoted: the
    installed status line command, the printed keys recipes, the tmux conf line. A $,
    backtick or space in a home directory no longer kills the strip or executes
    path-derived text. AppleScript tty interpolations are escaped the same way, and
    notification bodies are clamped before they reach any argv.

Fixed

  • A resumed session no longer shows a phantom permission prompt. SessionStart now
    resets the subagent tree and the attention fields, so claude --resume inside the
    ended-session window cannot inherit a blocked subagent from the previous life,
    which used to sort itself to jump priority one and then hold the spinner so the
    session never read as your turn again for the rest of its life.
  • The spool is bounded by atomic rotation instead of a read-filter-rewrite, so a
    concurrent append can no longer be lost and a backed-up spool no longer blows the
    forwarder's time budget. Rotated segments are capped at five, oldest dropped with
    a counted marker that now survives replay into the state file, where doctor reports
    it. A daemon standing down because another one is serving no longer consumes and
    deletes spooled events on its way out.
  • Each hook invocation carries a random eid shared by its delivered and spooled
    copy, and the daemon drops repeats, so the retry path can no longer double-count an
    anonymous subagent and leave a session spinning forever. A subagent tree whose
    start and stop events did not pair up is released after a bounded stall instead of
    hiding your turn for good, and doctor says when that happened.
  • A daemon whose socket rebind failed retries on the next sweep instead of staying
    permanently unreachable while holding the lock, and a stood-down daemon no longer
    deletes the serving daemon's info file. The daemon survives exceptions in its own
    side effects, drops subscribers that stopped reading before they grow its memory,
    retries snapshot writes that failed transiently, retries a tty resolve that failed
    once, caps captured environment values so no legal event can outgrow the line cap,
    and tracks sessions whose ids collide with object prototype names.
  • The installer validates your settings file before it copies or writes anything, so
    an aborted run really has changed nothing, binaries included. Binary copies land
    atomically, backups are created exclusively with millisecond-and-pid names so no
    run can overwrite the backup holding your pre-cctap settings, a symlinked
    settings.json is written through rather than replaced, and a settings file that
    changed mid-run aborts instead of reverting the other writer. Unknown flags exit 2
    before any work, so a misspelled --dry-run can never perform the real install.
    uninstall-hooks, stop and notify run even under a broken socket path, and an
    uninstall with no settings file still stops the daemon and honours --purge.
  • A hooks entry with a shape cctap cannot merge into is preserved and reported
    instead of being replaced, in every case.
  • A notification suppressed by the debounce window is deferred and delivered when the
    window closes if the state still holds, instead of being dropped. Permission
    answered fast then your turn no longer means no banner at all.
  • Key input on the live surfaces accepts only exact single digits, so F5, Delete,
    a paste or a mouse report can no longer jump you somewhere a digit happened to
    appear in the byte sequence.
  • The live strip keeps the last known board when the daemon link drops and marks it
    daemon down, state unknown, instead of repainting as a calm empty strip while a
    permission prompt may be pending. top clamps to the terminal viewport, so thirty
    sessions on twenty rows no longer scroll the screen into an unreadable smear, and
    both surfaces restore the terminal on every way out, including crashes, hangup and
    Ctrl-Z.
  • GNOME key setup captures the prior keybinding values before writing and restores
    them on undo, journals partial failures so nothing orphaned becomes invisible, and
    tmux setup only treats a binding as its own when it runs cctap's exact jump line.
    The macOS clipboard warning prints before the clipboard is replaced, not after.
  • The macOS socket path limit is 103 bytes, not 104. The old constant allowed a path
    that the kernel truncated by one byte.

Added

  • Reduced motion: CCTAP_MOTION=0 or "motion": false freezes the spinner and stops
    every animation ticker, in the status line, the live strip and top alike. NO_COLOR
    now also beats the installer-forced color on the status line.
  • Release engineering: CI proves the build byte-identical twice over, every workflow
    action is pinned to a commit SHA, the release workflow refuses a tag that does not
    match the manifest, skips green when the version is already on npm, publishes
    prereleases to the next tag, verifies the published rebuild matches the tested
    bundles, and creates a GitHub Release from this file's section for the tag.

Changed

  • cctap status says waiting for the state the strip calls your turn. One state,
    one word.
  • Node 22 or newer. Node 20 passed its end of life in April 2026.
  • Session labels that collide extend their disambiguating suffix until unique, and a
    repository's detached HEAD state is labelled detached instead of HEAD.
  • Docs: the README quick start works as pasted, the npm page renders its images, the
    install docs say exactly what is written where, PRIVACY documents every stored
    field including the nine environment variables and the new rotation and eid
    details, SECURITY carries a threat model, and cctap doctor is documented where
    people can find it.