Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5c1c3dd
Fix agent terminal profile recovery
DeadWaveWave Mar 28, 2026
d5346cc
Update changelog for agent terminal recovery
DeadWaveWave Mar 28, 2026
78a04eb
Hide duplicate agent cursor in alt screen
DeadWaveWave Mar 28, 2026
2eb2409
Reduce agent terminal layout sync churn
DeadWaveWave Mar 28, 2026
64a991f
Remove abandoned agent cursor visibility helper
DeadWaveWave Mar 28, 2026
381b4cf
fix: unify agent terminal launch semantics
DeadWaveWave Mar 28, 2026
056d8d9
fix: keep preload sandbox-compatible
DeadWaveWave Mar 28, 2026
d01b699
chore: add Win10 codex terminal diagnostics
DeadWaveWave Mar 28, 2026
6cb74dd
Merge origin/main and fix agent IPC Windows cwd validation
DeadWaveWave Mar 29, 2026
222e378
fix: stabilize ANSI screen cache restore
DeadWaveWave Mar 29, 2026
04007ac
fix: keep committed terminal cache during pending writes
DeadWaveWave Mar 29, 2026
8205214
Merge branch 'main' into fix/agent-terminal
DeadWaveWave Mar 30, 2026
c5a55ae
fix: drop stale terminal screen cache on pending writes
DeadWaveWave Mar 30, 2026
7bc9816
fix: refresh terminal screen cache after buffer switch
DeadWaveWave Mar 30, 2026
7331633
fix: keep terminal screen cache during pending writes
DeadWaveWave Mar 30, 2026
c3c2abe
fix: sync terminal size before hydration
DeadWaveWave Mar 30, 2026
1a8347d
test: log terminal size in ansi screen restore
DeadWaveWave Mar 30, 2026
cabedc0
test: log frame visibility around workspace switch
DeadWaveWave Mar 30, 2026
9db6abc
test: log ansi screen cache summary
DeadWaveWave Mar 30, 2026
c59b49e
fix: preserve alt-screen restore against pty delta
DeadWaveWave Mar 30, 2026
3eea938
fix: apply alt-screen delta when leaving alternate buffer
DeadWaveWave Mar 30, 2026
2100933
docs: document alt-screen restore delta handling
DeadWaveWave Mar 30, 2026
4dd4b7f
test: stabilize zoomed terminal resize handle drag
DeadWaveWave Mar 30, 2026
63562d4
docs: note boundingBox flakiness under zoomed e2e
DeadWaveWave Mar 30, 2026
952259d
Merge branch 'main' into fix/agent-terminal
DeadWaveWave Mar 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Spaces: warn before closing the last node in a space when it would become empty and auto-close, using the shared warning dialog shell. (#66)

### 🐞 Fixed
- Agent windows now inherit terminal profile runtime/env semantics during launch, recovery, and fallback; Windows raw-TUI wheel handling is covered by regression tests. (#110)
- UI: unified shared menu overlays to fix prompt template, task session, and related context-menu offset issues. (#121)
- Persistence: Repair cumulative SQLite schema upgrades and auto-heal mis-versioned local databases so workspace state saves no longer fail after upgrading from older installs. (#76)
- Spaces: New windows created from a crowded space now preserve existing window layout, expand the space only as needed, and keep the viewport centered on the final position. (#62)
Expand Down
19 changes: 19 additions & 0 deletions docs/DEBUGGING.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,25 @@ pnpm test:e2e
- space overlay / drag handle / label 区域是否抢占事件
- 点击点是否过于贴边

### 4) 缩放/transform 场景避免依赖 `locator.boundingBox()` 做像素命中与断言

在 React Flow 缩放(viewport transform)场景下,尤其是 CI 里的 `inactive/offscreen` 窗口模式,`locator.boundingBox()` 偶发返回不稳定坐标,导致鼠标按下点不到目标元素,进而出现“mouse 走完了但 resize/drag 根本没发生”的假操作。

建议:

- 计算鼠标命中点时,优先用 `locator.evaluate(el => el.getBoundingClientRect())` 获取可视坐标,再用其中心点进行 `mouse.move/down/up`。
- 对像素级对齐断言留出容差(例如降低 `toBeCloseTo` precision,或用自定义 tolerance),避免被平台舍入差/动画 settle 影响。
- 断言 resize/drag 结果时,优先读持久化状态确认是否真的提交,而不是只看 UI 像素位置。

示例(命中点计算):

```ts
const rect = await locator.evaluate(el => el.getBoundingClientRect())
const x = rect.x + rect.width / 2
const y = rect.y + rect.height / 2
await page.mouse.move(x, y)
```

## 持久化与状态污染排查

### 1) 测试优先使用 seed 状态
Expand Down
96 changes: 96 additions & 0 deletions docs/TERMINAL_ANSI_SCREEN_PERSISTENCE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Terminal ANSI Screen Persistence (Workspace Switch)

Date: 2026-03-30
Scope: renderer xterm persistence for full-screen TUI / alternate-screen content when switching workspaces.

## Symptom

Ubuntu CI consistently fails the E2E:

- `tests/e2e/workspace-canvas.persistence.ansi-screen.spec.ts`
- Assertion fails after a workspace switch:
- expected: terminal contains `FRAME_29999_TOKEN`
- actual: terminal often only shows `ROW_*_STATIC` + prompt, but not the final `FRAME_*` line

## Why This Is Tricky

This test intentionally produces a large amount of output:

- Enters alternate screen (`ESC[?1049h`)
- Draws static rows using absolute cursor positioning
- Writes 30,000 frames to the same absolute row (`ESC[20;1H...`)

OpenCove maintains a PTY snapshot and a persisted scrollback snapshot, but both are capped:

- cap: `400_000` chars (see `src/platform/process/pty/snapshot.ts` and terminal scrollback constants)

When output exceeds the cap:

- raw snapshots skew toward the most recent data (tail)
- the initial "enter alt screen" sequence and early static draw can fall out of the snapshot window

So restoring from raw snapshot alone can lose the "full-screen" semantics. This is why OpenCove also
caches an xterm SerializeAddon-based "committed screen state" on unmount.

## Restore Pipeline (Current)

1. On unmount:
- cache `{ serializedScreen, rawSnapshotBase, cols, rows }` per `nodeId/sessionId`
2. On mount:
- write cached `serializedScreen`
- fetch `pty.snapshot` and compute a delta (suffix/prefix overlap)
- for normal-buffer restores: append the delta to catch up
- for alternate-buffer restores: only append the delta when it contains an explicit alt-buffer exit (`ESC[?1049l`)
otherwise, skip the delta to avoid clobbering the committed full-screen snapshot with prompt/redraw output

## Failure Mode

During high-volume output, xterm writes are chunked and can still be draining while the user (or E2E)
switches workspaces.

If we drop the cached committed screen state during that window, the remount path may fall back to
persisted scrollback, which can be:

- stale (publish is debounced)
- or trimmed (cap) such that the expected final frame token is missing

Even when the cache contains the expected frame token, restoring can still fail if we immediately
replay the raw PTY delta on top of the committed serialized snapshot. In CI we observed the delta
containing the shell prompt/redraw output that happened while the workspace was inactive, which can
overwrite the last full-screen frame line.

## Fix

Keep the latest committed screen cache even when there are pending writes.

The cache is allowed to be slightly behind; the remount path will still fetch `pty.snapshot` and
apply the delta to catch up. Deleting the cache entirely is worse because it removes the only
representation that can preserve alternate-screen semantics when the raw snapshot cap is exceeded.

In addition, treat alternate-screen restores as a special case:

- Skip replaying the raw PTY delta unless it contains an explicit alt-buffer exit (`ESC[?1049l`).
This keeps "what the user last saw" stable and prevents prompt/redraw output from clobbering the
cached full-screen snapshot.
- Suppress PTY resizes (SIGWINCH) during alternate-screen restore until the user types again, so a
shell redraw cannot wipe the cached frame before it is visible.

## Verification

Local:

```powershell
pnpm build
$env:OPENCOVE_E2E_WINDOW_MODE='inactive'
pnpm exec playwright test tests/e2e/workspace-canvas.persistence.ansi-screen.spec.ts --project electron --reporter=line
```

CI:

- `ci (ubuntu-latest)` should pass the `Workspace Canvas - Persistence ANSI screen restore` E2E.

## Follow-ups (If We Need Stronger Guarantees)

- Add bounded "drain pending writes before caching" logic on unmount (avoid UI jank).
- Extend `OPENCOVE_TERMINAL_DIAGNOSTICS=1` to log cache/hydrate decision points (cache hit/miss,
pending writes, raw snapshot lengths, alt/normal buffer kind).
3 changes: 2 additions & 1 deletion docs/TERMINAL_TUI_RENDERING_BASELINE.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,11 @@ pnpm test:e2e
- `keeps terminal visible after drag, resize, and node interactions`
- `keeps agent tui visible while dragging window`
- `wheel over terminal scrolls terminal viewport`
- `wheel over a hydrated agent node scrolls the viewport instead of the canvas`
- `preserves terminal history after app reload`

推荐快速执行:

```bash
pnpm test:e2e -- tests/e2e/workspace-canvas.spec.ts -g "keeps terminal visible after drag, resize, and node interactions|keeps agent tui visible while dragging window|wheel over terminal scrolls terminal viewport|preserves terminal history after app reload"
pnpm test:e2e -- tests/e2e/workspace-canvas.spec.ts -g "keeps terminal visible after drag, resize, and node interactions|keeps agent tui visible while dragging window|wheel over terminal scrolls terminal viewport|wheel over a hydrated agent node scrolls the viewport instead of the canvas|preserves terminal history after app reload"
```
168 changes: 168 additions & 0 deletions docs/WIN10_CODEX_SCROLL_DIAGNOSTICS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Win10 Codex Scroll Diagnostics

Date: 2026-03-28
Scope: Windows 10 only, focused on Codex running inside an OpenCove agent/terminal window.

## Problem Statement

Observed user report:

- On Windows 10, when Codex is launched inside OpenCove's embedded terminal/agent window, the Codex UI can lose normal scrollback behavior.
- The same Codex workflow behaves correctly in:
- VS Code's integrated terminal
- a native local terminal outside OpenCove
- The symptom is not "all wheel input is broken". The narrower symptom is:
- the Codex TUI does not expose a normal vertical scrollbar / scrollback path inside OpenCove on Win10

## Current Working Theory

The strongest current explanation is a three-way interaction:

1. Codex switches into a full-screen TUI / alternate-screen workflow.
2. Windows 10 ConPTY has weaker scrollback/reflow behavior than newer Windows builds.
3. OpenCove currently uses the xterm.js + node-pty baseline, but not VS Code's deeper Windows terminal compatibility stack.

This means the likely failing boundary is not basic shell launch anymore. It is:

- ConPTY buffer semantics
- alternate-screen / mouse mode behavior
- xterm viewport / scrollbar state inside OpenCove's embedded terminal

## Why VS Code Can Behave Better

OpenCove already aligned one important part with VS Code:

- agent launch now goes through one terminal-profile normalization path
- Windows PTY metadata is propagated into xterm's `windowsPty`

But VS Code still has a much larger Windows terminal stack on top of that:

- PTY host orchestration
- Windows backend heuristics
- shell integration
- more mature ConPTY behavior handling

References:

- VS Code terminal profiles:
- https://code.visualstudio.com/docs/terminal/profiles
- VS Code advanced terminal docs:
- https://code.visualstudio.com/docs/terminal/advanced
- VS Code terminal troubleshooting:
- https://code.visualstudio.com/docs/supporting/troubleshoot-terminal-launch
- xterm `windowsPty` option:
- https://xtermjs.org/docs/api/terminal/interfaces/iterminaloptions/
- node-pty README:
- https://github.com/microsoft/node-pty

## What This Branch Adds

This branch adds an opt-in diagnostics path for terminal nodes.

When enabled, OpenCove writes structured JSON lines to the process stdout with:

- `init`
- `hydrated`
- `resize`
- `wheel`
- `scroll`

Each line includes:

- node/session identity
- terminal kind (`terminal` / `agent`)
- xterm buffer mode:
- `normal`
- `alternate`
- `unknown`
- active buffer values:
- `activeBaseY`
- `activeViewportY`
- `activeLength`
- DOM viewport facts:
- `hasViewport`
- `hasVerticalScrollbar`
- `viewportScrollTop`
- `viewportScrollHeight`
- `viewportClientHeight`

Log prefix:

```text
[opencove-terminal-diagnostics]
```

## How To Run On Windows 10

Use a terminal, not a desktop icon, so stdout remains visible.

PowerShell:

```powershell
$env:OPENCOVE_TERMINAL_DIAGNOSTICS='1'
pnpm dev
```

If testing a production build from terminal, launch the built executable from the same shell with `OPENCOVE_TERMINAL_DIAGNOSTICS=1` set first.

## What To Look For

### Case A: Wheel never reaches the xterm viewport

Expected signal:

- no `wheel` logs appear while scrolling over the Codex window

Interpretation:

- event routing is wrong before xterm receives the gesture
- likely a DOM/event capture issue rather than ConPTY scrollback

### Case B: Wheel arrives, but buffer stays `alternate` with no meaningful scrollback

Expected signal:

- `wheel` logs appear
- `bufferKind` remains `alternate`
- `activeBaseY` / `activeViewportY` do not move meaningfully
- `hasVerticalScrollbar` stays `false`

Interpretation:

- Codex is running in an alternate-screen mode where normal scrollback is not materialized
- Win10 ConPTY compatibility is the more likely bottleneck

### Case C: Scrollbar exists but viewport never scrolls

Expected signal:

- `hasVerticalScrollbar` is `true`
- `wheel` logs appear
- `scroll` logs never appear

Interpretation:

- wheel reaches the terminal surface
- viewport scrolling is not being converted into actual xterm viewport movement

## Expected Next Step After Win10 Manual Test

After collecting logs from a real Windows 10 machine, the next change should be chosen from evidence, not guesswork:

1. If wheel never arrives:
- fix event routing / capture path
2. If wheel arrives but alternate buffer never exposes scrollback:
- compare against VS Code's Windows terminal behavior more directly
- evaluate whether Codex needs a different Windows launch/runtime mode inside OpenCove
3. If scrollbar exists but viewport does not move:
- inspect xterm viewport state and mouse/wheel integration on Win10 specifically

## Non-Goals Of This Document

This document does not claim the root cause is fully proven yet.

It documents:

- the narrowed hypothesis
- the instrumentation added in this branch
- the exact evidence we need from a real Windows 10 machine
Loading
Loading