fix: remove queued content as-any casts
This commit is contained in:
parent
c130eaad4b
commit
ba36ca454d
|
|
@ -49,7 +49,7 @@ export interface ResolvePrepareCaptureResult extends ScreenshotResult {
|
|||
|
||||
export interface ComputerExecutorCapabilities {
|
||||
screenshotFiltering: 'native' | 'none'
|
||||
platform: 'darwin' | 'win32'
|
||||
platform: 'darwin' | 'win32' | 'linux'
|
||||
hostBundleId: string
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ export function normalizeKeySequence(seq: string): string {
|
|||
*/
|
||||
export function isSystemKeyCombo(
|
||||
seq: string,
|
||||
platform: 'darwin' | 'win32',
|
||||
platform: 'darwin' | 'win32' | 'linux',
|
||||
): boolean {
|
||||
const blocklist = platform === 'darwin' ? BLOCKED_DARWIN : BLOCKED_WIN32
|
||||
const { mods, keys } = partitionKeys(seq)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,14 @@ import type {
|
|||
* Individual message subtypes (UserMessage, AssistantMessage, etc.) extend
|
||||
* this with narrower `type` literals and additional fields.
|
||||
*/
|
||||
export type MessageType = 'user' | 'assistant' | 'system' | 'attachment' | 'progress' | 'grouped_tool_use' | 'collapsed_read_search'
|
||||
export type MessageType =
|
||||
| 'user'
|
||||
| 'assistant'
|
||||
| 'system'
|
||||
| 'attachment'
|
||||
| 'progress'
|
||||
| 'grouped_tool_use'
|
||||
| 'collapsed_read_search'
|
||||
|
||||
/** A single content element inside message.content arrays. */
|
||||
export type ContentItem = ContentBlockParam | ContentBlock
|
||||
|
|
@ -37,7 +44,14 @@ export type Message = {
|
|||
isCompactSummary?: boolean
|
||||
toolUseResult?: unknown
|
||||
isVisibleInTranscriptOnly?: boolean
|
||||
attachment?: { type: string; toolUseID?: string; [key: string]: unknown; addedNames: string[]; addedLines: string[]; removedNames: string[] }
|
||||
attachment?: {
|
||||
type: string
|
||||
toolUseID?: string
|
||||
[key: string]: unknown
|
||||
addedNames: string[]
|
||||
addedLines: string[]
|
||||
removedNames: string[]
|
||||
}
|
||||
message?: {
|
||||
role?: string
|
||||
id?: string
|
||||
|
|
@ -52,8 +66,12 @@ export type AssistantMessage = Message & {
|
|||
type: 'assistant'
|
||||
message: NonNullable<Message['message']>
|
||||
}
|
||||
export type AttachmentMessage<T = { type: string; [key: string]: unknown }> = Message & { type: 'attachment'; attachment: T }
|
||||
export type ProgressMessage<T = unknown> = Message & { type: 'progress'; data: T }
|
||||
export type AttachmentMessage<T = { type: string; [key: string]: unknown }> =
|
||||
Message & { type: 'attachment'; attachment: T }
|
||||
export type ProgressMessage<T = unknown> = Message & {
|
||||
type: 'progress'
|
||||
data: T
|
||||
}
|
||||
export type SystemLocalCommandMessage = Message & { type: 'system' }
|
||||
export type SystemMessage = Message & { type: 'system' }
|
||||
export type UserMessage = Message & {
|
||||
|
|
@ -78,7 +96,7 @@ export type SystemCompactBoundaryMessage = Message & {
|
|||
}
|
||||
export type TombstoneMessage = Message
|
||||
export type ToolUseSummaryMessage = Message
|
||||
export type MessageOrigin = string
|
||||
export type MessageOrigin = string | { kind: string; [key: string]: unknown }
|
||||
export type CompactMetadata = Record<string, unknown>
|
||||
export type SystemAPIErrorMessage = Message & { type: 'system' }
|
||||
export type SystemFileSnapshotMessage = Message & { type: 'system' }
|
||||
|
|
@ -126,7 +144,14 @@ export type RenderableMessage =
|
|||
| AssistantMessage
|
||||
| UserMessage
|
||||
| (Message & { type: 'system' })
|
||||
| (Message & { type: 'attachment'; attachment: { type: string; memories?: { path: string; content: string; mtimeMs: number }[]; [key: string]: unknown } })
|
||||
| (Message & {
|
||||
type: 'attachment'
|
||||
attachment: {
|
||||
type: string
|
||||
memories?: { path: string; content: string; mtimeMs: number }[]
|
||||
[key: string]: unknown
|
||||
}
|
||||
})
|
||||
| (Message & { type: 'progress' })
|
||||
| GroupedToolUseMessage
|
||||
| CollapsedReadSearchGroup
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@ import { env } from '../env.js'
|
|||
|
||||
export const COMPUTER_USE_MCP_SERVER_NAME = 'computer-use'
|
||||
|
||||
type CliComputerUseCapabilities = {
|
||||
screenshotFiltering: 'native' | 'none'
|
||||
platform: 'darwin' | 'win32' | 'linux'
|
||||
}
|
||||
|
||||
/**
|
||||
* Sentinel bundle ID for the frontmost gate. Claude Code is a terminal — it has
|
||||
* no window. This never matches a real `NSWorkspace.frontmostApplication`, so
|
||||
|
|
@ -52,15 +57,14 @@ export function getTerminalBundleId(): string | null {
|
|||
* takes this shape (no `hostBundleId`, no `teachMode`).
|
||||
*/
|
||||
export const CLI_CU_CAPABILITIES = {
|
||||
screenshotFiltering: (process.platform === 'darwin'
|
||||
? 'native'
|
||||
: 'none') as any,
|
||||
platform: (process.platform === 'win32'
|
||||
? 'win32'
|
||||
: process.platform === 'linux'
|
||||
? 'linux'
|
||||
: 'darwin') as any,
|
||||
}
|
||||
screenshotFiltering: process.platform === 'darwin' ? 'native' : 'none',
|
||||
platform:
|
||||
process.platform === 'win32'
|
||||
? 'win32'
|
||||
: process.platform === 'linux'
|
||||
? 'linux'
|
||||
: 'darwin',
|
||||
} satisfies CliComputerUseCapabilities
|
||||
|
||||
export function isComputerUseMCPServer(name: string): boolean {
|
||||
return normalizeNameForMCP(name) === COMPUTER_USE_MCP_SERVER_NAME
|
||||
|
|
|
|||
|
|
@ -94,11 +94,11 @@ export async function handleUrlSchemeLaunch(): Promise<number | null> {
|
|||
|
||||
try {
|
||||
const { waitForUrlEvent } = await import('url-handler-napi')
|
||||
const url = (waitForUrlEvent as any)(5000)
|
||||
const url = await waitForUrlEvent(5000)
|
||||
if (!url) {
|
||||
return null
|
||||
}
|
||||
return await handleDeepLinkUri(await url as string)
|
||||
return await handleDeepLinkUri(url)
|
||||
} catch {
|
||||
// NAPI module not available, or handleDeepLinkUri rejected — not a URL launch
|
||||
return null
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ export function modelSupportsMaxEffort(_model: string): boolean {
|
|||
}
|
||||
|
||||
export function modelSupportsXhighEffort(_model: string): boolean {
|
||||
const supported3P = get3PModelCapabilityOverride(_model, 'xhigh_effort' as any)
|
||||
const supported3P = get3PModelCapabilityOverride(_model, 'xhigh_effort')
|
||||
if (supported3P !== undefined) {
|
||||
return supported3P
|
||||
}
|
||||
|
|
|
|||
|
|
@ -368,7 +368,8 @@ export function isQueuedCommandEditable(cmd: QueuedCommand): boolean {
|
|||
export function isQueuedCommandVisible(cmd: QueuedCommand): boolean {
|
||||
if (
|
||||
(feature('KAIROS') || feature('KAIROS_CHANNELS')) &&
|
||||
(cmd as any).origin?.kind === 'channel'
|
||||
typeof cmd.origin === 'object' &&
|
||||
cmd.origin?.kind === 'channel'
|
||||
)
|
||||
return true
|
||||
return isQueuedCommandEditable(cmd)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { getAPIProvider } from './providers.js'
|
|||
export type ModelCapabilityOverride =
|
||||
| 'effort'
|
||||
| 'max_effort'
|
||||
| 'xhigh_effort'
|
||||
| 'thinking'
|
||||
| 'adaptive_thinking'
|
||||
| 'interleaved_thinking'
|
||||
|
|
|
|||
|
|
@ -362,19 +362,24 @@ export async function persistFileSnapshotIfRemote(): Promise<void> {
|
|||
return
|
||||
}
|
||||
try {
|
||||
const snapshotFiles: SystemFileSnapshotMessage['snapshotFiles'] = []
|
||||
type SnapshotFile = {
|
||||
key: string
|
||||
path: string
|
||||
content: string
|
||||
}
|
||||
const snapshotFiles: SnapshotFile[] = []
|
||||
|
||||
// Snapshot plan file
|
||||
const plan = getPlan()
|
||||
if (plan) {
|
||||
(snapshotFiles as any[]).push({
|
||||
snapshotFiles.push({
|
||||
key: 'plan',
|
||||
path: getPlanFilePath(),
|
||||
content: plan,
|
||||
})
|
||||
}
|
||||
|
||||
if ((snapshotFiles as any[]).length === 0) {
|
||||
if (snapshotFiles.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -184,11 +184,15 @@ export function getDeclaredMarketplaces(): Record<string, DeclaredMarketplace> {
|
|||
// Lowest precedence: implicit < --add-dir < merged settings.
|
||||
// An explicit extraKnownMarketplaces entry for claude-plugins-official
|
||||
// in --add-dir or settings wins.
|
||||
return {
|
||||
const declared = {
|
||||
...implicit,
|
||||
...getAddDirExtraMarketplaces(),
|
||||
...(getInitialSettings().extraKnownMarketplaces ?? {}),
|
||||
} as any
|
||||
...(getAddDirExtraMarketplaces() as Record<string, DeclaredMarketplace>),
|
||||
...((getInitialSettings().extraKnownMarketplaces ?? {}) as Record<
|
||||
string,
|
||||
DeclaredMarketplace
|
||||
>),
|
||||
} satisfies Record<string, DeclaredMarketplace>
|
||||
return declared
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import {
|
|||
isDeferredTool,
|
||||
SEARCH_EXTRA_TOOLS_TOOL_NAME,
|
||||
} from '@claude-code-best/builtin-tools/tools/SearchExtraToolsTool/prompt.js'
|
||||
import type { Message } from '../types/message.js'
|
||||
import type { Message, SystemCompactBoundaryMessage } from '../types/message.js'
|
||||
import {
|
||||
countToolDefinitionTokens,
|
||||
TOOL_TOKEN_COUNT_OVERHEAD,
|
||||
|
|
@ -504,12 +504,15 @@ export function extractDiscoveredToolNames(messages: Message[]): Set<string> {
|
|||
// check rather than isCompactBoundaryMessage — utils/messages.ts imports
|
||||
// from this file, so importing back would be circular.
|
||||
if (msg.type === 'system' && msg.subtype === 'compact_boundary') {
|
||||
const carried = (msg as any).compactMetadata?.preCompactDiscoveredTools as
|
||||
| string[]
|
||||
| undefined
|
||||
const boundary = msg as SystemCompactBoundaryMessage
|
||||
const carried = boundary.compactMetadata.preCompactDiscoveredTools
|
||||
if (carried) {
|
||||
for (const name of carried) discoveredTools.add(name)
|
||||
carriedFromBoundary += carried.length
|
||||
if (Array.isArray(carried)) {
|
||||
for (const name of carried) {
|
||||
if (typeof name === 'string') discoveredTools.add(name)
|
||||
}
|
||||
carriedFromBoundary += carried.length
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import type {
|
|||
ContextCollapseSnapshotEntry,
|
||||
PersistedWorktreeSession,
|
||||
} from '../types/logs.js'
|
||||
import type { Message } from '../types/message.js'
|
||||
import type { ContentItem, Message } from '../types/message.js'
|
||||
import { renameRecordingForSession } from './asciicast.js'
|
||||
import { clearMemoryFileCaches } from './claudemd.js'
|
||||
import {
|
||||
|
|
@ -78,7 +78,9 @@ function extractTodosFromTranscript(messages: Message[]): TodoList {
|
|||
for (let i = messages.length - 1; i >= 0; i--) {
|
||||
const msg = messages[i]
|
||||
if (msg?.type !== 'assistant') continue
|
||||
const toolUse = (msg.message!.content as any[]).find(
|
||||
const content = msg.message?.content
|
||||
if (!Array.isArray(content)) continue
|
||||
const toolUse = (content as ContentItem[]).find(
|
||||
block => block.type === 'tool_use' && block.name === TODO_WRITE_TOOL_NAME,
|
||||
)
|
||||
if (!toolUse || toolUse.type !== 'tool_use') continue
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import type { NonNullableUsage } from '../services/api/logging.js'
|
|||
import type { Message, SystemAPIErrorMessage } from '../types/message.js'
|
||||
import { type CacheSafeParams, runForkedAgent } from './forkedAgent.js'
|
||||
import { createUserMessage, extractTextContent } from './messages.js'
|
||||
import type { APIError } from '@anthropic-ai/sdk'
|
||||
|
||||
// Pattern to detect "/btw" at start of input (case-insensitive, word boundary)
|
||||
const BTW_PATTERN = /^\/btw\b/gi
|
||||
|
|
@ -125,7 +126,12 @@ ${question}`
|
|||
function extractSideQuestionResponse(messages: Message[]): string | null {
|
||||
// Flatten all assistant content blocks across the per-block messages.
|
||||
const assistantBlocks = messages.flatMap(m =>
|
||||
m.type === 'assistant' ? (m.message!.content as unknown as Array<{ type: string; [key: string]: unknown }>) : [],
|
||||
m.type === 'assistant'
|
||||
? (m.message!.content as unknown as Array<{
|
||||
type: string
|
||||
[key: string]: unknown
|
||||
}>)
|
||||
: [],
|
||||
)
|
||||
|
||||
if (assistantBlocks.length > 0) {
|
||||
|
|
@ -136,7 +142,8 @@ function extractSideQuestionResponse(messages: Message[]): string | null {
|
|||
// No text — check if the model tried to call a tool despite instructions.
|
||||
const toolUse = assistantBlocks.find(b => b.type === 'tool_use')
|
||||
if (toolUse) {
|
||||
const toolName = 'name' in toolUse ? (toolUse as any).name : 'a tool'
|
||||
const toolName =
|
||||
typeof toolUse.name === 'string' ? toolUse.name : 'a tool'
|
||||
return `(The model tried to call ${toolName} instead of answering directly. Try rephrasing or ask in the main conversation.)`
|
||||
}
|
||||
}
|
||||
|
|
@ -148,7 +155,11 @@ function extractSideQuestionResponse(messages: Message[]): string | null {
|
|||
m.type === 'system' && 'subtype' in m && m.subtype === 'api_error',
|
||||
)
|
||||
if (apiErr) {
|
||||
return `(API error: ${formatAPIError(apiErr.error as any)})`
|
||||
const error =
|
||||
apiErr.error instanceof Error
|
||||
? apiErr.error
|
||||
: new Error(String(apiErr.error))
|
||||
return `(API error: ${formatAPIError(error as APIError)})`
|
||||
}
|
||||
|
||||
return null
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import {
|
||||
type AnsiCode,
|
||||
type Char,
|
||||
ansiCodesToString,
|
||||
reduceAnsiCodes,
|
||||
type Token,
|
||||
tokenize,
|
||||
undoAnsiCodes,
|
||||
} from '@alcalzone/ansi-tokenize'
|
||||
|
|
@ -17,6 +19,10 @@ function filterStartCodes(codes: AnsiCode[]): AnsiCode[] {
|
|||
return codes.filter(c => !isEndCode(c))
|
||||
}
|
||||
|
||||
function isCharToken(token: Token): token is Char {
|
||||
return token.type === 'char'
|
||||
}
|
||||
|
||||
/**
|
||||
* Slice a string containing ANSI escape codes.
|
||||
*
|
||||
|
|
@ -43,7 +49,13 @@ export default function sliceAnsi(
|
|||
// pass start/end in display cells (via stringWidth), so position must
|
||||
// track the same units.
|
||||
const width =
|
||||
token.type === 'ansi' ? 0 : token.type === 'char' ? (token.fullWidth ? 2 : stringWidth(token.value)) : 0
|
||||
token.type === 'ansi'
|
||||
? 0
|
||||
: token.type === 'char'
|
||||
? token.fullWidth
|
||||
? 2
|
||||
: stringWidth(token.value)
|
||||
: 0
|
||||
|
||||
// Break AFTER trailing zero-width marks — a combining mark attaches to
|
||||
// the preceding base char, so "भा" (भ + ा, 1 display cell) sliced at
|
||||
|
|
@ -77,7 +89,7 @@ export default function sliceAnsi(
|
|||
}
|
||||
|
||||
if (include) {
|
||||
result += (token as any).value
|
||||
result += isCharToken(token) ? token.value : token.code
|
||||
}
|
||||
|
||||
position += width
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@ import {
|
|||
} from '@alcalzone/ansi-tokenize'
|
||||
import type { Theme } from './theme.js'
|
||||
|
||||
type TextToken = Extract<Token, { type: 'char' }>
|
||||
|
||||
function isTextToken(token: Token): token is TextToken {
|
||||
return token.type === 'char'
|
||||
}
|
||||
|
||||
export type TextHighlight = {
|
||||
start: number
|
||||
end: number
|
||||
|
|
@ -126,19 +132,23 @@ class HighlightSegmenter {
|
|||
this.codes.push(token)
|
||||
this.stringPos += token.code.length
|
||||
this.tokenIdx++
|
||||
} else {
|
||||
} else if (isTextToken(token)) {
|
||||
const tokenValue = token.value
|
||||
const charsNeeded = targetVisiblePos - this.visiblePos
|
||||
const charsAvailable = (token as any).value.length - this.charIdx
|
||||
const charsAvailable = tokenValue.length - this.charIdx
|
||||
const charsToTake = Math.min(charsNeeded, charsAvailable)
|
||||
|
||||
this.stringPos += charsToTake
|
||||
this.visiblePos += charsToTake
|
||||
this.charIdx += charsToTake
|
||||
|
||||
if (this.charIdx >= (token as any).value.length) {
|
||||
if (this.charIdx >= tokenValue.length) {
|
||||
this.tokenIdx++
|
||||
this.charIdx = 0
|
||||
}
|
||||
} else {
|
||||
this.stringPos += token.code.length
|
||||
this.tokenIdx++
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1290,10 +1290,10 @@ export async function execIntoTmuxWorktree(args: string[]): Promise<{
|
|||
worktreeName,
|
||||
prNumber !== null ? { prNumber } : undefined,
|
||||
)
|
||||
if (!result.existed) {
|
||||
if (result.existed === false) {
|
||||
// biome-ignore lint/suspicious/noConsole: intentional console output
|
||||
console.log(
|
||||
`Created worktree: ${worktreeDir} (based on ${(result as any).baseBranch})`,
|
||||
`Created worktree: ${worktreeDir} (based on ${result.baseBranch})`,
|
||||
)
|
||||
await performPostCreationSetup(repoRoot, worktreeDir)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user