Skip to content

v0.6.0

Choose a tag to compare

@hamzahamidi hamzahamidi released this 19 Aug 09:33
· 19 commits to main since this release
7cb005c

Highlights

  • cic session --jsonl holds one connection open and answers one JSON object per line each way. A tabId returned by one call is still valid in the next, which a one-shot cic call could not offer: it pays for a process, a handshake and an empty tab group every time.
  • The response record is the frozen 0.4.0 envelope with an id added, rather than a second vocabulary. Success is {id, exit: 0, result}, failure {id, error: true, kind, exit, message}, so a caller that already parses cic call --json needs no new branches. The id is yours and is echoed back untouched.
  • Because a persistent process has one exit status and many calls, each record carries its own outcome while the process code describes only the session: 0 clean shutdown, 2 an unknown outcome ended it, 3 it never started.
  • An unknown outcome is fatal to the session, deliberately, with no flag to continue past one. The request was sent, nobody knows whether the browser acted, and letting a later call race it is the one thing the exit-code split exists to prevent.
  • cic shell is the same connection with a prompt, and is deliberately dumb: no variables, captures, aliases, implicit current tab or control flow, because the program driving the JSONL interface already has those.
  • The one-shot contract is unchanged. cic list and cic call keep their stdout, stderr, exit codes and --json shape, proven by the 0.5.0 suites passing untouched.

Install

npm install -g claude-in-chrome-cli

Plugin users need nothing new: the CLI ships bundled at node ${CLAUDE_PLUGIN_ROOT}/bin/cic.js.

What it looks like

A cic shell session making four calls over one connection: the tabId printed by the first reply is threaded into the three that follow. Each reply's tab context is elided.

A real session, recorded through a pty. Each reply's tab context is elided, because the bridge appends the title and URL of every open tab to every reply. Worth knowing if you log session output.

Two bugs from building it

Both appear only with piped input, which is how a program will actually drive this. Readline emits every piped line and fires close before the first call has finished, so the shell's trailing prompt() hit a closed interface, threw ERR_USE_AFTER_CLOSE, and that rejection poisoned the queue: every line after the first was silently skipped while the process still exited 0. Separately, .exit did not stop work already queued behind it, for the same reason. Stopping now means stopping, including what is already queued.

Four more from review

A fatal session emitted its record and then did not exit: readline was closed, but stdin had been paused by hand and stayed referenced, so the process waited for whoever was writing to it. Eight seconds against a writer holding the pipe, now one. Every earlier test missed it structurally, because spawnSync closes stdin immediately and the condition never arose.

Backpressure was half-implemented. Reads were paced by the bridge, but records went out through unchecked write() calls, so with stdout unread forty one-megabyte replies were accepted and buffered into 142 MB of resident memory. Each record is now handed over before the next request is taken, and the test asserts that memory does not grow with the queue: twenty requests and two hundred both peak around 64 MB.

Windows gained a coverage floor of its own rather than losing enforcement, and flags a command cannot act on became usage errors. cic list --jsonl, cic session --jsonl --retries 3 and cic shell --json previously exited 0 while quietly doing something other than what was asked; each command now declares what it understands and anything else exits 64.

Stated precisely

Every platform is gated on its own floor. Windows skips the EPIPE pipeline, the detached-descendant test and the resident-memory probe by design, so it enforces 95 statements and 87 branches against a measured 95.75% and 87.24%, where macOS and Linux enforce 96 and 86 against 96.55% and 86.54%. Its branch figure is the higher of the two because the skipped tests take branches out of the denominator, which is the argument for comparing a platform against itself. The memory probe needs ps, so it prints a visible skip on Windows rather than a pass it did not earn.

Verified

281 checks across five offline suites, no Chrome and no extension required, and all eight matrix jobs green on Ubuntu, macOS and Windows for Node 22 and 24. Coverage 96.55% of statements, 86.54% of branches and 63 of 63 functions. The published tarball is 6 files and the plugin cache 8. Installed from the registry, cic --version reports 0.6.0 and cic session --retries 3 exits 64 with the reason. Provenance attached and verified here with npm audit signatures: one verified registry signature, one verified attestation.

Full changelog: v0.5.0...v0.6.0