# dsh-ccTUI — Staged Porting Plan Goal: port the **clawcodex `ui-tui`** TypeScript terminal UI (Claude-Code-style look, feel, and interactions) to a **deepseek-harness plugin**, using **dsh-TUI** as the packaging/integration skeleton reference. Reference material (gitignored, vendored locally under `reference_projects/`): | Project | Role | |---|---| | `reference_projects/clawcodex/ui-tui` | The TUI to port: ~41k LOC React app + ~29k LOC forked Ink renderer (`packages/dsh-cctui-ink`). MIT. | | `reference_projects/dsh-TUI` | A proven claude-code-style TUI plugin for deepseek-harness; we borrow its packaging skeleton and integration patterns. MIT. | | `reference_projects/deepseek-harness` | The harness itself (docs + source). Published on npm as `@deepseek-ai/*@0.1.0-rc.7`. | ## Core architectural insight The clawcodex TUI has exactly **one backend seam**: `src/gatewayClient.ts` (~2.9k LOC). It spawns the Python backend as a subprocess and translates NDJSON into an app-facing contract: - an `EventEmitter` emitting a **44-member `GatewayEvent` union** (`message.delta`, `tool.start`, `approval.request`, …) defined in `src/gatewayTypes.ts`, and - a `request(method, params)` promise RPC surface (~75 dotted methods: `prompt.submit`, `session.list`, `approval.respond`, …) where **unhandled methods gracefully resolve `{}`**. Everything above that seam (157 non-test files) is backend-agnostic. Therefore the port is: 1. **Copy the app + the Ink fork wholesale** (preserving look/feel/interactions by construction). 2. **Replace only the gateway client internals** with an in-process implementation over deepseek-harness services (`ctx.agents`, `session/event`, `approval/request` waterfall, `ctx.userQuestions`, `ctx.commands`, `ctx.sessionPersistence`, …). The graceful-degradation design means the TUI runs early and features light up RPC-by-RPC. 3. **Package as a cordis bundle plugin** (`package.json` → `"dsh": {"bundle": {"patch": "./cordis.patch.yml"}}`), installable with `dsh plugin --profile

add ` and launched with `dsh --profile

