feat: 第一个可以用的 ink 组件抽象 (#158)

This commit is contained in:
claude-code-best
2026-04-06 23:56:45 +08:00
committed by GitHub
parent 3ea64eeb0f
commit c445f43f8d
645 changed files with 7255 additions and 1214 deletions

View File

@@ -1,5 +1,4 @@
import { stringWidth } from '../ink/stringWidth.js'
import { wrapAnsi } from '../ink/wrapAnsi.js'
import { stringWidth, wrapAnsi } from '@anthropic/ink'
import {
firstGrapheme,
getGraphemeSegmenter,

View File

@@ -8,7 +8,7 @@ mock.module("figures", () => ({
},
}));
mock.module("src/components/design-system/color.js", () => ({
mock.module("src/ink.js", () => ({
color: (colorKey: string, themeName: string) => (text: string) => text,
}));

View File

@@ -19,7 +19,7 @@
*/
import { deflateSync } from 'zlib'
import { stringWidth } from '../ink/stringWidth.js'
import { stringWidth } from '@anthropic/ink'
import {
type AnsiColor,
DEFAULT_BG,

View File

@@ -1,7 +1,7 @@
import * as React from 'react'
import { useEffect, useRef } from 'react'
import { KeyboardShortcutHint } from '../components/design-system/KeyboardShortcutHint.js'
import { Box, Text } from '../ink.js'
import { KeyboardShortcutHint } from '@anthropic/ink'
import { Box, Text } from '@anthropic/ink'
import { useKeybinding } from '../keybindings/useKeybinding.js'
type Props = {

View File

@@ -4,6 +4,7 @@ import {
type Logger,
type PermissionMode,
} from '@ant/claude-for-chrome-mcp'
import { initializeAnalyticsSink } from '../../services/analytics/sink.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { format } from 'util'
import { shutdownDatadog } from '../../services/analytics/datadog.js'
@@ -13,7 +14,7 @@ import {
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
logEvent,
} from '../../services/analytics/index.js'
import { initializeAnalyticsSink } from '../../services/analytics/sink.js'
import { getClaudeAIOAuthTokens } from '../auth.js'
import { enableConfigs, getGlobalConfig, saveGlobalConfig } from '../config.js'
import { logForDebugging } from '../debug.js'

View File

@@ -1,7 +1,7 @@
import * as React from 'react'
import { MessageResponse } from '../../components/MessageResponse.js'
import { supportsHyperlinks } from '../../ink/supports-hyperlinks.js'
import { Link, Text } from '../../ink.js'
import { supportsHyperlinks } from '@anthropic/ink'
import { Link, Text } from '@anthropic/ink'
import { renderToolResultMessage as renderDefaultMCPToolResultMessage } from '../../tools/MCPTool/UI.js'
import type { MCPToolResult } from '../../utils/mcpValidation.js'
import { truncateToWidth } from '../format.js'

View File

@@ -3,8 +3,8 @@ import { mkdir, readFile, writeFile } from 'fs/promises'
import { homedir } from 'os'
import { dirname, join } from 'path'
import { pathToFileURL } from 'url'
import { color } from '../components/design-system/color.js'
import { supportsHyperlinks } from '../ink/supports-hyperlinks.js'
import { color } from '@anthropic/ink'
import { supportsHyperlinks } from '@anthropic/ink'
import { logForDebugging } from './debug.js'
import { isENOENT } from './errors.js'
import { execFileNoThrow } from './execFileNoThrow.js'

View File

@@ -2,13 +2,14 @@ import {
buildComputerUseTools,
createComputerUseMcpServer,
} from '@ant/computer-use-mcp'
import { initializeAnalyticsSink } from '../../services/analytics/sink.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'
import { homedir } from 'os'
import { shutdownDatadog } from '../../services/analytics/datadog.js'
import { shutdown1PEventLogging } from '../../services/analytics/firstPartyEventLogger.js'
import { initializeAnalyticsSink } from '../../services/analytics/sink.js'
import { enableConfigs } from '../config.js'
import { logForDebugging } from '../debug.js'
import { filterAppsForDescription } from './appNames.js'

View File

@@ -1,6 +1,6 @@
import * as React from 'react'
import { MessageResponse } from '../../components/MessageResponse.js'
import { Text } from '../../ink.js'
import { Text } from '@anthropic/ink'
import { truncateToWidth } from '../format.js'
import type { MCPToolResult } from '../mcpValidation.js'

View File

@@ -11,6 +11,7 @@
* directly — there is no terminal attached.
*/
import { parseDeepLink } from './parseDeepLink.js'
import { homedir } from 'os'
import { logForDebugging } from '../debug.js'
import {
@@ -19,7 +20,7 @@ import {
} from '../githubRepoPathMapping.js'
import { jsonStringify } from '../slowOperations.js'
import { readLastFetchTime } from './banner.js'
import { parseDeepLink } from './parseDeepLink.js'
import { MACOS_BUNDLE_ID } from './registerProtocol.js'
import { launchInTerminal } from './terminalLauncher.js'

View File

@@ -13,6 +13,7 @@
* Windows — Writes registry keys under HKEY_CURRENT_USER\Software\Classes
*/
import { DEEP_LINK_PROTOCOL } from './parseDeepLink.js'
import { promises as fs } from 'fs'
import * as os from 'os'
import * as path from 'path'
@@ -28,7 +29,6 @@ import { execFileNoThrow } from '../execFileNoThrow.js'
import { getInitialSettings } from '../settings/settings.js'
import { which } from '../which.js'
import { getUserBinDir, getXDGDataHome } from '../xdg.js'
import { DEEP_LINK_PROTOCOL } from './parseDeepLink.js'
export const MACOS_BUNDLE_ID = 'com.anthropic.claude-code-url-handler'
const APP_NAME = 'Claude Code URL Handler'

View File

@@ -6,7 +6,7 @@ import {
} from 'child_process'
import memoize from 'lodash-es/memoize.js'
import { basename } from 'path'
import instances from '../ink/instances.js'
import { instances } from '@anthropic/ink'
import { logForDebugging } from './debug.js'
import { whichSync } from './which.js'

View File

@@ -10,25 +10,7 @@ import {
getSessionId,
isSessionPersistenceDisabled,
} from '../bootstrap/state.js'
import instances from '../ink/instances.js'
import {
DISABLE_KITTY_KEYBOARD,
DISABLE_MODIFY_OTHER_KEYS,
} from '../ink/termio/csi.js'
import {
DBP,
DFE,
DISABLE_MOUSE_TRACKING,
EXIT_ALT_SCREEN,
SHOW_CURSOR,
} from '../ink/termio/dec.js'
import {
CLEAR_ITERM2_PROGRESS,
CLEAR_TAB_STATUS,
CLEAR_TERMINAL_TITLE,
supportsTabStatus,
wrapForMultiplexer,
} from '../ink/termio/osc.js'
import { DISABLE_KITTY_KEYBOARD, DISABLE_MODIFY_OTHER_KEYS, DBP, DFE, DISABLE_MOUSE_TRACKING, EXIT_ALT_SCREEN, SHOW_CURSOR, CLEAR_ITERM2_PROGRESS, CLEAR_TAB_STATUS, CLEAR_TERMINAL_TITLE, instances, supportsTabStatus, wrapForMultiplexer } from '@anthropic/ink'
import { shutdownDatadog } from '../services/analytics/datadog.js'
import { shutdown1PEventLogging } from '../services/analytics/firstPartyEventLogger.js'
import {

View File

@@ -1,5 +1,5 @@
import * as React from 'react'
import { Text } from '../ink.js'
import { Text } from '@anthropic/ink'
/**
* Inverse-highlight every occurrence of `query` in `text` (case-insensitive).

View File

@@ -1,5 +1,5 @@
import chalk from 'chalk'
import { supportsHyperlinks } from '../ink/supports-hyperlinks.js'
import { supportsHyperlinks } from '@anthropic/ink'
// OSC 8 hyperlink escape sequences
// Format: \e]8;;URL\e\\TEXT\e]8;;\e\\

View File

@@ -1,4 +1,4 @@
import type { TextProps } from '../ink.js'
import type { TextProps } from '@anthropic/ink'
import {
AGENT_COLOR_TO_THEME_COLOR,
type AgentColorName,

View File

@@ -1,5 +1,5 @@
import { getDirectConnectServerUrl, getSessionId } from '../bootstrap/state.js'
import { stringWidth } from '../ink/stringWidth.js'
import { stringWidth } from '@anthropic/ink'
import type { LogOption } from '../types/logs.js'
import { getSubscriptionName, isClaudeAISubscriber } from './auth.js'
import { getCwd } from './cwd.js'

View File

@@ -1,13 +1,13 @@
import chalk from 'chalk'
import { marked, type Token, type Tokens } from 'marked'
import stripAnsi from 'strip-ansi'
import { color } from '../components/design-system/color.js'
import { color } from '@anthropic/ink'
import { BLOCKQUOTE_BAR } from '../constants/figures.js'
import { stringWidth } from '../ink/stringWidth.js'
import { supportsHyperlinks } from '../ink/supports-hyperlinks.js'
import { stringWidth, supportsHyperlinks } from '@anthropic/ink'
import { createHyperlink } from '../utils/hyperlink.js'
import type { CliHighlight } from './cliHighlight.js'
import { logForDebugging } from './debug.js'
import { createHyperlink } from './hyperlink.js'
import { stripPromptXMLTags } from './messages.js'
import type { ThemeName } from './theme.js'

View File

@@ -4,7 +4,7 @@ import { logEvent } from 'src/services/analytics/index.js'
import { Spinner } from '../components/Spinner.js'
import { getOauthConfig } from '../constants/oauth.js'
import { useTimeout } from '../hooks/useTimeout.js'
import { Box, Text } from '../ink.js'
import { Box, Text } from '@anthropic/ink'
import { getSSLErrorHint } from '../services/api/errorUtils.js'
import { getUserAgent } from './http.js'
import { logError } from './log.js'

View File

@@ -3,7 +3,7 @@ import {
formatPastedTextRef,
getPastedTextRefNumLines,
} from '../history.js'
import instances from '../ink/instances.js'
import { instances } from '@anthropic/ink'
import type { PastedContent } from './config.js'
import { classifyGuiEditor, getExternalEditor } from './editor.js'
import { execSync_DEPRECATED } from './execSyncWrapper.js'

View File

@@ -1,6 +1,6 @@
import { openSync } from 'fs'
import { ReadStream } from 'tty'
import type { RenderOptions } from '../ink.js'
import type { RenderOptions } from '@anthropic/ink'
import { isEnvTruthy } from './envUtils.js'
import { logError } from './log.js'

View File

@@ -1,5 +1,6 @@
import { initializeAnalyticsSink } from '../services/analytics/sink.js'
import { initializeErrorLogSink } from './errorLogSink.js'
import { initializeAnalyticsSink } from '../services/analytics/sink.js'
/**
* Attach error log and analytics sinks, draining any events queued before

View File

@@ -5,7 +5,7 @@ import {
tokenize,
undoAnsiCodes,
} from '@alcalzone/ansi-tokenize'
import { stringWidth } from '../ink/stringWidth.js'
import { stringWidth } from '@anthropic/ink'
// A code is an "end code" if its code equals its endCode (e.g., hyperlink close)
function isEndCode(code: AnsiCode): boolean {

View File

@@ -2,7 +2,7 @@ import * as React from 'react'
import { useLayoutEffect } from 'react'
import { PassThrough } from 'stream'
import stripAnsi from 'strip-ansi'
import { render, useApp } from '../ink.js'
import { wrappedRender as render, useApp } from '@anthropic/ink'
// This is a workaround for the fact that Ink doesn't support multiple <Static>
// components in the same render tree. Instead of using a <Static> we just render

View File

@@ -1,7 +1,7 @@
import chalk from 'chalk'
import figures from 'figures'
import * as React from 'react'
import { color, Text } from '../ink.js'
import { color, Text } from '@anthropic/ink'
import type { MCPServerConnection } from '../services/mcp/types.js'
import { getAccountInformation, isClaudeAISubscriber } from './auth.js'
import {

View File

@@ -1,5 +1,5 @@
// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
import { Box, Text } from '../ink.js'
import { Box, Text } from '@anthropic/ink'
import * as React from 'react'
import {
getLargeMemoryFiles,

View File

@@ -3,11 +3,11 @@ import {
type OptionWithDescription,
Select,
} from '../../components/CustomSelect/index.js'
import { Pane } from '../../components/design-system/Pane.js'
import { Pane } from '@anthropic/ink'
import { Spinner } from '../../components/Spinner.js'
import { useExitOnCtrlCDWithKeybindings } from '../../hooks/useExitOnCtrlCDWithKeybindings.js'
// eslint-disable-next-line custom-rules/prefer-use-keybindings -- enter to proceed through setup steps
import { Box, Text, useInput } from '../../ink.js'
import { Box, Text, useInput } from '@anthropic/ink'
import { useKeybinding } from '../../keybindings/useKeybinding.js'
import {
detectPythonPackageManager,

View File

@@ -17,7 +17,7 @@ import {
} from '../components/TeleportError.js'
import { getOauthConfig } from '../constants/oauth.js'
import type { SDKMessage } from '../entrypoints/agentSdkTypes.js'
import type { Root } from '../ink.js'
import type { Root } from '@anthropic/ink'
import { KeybindingSetup } from '../keybindings/KeybindingProviderSetup.js'
import { queryHaiku } from '../services/api/claude.js'
import {

View File

@@ -1,6 +1,6 @@
import chalk from 'chalk'
import { ctrlOToExpand } from '../components/CtrlOToExpand.js'
import { stringWidth } from '../ink/stringWidth.js'
import { stringWidth } from '@anthropic/ink'
import sliceAnsi from './sliceAnsi.js'
// Text rendering utilities for terminal display

View File

@@ -17,7 +17,7 @@
import { spawn, spawnSync } from 'child_process'
import { getSessionId } from '../bootstrap/state.js'
import instances from '../ink/instances.js'
import { instances } from '@anthropic/ink'
import { registerCleanup } from './cleanupRegistry.js'
import { pwd } from './cwd.js'
import { logForDebugging } from './debug.js'

View File

@@ -1,5 +1,5 @@
import figures from 'figures'
import { color } from '../components/design-system/color.js'
import { color } from '@anthropic/ink'
import type { Theme, ThemeName } from './theme.js'
export type TreeNode = {

View File

@@ -1,6 +1,6 @@
// Width-aware truncation/wrapping — needs ink/stringWidth (not leaf-safe).
import { stringWidth } from '../ink/stringWidth.js'
import { stringWidth } from '@anthropic/ink'
import { getGraphemeSegmenter } from './intl.js'
/**