@lingxi-ai-cn/dsh-tui-runtime 0.1.6-rc.8 → 0.1.7-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,14 +1,21 @@
1
+ ---
2
+ description: "Native full-screen terminal frontend for one owned DeepSeek Harness Agent and its durable Session."
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # `@lingxi-ai-cn/dsh-tui-runtime`
2
7
 
3
8
  English | [中文](README.zh.md)
4
9
 
10
+ ## Summary
11
+
5
12
  `Ctrl+X` hands the current draft to `$VISUAL`, then `$EDITOR`, or an explicit platform fallback through a shell-free argv parser. The TUI releases its terminal transaction while the editor owns the TTY, then reacquires it and repaints; only a zero-exit, bounded valid UTF-8 file replaces the draft. Cancel, non-zero exit, invalid encoding, oversized output, spawn failure, and cleanup failure preserve the original draft.
6
13
 
7
14
  Slash completion consumes the effective `ctx.commands.list(agent)` descriptors. Root aliases and command-owned nested metadata complete paths such as `/goal edit`, display localized description fallbacks, argument hints, and disabled reasons, and accept only canonical text. The registry's bounded metadata may expose child paths but never a handler; after acceptance, submission still calls `ctx.commands.execute(agent, completeRawLine, blocks, signal)`, so nested completion cannot create a shadow command or a second audit path.
8
15
 
9
16
  While the root Agent is running, a non-empty draft uses Enter to steer the current turn, Tab to queue a follow-up turn, and Ctrl+Enter to interrupt with `keepInbox` before queueing a follow-up. With an empty composer, Alt+Up reclaims the newest still-pending user message submitted by this TUI process; claimed, foreign, or non-user inbox entries are ignored. Suggestions retain Tab and Enter, an empty draft retains Tab for the status footer, and child views keep the public continuation follow-up route. The running hint and `/help` panel show these routes.
10
17
 
11
- `Ctrl+Q` opens the owner-backed pending-input Queue. A Host that exposes the revisioned Inbox snapshot and CAS mutations enables safe edit and delete actions. Official DSH rc.8 exposes only the two pending lanes, so the same plugin presents their bounded contents read-only, omits unavailable insertion ages, and never calls a missing mutation method.
18
+ `Ctrl+Q` opens the owner-backed pending-input Queue. A Host that exposes the revisioned Inbox snapshot and CAS mutations enables safe edit and delete actions. A legacy Host that exposes only the two pending lanes still receives a bounded read-only projection; the TUI omits unavailable insertion ages and never calls a missing mutation method.
12
19
 
13
20
  Native full-screen terminal frontend for one owned root DeepSeek Harness Agent and its live continuable child views. The plugin waits for Loader settlement, creates or resumes the root through `ctx.agents`, retains only its root `AgentHandle`, renders committed `session/event` rows with Ink, and disposes the root after flushing its Session. It mounts no HTTP server and imports no browser Client package.
14
21
 
@@ -16,17 +23,21 @@ An empty root Session opens a centered startup workspace with a nine-row, 60-cel
16
23
 
17
24
  Before the first request, the startup workspace derives process-local guidance from the successful `tuiStartup` Host snapshot, the selected provider's public authentication and model-catalog reads, and mounted Plugin Hub availability. A Host or provider failure points to `/doctor`; an unconfigured provider uses its provider-owned authentication label and points to `/models`; a configured route with an empty advisory catalog offers a generic `/models` retry because the LLM service exposes no provider remediation field. A healthy route retains the selected model and reasoning effort, then offers `/models`, `/plugins` when available, and `/help` as secondary actions. Provider topology and successful model changes refresh the snapshot. Every line is terminal-sanitized and Unicode-cell bounded, required status does not depend on dim color, and a narrow workspace mounts only the highest-priority executable line. The collector never reads credential values, environment variables, or the system prompt, and it creates no Session event.
18
25
 
26
+ Before creating or resuming an Agent, the TUI performs a metadata-only preflight through the mounted Session persistence owner. An unreadable store or a header outside the exact `SESSION_FORMAT_VERSION` fails closed before any TUI-owned write and reports a bounded backup/export remediation; the preflight never loads message content, repairs tails, or rewrites storage. The persistence owner skips an unknown event only when its durable envelope says `ignorable: true`; an unknown required event refuses reconstruction before the TUI can project it. Its backend name, expected logical format, compatible Session count, and raw-artifact capability are retained only as process-local diagnostics facts.
27
+
19
28
  The transcript is a pure fold over the durable Session log. Append-origin messages remain human-visible while model-only surface replacements stay hidden; streaming assistant chunks reconcile into their completed message, tool calls and results pair by `callId` into one lifecycle node, and turn failures remain visible. Scheduler-owned `tool/execution-group` snapshots render model-ordered Parallel pools and Exclusive barriers with queued, running, successful, failed, and cancelled children plus completion progress. Provider-neutral read/search presentation remains an `Explore` semantic label inside a scheduler group rather than evidence of concurrency; older logs without scheduler snapshots retain consecutive Explore grouping. Service-owned `subagent/delegation-*` records attach task label, child identity, provider, elapsed time, terminal reason, and bounded outcome to the originating tool row without creating a second activity. The latest durable `todo/write` snapshot renders as a pinned `Tasks` surface above the composer: an active list shows at most six status-marked items, an all-complete list collapses to one progress row, an empty list renders nothing, and the next `turn/start` clears the standing list. A successful `todo_write` lifecycle with a paired snapshot is absorbed by that surface while failed calls remain in the transcript. Compact cards remain borderless summaries. `Ctrl+O` enters transcript browse mode at the latest inspectable block; Up and Down move among conversation blocks, activities and retained children, and Tasks. Enter or a primary click opens one bounded detail panel, and PageUp and PageDown scroll its complete body. Escape from keyboard-opened detail returns to Browse; Escape from pointer-opened detail returns directly to the composer and restores its normal pointer regions. Tool details use provider-neutral presentation intents. Diff details select a width-aware `split` or `unified` projection; split rows align unchanged and replacement content when both panes retain a readable cell budget, while narrow and malformed input falls back safely without wrapping a source row. Missing definitions, obsolete arguments, and throwing presenters fall back to sanitized raw content. Assistant GFM is projected to terminal text so headings, lists, code, and tables retain structure without leaking presentation markers; every untrusted string still passes through terminal-control sanitization. Live `agent/status`, approval requests, and user questions stay outside durable transcript state and are cleared during teardown.
20
29
 
30
+ A completed Turn adds one exact token-usage node folded by the official token-meter client from durable provider facts; absent cache, reasoning, or route buckets stay absent instead of being estimated. Settled `ask_user_question` lifecycles render a durable history card, while secret answers remain hidden. `Ctrl+Up` and `Ctrl+Down` jump among stable Turn boundaries from the composer, and `Shift+Up` and `Shift+Down` do the same while browsing; these anchors remain process-local view state and never append navigation events.
31
+
21
32
  `Ctrl+F` enters incremental search over every block in the complete folded transcript, including unmounted pages, user and assistant text, reasoning, command results, and complete tool detail. The index caches normalized lowercase text by stable node key and only replaces a cached document when that block's searchable text changes. Enter and Shift+Enter move cyclically through matching blocks, a second `Ctrl+F` closes search at the selected block, and Escape restores the exact pre-search transcript anchor. The current block and first visible match are highlighted only in process-local render state; query, index, selection, and highlights never modify Session events.
22
33
 
23
- The composer sends ordinary text with `Agent.followup()` while idle and `Agent.steer()` while running. It keeps one Unicode grapheme-aware insertion point, supports left/right and word movement, logical-line Home/End, backward/forward and previous-word deletion, submitted-history traversal with unsent-draft restoration, and up to five visible wrapped rows. `Ctrl+J` inserts a newline while Enter submits the original non-blank text without trimming its outer whitespace. `Ctrl+_` or `Ctrl+Shift+-` undoes an edit and `Ctrl+Y` redoes it through at most 100 process-local text-and-cursor snapshots. Rapid single-grapheme typing and same-direction deletion coalesce; paste, multiline insertion, suggestion acceptance, and history acceptance remain separate units, while cursor movement only ends coalescing. A bracketed paste of at least eight lines or 4 KiB becomes one bounded `[Pasted text]` placeholder; its terminal-safe original remains process-local and expands only at submission. `Ctrl+V` requests one typed system-clipboard read through the platform provider; macOS uses `pbpaste`, Linux Wayland uses `wl-paste`, and Linux X11 tries `xclip` then `xsel`. The provider uses argv-only execution, a short timeout, a complete byte cap, and independent image magic validation; file-list payloads are parsed as local `file:` paths. Unsupported Windows, headless SSH, missing utilities, and invalid media return a live notice and leave the draft untouched, so terminal paste and `@` path completion remain the fallback. Clipboard text and admitted image chips are inserted as one undo unit. Deleting the placeholder removes its payload, while undo, redo, stash, submitted history, and Agent-view switching retain the reference without mounting the pasted lines. `Ctrl+R` searches unique prompts submitted by the current TUI process newest-first; repeated use selects an older match, Enter accepts it, and Escape restores the exact draft and cursor. `Ctrl+S` stashes a non-empty draft, restores it into an empty editor, or swaps it with another non-empty draft so restoration never overwrites text; each draft retains its own edit history. Prompt-history search, stash, paste references, and edit history remain process-local and never enter the Session log. A command-only slash query opens the shared suggestion controller over the effective `ctx.commands.list(agent)` descriptors; the compatibility catalog retains TUI-owned localized metadata when an older Host omits additive discovery fields, while exact first-party rc.8 command descriptions receive a localized fallback without rewriting same-name third-party text. An `@token` at the draft or after whitespace opens the same controller over cancellable workspace results: a Host-provided `ctx.fs.completePaths()` is preferred, while official rc.8 uses an equivalent bounded traversal over `listDir()` and `contains()`. Both paths stay rooted at the current Session workspace; loading, no-match, and truncated states remain bounded, directory acceptance keeps its trailing slash, and file acceptance adds one separating space. The bounded list marks one selection; Up/Down moves it without traversing prompt history, Shift+Tab moves backward, Tab or Enter accepts the selected command or path, and Escape closes the list while preserving the draft. One immutable action registry owns the effective Global, Composer, Suggestion, HistorySearch, TranscriptSearch, Transcript, Detail, Dialog, Footer, Work, and Approval bindings and their input priority. `/help` keeps returning the effective command descriptors and also opens a bounded, scrollable interaction panel generated from that registry; unsupported capability actions are omitted, `/help extra` remains a usage error, and Escape returns to the prior local mode. `Alt+P` opens the existing model picker without replacing the current draft. A leading slash first uses `ctx.commands.execute()`; an unmatched line remains an ordinary prompt so skill gestures retain their shared Agent path. Approvals are scoped to the exact owned Agent and expose only allow-once/reject. `ctx.userQuestions.registerProvider()` supplies a FIFO structured-question surface whose Dialog owns Enter even while the Agent is running.
34
+ The composer sends ordinary text with `Agent.followup()` while idle and `Agent.steer()` while running. It keeps one Unicode grapheme-aware insertion point, supports left/right and word movement, logical-line Home/End, backward/forward and previous-word deletion, submitted-history traversal with unsent-draft restoration, and up to five visible wrapped rows. `Ctrl+J` inserts a newline while Enter submits the original non-blank text without trimming its outer whitespace. `Ctrl+_` or `Ctrl+Shift+-` undoes an edit and `Ctrl+Y` redoes it through at most 100 process-local text-and-cursor snapshots. Rapid single-grapheme typing and same-direction deletion coalesce; paste, multiline insertion, suggestion acceptance, and history acceptance remain separate units, while cursor movement only ends coalescing. A bracketed paste of at least eight lines or 4 KiB becomes one bounded `[Pasted text]` placeholder; its terminal-safe original remains process-local and expands only at submission. `Ctrl+V` requests one typed system-clipboard read through the platform provider; macOS uses `pbpaste`, Linux Wayland uses `wl-paste`, and Linux X11 tries `xclip` then `xsel`. The provider uses argv-only execution, a short timeout, a complete byte cap, and independent image magic validation; file-list payloads are parsed as local `file:` paths. Unsupported Windows, headless SSH, missing utilities, and invalid media return a live notice and leave the draft untouched, so terminal paste and `@` path completion remain the fallback. Clipboard text and admitted image chips are inserted as one undo unit. Deleting the placeholder removes its payload, while undo, redo, stash, submitted history, and Agent-view switching retain the reference without mounting the pasted lines. `Ctrl+R` searches unique prompts submitted by the current TUI process newest-first; repeated use selects an older match, Enter accepts it, and Escape restores the exact draft and cursor. `Ctrl+S` stashes a non-empty draft, restores it into an empty editor, or swaps it with another non-empty draft so restoration never overwrites text; each draft retains its own edit history. Prompt-history search, stash, paste references, and edit history remain process-local and never enter the Session log. A command-only slash query opens the shared suggestion controller over the effective `ctx.commands.list(agent)` descriptors; the compatibility catalog retains TUI-owned localized metadata when an older Host omits additive discovery fields, while exact legacy first-party descriptions receive a localized fallback without rewriting same-name third-party text. An `@token` at the draft or after whitespace opens the same controller over cancellable workspace results: a Host-provided `ctx.fs.completePaths()` is preferred, while a legacy Host uses an equivalent bounded traversal over `listDir()` and `contains()`. Both paths stay rooted at the current Session workspace; loading, no-match, and truncated states remain bounded, directory acceptance keeps its trailing slash, and file acceptance adds one separating space. The bounded list marks one selection; Up/Down moves it without traversing prompt history, Shift+Tab moves backward, Tab or Enter accepts the selected command or path, and Escape closes the list while preserving the draft. One immutable action registry owns the effective Global, Composer, Suggestion, HistorySearch, TranscriptSearch, Transcript, Detail, Dialog, Footer, Work, and Approval bindings and their input priority. `/help` keeps returning the effective command descriptors and also opens a bounded, scrollable interaction panel generated from that registry; unsupported capability actions are omitted, `/help extra` remains a usage error, and Escape returns to the prior local mode. `Alt+P` opens the existing model picker without replacing the current draft. A leading slash first uses `ctx.commands.execute()`; an unmatched line remains an ordinary prompt so skill gestures retain their shared Agent path. Approvals are scoped to the exact owned Agent and expose only allow-once/reject. `ctx.userQuestions.registerProvider()` supplies a FIFO structured-question surface whose Dialog owns Enter even while the Agent is running.
24
35
 
