# dsh-input-enhancer [δΈ­ζ–‡](README.md) | English A **DeepSeek Harness Web plugin** that makes the chat composer better suited to long-form editing. ## Features | Feature | What it does | How | | --- | --- | --- | | πŸ”’ **Lock Enter-send** | While locked, Enter won't accidentally send; you can keep editing | Click the lock button / `Cmd/Ctrl+Alt+L` | | ⚑ **Triple-Enter send** | Press Enter 3 times (≀800ms apart) to unlock and send immediately | Press Enter while locked | | πŸ”’ **Character count** | A live character-count badge appears after the lock button while non-empty | Automatic | | ⚠️ **Long-text warning** | Past 800 characters the badge turns amber, so the length is clear before sending | Automatic | | πŸ” **Auto-lock / unlock** | Past 80 characters the composer auto-locks; clearing the composer auto-unlocks | Automatic | | ⇄ **Draft swap** | Swap content between the composer and a staging slot, to park a half-finished draft for a later turn | Click the swap button / `Cmd/Ctrl+Opt+K` | - **Lock button**: registered in the official `conversation.input.right` slot, near the send button; a prominent red fill when locked, with a state tooltip on hover. It can also be toggled with `Ctrl/Cmd+Alt+L` (only while the composer is focused). - **Character count is independent**: it shows whenever the composer is non-empty, locked or not. - **Long-text warning**: once the draft reaches the threshold (800 chars by default), the count badge turns amber with a "long text" hover hint. - **Auto-lock / unlock**: on by default (source constants `AUTO_LOCK_ENABLED` / `AUTO_LOCK_THRESHOLD`). The composer locks the moment the length crosses from `≀80` up to `>80` (rising edge), and unlocks when the draft is fully cleared (length back to zero). The lock has no "manual vs automatic" source distinction β€” once it is on, it is on; the two length edges simply add and remove it. Shrinking to a non-empty length or hovering around 80 leaves the lock untouched, and after a clear-then-unlock, typing past 80 again re-locks. This `80`-lock is independent of the `800` warning above. - **Per-session state**: each conversation keeps its own lock flag. ### Lock state & composer | State | Lock icon | Composer | Enter behavior | | --- | --- | --- | --- | | Unlocked | Gray outlined | Default size | Sends normally | | Locked | **Red fill + white lock icon** | Default size | Does not send (3Γ— Enter unlocks and sends) | Tooltip: - Unlocked: `Unlocked: composer is normal size, Enter sends normally` - Locked: `Locked: Enter will not send. Press Enter 3 times to unlock and send` ### Triple-Enter (locked-state escape hatch) While locked, to send without first unlocking: **press Enter 3 times** to unlock and send immediately. - The first two Enters have no side effect (no send, no newline); they only count. The lock icon turns into the current count (1st shows "1", 2nd shows "2") with a growing pulse. - The 3rd Enter plays a **firework burst** (colored particles flying out from the lock button for ~1 second), then unlocks and sends the current content. - Timeout, any other key, or a session switch resets the count. > Triple-tap applies only while locked; an empty composer will not send. ### Draft swap (park a half-finished draft) While the agent is still thinking or executing, you'll often want to type the next message in advance. But sometimes you realize mid-draft that this text should wait a few turns. Park it with a direction-agnostic swap button (⇄), keep writing and sending other things, and swap it back in the right turn. - **Swap button**: registered in the `conversation.input.right` slot, just left of the lock button; the icon is ⇄ (opposing arrows, no direction bias). Clicking it swaps content between the composer and the staging slot. - **Atomic swap semantics**: - Slot **empty** β†’ the composer's text moves into the slot, and the composer empties; - Slot **full** β†’ the two swap: the staged draft returns to the composer, and the composer's current text moves into the slot (neither side is lost); - When the slot is full the button is **highlighted**, so you can tell at a glance that a draft is parked. - **Shortcut** `Cmd+Opt+K` (macOS) / `Ctrl+Alt+K` (Windows/Linux) is equivalent to clicking the swap button; it only acts while the composer is focused. - **Per-session, in-memory only**: each conversation has its own single slot; it is cleared on refresh or restart β€” it only serves the temporary "park for a few turns" case, never crossing sessions or touching disk. > When both the composer and the slot hold text, clicking swap will exchange them; use accordingly. ## Guarantees - **No composer replacement**: intercepts only the keyboard submit path, keeping the official input state machine, command menu, queue, and attachments. - **IME-friendly**: Enter during composition is never intercepted. - Blocked while locked: plain `Enter`, `Ctrl+Enter` / `Cmd+Enter`, other Enter combos that reach the official submit path. - Preserved: `Shift+Enter` newline, IME candidate confirmation, edit/copy/paste/attachments, and mouse-click send (the lock only guards the keyboard). ## Keyboard shortcut **`Ctrl+Alt+L`** (Windows/Linux) or **`Cmd+Alt+L`** (macOS) toggles the current composer's lock without reaching for the lock button. It only acts while the composer is focused. > Why not `Ctrl/Cmd+L`: Chrome / Edge reserve `Ctrl+L` and macOS reserves `Cmd+L` for the address bar, which intercepts them first; hence `Ctrl/Cmd+Alt+L`. **`Ctrl+Alt+K`** (Windows/Linux) or **`Cmd+Opt+K`** (macOS) triggers the draft swap. It only acts while the composer is focused. > Adjacent-shortcut note: `Cmd/Ctrl+Opt/Alt+K` (draft swap) and `Cmd/Ctrl+Opt/Alt+L` (lock) are adjacent, and Opt is Alt, so mis-presses are possible β€” if you hit the wrong one often, prefer the corresponding icon button. ## Requirements - DeepSeek Harness `0.1.2-alpha.1` or newer (verified; `0.1.0-rc.6` also runs); - the `web` profile; - a modern Chromium-based browser (Chrome or Edge). > This plugin works through DSH's internal DOM contract β€” `[data-composer-card]`, > `[data-composer-input]`, `[role="listbox"]` etc. β€” collected in the `SEL` table > at the top of `src/client.js`. DSH `0.1.2-alpha.1` replaced the composer > `