mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-20 23:35:51 +00:00
- Use double assertion (`as unknown as Record<string, unknown>`) at lines 30 and 90 to fix TS2352 per project convention - Tighten URL_REGEX to avoid capturing trailing punctuation (parens, quotes, commas) when URL is embedded in text - Add test case for array-form tool_result content path Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
98 lines
2.8 KiB
TypeScript
98 lines
2.8 KiB
TypeScript
import { basename } from 'path'
|
|
import type { Message } from 'src/types/message.js'
|
|
|
|
export type ArtifactInfo = {
|
|
toolUseId: string
|
|
filePath: string
|
|
basename: string
|
|
hash?: string
|
|
url?: string
|
|
expiresAt?: string
|
|
rawContent: string
|
|
isError: boolean
|
|
}
|
|
|
|
const URL_REGEX = /https?:\/\/[^\s)"',]+\.html\b/
|
|
const ID_REGEX = /\bid:\s*([A-Za-z0-9_-]+)/
|
|
const EXPIRES_REGEX = /\bexpires:\s*([0-9T:.Z+-]+)/
|
|
|
|
export function extractArtifacts(messages: Message[]): ArtifactInfo[] {
|
|
const results: ArtifactInfo[] = []
|
|
|
|
for (const message of messages) {
|
|
if (message.type !== 'assistant') continue
|
|
const content = message.message?.content
|
|
if (!Array.isArray(content)) continue
|
|
|
|
for (const block of content) {
|
|
if (typeof block !== 'object' || block === null) continue
|
|
if (!('type' in block)) continue
|
|
const b = block as unknown as Record<string, unknown>
|
|
if (b.type !== 'tool_use') continue
|
|
if (b.name !== 'artifact') continue
|
|
|
|
const toolUseId = b.id as string
|
|
const input = b.input as { file_path?: string } | undefined
|
|
const filePath = input?.file_path ?? '<unknown>'
|
|
|
|
const resultBlock = findToolResult(messages, toolUseId)
|
|
if (!resultBlock) continue
|
|
|
|
const rawContent =
|
|
typeof resultBlock.content === 'string'
|
|
? resultBlock.content
|
|
: Array.isArray(resultBlock.content)
|
|
? resultBlock.content
|
|
.map(c =>
|
|
typeof c === 'string'
|
|
? c
|
|
: 'text' in c
|
|
? (c as { text: string }).text
|
|
: '',
|
|
)
|
|
.join('')
|
|
: ''
|
|
|
|
const isError = resultBlock.is_error === true
|
|
const urlMatch = rawContent.match(URL_REGEX)
|
|
const idMatch = rawContent.match(ID_REGEX)
|
|
const expiresMatch = rawContent.match(EXPIRES_REGEX)
|
|
|
|
results.push({
|
|
toolUseId,
|
|
filePath,
|
|
basename: basename(filePath),
|
|
hash: idMatch?.[1],
|
|
url: urlMatch?.[0],
|
|
expiresAt: expiresMatch?.[1],
|
|
rawContent,
|
|
isError,
|
|
})
|
|
}
|
|
}
|
|
|
|
// newest first
|
|
return results.reverse()
|
|
}
|
|
|
|
function findToolResult(
|
|
messages: Message[],
|
|
toolUseId: string,
|
|
): { content: unknown; is_error?: boolean } | null {
|
|
for (const message of messages) {
|
|
if (message.type !== 'user') continue
|
|
const content = message.message?.content
|
|
if (!Array.isArray(content)) continue
|
|
|
|
for (const block of content) {
|
|
if (typeof block !== 'object' || block === null) continue
|
|
if (!('type' in block)) continue
|
|
const b = block as unknown as Record<string, unknown>
|
|
if (b.type !== 'tool_result') continue
|
|
if (b.tool_use_id !== toolUseId) continue
|
|
return { content: b.content, is_error: b.is_error as boolean | undefined }
|
|
}
|
|
}
|
|
return null
|
|
}
|