feat: 完成第二版类型清理

This commit is contained in:
claude-code-best
2026-03-31 23:03:47 +08:00
parent 4c0a655a1c
commit d7a729ca68
604 changed files with 595 additions and 953 deletions

View File

@@ -288,8 +288,8 @@ async function countSystemTokens(
)
.map(content => ({ name: extractSectionName(content), content })),
...Object.entries(systemContext)
.filter(([, content]) => content.length > 0)
.map(([name, content]) => ({ name, content })),
.filter(([, content]) => (content as string).length > 0)
.map(([name, content]) => ({ name, content: content as string })),
]
if (namedEntries.length < 1) {
@@ -445,9 +445,10 @@ async function countBuiltInToolTokens(
if (messages) {
const deferredToolNameSet = new Set(deferredBuiltinTools.map(t => t.name))
for (const msg of messages) {
if (msg.type === 'assistant') {
if (msg.type === 'assistant' && Array.isArray(msg.message.content)) {
for (const block of msg.message.content) {
if (
typeof block !== 'string' &&
'type' in block &&
block.type === 'tool_use' &&
'name' in block &&
@@ -682,9 +683,10 @@ export async function countMcpToolTokens(
if (isDeferred && messages) {
const mcpToolNameSet = new Set(mcpTools.map(t => t.name))
for (const msg of messages) {
if (msg.type === 'assistant') {
if (msg.type === 'assistant' && Array.isArray(msg.message.content)) {
for (const block of msg.message.content) {
if (
typeof block !== 'string' &&
'type' in block &&
block.type === 'tool_use' &&
'name' in block &&
@@ -784,11 +786,12 @@ function processAssistantMessage(
breakdown: MessageBreakdown,
): void {
// Process each content block individually
for (const block of msg.message.content) {
const contentBlocks = Array.isArray(msg.message.content) ? msg.message.content : []
for (const block of contentBlocks) {
const blockStr = jsonStringify(block)
const blockTokens = roughTokenCountEstimation(blockStr)
if ('type' in block && block.type === 'tool_use') {
if (typeof block !== 'string' && 'type' in block && block.type === 'tool_use') {
breakdown.toolCallTokens += blockTokens
const toolName = ('name' in block ? block.name : undefined) || 'unknown'
breakdown.toolCallsByType.set(
@@ -871,12 +874,12 @@ async function approximateMessageTokens(
// Build a map of tool_use_id to tool_name for easier lookup
const toolUseIdToName = new Map<string, string>()
for (const msg of microcompactResult.messages) {
if (msg.type === 'assistant') {
if (msg.type === 'assistant' && Array.isArray(msg.message.content)) {
for (const block of msg.message.content) {
if ('type' in block && block.type === 'tool_use') {
const toolUseId = 'id' in block ? block.id : undefined
if (typeof block !== 'string' && 'type' in block && block.type === 'tool_use') {
const toolUseId = 'id' in block ? (block.id as string) : undefined
const toolName =
('name' in block ? block.name : undefined) || 'unknown'
(('name' in block ? block.name : undefined) as string | undefined) || 'unknown'
if (toolUseId) {
toolUseIdToName.set(toolUseId, toolName)
}
@@ -888,11 +891,11 @@ async function approximateMessageTokens(
// Process each message for detailed breakdown
for (const msg of microcompactResult.messages) {
if (msg.type === 'assistant') {
processAssistantMessage(msg, breakdown)
processAssistantMessage(msg as AssistantMessage, breakdown)
} else if (msg.type === 'user') {
processUserMessage(msg, breakdown, toolUseIdToName)
processUserMessage(msg as UserMessage, breakdown, toolUseIdToName)
} else if (msg.type === 'attachment') {
processAttachment(msg, breakdown)
processAttachment(msg as AttachmentMessage, breakdown)
}
}
@@ -902,12 +905,12 @@ async function approximateMessageTokens(
if (_.type === 'assistant') {
return {
// Important: strip out fields like id, etc. -- the counting API errors if they're present
role: 'assistant',
role: 'assistant' as const,
content: _.message.content,
}
}
return _.message
}),
}) as Anthropic.Beta.Messages.BetaMessageParam[],
[],
)

View File

@@ -995,11 +995,11 @@ export async function getAttachments(
clearTimeout(timeoutId)
// Defensive: a getter leaking [undefined] crashes .map(a => a.type) below.
return [
return ([
...userAttachmentResults.flat(),
...threadAttachmentResults.flat(),
...mainThreadAttachmentResults.flat(),
].filter(a => a !== undefined && a !== null)
] as Attachment[]).filter(a => a !== undefined && a !== null)
}
async function maybe<A>(label: string, f: () => Promise<A[]>): Promise<A[]> {
@@ -1095,7 +1095,7 @@ export function getAgentPendingMessageAttachments(
return drained.map(msg => ({
type: 'queued_command' as const,
prompt: msg,
origin: { kind: 'coordinator' as const },
origin: { kind: 'coordinator' as const } as unknown as MessageOrigin,
isMeta: true,
}))
}
@@ -1525,8 +1525,8 @@ export function getAgentListingDeltaAttachment(
for (const msg of messages ?? []) {
if (msg.type !== 'attachment') continue
if (msg.attachment.type !== 'agent_listing_delta') continue
for (const t of msg.attachment.addedTypes) announced.add(t)
for (const t of msg.attachment.removedTypes) announced.delete(t)
for (const t of msg.attachment.addedTypes as string[]) announced.add(t)
for (const t of msg.attachment.removedTypes as string[]) announced.delete(t)
}
const currentTypes = new Set(filtered.map(a => a.agentType))
@@ -2256,7 +2256,7 @@ export function collectSurfacedMemories(messages: ReadonlyArray<Message>): {
let totalBytes = 0
for (const m of messages) {
if (m.type === 'attachment' && m.attachment.type === 'relevant_memories') {
for (const mem of m.attachment.memories) {
for (const mem of m.attachment.memories as { path: string; content: string; mtimeMs: number }[]) {
paths.add(mem.path)
totalBytes += mem.content.length
}
@@ -2776,7 +2776,7 @@ export function extractAtMentionedFiles(content: string): string[] {
}
// Extract regular mentions
const regularMatchArray = content.match(regularAtMentionRegex) || []
const regularMatchArray: string[] = content.match(regularAtMentionRegex) ?? []
regularMatchArray.forEach(match => {
const filename = match.slice(match.indexOf('@') + 1)
// Don't include if it starts with a quote (already handled as quoted)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -15,16 +15,16 @@ function isCompletedBackgroundBash(
msg: RenderableMessage,
): msg is NormalizedUserMessage {
if (msg.type !== 'user') return false
const content = msg.message.content[0]
if (content?.type !== 'text') return false
if (!content.text.includes(`<${TASK_NOTIFICATION_TAG}`)) return false
const content0 = Array.isArray(msg.message.content) ? msg.message.content[0] : undefined
if (!content0 || typeof content0 === 'string' || content0?.type !== 'text') return false
if (!content0.text.includes(`<${TASK_NOTIFICATION_TAG}`)) return false
// Only collapse successful completions — failed/killed stay visible individually.
if (extractTag(content.text, STATUS_TAG) !== 'completed') return false
if (extractTag(content0.text, STATUS_TAG) !== 'completed') return false
// The prefix constant distinguishes bash-kind LocalShellTask completions from
// agent/workflow/monitor notifications. Monitor-kind completions have their
// own summary wording and deliberately don't collapse here.
return (
extractTag(content.text, SUMMARY_TAG)?.startsWith(
extractTag(content0.text, SUMMARY_TAG)?.startsWith(
BACKGROUND_BASH_SUMMARY_PREFIX,
) ?? false
)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -93,7 +93,7 @@ function migrateLegacyAttachmentTypes(message: Message): Message {
type: 'file',
displayPath: relative(getCwd(), attachment.filename as string),
},
} as SerializedMessage // Cast entire message since we know the structure is correct
} as unknown as SerializedMessage // Cast entire message since we know the structure is correct
}
if (attachment.type === 'new_directory') {
@@ -104,7 +104,7 @@ function migrateLegacyAttachmentTypes(message: Message): Message {
type: 'directory',
displayPath: relative(getCwd(), attachment.path as string),
},
} as SerializedMessage // Cast entire message since we know the structure is correct
} as unknown as SerializedMessage // Cast entire message since we know the structure is correct
}
// Backfill displayPath for attachments from old sessions
@@ -177,7 +177,7 @@ export function deserializeMessagesWithInterruptDetection(
if (
msg.type === 'user' &&
msg.permissionMode !== undefined &&
!validModes.has(msg.permissionMode)
!validModes.has(msg.permissionMode as string)
) {
msg.permissionMode = undefined
}
@@ -320,7 +320,7 @@ function detectTurnInterruption(
return { kind: 'interrupted_turn' }
}
// Plain text user prompt — CC hadn't started responding
return { kind: 'interrupted_prompt', message: lastMessage }
return { kind: 'interrupted_prompt', message: lastMessage as NormalizedUserMessage }
}
if (lastMessage.type === 'attachment') {
@@ -359,12 +359,14 @@ function isTerminalToolResult(
for (let i = resultIdx - 1; i >= 0; i--) {
const msg = messages[i]!
if (msg.type !== 'assistant') continue
for (const b of msg.message.content) {
if (b.type === 'tool_use' && b.id === toolUseId) {
const msgContent = msg.message.content
if (!Array.isArray(msgContent)) continue
for (const b of msgContent) {
if (typeof b !== 'string' && 'type' in b && b.type === 'tool_use' && 'id' in b && b.id === toolUseId) {
return (
b.name === BRIEF_TOOL_NAME ||
b.name === LEGACY_BRIEF_TOOL_NAME ||
b.name === SEND_USER_FILE_TOOL_NAME
('name' in b ? b.name : undefined) === BRIEF_TOOL_NAME ||
('name' in b ? b.name : undefined) === LEGACY_BRIEF_TOOL_NAME ||
('name' in b ? b.name : undefined) === SEND_USER_FILE_TOOL_NAME
)
}
}
@@ -385,7 +387,8 @@ export function restoreSkillStateFromMessages(messages: Message[]): void {
continue
}
if (message.attachment.type === 'invoked_skills') {
for (const skill of message.attachment.skills) {
const skills = message.attachment.skills as Array<{ name?: string; path?: string; content?: string }>;
for (const skill of skills) {
if (skill.name && skill.path && skill.content) {
// Resume only happens for the main session, so agentId is null
addInvokedSkill(skill.name, skill.path, skill.content, null)

File diff suppressed because one or more lines are too long

View File

@@ -242,7 +242,7 @@ export function extractResultText(
if (!lastAssistantMessage) return defaultText
const textContent = extractTextContent(
lastAssistantMessage.message.content,
Array.isArray(lastAssistantMessage.message.content) ? lastAssistantMessage.message.content : [],
'\n',
)

View File

@@ -1,5 +1,5 @@
import type { BetaToolUseBlock } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/messages/messages.mjs'
import type { ContentBlockParam, ToolResultBlockParam } from '@anthropic-ai/sdk/resources/messages/messages.mjs'
import type { Tools } from '../Tool.js'
import type {
GroupedToolUseMessage,
@@ -34,10 +34,10 @@ function getToolsWithGrouping(tools: Tools): Set<string> {
function getToolUseInfo(
msg: MessageWithoutProgress,
): { messageId: string; toolUseId: string; toolName: string } | null {
if (msg.type === 'assistant' && msg.message.content[0]?.type === 'tool_use') {
const content = msg.message.content[0]
if (msg.type === 'assistant' && msg.message?.content && Array.isArray(msg.message.content) && (msg.message.content[0] as { type?: string })?.type === 'tool_use') {
const content = msg.message.content[0] as unknown as { type: 'tool_use'; id: string; name: string; [key: string]: unknown }
return {
messageId: msg.message.id,
messageId: msg.message.id as string,
toolUseId: content.id,
toolName: content.name,
}
@@ -59,7 +59,7 @@ export function applyGrouping(
// In verbose mode, don't group - each message renders at its original position
if (verbose) {
return {
messages: messages,
messages: messages as RenderableMessage[],
}
}
const toolsWithGrouping = getToolsWithGrouping(tools)
@@ -104,13 +104,13 @@ export function applyGrouping(
const resultsByToolUseId = new Map<string, NormalizedUserMessage>()
for (const msg of messages) {
if (msg.type === 'user') {
if (msg.type === 'user' && msg.message?.content && Array.isArray(msg.message.content)) {
for (const content of msg.message.content) {
if (
content.type === 'tool_result' &&
groupedToolUseIds.has(content.tool_use_id)
(content as { type?: string }).type === 'tool_result' &&
groupedToolUseIds.has((content as { tool_use_id: string }).tool_use_id)
) {
resultsByToolUseId.set(content.tool_use_id, msg)
resultsByToolUseId.set((content as { tool_use_id: string }).tool_use_id, msg as NormalizedUserMessage)
}
}
}
@@ -161,8 +161,8 @@ export function applyGrouping(
}
// Skip user messages whose tool_results are all grouped
if (msg.type === 'user') {
const toolResults = msg.message.content.filter(
if (msg.type === 'user' && msg.message?.content && Array.isArray(msg.message.content)) {
const toolResults = (msg.message.content as Array<ContentBlockParam>).filter(
(c): c is ToolResultBlockParam => c.type === 'tool_result',
)
if (toolResults.length > 0) {
@@ -175,7 +175,7 @@ export function applyGrouping(
}
}
result.push(msg)
result.push(msg as RenderableMessage)
}
return { messages: result }

View File

@@ -25,4 +25,3 @@ export function highlightMatch(text: string, query: string): React.ReactNode {
if (offset < text.length) parts.push(text.slice(offset));
return <>{parts}</>;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIlRleHQiLCJoaWdobGlnaHRNYXRjaCIsInRleHQiLCJxdWVyeSIsIlJlYWN0Tm9kZSIsInF1ZXJ5TG93ZXIiLCJ0b0xvd2VyQ2FzZSIsInRleHRMb3dlciIsInBhcnRzIiwib2Zmc2V0IiwiaWR4IiwiaW5kZXhPZiIsInB1c2giLCJzbGljZSIsImxlbmd0aCJdLCJzb3VyY2VzIjpbImhpZ2hsaWdodE1hdGNoLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IFRleHQgfSBmcm9tICcuLi9pbmsuanMnXG5cbi8qKlxuICogSW52ZXJzZS1oaWdobGlnaHQgZXZlcnkgb2NjdXJyZW5jZSBvZiBgcXVlcnlgIGluIGB0ZXh0YCAoY2FzZS1pbnNlbnNpdGl2ZSkuXG4gKiBVc2VkIGJ5IHNlYXJjaCBkaWFsb2dzIHRvIHNob3cgd2hlcmUgdGhlIHF1ZXJ5IG1hdGNoZWQgaW4gcmVzdWx0IHJvd3NcbiAqIGFuZCBwcmV2aWV3IHBhbmVzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaGlnaGxpZ2h0TWF0Y2godGV4dDogc3RyaW5nLCBxdWVyeTogc3RyaW5nKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgaWYgKCFxdWVyeSkgcmV0dXJuIHRleHRcbiAgY29uc3QgcXVlcnlMb3dlciA9IHF1ZXJ5LnRvTG93ZXJDYXNlKClcbiAgY29uc3QgdGV4dExvd2VyID0gdGV4dC50b0xvd2VyQ2FzZSgpXG4gIGNvbnN0IHBhcnRzOiBSZWFjdC5SZWFjdE5vZGVbXSA9IFtdXG4gIGxldCBvZmZzZXQgPSAwXG4gIGxldCBpZHggPSB0ZXh0TG93ZXIuaW5kZXhPZihxdWVyeUxvd2VyLCBvZmZzZXQpXG4gIGlmIChpZHggPT09IC0xKSByZXR1cm4gdGV4dFxuICB3aGlsZSAoaWR4ICE9PSAtMSkge1xuICAgIGlmIChpZHggPiBvZmZzZXQpIHBhcnRzLnB1c2godGV4dC5zbGljZShvZmZzZXQsIGlkeCkpXG4gICAgcGFydHMucHVzaChcbiAgICAgIDxUZXh0IGtleT17aWR4fSBpbnZlcnNlPlxuICAgICAgICB7dGV4dC5zbGljZShpZHgsIGlkeCArIHF1ZXJ5Lmxlbmd0aCl9XG4gICAgICA8L1RleHQ+LFxuICAgIClcbiAgICBvZmZzZXQgPSBpZHggKyBxdWVyeS5sZW5ndGhcbiAgICBpZHggPSB0ZXh0TG93ZXIuaW5kZXhPZihxdWVyeUxvd2VyLCBvZmZzZXQpXG4gIH1cbiAgaWYgKG9mZnNldCA8IHRleHQubGVuZ3RoKSBwYXJ0cy5wdXNoKHRleHQuc2xpY2Uob2Zmc2V0KSlcbiAgcmV0dXJuIDw+e3BhcnRzfTwvPlxufVxuIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUtBLEtBQUssTUFBTSxPQUFPO0FBQzlCLFNBQVNDLElBQUksUUFBUSxXQUFXOztBQUVoQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTyxTQUFTQyxjQUFjQSxDQUFDQyxJQUFJLEVBQUUsTUFBTSxFQUFFQyxLQUFLLEVBQUUsTUFBTSxDQUFDLEVBQUVKLEtBQUssQ0FBQ0ssU0FBUyxDQUFDO0VBQzNFLElBQUksQ0FBQ0QsS0FBSyxFQUFFLE9BQU9ELElBQUk7RUFDdkIsTUFBTUcsVUFBVSxHQUFHRixLQUFLLENBQUNHLFdBQVcsQ0FBQyxDQUFDO0VBQ3RDLE1BQU1DLFNBQVMsR0FBR0wsSUFBSSxDQUFDSSxXQUFXLENBQUMsQ0FBQztFQUNwQyxNQUFNRSxLQUFLLEVBQUVULEtBQUssQ0FBQ0ssU0FBUyxFQUFFLEdBQUcsRUFBRTtFQUNuQyxJQUFJSyxNQUFNLEdBQUcsQ0FBQztFQUNkLElBQUlDLEdBQUcsR0FBR0gsU0FBUyxDQUFDSSxPQUFPLENBQUNOLFVBQVUsRUFBRUksTUFBTSxDQUFDO0VBQy9DLElBQUlDLEdBQUcsS0FBSyxDQUFDLENBQUMsRUFBRSxPQUFPUixJQUFJO0VBQzNCLE9BQU9RLEdBQUcsS0FBSyxDQUFDLENBQUMsRUFBRTtJQUNqQixJQUFJQSxHQUFHLEdBQUdELE1BQU0sRUFBRUQsS0FBSyxDQUFDSSxJQUFJLENBQUNWLElBQUksQ0FBQ1csS0FBSyxDQUFDSixNQUFNLEVBQUVDLEdBQUcsQ0FBQyxDQUFDO0lBQ3JERixLQUFLLENBQUNJLElBQUksQ0FDUixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQ0YsR0FBRyxDQUFDLENBQUMsT0FBTztBQUM3QixRQUFRLENBQUNSLElBQUksQ0FBQ1csS0FBSyxDQUFDSCxHQUFHLEVBQUVBLEdBQUcsR0FBR1AsS0FBSyxDQUFDVyxNQUFNLENBQUM7QUFDNUMsTUFBTSxFQUFFLElBQUksQ0FDUixDQUFDO0lBQ0RMLE1BQU0sR0FBR0MsR0FBRyxHQUFHUCxLQUFLLENBQUNXLE1BQU07SUFDM0JKLEdBQUcsR0FBR0gsU0FBUyxDQUFDSSxPQUFPLENBQUNOLFVBQVUsRUFBRUksTUFBTSxDQUFDO0VBQzdDO0VBQ0EsSUFBSUEsTUFBTSxHQUFHUCxJQUFJLENBQUNZLE1BQU0sRUFBRU4sS0FBSyxDQUFDSSxJQUFJLENBQUNWLElBQUksQ0FBQ1csS0FBSyxDQUFDSixNQUFNLENBQUMsQ0FBQztFQUN4RCxPQUFPLEVBQUUsQ0FBQ0QsS0FBSyxDQUFDLEdBQUc7QUFDckIiLCJpZ25vcmVMaXN0IjpbXX0=

View File

@@ -108,7 +108,7 @@ export function createApiQueryHook<TResult>(
})
// Parse response
const content = extractTextContent(response.message.content).trim()
const content = extractTextContent(Array.isArray(response.message.content) ? response.message.content : []).trim()
try {
const result = config.parseResponse(content, context)

View File

@@ -102,7 +102,7 @@ Your response must be a JSON object matching one of the following schemas:
cleanupSignal()
// Extract text content from response
const content = extractTextContent(response.message.content)
const content = extractTextContent(Array.isArray(response.message.content) ? response.message.content : [])
// Update response length for spinner display
toolUseContext.setResponseLength(length => length + content.length)

View File

@@ -249,7 +249,7 @@ Rules:
},
})
const responseText = extractTextContent(response.message.content).trim()
const responseText = extractTextContent(Array.isArray(response.message.content) ? response.message.content : []).trim()
const updatedContent = extractTag(responseText, 'updated_file')
if (!updatedContent) {

View File

@@ -80,7 +80,7 @@ Parse the user's input into ISO 8601 format. Return ONLY the formatted string, o
})
// Extract text from result
const parsedText = extractTextContent(result.message.content).trim()
const parsedText = extractTextContent(Array.isArray(result.message.content) ? result.message.content : []).trim()
// Validate that we got something usable
if (!parsedText || parsedText === 'INVALID') {

View File

@@ -113,7 +113,7 @@ function extractConversationContext(
for (const msg of assistantMessages.reverse()) {
// Extract text content from assistant message
const textBlocks = msg.message.content
const textBlocks = (Array.isArray(msg.message.content) ? msg.message.content : [])
.filter(c => c.type === 'text')
.map(c => ('text' in c ? c.text : ''))
.join(' ')

View File

@@ -343,7 +343,7 @@ export function buildTranscriptEntries(messages: Message[]): TranscriptEntry[] {
for (const block of msg.message.content) {
// Only include tool_use blocks — assistant text is model-authored
// and could be crafted to influence the classifier's decision.
if (block.type === 'tool_use') {
if (typeof block !== 'string' && block.type === 'tool_use') {
blocks.push({
type: 'tool_use',
name: block.name,

File diff suppressed because one or more lines are too long

View File

@@ -408,7 +408,7 @@ export async function installResolvedPlugin({
allowedCrossMarketplaces,
)
if (!resolution.ok) {
return { ok: false, reason: 'resolution-failed', resolution }
return { ok: false, reason: 'resolution-failed', resolution: resolution as ResolutionResult & { ok: false } }
}
// ── Policy guard for transitive dependencies ──
@@ -525,31 +525,32 @@ export async function installPluginFromMarketplace({
})
if (!result.ok) {
switch (result.reason) {
const failedResult = result as Exclude<InstallCoreResult, { ok: true }>
switch (failedResult.reason) {
case 'local-source-no-location':
return {
success: false,
error: `Cannot install local plugin "${result.pluginName}" without marketplace install location`,
error: `Cannot install local plugin "${failedResult.pluginName}" without marketplace install location`,
}
case 'settings-write-failed':
return {
success: false,
error: `Failed to update settings: ${result.message}`,
error: `Failed to update settings: ${failedResult.message}`,
}
case 'resolution-failed':
return {
success: false,
error: formatResolutionError(result.resolution),
error: formatResolutionError(failedResult.resolution),
}
case 'blocked-by-policy':
return {
success: false,
error: `Plugin "${result.pluginName}" is blocked by your organization's policy and cannot be installed`,
error: `Plugin "${failedResult.pluginName}" is blocked by your organization's policy and cannot be installed`,
}
case 'dependency-blocked-by-policy':
return {
success: false,
error: `Cannot install "${result.pluginName}": dependency "${result.blockedDependency}" is blocked by your organization's policy`,
error: `Cannot install "${failedResult.pluginName}": dependency "${failedResult.blockedDependency}" is blocked by your organization's policy`,
}
}
}
@@ -585,7 +586,7 @@ export async function installPluginFromMarketplace({
return {
success: true,
message: `✓ Installed ${entry.name}${result.depNote}. Run /reload-plugins to activate.`,
message: `✓ Installed ${entry.name}${(result as Extract<InstallCoreResult, { ok: true }>).depNote}. Run /reload-plugins to activate.`,
}
} catch (err) {
const errorMessage = err instanceof Error ? err.message : String(err)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -307,8 +307,8 @@ async function processSessionFiles(
// Track model usage if available (skip synthetic messages)
if (message.message?.usage) {
const usage = message.message.usage
const model = message.message.model || 'unknown'
const usage = message.message.usage as Record<string, number>
const model = (message.message.model as string) || 'unknown'
// Skip synthetic messages - they are internal and shouldn't appear in stats
if (model === SYNTHETIC_MODEL) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1235,8 +1235,8 @@ export async function runInProcessTeammate(
// Track in-progress tool use IDs for animation in transcript view
let inProgressToolUseIDs = task.inProgressToolUseIDs
if (message.type === 'assistant') {
for (const block of message.message.content) {
if (block.type === 'tool_use') {
for (const block of (Array.isArray(message.message.content) ? message.message.content : [])) {
if (typeof block !== 'string' && block.type === 'tool_use') {
inProgressToolUseIDs = new Set([
...(inProgressToolUseIDs ?? []),
block.id,

File diff suppressed because one or more lines are too long