fix: remove mid-plan as-any casts
This commit is contained in:
parent
33a6217702
commit
c130eaad4b
|
|
@ -18,7 +18,7 @@ let pump: ReturnType<typeof setInterval> | undefined
|
|||
let pending = 0
|
||||
|
||||
function drainTick(cu: ReturnType<typeof requireComputerUseSwift>): void {
|
||||
;(cu as any)?._drainMainRunLoop?.()
|
||||
cu._drainMainRunLoop?.()
|
||||
}
|
||||
|
||||
function retain(): void {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export function registerEscHotkey(onEscape: () => void): boolean {
|
|||
if (process.platform !== 'darwin') return false
|
||||
if (registered) return true
|
||||
const cu = requireComputerUseSwift()
|
||||
if (!(cu as any).hotkey?.registerEscape(onEscape)) {
|
||||
if (!cu.hotkey?.registerEscape(onEscape)) {
|
||||
// CGEvent.tapCreate failed — typically missing Accessibility permission.
|
||||
// CU still works, just without ESC abort. Mirrors Cowork's escAbort.ts:81.
|
||||
logForDebugging('[cu-esc] registerEscape returned false', { level: 'warn' })
|
||||
|
|
@ -41,7 +41,7 @@ export function registerEscHotkey(onEscape: () => void): boolean {
|
|||
export function unregisterEscHotkey(): void {
|
||||
if (!registered) return
|
||||
try {
|
||||
(requireComputerUseSwift() as any).hotkey?.unregister()
|
||||
requireComputerUseSwift().hotkey?.unregister()
|
||||
} finally {
|
||||
releasePump()
|
||||
registered = false
|
||||
|
|
@ -51,5 +51,5 @@ export function unregisterEscHotkey(): void {
|
|||
|
||||
export function notifyExpectedEscape(): void {
|
||||
if (!registered) return
|
||||
(requireComputerUseSwift() as any).hotkey?.notifyExpectedEscape()
|
||||
requireComputerUseSwift().hotkey?.notifyExpectedEscape()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import { CLI_CU_CAPABILITIES, CLI_HOST_BUNDLE_ID } from './common.js'
|
|||
import { validateHwnd } from './win32/shared.js'
|
||||
import { loadPlatform } from './platforms/index.js'
|
||||
import type { Platform } from './platforms/index.js'
|
||||
import type { WindowAction } from './platforms/types.js'
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers for HWND-bound mode
|
||||
|
|
@ -62,6 +63,19 @@ function isBound(): boolean {
|
|||
return getBoundHwndStr() !== null
|
||||
}
|
||||
|
||||
function isWindowAction(action: string): action is WindowAction {
|
||||
return (
|
||||
action === 'minimize' ||
|
||||
action === 'maximize' ||
|
||||
action === 'restore' ||
|
||||
action === 'close' ||
|
||||
action === 'focus' ||
|
||||
action === 'move_offscreen' ||
|
||||
action === 'move_resize' ||
|
||||
action === 'get_rect'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the non-client area offset (title bar height, left border width).
|
||||
* Returns {dx, dy} to subtract from window coords → client coords.
|
||||
|
|
@ -207,7 +221,7 @@ export function createCrossPlatformExecutor(opts: {
|
|||
`[computer-use] cross-platform executor for ${process.platform}`,
|
||||
)
|
||||
|
||||
return {
|
||||
const executor: ComputerExecutor = {
|
||||
capabilities: {
|
||||
...CLI_CU_CAPABILITIES,
|
||||
hostBundleId: CLI_HOST_BUNDLE_ID,
|
||||
|
|
@ -491,12 +505,12 @@ $i = New-Object MUp+INPUT; $i.type=0; $i.mi.dwFlags=0x0004; [MUp]::SendInput(1,
|
|||
await sleep(16)
|
||||
}
|
||||
// mouseDown
|
||||
await (this as any).mouseDown()
|
||||
await executor.mouseDown()
|
||||
await sleep(50)
|
||||
await platform.input.moveMouse(to.x, to.y)
|
||||
await sleep(16)
|
||||
// mouseUp
|
||||
await (this as any).mouseUp()
|
||||
await executor.mouseUp()
|
||||
},
|
||||
|
||||
async scroll(x: number, y: number, dx: number, dy: number): Promise<void> {
|
||||
|
|
@ -553,7 +567,8 @@ $i = New-Object MUp+INPUT; $i.type=0; $i.mi.dwFlags=0x0004; [MUp]::SendInput(1,
|
|||
// ── Window management (Windows only) ──────────────────────────────
|
||||
async manageWindow(action: string, opts?): Promise<boolean> {
|
||||
if (!platform.windowManagement) return false
|
||||
const result = platform.windowManagement.manageWindow(action as any, opts)
|
||||
if (!isWindowAction(action)) return false
|
||||
const result = platform.windowManagement.manageWindow(action, opts)
|
||||
// Invalidate NC offset cache on window state change
|
||||
_ncOffset = null
|
||||
_ncOffsetHwnd = null
|
||||
|
|
@ -1138,6 +1153,7 @@ $i = New-Object MUp+INPUT; $i.type=0; $i.mi.dwFlags=0x0004; [MUp]::SendInput(1,
|
|||
}
|
||||
},
|
||||
}
|
||||
return executor
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -36,7 +36,11 @@ class DebugLogger implements Logger {
|
|||
function checkAccessibilityJXA(): boolean {
|
||||
try {
|
||||
const result = Bun.spawnSync({
|
||||
cmd: ['osascript', '-e', 'tell application "System Events" to get name of every process whose background only is false'],
|
||||
cmd: [
|
||||
'osascript',
|
||||
'-e',
|
||||
'tell application "System Events" to get name of every process whose background only is false',
|
||||
],
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
})
|
||||
|
|
@ -80,7 +84,7 @@ export function getComputerUseHostAdapter(): ComputerUseHostAdapter {
|
|||
ensureOsPermissions: async () => {
|
||||
if (process.platform !== 'darwin') return { granted: true }
|
||||
const cu = requireComputerUseSwift()
|
||||
const tcc = (cu as any).tcc
|
||||
const tcc = cu.tcc
|
||||
// Native Swift .node module provides tcc.checkAccessibility/checkScreenRecording.
|
||||
// When absent (decompiled/reverse-engineered build), fall back to JXA probes.
|
||||
if (tcc) {
|
||||
|
|
|
|||
|
|
@ -1,19 +1,32 @@
|
|||
import type { ComputerUseAPI } from '@ant/computer-use-swift'
|
||||
|
||||
let cached: ComputerUseAPI | undefined
|
||||
export type ComputerUseSwiftAPI = ComputerUseAPI & {
|
||||
hotkey?: {
|
||||
registerEscape(onEscape: () => void): boolean
|
||||
unregister(): void
|
||||
notifyExpectedEscape(): void
|
||||
}
|
||||
tcc?: {
|
||||
checkAccessibility(): boolean
|
||||
checkScreenRecording(): boolean
|
||||
}
|
||||
_drainMainRunLoop?: () => void
|
||||
}
|
||||
|
||||
let cached: ComputerUseSwiftAPI | undefined
|
||||
|
||||
/**
|
||||
* macOS-only loader for @ant/computer-use-swift.
|
||||
* Non-darwin platforms should use src/utils/computerUse/platforms/ instead.
|
||||
*/
|
||||
export function requireComputerUseSwift(): ComputerUseAPI {
|
||||
export function requireComputerUseSwift(): ComputerUseSwiftAPI {
|
||||
if (cached) return cached
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const mod = require('@ant/computer-use-swift')
|
||||
if (mod.ComputerUseAPI && typeof mod.ComputerUseAPI === 'function') {
|
||||
cached = new mod.ComputerUseAPI() as ComputerUseAPI
|
||||
cached = new mod.ComputerUseAPI() as ComputerUseSwiftAPI
|
||||
} else {
|
||||
cached = mod as ComputerUseAPI
|
||||
cached = mod as ComputerUseSwiftAPI
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ interface BridgeResponse {
|
|||
error?: string
|
||||
}
|
||||
|
||||
type FlushableWritable = Writable & {
|
||||
flush?: () => void
|
||||
}
|
||||
|
||||
let bridgeProc: ReturnType<typeof Bun.spawn> | null = null
|
||||
let requestId = 0
|
||||
const pendingRequests = new Map<
|
||||
|
|
@ -131,10 +135,10 @@ export async function call<T = unknown>(
|
|||
try {
|
||||
const stdin = bridgeProc!.stdin
|
||||
if (stdin) {
|
||||
const writable = stdin as unknown as Writable
|
||||
const writable = stdin as unknown as FlushableWritable
|
||||
writable.write(JSON.stringify(req) + '\n')
|
||||
if (typeof (writable as any).flush === 'function') {
|
||||
(writable as any).flush()
|
||||
if (typeof writable.flush === 'function') {
|
||||
writable.flush()
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -8,11 +8,17 @@
|
|||
*/
|
||||
|
||||
import * as fs from 'fs/promises'
|
||||
import type { Dirent } from 'fs'
|
||||
import * as path from 'path'
|
||||
import { logForDebugging } from '../debug.js'
|
||||
import type { EnvironmentKind } from '../teleport/environments.js'
|
||||
import type { TurnStartTime } from './types.js'
|
||||
|
||||
type RecursiveDirent = Dirent & {
|
||||
parentPath?: string
|
||||
path?: string
|
||||
}
|
||||
|
||||
/** Shared debug logger for file persistence modules */
|
||||
export function logDebug(message: string): void {
|
||||
logForDebugging(`[file-persistence] ${message}`)
|
||||
|
|
@ -63,13 +69,14 @@ export async function findModifiedFiles(
|
|||
turnStartTime: TurnStartTime,
|
||||
outputsDir: string,
|
||||
): Promise<string[]> {
|
||||
const turnStartMs = turnStartTime.turnStartTime
|
||||
// Use recursive flag to get all entries in one call
|
||||
let entries: Awaited<ReturnType<typeof fs.readdir>> | any[]
|
||||
let entries: RecursiveDirent[]
|
||||
try {
|
||||
entries = await fs.readdir(outputsDir, {
|
||||
withFileTypes: true,
|
||||
recursive: true,
|
||||
}) as any[]
|
||||
})
|
||||
} catch {
|
||||
// Directory doesn't exist or is not accessible
|
||||
return []
|
||||
|
|
@ -113,7 +120,7 @@ export async function findModifiedFiles(
|
|||
// Filter to files modified since turn start
|
||||
const modifiedFiles: string[] = []
|
||||
for (const result of statResults) {
|
||||
if (result && result.mtimeMs >= (turnStartTime as any as number)) {
|
||||
if (result && result.mtimeMs >= turnStartMs) {
|
||||
modifiedFiles.push(result.filePath)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { feature } from 'bun:bundle'
|
||||
import type { BetaMessageStreamParams } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
|
||||
import type { Dirent } from 'fs'
|
||||
import { readdir, readFile, stat } from 'fs/promises'
|
||||
import memoize from 'lodash-es/memoize.js'
|
||||
import { join } from 'path'
|
||||
|
|
@ -228,9 +229,9 @@ export async function getErrorLogByIndex(
|
|||
* @private
|
||||
*/
|
||||
async function loadLogList(path: string): Promise<LogOption[]> {
|
||||
let files: Awaited<ReturnType<typeof readdir>>
|
||||
let files: Dirent<string>[]
|
||||
try {
|
||||
files = (await readdir(path, { withFileTypes: true })) as any
|
||||
files = await readdir(path, { withFileTypes: true })
|
||||
} catch {
|
||||
logError(new Error(`No logs found at ${path}`))
|
||||
return []
|
||||
|
|
|
|||
|
|
@ -25,6 +25,14 @@ const measures = new Map<
|
|||
{ name: string; startTime: number; duration: number }
|
||||
>()
|
||||
|
||||
declare global {
|
||||
var __performanceShimInstalled: boolean | undefined
|
||||
}
|
||||
|
||||
type PerformanceWithUndiciResourceTiming = Performance & {
|
||||
markResourceTiming(...args: unknown[]): void
|
||||
}
|
||||
|
||||
function now(): number {
|
||||
return original.now()
|
||||
}
|
||||
|
|
@ -124,7 +132,10 @@ function clearMeasures(name?: string): void {
|
|||
// Plain object shim — must NOT inherit from Performance.prototype because
|
||||
// native getters (onresourcetimingbufferfull, timeOrigin, toJSON) check
|
||||
// that `this` is an actual JSC Performance instance and throw otherwise.
|
||||
const shim = {
|
||||
const originalWithResourceTiming =
|
||||
original as PerformanceWithUndiciResourceTiming
|
||||
|
||||
const shim: PerformanceWithUndiciResourceTiming = {
|
||||
now,
|
||||
mark,
|
||||
measure: measure as typeof performance.measure,
|
||||
|
|
@ -137,21 +148,21 @@ const shim = {
|
|||
(() => {}) as typeof performance.setResourceTimingBufferSize,
|
||||
// Node.js v22 undici internal calls this after every fetch — must exist to
|
||||
// avoid TypeError: markResourceTiming is not a function
|
||||
markResourceTiming: (() => {}) as any,
|
||||
markResourceTiming: () => {},
|
||||
// Delegate read-only properties to the original
|
||||
get timeOrigin() {
|
||||
return original.timeOrigin
|
||||
},
|
||||
get onresourcetimingbufferfull() {
|
||||
return (original as any).onresourcetimingbufferfull
|
||||
return originalWithResourceTiming.onresourcetimingbufferfull
|
||||
},
|
||||
set onresourcetimingbufferfull(_v: any) {
|
||||
set onresourcetimingbufferfull(_v: Performance['onresourcetimingbufferfull']) {
|
||||
// no-op — prevent accumulation
|
||||
},
|
||||
toJSON() {
|
||||
return original.toJSON()
|
||||
},
|
||||
} as unknown as typeof performance
|
||||
} as unknown as PerformanceWithUndiciResourceTiming
|
||||
|
||||
/**
|
||||
* Install the shim onto globalThis.performance. Safe to call multiple times.
|
||||
|
|
@ -159,8 +170,8 @@ const shim = {
|
|||
* native Performance reference.
|
||||
*/
|
||||
export function installPerformanceShim(): void {
|
||||
if ((globalThis as any).__performanceShimInstalled) return
|
||||
;(globalThis as any).__performanceShimInstalled = true
|
||||
if (globalThis.__performanceShimInstalled) return
|
||||
globalThis.__performanceShimInstalled = true
|
||||
globalThis.performance = shim
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@ export function validateInputForSettingsFileEdit(
|
|||
const updatedContent = getUpdatedContent()
|
||||
const afterValidation = validateSettingsFileContent(updatedContent)
|
||||
|
||||
if (!afterValidation.isValid) {
|
||||
if (afterValidation.isValid === false) {
|
||||
return {
|
||||
result: false,
|
||||
message: `Claude Code settings.json validation failed after edit:\n${(afterValidation as any).error}\n\nFull schema:\n${(afterValidation as any).fullSchema}\nIMPORTANT: Do not update the env unless explicitly instructed to do so.`,
|
||||
message: `Claude Code settings.json validation failed after edit:\n${afterValidation.error}\n\nFull schema:\n${afterValidation.fullSchema}\nIMPORTANT: Do not update the env unless explicitly instructed to do so.`,
|
||||
errorCode: 10,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,19 @@ const RENDERED_AS_SENTINEL = new Set([
|
|||
|
||||
const searchTextCache = new WeakMap<RenderableMessage, string>()
|
||||
|
||||
function isTextContentBlock(
|
||||
block: unknown,
|
||||
): block is { type: 'text'; text: string } {
|
||||
return (
|
||||
typeof block === 'object' &&
|
||||
block !== null &&
|
||||
'type' in block &&
|
||||
block.type === 'text' &&
|
||||
'text' in block &&
|
||||
typeof block.text === 'string'
|
||||
)
|
||||
}
|
||||
|
||||
/** Flatten a RenderableMessage to lowercased searchable text. WeakMap-
|
||||
* cached — messages are append-only and immutable so a hit is always
|
||||
* valid. Lowercased at cache time: the only caller immediately
|
||||
|
|
@ -38,7 +51,7 @@ function computeSearchText(msg: RenderableMessage): string {
|
|||
raw = RENDERED_AS_SENTINEL.has(c) ? '' : c
|
||||
} else {
|
||||
const parts: string[] = []
|
||||
for (const b of (c ?? [])) {
|
||||
for (const b of c ?? []) {
|
||||
if (b.type === 'text') {
|
||||
if (!RENDERED_AS_SENTINEL.has(b.text)) parts.push(b.text)
|
||||
} else if (b.type === 'tool_result') {
|
||||
|
|
@ -84,7 +97,9 @@ function computeSearchText(msg: RenderableMessage): string {
|
|||
// (AttachmentMessage.tsx <Ansi>{m.content}</Ansi>). Visible but
|
||||
// unsearchable without this — [ dump finds it, / doesn't.
|
||||
if (msg.attachment!.type === 'relevant_memories') {
|
||||
raw = (msg.attachment!.memories ?? []).map((m: { content: string }) => m.content).join('\n')
|
||||
raw = (msg.attachment!.memories ?? [])
|
||||
.map((m: { content: string }) => m.content)
|
||||
.join('\n')
|
||||
} else if (
|
||||
// Mid-turn prompts — queued while an agent is running. Render via
|
||||
// UserTextMessage (AttachmentMessage.tsx:~348). stickyPromptText
|
||||
|
|
@ -97,7 +112,11 @@ function computeSearchText(msg: RenderableMessage): string {
|
|||
raw =
|
||||
typeof p === 'string'
|
||||
? p
|
||||
: (p as any[]).flatMap(b => (b.type === 'text' ? [b.text] : [])).join('\n')
|
||||
: Array.isArray(p)
|
||||
? p
|
||||
.flatMap(b => (isTextContentBlock(b) ? [b.text] : []))
|
||||
.join('\n')
|
||||
: ''
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user