25
- `/models` opens a bounded, scrollable selector over `ctx.llm.listProviders()` and each provider's live `listModels()` result. Providers that advertise interactive authentication appear as sign-in actions until configured. The first native flow is OpenAI Codex: choosing **Sign in with ChatGPT** runs the provider-owned browser OAuth flow, stores the refreshable credential under `$DSH_HOME/oauth/openai-codex.json`, refreshes the account model catalog, and returns to the selector. After a model declares selectable reasoning efforts, a second bounded question chooses one exact effort. The resolved model and effort are persisted through `ctx.agentDefaultModel.saveSelection()`, become the owned Agent's next-step selection, and update the idle header immediately; an already-running step keeps its captured selection.
36
+ `/models` opens a bounded, scrollable selector over `ctx.llm.listProviders()` and each provider's live `listModels()` result. Providers that advertise interactive authentication appear as sign-in actions until configured. The first native flow is OpenAI Codex: choosing **Sign in with ChatGPT** runs the provider-owned browser OAuth flow through the official authorization owner, stores the refreshable grant through the scoped credential-record owner, refreshes the account model catalog, and returns to the selector. Older Hosts fall back to the provider-neutral LLM authentication bridge without changing the UI contract. After a model declares selectable reasoning efforts, a second bounded question chooses one exact effort. The resolved model and effort are persisted through `ctx.agentDefaultModel.saveSelection()`, become the owned Agent's next-step selection, and update the idle header immediately; an already-running step keeps its captured selection.
26
37
 
27
- `/mode` opens the dynamic `ctx.agentPresets` roster, with localized names and descriptions for Standard (`standard`), PTC (`code`), Minimal (`minimal`), and Creator (`cordis`) plus installed user presets. Missing and broken rows remain visible with bounded disabled reasons, without exposing preset paths. A blank Session switches through `ctx.agentPresets.recompose()` under one single-flight transaction and appends `agent-preset/selected` only after the new composition commits. After the first `turn/start`, selection opens the existing fresh-Session confirmation instead; Escape keeps the current Agent, draft, transcript anchor, and footer, while confirmation creates and publishes a new Session under the selected preset before disposing the old handle. The current mode is an actionable footer item, and both footer and single-select menu rows use the same state transition for keyboard and primary SGR clicks. This package selects existing presets but does not copy, edit, or remove them.
38
+ `/mode` opens the dynamic `ctx.agentPresets` roster, with localized names and descriptions for Standard (`standard`), PTC (`ptc`), Minimal (`minimal`), and Creator (`cordis`) plus installed user presets. Missing and broken rows remain visible with bounded disabled reasons, without exposing preset paths. A downstream Session that durably records the retired `code` preset is interpreted as PTC and appends the canonical `ptc` selection only when a successful recomposition commits. A blank Session switches through `ctx.agentPresets.recompose()` under one single-flight transaction and appends `agent-preset/selected` only after the new composition commits. After the first `turn/start`, selection opens the existing fresh-Session confirmation instead; Escape keeps the current Agent, draft, transcript anchor, and footer, while confirmation creates and publishes a new Session under the selected preset before disposing the old handle. The current mode is an actionable footer item, and both footer and single-select menu rows use the same state transition for keyboard and primary SGR clicks. This package selects existing presets but does not copy, edit, or remove them.
28
39
 
29
- `/doctor` opens a bounded read-only runtime-health panel for the owned root Agent view. Each invocation refreshes the successful post-install Host compatibility result, negotiated terminal capabilities, up to eight provider authentication and model-catalog summaries, Plugin Hub availability and catalog freshness, installed-plugin count, and optional service presence. One provider or Registry failure becomes one warning row instead of failing the panel; additional providers are reported as an omitted count. Every field is terminal-sanitized and bounded, arbitrary provider error messages, package paths, and credentials are not rendered, and severity remains explicit in text as well as color. The snapshot, scroll offset, and non-secret failure labels remain process-local. The durable command audit records only `Opened runtime diagnostics.`; Escape closes the panel and returns to the prior transcript without creating diagnostic Session events.
40
+ `/doctor` opens a bounded read-only runtime-health panel for the owned root Agent view. Each invocation refreshes the successful post-install Host compatibility result, negotiated terminal capabilities, Session storage preflight facts, up to eight provider authentication and model-catalog summaries, Plugin Hub availability and catalog freshness, installed-plugin count, and optional service presence. One provider or Registry failure becomes one warning row instead of failing the panel; additional providers are reported as an omitted count. Every field is terminal-sanitized and bounded, arbitrary provider error messages, package paths, and credentials are not rendered, and severity remains explicit in text as well as color. The snapshot, scroll offset, and non-secret failure labels remain process-local. The durable command audit records only `Opened runtime diagnostics.`; Escape closes the panel and returns to the prior transcript without creating diagnostic Session events.
30
41
 
31
42
  `/context` opens a bounded read-only view of public loaded-context facts for the owned root Agent: system-prompt section names, dynamic context contributor names, active tool names, available skill names, and the current model and permission capability. It calls the prompt assembly owner with the Agent scope and never parses or renders assembled prompt text; unavailable optional skill discovery is represented as an empty category. The snapshot and scroll offset remain process-local, and Escape returns to the prior transcript without creating context Session events.
32
43
 
@@ -54,6 +65,8 @@ Terminal mutation has one owner. It refuses non-TTY streams before writing, ente
54
65
 
55
66
  Raw input passes through one incremental decoder before interaction dispatch. It preserves UTF-8 across transport chunks, separates control bytes from adjacent committed text, and normalizes traditional xterm keys, Kitty CSI-u, xterm modifyOtherKeys, application-keypad sequences, and their available Shift/Ctrl/Alt/Meta/Super modifiers. The same tokenizer consumes SGR mouse reports, focus reports, bracketed paste, terminal replies, unknown function keys, and unknown or incomplete CSI without leaking their bytes into an editor. A standalone Escape settles after 35 ms; a bracketed paste remains one undo unit and is bounded to 16 MiB, with a live truncation notice. Enhanced keyboard protocols are decoded when the terminal emits them; the TUI does not infer support from `$TERM` or enable them without a negotiated terminal capability.
56
67
 
68
+ The bounded Work panel projects child execution routes only from owner-provided facts: provider, model, reasoning effort, maximum output, and source appear when present and stay explicitly unavailable otherwise. It never infers a route from the root selection or from display labels.
69
+
57
70
  Before entering the alternate screen, `TerminalSession` sends bounded device, Kitty keyboard, and OSC foreground/background probes through the same decoder. A validated OSC 11 reply becomes only `light` or `dark` in the process-local capability snapshot; an absent or malformed reply becomes `unknown`, and no raw reply is retained. A reply-free terminal reaches the UI after the probe deadline with legacy input and no enhanced mouse, focus, paste, or clipboard mode; a confirmed capability enables only its own mode. Replies split across chunks and ordinary input interleaved with them retain byte order, and input buffered during probing is dispatched after Ink mounts. Y in transcript browse or detail copies at most 100,000 UTF-8 bytes through negotiated OSC 52. Under tmux the same sequence enters tmux's configured clipboard buffer path, whose `set-clipboard` policy may forward it; SSH uses OSC only after the remote process observes a reply. Unsupported, oversized, or failed writes produce a live notice and never a Session event. Color depth comes from the output stream and `NO_COLOR`; tmux and SSH are recorded only as this process's outer transport context. Teardown disables exactly the modes enabled by that transaction.
58
71
 
59
72
  Text editors use the terminal's real cursor rather than a rendered inverse-space cursor. `TuiApp` computes the insertion cell from the visible multiline layout with Unicode display width and follows Ink/Yoga's leading-cell rounding for a centered startup composer. `TerminalSession.rendererOutput` restores that cell after every full-screen Ink render while suppressing Ink's cursor-hide request. The terminal transaction enables only negotiated bracketed paste and restores paste, mouse, focus, keyboard, cursor, raw, and alternate-screen modes on every shutdown path. Leaving temporary button-event drag selection explicitly restores the negotiated `1000` click and `1006` SGR reports before pointer regions resume, so closing transcript detail cannot strand the terminal in selection-only mouse mode. This gives macOS and other terminal IMEs the correct anchor for CJK preedit text; read-only panels, including Plugin Hub detail, and approval-only interactions hide the cursor, and teardown still restores it unconditionally.
@@ -62,7 +75,7 @@ The package-local design system gives startup and transcript chrome, Plugin Hub,
62
75
 
63
76
  The native TUI exposes a versioned low-ABI DTO surface through `ctx.tuiExtensions` and the package entrypoint. A plugin can register owner-scoped settings, keyed status rows with priority and cell budgets, managed select/confirm/input dialogs, low-priority shortcuts, bounded workspace providers, structured fullscreen scenes, bounded renderers for known user/assistant message events, owner-scoped plugin-local JSON storage, sanitized completed-message observers, and allow/deny decision hooks for input, rewind, and Session switch boundaries. A fullscreen scene renders bounded terminal-safe text and may receive bounded input while the host retains Escape, terminal sizing, and teardown ownership; it never receives a React tree or writes Session state. A known-event renderer receives only validated append-surface type, sequence, bounded terminal-safe text, and the assistant interruption marker, then returns a bounded text DTO or falls back to the host projection; it cannot see raw Session events, tool payloads, or model-only replacements. When the host supplies a Plugin Hub grant ledger, sensitive storage, observer, decision, scene, and message-render calls require the matching package/version/activation identity and recheck the managed capability on every call; the ledger records only contribution lifecycle transitions and never replaces installed-profile truth. Each registration carries package/version metadata and the real Cordis activation id, returns an effect disposer or disposable storage handle, is removed on unload, and receives timeout, cancellation, terminal-sanitization, length, quota, and conflict checks. Decision hooks run in a fixed total deadline and timeout or failure defaults to allow so optional extensions cannot stall built-in work. Completed-message observers receive only bounded text, session/message ids, turn/step, and an interruption marker from known committed `assistant/message` events; reasoning, tool calls, images, provider provenance, and the complete Session event stay host-owned. Storage paths are host-owned below `$DSH_HOME/tui/extensions`; writes use a writer lock plus atomic replacement, and corrupt files are retained before the namespace is reopened empty. Settings and storage reads/writes stay inside the owning namespace. The registry does not execute commands, replace approval/question/security interactions, or append durable Session events; nested command completion remains owned by `ctx.commands`.
64
77
 
