Dev - #2619
Dev#2619
Conversation
Group A foundation for the codex-plugin-update-handoff activation protocol: - codex-activation-persistence.ts: bounded regular-file reads that fail closed on symlink/non-regular/oversize, atomic backup-first fsync-before-rename writes, and non-overwriting renames for quarantine and stale-lease supersession. - codex-lifecycle-lease.ts: single-host O_EXCL lifecycle lease with fresh 128-bit operation IDs, typed codex-lifecycle-busy refusals naming the holder kind, dead-pid supersession (one retry, rename evidence retained), fail-closed handling of symlinked/oversized/invalid lease files, and operation-ID fencing (assertOperation) for store transitions. Tests include a real two-process O_EXCL race proving exactly one winner.
Group A core for codex-plugin-update-handoff: one deep, fail-closed activation protocol whose state and authorization decisions are pure and total, with unforgeable consent/permit APIs. - observeCodexActivation(): bounded reads only — canonical payload version/digest, codex plugin list --json bounded to 5s/64KiB with exact single-JSON-value + duplicate rejection + ANSI/OSC sanitisation, symlink-rejecting cache parity, downgrade receipt/delivery/tombstone facts, and a cache-family witness snapshotted before+after the query to prove observation is inert. - classifyCodexActivation(): pure, total truth-table classifier (first match) over every design row incl. intent-target-current dominance and all four refresh-intent phases. - authorizeCodexActivation(): pure, no I/O; consumes a runtime-branded RetirementAssertion and returns a process-local, fingerprint-bound ActivationPermit. Brands are WeakSet-tracked so forgery, persisted consent, booleans, and test construction fail at runtime. - requestRetirementAssertion(): the only brand source — owns TTY/env/flag guards and the affirmative N→T prompt. - CodexActivationStore: only writer of delivery/intent/receipt/tombstone; raw paths private; publishDelivery, withRevalidatedDeliveryRoot (revalidates + rejects escaped capabilities + refuses GENIE_BUNDLE_ROOT), beginActivation (re-observes + exact fingerprint match, zero mutation on stale), fenced journal transitions, crash-safe finalize, and quarantine. - Stable human/JSON projections, doctor integrationSummary schema-1, the exit-2 result-trailer type + single canonical serializer, and the setup exit overlay. 64 table-driven tests under isolated GENIE_HOME/CODEX_HOME fixtures.
…e-private factories
…+ H3 smoke Add src/lib/codex-activation-executor.ts as the single permit-gated route to Codex plugin activation mutation. It acquires and holds the lifecycle lease, begins activation through A's store (fingerprint-checked), drives the supported codex plugin add via A's typed phase transitions, verifies full physical N+1 parity strictly inside withRevalidatedDeliveryRoot, runs the exact bounded no-shell H3 SessionStart smoke, restores the observed enabled flag, and finalizes (journal + one-time downgrade-receipt tombstone) through A. A busy lease is the typed codex-lifecycle-busy refusal with zero mutation. Focused test covers: non-genuine permit refusal, upgrade/install/disabled activation, stale-fingerprint zero-mutation refusal, lease busy + release, mid-transaction fencing, planned/command-started/target-current crash recovery and idempotent retry, one-time downgrade receipt consumption, store-only mutation spies, the H3 timeout/cap/schema/stderr/node/env-poison cases, and a real spawned two-process executor race proving exactly one winner.
The both-verifiers-failed throw tells the user to install gh or cosign, but the earlier missing-bundle throw gave no guidance. Point it at the gh CLI, since cosign cannot help without the .bundle asset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… Latest install.sh treats gh as the verification prerequisite it already is: when the system gh is missing or lacks the attestation subcommand, bootstrap the official gh v2.96.0 into the private staging dir — pinned per-platform SHA256s taken from the release's checksums file, verified before extraction, never installed system-wide, fail-closed to the cosign fallback. Mirrors the existing cosign bootstrap. reconcile-release-note.sh: stable finalize now sets prerelease=false and make_latest=true, so promoting a tag the dev channel already published flips it to the GitHub Latest release. Every release since v5.260714.3 stayed Pre-release because finalize preserved the dev-time flag with make_latest=false, freezing the Latest badge at July 14. dev/homolog behavior unchanged; the demote guard stays intact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… G1-G4) Author the executor-facing DESIGN for the genie-ui wish from the ratified brainstorm (DRAFT/RESEARCH/COUNCIL): two channels (PTY viewing + ACP control), Model-B-corrected contract verbatim, module/interface/isolation architecture, the 8 council acceptance criteria verbatim, G1-G4 execution groups, risks incl. council dissent as future work, and the OUT list (conductor auto-pilot, write-promotion toggle, broadcast routing, Electron). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gate/build/residue tightenings) Fix the design-review gaps without altering the ratified verbatim texts (council contract, AC1-8): - MAJOR: pin the exact wish<->worktree mapping. The coherence contract binds per hired agent, not per wish: an agent's two faces cd into that agent's ready-group worktree (reused from `genie launch`, one per group), never a parallel wish-level worktree. Wish-level coherence rides on the shared `.genie` git artifacts (git-tracked wishes + worktree-shared genie.db), not a single path. Reconciles the "compose, don't duplicate" promise. Updated worktree wall, knot gloss, Scope IN, chat prose, `worktreeFor(rosterEntry)` signature, and G2 validation. - MINOR: G1 must wire `packages/**` into the gates (tsconfig include, complexity-budget scope, biome complexity override) or typecheck + the budget silently skip the package. - MINOR: "zero build step" scoped to the server; G1 replaces the prototype's Vite client transpile with a bun-native serve path (Bun.serve + import map). - MINOR: soften the rlmx-acp "all four exist today" overclaim (in flight). - MINOR: reframe G4/AC8 to verify no LIVE refs remain (already true) and preserve historical CHANGELOG/wish records rather than scrub them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Curated from .genie/brainstorms/genie-ui/DESIGN.md (SHIP, digest-verified): the fleet floor (PTY viewing) + genie lane + wish group chat (ACP control). 8 ratified ACs, D1-D13, R1-R11, four sequential waves G1->G2->G3->G4. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Make CLAUDE.md's "src/** AND packages/**" complexity claim true and stop
typecheck + the complexity budget silently skipping the new package before
any feature code lands.
- tsconfig: add packages/genie-ui project reference; the package has its own
tsconfig (DOM lib for the client) so the typecheck script runs both.
- biome: add a packages/** override (noExcessiveCognitiveComplexity warn @ 25,
matching src/**).
- complexity-budget: extend the suppression grep scope from src to src+packages
(biome check . already reports packages/** complexity warnings).
- knip: add the package entries + project glob so dead-code resolves the new
runtime imports instead of flagging them unused.
- deps: node-pty, ws, @xterm/{xterm,addon-fit,addon-clipboard,headless,addon-serialize}
land in root package.json (no workspaces field in the repo); node-pty added to
trustedDependencies so a fresh install builds its native binary.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port the A/B "fresh" substrate into packages/genie-ui/server as TypeScript: - fleet-config: loadFleet() -> PaneSpec[], grown with the genie seams wishId + role. - pty-session: PtySession + PtySessionManager (startAll/spawn/kill/restart/write/ resize/replay/list/killAll; events data/exit/status = idle/running/exited). THE single node-pty importer. - transport: the ws protocol codec (FLEET/DATA/EXIT/STATUS/REPLAY/INPUT/RESIZE/ SPAWN/KILL/RESTART/LIST) as a typed pure codec. - reused/TerminalMirror.ts: salvaged verbatim from dash (syv-ai/dash, MIT) as the replay path, replacing fresh's 256 KB raw-byte ring. Verified under bun: the createRequire loader for @xterm/headless + @xterm/addon-serialize round-trips serialize() with SGR styling (design R4) — no loader change, no ring fallback. Imported only by pty-session. - index: thin composition root + the bun-native serve path (no Vite) — one node http server serves the client (Bun.build of the single entry) and upgrades to the bare ws PTY protocol on the same port. Colocated bun:test: pty-session (spawn/kill/restart + status/exit events) and the TerminalMirror serialize/replay round-trip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The browser client, served by the bun-native path (no Vite):
- pane: one @xterm/xterm 5.5 Terminal + FitAddon per pane, ClipboardAddon wired
through the salvaged Utf8Base64 (UTF-8 OSC-52), and the salvaged FitScheduler
debouncing refits via a ResizeObserver. Each pane is a split-cell with a header
(role badge, status dot, per-pane spawn/kill/restart/split/max/close).
- layout: vanilla reimplementation of Lane A's grid concept — tabs (swap the
visible agent), horizontal splits (2+ side-by-side cells), maximize. Panes stay
mounted; the layout only toggles visibility so scrollback survives switching.
- transport: typed ws client, same-origin (server serves assets + ws on one port),
reconnecting.
- main: roster-driven composition; talks to the server exclusively over transport.
- reused/{Utf8Base64,FitScheduler}.ts: salvaged verbatim from dash (MIT).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- README: module map + provenance, the pinned no-Vite serve decision, the TerminalMirror-under-bun (R4) outcome, and the no-workspaces deps call. - qa.md: the AC2-substrate manual QA — local pane render -> TerminalMirror -> reattach-identical replay (proven), ssh localhost key auth (proven), the bun-native serve path + ws FLEET handshake (proven), and the lifecycle events. Records the nested-sandbox PTY-SIGHUP limitation that blocks live btop/ssh -t frames + browser splits here, flagged operator-confirm on the real box. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MSG.INPUT feeds arbitrary keystrokes into live login shells, so the ws upgrade is a remote-control surface. Close it by default: - server.listen now binds HOST (default 127.0.0.1); LAN reach (mac + phone) is opt-in via HOST=0.0.0.0, not the implicit all-interfaces bind. - WebSocketServer gains verifyClient: a browser Origin must be same-origin with the page host (any LAN hostname, no config) or on the explicit GENIE_UI_ALLOWED_ORIGINS allowlist. Browsers always send Origin, so this defeats a cross-origin drive-by into the shells; no-Origin CLI/test clients stay gated by the loopback bind. Records the trust boundary as an explicit decision in the package README (the seam G2/G3 build on) and adds colocated verifyClient regression tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
refreshTab and renderMeta interpolated PaneInfo fields (name, role, command, args, wishId) straight into innerHTML. Config-trusted today, but the SEAM comment marks this tab strip as where G2 feeds genie state (wish slugs, markdown-derived roles) — a wish title must not inject markup. Add an esc() helper and wrap every string interpolation before G2 lands. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-remediation docs(wish): plan Codex task-CWD remediation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Important Review skippedToo many files! This PR contains 114 files, which is 14 over the limit of 100. To get a review, narrow the scope: Upgrade to a paid plan to raise the limit. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (114)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9610fb56a9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ate-mode contract is live Design SHIP (digest 84cb10c4…) after one fix-first round; plan SHIP after two; G1/G3/G2 all execution-reviewed SHIP (one G3 fix loop: loopback bind); branch merged to khal-os/genie-desktop main 5a17077. ITERATE.md is the durable loop contract; genie memory carries the pointer. Wish IN_PROGRESS pending Felipe-live QA. Ledger pm-verified (2 must-fix INDEX-drift findings fixed; SC boxes checked per review evidence). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…inding verifyClient trusted new URL(origin).host === host unconditionally. both Origin and Host are browser-set, so DNS rebinding (evil.com -> 127.0.0.1) presents Origin === Host === evil.com:PORT and passed the check, opening MSG.INPUT -> proc.write() into a live login shell (RCE). the same-origin branch now additionally requires the real Host hostname to be a loopback identity; non-loopback hosts fall through to the existing GENIE_UI_ALLOWED_ORIGINS allowlist. adds a named rebinding regression test, inverts the old any-LAN-host test, and corrects the README trust-boundary claim. found by ultracode review of PR #2619.
live-dev-loop ledger: pm-verified, CI 11/11.
…ding fix(genie-ui): defeat DNS rebinding on the ws PTY trust boundary
packages/genie-ui was the original fresh-substrate UI (PR #2609), superseded 2026-07-21 when Felipe rejected the substrate live and the UI direction moved to genie-ui-dash in the private khal-os/genie-desktop repo. it was never promoted to main; the docs superseded it but the code kept squatting on dev. removes the standalone package (@automagik/genie-ui, private) and its 9 root-package deps that nothing in src/ imports (@agentclientprotocol/sdk, node-pty-prebuilt-multiarch, 5x @xterm/*, ws, @types/ws), plus the gate touchpoints: typecheck leg, tsconfig reference, biome packages/** override, knip entries/project, complexity-budget scan scope. the sanctioned genie ui-bridge command (src/term-commands/ui-bridge.ts) stays — it is the stdio MCP channel the private UI spawns, not the shell. gate: typecheck/lint/dead-code/complexity-budget clean; 2343 tests pass (the single ui-bridge 'ss' failure is a pre-existing linux-only test, absent on darwin, byte-unchanged here).
…enie-ui chore(genie-ui): remove superseded browser-shell package from the OSS tree
…liveness releaseTask cleared claimed_by/claimed_at but left heartbeat_at, so after a release the card kept the prior owner's pulse. when a new worker checked it out, the liveness badge computed from the old heartbeat and could show a fresh checkout as running (▶) before it ever pulsed. clear heartbeat_at in the same conditional UPDATE; add a regression test (release → heartbeatAt null → survives re-claim). found by codex PR review of automagik-dev#2619 (P2).
No description provided.