Repro: a focused Claude Code mod Input paints only the first wrapped row of a long value

A Pane with one focused Input. Once the typed value wraps past one row, the field paints row 1, a short fragment ending in …, and then blank rows, with the caret on an empty last row.
ui.render hook drawing a Pane with the Input elementFrom a terminal session, at the prompt:
/plugin install cc-mod-input-wrap-repro --marketplace bassic-nerd/cc-mod-input-wrap-repro
Answer y to add the marketplace, then pick a scope. Or load it straight from a clone, for one session:
git clone https://github.com/bassic-nerd/cc-mod-input-wrap-repro
claude --plugin-dir ./cc-mod-input-wrap-repro
Then run the slash command /input-wrap. It opens a pane and gives it the keyboard.
The whole mod is one file, hooks/register.tsx.
/input-wrap. The pane has one focused Input (placeholder describe) and about 15 free rows below it.The focused field shows every wrapped row of its value, or at least the rows around the caret.
…. ⏎ submit hint shows) and typing keeps going into the value, so no text is lost. It just cannot be seen. The layout reserves the right number of rows; only the painted text is cut.The Input is drawn with a constant empty value, an autoFocus and a no-op onInput, so nothing in the mod redraws while you type. The fault is in how the focused field is painted.
claude plugin validate .
claude plugin test .
tsc --noEmit -p .
(the last needs the API types in .claude-plugin/types/, which Claude Code lays beside a mod it loads from a folder.)
License: MIT.
hooks/register.tsx 34 lines1import type { Register } from 'claude-code'
2
3const PANE = 'input-wrap'
4
5export const register: Register = on => {
6 on('session.start', async ($, e, next) => {
7 await $.command.register({ name: 'input-wrap', description: 'Open the Input wrap repro pane' })
8 return next(e)
9 })
10
11 on('command.run', { command: 'input-wrap' }, async $ => {
12 await $.ui.open({ id: PANE, title: 'Input wrap', focus: true })
13 return { text: 'Input wrap pane opened. Type about 150 characters into the field.' }
14 })
15
16 on('ui.render', { component: 'Pane', requestId: PANE }, ($, e, next) => {
17 if (e.surface !== 'terminal') return next(e)
18 const { Box, Text, Input } = $.ui.resolve(e)
19 return (
20 <Box flexDirection="column" height={20}>
21 <Text dimColor>Type ~150 characters. Enter logs the real length.</Text>
22 <Input
23 key="desc"
24 autoFocus
25 placeholder="describe"
26 value=""
27 onInput={() => {}}
28 onSubmit={v => $.ui.log(`input-wrap: field holds ${v.length} chars`)}
29 />
30 </Box>
31 )
32 })
33}
34