ResearchShared TUI Extraction

02 - Donor Audit

02 - Donor Audit

Current repository facts

crates/jackin-tui is Apache-2.0, version 0.6.0-dev, and publish = false. It depends on Ratatui, Crossterm, Tokio, and jackin-core plus focused rendering helpers. crates/jackin-tui-lookbook is an Apache-2.0 binary over the component crate.

The two source trees contain 77 Rust files and 17,033 lines. jackin-tui has 246 #[test]/#[tokio::test] attributes and the lookbook has 15. There are 24 top-level component implementation files, 29 committed SVG previews, and 18 donor Rust files that use Ratatui TestBackend. These numbers were measured on 2026-07-15 at donor revision 33896a504e19ef13adb8692550c1845cb86a9504 with find, wc -l, and rg; test attributes measure declared test functions, not parameter-expanded executions.

Outside the two donor crates, 195 Rust files reference jackin_tui. Grouped by package path, the largest consumers are jackin-console (105 files), jackin-capsule (42), and jackin-launch-tui (26). This should be treated as a mature donor with compatibility obligations, not a new empty crate. The complete migration grouping and measurement method are in 08 - Migration evidence and gates.

Dependency inversion to remove

The shared-looking crate imports or re-exports from jackin-core:

  • shorten_home;
  • pointer/OSC52 ANSI helpers;
  • TailScroll, scrolling calculations, and line-width helpers;
  • DialogBodyScroll and status-footer hover state;
  • bottom-chrome geometry and constants.

Some of these neutral TUI types also exist as compatibility copies or lower-layer definitions, creating the wrong direction for an external component library. Move neutral TUI ownership to the external component crate, migrate callers, then remove duplicates. shorten_home is explicitly not part of that move: it reads process environment, is used by non-TUI commands, and remains a jackin-core path-display helper; remove only the jackin-tui re-export. Product configuration and agent/container types remain outside.

Extract into the shared project

Chapter 09 - Component redesign catalog fixes the redesign tier per item: some of these move with naming cleanup only, others are reimplemented behind the same contract before publication. This list states what TermRock ends up owning, not that every item moves verbatim.

  • display-column measurement, terminal text sanitization, and bounded text helpers;
  • key/input normalization and focus ownership;
  • hover tracking and scroll state/math, retaining the maintained tui-scrollbar dependency that owns the proportional thumb metrics;
  • the terminal mode session, reimplemented partial-initialization-safe under the optional crossterm feature;
  • ANSI text parsing;
  • pure OSC 8/22/52 escape encoding and pointer-shape naming (PointerShape), extracted as typed request/encoder data with no emission;
  • executor-neutral runtime contracts plus the persistent drive_frame and one-shot drive_render frame drivers in a base module that is optional by use and required by no widget;
  • Panel, TabStrip, ButtonStrip, confirmation/error dialogs, hints, scrollable panel/list, selection list, text input plus a documented filter composition/preset, toast, and diff view — no separate public FilterField, while status-popup behavior folds into the generic message/toast surface without a dedicated public type;
  • modal backdrop, pure inside/outside hit classification, and generic dialog layout — modal stack, parent-chain lifecycle, and application routing remain consumer-local;
  • lookbook registry, interactive driver, SVG/golden renderer, and fixture runner;
  • neutral component catalog pages and the generated-preview workflow that feeds them.

Parameterize before publishing

  • replace global color constants with semantic Theme tokens such as accent, surface, border, danger, warning, success, selection, and link;
  • retain a default Tailrocks phosphor theme as a preset;
  • replace hardcoded jackin❯ brand output with consumer-provided brand/header data;
  • make bottom chrome, tabs, status, badges, hints, and actions data-driven;
  • replace use-case-specific modal rectangle functions with generic responsive dialog specifications;
  • keep Tokio subscription helpers consumer-owned so widgets never force an executor, while the executor-neutral contracts and frame driver move to the shared base runtime module, optional by use;
  • define public state IDs and callbacks/messages without consumer domain types;
  • give the shared tab strip per-tab glyph/state slots and stable click regions, and cover Capsule's wrapped-hint behavior in the hint bar, so the Capsule status bar and hint rows can converge on shared widgets after parity;
  • derive the lookbook SVG color table from the shared theme values instead of the duplicated hex table hardcoded in the SVG writer today;
  • turn the preview binary into the external project's documented terminal/render/check CLI without retaining jackin❯ paths or wording.
  • standardize logical scroll offsets, lengths, and indices on usize; clip values in logical space, then convert terminal geometry through one centralized saturating u16 edge helper.

