mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-23 08:45:50 +00:00
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>
This commit is contained in:
381
packages/@ant/ink/docs/12-terminal-integration.md
Normal file
381
packages/@ant/ink/docs/12-terminal-integration.md
Normal file
@@ -0,0 +1,381 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user