Releases: B1ueMu3ic4m/OPCCompany
Release list
v2.7.0 — the visible face
Added — v2.7.0 "the visible face"
- Flutter shell: the visible/raw toggle — the transcript pane can now
show an employee's VISIBLE log (product-scoped, sanitized, compacted —
the same text the macOS card renders) beside the raw seat stream. The
header counts honestly ("visible · N of T lines"); a refused ask keeps
the previous text — no answer is not a guess. transcript()binding over the v1.14 verb: a malformed payload (any
non-String line) refuses WHOLESALE, like every other typed wrapper.
v2.6.0 — the transcript door
Added — v2.6.0 "the transcript door"
opc transcript <agent> [--tail N] [--json]— read an employee's
VISIBLE terminal log from the visitor's seat: the same product-scoped,
sanitized, compacted text the GUI's agent card renders, clipped to the
last N lines (default 40;--tail 0serves everything). The header
counts honestly ("2 of 4 lines"); an empty seat answers its one
placeholder line instead of inventing output. Pure read by
construction.- Bridge verb
transcript(contract v1.14) — the same door over the
frozen six-symbol ABI: a JSON OBJECT {agentID, displayName,
totalLines, tail, lines} riding the smuggle channel,.sortedKeys
byte-stable, documented inopc_bridge.h.opc transcript --json
serves these exact bytes — one serializer, no second derivation. - Unknown ids and unknown names refuse like every other door; ambiguity
refuses rather than guesses.
Hardened
- Test-suite isolation, rebuilt honestly:
CompanyPersistence
gained atestSupportDirectoryOverrideseam (ForTesting convention);
tests that used to setenvOPC_COMPANY_SUPPORT_DIRwere flipping a
process-START knob the runtime never re-reads — dead theater where
only the first-touching test's flip ever applied, everyone else
silently shared one directory and dumped into each other. The 21
bridge-ABI door tests now live in one@Suite(.serialized)suite
(the bridge is a process-global singleton that refuses a second
create — the thread-storm test runs off the main actor by design and
used to collide with every other door). CLI child-process tests seed
through the seam into private dirs. A repo-hygiene gate now fails any
test that setenvs the support-dir knob again.
v2.5.0 — the seats line
opc watch already restamped the doors on a clock. Now every frame answers the boss's other live question: who is actually at their desk?
The seats line
OPC Company — 默认产品工作区 · 02:10:44
...
awaiting you: 0 approvals
seats: 2 open — Alice, Bob
- every frame carries the agents with a physically open tmux window RIGHT NOW
- fed by ONE
tmux list-windowsprobe per frame (openTerminalWindowAgentIDs()— a store read, never per-agent probes) - an empty office says
seats: no windows open, honestly hasOpenTerminalWindow(the v2.4 hall doctor's read) now shares the same verified{index}: {name}matcher
Gates: 4/4 CI · 690 Swift tests · release binary feature-verified (opc --version → 2.5.0; watch --once carries the seats line).
macOS app: unzip, drag to Applications. Windows shell unchanged (CLI/core round — v2.3.0's shell build stays current).
v2.4.0 — the hall doctor
Three additions, one theme: see the office honestly — from the terminal.
opc tell <agent> - — stdin multi-line steering
The seat semantics are one line at a time, so a multi-line paste is N honest sends, not one pretend one. The count prints (→ Alice (3 lines)); the first refusal stops the run and names its line number; empty stdin refuses. Round-trip tested against a real tmux seat.
opc hall — the terminal office in one paragraph
tmux present, workspace session running, per-agent window liveness. Pure read; nothing starts or stops. The new hasOpenTerminalWindow door probes tmux list-windows (line shape verified live: index-prefixed, 1: name#*). Deliberately distinct from "could a send go through right now" — the doctor must not dress a send-capable backend up as an open seat.
The contract drift guard
A new test parses the verb table in opc_bridge.h and demands exact equality with the bridge switch — both directions. Its first run caught a real hole: weight_json (v1.10) had never been documented in the header. The full six-key contract section is there now.
Also new: docs/DOORS.md — the door map (doors → verbs → surfaces, one math), and the session probe as a store read so the CLI never touches processes directly.
Gates: 4/4 CI · 688 Swift tests · release binary feature-verified (opc --version → 2.4.0, opc hall verified against a live office).
macOS app: unzip, drag to Applications. Windows shell unchanged (CLI/core round — v2.3.0's shell build stays current).
v2.3.0 — who's actually at their desk
The seat lifecycle left one loop open: the shell knew what IT spawned this session — but a seat that CRASHED an hour ago looked identical to a live one. v2.3.0 closes it.
The seat roster (bridge v1.13 seat_list)
seat_list→{"<uuid>": true|false}— every local seat the current process spawned, with its liveness AS OF THIS INSTANT. Pure read,.sortedKeysbyte-stable, over the same frozen six-symbol ABI.- A stopped seat has NO entry (not
false— after an explicit stop it was never the store's fact). - An exited-but-unstopped process reports
falsehonestly. - A seat another process spawned was never this roster's to report.
- An empty office answers
{}.
The shell follows the truth
The start seat / stop seat toggle is now driven by the roster, synced on every refresh: stop seat means ALIVE — whether this session spawned it or not — and start seat means not running. A null answer (old core, refused verb) keeps the previous roster: no answer is not a guess.
Gates: 4/4 CI · 685 Swift tests · 66 Flutter tests · smoke +1 roster shape check · release binary feature-verified (opc --version → 2.3.0).
macOS app: unzip, drag to Applications. Windows shell users: update both — the roster verb lives in the DLL.
v2.2.0 — the readable seat
Patch-grade fix, minor-grade confidence: the local-seat transcript stays readable.
The asymmetry this closes
tmux seats capture via tmux capture-pane -p — escape sequences stripped by construction. Local pipe seats (v2.0.0) streamed the process's RAW stdout/stderr. An interactive claude REPL speaks ANSI: SGR colors, spinner frames redrawn via CR, OSC window titles. Those bytes were being appended verbatim into the per-seat transcript — escape garbage on exactly the seats Windows users start.
The fix
ANSIStreamNormalizer at the transcript door:
- reuses the cursor-aware normalizer the preflight matchers already trust (CR overwrites, BS, CSI-K erases, OSC stripped;
\n/\tkept, other control bytes dropped) - carries a trailing PARTIAL escape sequence across chunk boundaries — a CSI split by a pipe read degrades into nothing, not garbage
- flushes the carry exactly once at end-of-stream
Test: a real seat ECHOING an ANSI-wrapped marker: the marker survives, the transcript contains zero ESC bytes.
macOS app: unzip, drag to Applications. Windows shell unchanged (this is core-side); its v2.1.0 build remains current.
v2.1.1 — no silent Chinese
Patch release: no silent Chinese.
The l10n audit's skipped class, closed. Ten sites across six files used interpolation-shaped lookup keys — strings like "\(name) 的 ".L() froze a runtime value INTO the key, so the translation map always missed and English mode silently rendered Chinese fragments. All ten now follow the house pattern (fragments are keys; values ride outside), with 8 new fragment keys translated. Two of the ten already had their English fragments sitting translated in en.json — the code just never called them.
Also in the fix round: CI's type-checker hit "unable to type-check in reasonable time" on one of the restructured concatenation chains (the v0.15 lesson recurring) — both long chains split into named locals.
Audit grep for interpolation-shaped .L() keys now measures zero.
macOS-only patch (Windows shell unchanged — v2.1.0's build remains current): unzip, drag to Applications.
v2.1.0 — steering everywhere
The v1.11 terminal_send door now has every surface it can have.
Steering everywhere
Every terminal-hall agent card in the macOS app gains a steering line: type one line, hit Enter — it lands in that employee's live seat through the SAME store door the CLI (opc tell, v0.18) and the Flutter shell input (v0.18) use. tmux paste first, the v2.0 local pipe-seat fallback for free.
- refusals surface verbatim inline —
no live seat,empty line, a failed paste — never a fake ack; success confirms "Delivered to the seat" and clears the field - boss cards refuse by design (the boss doesn't steer themselves)
- 6 new l10n keys, strings regenerated, the l10n audit gate green
With v0.17 (the door), v0.18 (CLI + shell), v2.0 (Windows seats) and this, the steering story is complete: one verb, every surface, whichever office you're in.
Gates: CI build + full test suite (681 Swift tests) ✅ · release binary feature-verified (opc --version → 2.1.0).
macOS app: unzip, drag to Applications. (No Windows-shell change in this release — the shell build below is unchanged since v2.0.0 but re-verified.)
v2.0.0 — the Windows office opens
First release out of 0.x — and it skips 1.x on purpose (project version policy: a capability milestone this size goes 2.0).
The Windows office opens
Until today, seats were tmux-backed — macOS machinery. A Windows shell could WATCH transcripts but could not start an employee. Now it can.
Local seats — the shell STARTS its own employees natively: a long-lived process of the agent's CLI in interactive mode, stdin kept open, pipe-mode. No tmux, no ConPTY.
- Seat output streams into the SAME per-seat transcript keys tmux seats write, so
terminal_digest,terminal_tail, the weight door and every transcript surface see local-seat traffic with zero new read path. terminal_send(v0.17) now steers whichever seat kind is live: tmux first, local pipe seat second — one verb, whichever office you're in.- Bridge contract v1.12:
seat_spawn/seat_stopover the same frozen six-symbol ABI. - The shell's toggle tracks only what IT spawned this session; a seat it didn't spawn is honestly "no local seat", never a guessed toggle.
- Honest refusals end to end: codex is refused (its TUI needs a real TTY), API/local employees have no CLI seat, double spawns refuse, and the registry is a runtime fact — never persisted, never guessed across restarts.
- Deliberately NOT a CLI verb: pipe seats belong to a long-lived office; a
opc seatwould orphan the process and lose the transcript when the CLI exits.
Also since v0.17.0: v0.18.0 "the tell door" — opc tell <agent> <line> and the shell's steering input put the v1.11 terminal_send verb in the terminal's and the shell's hands.
Gates: 4/4 CI (macOS release build, macOS tests, Windows compile, Flutter) · 681 Swift tests · 64 Flutter tests · smoke +2 deterministic seat refusal checks · release binary feature-verified (opc --version → 2.0.0).
macOS app: unzip, drag to Applications. Windows shell build follows shortly.
v0.18.0 — the tell door
Seat steering reaches the surfaces: the terminal and the shell can now TALK to a live seat, not just watch it.
opc tell <agent> <line> — inject ONE line into an agent's live tmux seat from the terminal. The agent may be named by uuid or exact display name; an ambiguous name refuses rather than guessing. Refusals are the store's own, verbatim: unknown name, empty or >4096-byte line, no live seat on this machine, failed paste. Never a fake ack.
The Flutter shell steers too — an input line under the selected seat's transcript. Success clears the field and re-pulls the transcript; a refusal shows verbatim and keeps your line for a retry. Windows shells (no tmux seats) see the honest refusal — the plumbing is identical, the office is just elsewhere.
Same frozen six-symbol ABI (contract v1.11, already shipped in v0.17.0) — this release is pure surface: the door existed, now every entrance opens onto it.
Gates: 4/4 CI · 676 Swift tests (--no-parallel) · 61 Flutter tests · smoke +2 deterministic refusal checks · release binary feature-verified (opc --version → 0.18.0, tell refusals verified against an isolated store).
macOS app: unzip, drag to Applications. Windows shell build follows shortly.