Files
claude-code/packages/image-processor-napi/src/index.ts
claude-code-best e4ce08fe39 Fixture/langfuse record auto mode data error (#308)
* fix: 修复状态栏 context 计数器在 loading 时闪现为 0 的问题

第三方 API(如智谱)在 message_start 中可能不返回完整 usage 数据,
导致 getCurrentUsage 返回全零 usage 对象,使 ctx 显示为 0%。

双重保护:
- getCurrentUsage: 跳过全零 usage,继续往前找有真实数据的 message
- calculateContextPercentages: totalInputTokens 为 0 时返回 null

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 外部化 ESM 包使用 createRequire 替代裸 require

color-diff-napi、image-processor-napi、audio-capture-napi 声明
"type": "module" 但使用裸 require(),Node.js ESM 中 require
不可用。改用 createRequire(import.meta.url) 或顶层 import。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: getDefaultSonnetModel 优先使用用户配置的模型,修复第三方 provider 模型不存在错误

当用户通过 ANTHROPIC_MODEL 或 settings 配置了自定义 provider 支持的模型时,
getDefaultSonnetModel/Haiku/Opus 现在会优先使用该配置,而非硬编码 Anthropic 官方模型 ID。
同时改进 Langfuse 可观测性:sideQuery 失败时记录错误信息到 span,
optional 模式下标记 WARNING 而非 ERROR。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 将 auto_mode classifier 的 side-query span 绑定到父 trace

classifyYoloAction 及 classifyYoloActionXml 接收 parentSpan 参数,
透传给 sideQuery 调用,使 auto_mode 的 side-query span 嵌套在主 agent trace 下。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 穷鬼模式下跳过 memdir_relevance side-query

Poor mode 启用时不执行 findRelevantMemories 的预取调用,
避免额外的 API token 消耗。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: 添加 test:all 脚本用于完成任务后的全量检查

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Vite 构建补齐缺失的 feature flags,修复 auto mode 不可见

Vite 构建插件的 DEFAULT_BUILD_FEATURES 缺少 BUDDY、TRANSCRIPT_CLASSIFIER、
BRIDGE_MODE、ACP、BG_SESSIONS、TEMPLATES,导致 feature('TRANSCRIPT_CLASSIFIER')
被替换为 false,auto mode 从 Shift+Tab 循环中消失。与 build.ts 对齐。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 统一 feature flags 到 defines.ts,修复 Vite 构建缺失 auto mode

将 DEFAULT_BUILD_FEATURES 列表从 build.ts、dev.ts、vite-plugin-feature-flags.ts
三处内联定义统一到 scripts/defines.ts 单一导出。之前的 Vite 插件缺少
TRANSCRIPT_CLASSIFIER 等 feature flag,导致 auto mode 在 Vite 构建中不可见。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 13:30:05 +08:00

125 lines
3.2 KiB
TypeScript

import { readFileSync, unlinkSync } from 'node:fs'
import sharpModule from 'sharp'
export const sharp = sharpModule
interface NativeModule {
hasClipboardImage(): boolean
readClipboardImage(
maxWidth?: number,
maxHeight?: number,
): {
png: Buffer
width: number
height: number
originalWidth: number
originalHeight: number
} | null
}
function createDarwinNativeModule(): NativeModule {
return {
hasClipboardImage(): boolean {
try {
const result = Bun.spawnSync({
cmd: [
'osascript',
'-e',
'try\nthe clipboard as «class PNGf»\nreturn "yes"\non error\nreturn "no"\nend try',
],
stdout: 'pipe',
stderr: 'pipe',
})
const output = result.stdout.toString().trim()
return output === 'yes'
} catch {
return false
}
},
readClipboardImage(
maxWidth?: number,
maxHeight?: number,
) {
try {
// Use osascript to read clipboard image as PNG data and write to a temp file,
// then read the temp file back
const tmpPath = `/tmp/claude_clipboard_native_${Date.now()}.png`
const script = `
set png_data to (the clipboard as «class PNGf»)
set fp to open for access POSIX file "${tmpPath}" with write permission
write png_data to fp
close access fp
return "${tmpPath}"
`
const result = Bun.spawnSync({
cmd: ['osascript', '-e', script],
stdout: 'pipe',
stderr: 'pipe',
})
if (result.exitCode !== 0) {
return null
}
const file = Bun.file(tmpPath)
const buffer: Buffer = readFileSync(tmpPath)
// Clean up temp file
try {
unlinkSync(tmpPath)
} catch {
// ignore cleanup errors
}
if (buffer.length === 0) {
return null
}
// Read PNG dimensions from IHDR chunk
// PNG header: 8 bytes signature, then IHDR chunk
// IHDR starts at offset 8 (4 bytes length) + 4 bytes "IHDR" + 4 bytes width + 4 bytes height
let width = 0
let height = 0
if (buffer.length > 24 && buffer[12] === 0x49 && buffer[13] === 0x48 && buffer[14] === 0x44 && buffer[15] === 0x52) {
width = buffer.readUInt32BE(16)
height = buffer.readUInt32BE(20)
}
const originalWidth = width
const originalHeight = height
// If maxWidth/maxHeight are specified and the image exceeds them,
// we still return the full PNG - the caller handles resizing via sharp
// But we report the capped dimensions
if (maxWidth && maxHeight) {
if (width > maxWidth || height > maxHeight) {
const scale = Math.min(maxWidth / width, maxHeight / height)
width = Math.round(width * scale)
height = Math.round(height * scale)
}
}
return {
png: buffer,
width,
height,
originalWidth,
originalHeight,
}
} catch {
return null
}
},
}
}
export function getNativeModule(): NativeModule | null {
if (process.platform === 'darwin') {
return createDarwinNativeModule()
}
return null
}
export default sharp