✨ feat(vscode): 问 AI 输入框能粘贴、拖进图片随问题发给 Claude Code,缩略图能点开看大图,图片存进 .spx/code-qa 跟着问答删

This commit is contained in:
cruldra committed 2026-09-26 23:15:02 +08:00
1 parent d9a5c3673e
commit 36d842e18e
28 files changed
+825 -121

No files matched your search

+10
View File
@@ -29,6 +29,16 @@ describe('跑 claude、逐行交出 stdout', () => {
expect(lines).toEqual(['{"a":1}', '{"b":2}', await fsp.realpath(dir), '-p|带 空格 的问题|'])
})
it('给了 input 就写进 stdin 再关上(stream-json 的消息);不给时 stdin 是空的,读 stdin 的也不会卡住', async () => {
const bin = await fakeBin('cat; echo end')
const withInput: string[] = []
await runClaudeLines({ bin, args: [], cwd: dir, input: '{"type":"user"}\n', onLine: item => withInput.push(item) })
expect(withInput).toEqual(['{"type":"user"}', 'end'])
const without: string[] = []
await runClaudeLines({ bin, args: [], cwd: dir, timeoutMs: 2000, onLine: item => without.push(item) })
expect(without).toEqual(['end'])
})
it('退出码非零:带上 stderr 的原话', async () => {
const bin = await fakeBin('echo "No conversation found with session ID: x" >&2; exit 1')
const error = await runClaudeLines({ bin, args: [], cwd: dir, onLine: () => {} }).catch((err: unknown) => err)
+8 -2
View File
@@ -222,7 +222,8 @@ function createProgressFeeder(onProgress?: ClaudeProgressListener): (chunk: stri
}).feed
}
function buildStreamJsonLine(prompt: string, images: ClaudeImage[]): string {
/** `--input-format stream-json` 的一条用户消息(一行 NDJSON):先是文字,后面跟着各张图片。 */
export function buildStreamJsonLine(prompt: string, images: readonly ClaudeImage[]): string {
const content: Array<Record<string, unknown>> = [
{ type: 'text', text: prompt },
]
@@ -566,6 +567,8 @@ function spawnClaudeStreamed(
export function runClaudeLines(opts: {
args: string[]
cwd: string
/** 写进 stdin 后关上(`--input-format stream-json` 的消息,见 buildStreamJsonLine);不给时 stdin 是空的 */
input?: string
onLine: (line: string) => void
timeoutMs?: number
signal?: AbortSignal
@@ -589,8 +592,11 @@ export function runClaudeLines(opts: {
const child = spawn(bin, opts.args, {
cwd: opts.cwd,
env: buildClaudeChildEnv(bin),
stdio: ['ignore', 'pipe', 'pipe'],
stdio: ['pipe', 'pipe', 'pipe'],
})
// 进程先退了(参数不对)时写不进去:真正的原因由退出码和 stderr 报
child.stdin.on('error', () => {})
child.stdin.end(opts.input ?? '')
const timer = setTimeout(() => {
child.kill('SIGKILL')