65
- Completed reasoning occupies one `Thinking · duration` transcript heading while its complete text remains available through block detail. Fenced code keeps a language heading, narrow tables become row-oriented field lists, and tool summaries use workspace-relative paths inside the Session workspace while preserving external absolute paths. Terminal, read, search, diff, web, delegation, and generic rows remain bounded at 80 columns; below 60 columns the activity row and footer omit secondary metadata rather than overlap. Before the first request, the centered startup workspace shows the resolved model and provider-default reasoning effort. While running, the activity row shows the durable request selection beside the work indicator and `Esc stop`; while idle, it shows the next-step selection. The footer projects that same captured-or-next selection together with the effective `ctx.agentPresets` mode, `ctx.permissionPresets`, provider-anchored `contextPressure`, durable `tokenUsage` buckets, heuristic `contextBreakdown`, authoritative background-work counters, the Session workspace, and the mounted transcript range; context is absent until both capacity and a provider usage sample exist, and its detail marks composition as approximate, shows cache-hit percentages only when a prompt denominator exists, and hides unavailable values. When `sessionStats` is mounted, the same detail shows settled average TTFT and decode throughput only for steps with durable token boundaries and provider output-token usage; missing timing remains hidden. Work is absent until at least one row exists. Tab enters an explicit Footer mode after suggestion handling, Left/Right or Tab/Shift+Tab moves among mounted items, Enter opens the existing model picker, the mode selector, the permission preset picker, the bounded Work panel, or bounded read-only details, and Escape returns to the composer. Permission changes execute the registered `/permission` command instead of mutating policy locally. At fewer than 56 columns model, mode, permission, and Work when present remain mounted; wider layouts add context, transcript position, and workspace in priority order. `NO_COLOR` and limited-color terminals retain text and symbols; tmux and SSH inherit their outer terminal capabilities, while Windows Terminal uses the same ANSI and Unicode-width path.
78
+ Completed reasoning occupies one `Thinking · duration` transcript heading while its complete text remains available through block detail. Fenced code keeps a language heading, narrow tables become row-oriented field lists, and tool summaries use workspace-relative paths inside the Session workspace while preserving external absolute paths. Terminal, read, search, diff, web, delegation, and generic rows remain bounded at 80 columns; below 60 columns the activity row and footer omit secondary metadata rather than overlap. Before the first request, the centered startup workspace shows the resolved model and provider-default reasoning effort. While running, the activity row shows the durable request selection beside the work indicator and `Esc stop`; while idle, it shows the next-step selection. The footer projects that same captured-or-next selection together with the effective `ctx.agentPresets` mode, `ctx.permissionPresets`, provider-anchored `contextPressure`, durable `tokenUsage` buckets, heuristic `contextBreakdown`, authoritative background-work counters, the official active Schedule projection, the Session workspace, and the mounted transcript range; context is absent until both capacity and a provider usage sample exist, and its detail marks composition as approximate, shows cache-hit percentages only when a prompt denominator exists, and hides unavailable values. When `sessionStats` is mounted, the same detail shows settled average TTFT and decode throughput only for steps with durable token boundaries and provider output-token usage; missing timing remains hidden. Work and Schedule items are absent until their owners publish at least one row. Tab enters an explicit Footer mode after suggestion handling, Left/Right or Tab/Shift+Tab moves among mounted items, Enter opens the existing model picker, the mode selector, the permission preset picker, the bounded Work or Schedule panel, or bounded read-only details, and Escape returns to the composer. Permission changes execute the registered `/permission` command instead of mutating policy locally. At fewer than 56 columns model, mode, permission, and Work when present remain mounted; wider layouts add Schedule, context, transcript position, and workspace in priority order. `NO_COLOR` and limited-color terminals retain text and symbols; tmux and SSH inherit their outer terminal capabilities, while Windows Terminal uses the same ANSI and Unicode-width path.
66
79
 
67
80
  The footer adds an eight-cell approximate `S` system, `T` tools, and `M` messages composition bar beside provider-anchored context pressure. Its TPS item uses provider output tokens when the latest step settles; during an open latest-step stream it derives a visibly `~`-marked four-characters-per-token sample and six-cell process-local trend from durable chunks, while the Session-stats fallback remains a settled whole-Session aggregate. The transcript item appends the exact unseen-row count and becomes a direct return-to-live-tail action while newer rows exist. These projections cache no second transcript or usage state and disappear when their required event or projection facts are absent.
68
81
 
@@ -78,16 +91,26 @@ Plugin Hub Detail uses bounded semantic sections for Overview, Compatibility and
78
91
 
79
92
  Registry entries defaults to all accepted catalog records and Stars ordering. `Shift+I` or the rendered label switches between all Registry entries and installable-only records; `Shift+S` cycles Relevance, Stars, Updated, and Newest. `Shift+C` cycles only Registry-owned categories observed in loaded unfiltered pages and returns to All categories. When no loaded row supplies category metadata, the category binding is a no-op and the footer and pointer registry omit that unavailable control. Rendered filter, category, and ordering labels accept primary SGR clicks. The TUI sends the selected installability, ordering, and category, appends opaque continuation pages, deduplicates plugin ids, and restarts from the first page when the Registry rejects a stale cursor. Existing cards remain visible while another page loads; catalog status and Showing ranges expose the current filter, ordering, and continuation state without entering the Session log. A non-installable Registry entry remains visible under the all-entries filter and keeps its detail, but has no install action.
80
93
 
