mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-17 22:05:50 +00:00
chore: 清理 src 下 33 项死代码和类型断言
删除未使用的文件/目录(mcp/adapter、cli/update.ts 等)、 未使用的重导出文件(design-system/color.ts 等 12 个)、 7 个零引用的导出函数、修复 5 处 as any 为精确类型。 净减少 ~1194 行代码,precheck 4077 测试全部通过。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -66,34 +66,3 @@ export function generateRequestId(
|
||||
const timestamp = Date.now()
|
||||
return `${requestType}-${timestamp}@${agentId}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a request ID into its components.
|
||||
* Returns null if the request ID doesn't match the expected format.
|
||||
*/
|
||||
export function parseRequestId(
|
||||
requestId: string,
|
||||
): { requestType: string; timestamp: number; agentId: string } | null {
|
||||
const atIndex = requestId.indexOf('@')
|
||||
if (atIndex === -1) {
|
||||
return null
|
||||
}
|
||||
|
||||
const prefix = requestId.slice(0, atIndex)
|
||||
const agentId = requestId.slice(atIndex + 1)
|
||||
|
||||
const lastDashIndex = prefix.lastIndexOf('-')
|
||||
if (lastDashIndex === -1) {
|
||||
return null
|
||||
}
|
||||
|
||||
const requestType = prefix.slice(0, lastDashIndex)
|
||||
const timestampStr = prefix.slice(lastDashIndex + 1)
|
||||
const timestamp = parseInt(timestampStr, 10)
|
||||
|
||||
if (isNaN(timestamp)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return { requestType, timestamp, agentId }
|
||||
}
|
||||
|
||||
@@ -48,31 +48,6 @@ export function _resetRecordingStateForTesting(): void {
|
||||
recordingState.timestamp = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all .cast files for the current session.
|
||||
* Returns paths sorted by filename (chronological by timestamp suffix).
|
||||
*/
|
||||
export function getSessionRecordingPaths(): string[] {
|
||||
const sessionId = getSessionId()
|
||||
const projectsDir = join(getClaudeConfigHomeDir(), 'projects')
|
||||
const projectDir = join(projectsDir, sanitizePath(getOriginalCwd()))
|
||||
try {
|
||||
// eslint-disable-next-line custom-rules/no-sync-fs -- called during /share before upload, not in hot path
|
||||
const entries = getFsImplementation().readdirSync(projectDir)
|
||||
const names = (
|
||||
typeof entries[0] === 'string'
|
||||
? entries
|
||||
: (entries as { name: string }[]).map(e => e.name)
|
||||
) as string[]
|
||||
const files = names
|
||||
.filter(f => f.startsWith(sessionId) && f.endsWith('.cast'))
|
||||
.sort()
|
||||
return files.map(f => join(projectDir, f))
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename the recording file to match the current session ID.
|
||||
* Called after --resume/--continue changes the session ID via switchSession().
|
||||
@@ -124,14 +99,6 @@ function getTerminalSize(): { cols: number; rows: number } {
|
||||
return { cols, rows }
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush pending recording data to disk.
|
||||
* Call before reading the .cast file (e.g., during /share).
|
||||
*/
|
||||
export async function flushAsciicastRecorder(): Promise<void> {
|
||||
await recorder?.flush()
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the asciicast recorder.
|
||||
* Wraps process.stdout.write to capture all terminal output with timestamps.
|
||||
|
||||
@@ -1,250 +0,0 @@
|
||||
/**
|
||||
* OCR module using Windows.Media.Ocr.OcrEngine via PowerShell.
|
||||
* Captures a screen region or window, then runs WinRT OCR to extract text.
|
||||
*/
|
||||
|
||||
import { ps as runPs } from './shared.js'
|
||||
|
||||
export interface OcrLine {
|
||||
text: string
|
||||
bounds: { x: number; y: number; w: number; h: number }
|
||||
}
|
||||
|
||||
export interface OcrResult {
|
||||
text: string
|
||||
lines: OcrLine[]
|
||||
language: string
|
||||
}
|
||||
|
||||
function emptyResult(language: string): OcrResult {
|
||||
return { text: '', lines: [], language }
|
||||
}
|
||||
|
||||
/**
|
||||
* PowerShell script that:
|
||||
* 1. Screenshots a screen region using CopyFromScreen
|
||||
* 2. Saves to temp PNG
|
||||
* 3. Loads via WinRT BitmapDecoder -> SoftwareBitmap
|
||||
* 4. Runs OcrEngine.RecognizeAsync
|
||||
* 5. Outputs JSON with text, lines, and bounding rects
|
||||
*/
|
||||
function buildOcrRegionScript(
|
||||
x: number,
|
||||
y: number,
|
||||
w: number,
|
||||
h: number,
|
||||
lang: string,
|
||||
): string {
|
||||
return `
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
Add-Type -AssemblyName System.Runtime.WindowsRuntime
|
||||
|
||||
# Load WinRT types
|
||||
$null = [Windows.Media.Ocr.OcrEngine, Windows.Foundation, ContentType = WindowsRuntime]
|
||||
$null = [Windows.Graphics.Imaging.SoftwareBitmap, Windows.Foundation, ContentType = WindowsRuntime]
|
||||
$null = [Windows.Graphics.Imaging.BitmapDecoder, Windows.Foundation, ContentType = WindowsRuntime]
|
||||
$null = [Windows.Storage.StorageFile, Windows.Foundation, ContentType = WindowsRuntime]
|
||||
$null = [Windows.Storage.Streams.RandomAccessStream, Windows.Foundation, ContentType = WindowsRuntime]
|
||||
$null = [Windows.Globalization.Language, Windows.Foundation, ContentType = WindowsRuntime]
|
||||
|
||||
# Await helper for WinRT async operations
|
||||
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | Where-Object {
|
||||
$_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and
|
||||
$_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation\`1'
|
||||
})[0]
|
||||
Function Await($WinRtTask, $ResultType) {
|
||||
$asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
|
||||
$netTask = $asTask.Invoke($null, @($WinRtTask))
|
||||
$netTask.Wait(-1) | Out-Null
|
||||
$netTask.Result
|
||||
}
|
||||
|
||||
try {
|
||||
# Step 1: Screenshot region
|
||||
$bmp = New-Object System.Drawing.Bitmap(${w}, ${h})
|
||||
$g = [System.Drawing.Graphics]::FromImage($bmp)
|
||||
$g.CopyFromScreen(${x}, ${y}, 0, 0, (New-Object System.Drawing.Size(${w}, ${h})))
|
||||
$g.Dispose()
|
||||
|
||||
# Step 2: Save to temp file
|
||||
$tmpFile = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "ocrtemp_$([guid]::NewGuid().ToString('N')).png")
|
||||
$bmp.Save($tmpFile, [System.Drawing.Imaging.ImageFormat]::Png)
|
||||
$bmp.Dispose()
|
||||
|
||||
# Step 3: Open as StorageFile -> BitmapDecoder -> SoftwareBitmap
|
||||
$storageFile = Await ([Windows.Storage.StorageFile]::GetFileFromPathAsync($tmpFile)) ([Windows.Storage.StorageFile])
|
||||
$stream = Await ($storageFile.OpenAsync([Windows.Storage.FileAccessMode]::Read)) ([Windows.Storage.Streams.IRandomAccessStream])
|
||||
$decoder = Await ([Windows.Graphics.Imaging.BitmapDecoder]::CreateAsync($stream)) ([Windows.Graphics.Imaging.BitmapDecoder])
|
||||
$softwareBmp = Await ($decoder.GetSoftwareBitmapAsync()) ([Windows.Graphics.Imaging.SoftwareBitmap])
|
||||
|
||||
# Step 4: Create OCR engine
|
||||
$ocrLang = New-Object Windows.Globalization.Language('${lang}')
|
||||
$engine = [Windows.Media.Ocr.OcrEngine]::TryCreateFromLanguage($ocrLang)
|
||||
if ($engine -eq $null) {
|
||||
# Fallback to en-US
|
||||
$ocrLang = New-Object Windows.Globalization.Language('en-US')
|
||||
$engine = [Windows.Media.Ocr.OcrEngine]::TryCreateFromLanguage($ocrLang)
|
||||
}
|
||||
if ($engine -eq $null) {
|
||||
Write-Output '{"text":"","lines":[],"language":"${lang}"}'
|
||||
return
|
||||
}
|
||||
|
||||
# Step 5: Run OCR
|
||||
$ocrResult = Await ($engine.RecognizeAsync($softwareBmp)) ([Windows.Media.Ocr.OcrResult])
|
||||
|
||||
# Step 6: Extract lines with bounding rects
|
||||
$lines = @()
|
||||
foreach ($line in $ocrResult.Lines) {
|
||||
$minX = [double]::MaxValue; $minY = [double]::MaxValue
|
||||
$maxX = 0.0; $maxY = 0.0
|
||||
foreach ($word in $line.Words) {
|
||||
$r = $word.BoundingRect
|
||||
if ($r.X -lt $minX) { $minX = $r.X }
|
||||
if ($r.Y -lt $minY) { $minY = $r.Y }
|
||||
if (($r.X + $r.Width) -gt $maxX) { $maxX = $r.X + $r.Width }
|
||||
if (($r.Y + $r.Height) -gt $maxY) { $maxY = $r.Y + $r.Height }
|
||||
}
|
||||
$lines += @{
|
||||
text = $line.Text
|
||||
bounds = @{
|
||||
x = [int]$minX
|
||||
y = [int]$minY
|
||||
w = [int]($maxX - $minX)
|
||||
h = [int]($maxY - $minY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output = @{
|
||||
text = $ocrResult.Text
|
||||
lines = $lines
|
||||
language = $ocrLang.LanguageTag
|
||||
}
|
||||
Write-Output (ConvertTo-Json $output -Depth 4 -Compress)
|
||||
|
||||
# Cleanup
|
||||
$stream.Dispose()
|
||||
Remove-Item $tmpFile -ErrorAction SilentlyContinue
|
||||
} catch {
|
||||
Write-Output '{"text":"","lines":[],"language":"${lang}"}'
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* PowerShell script to get a window's bounding rect by title.
|
||||
*/
|
||||
function buildGetWindowRectScript(windowTitle: string): string {
|
||||
const escaped = windowTitle.replace(/'/g, "''")
|
||||
return `
|
||||
Add-Type @'
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
public class WinRect {
|
||||
[DllImport("user32.dll", CharSet=CharSet.Unicode)]
|
||||
public static extern IntPtr FindWindow(string c, string t);
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool GetWindowRect(IntPtr h, out RECT r);
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT { public int L, T, R, B; }
|
||||
public static string Get(string title) {
|
||||
IntPtr hwnd = FindWindow(null, title);
|
||||
if (hwnd == IntPtr.Zero) return "NOT_FOUND";
|
||||
RECT r; GetWindowRect(hwnd, out r);
|
||||
int w = r.R - r.L; int h = r.B - r.T;
|
||||
if (w <= 0 || h <= 0) return "INVALID_SIZE";
|
||||
return r.L + "," + r.T + "," + w + "," + h;
|
||||
}
|
||||
}
|
||||
'@
|
||||
[WinRect]::Get('${escaped}')
|
||||
`
|
||||
}
|
||||
|
||||
function parseOcrOutput(raw: string, lang: string): OcrResult {
|
||||
if (!raw) return emptyResult(lang)
|
||||
try {
|
||||
const parsed = JSON.parse(raw)
|
||||
return {
|
||||
text: parsed.text ?? '',
|
||||
lines: Array.isArray(parsed.lines)
|
||||
? parsed.lines.map((l: any) => ({
|
||||
text: l.text ?? '',
|
||||
bounds: {
|
||||
x: l.bounds?.x ?? 0,
|
||||
y: l.bounds?.y ?? 0,
|
||||
w: l.bounds?.w ?? 0,
|
||||
h: l.bounds?.h ?? 0,
|
||||
},
|
||||
}))
|
||||
: [],
|
||||
language: parsed.language ?? lang,
|
||||
}
|
||||
} catch {
|
||||
return emptyResult(lang)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform OCR on a screen region.
|
||||
* Screenshots the specified rectangle, then runs WinRT OcrEngine.
|
||||
*
|
||||
* @param x - Left coordinate
|
||||
* @param y - Top coordinate
|
||||
* @param w - Width in pixels
|
||||
* @param h - Height in pixels
|
||||
* @param lang - BCP-47 language tag (default 'en-US'). Confirmed: 'en-US', 'zh-Hans-CN'
|
||||
*/
|
||||
export async function ocrRegion(
|
||||
x: number,
|
||||
y: number,
|
||||
w: number,
|
||||
h: number,
|
||||
lang?: string,
|
||||
): Promise<OcrResult> {
|
||||
const language = lang ?? 'en-US'
|
||||
if (w <= 0 || h <= 0) return emptyResult(language)
|
||||
|
||||
try {
|
||||
const script = buildOcrRegionScript(x, y, w, h, language)
|
||||
const raw = runPs(script)
|
||||
return parseOcrOutput(raw, language)
|
||||
} catch {
|
||||
return emptyResult(language)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform OCR on a specific window by its title.
|
||||
* Gets the window rect, then delegates to ocrRegion.
|
||||
*
|
||||
* @param windowTitle - Exact window title to find via FindWindow
|
||||
* @param lang - BCP-47 language tag (default 'en-US')
|
||||
*/
|
||||
export async function ocrWindow(
|
||||
windowTitle: string,
|
||||
lang?: string,
|
||||
): Promise<OcrResult> {
|
||||
const language = lang ?? 'en-US'
|
||||
|
||||
try {
|
||||
const rectScript = buildGetWindowRectScript(windowTitle)
|
||||
const raw = runPs(rectScript)
|
||||
const trimmed = raw.trim()
|
||||
|
||||
if (!trimmed || trimmed === 'NOT_FOUND' || trimmed === 'INVALID_SIZE') {
|
||||
return emptyResult(language)
|
||||
}
|
||||
|
||||
const parts = trimmed.split(',')
|
||||
if (parts.length !== 4) return emptyResult(language)
|
||||
|
||||
const [x, y, w, h] = parts.map(Number)
|
||||
if (!w || !h) return emptyResult(language)
|
||||
|
||||
return ocrRegion(x, y, w, h, lang)
|
||||
} catch {
|
||||
return emptyResult(language)
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,8 @@ export async function validateManifest(
|
||||
const errors = parseResult.error.flatten()
|
||||
const errorMessages = [
|
||||
...Object.entries(errors.fieldErrors).map(
|
||||
([field, errs]) => `${field}: ${(errs as any)?.join(', ')}`,
|
||||
([field, errs]) =>
|
||||
`${field}: ${(errs as string[] | undefined)?.join(', ')}`,
|
||||
),
|
||||
...(errors.formErrors || []),
|
||||
]
|
||||
|
||||
@@ -65,8 +65,9 @@ export function getMcpInstructionsDelta(
|
||||
attachmentCount++
|
||||
if (msg.attachment!.type !== 'mcp_instructions_delta') continue
|
||||
midCount++
|
||||
for (const n of (msg.attachment! as any).addedNames) announced.add(n)
|
||||
for (const n of (msg.attachment! as any).removedNames) announced.delete(n)
|
||||
const delta = msg.attachment! as unknown as McpInstructionsDelta
|
||||
for (const n of delta.addedNames) announced.add(n)
|
||||
for (const n of delta.removedNames) announced.delete(n)
|
||||
}
|
||||
|
||||
const connected = mcpClients.filter(
|
||||
|
||||
@@ -37,8 +37,8 @@ export function extractConversationText(messages: Message[]): string {
|
||||
if ('isMeta' in msg && msg.isMeta) continue
|
||||
if (
|
||||
'origin' in msg &&
|
||||
(msg as any).origin &&
|
||||
(msg as any).origin.kind !== 'human'
|
||||
(msg as unknown as { origin?: { kind?: string } }).origin &&
|
||||
(msg as unknown as { origin: { kind?: string } }).origin.kind !== 'human'
|
||||
)
|
||||
continue
|
||||
const content = msg.message!.content
|
||||
@@ -116,7 +116,9 @@ export async function generateSessionTitle(
|
||||
},
|
||||
})
|
||||
|
||||
const text = extractTextContent(result.message.content as any)
|
||||
const text = extractTextContent(
|
||||
result.message.content as readonly { readonly type: string }[],
|
||||
)
|
||||
|
||||
const parsed = titleSchema().safeParse(safeParseJSON(text))
|
||||
const title = parsed.success ? parsed.data.title.trim() || null : null
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
// Auto-generated stub — replace with real implementation
|
||||
export {}
|
||||
export const watchSystemTheme: (
|
||||
querier: unknown,
|
||||
setTheme: React.Dispatch<
|
||||
React.SetStateAction<import('./systemTheme.js').SystemTheme>
|
||||
>,
|
||||
) => () => void = () => () => {}
|
||||
@@ -48,15 +48,6 @@ function isInternalWarning(warning: Error): boolean {
|
||||
// Store reference to our warning handler so we can detect if it's already installed
|
||||
let warningHandler: ((warning: Error) => void) | null = null
|
||||
|
||||
// For testing only - allows resetting the warning handler state
|
||||
export function resetWarningHandler(): void {
|
||||
if (warningHandler) {
|
||||
process.removeListener('warning', warningHandler)
|
||||
}
|
||||
warningHandler = null
|
||||
warningCounts.clear()
|
||||
}
|
||||
|
||||
export function initializeWarningHandler(): void {
|
||||
// Only set up handler once - check if our handler is already installed
|
||||
const currentListeners = process.listeners('warning')
|
||||
|
||||
Reference in New Issue
Block a user