Skip to content
Merged

Dev #162

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
170 commits
Select commit Hold shift + click to select a range
a98341f
docs(文档): 更新 README 当前架构说明
lyfmt Jun 20, 2026
3b857d8
Merge branch 'dev' into chore/readme-refresh
lyfmt Jun 20, 2026
ff54a79
Merge pull request #152 from lyfmt/chore/readme-refresh
lyfmt Jun 20, 2026
28c89aa
chore: start anthropic ai compatibility layer
lyfmt Jun 21, 2026
1b43353
feat(ai): add anthropic messages request builder
lyfmt Jun 21, 2026
bf19bb1
feat(ai): normalize anthropic messages stream
lyfmt Jun 21, 2026
0dc77ba
feat(ai): add anthropic provider adapter
lyfmt Jun 21, 2026
142a208
feat(boot): wire anthropic ai provider
lyfmt Jun 21, 2026
20f9032
docs(boot): document anthropic ai provider configuration
lyfmt Jun 21, 2026
ed9f962
fix(ai): harden anthropic request compatibility
lyfmt Jun 21, 2026
092e040
fix(ai): disable unsafe anthropic thinking replay
lyfmt Jun 21, 2026
cb953e5
fix(ai): stop anthropic stream after provider error
lyfmt Jun 21, 2026
ad11398
fix(boot): align anthropic example thinking support
lyfmt Jun 21, 2026
600763f
fix(ai): 合并 Anthropic stream usage
lyfmt Jun 22, 2026
8c8ba63
fix(boot): 恢复 OpenAI 示例 thinking 能力
lyfmt Jun 22, 2026
ca7dd24
Merge pull request #153 from lyfmt/feature/anthropic-ai-compat
lyfmt Jun 22, 2026
8f6f08f
feat(compact): 添加状态回填运行时端口
lyfmt Jun 22, 2026
4516bee
feat(compact): 聚合 compact 后状态回填消息
lyfmt Jun 22, 2026
fb0089e
feat(compact): 接入 compact 状态回填端口
lyfmt Jun 22, 2026
67a2833
feat(subagent): 回填 compact 后 agent 状态
lyfmt Jun 22, 2026
9732a9a
feat(runtime): 装配 compact 状态回填
lyfmt Jun 22, 2026
916deb7
test(compact): 覆盖状态回填截断和安全边界
lyfmt Jun 22, 2026
6829486
chore: start web search provider work
lyfmt Jun 22, 2026
1f8a9ef
feat: add web search contracts
lyfmt Jun 22, 2026
7cb562d
feat: add web tool input validation
lyfmt Jun 22, 2026
999f2f5
fix(compact): 修复状态回填分支一致性
lyfmt Jun 22, 2026
a71b420
feat: add web provider registry
lyfmt Jun 22, 2026
a4a0076
feat: add commercial web search providers
lyfmt Jun 22, 2026
759819f
feat: add web search and fetch tools
lyfmt Jun 22, 2026
abdabf9
feat: wire web search tool configuration
lyfmt Jun 22, 2026
57f7dda
docs: document commercial web search tools
lyfmt Jun 22, 2026
dbf0026
fix: harden web search provider configuration
lyfmt Jun 22, 2026
ad114b1
fix: make web fetch local
lyfmt Jun 22, 2026
9f5f6f5
chore(session): 初始化 JSONL 优化实现分支
lyfmt Jun 23, 2026
c65fa53
perf(session): 流式读取 JSONL session
lyfmt Jun 23, 2026
4ddb922
perf(session): 仅读取 JSONL header 首行
lyfmt Jun 23, 2026
c36a334
test(session): 补强 header-only 查询回归
lyfmt Jun 23, 2026
7fe58cd
fix(session): 避免 header 查询解码 entry 字节
lyfmt Jun 23, 2026
ff92b0c
fix(session): 严格解码 JSONL header 首行
lyfmt Jun 23, 2026
82c4649
fix(session): 跳过不可读 session header
lyfmt Jun 23, 2026
3ea2e1f
perf(session): 轻量扫描 resume 元数据
lyfmt Jun 23, 2026
f581390
fix(session): 保留 resume 单条容错
lyfmt Jun 23, 2026
8e3888b
fix(session): 校验 resume 扫描 header id
lyfmt Jun 23, 2026
1e4e389
fix(session): 校验 JSONL header 文件匹配
lyfmt Jun 23, 2026
6d27abb
fix(session): 补强 resume 扫描空值容错
lyfmt Jun 23, 2026
ca9291f
perf(session): 限制 resume 元数据并发加载
lyfmt Jun 23, 2026
dead209
fix(session): 保留 resume 并发扫描异常
lyfmt Jun 23, 2026
82a03b2
docs(session): 沉淀 JSONL 优化边界
lyfmt Jun 23, 2026
054f869
Merge pull request #156 from lyfmt/feature/web-search-providers
lyfmt Jun 23, 2026
1b17868
feat: add web result store
lyfmt Jun 23, 2026
6b112a0
feat: add web content retrieval tool
lyfmt Jun 23, 2026
b0822ea
feat: persist web tool results
lyfmt Jun 23, 2026
da48fda
feat: add web search provider fallback
lyfmt Jun 23, 2026
224ce1e
fix: wire web result store in boot
lyfmt Jun 23, 2026
ac710de
feat: add exa web search provider
lyfmt Jun 23, 2026
a21d79c
feat: improve web fetch extraction
lyfmt Jun 23, 2026
0bde40c
docs: document web access phase one
lyfmt Jun 23, 2026
d2f6606
fix: address web access review findings
lyfmt Jun 23, 2026
89801a8
fix: refine web result cache semantics
lyfmt Jun 23, 2026
52e77b6
fix: lock web cache reads consistently
lyfmt Jun 23, 2026
8da2fc7
fix(web): 兼容 Exa MCP 纯文本搜索结果
lyfmt Jun 23, 2026
83ba90d
Merge pull request #158 from lyfmt/feature/web-search-cache-exa
lyfmt Jun 23, 2026
ec9c914
Merge pull request #157 from lyfmt/feature/session-jsonl-optimization
lyfmt Jun 23, 2026
2998327
Merge pull request #155 from lyfmt/feature/compact-state-backfill
lyfmt Jun 23, 2026
38d1aca
chore: 启动 TUI 物理行协议修复
lyfmt Jul 14, 2026
1cba448
test(tui): 覆盖帧内嵌换行回归
lyfmt Jul 14, 2026
ce82130
refactor(tui): 用物理行约束渲染帧
lyfmt Jul 14, 2026
95464a2
fix(tui): 在帧边界拆分所有逻辑换行
lyfmt Jul 14, 2026
c1baff7
test(tui): 验证真实 PTY 连续帧不覆盖
lyfmt Jul 14, 2026
bf10497
Merge pull request #159 from lyfmt/fix/tui-physical-line-frame
lyfmt Jul 14, 2026
633f08e
chore: 启动 TUI viewport 布局修复
lyfmt Jul 14, 2026
53800e3
test(tui): 固定消息输入区域高度预算
lyfmt Jul 14, 2026
fd21984
refactor(tui): 集中计算帧区域高度
lyfmt Jul 14, 2026
e659a9d
fix(tui): 用消息 viewport 约束最终帧
lyfmt Jul 14, 2026
a0666a4
feat(tui): 支持消息视口按页滚动
lyfmt Jul 14, 2026
8708d35
fix(tui): resize 时保留消息滚动状态
lyfmt Jul 14, 2026
19dfbd2
test(tui): 固定工具进度有界尾部语义
lyfmt Jul 15, 2026
d06b504
fix(tui): 限制运行中工具输出尾部
lyfmt Jul 15, 2026
f9d058e
feat(tui): 增加可合并重绘调度器
lyfmt Jul 15, 2026
514ca56
fix(tui): 合并事件触发的终端重绘
lyfmt Jul 15, 2026
98fffc3
test(tui): 增加大工具输出性能门槛
lyfmt Jul 15, 2026
e7becb5
test(tool): 固定有限单行事件摘要契约
lyfmt Jul 15, 2026
5623b3f
fix(tool): 生成有限单行生命周期摘要
lyfmt Jul 15, 2026
faac33e
fix(tool): 收紧内建与 MCP 调用展示
lyfmt Jul 15, 2026
d775614
test(tui): 固定工具折叠与展开行预算
lyfmt Jul 15, 2026
36ba1e4
fix(tui): 统一工具折叠与展开预算
lyfmt Jul 15, 2026
f1bdc84
fix(tool): 收紧剩余通用输入摘要
lyfmt Jul 15, 2026
d56c0ac
fix(tui): 窄宽度保留工具省略标记
lyfmt Jul 15, 2026
c91786b
test(ai): 复现 AssistantStart 阻断 provider 回退
lyfmt Jul 15, 2026
3e42c21
fix(ai): 仅用可见输出阻止 provider 回退
lyfmt Jul 15, 2026
8b33ca4
feat(contracts): 增加 provider fallback 生命周期事件
lyfmt Jul 15, 2026
efd2ba4
feat(ai): 发布 provider attempt 回退通知
lyfmt Jul 15, 2026
4347e5c
feat(agent): 映射 provider fallback 生命周期
lyfmt Jul 15, 2026
86beaca
feat(tui): 展示 provider fallback 状态
lyfmt Jul 15, 2026
a195eb6
docs(architecture): 记录 provider fallback 事件流
lyfmt Jul 15, 2026
cece49d
fix(ai): 保留 provider fallback 通知身份
lyfmt Jul 15, 2026
1a5b33d
test(tui): 固定恢复工具调用结果关联
lyfmt Jul 15, 2026
0e2f6af
fix(tui): 关联恢复 transcript 的工具结果
lyfmt Jul 15, 2026
f0e79a4
refactor(tui): 统一实时与恢复工具投影
lyfmt Jul 15, 2026
2fe0d58
test(tui): 验证恢复首帧工具完成状态
lyfmt Jul 15, 2026
020364b
fix(tui): isolate rendering in alternate screen
lyfmt Jul 15, 2026
0a242e3
feat(tui): partition history from live transcript
lyfmt Jul 15, 2026
c800262
fix(tui): retain bounded history projection
lyfmt Jul 15, 2026
14ecd9e
feat(tui): allocate history and live content regions
lyfmt Jul 15, 2026
a21b56a
feat(tui): render bounded history beside live output
lyfmt Jul 15, 2026
60fbf49
refactor(tui): render fixed alternate-screen frames
lyfmt Jul 15, 2026
0927a99
fix(tui): preserve bounded history across live redraws
lyfmt Jul 15, 2026
7feb32c
test(tui): verify alternate-screen history split
lyfmt Jul 15, 2026
aa3466a
docs(tui): record alternate-screen rendering invariants
lyfmt Jul 15, 2026
b5a0d19
fix(tui): reconcile terminal size before redraw
lyfmt Jul 15, 2026
1e1e14c
fix(tui): render leading streaming delta
lyfmt Jul 15, 2026
0c9dadf
fix(tui): route mouse wheel to transcript history
lyfmt Jul 15, 2026
e094b5f
test(tui): cover streaming and wheel interaction in PTY
lyfmt Jul 15, 2026
8826686
refactor(tui): run terminal session on normal screen
lyfmt Jul 15, 2026
819f93a
feat(tui): track inline terminal viewport
lyfmt Jul 15, 2026
71df9da
feat(tui): track committed transcript prefix
lyfmt Jul 15, 2026
6c02e3b
refactor(tui): split transcript from mutable surface
lyfmt Jul 15, 2026
60fc799
feat(tui): render inline viewport above terminal scrollback
lyfmt Jul 15, 2026
1287436
refactor(tui): coordinate transcript commits and inline surface
lyfmt Jul 15, 2026
5466efe
refactor(tui): return scrollback controls to terminal
lyfmt Jul 15, 2026
c76f643
test(tui): lock inline scrollback commit protocol
lyfmt Jul 15, 2026
47efc9a
fix(tui): preserve scrollback across resize and close
lyfmt Jul 16, 2026
3541623
test(tui): verify native scrollback in tmux pty
lyfmt Jul 16, 2026
67112c7
docs(tui): record inline scrollback invariants
lyfmt Jul 16, 2026
19bcdc7
feat(tui): restore startup banner artwork (task 1/4)
lyfmt Jul 17, 2026
7df215c
feat(tui): commit startup banner to native scrollback (task 2/4)
lyfmt Jul 17, 2026
20332da
fix(tui): show startup banner in inline terminal (task 3/4)
lyfmt Jul 17, 2026
5c66220
docs(tui): record startup banner invariant (task 4/4)
lyfmt Jul 17, 2026
9820867
Merge pull request #161 from lyfmt/refactor/tui-inline-terminal-scrol…
lyfmt Jul 17, 2026
dfcd003
fix(boot): load user root configuration
lyfmt Jul 20, 2026
b46c231
docs(config): document user root configuration
lyfmt Jul 20, 2026
975bc8d
refactor(permission): migrate mode contracts (task 1/6)
lyfmt Jul 21, 2026
6b0480a
refactor(permission): unify mode authorization routing (task 2/6)
lyfmt Jul 21, 2026
b6fa9c1
feat(permission): add model auto reviewer (task 3/6)
lyfmt Jul 21, 2026
b3cb0e5
fix(permission): align runtime sandbox profiles (task 4/6)
lyfmt Jul 21, 2026
9a9970c
feat: add steering message queue foundation
lyfmt Jul 21, 2026
1dcc98a
feat(permission): migrate runtime surfaces to three modes (task 5/6)
lyfmt Jul 21, 2026
6d3162a
fix(permission): close three-mode migration gaps (task 6/6)
lyfmt Jul 21, 2026
a02a56e
fix(tui): merge pending steering input
lyfmt Jul 21, 2026
73f5cb1
fix(tui): render and recall pending steering
lyfmt Jul 21, 2026
f9eaf00
fix(tui): submit steering after interrupt
lyfmt Jul 21, 2026
83f773b
feat(permission): build bounded auto reviewer context
lyfmt Jul 21, 2026
995fc31
fix(tui): hide approval details from status bar
lyfmt Jul 21, 2026
c9a5360
merge: permission three modes
lyfmt Jul 21, 2026
a60f186
feat(tui): format working directory status label (task 1/4)
lyfmt Jul 21, 2026
ec05cfb
feat(tui): show cwd in status bar (tasks 2-3/4)
lyfmt Jul 21, 2026
976e555
merge: tui cwd status
lyfmt Jul 21, 2026
444ac11
refactor(subagent): define simplified spawn wait contracts
lyfmt Jul 21, 2026
4d5c144
refactor(subagent): expose only spawn and wait tools
lyfmt Jul 21, 2026
d811614
refactor(subagent): separate agent and run runtime state
lyfmt Jul 21, 2026
46a5873
feat(subagent): deliver completions exactly once
lyfmt Jul 21, 2026
951ef33
refactor(subagent): remove legacy control surfaces
lyfmt Jul 21, 2026
b5299a5
test(subagent): verify simplified runtime end to end
lyfmt Jul 21, 2026
31889f6
docs(skill): update subagent runtime knowledge
lyfmt Jul 21, 2026
1d2ca73
test(subagent): cover active turn completion delivery
lyfmt Jul 21, 2026
3111e63
feat(tui): add terminal render intent
lyfmt Jul 21, 2026
35a975b
feat(tui): reset transcript commit epoch
lyfmt Jul 21, 2026
4d72141
feat(tui): replace terminal frame on session switch
lyfmt Jul 21, 2026
c85705e
fix(tui): refresh terminal after session switch
lyfmt Jul 21, 2026
0b7407c
test(tui): cover session replacement in pty
lyfmt Jul 21, 2026
8dc2cc2
fix(subagent): finalize simplified async runtime
lyfmt Jul 21, 2026
6a65f0d
merge: subagent api simplification
lyfmt Jul 21, 2026
850e27b
docs(readme): 同步当前项目能力说明
lyfmt Jul 21, 2026
f8062a6
Merge pull request #163 from lyfmt/chore/readme-master-refresh
lyfmt Jul 21, 2026
090b591
feat(subagent): define expert agent contracts
lyfmt Jul 21, 2026
23db168
feat(resource): load layered expert agent yaml
lyfmt Jul 21, 2026
5ff5466
feat(tool): select expert agents in spawn
lyfmt Jul 21, 2026
0e5d09e
feat(subagent): persist expert prompt in child session
lyfmt Jul 21, 2026
73c47f1
feat(boot): load expert agents for spawn at startup
lyfmt Jul 21, 2026
f044a5d
Merge pull request #164 from lyfmt/feature/expert-agents
lyfmt Jul 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 2 additions & 1 deletion .codex/skills/lypi-architecture/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ The root `pom.xml` defines these Maven modules:
- Transports adapt input/output and display. They should not own durable session or tool state.
- Session history is append-only JSONL; branch movement changes the leaf, not old entries.
- Permission runtime changes are represented by session entries and replayed into `SessionContext`; do not mutate historical entries to change permission state.
- Tool calls, permission decisions, retry, compaction and UI updates flow through contract events where possible.
- Tool calls, permission decisions, retry, provider fallback, compaction and UI updates flow through contract events where possible.
- Provider retry and fallback notices are stream control events: agent core maps them to lifecycle events, TUI projects transient state, and neither enters the durable transcript.
- Permission request/decision events expose approval kind, available decisions and additional permission metadata for TUI/headless rendering.
- Memory consolidation is driven by `TurnEndEvent` after the main turn completes; `DefaultTurnExecutor` must not synchronously call legacy `MemoryExtractionWorker` on the user-facing path.
- `TurnEndEvent.leafEntryId` is the stable fork point for background consolidation. Runtime listeners must use this event field instead of the mutable `SessionManagerPort.currentView().leafId()`.
Expand Down
7 changes: 6 additions & 1 deletion .codex/skills/lypi-session-engine/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Shared entry records and views live in `lypi-contracts/src/main/java/cn/lypi/con
- `lypi-session/src/main/java/cn/lypi/session/ForkService.java`
- `lypi-session/src/main/java/cn/lypi/session/ChildSessionService.java`
- `lypi-session/src/main/java/cn/lypi/session/SessionResumeQuery.java`
- `lypi-session/src/main/java/cn/lypi/session/SessionResumeScan.java`
- `lypi-session/src/main/java/cn/lypi/session/SessionEntryDisplayText.java`
- `lypi-session/src/main/java/cn/lypi/session/SessionBranchTreeQuery.java`
- `lypi-session/src/main/java/cn/lypi/session/SessionFileQuery.java`
- `lypi-session/src/main/java/cn/lypi/session/GitDiffQuery.java`
Expand All @@ -48,6 +50,9 @@ Shared entry records and views live in `lypi-contracts/src/main/java/cn/lypi/con
## Invariants