94
+ ## Table of Contents
95
+
96
+ - [WebUI-aligned terminal workflows](#webui-aligned-terminal-workflows)
97
+ - [Performance diagnostics](#performance-diagnostics)
98
+ - [Host compatibility](#host-compatibility)
99
+ - [Configuration](#configuration)
100
+ - [Model Experience](#model-experience)
101
+ - [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
102
+ - [Dev Note](#dev-note)
103
+
81
104
  ## WebUI-aligned terminal workflows
82
105
 
83
106
  The native surface consumes the same Host owners as Web rather than importing browser state. Every panel is capability-gated, terminal-safe, keyboard-complete, and mirrored by primary-pointer regions only for actions that are visibly rendered.
84
107
 
85
108
  - **Provider Center and onboarding:** `/provider` joins live and configurable routes, redacted settings descriptors, value-free credential status, provider-owned authentication, and model discovery. It can add or edit supported OpenAI-compatible routes, stage endpoint/model changes, write an API key through the credential owner, sign in or out where the adapter advertises the action, and recover from revision conflicts without retaining a secret in Session state, command history, diagnostics, or ordinary drafts.
86
- - **Pending input queue:** while the root Agent is running, the queue card separates next-step from next-turn work. A revisioned `agent.inbox.snapshot()` enables detail, edit, and remove through owner-fenced mutations; official rc.8 falls back to bounded read-only lane projection. Enter, Tab, Ctrl+Enter, and Alt+Up remain the fast paths over the same owner.
109
+ - **Pending input queue:** while the root Agent is running, the queue card separates next-step from next-turn work. A revisioned `agent.inbox.snapshot()` enables detail, edit, and remove through owner-fenced mutations; a legacy Host falls back to bounded read-only lane projection. Enter, Tab, Ctrl+Enter, and Alt+Up remain the fast paths over the same owner.
87
110
  - **Session and Workspace management:** `/sessions` presents active and archived Sessions across Workspace groupings with metadata search, preview, resume, rename, fork, archive, and safe fresh-Session actions. Restore appears only when the Workspace owner exposes its unarchive mutation. `/workspace [path]` and the bounded Host directory browser create or select Workspace paths without moving Session logs or assuming the Host is the local desktop.
88
- - **Unified references:** composer `@` suggestions merge bounded Workspace file discovery with stable canonical Session mentions. File references remain attachment-owner or filesystem-owner facts; a newer Session owner performs metadata-only preflight before submission, while official rc.8 validates and captures immutable, untrusted context at `agent/pre-step`.
111
+ - **Unified references:** composer `@` suggestions merge bounded Workspace file discovery with stable canonical Session mentions. File references remain attachment-owner or filesystem-owner facts; the current Session owner performs metadata-only preflight before submission, while a legacy owner validates and captures immutable, untrusted context at `agent/pre-step`.
89
112
  - **Goal, plan, and deliverables:** durable Goal and Plan projections occupy compact status surfaces with owner commands for their supported lifecycle. Finalized turns derive bounded produced-file rows from durable tool/result facts, provide Host-owned open/copy actions, and place explicit references beside the closing assistant message without parsing prose as authority.
90
- - **Preset and Host plugin centers:** `/presets` lists healthy and broken roster entries, atomically copies a source preset into the user root, removes only user-owned rows, and delegates file opening to the Host. Future-default selection appears only with the settings compare-and-set owner seam. `/host-plugins` reads the public Loader inventory and settings descriptors, exposing only owner-supported revisioned edits; it is separate from Plugin Hub installation and never walks Loader internals.
113
+ - **Preset, Host plugin, and Schedule centers:** `/presets` lists healthy and broken roster entries, projects structured composition rows from `AgentPresets.compositionInventory()`, atomically copies a source preset into the user root, removes only user-owned rows, and delegates file opening to the Host. Future-default selection appears only with the settings compare-and-set owner seam. `/host-plugins` separates loaded Host rows, Agent preset compositions, and settings descriptors; live compositions show Fiber phase, cold compositions preserve conditional enablement, and broken compositions retain their owner reason. `/schedules` and the footer read the official active Schedule projection; creation, deletion, persistence, and dispatch remain Schedule-owner operations.
91
114
  - **Trajectory and feedback:** `/trajectory` folds the durable Session log into a bounded turn/step ledger with timing, token, search, fold, tail-follow, paging, and inspector tabs. Finalized assistant rows expose like, dislike, note, and clear actions through the feedback owner; feedback never rewrites the message or enters the transcript.
92
115
  - **Attachments and complete interaction ownership:** path completion, clipboard admission, drag/drop terminal paths, image capability checks, chips, and unified references converge on the same bounded intake. Full-screen panels, nested details, footer actions, transcript browse, links, and selection restore their exact keyboard and pointer regions after Escape; hidden or covered rows publish no stale hit targets.
93
116
 
@@ -164,9 +187,14 @@ Changing provider or model selects a different provider cache domain for the nex
164
187
  ## Known Limitations and Deferred Work
165
188
 
166
189
  - **One visible Agent view and one bounded transcript page** — root and live continuable child views switch in place; there are no simultaneous panes or Session tabs. Inactive and one-shot local children and remote runs remain summary-only. Per-view drafts are process-local rather than durable.
167
- - **Preset source editing is delegated to the Host** — `/presets` owns default selection, atomic copy, inspection, and user-preset deletion, but it does not embed a YAML editor or invent composition validation; Open uses the Host opener and the roster remains the authority on the next read.
190
+ - **Preset source editing is delegated to the Host** — `/presets` owns default selection, atomic copy, structured composition inspection, and user-preset deletion, but it does not embed a YAML editor or validate composition files independently; Open uses the Host opener and the roster remains the authority on the next read.
168
191
  - **Pointer actions are limited to mounted core surfaces** — primary SGR clicks select visible transcript blocks and tool-group children, activate mounted footer items, select visible Work rows, use Plugin Hub and Resume picker targets, commit single-select question/model/permission options, answer Approval, close mounted detail/help panels, or accept visible suggestions; disabled rows, multi-select submission, draft confirmations, hidden history, destructive dialogs, and unsupported surfaces remain keyboard-owned.
169
192
  - **Terminal integration varies by host** — automated PTY coverage proves committed Unicode, narrow layout, bracketed-paste restoration, and cursor placement. Native macOS IME preedit and Windows ConPTY behavior remain manual release checks.
170
193
  - **Terminal image paste is unavailable** — standard terminal input supplies committed text but no typed image bytes. `Ctrl+V` can read validated image bytes on macOS and Linux when the platform clipboard utility is available; Windows, headless SSH, and unsupported terminals fall back to `@` path completion. Every ordinary or command submission still preflights the exact model's `inputModalities` before Agent or command delivery.
171
194
  - **Ink 5 follows the repository React 18 line** — adopting a newer renderer major requires an isolated React build-face proof or a coordinated Web React migration.
172
195
  - **The contribution ABI is intentionally narrow** — third-party plugins receive structured DTO registration through `ctx.tuiExtensions`, not React components, arbitrary Session events, or process isolation. Fullscreen scenes use host-owned text frames and input ownership; grant/effect-ledger authorization remains capability-scoped.
196
+
197
+ <a id="dev-note"></a>
198
+ ### Dev Note
199
+
200
+ None.
package/README.zh.md CHANGED
@@ -1,14 +1,21 @@
1
+ ---
2
+ description: "面向一个 owned DeepSeek Harness Agent 及其 durable Session 的原生全屏终端前端。"
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # `@lingxi-ai-cn/dsh-tui-runtime`
2
7
 
3
8
  [English](README.md) | 中文
4
9
 
10
+ ## 概述
11
+
5
12
  `Ctrl+X` 会通过不经过 shell 的 argv 解析,把当前 draft 交给 `$VISUAL`、再回退到 `$EDITOR` 或明确的平台 fallback。编辑器接管 TTY 时 TUI 会释放 terminal transaction,退出后重新取得并完整重绘;只有零退出、未超过上限且为有效 UTF-8 的文件内容才替换 draft。取消、非零退出、非法编码、超限输出、启动失败或清理失败都会保留原 draft。
6
13
 
7
14
  斜杠补全使用有效 agent 的 `ctx.commands.list(agent)` 描述符。根命令别名和命令拥有的嵌套元数据可以补全 `/goal edit` 这样的路径,显示本地化描述回退、参数提示和禁用原因,并且只接受规范文本。注册表的有界元数据可以暴露子路径但不包含处理器;接受后仍调用 `ctx.commands.execute(agent, completeRawLine, blocks, signal)` 提交,因此嵌套补全不会注册 shadow command,也不会产生第二条审计路径。
8
15
 
9
16
  root Agent running 时,非空 draft 使用 Enter steer 当前 turn,Tab 排入下一轮 follow-up,Ctrl+Enter 以 `keepInbox` 中断后再排入 follow-up。composer 为空时,Alt+Up 会取回当前 TUI 进程提交且仍 pending 的最新 user message;已被 claim、其他来源或非 user 的 inbox entry 会被忽略。Suggestion 仍优先消费 Tab 与 Enter,空 draft 的 Tab 仍进入 status footer,child view 保留公开的 continuation follow-up 路径。Running hint 与 `/help` 面板会显示这些路径。
10
17
 
11
- `Ctrl+Q` 会打开由 owner 支持的待处理输入队列。Host 暴露带 revision 的 Inbox snapshot 与 CAS mutation 时,会启用安全的编辑和删除操作。官方 DSH rc.8 只暴露两个 pending lane,因此同一个插件会以只读方式显示其中的有界内容,省略无法取得的插入时间,并且绝不会调用不存在的 mutation 方法。
18
+ `Ctrl+Q` 会打开由 owner 支持的待处理输入队列。Host 暴露带 revision 的 Inbox snapshot 与 CAS mutation 时,会启用安全的编辑和删除操作。旧版 Host 若只暴露两个 pending lane,同一个插件仍会以只读方式显示其中的有界内容,省略无法取得的插入时间,并且绝不会调用不存在的 mutation 方法。
12
19
 
13
20
  面向一个自有 root DeepSeek Harness Agent 及其 live continuable child view 的原生全屏终端前端。该插件等待 Loader 结算,通过 `ctx.agents` 创建或恢复 root,只持有它的 root `AgentHandle`,用 Ink 渲染已提交的 `session/event` 行,并在 flush 其 Session 后处置 root。它不挂载 HTTP server,也不导入浏览器 Client 包。
14
21
 
@@ -16,17 +23,21 @@ root Agent running 时,非空 draft 使用 Enter steer 当前 turn,Tab 排
16
23
 
17
24
  第一次请求前,启动工作区会根据已成功的 `tuiStartup` Host 快照、所选 provider 的公开认证与模型目录读取结果,以及 Plugin Hub 是否挂载,生成只存在于当前进程的引导。Host 或 provider 失败时指向 `/doctor`;provider 未配置时使用该 provider 自有的认证名称并指向 `/models`;已配置 route 的 advisory 目录为空时提供通用 `/models` 重试,因为 LLM service 没有暴露 provider 修复字段。健康 route 保留已选 model 与 reasoning effort,并把 `/models`、可用时的 `/plugins` 和 `/help` 作为次要操作。Provider topology 和成功的 model 变更会刷新该快照。每行都会清理终端控制字符并按 Unicode cell 限界,必要状态不依赖 dim color,窄工作区只挂载一条优先级最高的可执行提示。Collector 不读取 credential 值、环境变量或 system prompt,也不创建 Session event。
18
25
 
26
+ 在创建或恢复 Agent 之前,TUI 会通过已挂载的 Session persistence owner 执行仅元数据 preflight。存储不可读或 header 不符合确切 `SESSION_FORMAT_VERSION` 时,会在任何 TUI 自有写入前 fail closed,并报告有界的备份/导出修复提示;preflight 不加载消息正文、不修复 tail,也不改写存储。Persistence owner 只会跳过耐久 envelope 标记为 `ignorable: true` 的未知 event;未知 required event 会在 TUI 投影前拒绝重建。其 backend 名称、预期逻辑格式、兼容 Session 数量和 raw-artifact capability 只作为进程内诊断事实保留。
27
+
19
28
  Transcript 是对耐久 Session 日志的纯 fold。以 append 方式产生的消息保持人类可见,仅供模型使用的 surface replacement 不显示;流式 assistant chunk 会校准为其完成消息,工具调用与结果按 `callId` 配对成一个生命周期节点,turn 失败保持可见。调度器所有的 `tool/execution-group` 快照会按模型顺序渲染 Parallel pool 与 Exclusive barrier,显示 queued、running、successful、failed、cancelled child 及完成进度。提供方无关的 read/search 呈现只保留为调度组内的 `Explore` 语义标签,而不作为并发证据;没有调度快照的旧日志仍使用连续 Explore grouping。service 所有的 `subagent/delegation-*` 记录会把任务标签、child 身份、提供方、耗时、终止原因和有界结果附到发起调用的工具行,不会创建第二个活动。最近的耐久 `todo/write` 快照会在 composer 上方渲染成固定的 `Tasks` 界面:活动列表最多显示六个带状态标记的条目,全部完成的列表压缩为一行进度,空列表不渲染,下一次 `turn/start` 会清除当前列表。具有配对快照的成功 `todo_write` 生命周期会被该界面吸收,失败调用仍保留在 transcript 中。紧凑卡片继续使用无边框摘要。`Ctrl+O` 会在最近一个可检查 block 上进入 transcript 浏览模式;上下方向键可在 conversation block、活动及其保留 child 和 Tasks 间移动。Enter 或 primary click 会打开有界详情面板,PageUp 与 PageDown 滚动其完整正文。键盘打开的详情按 Escape 返回 Browse;鼠标打开的详情按 Escape 会直接返回 composer,并恢复其普通 pointer region。工具详情根据提供方无关的呈现意图显示。Diff 详情会根据宽度选择 `split` 或 `unified` 投影;两侧有足够 cell 时对齐未变更和替换内容,窄屏或异常输入则安全回退,且不会把源代码行软换行。缺失定义、过期参数或抛出异常的 presenter 会回退到清理后的原始内容。Assistant GFM 会投影成终端文本,使标题、列表、代码与表格保留结构且不泄露呈现标记;每个不受信任字符串仍会经过终端控制字符清理。实时 `agent/status`、审批请求与用户问题不进入耐久 transcript 状态,并在 teardown 期间清空。
20
29
 
30
+ 每个已完成 Turn 都会添加一个 exact token-usage 节点,由官方 token-meter client 从耐久 provider 事实 fold 得出;缺失的 cache、reasoning 或 route bucket 会继续缺失,而不会被估算。已结算的 `ask_user_question` lifecycle 会渲染耐久历史卡片,secret answer 则保持隐藏。Composer 中的 `Ctrl+Up`/`Ctrl+Down` 和 Browse 中的 `Shift+Up`/`Shift+Down` 会在稳定 Turn 边界间跳转;这些 anchor 只属于进程内 view state,绝不追加 navigation event。
31
+
21
32
  `Ctrl+F` 会在完整 folded transcript 的每个 block 上进入增量搜索,包括未挂载页面、user 与 assistant 文本、reasoning、command result 和完整工具详情。索引按稳定 node key 缓存规范化小写文本,只有 block 的可搜索文本改变时才替换对应缓存文档。Enter 与 Shift+Enter 会在匹配 block 间循环移动,再按一次 `Ctrl+F` 会在所选 block 关闭搜索,Escape 则恢复搜索前确切的 transcript anchor。当前 block 与第一个可见匹配只在进程内 render state 中高亮;query、索引、选择与高亮绝不修改 Session event。
22
33
 
23
- Agent idle 时,composer 用 `Agent.followup()` 发送普通文本;running 时使用 `Agent.steer()`。它维护一个感知 Unicode grapheme 的插入点,支持左右与按词移动、逻辑行 Home/End、向前/向后及删除前一词、保留未提交草稿的已提交历史遍历,以及最多五行可见换行内容。`Ctrl+J` 插入换行,Enter 提交原始非空白文本而不裁掉首尾空白。`Ctrl+_` 或 `Ctrl+Shift+-` 通过最多 100 份进程内文本与光标快照撤销编辑,`Ctrl+Y` 则重做。快速的单 grapheme 输入和同方向删除会合并;paste、多行插入、suggestion 接受与历史接受各自形成独立 unit,光标移动只会终止合并。至少八行或 4 KiB 的 bracketed paste 会变成一条有界的 `[Pasted text]` placeholder;经过终端安全处理的原文只保留在当前进程中,并仅在提交时展开。`Ctrl+V` 会通过平台 provider 请求一次 typed system clipboard 读取;macOS 使用 `pbpaste`,Linux Wayland 使用 `wl-paste`,Linux X11 依次尝试 `xclip` 与 `xsel`。provider 使用仅 argv 的执行方式、短超时、完整字节上限和独立的图片 magic 校验;file-list 只解析本地 `file:` path。Windows、无头 SSH、缺少 utility 或媒体无效时只显示 live notice 并保留 draft,回退到 terminal paste 与 `@` 路径补全。剪贴板文本和已准入的图片 chip 作为一个 undo unit 插入。删除 placeholder 会移除其 payload;undo、redo、stash、已提交历史与 Agent view 切换都能保留 reference,而不挂载被粘贴的行。`Ctrl+R` 按从新到旧的顺序搜索当前 TUI 进程提交的去重 prompt;重复触发会选择更早的匹配,Enter 接受匹配,Escape 恢复原 draft 和确切光标。`Ctrl+S` 会暂存非空 draft、把它恢复到空 editor,或与另一个非空 draft 交换,因此恢复不会覆盖文本;每份 draft 保留自己的编辑历史。Prompt-history 搜索、暂存、paste reference 与编辑历史仅存在于当前进程,绝不进入 Session 日志。只含命令的斜杠查询会通过共享 suggestion controller 使用有效的 `ctx.commands.list(agent)` descriptor;旧版 Host 省略 additive discovery 字段时,compatibility catalog 会保留 TUI 自有的本地化 metadata,而确切匹配 first-party rc.8 命令描述的条目会得到本地化 fallback,不会改写同名第三方文本。在 draft 开头或空白之后的 `@token` 会通过同一 controller 使用可取消的 workspace 结果:优先调用 Host 提供的 `ctx.fs.completePaths()`,官方 rc.8 则通过 `listDir()` 与 `contains()` 执行等价的有界遍历。两条路径都以当前 Session workspace 为根;loading、无匹配和 truncated 状态保持有界,目录接受时保留尾部斜杠,文件接受时追加一个分隔空格。有界列表标出一个选中项;Up/Down 移动选中项而不遍历 prompt history,Shift+Tab 向前移动,Tab 或 Enter 接受选中的命令或路径,Escape 关闭列表但保留 draft。一个不可变 action registry 统一拥有有效的 Global、Composer、Suggestion、HistorySearch、TranscriptSearch、Transcript、Detail、Dialog、Footer、Work 与 Approval binding 及其输入优先级。`/help` 继续返回有效 command descriptor,同时打开由该 registry 生成的有界可滚动交互面板;不支持的 capability action 会被省略,`/help extra` 仍返回 usage error,Escape 会回到之前的本地模式。`Alt+P` 可打开现有 model picker,且不会替换当前 draft。以斜杠开头的输入会先尝试 `ctx.commands.execute()`;未匹配行仍作为普通提示提交,使 skill 手势继续走共享 Agent 路径。审批限定到确切的自有 Agent,只提供单次允许/拒绝。`ctx.userQuestions.registerProvider()` 提供 FIFO 结构化问题界面;即使 Agent 正在 running,其 Dialog 也拥有 Enter。
34
+ Agent idle 时,composer 用 `Agent.followup()` 发送普通文本;running 时使用 `Agent.steer()`。它维护一个感知 Unicode grapheme 的插入点,支持左右与按词移动、逻辑行 Home/End、向前/向后及删除前一词、保留未提交草稿的已提交历史遍历,以及最多五行可见换行内容。`Ctrl+J` 插入换行,Enter 提交原始非空白文本而不裁掉首尾空白。`Ctrl+_` 或 `Ctrl+Shift+-` 通过最多 100 份进程内文本与光标快照撤销编辑,`Ctrl+Y` 则重做。快速的单 grapheme 输入和同方向删除会合并;paste、多行插入、suggestion 接受与历史接受各自形成独立 unit,光标移动只会终止合并。至少八行或 4 KiB 的 bracketed paste 会变成一条有界的 `[Pasted text]` placeholder;经过终端安全处理的原文只保留在当前进程中,并仅在提交时展开。`Ctrl+V` 会通过平台 provider 请求一次 typed system clipboard 读取;macOS 使用 `pbpaste`,Linux Wayland 使用 `wl-paste`,Linux X11 依次尝试 `xclip` 与 `xsel`。provider 使用仅 argv 的执行方式、短超时、完整字节上限和独立的图片 magic 校验;file-list 只解析本地 `file:` path。Windows、无头 SSH、缺少 utility 或媒体无效时只显示 live notice 并保留 draft,回退到 terminal paste 与 `@` 路径补全。剪贴板文本和已准入的图片 chip 作为一个 undo unit 插入。删除 placeholder 会移除其 payload;undo、redo、stash、已提交历史与 Agent view 切换都能保留 reference,而不挂载被粘贴的行。`Ctrl+R` 按从新到旧的顺序搜索当前 TUI 进程提交的去重 prompt;重复触发会选择更早的匹配,Enter 接受匹配,Escape 恢复原 draft 和确切光标。`Ctrl+S` 会暂存非空 draft、把它恢复到空 editor,或与另一个非空 draft 交换,因此恢复不会覆盖文本;每份 draft 保留自己的编辑历史。Prompt-history 搜索、暂存、paste reference 与编辑历史仅存在于当前进程,绝不进入 Session 日志。只含命令的斜杠查询会通过共享 suggestion controller 使用有效的 `ctx.commands.list(agent)` descriptor;旧版 Host 省略 additive discovery 字段时,compatibility catalog 会保留 TUI 自有的本地化 metadata,而确切匹配旧版 first-party 命令描述的条目会得到本地化 fallback,不会改写同名第三方文本。在 draft 开头或空白之后的 `@token` 会通过同一 controller 使用可取消的 workspace 结果:优先调用 Host 提供的 `ctx.fs.completePaths()`,旧版 Host 则通过 `listDir()` 与 `contains()` 执行等价的有界遍历。两条路径都以当前 Session workspace 为根;loading、无匹配和 truncated 状态保持有界,目录接受时保留尾部斜杠,文件接受时追加一个分隔空格。有界列表标出一个选中项;Up/Down 移动选中项而不遍历 prompt history,Shift+Tab 向前移动,Tab 或 Enter 接受选中的命令或路径,Escape 关闭列表但保留 draft。一个不可变 action registry 统一拥有有效的 Global、Composer、Suggestion、HistorySearch、TranscriptSearch、Transcript、Detail、Dialog、Footer、Work 与 Approval binding 及其输入优先级。`/help` 继续返回有效 command descriptor,同时打开由该 registry 生成的有界可滚动交互面板;不支持的 capability action 会被省略,`/help extra` 仍返回 usage error,Escape 会回到之前的本地模式。`Alt+P` 可打开现有 model picker,且不会替换当前 draft。以斜杠开头的输入会先尝试 `ctx.commands.execute()`;未匹配行仍作为普通提示提交,使 skill 手势继续走共享 Agent 路径。审批限定到确切的自有 Agent,只提供单次允许/拒绝。`ctx.userQuestions.registerProvider()` 提供 FIFO 结构化问题界面;即使 Agent 正在 running,其 Dialog 也拥有 Enter。
24
35
 
25
- `/models` 会在 `ctx.llm.listProviders()` 及各提供方实时 `listModels()` 结果上打开有界、可滚动的选择器。声明了交互认证的提供方在尚未配置时显示为登录操作。首个原生流程是 OpenAI Codex:选择 **使用 ChatGPT 登录** 后,界面运行提供方自有的浏览器 OAuth 流程,把可刷新的凭据存到 `$DSH_HOME/oauth/openai-codex.json`,刷新账户模型目录,再回到选择器。模型声明可选 reasoning effort 时,第二个有界问题会选择一个确切等级。解析后的模型与 effort 会经 `ctx.agentDefaultModel.saveSelection()` 持久化,成为自有 Agent 的下一步选择,并立即更新 idle header;已经运行中的 step 仍保留它捕获的选择。
36
+ `/models` 会在 `ctx.llm.listProviders()` 及各提供方实时 `listModels()` 结果上打开有界、可滚动的选择器。声明了交互认证的提供方在尚未配置时显示为登录操作。首个原生流程是 OpenAI Codex:选择 **使用 ChatGPT 登录** 后,界面会通过官方 authorization owner 运行提供方自有的浏览器 OAuth flow,经 scoped credential-record owner 保存可刷新的 grant,刷新账户模型目录,再回到选择器。旧版 Host 会回退到 provider-neutral LLM authentication bridge,而不改变 UI 契约。模型声明可选 reasoning effort 时,第二个有界问题会选择一个确切等级。解析后的模型与 effort 会经 `ctx.agentDefaultModel.saveSelection()` 持久化,成为自有 Agent 的下一步选择,并立即更新 idle header;已经运行中的 step 仍保留它捕获的选择。
26
37
 
27
- `/mode` 会打开动态 `ctx.agentPresets` roster,其中包含本地化的 Standard(`standard`)、PTC(`code`)、Minimal(`minimal`)和 Creator(`cordis`)名称与说明,以及已经安装的 user preset。缺失和损坏的行会继续显示有界的禁用原因,但不会暴露 preset path。空白 Session 会在一项 single-flight transaction 中通过 `ctx.agentPresets.recompose()` 切换,并且只在新组装提交后追加 `agent-preset/selected`。第一次 `turn/start` 之后,选择操作会改为打开现有的新 Session 确认;Escape 会保持当前 Agent、draft、transcript anchor 与 footer,确认则会使用所选 preset 创建并发布新 Session,然后处置旧 handle。当前模式是可操作的 footer item;footer 与单选菜单行无论通过键盘还是 primary SGR click,都会使用同一项状态转换。本 package 只选择既有 preset,不会复制、编辑或移除 preset。
38
+ `/mode` 会打开动态 `ctx.agentPresets` roster,其中包含本地化的 Standard(`standard`)、PTC(`ptc`)、Minimal(`minimal`)和 Creator(`cordis`)名称与说明,以及已经安装的 user preset。缺失和损坏的行会继续显示有界的禁用原因,但不会暴露 preset path。耐久记录旧 downstream `code` preset 的 Session 会按 PTC 解释,并且只有成功 recomposition 提交时才追加规范的 `ptc` selection。空白 Session 会在一项 single-flight transaction 中通过 `ctx.agentPresets.recompose()` 切换,并且只在新组装提交后追加 `agent-preset/selected`。第一次 `turn/start` 之后,选择操作会改为打开现有的新 Session 确认;Escape 会保持当前 Agent、draft、transcript anchor 与 footer,确认则会使用所选 preset 创建并发布新 Session,然后处置旧 handle。当前模式是可操作的 footer item;footer 与单选菜单行无论通过键盘还是 primary SGR click,都会使用同一项状态转换。本 package 只选择既有 preset,不会复制、编辑或移除 preset。
28
39
 
29
- `/doctor` 会为自有 root Agent view 打开有界只读的运行健康面板。每次调用都会重新读取已经成功的后装 Host 兼容结果、协商后的终端能力、最多八个 provider 的认证与模型目录摘要、Plugin Hub 可用性与目录新鲜度、已安装插件数量,以及可选服务是否挂载。单个 provider 或 Registry 失败只形成一条 warning,不会使整个面板失败;更多 provider 会以省略数量报告。所有字段都会清理终端控制字符并限制长度,任意 provider 错误消息、package 路径和凭据都不会呈现,严重度除颜色外也始终有明确文字符号。快照、滚动位置与非敏感失败标签仅保留在当前进程中;耐久命令审计只记录 `Opened runtime diagnostics.`。Escape 关闭面板并返回原 transcript,不创建诊断 Session event。
40
+ `/doctor` 会为自有 root Agent view 打开有界只读的运行健康面板。每次调用都会重新读取已经成功的后装 Host 兼容结果、协商后的终端能力、Session storage preflight 事实、最多八个 provider 的认证与模型目录摘要、Plugin Hub 可用性与目录新鲜度、已安装插件数量,以及可选服务是否挂载。单个 provider 或 Registry 失败只形成一条 warning,不会使整个面板失败;更多 provider 会以省略数量报告。所有字段都会清理终端控制字符并限制长度,任意 provider 错误消息、package 路径和凭据都不会呈现,严重度除颜色外也始终有明确文字符号。快照、滚动位置与非敏感失败标签仅保留在当前进程中;耐久命令审计只记录 `Opened runtime diagnostics.`。Escape 关闭面板并返回原 transcript,不创建诊断 Session event。
30
41
 
31
42
  `/context` 会为自有 root Agent 打开有界只读的已加载上下文视图,显示 public loaded-context fact:system-prompt section 名称、dynamic context contributor 名称、当前 tool 名称、可用 skill 名称,以及当前 model 和 permission capability。它使用带 Agent scope 的 prompt assembly owner,不解析或渲染最终 assembled prompt 文本;可选 skill discovery 不可用时显示为空分类。快照与滚动位置仅保留在当前进程中,Escape 返回原 transcript,不创建 context Session event。
32
43
 
@@ -48,12 +59,14 @@ Compaction 生命周期 event 会被 fold 成一个耐久 transcript marker。Ma
48
59
 
49
60
  大量选项不会无限撑高终端。问题界面只挂载与 viewport 相称的一段,显示当前范围,并用上下方向键移动窗口;数字或精确标签仍可作为输入。Transcript 使用 Unicode cell 宽度预算物理显示行,而不会把一个语义 node 当成一行。同一 Turn 中连续的工具生命周期会投影为一个稳定的 activity node:已结束的活动占一行,运行中的活动最多再增加一行当前操作,类别与失败计数来自提供方所有的 presentation intent。Enter 或 primary click 会打开有界的 Activity Inspector;选择具体调用会进入已有的精确 Tool Detail,Escape 会依次从 Tool Detail、活动列表返回 transcript,并且不会留下过期 pointer region。完整 tool node 仍可用于搜索、选择、详情、交付物投影与耐久 reload。
50
61
 
51
- 在浏览模式之外,`PageUp` 与 `PageDown` 保持按 viewport 翻页,每个鼠标滚轮 report 则移动少量物理行。进入新的 assistant 文本 block 后,同方向惯性 report 会暂停到本次手势安静为止,因此不会跳过结果第一页;composer 为空时,Home 与 End 仍跳到最早 block 和实时尾部。Wheel event 会由最高优先级的 approval/question、dialog、Plugin Hub、detail、Work、suggestion/search 或 transcript owner 消费,到达边界也不会冒泡到背景 history;对可见 transcript block 的 primary SGR click 会进入浏览模式或移动现有焦点。Composer 上下方向键仍控制已提交输入历史。历史页面会在流式更新、Tasks 替换与终端 resize 期间保留语义顶部锚点;新事件只显示有更新内容的提示,不会把读者拉回底部。回到尾部后会恢复自动跟随。浏览模式会在翻页和 resize 期间保持焦点 parent block 可见,消费非导航输入而不修改 composer,并在流式替换移除焦点 key 时恢复到最近的存活 target。Pointer region 只来自已提交的可见 frame,会在 resize、modal 变化、Agent view 切换与 unmount 后替换,因此旧坐标不会继续触发 action。Tasks 仍是 focus target,其完整耐久 checklist 会在共享详情面板中打开。详情正文按 Unicode 显示宽度包装 grapheme cluster,并报告当前可见的物理行范围。过大的文本 block 会先在同一个语义 node 内显示带标记的头部、中部和尾部页面,之后导航才会到达相邻活动。[结果优先 transcript Agent Note](../../../.agents/notes/implemented/feature/2026-08-26-native-tui-result-centered-transcript.md)记录 projection、navigation、输出 scope 与兼容性决策。
62
+ 在浏览模式之外,`PageUp` 与 `PageDown` 保持按 viewport 翻页,每个鼠标滚轮 report 则移动少量物理行。进入新的 assistant 文本 block 后,同方向惯性 report 会暂停到本次手势安静为止,因此不会跳过结果第一页;composer 为空时,Home 与 End 仍跳到最早 block 和实时尾部。Wheel event 会由最高优先级的 approval/question、dialog、Plugin Hub、detail、Work、suggestion/search 或 transcript owner 消费,到达边界也不会冒泡到背景 history;对可见 transcript block 的 primary SGR click 会进入浏览模式或移动现有焦点。Composer 上下方向键仍控制已提交输入历史。历史页面会在流式更新、Tasks 替换与终端 resize 期间保留语义顶部锚点;新事件只显示有更新内容的提示,不会把读者拉回底部。回到尾部后会恢复自动跟随。浏览模式会在翻页和 resize 期间保持焦点 parent block 可见,消费非导航输入而不修改 composer,并在流式替换移除焦点 key 时恢复到最近的存活 target。Pointer region 只来自已提交的可见 frame,会在 resize、modal 变化、Agent view 切换与 unmount 后替换,因此旧坐标不会继续触发 action。Tasks 仍是 focus target,其完整耐久 checklist 会在共享详情面板中打开。详情正文按 Unicode 显示宽度包装 grapheme cluster,并报告当前可见的物理行范围。过大的文本 block 会先在同一个语义 node 内显示带标记的头部、中部和尾部页面,之后导航才会到达相邻活动。[结果优先 transcript Agent Note](../../../.agents/notes/implemented/feature/2026-08-26-native-tui-result-centered-transcript.zh.md)记录 projection、navigation、输出 scope 与兼容性决策。
52
63
 
53
- 终端改变只有一个 owner。它在写入前拒绝非 TTY stream,只进入一次 alternate buffer,启用 SGR 鼠标报告与 bracketed paste,复用 Ink 的 raw-mode 生命周期,并在关停流程等待命令取消、Session flush 或 Agent dispose 之前恢复 raw mode、mouse/paste mode、cursor 与 screen。完整的 SGR 按下、释放、移动与滚轮报告会在 composer 插入之前被消费;primary press 会通过 render-generation pointer registry 路由,滚轮报告导航 transcript。`TerminalSession.setSelectionMouseMode()` 只能在 active 且已确认 mouse capability 的 transaction 上增加 SGR `1002` button-motion,绝不会启用 `1003` all-motion,并会在 terminal handoff 后恢复该显式 mode。`TuiApp` 只在 detail panel 的 active selection drag 中请求它,释放后恢复普通 click owner;`mouse: off` 永远不会进入这条路径。这条幂等路径也会移除 signal listener 并结算未完成交互。
64
+ 终端改变只有一个 owner。它在写入前拒绝非 TTY stream,只进入一次 alternate buffer,启用 SGR 鼠标报告与 bracketed paste,复用 Ink 的 raw-mode 生命周期,并在关停流程等待命令取消、Session flush 或 Agent dispose 之前恢复 raw mode、mouse/paste mode、cursor 与 screen。完整的 SGR 按下、释放、移动与滚轮报告会在 composer 插入之前被消费;primary press 会通过 render-generation pointer registry 路由,滚轮报告导航 transcript。`TerminalSession.setSelectionMouseMode()` 只能在 active 且已确认 mouse capability 的 transaction 上增加 SGR `1002` button-motion,绝不会启用 `1003` all-motion,并会在 terminal handoff 后恢复该显式 mode;`TuiApp` 在 selection interaction 接入前不会请求它。这条幂等路径也会移除 signal listener 并结算未完成交互。
54
65
 
55
66
  原始输入在交互分派前经过一个增量 decoder。它跨传输 chunk 保留 UTF-8,将控制字节与相邻的已提交文本分开,并统一传统 xterm 按键、Kitty CSI-u、xterm modifyOtherKeys、application keypad 序列及协议提供的 Shift/Ctrl/Alt/Meta/Super 修饰键。同一 tokenizer 会消费 SGR 鼠标报告、focus 报告、bracketed paste、终端回复、未知功能键及未知或不完整 CSI,不让其字节泄漏到编辑器。单独的 Escape 在 35 ms 后结算;一段 bracketed paste 保持为一个 undo unit,并以 16 MiB 为上限,截断时显示 live notice。终端发出增强键盘协议时 TUI 可以解码,但不会根据 `$TERM` 推断支持,也不会在缺少协商所得终端能力时启用协议。
56
67
 
68
+ 有界 Work 面板只根据 owner 提供的事实投影 child execution route:provider、model、reasoning effort、最大输出和来源只在存在时显示,否则明确保持不可用。它不会根据 root selection 或显示标签推断 route。
69
+
57
70
  进入 alternate screen 前,`TerminalSession` 会通过同一个 decoder 在有界时间内发送设备、Kitty 键盘及 OSC 前景色和背景色查询。通过校验的 OSC 11 回复在仅存在于当前进程的 capability snapshot 中只会变成 `light` 或 `dark`;缺失或格式错误的回复会变成 `unknown`,原始回复不会保留。没有回复的终端会在 deadline 内进入界面,并使用传统输入且不启用增强 mouse、focus、paste 或 clipboard mode;只有确认过的 capability 才会启用对应 mode。跨 chunk 拆分的回复与交错的普通输入保持字节顺序,协商期间缓存的输入会在 Ink 挂载后分派。在 transcript 浏览或详情中按 Y,会通过已协商的 OSC 52 复制最多 100,000 个 UTF-8 字节。tmux 中同一序列会进入 tmux 配置的 clipboard buffer 路径,并可由其 `set-clipboard` 策略转发;SSH 只有在远端进程观察到回复后才会使用 OSC。不支持、超过限制或写入失败只会产生 live notice,绝不写入 Session event。颜色深度来自输出 stream 与 `NO_COLOR`;tmux 与 SSH 只作为当前进程的外层传输上下文记录。关停时只关闭该事务实际启用的 mode。
58
71
 
59
72
  文本编辑器使用终端真实光标,而不是渲染出来的反色空格光标。`TuiApp` 根据可见多行布局和 Unicode 显示宽度计算插入 cell,居中的启动 composer 会沿用 Ink/Yoga 对起始侧 cell 的取整方式。`TerminalSession.rendererOutput` 在每次 Ink 全屏渲染后恢复该 cell,同时拦下 Ink 隐藏光标的请求。终端事务只启用已协商的 bracketed paste,并在每条关停路径恢复 paste、mouse、focus、keyboard、cursor、raw 与 alternate-screen mode。退出临时 button-event 拖拽选择时,会在恢复 pointer region 前明确重新启用已协商的 `1000` click 与 `1006` SGR report,因此关闭 transcript 详情不会让终端滞留在仅选择的 mouse mode。这样 macOS 等终端 IME 的中日韩预编辑文本会锚定在正确位置;包括 Plugin Hub 详情在内的只读 panel 与只接受审批的交互会隐藏光标,teardown 仍会无条件恢复它。
@@ -62,7 +75,7 @@ Package 本地 design system 为 startup 与 transcript chrome、Plugin Hub、
62
75
 
63
76
  原生 TUI 通过 `ctx.tuiExtensions` 和 package entrypoint 暴露一个版本化的低 ABI DTO surface。插件可以注册 owner-scoped settings、带 priority 和 cell budget 的 keyed status row、managed select/confirm/input dialog、低优先级 shortcut、有界 workspace provider、structured fullscreen scene、针对已知 user/assistant message event 的有界 renderer、owner-scoped plugin-local JSON storage、sanitized completed-message observer,以及针对 input、rewind 和 Session switch boundary 的 allow/deny decision hook。Fullscreen scene 只渲染有界且 terminal-safe 的文字,也可以接收有界 input;host 保留 Escape、终端尺寸与 teardown ownership,它不会收到 React tree,也不会写入 Session state。Known-event renderer 只接收经过验证的 append-surface type、sequence、有界 terminal-safe text 与 assistant interruption marker,然后返回有界 text DTO 或回退到 host projection;它看不到 raw Session event、tool payload 或 model-only replacement。当 host 提供 Plugin Hub grant ledger 时,敏感的 storage、observer、decision、scene 与 message-render call 需要匹配的 package/version/activation identity,并在每次 call 重新检查 managed capability;ledger 只记录 contribution lifecycle transition,不替代 installed-profile truth。每个 registration 都携带 package/version metadata 与真实 Cordis activation id,返回 effect disposer 或可 dispose 的 storage handle,在 unload 时移除,并经过 timeout、cancellation、terminal sanitization、长度、quota 和冲突校验。Decision hook 具有固定 total deadline;timeout 或 failure 默认 allow,因此可选 extension 不会阻塞内建工作。Completed-message observer 只会从已知且已提交的 `assistant/message` event 接收有界 text、session/message id、turn/step 和 interrupted marker;reasoning、tool call、image、provider provenance 与完整 Session event 仍由 host 拥有。Storage 路径由 host 管理,位于 `$DSH_HOME/tui/extensions` 下;写入使用 writer lock 与 atomic replacement,损坏文件会先保留,再以空 namespace 重新打开。Settings 与 storage 的读写只能发生在 owner namespace 内。Registry 不执行 command,不替换 approval/question/security interaction,也不追加 durable Session event;nested command completion 仍由 `ctx.commands` 拥有。
64
77
 
65
- 完成的 reasoning 在 transcript 中只占一条 `Thinking · duration` 标题,其完整文本仍可通过 block 详情查看。围栏代码保留语言标题,窄屏表格转成逐行字段列表,工具摘要对 Session workspace 内路径使用相对形式,同时保留外部绝对路径。Terminal、read、search、diff、web、delegation 与 generic 行在 80 列下保持有界;低于 60 列时,activity row 与 footer 会省略次要元数据而不发生重叠。第一次请求前,居中的启动工作区显示解析后的 model 与提供方默认 reasoning effort。running 时,activity row 会在工作指示器和 `Esc stop` 旁显示耐久 request 选择;idle 时显示下一步选择。Footer 会投影同一份已捕获或下一步选择,并组合实际 `ctx.agentPresets` 模式、`ctx.permissionPresets`、以提供方用量为锚点的 `contextPressure`、耐久的 `tokenUsage` buckets、启发式的 `contextBreakdown`、权威 background-work counter、Session workspace 与已挂载 transcript 范围;只有容量和提供方用量样本同时存在时才显示 context,详情会标记 composition 为近似值,仅在 prompt denominator 存在时显示 cache-hit 百分比,并隐藏不可用值。挂载 `sessionStats` 时,同一详情只会在存在耐久 token boundary 且提供方报告 output token 的 step 上显示 settled 平均 TTFT 与 decode throughput;缺失 timing 时保持隐藏。只有至少一个 work row 时才显示 Work。Suggestion 处理完毕后,Tab 进入显式 Footer mode;Left/Right 或 Tab/Shift+Tab 在已挂载项目间移动,Enter 打开既有模型选择器、模式选择器、permission preset 选择器、有界 Work 面板或有界只读详情,Escape 返回 composer。Permission 变更执行已注册的 `/permission` 命令,不在本地修改策略。终端少于 56 列时保留 model、mode、permission 与存在时的 Work;更宽布局按优先级加入 context、transcript position 与 workspace。`NO_COLOR` 和有限色终端仍保留文本与符号;tmux 和 SSH 继承外层终端能力,Windows Terminal 使用同一套 ANSI 与 Unicode 宽度路径。
78
+ 完成的 reasoning 在 transcript 中只占一条 `Thinking · duration` 标题,其完整文本仍可通过 block 详情查看。围栏代码保留语言标题,窄屏表格转成逐行字段列表,工具摘要对 Session workspace 内路径使用相对形式,同时保留外部绝对路径。Terminal、read、search、diff、web、delegation 与 generic 行在 80 列下保持有界;低于 60 列时,activity row 与 footer 会省略次要元数据而不发生重叠。第一次请求前,居中的启动工作区显示解析后的 model 与提供方默认 reasoning effort。running 时,activity row 会在工作指示器和 `Esc stop` 旁显示耐久 request 选择;idle 时显示下一步选择。Footer 会投影同一份已捕获或下一步选择,并组合实际 `ctx.agentPresets` 模式、`ctx.permissionPresets`、以提供方用量为锚点的 `contextPressure`、耐久的 `tokenUsage` buckets、启发式的 `contextBreakdown`、权威 background-work counter、官方活动 Schedule projection、Session workspace 与已挂载 transcript 范围;只有容量和提供方用量样本同时存在时才显示 context,详情会标记 composition 为近似值,仅在 prompt denominator 存在时显示 cache-hit 百分比,并隐藏不可用值。挂载 `sessionStats` 时,同一详情只会在存在耐久 token boundary 且提供方报告 output token 的 step 上显示 settled 平均 TTFT 与 decode throughput;缺失 timing 时保持隐藏。Work 与 Schedule 项都只在各自 owner 发布至少一条 row 时出现。Suggestion 处理完毕后,Tab 进入显式 Footer mode;Left/Right 或 Tab/Shift+Tab 在已挂载项目间移动,Enter 打开既有模型选择器、模式选择器、permission preset 选择器、有界 Work/Schedule 面板或有界只读详情,Escape 返回 composer。Permission 变更执行已注册的 `/permission` 命令,不在本地修改策略。终端少于 56 列时保留 model、mode、permission 与存在时的 Work;更宽布局按优先级加入 Schedule、context、transcript position 与 workspace。`NO_COLOR` 和有限色终端仍保留文本与符号;tmux 和 SSH 继承外层终端能力,Windows Terminal 使用同一套 ANSI 与 Unicode 宽度路径。
66
79
 
67
80
  Footer 会在 provider 锚定的 context pressure 旁增加一个八 cell 的近似 `S` system、`T` tools、`M` messages composition bar。TPS 项在最新 step settled 后使用 provider output token;最新 step 仍在流式输出时,则从耐久 chunk 推导显式带 `~` 标记的四字符每 token 样本和六 cell 进程内趋势,Session-stats fallback 仍是 settled 的全 Session 汇总。Transcript 项会追加精确的未读行数;存在更新行时,点击它可直接回到 live tail。这些投影不缓存第二份 transcript 或 usage state,缺少必要 event 或 projection fact 时会消失。
68
81
 
@@ -78,41 +91,55 @@ Plugin Hub Detail 使用有界语义 section,依次呈现 Overview、Compatibi
78
91
 
79
92
  Registry 收录默认显示全部已接纳的目录记录,并按 Stars 排序。`Shift+I` 或已渲染 label 在“全部收录”和“仅可安装”之间切换;`Shift+S` 在 Relevance、Stars、Updated 与 Newest 之间循环。`Shift+C` 只循环已加载且未筛选 page 中实际出现的 Registry-owned category,并回到 All categories。已加载 row 都没有 category metadata 时,category binding 不执行请求,footer 与 pointer registry 也会省略该 control。已渲染的过滤、分类与排序 label 都支持 primary SGR click。TUI 会发送当前 installability、ordering 与 category,在列表尾部追加 opaque continuation page,按 plugin id 去重,并在 Registry 拒绝 stale cursor 时从第一页重新加载。后续 page 加载期间保留已有 card;目录状态和 Showing range 会公开当前过滤、排序与 continuation state,但不会进入 Session log。“全部收录”下的不可安装条目仍可查看详情,但没有 install action。
80
93
 
94
+ ## 目录
95
+
96
+ - [与 WebUI 对齐的原生终端工作流](#webui-aligned-terminal-workflows)
97
+ - [性能诊断](#performance-diagnostics)
98
+ - [Host 兼容性](#host-compatibility)
99
+ - [配置](#configuration)
100
+ - [模型体验](#model-experience)
101
+ - [已知限制与暂缓事项](#known-limitations-and-deferred-work)
102
+ - [开发备注](#dev-note)
103
+
104
+ <a id="webui-aligned-terminal-workflows"></a>
81
105
  ## 与 WebUI 对齐的原生终端工作流
82
106
 
83
107
  原生界面消费与 Web 相同的 Host owner,而不导入浏览器状态。每个 panel 都按 capability 门控,经过 terminal-safe 处理,完整支持键盘;只有实际渲染出来的动作才会同时发布 primary pointer region。
84
108
 
85
109
  - **Provider Center 与首次引导:** `/provider` 汇合 live/configurable route、脱敏 settings descriptor、不含值的 credential 状态、provider-owned 认证与模型发现。它可以新增或编辑受支持的 OpenAI-compatible route,暂存 endpoint/model 变更,通过 credential owner 写 API key,在 adapter 公布能力时登录或退出,并在 revision conflict 后恢复;secret 不会留在 Session、command history、diagnostics 或普通 draft 中。
86
- - **待发送输入队列:** root Agent 运行时,queue card 分开显示 next-step 与 next-turn work。带 revision 的 `agent.inbox.snapshot()` 会启用详情、编辑和 owner-fenced 删除;官方 rc.8 则退化为有界只读 lane 投影。Enter、Tab、Ctrl+Enter 与 Alt+Up 仍是同一 owner 上的快速路径。
110
+ - **待发送输入队列:** root Agent 运行时,queue card 分开显示 next-step 与 next-turn work。带 revision 的 `agent.inbox.snapshot()` 会启用详情、编辑和 owner-fenced 删除;旧版 Host 则退化为有界只读 lane 投影。Enter、Tab、Ctrl+Enter 与 Alt+Up 仍是同一 owner 上的快速路径。
87
111
  - **Session 与 Workspace 管理:** `/sessions` 按 Workspace 分组显示 active/archived Session,支持 metadata 搜索、preview、resume、rename、fork、archive 与安全的新建 Session 动作;只有 Workspace owner 暴露 unarchive mutation 时才显示恢复。`/workspace [path]` 和有界 Host 目录浏览器可以创建或选择 Workspace 路径,不移动 Session log,也不假定 Host 就是本地桌面。
88
- - **统一引用:** composer 的 `@` suggestion 合并有界 Workspace 文件发现与稳定规范 Session mention。File reference 仍由 attachment owner 或 filesystem owner 提供事实;较新 Session owner 会在提交前执行只读 metadata preflight,官方 rc.8 则在 `agent/pre-step` 验证并捕获不可变且不受信任的上下文。
112
+ - **统一引用:** composer 的 `@` suggestion 合并有界 Workspace 文件发现与稳定规范 Session mention。File reference 仍由 attachment owner 或 filesystem owner 提供事实;当前 Session owner 会在提交前执行只读 metadata preflight,旧版 owner 则在 `agent/pre-step` 验证并捕获不可变且不受信任的上下文。
89
113
  - **Goal、Plan 与交付物:** 耐久 Goal/Plan 投影进入紧凑状态面,其生命周期动作仍调用 owner command。已完成 Turn 会从耐久 tool/result fact 推导有界 produced-file row,提供 Host-owned 打开/复制动作,并在 closing assistant message 旁放置显式 reference;绝不从 prose 猜测交付物。
90
- - **Preset 与 Host Plugin Center:** `/presets` 列出健康和损坏的 roster entry,把来源 preset 原子复制进 user root,只删除 user-owned row,并把文件打开委托给 Host;只有 settings compare-and-set owner seam 存在时才显示未来默认值选择。`/host-plugins` 读取公共 Loader inventory 与 settings descriptor,只暴露 owner 支持的 revisioned edit;它与 Plugin Hub 安装分离,也不遍历 Loader 内部对象。
114
+ - **Preset、Host Plugin 与 Schedule Center:** `/presets` 列出健康和损坏的 roster entry,从 `AgentPresets.compositionInventory()` 投影结构化组合条目,把来源 preset 原子复制进 user root,只删除 user-owned row,并把文件打开委托给 Host;只有 settings compare-and-set owner seam 存在时才显示未来默认值选择。`/host-plugins` 分开显示已加载 Host 条目、Agent preset 组合与 settings descriptor;live 组合显示 Fiber phase,cold 组合保留 conditional enablement,损坏组合保留 owner 原因。`/schedules` 与 footer 读取官方活动 Schedule projection;创建、删除、持久化与派发仍是 Schedule owner 操作。
91
115
  - **Trajectory 与反馈:** `/trajectory` 把耐久 Session log 折叠成有界 turn/step ledger,提供 timing、token、search、fold、tail-follow、paging 与 inspector tab。已完成 assistant row 通过 feedback owner 提供 like、dislike、note 与 clear;反馈不改写消息,也不进入 transcript。
92
116
  - **附件与完整交互 ownership:** path completion、clipboard admission、终端拖放路径、图片 capability 检查、chip 与统一引用汇入同一有界 intake。全屏 panel、嵌套详情、footer action、transcript browse、link 与 selection 在 Escape 后恢复其确切键盘和 pointer region;隐藏或被覆盖的行不会发布陈旧 hit target。
93
117
 
94
- [WebUI 工作流对齐 Agent Note](../../../.agents/notes/implemented/feature/2026-08-25-native-tui-webui-workflow-alignment.md)记录 owner seam、durable/transient 边界、capability 退化与组装验证约定。
118
+ [WebUI 工作流对齐 Agent Note](../../../.agents/notes/implemented/feature/2026-08-25-native-tui-webui-workflow-alignment.zh.md)记录 owner seam、durable/transient 边界、capability 退化与组装验证约定。
95
119
 
96
120
  可选择的问题与菜单行会使用当前 theme 的 selection 颜色和粗体强调。Approval 让导航 metadata 保持次要样式,同时用粗体 success 渲染 Allow、用粗体 error 渲染 Reject;no-color mode 仍保留粗体 action label。通过 Escape 关闭 command-owned picker 表示用户主动取消:交互会以本地化 cancellation result 结束,并清除临时 footer notice,而不会留下 failure banner。SGR mouse ownership 活动期间,terminal transaction 会禁用 DEC alternate scroll,让 wheel report 到达前景 TUI owner,而不是变成 composer history 按键;释放 pointer ownership 或恢复终端时会重新启用 alternate scroll。Composer 换行会为本地化前缀在每个可见行预留固定 Unicode-cell gutter,终端光标也使用同一个 gutter。因此,长 `@` 引用、CJK 续写、垂直窗口移动与 `/lang` 切换都不会让 Ink 的换行列与 IME 插入点分离。
97
121
 
122
+ <a id="performance-diagnostics"></a>
98
123
  ## 性能诊断
99
124
 
100
- `pnpm run test:tui:perf` 会通过生产 transcript fold、搜索索引、物理行 viewport、详情换行和 Ink transcript renderer,运行一个可选择执行、确定性的 100/1,000/10,000-node 长 Session benchmark。Fixture 包含 Markdown 与 Unicode conversation block、工具组、大型输出、Tasks、已完成 delegation 和一次 streaming append。输出的 JSON 会记录 initial 与 appended fold 时间、append projection 加 render 时间、PageUp、搜索导航与刷新、40/80/160 列 resize、详情 projection 与打开、保留 heap、已挂载 transcript block,以及每 frame 输出字节。Wall-clock 与 heap 观察只描述所报告的主机;benchmark 与 correctness tests 分离,其阶段目标用于指导优化,不构成跨平台 latency 保证。归属的[长 Session benchmark Agent Note](../../../.agents/notes/implemented/testing/2026-08-16-native-tui-long-session-benchmark.md)记录初始机器基线和已知未达项目。
125
+ `pnpm run test:tui:perf` 会通过生产 transcript fold、搜索索引、物理行 viewport、详情换行和 Ink transcript renderer,运行一个可选择执行、确定性的 100/1,000/10,000-node 长 Session benchmark。Fixture 包含 Markdown 与 Unicode conversation block、工具组、大型输出、Tasks、已完成 delegation 和一次 streaming append。输出的 JSON 会记录 initial 与 appended fold 时间、append projection 加 render 时间、PageUp、搜索导航与刷新、40/80/160 列 resize、详情 projection 与打开、保留 heap、已挂载 transcript block,以及每 frame 输出字节。Wall-clock 与 heap 观察只描述所报告的主机;benchmark 与 correctness tests 分离,其阶段目标用于指导优化,不构成跨平台 latency 保证。归属的[长 Session benchmark Agent Note](../../../.agents/notes/implemented/testing/2026-08-16-native-tui-long-session-benchmark.zh.md)记录初始机器基线和已知未达项目。
101
126
 
102
- `TuiApp` 为每个 Agent 持有一个 append-oriented transcript projection。经过验证的 Session-event suffix 会以 copy-on-write 方式更新 stream、tool、activity、delegation、Tasks 和 compaction 状态,同时保留未变化 node 的 identity;resolver 变化、非 prefix snapshot、Session replacement 或 compaction start 会从完整耐久日志重建。完整 `foldTranscript()` 路径会从空状态运行同一个 event state machine,并继续作为 differential oracle。完整 transcript 搜索会在 node 引用未变化时复用规范化文本。Focused detail 按 node 或保留 child 引用缓存逻辑行,并按 terminal width 缓存物理行;resize 只使依赖宽度的结果失效。[增量 projection Agent Note](../../../.agents/notes/implemented/architecture/2026-08-16-native-tui-incremental-transcript-projection.md)记录 ownership 与 invalidation 规则。
127
+ `TuiApp` 为每个 Agent 持有一个 append-oriented transcript projection。经过验证的 Session-event suffix 会以 copy-on-write 方式更新 stream、tool、activity、delegation、Tasks 和 compaction 状态,同时保留未变化 node 的 identity;resolver 变化、非 prefix snapshot、Session replacement 或 compaction start 会从完整耐久日志重建。完整 `foldTranscript()` 路径会从空状态运行同一个 event state machine,并继续作为 differential oracle。完整 transcript 搜索会在 node 引用未变化时复用规范化文本。Focused detail 按 node 或保留 child 引用缓存逻辑行,并按 terminal width 缓存物理行;resize 只使依赖宽度的结果失效。[增量 projection Agent Note](../../../.agents/notes/implemented/architecture/2026-08-16-native-tui-incremental-transcript-projection.zh.md)记录 ownership 与 invalidation 规则。
103
128
 
104
- `TuiTranscriptViewportIndex` 保存 Agent-local 语义 key index、immutable node index、未测量 block 的保守高度、按 identity 与 width 缓存的精确测量,以及一个 Fenwick 物理行 prefix index。每个 frame 只测量足以填满物理行预算的 block 和第一个被排除的边界 block;前后各两个相邻 block 会挂载到零高度 overscan。固定高度的 tool、group、Tasks 和 compaction block 会跨 width 复用测量,text 测量则按 width 隔离。`TuiTranscriptScrollController` 是 live-tail follow、PageUp/PageDown、鼠标滚轮、Home/End、focus reveal、transcript search、rewind selection、replacement fallback 和 resize-stable semantic anchor 的唯一 transition authority。Oversized text entry 会保留进程内物理行范围;带标记的 head、middle 和 tail page 会先在同一个语义 assistant block 内前进,之后导航才会到达相邻 tool。点击 transcript block 会打开多数高度的详情 panel,而 footer 状态详情仍使用较小的有界 panel。index 引入前的 helper 继续作为 differential oracle。[物理行 virtualization Agent Note](../../../.agents/notes/implemented/architecture/2026-08-16-native-tui-physical-row-virtualization.md)记录 index 与校正规则。
129
+ `TuiTranscriptViewportIndex` 保存 Agent-local 语义 key index、immutable node index、未测量 block 的保守高度、按 identity 与 width 缓存的精确测量,以及一个 Fenwick 物理行 prefix index。每个 frame 只测量足以填满物理行预算的 block 和第一个被排除的边界 block;前后各两个相邻 block 会挂载到零高度 overscan。固定高度的 tool、group、Tasks 和 compaction block 会跨 width 复用测量,text 测量则按 width 隔离。`TuiTranscriptScrollController` 是 live-tail follow、PageUp/PageDown、鼠标滚轮、Home/End、focus reveal、transcript search、rewind selection、replacement fallback 和 resize-stable semantic anchor 的唯一 transition authority。超大 text entry 会保留进程内物理行范围;带标记的 head、middle 和 tail page 会先在同一个语义 assistant block 内前进,之后导航才会到达相邻 tool。点击 transcript block 会打开占据多数高度的详情 panel,而 footer 状态详情仍使用较小的有界 panel。index 引入前的 helper 继续作为 differential oracle。[物理行 virtualization Agent Note](../../../.agents/notes/implemented/architecture/2026-08-16-native-tui-physical-row-virtualization.zh.md)记录 index 与校正规则。
105
130
 
106
- `projectTuiScreenMap()` 会把有界的 transcript、Tasks 或 detail 行投影为供文本选择与安全链接激活使用的 immutable terminal cell。每一行记录 grapheme cluster、实际显示宽度、宽 grapheme 的 continuation cell、soft-wrap 与 hard-newline 边界、语义 block key、可选择 text、不可选择的 gutter/padding 来源,以及出现时经过验证的 HTTP(S) hyperlink target。Logical map 保留 source order;visual map 使用 UAX #9 grapheme ordering,同时保留供 copy 使用的 logical index。Map 不读取 Ink internals 或修改 Session state。OSC 8 只为 sanitized URL 输出,未移动的 primary click 会在普通 pointer region 前把安全 target 交给 host browser opener。[screen-cell provenance Agent Note](../../../.agents/notes/implemented/architecture/2026-08-21-native-tui-screen-cell-provenance.md)记录该有界算法及其限制。
131
+ `projectTuiScreenMap()` 会把有界的 transcript、Tasks 或 detail 行投影为供文本选择与安全链接激活使用的 immutable terminal cell。每一行记录 grapheme cluster、实际显示宽度、宽 grapheme 的 continuation cell、soft-wrap 与 hard-newline 边界、语义 block key、可选择 text、不可选择的 gutter/padding 来源,以及出现时经过验证的 HTTP(S) hyperlink target。Logical map 保留 source order;visual map 使用 UAX #9 grapheme ordering,同时保留供 copy 使用的 logical index。Map 不读取 Ink internals 或修改 Session state。OSC 8 只为 sanitized URL 输出,未移动的 primary click 会在普通 pointer region 前把安全 target 交给 host browser opener。[screen-cell provenance Agent Note](../../../.agents/notes/implemented/architecture/2026-08-21-native-tui-screen-cell-provenance.zh.md)记录该有界算法及其限制。
107
132
 
108
- `resolveTuiScreenSelection()` 会在该 map 上解析进程内的 drag、double-click 和 triple-click gesture。未移动的 drag coordinate 不返回 range,交还普通 click owner;double-click 按固定 class 处理 path/URL、CJK、emoji、标点和空白,triple-click 覆盖一个由 soft-wrap 连接的 logical line。`extendTuiScreenSelection()` 允许 Shift+Arrow/Home/End 按 grapheme、最近物理行或 logical-line 边缘单调扩展已有 pointer range。`TuiApp` 会把 map 应用到可见 transcript text/body row、ToolGroup heading 与 child heading、compaction status/error/summary row、固定 Tasks 的 heading/task content 和 detail row:mapped cell 会显示 selection highlight,完成或经键盘扩展的 range 通过协商后的 `onCopy()` path 复制,clipboard 失败时保留 selection 并显示 remediation。树 glyph、status marker、被省略的 operation/task row 和 padding 仍为 no-select;OSC 8 activation 与 UAX #9 visual bidi ordering 都已由独立 owner 实现。[selection-range Agent Note](../../../.agents/notes/implemented/architecture/2026-08-21-native-tui-selection-ranges.md)记录确定性的 range 规则与当前 owner 限制。
133
+ `resolveTuiScreenSelection()` 会在该 map 上解析进程内的 drag、double-click 和 triple-click gesture。未移动的 drag coordinate 不返回 range,交还普通 click owner;double-click 按固定 class 处理 path/URL、CJK、emoji、标点和空白,triple-click 覆盖一个由 soft-wrap 连接的 logical line。`extendTuiScreenSelection()` 允许 Shift+Arrow/Home/End 按 grapheme、最近物理行或 logical-line 边缘单调扩展已有 pointer range。`TuiApp` 会把 map 应用到可见 transcript text/body row、ToolGroup heading 与 child heading、compaction status/error/summary row、固定 Tasks 的 heading/task content 和 detail row:mapped cell 会显示 selection highlight,完成或经键盘扩展的 range 通过协商后的 `onCopy()` path 复制,clipboard 失败时保留 selection 并显示 remediation。树 glyph、status marker、被省略的 operation/task row 和 padding 仍为 no-select;OSC 8 activation 与 UAX #9 visual bidi ordering 都已由独立 owner 实现。[selection-range Agent Note](../../../.agents/notes/implemented/architecture/2026-08-21-native-tui-selection-ranges.zh.md)记录确定性的 range 规则与当前 owner 限制。
109
134
 
110
135
  从 `@` 补全选择的图片路径会通过 `ctx.fs` 与 `ctx.attachments` admission 为耐久的 content-addressed 引用。Composer 显示类型化 chip,在本地 draft、undo history、stash 与 Agent view 状态中只保留引用;普通消息追加 `ImageBlock` 引用,支持图片的命令则通过 `ctx.commands.execute()` 接收瞬时编码字节。确切路由模型必须在 `inputModalities` 中明确声明 `image`,否则提交会在 Agent 或命令投递前失败,并保留原 draft。
111
136
 
137
+ <a id="host-compatibility"></a>
112
138
  ## Host 兼容性
113
139
 
114
140
  后装 runtime 把所有官方 package import 集中在 `src/host.ts`。顶层 startup provider 会在 runtime 挂载前,把已经通过的精确版本、profile 外 package 与 4 个 system preset 校验发布为带类型且仅存在于当前进程的 `tuiStartup.diagnostics` 快照,并提供官方 preset root;不兼容安装仍会在命令解析或终端变更之前失败。如果受支持的 Host 不提供交互式 provider 认证或有界文件系统补全,`/models` 只列出已经配置的 route,路径建议保持为空;普通模型请求和显式路径提交仍然可用。Session rewind 在本 package 内使用相同的耐久事件算法,不要求较新的 `@deepseek-ai/dsh-session` 命名导出。
115
141
 
142
+ <a id="configuration"></a>
116
143
  ## 配置
117
144
 
118
145
  | 键 | 默认值 | 行为 |
@@ -151,8 +178,9 @@ tui:
151
178
 
152
179
  `/config` 会打开原生设置菜单。用户可以选择内置或发现的 custom theme、选择 TUI 或外层终端的 mouse ownership、选择一种 running animation、选择任意支持按键的 interaction action,或重置全部 TUI settings。`/lang [en|zh]` 通过同一个 settings owner 切换 runtime catalog;不带参数的 `/lang` 会打开有界语言选择器。快捷键编辑器接受逗号分隔的规范序列;输入 `default` 只会删除该 action 的 override 并恢复内建 binding。确认重置后,完整的 `tui` settings section 会被替换为空默认值。每次变更都通过 `ctx.settings` 提交,因此由 file provider 负责持久化,当前 theme、activity、locale、mouse mode 与 interaction registry 会立即更新而无需重启 Agent。common primitives、startup guidance、diagnostics 和 command description 都消费所选 catalog,而 provider-owned description 保留稳定英文 fallback。
153
180
 
154
- Diff 详情的 `split` 与 `unified` 使用同一套有界对齐:保留 context,把 replacement 配对为相邻的 `-`/`+` 行,并为 only-add/only-delete hunk 保留独立标记。只有在两个可读 pane 和 gutter 都能容纳时才选择 split;显式 split 请求低于物理 gutter 宽度时会降级为 unified。源代码行不会换行,长 path 和 Unicode 内容按终端显示 cell 截断;DTO 没有 offset 时不会编造行号。对齐与回退边界见[自适应 diff Agent Note](../../../.agents/notes/implemented/architecture/2026-08-21-native-tui-adaptive-diff.md)。
181
+ Diff 详情的 `split` 与 `unified` 使用同一套有界对齐:保留 context,把 replacement 配对为相邻的 `-`/`+` 行,并为 only-add/only-delete hunk 保留独立标记。只有在两个可读 pane 和 gutter 都能容纳时才选择 split;显式 split 请求低于物理 gutter 宽度时会降级为 unified。源代码行不会换行,长 path 和 Unicode 内容按终端显示 cell 截断;DTO 没有 offset 时不会编造行号。对齐与回退边界见[自适应 diff Agent Note](../../../.agents/notes/implemented/architecture/2026-08-21-native-tui-adaptive-diff.zh.md)。
155
182
 
183
+ <a id="model-experience"></a>
156
184
  ## 模型体验
157
185
 
158
186
  间接影响:选择哪一条已注册 LLM 路由接收 root 的下一次普通请求,并通过 continuable subagent service 交付明确的 child-view input;模型可见内容仍由适配器与 `tui-app` bundle 拥有。
@@ -161,12 +189,18 @@ Diff 详情的 `split` 与 `unified` 使用同一套有界对齐:保留 contex
161
189
 
162
190
  切换提供方或模型会让下一 Agent step 进入不同的提供方缓存域;除此以外,本包不注册 system-prompt section 或工具 schema。
163
191
 
192
+ <a id="known-limitations-and-deferred-work"></a>
164
193
  ## 已知限制与暂缓事项
165
194
 
166
195
  - **只有一个可见 Agent view,且只挂载一页有界 transcript**:root 与 live continuable child view 会原位切换;不提供同时显示的 pane 或 Session tab。Inactive 与 one-shot local child 及 remote run 仍为 summary-only。每个 view 的 draft 只存在于进程内,不会持久化。
167
- - **Preset 源文件编辑委托给 Host**:`/presets` 已负责默认选择、原子复制、检查与 user preset 删除,但不会内嵌 YAML editor 或虚构 composition validation;Open 使用 Host opener,下一次读取仍由 roster 决定权威状态。
196
+ - **Preset 源文件编辑委托给 Host**:`/presets` 负责默认选择、原子复制、结构化组合检查与 user preset 删除,但不会内嵌 YAML editor 或独立验证 composition 文件;Open 使用 Host opener,下一次读取仍由 roster 决定权威状态。
168
197
  - **指针只属于实际渲染的动作**:primary SGR click 已覆盖 transcript、footer、Work、Plugin Hub、Provider、Session、Preset、Trajectory、Host Plugin、directory browser、detail、question、approval 与 suggestion 等已挂载 surface;disabled、隐藏、被 overlay 覆盖或要求显式确认的动作不发布 stale hit target,仍可通过键盘完成。
169
198
  - **终端集成随宿主而异**:自动化 PTY 覆盖证明已提交 Unicode、窄屏布局、bracketed-paste 恢复与光标定位。原生 macOS IME preedit 和 Windows ConPTY 行为仍是手工 release check。
170
199
  - **终端图片粘贴不可用**:标准终端输入只提供已提交文本,不提供带类型的图片字节。macOS 和 Linux 在平台 clipboard utility 可用时可通过 `Ctrl+V` 读取并校验图片字节;Windows、无头 SSH 与不支持的终端回退到 `@` 路径补全。普通消息或命令提交前仍会预检确切模型的 `inputModalities`,再交给 Agent 或命令层。
171
200
  - **Ink 5 跟随仓库 React 18 版本线**:采用更新 renderer major 需要先证明隔离的 React build face,或协调 Web React 迁移。
172
201
  - **Contribution ABI 刻意保持窄小**:第三方插件通过 `ctx.tuiExtensions` 注册结构化 DTO,不能提供 React component、任意 Session event 或 process isolation。Fullscreen scene 使用 host-owned text frame 与 input ownership;grant/effect-ledger authorization 仍按 capability 限定。
202
+
203
+ <a id="dev-note"></a>
204
+ ### 开发备注
205
+
206
+ 无。