SLOPSHOPPER

Prompt select (experimental)

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

newtimer
★ 1v0.1.0MITupdated 2026-10-24benjaminb10/encore-mods/plugins/prompt-select
A shopper browsing a rack in a slop shop
README

Prompt select (experimental: macOS + Hammerspoon)

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:

  • Cmd+A paints the whole prompt like a mouse selection.
  • then Delete clears it, Cmd+C copies it (the selection stays), Cmd+X copies and clears it, and a letter replaces it.
  • Escape or an arrow key cancels. Elsewhere in the app, Cmd+A works as before.

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).

Install

  1. The mod:
   /plugin marketplace add benjaminb10/encore-mods
   /plugin install prompt-select@encore-mods

Then /reload-plugins or restart Claude Code.

  1. The Hammerspoon script: copy 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).

How it works

  • The mod writes your prompt's text to ~/Library/Caches/prompt-select/prompts/<session>.txt whenever it changes. The session whose file changed last is the one you are typing in.
  • On Cmd+A in Orca's terminal, the script writes 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.
  • The script turns on Orca's accessibility tree (AXManualAccessibility) so it can tell the terminal from Orca's other fields.

What it can reach

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.

Source 1 files
hooks/register.js 54 lines
1// 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