- Entries have stable `id` and `parentId`; branching is represented by parent links.
- JSONL full reads must parse line by line; header/list queries must read only the header line.
- Resume queries use `JsonlSessionStore.resumeScans()` lightweight metadata scans, bounded by `MAX_CONCURRENT_SESSION_INFO_LOADS`, and must not full replay every session.
- Header `id` must match the JSONL file name; list/resume paths skip unreadable or mismatched files, while direct reads fail loudly.
- `switchLeaf()` moves the view only; it does not rewrite transcript.
- `MessageEntry`, `BranchSummaryEntry`, `CustomMessageEntry`, and `CompactionEntry` can affect model-visible context.
- Model, thinking, agent mode and permission runtime state are restored from entry history or child session header defaults.
Expand Down Expand Up @@ -83,7 +88,7 @@ Shared entry records and views live in `lypi-contracts/src/main/java/cn/lypi/con
| New entry type | `lypi-contracts/src/main/java/cn/lypi/contracts/session/`, `SessionJsonMapper`, replay tests |
| Change context reconstruction | `SessionReplayProjector`, `SessionManagerReplayTest` |
| Change branch selection | `EntryTreeIndex`, `SessionLeafSelector`, branch query tests |
| Change resume UI data | `SessionResumeQuery`, `SessionBranchTreeQuery`, TUI contract tests |
| Change resume UI data | `SessionResumeQuery`, `SessionResumeScan`, `SessionEntryDisplayText`, `SessionBranchTreeQuery`, TUI contract tests |
| Change child session metadata | `ChildSessionService`, subagent runtime tests |
| Change permission runtime replay | `PermissionRuntimeStateChangeEntry`, `SessionReplayProjector`, contracts serialization tests |

Expand Down
198 changes: 128 additions & 70 deletions .codex/skills/lypi-subagent-runtime/SKILL.md

Large diffs are not rendered by default.

111 changes: 111 additions & 0 deletions .codex/skills/lypi-transport-tui/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
name: lypi-transport-tui
description: Use when changing ly-pi terminal UI, JLine input, TUI event reduction, rendering, slash commands, overlays, permission prompts, diff display, file mentions, or Skill mentions.
---

# ly-pi Transport TUI

## Core Rule

The TUI adapts input and renders state. Durable behavior belongs in session, agent core, tool runtime, resource runtime or contracts.

## Main Responsibilities

- Open a JLine terminal transport and attach to `AgentEvent`.
- Convert semantic events into `TuiViewModel`.
- Route user input, slash commands and compact commands.
- Parse file and Skill mentions for user input.
- Render message, thinking, tool, error, permission, diff and status views.
- Forward submissions to `AgentCorePort` through `TurnRequest`.

## Key Code

- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/JLineTuiTransport.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/RuntimeTuiSubmitHandler.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/TuiEventReducer.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/TuiTranscriptPartitioner.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/TuiTranscriptCommitLedger.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/TuiRenderBatch.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/TuiLayout.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/TuiRenderer.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/InlineViewport.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/InlineTerminalRenderer.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/TuiStartupBanner.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/TerminalCursorProbe.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/TerminalSession.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/TuiRenderState.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/TuiInputLoop.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/SlashCommandRouter.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/PermissionOverlay.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/DiffOverlay.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/SkillMentionParser.java`
- `lypi-transport-tui/src/main/java/cn/lypi/transport/tui/FileMentionPicker.java`

