fix: remove runtime helper as-any casts

This commit is contained in:
James Feng 2026-06-07 15:45:11 +08:00
parent ba36ca454d
commit ac807aeb08
14 changed files with 102 additions and 46 deletions

View File

@ -10,7 +10,7 @@ import { getGlobalConfig } from '../utils/config.js'
import { getClaudeAIOAuthTokens } from '../utils/auth.js'
import { getOauthConfig } from '../constants/oauth.js'
import { getUserAgent } from '../utils/http.js'
import type { Message } from '../types/message.js'
import type { ContentItem, Message } from '../types/message.js'
// ─── Rate limiting ──────────────────────────────────
@ -64,6 +64,15 @@ export function triggerCompanionReaction(
// ─── Helpers ────────────────────────────────────────
function getMessageContent(
message: Message,
): string | ContentItem[] | undefined {
const content = message.message?.content
return typeof content === 'string' || Array.isArray(content)
? content
: undefined
}
function isAddressed(messages: Message[], name: string): boolean {
const pattern = new RegExp(`\\b${escapeRegex(name)}\\b`, 'i')
for (
@ -73,7 +82,7 @@ function isAddressed(messages: Message[], name: string): boolean {
) {
const m = messages[i]
if (m?.type !== 'user') continue
const content = (m as any).message?.content
const content = getMessageContent(m)
if (typeof content === 'string' && pattern.test(content)) return true
}
return false
@ -89,14 +98,17 @@ function buildTranscript(messages: Message[]): string {
.filter(m => m.type === 'user' || m.type === 'assistant')
.map(m => {
const role = m.type === 'user' ? 'user' : 'claude'
const content = (m as any).message?.content
const content = getMessageContent(m)
const text =
typeof content === 'string'
? content.slice(0, 300)
: Array.isArray(content)
? content
.filter((b: any) => b?.type === 'text')
.map((b: any) => b.text)
.filter(
(b): b is Extract<ContentItem, { type: 'text' }> =>
b.type === 'text',
)
.map(b => b.text)
.join(' ')
.slice(0, 300)
: ''

View File

@ -185,8 +185,8 @@ export async function getOutputStyleConfig(): Promise<OutputStyleConfig | null>
const forcedStyles = Object.values(allStyles).filter(
(style): style is OutputStyleConfig =>
style !== null &&
(style as any).source === 'plugin' &&
(style as any).forceForPlugin === true,
style.source === 'plugin' &&
style.forceForPlugin === true,
)
const firstForcedStyle = forcedStyles[0]

View File

@ -12,7 +12,7 @@
import { describe, test, expect, mock, beforeEach } from 'bun:test'
// --- MACRO 全局注入 (编译时 define 在测试中不可用) ---
;(globalThis as any).MACRO = {
globalThis.MACRO = {
VERSION: '2.1.888',
BUILD_TIME: '2026-04-22T00:00:00Z',
FEEDBACK_CHANNEL: '',
@ -214,7 +214,7 @@ const standardTools: Tools = [
{ name: 'Agent' },
{ name: 'AskUserQuestion' },
{ name: 'TaskCreate' },
] as any
] as unknown as Tools
async function getFullPrompt(
tools: Tools = standardTools,

View File

@ -10,7 +10,7 @@ import { isEnvTruthy } from '../utils/envUtils.js';
// Runtime fallback for MACRO.* when not injected by build/dev defines.
// This happens when running cli.tsx directly (not via `bun run dev` or built dist/).
if (typeof globalThis.MACRO === 'undefined') {
(globalThis as any).MACRO = {
globalThis.MACRO = {
VERSION: process.env.CLAUDE_CODE_VERSION || '2.1.888',
BUILD_TIME: new Date().toISOString(),
FEEDBACK_CHANNEL: '',

View File

@ -142,9 +142,9 @@ export async function startMCPServer(
(args as never) ?? {},
toolUseContext,
)
if (validationResult && !validationResult.result) {
if (validationResult?.result === false) {
throw new Error(
`Tool ${name} input is invalid: ${(validationResult as any).message}`,
`Tool ${name} input is invalid: ${validationResult.message}`,
)
}
const finalResult = await tool.call(

View File

@ -136,7 +136,7 @@ async function isAppleTerminalBellDisabled(): Promise<boolean> {
// Lazy-load plist (~280KB with xmlbuilder+@xmldom) — only hit on
// Apple_Terminal with auto-channel, which is a small fraction of users.
const plist = await import('plist')
const parsed: Record<string, unknown> = plist.parse(defaultsOutput.stdout) as any
const parsed = plist.parse(defaultsOutput.stdout) as Record<string, unknown>
const windowSettings = parsed?.['Window Settings'] as
| Record<string, unknown>
| undefined

View File

@ -241,7 +241,7 @@ export async function startSkillDiscoveryPrefetch(
durationMs: Date.now() - startedAt,
indexSize: index.length,
method: 'tfidf',
} as any
}
logForDebugging(
`[skill-search] prefetch found ${newResults.length} skills in ${signal.durationMs}ms`,
@ -306,7 +306,7 @@ export async function getTurnZeroSkillDiscovery(
durationMs: Date.now() - startedAt,
indexSize: index.length,
method: 'tfidf',
} as any
}
logForDebugging(
`[skill-search] turn-zero found ${results.length} skills in ${signal.durationMs}ms`,

View File

@ -1,9 +1,8 @@
// STUB: 待补全 — 见 docs/devlog/02-tsc-stubs.md
// Skill search signal types — used by skill search prefetch and attachment utilities.
// DiscoverySignal represents the signal emitted when a skill is discovered during prefetch.
export type DiscoverySignal = {
type: 'skill_discovery'
skillId: string
[key: string]: unknown
trigger: 'assistant_turn' | 'user_input'
queryText: string
startedAt: number
durationMs: number
indexSize: number
method: 'tfidf'
}

View File

@ -479,7 +479,13 @@ function roughTokenCountEstimationForBlock(
return 2000
}
if (block.type === 'tool_result') {
return roughTokenCountEstimationForContent(block.content as any)
return roughTokenCountEstimationForContent(
block.content as
| string
| Array<Anthropic.ContentBlock>
| Array<Anthropic.ContentBlockParam>
| undefined,
)
}
if (block.type === 'tool_use') {
// input is the JSON the model generated — arbitrarily large (bash

View File

@ -1,4 +1,7 @@
import type { BetaContentBlock, BetaUsage } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
import type {
BetaContentBlock,
BetaUsage,
} from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
import { createHash, randomUUID, type UUID } from 'crypto'
import { mkdir, readFile, writeFile } from 'fs/promises'
import isPlainObject from 'lodash-es/isPlainObject.js'
@ -9,6 +12,7 @@ import { calculateUSDCost } from 'src/utils/modelCost.js'
import type {
AssistantMessage,
Message,
MessageContent,
StreamEvent,
SystemAPIErrorMessage,
UserMessage,
@ -252,24 +256,27 @@ function mapAssistantMessage(
message: {
...message.message,
content: (message.message.content as BetaContentBlock[])
.map(_ => {
switch (_.type) {
.map(block => {
switch (block.type) {
case 'text':
return {
..._,
text: f(_.text) as string,
citations: _.citations || [],
...block,
text: f(block.text) as string,
citations: block.citations || [],
} // Ensure citations
case 'tool_use':
return {
..._,
input: mapValuesDeep(_.input as Record<string, unknown>, f),
...block,
input: mapValuesDeep(block.input as Record<string, unknown>, f),
}
default:
return _ // Handle other block types unchanged
return block // Handle other block types unchanged
}
})
.filter(Boolean) as any,
.filter(
(block): block is NonNullable<typeof block> =>
block !== null && block !== undefined,
) as unknown as MessageContent,
},
type: 'assistant',
}

View File

@ -15,7 +15,7 @@ type SetAppStateFn = (updater: (prev: AppState) => AppState) => void
export function killTask(taskId: string, setAppState: SetAppStateFn): void {
updateTaskState(taskId, setAppState, task => {
if ((task as any).status !== 'running' || !isLocalShellTask(task)) {
if (!isLocalShellTask(task) || task.status !== 'running') {
return task
}

39
src/types/global.d.ts vendored
View File

@ -16,12 +16,28 @@ declare namespace MACRO {
export const VERSION_CHANGELOG: string
}
interface GlobalThis {
MACRO:
| {
VERSION: string
BUILD_TIME: string
FEEDBACK_CHANNEL: string
ISSUES_EXPLAINER: string
NATIVE_PACKAGE_URL: string
PACKAGE_URL: string
VERSION_CHANGELOG: string
}
| undefined
}
// ============================================================================
// Internal Anthropic-only identifiers (dead-code eliminated in open-source)
// These are referenced inside `MACRO(() => ...)` or `false && ...` blocks.
// Model resolution (internal)
declare function resolveAntModel(model: string): import('../utils/model/antModels.js').AntModel | undefined
declare function resolveAntModel(
model: string,
): import('../utils/model/antModels.js').AntModel | undefined
declare function getAntModels(): import('../utils/model/antModels.js').AntModel[]
declare function getAntModelOverrideConfig(): {
defaultSystemPromptSuffix?: string
@ -31,7 +47,13 @@ declare function getAntModelOverrideConfig(): {
// Companion reactions handled by src/buddy/companionReact.ts (direct import)
// Metrics (internal)
type ApiMetricEntry = { ttftMs: number; firstTokenTime: number; lastTokenTime: number; responseLengthBaseline: number; endResponseLength: number }
type ApiMetricEntry = {
ttftMs: number
firstTokenTime: number
lastTokenTime: number
responseLengthBaseline: number
endResponseLength: number
}
declare const apiMetricsRef: React.RefObject<ApiMetricEntry[]> | null
declare function computeTtftText(metrics: ApiMetricEntry[]): string
@ -44,8 +66,12 @@ declare function ExperimentEnrollmentNotice(): JSX.Element | null
declare const HOOK_TIMING_DISPLAY_THRESHOLD_MS: number
// Ultraplan (internal)
declare function UltraplanChoiceDialog(props: Record<string, unknown>): JSX.Element | null
declare function UltraplanLaunchDialog(props: Record<string, unknown>): JSX.Element | null
declare function UltraplanChoiceDialog(
props: Record<string, unknown>,
): JSX.Element | null
declare function UltraplanLaunchDialog(
props: Record<string, unknown>,
): JSX.Element | null
declare function launchUltraplan(...args: unknown[]): Promise<string>
// T — Generic type parameter leaked from React compiler output
@ -53,7 +79,10 @@ declare function launchUltraplan(...args: unknown[]): Promise<string>
declare type T = unknown
// Tungsten (internal)
declare function TungstenPill(props?: { key?: string; selected?: boolean }): JSX.Element | null
declare function TungstenPill(props?: {
key?: string
selected?: boolean
}): JSX.Element | null
// ============================================================================
// Build-time constants BUILD_TARGET/BUILD_ENV/INTERFACE_TYPE — removed (zero runtime usage)

View File

@ -117,8 +117,8 @@ export function isAnthropicAuthEnabled(): boolean {
isEnvTruthy(process.env.CLAUDE_CODE_USE_BEDROCK) ||
isEnvTruthy(process.env.CLAUDE_CODE_USE_VERTEX) ||
isEnvTruthy(process.env.CLAUDE_CODE_USE_FOUNDRY) ||
(settings as any).modelType === 'openai' ||
(settings as any).modelType === 'gemini' ||
settings.modelType === 'openai' ||
settings.modelType === 'gemini' ||
!!process.env.OPENAI_BASE_URL ||
!!process.env.GEMINI_BASE_URL
const apiKeyHelper = settings.apiKeyHelper

View File

@ -56,7 +56,7 @@ import { TASK_LIST_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskL
import { TASK_UPDATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskUpdateTool/constants.js'
import { TEAM_CREATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TeamCreateTool/constants.js'
import { TEAM_DELETE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TeamDeleteTool/constants.js'
import type { Message } from '../../types/message.js'
import type { ContentItem, Message } from '../../types/message.js'
import type { PermissionDecision } from '../../types/permissions.js'
import {
createAssistantAPIErrorMessage,
@ -1449,13 +1449,16 @@ export async function runInProcessTeammate(
for (let i = allMessages.length - 1; i >= 0; i--) {
const m = allMessages[i]!
if (m.type === 'assistant') {
const blocks = (m.message?.content ?? []) as any[]
const content = m.message?.content
const blocks: ContentItem[] = Array.isArray(content) ? content : []
for (const b of blocks) {
if (b?.type === 'tool_use') completionToolUseCount++
if (b.type === 'tool_use') completionToolUseCount++
}
const textBlocks = blocks.filter((b: any) => b?.type === 'text')
const textBlocks = blocks.filter(
(b): b is Extract<ContentItem, { type: 'text' }> => b.type === 'text',
)
if (textBlocks.length > 0 && lastAssistantContent.length === 0) {
lastAssistantContent = textBlocks.map((b: any) => ({
lastAssistantContent = textBlocks.map(b => ({
type: 'text' as const,
text: b.text,
}))