Files
claude-code/packages/@ant/ink/docs/12-terminal-integration.md
claude-code-best 2fb1c9dcd8 feat: 工具层及 mcp 大重构 (#252)
* feat: 第一版大重构

* fix: 修复类型问题

* chore: 更新版本到 1.3.2

* Add brave as alternative WebSearchTool

* fix: 修正顺序

* fix: 修复对穷鬼模式的 auto dream 和 session memory 越过

* feat: 穷鬼模式去除 session-summary

* feat: 创建 builtin-tools 包,搬运所有工具实现

将 src/tools/ 下的全部 60 个工具目录迁移至 packages/builtin-tools/src/tools/,
内部导入路径已更新为 src/ alias 模式。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 更新 src/ 中所有工具引用至 builtin-tools 包,删除 src/tools/

- src/tools.ts 及 178 个 src/ 文件的 import 路径从 ./tools/ 改为 builtin-tools/tools/
- 删除 src/tools/ 整个目录(已迁移至 packages/builtin-tools/)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: 添加 builtin-tools 路径别名至 tsconfig,更新 bun.lock

- tsconfig.json 新增 builtin-tools/* 和 builtin-tools 路径映射
- 新增 packages/builtin-tools/src 至 include

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 为 builtin-tools、mcp-client、agent-tools 添加 @claude-code-best 作用域前缀

所有包名及 import 路径统一添加 @claude-code-best/ 前缀:
- builtin-tools → @claude-code-best/builtin-tools
- mcp-client → @claude-code-best/mcp-client
- agent-tools → @claude-code-best/agent-tools

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 修复 node 环境没有 bun 的问题

---------

Co-authored-by: Eric-Guo <eric.guocz@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 09:52:05 +08:00

382 lines
8.0 KiB
Markdown

# Chapter 12: Terminal Integration
This chapter covers terminal-specific features: alternate screen, mouse tracking, clipboard, notifications, and terminal querying.
## Alternate Screen
Enter a fullscreen alternate screen buffer (like vim, less, htop).
```tsx
import { AlternateScreen } from '@anthropic/ink'
<AlternateScreen mouseTracking={true}>
<Box flexDirection="column" height="100%">
<Text>Fullscreen content</Text>
</Box>
</AlternateScreen>
```
### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `ReactNode` | - | Content |
| `mouseTracking` | `boolean` | `true` | Enable SGR mouse tracking |
### Behavior
On mount:
1. Enters DEC 1049 alternate screen buffer
2. Hides cursor
3. Enables mouse tracking (if `mouseTracking=true`)
4. Constrains rendering height to terminal rows
On unmount:
1. Exits alternate screen buffer
2. Shows cursor
3. Disables mouse tracking
4. Restores original terminal content
### Mouse Tracking Modes
When enabled:
- **Mode 1003** -- Button press/release + motion (hover)
- **Mode 1006** -- SGR extended mouse format (coordinates > 223)
- **Wheel events** -- Scroll up/down
### External Editor Handoff
The Ink instance supports pausing for an external editor:
```ts
// Pause Ink, run external command, resume
ink.enterAlternateScreen() // Save state
// ... external editor runs ...
ink.reassertTerminalModes() // Restore on resume
```
This is triggered by Ctrl+Z (SIGTSTP) and SIGCONT.
## Mouse Events
### Click Events
```tsx
<Box onClick={(event) => {
console.log(`Clicked at col=${event.x}, row=${event.y}`)
event.stopImmediatePropagation()
}}>
<Text>Clickable area</Text>
</Box>
```
### Multi-Click
Double-click selects a word, triple-click selects a line. Handled by the App component:
```ts
// App prop
onMultiClick: (col: number, row: number, count: 2 | 3) => void
```
### Hover Events
```tsx
<Box
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
>
<Text>{hovered ? 'Hovered!' : 'Hover me'}</Text>
</Box>
```
Hover uses `mouseenter`/`mouseleave` semantics (no bubbling between children).
### Drag-to-Select
In alt-screen mode, click-drag creates a text selection:
```ts
// App prop
onSelectionDrag: (col: number, row: number) => void
```
## Clipboard
### OSC 52 Clipboard
```tsx
import { setClipboard } from '@anthropic/ink'
await setClipboard('Copied text')
```
### Copy Selection
```tsx
const { copySelection } = useSelection()
const text = copySelection() // Copies to clipboard and clears highlight
```
### Copy Without Clear
```tsx
const { copySelectionNoClear } = useSelection()
const text = copySelectionNoClear() // Copies but keeps highlight
```
## Terminal Notifications
Send desktop notifications from the terminal.
```tsx
import { useTerminalNotification } from '@anthropic/ink'
function MyComponent() {
const { notifyBell, progress } = useTerminalNotification()
// Terminal bell (audible/system notification)
notifyBell()
// Progress bar in terminal title/tab
progress('running', 65) // 65% complete
progress('completed') // Done
progress('error') // Error state
progress('indeterminate') // Unknown progress
progress(null) // Clear
}
```
### Terminal-Specific Notifications
```tsx
const { notifyITerm2, notifyKitty, notifyGhostty } = useTerminalNotification()
// iTerm2
notifyITerm2({ message: 'Build complete', title: 'My App' })
// Kitty
notifyKitty({ message: 'Build complete', title: 'My App', id: 1 })
// Ghostty
notifyGhostty({ message: 'Build complete', title: 'My App' })
```
## Terminal Queries
### Background Color (OSC 11)
Used for auto-theme detection:
```ts
import { getTerminalBackground } from '@anthropic/ink'
const bg = await getTerminalBackground()
// e.g., 'rgb:0000/0000/0000' (dark) or 'rgb:ffff/ffff/ffff' (light)
```
### Terminal Version (XTVERSION)
```ts
import { isXtermJs, setXtversionName, getXtversionName } from '@anthropic/ink'
```
### Feature Detection
```ts
import { supportsHyperlinks } from '@anthropic/ink'
if (supportsHyperlinks()) {
// OSC 8 hyperlinks supported
}
import { supportsExtendedKeys } from '@anthropic/ink'
if (supportsExtendedKeys()) {
// Kitty keyboard protocol / modifyOtherKeys available
}
```
## Terminal Focus
Track terminal window focus/unfocus:
```tsx
import { useTerminalFocus } from '@anthropic/ink'
const isFocused = useTerminalFocus()
```
Low-level API:
```ts
import { getTerminalFocused, subscribeTerminalFocus } from '@anthropic/ink'
getTerminalFocused() // boolean
subscribeTerminalFocus((focused: boolean) => {
// Called on focus change
})
```
Uses DECSET 1004 focus reporting.
## Terminal Title
Set the terminal window title:
```tsx
import { useTerminalTitle } from '@anthropic/ink'
useTerminalTitle('My App - Dashboard')
```
Clear:
```tsx
useTerminalTitle(null)
```
## Terminal I/O Sequences
Low-level ANSI sequence constants for advanced use.
### Cursor Control
```ts
import {
SHOW_CURSOR,
HIDE_CURSOR,
CURSOR_HOME,
} from '@anthropic/ink'
// cursorPosition(row, col) -- Move cursor to absolute position
// cursorMove(dx, dy) -- Move cursor relative
```
### Screen Control
```ts
import {
ENTER_ALT_SCREEN,
EXIT_ALT_SCREEN,
ERASE_SCREEN,
} from '@anthropic/ink'
```
### Mouse Control
```ts
import {
ENABLE_MOUSE_TRACKING,
DISABLE_MOUSE_TRACKING,
} from '@anthropic/ink'
```
### Keyboard Protocols
```ts
import {
ENABLE_KITTY_KEYBOARD,
DISABLE_KITTY_KEYBOARD,
ENABLE_MODIFY_OTHER_KEYS,
DISABLE_MODIFY_OTHER_KEYS,
} from '@anthropic/ink'
```
### Clipboard & Tab Status
```ts
import {
CLEAR_ITERM2_PROGRESS,
CLEAR_TAB_STATUS,
CLEAR_TERMINAL_TITLE,
wrapForMultiplexer,
} from '@anthropic/ink'
```
`wrapForMultiplexer` wraps OSC sequences for tmux compatibility.
## Terminal Compatibility
### Supported Terminals
| Terminal | Features |
|----------|----------|
| iTerm2 | Full support (hyperlinks, notifications, progress) |
| Kitty | Full support (keyboard protocol, notifications) |
| Ghostty | Full support |
| WezTerm | Full support |
| Alacritty | Most features |
| Windows Terminal | Most features |
| Apple Terminal | 256-color fallback |
| xterm.js (VS Code) | Detected and special-cased |
| tmux | Wrapped sequences via `wrapForMultiplexer` |
| Screen | Basic support |
### Feature Degradation
The framework gracefully degrades:
- No true color → Falls back to ANSI 16-color themes
- No OSC 52 → Clipboard operations silently fail
- No mouse tracking → Click/hover events are no-ops
- No extended keys → Standard escape sequences used
- No bracketed paste → Paste detected by timing heuristic
### Synchronized Output
```ts
import { isSynchronizedOutputSupported } from '@anthropic/ink'
if (isSynchronizedOutputSupported()) {
// BSU/ESU for tear-free rendering
}
```
Uses DECSET 2026 synchronized output to prevent partial frame display.
### Bracketed Paste
Uses DECSET 2004 to distinguish paste events from rapid typing. Automatically enabled by the App component.
## Text Selection (Alt-Screen)
### Selection State
```ts
type SelectionState = {
anchor: Point | null // Drag start
focus: Point | null // Current position
isDragging: boolean
anchorSpan: { lo: Point; hi: Point; kind: 'word' | 'line' } | null
scrolledOffAbove: string[] // Text scrolled out above
scrolledOffBelow: string[] // Text scrolled out below
}
```
### Selection Operations
- **Click-drag** -- Free-form selection
- **Double-click** -- Word selection
- **Triple-click** -- Line selection
- **Shift+Arrow** -- Extend selection from keyboard
- **Drag-to-scroll** -- Auto-scroll when dragging near edges
### noSelect Regions
Exclude areas from selection (gutters, line numbers):
```tsx
<Box noSelect={true}>
<Text>1 </Text>
</Box>
<Box>
<Text>code here</Text> {/* Only this is selectable */}
</Box>
```
### Soft-Wrap Awareness
Selection correctly handles text that was wrapped across multiple rows:
- Wrapped lines are joined when copied
- Trailing whitespace is trimmed
- The `softWrap` bitmap tracks which rows are continuations