Paste an image from the Windows clipboard (Win+V history) into the chat without Alt+V.

ชุด mod สำหรับ Claude Code บน Windows
| Mod | ทำอะไร |
|---|---|
statusline/statusline.js | Status bar 2 บรรทัด: ชื่อโปรเจค, git branch, แถบ context (ไล่สีเขียว→แดง), จำนวน token, ชื่อโมเดล และแถบเรทลิมิต Session (5 ชม.) / Week พร้อมเวลารีเซ็ต (ภาษาไทย) |
mods/clipboard-image-paste | วางรูปจาก Win+V ลงแชทได้ทันทีโดยไม่ต้องกด Alt+V และมีคำสั่ง /pasteimg ให้วางรูปจาก clipboard ซ้ำ |
mods/done-and-ask-sounds | มีเสียงเตือนตอน Claude ตอบเสร็จ และตอนถามคำถามหรือขอ permission (เงียบถ้ากำลังดูหน้าต่าง terminal อยู่) |
mods/codex-imagegen | เพิ่ม tool generate_image ให้ Claude สั่งสร้างรูปผ่าน Codex CLI (ChatGPT) ในเครื่อง (ไม่บังคับ) |
bypass/claude.cmd | พิมพ์ claude --bypass ได้เลย (แปลงเป็น --dangerously-skip-permissions) ใช้ได้ทั้งใน cmd, PowerShell และช่อง address bar ของ File Explorer |
%USERPROFILE%\.local\bin\claude.exe)codex-imagegengit clone https://github.com/bngxyz/claude-mods.git
cd claude-mods
powershell -ExecutionPolicy Bypass -File install.ps1
ถ้าจะใช้ codex-imagegen ด้วย ให้ใส่ path ของ codex.exe:
powershell -ExecutionPolicy Bypass -File install.ps1 -CodexPath "C:\Users\<you>\AppData\Local\Programs\OpenAI\Codex\bin\codex.exe"
เสร็จแล้วให้ ปิดแล้วเปิด Claude Code ใหม่ และ sign out/in หรือ restart Explorer (Task Manager → Windows Explorer → Restart) เพื่อให้ PATH ใหม่มีผล
statusline.js ไปที่ %USERPROFILE%\.claude\%USERPROFILE%\.claude\mods\%USERPROFILE%\.claude\settings.json (สำรองไฟล์เดิมเป็น settings.json.bak ก่อน)statusLine → node "<...>\statusline.js"env.CLAUDE_CODE_PLUGIN_DIRS → เพิ่ม path ของแต่ละ mod (คั่นด้วย ;)pluginConfigs.codex-imagegen.options.codexPath (เฉพาะตอนใส่ -CodexPath)claude.cmd ไปที่ %USERPROFILE%\.local\claude-wrap\ แล้วใส่โฟลเดอร์นี้ไว้หน้าสุดของ user PATHHKCU\Software\Microsoft\Windows\CurrentVersion\App Paths\claude.exe ชี้ไปที่ claude.cmd เพื่อให้ address bar ของ Explorer และ Win+R เรียกผ่าน wrapperclaude # เปิดปกติ
claude --bypass # เปิดแบบข้าม permission ทั้งหมด
ในช่อง address bar ของ File Explorer พิมพ์ claude --bypass แล้วกด Enter จะเปิด Claude Code ในโฟลเดอร์นั้นเลย
ถ้าไม่อยากเห็นหน้าต่างเตือนทุกครั้งที่เปิดแบบ bypass ให้เพิ่มใน settings.json:
{
"skipDangerousModePermissionPrompt": true
}
Remove-Item "$env:USERPROFILE\.claude\statusline.js"
Remove-Item -Recurse "$env:USERPROFILE\.claude\mods\clipboard-image-paste", "$env:USERPROFILE\.claude\mods\done-and-ask-sounds", "$env:USERPROFILE\.claude\mods\codex-imagegen"
Remove-Item -Recurse "$env:USERPROFILE\.local\claude-wrap"
Remove-Item "HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\claude.exe"
จากนั้นลบ statusLine, env.CLAUDE_CODE_PLUGIN_DIRS และ pluginConfigs.codex-imagegen ออกจาก settings.json และลบ %USERPROFILE%\.local\claude-wrap ออกจาก user PATH (Settings → System → About → Advanced system settings → Environment Variables)
hooks/register.ts 83 lines1import type { Hook, Register } from 'claude-code'
2
3type Engine = Parameters<Hook<'prompt.edit'>>[0]
4
5const PLUGIN = 'clipboard-image-paste'
6
7// One PowerShell for the session's life, started with everything loaded, so a
8// paste costs a file write instead of a process start. It waits for the
9// trigger file, and when the clipboard holds an image it has not pasted yet it
10// presses Alt+V, Claude Code's own image paste, once the prompt edit that
11// raised the trigger has finished. `force` (the /pasteimg command) pastes the
12// image again even if it was pasted already.
13const WATCHER_SCRIPT = `
14$ErrorActionPreference = 'Stop'
15Add-Type -AssemblyName System.Windows.Forms
16Add-Type -Namespace Win -Name Clip -MemberDefinition '[System.Runtime.InteropServices.DllImport("user32.dll")] public static extern uint GetClipboardSequenceNumber();'
17$trigger = $env:CLIP_TRIGGER
18$last = ''
19Write-Output 'ready'
20while ($true) {
21 if (Test-Path -LiteralPath $trigger) {
22 $mode = ''
23 try { $mode = (Get-Content -LiteralPath $trigger -Raw).Trim() } catch { Start-Sleep -Milliseconds 10; continue }
24 Remove-Item -LiteralPath $trigger -Force
25 $seq = [string][Win.Clip]::GetClipboardSequenceNumber()
26 if ([System.Windows.Forms.Clipboard]::ContainsImage() -and ($mode -eq 'force' -or $seq -ne $last)) {
27 $last = $seq
28 Start-Sleep -Milliseconds 50
29 [System.Windows.Forms.SendKeys]::SendWait('%v')
30 } elseif ($mode -eq 'force') {
31 Write-Output 'no-image'
32 }
33 }
34 Start-Sleep -Milliseconds 20
35}
36`
37
38function triggerPath($: Engine): string {
39 return `${$.plugin.root}/.paste-trigger`
40}
41
42export const register: Register = on => {
43 on('session.start', async ($, e, next) => {
44 await $.command.register({
45 name: 'pasteimg',
46 description: 'Paste the image on the clipboard as an attachment',
47 })
48
49 const started = await next(e)
50
51 void (async () => {
52 const watcher = $.process.spawn({
53 argv: ['powershell.exe', '-NoProfile', '-NonInteractive', '-STA', '-Command', WATCHER_SCRIPT],
54 env: { CLIP_TRIGGER: triggerPath($) },
55 })
56
57 for await (const { stream, text } of watcher) {
58 if (stream === 'stderr') $.ui.toast(`${PLUGIN}: ${text.trim()}`)
59 else if (text.includes('no-image')) $.ui.toast('There is no image on the clipboard.')
60 }
61
62 $.ui.toast(`${PLUGIN}: the clipboard watcher stopped`)
63 })()
64
65 return started
66 })
67
68 // A Win+V paste of an image-only clipboard reaches the editor as an empty
69 // paste: no key, nothing inserted, nothing replaced.
70 on('prompt.edit', async ($, e, next) => {
71 const isEmptyPaste = e.key === undefined && e.inputText === '' && e.start === e.end
72 if (isEmptyPaste) await $.fs.write(triggerPath($), 'auto')
73
74 return next(e)
75 })
76
77 on('command.run', { command: 'pasteimg' }, async $ => {
78 await $.fs.write(triggerPath($), 'force')
79
80 return { text: 'Pasting the clipboard image.' }
81 })
82}
83