Selaa lähdekoodia

docs(tui): remove completed extraction plan

Kit Langton 1 päivä sitten
vanhempi
sitoutus
c42c7f7793
1 muutettua tiedostoa jossa 0 lisäystä ja 641 poistoa
  1. 0 641
      specs/tui-package.md

+ 0 - 641
specs/tui-package.md

@@ -1,641 +0,0 @@
-# TUI Package Extraction
-
-## Goal
-
-Move the canonical OpenCode terminal application from
-`packages/opencode/src/cli/cmd/tui` into a self-contained workspace package while
-the legacy CLI and the new CLI continue to use the same implementation.
-
-Target package:
-
-```text
-packages/tui
-name: @opencode-ai/tui
-```
-
-Target dependency graph:
-
-```text
-packages/opencode ---\
-                      > @opencode-ai/tui -> @opencode-ai/sdk
-packages/cli --------/
-```
-
-The TUI may directly depend on terminal and UI infrastructure such as
-`@opentui/core`, `@opentui/solid`, `@opentui/keymap`, `solid-js`, Effect, and
-generic presentation libraries. It must not depend on `packages/opencode`,
-`packages/cli`, or `@opencode-ai/core`.
-
-The SDK is the TUI's OpenCode boundary. Missing backend data or operations must
-be added to the server API and generated SDK rather than imported from backend
-implementation modules.
-
-## Migration Rules
-
-- Keep one canonical implementation of every TUI feature. Do not copy the full
-  TUI into `packages/cli` and synchronize two trees.
-- Land each section below independently and commit it before starting the next
-  section.
-- Keep each intermediate commit buildable and type-safe.
-- Continue integrating team changes into whichever location is canonical for a
-  file at that point in the migration.
-- Use temporary compatibility re-exports only when they materially reduce the
-  size or conflict risk of a section. Mark them for removal in a later section.
-- Do not preserve private imports by creating aliases from `packages/tui` back
-  into `packages/opencode`.
-- Do not replace private `packages/opencode` imports with `@opencode-ai/core`
-  imports merely to make the package compile.
-- Keep tool rendering tolerant of unknown tools and wire-format changes. Local
-  checks over `unknown` input and metadata are acceptable; importing backend
-  tool implementations for type safety is not.
-- Keep legacy CLI command parsing, server startup, worker management,
-  authentication, and config discovery outside `@opencode-ai/tui`.
-
-## Ownership Boundary
-
-### `@opencode-ai/tui` Owns
-
-- OpenTUI renderer lifecycle shared by both CLI hosts
-- Solid application composition
-- Components, routes, dialogs, themes, keymaps, and UI primitives
-- SDK client synchronization and event consumption
-- Tool-call and tool-result presentation
-- TUI-facing plugin contracts and presentation slots
-- Resolved TUI configuration types, defaults, and pure validation
-- Terminal behavior such as selection, clipboard integration, and local editor
-  launching when it is not host-specific
-- TUI-local persistence such as prompt history, stash, frecency, selected model,
-  and selected theme
-- Presentation utilities such as locale formatting, error display, record
-  checks, duration formatting, and layout helpers
-
-### CLI Hosts Own
-
-- Command definitions and argument parsing
-- Starting, locating, and stopping servers and workers
-- Authentication and transport construction
-- Process-level signal policy
-- Config file discovery, precedence, migration, and environment substitution
-- Plugin package discovery, installation, and backend activation
-- Upgrade checks and installation metadata
-- Executable build wiring and worker path defines
-
-### Server And SDK Own
-
-- OpenCode domain data displayed by the TUI
-- Session, message, workspace, file, provider, model, agent, and permission
-  operations
-- Retry, revert, fork, share, and other backend actions
-- Stable wire shapes for tool parts and plugin metadata
-- Server capabilities needed to conditionally expose UI behavior
-
-## Current Boundary
-
-The canonical implementation currently lives under:
-
-```text
-packages/opencode/src/cli/cmd/tui
-```
-
-Its private dependency on `packages/opencode` is primarily expressed through
-the `@/*` TypeScript alias, which resolves to `packages/opencode/src/*`.
-`@tui/*` imports are internal to the TUI and are not themselves a package
-boundary problem.
-
-The main private dependency groups are:
-
-- `@/util/*`: presentation helpers plus filesystem/process/RPC helpers
-- `@/tool/*`: backend tool implementations used by renderers
-- `@/session/*`, `@/provider/*`, and `@/reference/*`: backend data and actions
-- `@/config/*`: config discovery, parsing, variables, and plugin resolution
-- `@/plugin/*`: plugin loading and installation
-- `@/cli/*`: yargs adapters, network setup, errors, and CLI presentation
-- `@/server/*`: authentication and embedded server behavior
-- `Global.Path`, `Flag`, and process environment reads
-
-The initial extraction should reduce these dependencies in place before moving
-the application root.
-
-## Section 1: Create The Package Skeleton
-
-Status: Completed. The private `@opencode-ai/tui` workspace package now has an
-independent OpenTUI Solid JSX configuration, narrow root export, package-local
-alias, and in-memory render smoke test. Neither CLI consumes the package yet.
-
-Create `packages/tui` without moving the application root yet.
-
-Tasks:
-
-- Add `packages/tui/package.json` with the name `@opencode-ai/tui`.
-- Add a package `tsconfig.json` configured for OpenTUI Solid JSX.
-- Add `bunfig.toml` with the OpenTUI Solid preload for package-local development
-  and tests.
-- Add package scripts for `typecheck` and package-local tests.
-- Add direct dependencies used by the TUI. Do not rely on workspace hoisting.
-- Add a narrow package export, initially only the package root and any explicit
-  testing entrypoint needed by migrated tests.
-- Establish a package-local import convention. A local alias such as `@tui/*`
-  is acceptable, but it must resolve entirely inside `packages/tui`.
-- Add a minimal package entrypoint and smoke test proving OpenTUI Solid TSX can
-  typecheck and render.
-- Do not make either CLI consume the package yet.
-
-Exit criteria:
-
-- `packages/tui` typechecks independently.
-- Its test command runs from `packages/tui`.
-- The package has no dependency on `opencode`, `@opencode-ai/cli`, or
-  `@opencode-ai/core`.
-
-Checkpoint commit:
-
-```text
-feat(tui): add standalone package skeleton
-```
-
-## Section 2: Move Presentation Utilities And Leaf UI
-
-Status: Completed. Presentation utilities, bundled themes and their pure theme
-engine, keybinding/keymap mechanics, and low-coupling border, link, and spinner
-primitives now live in `@opencode-ai/tui`. The legacy host consumes explicit
-package exports and retains only integration wrappers or compatibility
-re-exports where backend and process concerns have not moved yet.
-
-Move low-coupling code first so subsequent team changes land in the new package
-without waiting for the application root migration.
-
-Tasks:
-
-- Move TUI presentation utilities into `packages/tui/src/util`, including the
-  portions of locale, error display, record checks, duration formatting, and
-  small functional helpers used by TUI code.
-- Move pure TUI utilities already under the old TUI directory.
-- Move themes and bundled theme JSON files.
-- Move UI primitives and leaf components that have no private backend imports.
-- Move pure keybinding schemas and keymap helpers that do not read host flags.
-- Move related unit and snapshot tests.
-- Update remaining old-tree consumers to import the new canonical modules.
-- Use temporary compatibility re-exports from old TUI paths only if needed to
-  avoid a large unrelated import rewrite.
-- Do not move `Filesystem`, `Process`, `Rpc`, worker startup, or config discovery
-  as generic utilities in this section.
-
-Exit criteria:
-
-- Moved files have no `@/...` imports.
-- Tests for moved code run from `packages/tui`.
-- Existing legacy TUI behavior and typecheck remain unchanged.
-
-Checkpoint commit:
-
-```text
-refactor(tui): move presentation utilities and primitives
-```
-
-## Section 3: Remove Backend Tool Implementation Imports
-
-Status: Completed. Legacy and V2 tool renderers now dispatch on SDK wire names,
-accept `Record<string, unknown>` input and metadata, and use local guards for
-nested presentation data. Web-search labels and structured metadata extraction
-are TUI-owned, unknown tools retain the generic fallback, and no TUI source
-imports backend tool implementations. The route components remain in the legacy
-tree until the SDK state and route move in Section 6.
-
-Make tool rendering depend only on SDK wire data and local presentation logic.
-
-Tasks:
-
-- Remove imports from `@/tool/*` in TUI routes and feature plugins.
-- Key built-in renderers by SDK tool name strings such as `read`, `write`,
-  `edit`, `apply_patch`, `grep`, `glob`, `bash`, `question`, and `task`.
-- Treat tool input, output metadata, and plugin-defined fields as `unknown` at
-  the package boundary.
-- Add small local type guards only where a renderer needs a particular field.
-- Preserve a generic fallback renderer for unknown and plugin-provided tools.
-- Keep renderer failures local: malformed metadata must not crash the entire
-  session view.
-- Replace backend-derived labels or IDs with TUI-owned presentation constants or
-  SDK-provided values.
-- Move the affected tool presentation components and tests to `packages/tui`.
-
-Exit criteria:
-
-- No TUI source imports `@/tool/*`.
-- Unknown tools render through the generic fallback.
-- Existing built-in tool snapshots remain equivalent unless intentionally
-  updated and reviewed.
-
-Checkpoint commit:
-
-```text
-refactor(tui): decouple tool rendering from backend tools
-```
-
-## Section 4: Make Runtime Inputs Explicit
-
-Status: Completed for the shared runtime contract and legacy host. The TUI now
-receives immutable launch-directory, path, capability, terminal/editor, startup,
-and build inputs through `@opencode-ai/tui/runtime`. Movable app, component,
-route, and feature-plugin code no longer reads OpenCode globals or process state;
-command, config, plugin-loading, custom-theme discovery, editor/clipboard, and
-Windows lifecycle adapters remain host-owned. `packages/cli` does not consume
-this contract yet; that integration remains deferred to Section 9.
-
-Replace process-global OpenCode state with resolved TUI inputs.
-
-Define narrow inputs rather than one unstructured host object. Expected groups
-include:
-
-```ts
-type TuiCapabilities = {
-  mouse: boolean
-  copyOnSelect: boolean
-  terminalTitle: boolean
-  workspaces: boolean
-  showTimeToFirstDraw: boolean
-}
-
-type TuiPaths = {
-  home: string
-  state: string
-  config: string
-  data: string
-}
-
-type TuiBuildInfo = {
-  version: string
-  channel?: string
-}
-```
-
-Tasks:
-
-- Inventory direct reads of `Flag`, `Global.Path`, and relevant environment
-  variables in movable TUI code.
-- Pass resolved capabilities into the application/provider tree.
-- Pass local path roots or a narrow TUI storage capability into persistence
-  contexts.
-- Pass build/version information explicitly.
-- Keep environment reads needed by legacy command or worker startup in
-  `packages/opencode` adapters.
-- Give `packages/tui` sensible host-neutral defaults only when behavior is truly
-  local to a terminal client.
-- Move contexts and components after their global dependencies are removed.
-
-Exit criteria:
-
-- Movable TUI code does not import `Flag` or `Global`.
-- TUI tests can supply deterministic capabilities and storage paths.
-- The legacy host constructs the required input through the public package API;
-  the new CLI integration remains deferred to Section 9.
-
-Checkpoint commit:
-
-```text
-refactor(tui): make runtime capabilities explicit
-```
-
-## Section 5: Separate Resolved TUI Config From Host Config Loading
-
-Status: Completed for the package config contract and legacy host adapter.
-`@opencode-ai/tui/config` now owns schemas, defaults, keybind resolution, the
-resolved config type, and the Solid config provider. The legacy host retains
-file discovery, precedence, JSONC parsing, substitutions, migration,
-source-relative sound paths, plugin origins, dependency installation, and
-Effect services. `packages/cli` remains untouched until Section 9.
-
-Move config semantics needed by rendering while retaining filesystem discovery
-and migration in the legacy host.
-
-Tasks:
-
-- Move TUI config schemas, keybind schemas, defaults, and pure resolution to
-  `packages/tui`.
-- Define the resolved config accepted by the public TUI entrypoint.
-- Keep config path discovery, project/global precedence, migration, variable
-  expansion, and plugin package installation in `packages/opencode` initially.
-- Make the legacy host produce the same resolved config shape.
-- Add a new CLI adapter that can initially provide defaults or its own resolved
-  configuration.
-- Update schema-generation imports to use the package's explicit config export
-  if schema generation still needs TUI schemas.
-- Move pure config tests; retain discovery and migration integration tests in
-  `packages/opencode`.
-
-Exit criteria:
-
-- `packages/tui` does not import `@/config/*`.
-- Config discovery can change without changing TUI rendering code.
-- The old CLI still honors existing config precedence and migration behavior.
-
-Checkpoint commit:
-
-```text
-refactor(tui): separate config resolution from loading
-```
-
-## Section 6: Move SDK State, Routes, And Backend Operations
-
-Status: Completed for the SDK/domain boundary. SDK, project, event, legacy sync,
-V2 sync, local model state, prompt persistence, and pure prompt helpers are now
-canonical in `@opencode-ai/tui`. Configured references resolve through the new
-generated `reference.list` SDK operation; prompt payloads rely on optional
-server-assigned IDs; local attachment reads use the package platform contract.
-Legacy route files remain in place until the plugin slot boundary and app-root
-move, but their only private dependencies are plugin presentation or local host
-adapters rather than OpenCode domain implementations.
-
-Make the SDK the only OpenCode domain boundary used by the TUI.
-
-Tasks:
-
-- Move SDK client providers, event synchronization, routes, prompt UI, and
-  session views into `packages/tui`.
-- Replace direct imports from `@/session/*`, `@/provider/*`, `@/reference/*`,
-  `@/lsp/*`, and other backend domains with SDK data or TUI-owned presentation
-  helpers.
-- Replace direct backend actions such as retry with SDK calls.
-- For each missing operation, add or adjust the server endpoint, regenerate the
-  JavaScript SDK with `./packages/sdk/js/script/build.ts`, and consume the
-  generated SDK API.
-- Keep transport creation outside the package. Accept a base URL, headers,
-  custom fetch, event source, or constructed SDK client as appropriate.
-- Keep local-only UI state in the TUI package rather than adding it to the
-  server API.
-- Move affected tests and fixtures. Use real SDK/server integration where
-  practical instead of mocking backend modules.
-
-Exit criteria:
-
-- Domain-facing TUI code imports OpenCode data and operations only from
-  `@opencode-ai/sdk`.
-- No TUI source imports private session, provider, reference, LSP, server, or
-  core domain implementations.
-- SDK generation is clean after any API changes.
-
-Checkpoint strategy:
-
-This section may be split into multiple commits when an SDK gap is substantial.
-Each commit must leave both the old TUI host and package tests working. Suggested
-commit pattern:
-
-```text
-feat(sdk): expose <operation> for tui clients
-refactor(tui): move <area> to sdk boundary
-```
-
-Final section checkpoint:
-
-```text
-refactor(tui): move sdk state and routes into package
-```
-
-## Section 7: Isolate Plugin Presentation From Plugin Loading
-
-Status: Completed. Plugin slots, route registration, TUI-facing APIs, runtime
-presentation state, and built-in feature plugins now live in
-`@opencode-ai/tui`. The legacy host injects a narrow plugin host that retains
-discovery, installation, manifest/config mutation, external module execution,
-pure-mode filtering, and cleanup ownership. Missing or failing plugin hosts
-degrade to the base TUI without blocking startup.
-
-Keep plugin UI extensibility without importing the legacy plugin installer and
-loader into the TUI package.
-
-Tasks:
-
-- Move plugin presentation slots, route contracts, and TUI-facing APIs into
-  `packages/tui` or the existing public plugin TUI contract package.
-- Keep package discovery, installation, manifest resolution, backend activation,
-  and process lifecycle in the host.
-- Define the serialized or runtime plugin presentation data the TUI requires.
-- Prefer SDK-delivered plugin metadata when the behavior must also work for a
-  remote server.
-- Make plugin absence or incompatibility degrade gracefully.
-- Move plugin rendering tests to `packages/tui`; retain installation/loading
-  integration tests in `packages/opencode`.
-
-Exit criteria:
-
-- `packages/tui` does not import `@/plugin/*` or the old TUI plugin runtime.
-- Remote and local TUI clients have a defined plugin behavior.
-- Plugin UI failures cannot prevent the base TUI from starting.
-
-Checkpoint commit:
-
-```text
-refactor(tui): separate plugin presentation from loading
-```
-
-## Section 8: Move The Application Root And Renderer Lifecycle
-
-Status: Completed. `packages/tui` now owns the canonical application root,
-provider composition, routes, components, parser presentation, renderer
-configuration, and renderer lifecycle. Process mutation, Windows console
-handling, backend worker startup, config loading, plugin loading, native audio,
-and legacy platform implementations remain injected host adapters. Old source
-paths are temporary compatibility re-exports for the legacy command host.
-
-Move the canonical app composition after its dependencies have already crossed
-the package boundary.
-
-Tasks:
-
-- Move `app.tsx`, remaining providers, routes, components, attention handling,
-  keymaps, and renderer lifecycle to `packages/tui`.
-- Export a narrow public API such as:
-
-```ts
-export type TuiInput = {
-  url: string
-  directory?: string
-  headers?: RequestInit["headers"]
-  fetch?: typeof fetch
-  config: TuiConfig.Resolved
-  capabilities: TuiCapabilities
-  paths: TuiPaths
-}
-
-export function run(input: TuiInput): TuiHandle
-export function createRenderer(config: TuiConfig.Resolved): Promise<CliRenderer>
-```
-
-- Preserve the existing lifecycle guarantees: readiness, waiting until exit,
-  idempotent cleanup, renderer destruction, SIGHUP handling where appropriate,
-  and terminal restoration.
-- Keep Windows process adapters outside the package if they mutate host process
-  state; invoke them from CLI adapters around the package lifecycle.
-- Keep OpenTUI parser-worker embedding in executable build scripts.
-- Move app lifecycle and rendering tests to `packages/tui`.
-
-Exit criteria:
-
-- `packages/tui` contains the canonical application root.
-- The package has no imports from `packages/opencode`, `packages/cli`, or
-  `@opencode-ai/core`.
-- The package public API is sufficient for both old and new CLI adapters.
-
-Checkpoint commit:
-
-```text
-refactor(tui): move application root into package
-```
-
-## Section 9: Convert Both CLIs To Thin Adapters
-
-Status: Completed. The legacy thread and attach commands now lazily invoke the
-public `@opencode-ai/tui` root while retaining worker/server/config/plugin and
-process adapters. The new CLI default command launches the same package against
-its authenticated daemon transport with a minimal local platform/host. Missing
-legacy provider/config APIs currently degrade to the shared provider-connect
-screen; source and compiled new-CLI behavior match, while named commands remain
-outside the TUI path.
-
-Make both executable packages consume the same TUI package.
-
-Tasks:
-
-- Keep the legacy yargs commands corresponding to current `thread.ts` and
-  `attach.ts` in `packages/opencode`.
-- Keep the legacy embedded worker and server startup in `packages/opencode`.
-- Change those adapters to load config, create transport inputs, and call the
-  public `@opencode-ai/tui` API.
-- Change `packages/cli`'s default command handler to call the same public API.
-- Remove the temporary `packages/cli/src/tui` shell after the shared package is
-  integrated.
-- Remove duplicated OpenTUI lifecycle code from both hosts.
-- Ensure non-TUI subcommands remain lazily isolated from OpenTUI startup.
-- Update executable build scripts to bundle the shared package, parser worker,
-  assets, and any retained host worker.
-
-Exit criteria:
-
-- Both CLIs launch the same package implementation.
-- There is no duplicate TUI source tree in `packages/cli`.
-- Legacy attach and local-worker modes still work.
-- Named non-TUI commands do not launch or eagerly initialize the TUI.
-
-Checkpoint commit:
-
-```text
-refactor(cli): share tui package across command hosts
-```
-
-## Section 10: Remove Compatibility Paths And Finish Ownership
-
-Status: Completed. Package source imports are self-contained, package exports
-are narrowed to active host contracts, package-owned tests and snapshots live
-under `packages/tui`, and the obsolete compatibility tree has been removed.
-Legacy command, worker, config, plugin-loader, process, editor, audio, and event
-adapters now live in explicit host-owned locations outside `src/cli/cmd/tui/`.
-
-Delete migration scaffolding only after both hosts consume the package.
-
-Tasks:
-
-- Remove old TUI compatibility re-exports and the obsolete directory tree under
-  `packages/opencode/src/cli/cmd/tui`.
-- Retain and relocate only true host adapters such as legacy commands, worker,
-  transport setup, and config loading.
-- Remove obsolete `@tui/*` path mappings from `packages/opencode`.
-- Remove stale test fixtures and update all imports to package exports.
-- Narrow `@opencode-ai/tui` exports to intentional public entrypoints.
-- Verify package manifests list every direct dependency and no accidental
-  dependency is supplied only by workspace hoisting.
-- Update repository documentation describing TUI ownership and development.
-
-Exit criteria:
-
-- No production import references the old TUI source location.
-- No source under `packages/tui` imports `@/...`, `@opencode-ai/core`, or either
-  executable package.
-- The old TUI directory contains no canonical implementation files.
-- The dependency graph has no cycle.
-
-Checkpoint commit:
-
-```text
-refactor(tui): complete standalone package extraction
-```
-
-## Invariants To Preserve
-
-- There is one canonical TUI implementation at every migration stage.
-- Legacy TUI behavior remains available until its host is intentionally removed.
-- The default new CLI command launches the TUI, while named subcommands continue
-  to route to their own handlers.
-- Renderer cleanup restores the terminal on normal exit, interruption, startup
-  failure, and renderer destruction.
-- TUI package imports do not reach into executable or backend implementation
-  packages.
-- SDK wire data is treated as the source of truth for OpenCode domain state.
-- Unknown tools and plugin data render safely without backend type imports.
-- Remote-server use remains possible; the TUI must not require an in-process
-  backend implementation.
-- TUI-local persistence remains local and does not become server state unless
-  there is an explicit product requirement.
-- Team changes should be moved with their canonical file, not manually copied
-  between old and new implementations.
-
-## Verification Gates
-
-Run verification after every section, adding narrower tests for the area being
-moved.
-
-Package checks:
-
-```text
-cd packages/tui && bun typecheck
-cd packages/tui && bun test
-cd packages/opencode && bun typecheck
-cd packages/cli && bun typecheck
-```
-
-Dependency checks:
-
-```text
-rg "from ['\"]@/" packages/tui/src
-rg '@opencode-ai/core|packages/opencode|packages/cli' packages/tui
-rg 'src/cli/cmd/tui|@tui/' packages/opencode/src packages/opencode/test
-```
-
-SDK checks when server APIs change:
-
-```text
-./packages/sdk/js/script/build.ts
-git diff --check
-```
-
-Interactive smoke checks should run in `tmux` so the terminal can be captured
-and cleaned up reliably:
-
-- Start the legacy local TUI and confirm initial render.
-- Start legacy attach mode against a server.
-- Start the new CLI default command and confirm it renders the same package.
-- Exit each mode with Ctrl-C and verify the process and terminal are restored.
-- Run representative named commands in both CLIs and verify they do not launch
-  the TUI.
-
-Compiled checks:
-
-- Build the current-platform `packages/opencode` binary.
-- Build the current-platform `packages/cli` binary.
-- Run TUI and non-TUI smoke checks against both compiled binaries.
-- Verify theme JSON, audio assets, OpenTUI parser worker, and retained backend
-  worker assets are included.
-
-## Progress Tracking
-
-- [x] Section 1: Create the package skeleton
-- [x] Section 2: Move presentation utilities and leaf UI
-- [x] Section 3: Remove backend tool implementation imports
-- [x] Section 4: Make runtime inputs explicit
-- [x] Section 5: Separate resolved TUI config from host config loading
-- [x] Section 6: Move SDK state, routes, and backend operations
-- [x] Section 7: Isolate plugin presentation from plugin loading
-- [x] Section 8: Move the application root and renderer lifecycle
-- [x] Section 9: Convert both CLIs to thin adapters
-- [x] Section 10: Remove compatibility paths and finish ownership
-
-Update each section's status and this checklist in the same commit that completes
-the section.