Experimental, macOS + Hammerspoon: Cmd+A selects your prompt (painted like a mouse selection), then Delete clears it, Cmd+C copies it, typing replaces it

A Claude Code mod from Encore Mods. Cmd+A on your prompt, like in any text field.
Claude Code's prompt has no selection you can start from the keyboard, and the terminal keeps Cmd+A for itself (it selects the whole screen). With this mod and its Hammerspoon script, in the terminal:
Handy when a dictated prompt went wrong, or to keep a prompt for later.
Experimental: it needs Hammerspoon and only recognises the Orca terminal for now (it looks for xterm.js's input field through macOS accessibility). It goes away once Claude Code gets a keyboard "select all" (anthropics/claude-code#99752).
/plugin marketplace add benjaminb10/encore-mods
/plugin install prompt-select@encore-mods
Then /reload-plugins or restart Claude Code.
hammerspoon/prompt-select.lua to ~/.hammerspoon/, add this line to ~/.hammerspoon/init.lua, and reload Hammerspoon: promptSelect = require("prompt-select") -- global, or the garbage collector stops it
Hammerspoon needs the Accessibility right (System Settings > Privacy & Security > Accessibility).
~/Library/Caches/prompt-select/prompts/<session>.txt whenever it changes. The session whose file changed last is the one you are typing in.on to ~/Library/Caches/prompt-select/select/<session>, and the mod paints the prompt. Delete sends Ctrl+L (Claude Code's chat:clearInput), Cmd+C copies the text from the prompt file.AXManualAccessibility) so it can tell the terminal from Orca's other fields.Your prompt's text (written to the cache folder above, on your Mac only), your prompt box (to paint it). The script reads your keys while Orca's terminal has focus, and the clipboard when you press Cmd+C or Cmd+X. Nothing goes over the network.
hooks/register.js 54 lines1// prompt-select (experimental, macOS + Hammerspoon): Claude Code's prompt has no selection, and a terminal keeps
2// Cmd+A for itself, so this mod works with a Hammerspoon script (hammerspoon/prompt-select.lua) that catches
3// Cmd+A in the terminal. This side does two things:
4// - writes the prompt's text to ~/Library/Caches/prompt-select/prompts/<session>.txt whenever it changes, so the
5// script can copy it (the session whose file changed last is the one being typed in);
6// - watches ~/Library/Caches/prompt-select/select/<session> ("on <n>" / "off <n>") and paints the whole prompt
7// like a mouse selection, or unpaints it.
8
9const PAINT = { backgroundColor: '#3A5F9E', color: 'white' }
10
11// The prompt painted as selected (or not), for prompt.fill's decorations
12export function paint(text, on) {
13 return on && text ? [{ start: 0, end: text.length, ...PAINT }] : []
14}
15
16export function register(on) {
17 on('session.start', async ($, e, next) => {
18 try {
19 const home = await $.env.get('HOME')
20 const id = await $.session.id()
21 const base = home + '/Library/Caches/prompt-select'
22 const file = base + '/prompts/' + id + '.txt'
23 const signal = base + '/select/' + id
24 let written = null
25 let seen = null
26 $.clock.every(400, async () => {
27 try {
28 const box = await $.prompt.read()
29 const text = box.text || ''
30 if (text === written) return
31 written = text
32 await $.fs.write(file, text)
33 } catch {}
34 })
35 $.clock.every(120, async () => {
36 try {
37 if (!(await $.fs.exists(signal))) return
38 const v = String(await $.fs.read(signal)).trim()
39 if (v === seen) return
40 const first = seen === null
41 seen = v
42 // A signal left from before this session started is not a new Cmd+A
43 if (first) return
44 const box = await $.prompt.read()
45 const text = box.text || ''
46 if (!text) return
47 await $.prompt.fill({ text, mode: 'replace', decorations: paint(text, v.startsWith('on')) })
48 } catch {}
49 })
50 } catch {}
51 return next(e)
52 })
53}
54