## Event Flow

1. `JLineTuiTransport.open()` enters normal-screen interactive modes, probes the cursor with a timeout and replays non-CPR input.
2. `RuntimeTuiSubmitHandler.submitUserInput()` routes slash commands and resolves Skill mentions.
3. Normal input becomes `TurnRequest` and executes asynchronously.
4. `TuiEventReducer.reduce()` projects message, tool, permission, retry, compact, interrupt and session events.
5. `TuiTranscriptPartitioner` splits the stable prefix from the live tail without storing durable state.
6. `TuiTranscriptCommitLedger` emits each stable block once per `(sessionId, leafId)` projection.
7. `TuiRenderer` renders new committed blocks separately from the bounded live/input/overlay/status surface.
8. On the first real-terminal frame, `InlineTerminalRenderer` prepends `TuiStartupBanner` as a one-time native-scrollback prelude.
9. `InlineTerminalRenderer` inserts committed lines above the viewport and diffs only the mutable surface in one synchronized terminal transaction.

## Invariants

- Reducers should not invent durable transcript content. They project events into display state.
- The first streaming, active, pending or running block starts the live tail; only the stable prefix can be committed.
- A stable block ID is committed at most once per projection key, including after transient stable/live regressions.
- Committed transcript is terminal-native scrollback. There is no application-side 500-line history window or scroll offset.
- The startup banner is terminal decoration, not transcript: render it once per transport before initial committed history, then preserve it across redraw, resize, projection changes and close.
- PageUp, PageDown and mouse wheel never enter an application history model or mutate the draft; scrollback remains terminal/tmux-owned.
- Historical tools always use their completed collapsed rendering. Ctrl+O affects tools in the live region only.
- The mutable surface is bounded by `terminalHeight - 1` and contains only live content, input, overlays and status.
- `TerminalSession` must not enable 1049, 1000 or 1006; close and partial failure restore raw mode, cursor and interactive modes.
- Resize probes the post-reflow cursor, preserves concurrent input, never replays committed blocks and redraws only the mutable surface.
- Finalizing a streaming block commits its final text once in the same transaction that removes it from the surface.
- Close clears the mutable surface while preserving committed transcript and the shell cursor handoff position.
- A projection-key change opens a new commit epoch without clearing earlier terminal scrollback.
- Slash commands that change durable state should route through session/runtime contracts, not UI-only variables.
- Permission prompts display decision context and should clear on decision or interrupt.
- Skill mentions are resolved from the current `SkillIndex`, then passed into `TurnRequest`.
- Long-running work should not hold the UI lock while executing core logic.

