# dsh-nav-keys [![简体中文](https://img.shields.io/badge/语言-简体中文-57606a)](./README.md) [![English](https://img.shields.io/badge/Language-English-0969da)](./README.en.md) A DeepSeek Harness Web composer plugin: bare ↑/↓ recall and walk your sent-message history exactly like a terminal (bash/readline) — **key-usage-intent driven**: the moment you position the caret with ←/→/Home/End or a mouse click, ↑/↓ instantly revert to ordinary line-to-line caret movement, so editing is never interrupted. Zero core changes. This is an unofficial community plugin and is not affiliated with, authorized by, or endorsed by DeepSeek. ## Relationship to DeepSeek The plugin runs inside the DeepSeek Harness Web client and touches only the official input facade (`conversation.input.for(actx).setDraft()`) and the conversation snapshot (`ConversationSnapshot.nodes`). It does not modify models, prompts, or session data, and sends nothing to external services — pure browser-side behavior. ## Features and behavior **Bare ↑/↓ — terminal-style history recall (intent-driven)**: - **Default (history mode)**: ↑/↓ navigate history — ↑ recalls the newest sent message, repeated presses walk older; ↓ walks back toward live and restores the draft you were writing when recall started (empty, single-line, and multi-line drafts alike) - **After positioning (caret mode)**: once you use ←/→/Home/End (incl. Ctrl word-jumps and Shift selection extension) or click to move the caret, ↑/↓ immediately become **ordinary caret movements between lines** — you are editing; arrows must not flip history - **Natural boundaries back to history mode**: sending (draft cleared), deleting to empty, a recall fill landing (keep browsing), switching sessions **Ctrl+↑ / Ctrl+↓ (Cmd+↑/↓ on macOS) — unconditional recall**: - Enters history browsing from any mode/draft state (the escape hatch while in caret mode) - Cmd is bound as the macOS alias (Ctrl+arrows are frequently claimed by the system); the cost is overriding the native Cmd+↑/↓ jump-to-start/end, which has little value in a chat draft **History source**: user messages from the current session snapshot (adjacent duplicates collapsed, blanks skipped); survives page refresh. **Yield rules** (keys this plugin never claims): - While the `/` / `@` trigger menu or a command popup is open: every arrow key (chords included) yields to the menu highlight - During IME composition (`isComposing` / keyCode 229): everything passes through - Alt+arrows, stacked Ctrl+Cmd, and every other key: untouched - Editing a recalled entry resets the browse state ## Installation Install into the Web profile (a Git install runs the `prepare` build): ```sh dsh plugin --profile web add github:ClausYang/dsh-nav-keys ``` Or install a local checkout: ```sh dsh plugin --profile web add /path/to/dsh-nav-keys ``` Restart `dsh web`; the browser half loads with the page. ## Build ```bash pnpm install pnpm run build # lib/index.js + lib/invariant.js + lib/client.js pnpm run test # pure-logic unit tests (19) pnpm run typecheck ``` ## Design notes - Pure browser-side implementation: no server behavior (`src/index.ts` is a registration shell); nothing is injected into model traffic or session logs - Two pure-logic layers, zero DOM/cordis dependencies, fully unit-testable: - `src/client/history.ts` — history extraction (kind filter, text-block join, blank skip, adjacent dedup) + the browse state machine (enter/oldest/newest/restore-live-draft) + external-change re-sync - `src/client/decision.ts` — the mode state machine (intent-driven): position (←/→/Home/End/selection/mouse) → caret; recall / emptied draft / session switch → history - Keys are captured at the document capture phase; `preventDefault` fires only on an adjudicated recall, everything else passes through - Recall writes go through the official input facade `conversation.input.for(actx).setDraft()`, compatible with undo/send transactions ## Compatibility Developed and verified against the snapshot0812 / npm `@deepseek-ai/dsh@0.0.1-rc.5` baseline (boot-graph load, recall and mode switching tested live). Contracts depended on: - the `conversation` / `sessions` services with `conversation.input.for(actx).setDraft()` and `ConversationSnapshot.nodes` (the same official facade dsh-input-history uses; unchanged across 0808–0812) - the `data-input-scroll` (composer location) and `data-composer-seat` (menu-yield detection) DOM markers ## Known limitations - History covers the current session only; cross-session/cross-device sharing is not implemented - Messages outside the snapshot window cannot be recalled - The Cmd+↑/↓ alias overrides the textarea's native jump-to-start/end (macOS) - The browse state resets on session switch and does not carry across sessions - In caret mode bare ↑/↓ are native caret movements (by design); use Ctrl/Cmd+↑ to recall, or clear the draft to return to the default mode ## License BSD 3-Clause — see [LICENSE](./LICENSE). ## Maintenance Maintained by [@ClausYang](https://github.com/ClausYang). Issues and PRs welcome.