`, following dsh-TUI's proven skeleton (peerDeps on `@deepseek-ai/*`, adapter boundary, exit funnel, `NODE_ENV=production` for React). The full event/RPC mapping is in [ARCHITECTURE.md](./ARCHITECTURE.md). ## Working agreements - Each stage: implement → test → PR → merge → next stage. Branch names `stage-N-`. - English is the project language (code, docs, commits, UI strings). - Tests per stage: `tsc --noEmit` + `vitest run` (ported suites) and, from Stage 4 on, scripted end-to-end boots of the real harness (`@deepseek-ai/dsh` rc.7) with a **scripted LLM plugin** (no API key exists in dev/CI; the mock replays canned deltas/tool calls). - Features whose backend doesn't exist in the harness stay as gracefully-degrading stubs: billing/credits, voice, pets, browser progress, worktree exit flow, rollback. The UI code remains; the RPCs resolve `{}` / events never fire. - Provenance: clawcodex and dsh-TUI are MIT; attribution kept in `NOTICE.md`. ## Stages ### Stage 1 — Plan & scaffolding (this PR) Deliverables: `docs/PLAN.md`, `docs/ARCHITECTURE.md`, `README.md`, `LICENSE`, `NOTICE.md`, `.gitignore`. Acceptance: docs merged to `main`. ### Stage 2 — Toolchain + vendored Ink fork - Root `package.json` (`dsh-cctui`, ESM, React 19, `file:` dep on the fork), `tsconfig.json`, `vitest.config.ts`, CI workflow (typecheck + vitest). - Vendor `packages/dsh-cctui-ink` unchanged (esbuild build, root `index.js` shims). - Acceptance: fork builds; its own unit tests pass; a headless `renderSync` smoke test renders Box/Text into a fake stdout; CI green. ### Stage 3 — App source copy compiles; unit suite green (null gateway) - Copy `src/` app + tests from ui-tui. Keep `gatewayTypes.ts` verbatim (it is the contract). - Replace `gatewayClient.ts` with the same class surface backed by a **null backend** (no subprocess; RPCs resolve `{}`), keeping `SLASHES` catalog and pure helpers. - Adapt/skip subprocess-specific tests with a documented list; everything else must pass. - Acceptance: `tsc --noEmit` green; `vitest run` green; headless mount of `AppLayout` renders the banner/composer. ### Stage 4 — Harness plugin boots; core conversation loop works - `src/harness/` adapter (the only dir importing `@deepseek-ai/*`): plugin entry (`name`/`inject`/`Config`/`apply`), TTY guard, exit funnel, React mount; `cordis.patch.yml` + dev `cordis.yml`; `HarnessGatewayClient` v1: - boot: agent create/resume → `gateway.ready` + `session.info`; - `prompt.submit` → `agent.followup()` / busy → `agent.steer()`; `session.interrupt` → `agent.cancel({kind:'user'})`; - `session/event` → `message.delta` (assistant/chunk text), `thinking.delta` (reasoning chunks), `tool.start` (tool/call), `tool.complete` (tool/result), `message.complete` (assistant/message + turn/end), busy state from `agent/status`. - Scripted-LLM e2e: a tiny test-only cordis plugin registering a canned LLM adapter; PTY/headless boot asserts prompt→stream→tool→result renders in the transcript. - Acceptance: `dsh --profile cc` (dev profile) shows the clawcodex UI and completes a scripted turn end-to-end. ### Stage 5 — Interaction gates - `approval/request` waterfall → `approval.request` → ApprovalPrompt → outcomes (`allowed-once`/`rejected`); pairing with streamed `tool/call` via `callId`. - `ctx.userQuestions.registerProvider` → `question.request` → AskUserQuestion panel; plan-review intent → PlanApprovalPrompt; plan mode via `ctx.planMode`. - Permission modes: map clawcodex `default/plan/acceptEdits/bypassPermissions` onto harness approval policy + permission presets + plan mode; Shift+Tab cycle; footer badges. - Acceptance: e2e scripts covering approve/deny, question answer/cancel, mode cycling. ### Stage 6 — Sessions - `session.list`/`active_list`/`resume`/`create`/`close`/`delete`/`title`/`stats` over `ctx.agents`, `ctx.sessionPersistence`, `ctx.sessionProjections`; transcript rehydration from the session event log on resume; Ctrl+X switcher; `/clear`, `/new`, `/rename`, `/resume`. - Acceptance: e2e resume of a prior scripted session shows the replayed transcript. ### Stage 7 — Slash commands, completions, model picker, config - Merge local registry + `ctx.commands` catalog (`commands.catalog`, `slash.exec`, `command.dispatch`, `commands/change` refresh); `complete.slash` + `complete.path`. - `/model` via `ctx.llm` catalog + `installModelSelection` + `ctx.agentDefaultModel`; `/compact` via `ctx.compaction`; `/status`, `/help`, `/usage`; `config.get/set` over a `dsh-cctui` settings namespace. - Acceptance: e2e slash dispatch of a harness-registered command; model switch reflected in `session.info`. ### Stage 8 — Rich rendering & telemetry - Structured diffs: tool `presentCall/presentResult` Diff views → `StructuredDiffPayload` (colorDiff pipeline); terminal views → tool trail output; `todo/write` → TodoPanel; token usage/context bar via `ctx.tokenMeter` + `resolveModelInfo`; subagent progress (`ctx.subagents` → `subagent.*`); goal indicator (`ctx.goals`); notices. - Acceptance: e2e scripted Edit tool shows the diff card; todos render; context % moves. ### Stage 9 — Packaging, launcher, final QA - `bin/dsh-cctui.js` launcher (profile bootstrap via `dsh plugin add`, version-skew guard, `NODE_ENV=production`), `install.sh`, packaged `files` list, README usage docs. - Fresh-`DSH_HOME` install e2e from a local checkout; tag `v0.1.0`. - Acceptance: `./install.sh` on a clean profile launches the TUI. ## Status log - 2026-08-18: Stage 1 merged (#1). Stage 2 merged (#2) — fork vendored, 129 fork tests green. - 2026-08-18: Stage 3 merged (#3) — verbatim app copy, 1879 tests green, AppLayout mounts headless. - 2026-08-18: Stage 4 merged (#4) — harness gateway: real dsh boots the TUI as a cordis plugin; scripted end-to-end turn passes in a PTY e2e (also in CI). - 2026-08-18: Stage 5 merged (#5) — gates: approvals (sandbox escalation e2e round-trip), user questions, plan review, permission-mode cycle. - 2026-08-18: Stage 6 merged (#6) — sessions: live-agent registry, resume/activate with transcript rehydration, session list/close/title; two-phase resume e2e. - 2026-08-18: Stage 7 merged (#7) — command bridge, /model + effort via llm catalog with persisted selection, token-meter usage/context bar. - 2026-08-18: Stage 8 merged (#8) — presentation views (diff cards via structuredPatch, terminal/search views), todos rider, tool.generating, resume stats. - 2026-08-18: Stage 9 merged (#9) — packaging: install.sh + bin launcher, installed-path e2e via real `dsh plugin add` (in CI), README. - 2026-08-18: **v0.1.0 tagged — all nine stages complete.** The clawcodex TUI runs as a deepseek-harness plugin: conversation loop, tool trail + diff cards, approvals, questions, plan review, permission modes, sessions/resume, command bridge, model picker, usage metering, checkout-based install. Remaining ideas live in PORTING-NOTES (skipped upstream test skew, features with no harness backend). - 2026-08-18: v0.2.1 — ocean-blue brand ramp + DeepSeek-blue theme hue; the app owns `~/.dsh-cctui` (no longer reads clawcodex's config); `/logo` persistence implemented; banner colors now regression-tested.