## Tests To Check

- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/TerminalSessionTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/TerminalCursorProbeTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/InlineViewportTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/InlineTerminalRendererTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/TuiStartupBannerTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/TuiTranscriptPartitionerTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/TuiTranscriptCommitLedgerTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/TuiLayoutTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/TuiRendererTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/JLineTuiTransportTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/JLineTuiTransportConcurrencyTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/JLineTuiTransportRenderPipelineTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/RuntimeTuiSubmitHandlerTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/TuiEventReducerTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/PermissionOverlayTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/DiffOverlayTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/FileMentionPickerTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/SlashCommandRouterTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/SkillMentionParserTest.java`
- `lypi-transport-tui/src/test/java/cn/lypi/transport/tui/TuiContractEndToEndTest.java`
- `lypi-transport-tui/src/test/resources/run-tui-frame-pty.sh`
- `lypi-transport-tui/src/test/resources/run-tui-interaction-pty.sh`
- `lypi-transport-tui/src/test/resources/run-tui-smoke.sh`

## Before Editing

- Decide whether the change is view projection, rendering, input handling or runtime behavior.
- If it changes data shape, update `lypi-contracts` view model records first.
- Prefer event-driven state updates over querying internals from the UI layer.
- For rendering changes, test narrow width, multiline input, streaming finalization, resize reflow and surface-height bounds.
- For terminal lifecycle changes, test partial open failure and real tmux server/client PTYs before relying on control-sequence unit tests alone.
- For slash commands, test consumed, prompt-rewrite and state-change paths.

After using this Skill, reverse-check that the change did not move business state into TUI classes.
Loading
Loading