Keep in jackin❯

  • agent display names, roles, workspaces, container/Capsule information, and host-container color mapping;
  • launch digital-rain and closing animations with product-specific meaning;
  • OnePassword, role, scope, mount, and project-specific pickers;
  • file browser and application editors;
  • jackin❯ brand composition and status policies;
  • terminal-ownership process globals (rich-surface/host-screen atomics) and title/alternate-screen policy;
  • direct CLI output and output-pruning helpers; a pure bounded-lines projection may graduate later under the two-consumer rule;
  • Tokio subscription implementations, spawn helpers, and the fallback runtime in jackin-console;
  • shorten_home and other environment-aware path-display policy in jackin-core;
  • product palette tokens (CAPSULE_MENU_*, BRAND_BLOCK, DEBUG_AMBER, TAB_BG_*, rain colors) as local constants layered on top of the semantic theme;
  • lookbook stories and fixtures containing agents, roles, workspaces, containers, or product paths;
  • jackin❯ product interaction decisions and composition docs, which may link to the external component catalog rather than duplicate its generic API pages.

Known defects and stale artifacts

Extraction is bug-compatible: these are recorded at freeze and fixed only after jackin❯ parity passes, per the sequencing decision in 05 - Decision record.

  • character-count width math instead of display columns in HintSpan::display_cols, select-list label measurement, the status-footer right group, and error-dialog wrap math;
  • panel focus signaled by border color alone, with no non-color cue;
  • three parallel color layers (Rgb constants, Ratatui Color constants, raw ANSI string helpers) plus a fourth duplicated hex table inside the lookbook SVG writer;
  • hyperlink overlays returned as raw post-frame byte vectors from the error and container-info dialogs;
  • COMPONENTS.md references a lookbook binary and in-crate story module that no longer exist, and the crate-root docs name a Theme type that was never implemented — both corrected at freeze;
  • the lookbook SVG drift check (tui-lookbook --check) is a documented CLI command that no CI workflow currently runs, so committed fixtures are not mechanically proven current; wiring it into jackin❯ CI is a freeze prerequisite.

Module-level review rule

The classification above is a starting point, not permission for a bulk move. Before extraction, create a ledger for every public export containing:

  • current owner and every caller;
  • dependency graph and feature requirements;
  • product vocabulary or assumptions;
  • tests and render fixtures that define behavior;
  • component documentation, generated SVGs, and preview CLI behavior that must move with it;
  • target decision: extract, parameterize, remain local, or remove;
  • semver/API notes.

No module moves merely because its filename sounds generic.

Signatures that must change before publication

  • SelectListState owns Vec<String>, reports indices, hardcodes ASCII substring filtering and action labels, and measures width with character count rather than display columns. Separate consumer rows from interaction state, use stable IDs, and make filtering/hints inputs.
  • TextField combines cursor/edit state, forbidden-value validation, and save/cancel wording. Make editing Unicode/display-width aware and validation/action wording consumer-owned.
  • StatusFooter names container/run/usage concepts. Replace it with generic data-driven slots and retain product composition locally.
  • ContainerInfoState/DebugInfo combine reusable detail rows with agent, role, container, and version fields. Extract a neutral detail/inspector widget; keep the builder in jackin.
  • modal rectangle modes expose auth, role, mount, source, scope, and operation cases. Replace them with generic min/preferred/max responsive specifications.
  • runtime helpers create Tokio channels/tasks and even a fallback runtime. Extract the executor-neutral contracts (Dirty, UpdateResult, SubscriptionPoll, Subscription, Component, View) and the pure Ratatui drive_frame/drive_render drivers into the base runtime module, which is optional by use rather than feature-gated; Tokio receiver implementations and spawn helpers stay in jackin❯, connecting to the shared subscription trait through its closure adapter because coherence forbids implementing it directly for Tokio receiver types.
  • terminal ownership contains jackin process-global flags and title/screen policy. Do not extract it as the generic lifecycle API.

The proposed replacements and semver constraints are in 06 - Public API and refactoring.

On this page