# DSH Adaptation Architecture ADAPT, NOT REBUILD. The Chrome extension is the product spec, UI spec, interaction spec, state machine spec, motion spec and data model spec. DSH is only a new host environment. We are writing `DeepSeekHarnessAdapter`, not another implementation. ## Principles 1. No UI redesign — reuse `src/content/*` and `src/shared/*` as-is where possible. 2. The shared product core stays host-agnostic and its DSH regression suite remains green. 3. Every host difference goes into an Adapter (platform interface), never into product core. 4. Quick Explain stays a side mini-thread; it never writes a user/assistant message into the DSH main session (no `agent.followup`, no `agent.steer`). 5. Annotation drop never auto-submits. Drop only modifies the draft (`input.setDraft`). Sending is always the user's act. 6. Parity first. DSH-native enhancements (reference chips, side sessions, ConversationNode, native history events) are explicitly out of v1. ## Target layout ``` look-here/ ├── src/ │ ├── content/ # product core (kept in place, host-agnostic) │ │ ├── content.js │ │ ├── content-ui.js │ │ ├── annotation-runtime.js │ │ ├── content-performance.js │ │ └── panel-layout.js │ ├── shared/ │ │ ├── constants.js │ │ ├── annotations.js │ │ └── ... │ └── platform/ │ ├── platform.js # globalThis.InlineAIPlatform — platform interface │ └── chrome-platform.js # Chrome adapter (keeps original behavior) ├── dsh/ │ ├── cordis.patch.yml # - insert: [{id, name}] │ ├── host/ │ │ ├── index.js # export const name + apply(ctx) │ │ ├── quick-explain.js # ctx.llm side calls, job map, abort/cleanup │ │ ├── rpc.js # /look-here channel: quick/start|poll|cancel │ │ └── settings.js # settings namespace (installSettingsSection) │ ├── client/ │ │ ├── index.js # client bundle entry │ │ ├── overlay-root.js # thin React mount point for shell.overlay │ │ ├── selection-adapter.js# DshSelectionContext + re-anchor │ │ ├── composer-adapter.js # input machine setDraft │ │ ├── storage-adapter.js # localStorage-backed storage, look-here:dsh:* keys │ │ ├── quick-explain-client.js │ │ ├── settings-card.js # settings.plugin.item card │ │ └── dsh-dom.js # ALL DSH DOM selectors live here │ └── build/ │ └── build-client.mjs ├── dist/dsh/ │ ├── index.js # host bundle │ └── client.js # client module bundle ├── docs/dsh-adaptation/ └── tests/dsh/ ``` ## Platform interface (strangler pattern) `src/platform/platform.js` exposes `globalThis.InlineAIPlatform`: ``` InlineAIPlatform { kind: "chrome" | "dsh" storage: { get(keys), set(values), remove(keys), onChanged(listener) } ai: { stream(request, handlers), cancel(requestId) } context: { currentScope(), currentDocument(), resolveSelection(selection) } composer: { canInsert(), insertText(text) } navigation:{ openSettings(), openHistory(), openOnboarding() } } ``` Each Chrome API found in product core moves behind the interface; the Chrome adapter keeps the original implementation, the DSH adapter adds its own. After every extraction, `npm run check` must pass. ## Host adaptation map | Chrome | DSH | |---|---| | page | session | | site | workspace | | chrome.storage.local | storage adapter (settings → DSH settings ns, history → localStorage) | | background.js OpenAI-compatible API | host `ctx.llm` (current session provider/model) | | generic editor injection | DSH input machine `setDraft` | | Chrome options page | DSH plugin settings card | | page DOM | shell.overlay mount root + conversation DOM | ## Quick Explain bridge (v1, unary RPC + poll) ``` Client Host │ rpc.call('/look-here','quick/start') │ ctx.llm.stream(...) — side call │ ← requestId │ Map │ rpc.call('/look-here','quick/poll',{id,cursor}) │ ← {chunks, done, error} (poll 50–100ms) │ rpc.call('/look-here','quick/cancel',{id}) ``` - Job cleanup after completion TTL; plugin dispose aborts all jobs. - Prompt shape unchanged: system instruction + selected text + surrounding context + question + mini-thread; default prompt keeps `联系上下文{{term}} ,请用简洁中文解释这个概念。` - No main-session writes. No API keys stored/read by the plugin. ## DOM isolation All DSH selectors (`[data-chat-anchor-key]`, `[data-composer-seat]`, conversation root) live only in `dsh/client/dsh-dom.js`. Product core must not contain them. ## History surface The DSH history surface renders inside `shell.overlay`. Card internals (pill filter, expandable cards, markdown render, annotation history) come from `dsh/client/history-view.js`, which is a verbatim extraction of the product logic in `src/history/history.js`. The Chrome history page keeps its own copy for now (strangler: shared adoption is a later cleanup, never a behavior change). ## Diagnostics `globalThis.__LOOK_HERE_DSH_DIAGNOSTICS__` exposes health / platform / selection / composer / storage / quickExplainJobs (via `/look-here quick/diag`) / selfTest. ## Performance guards - Product core keeps its throttle / requestAnimationFrame / lazy full UI / debounced MutationObserver (unchanged). - The Quick Explain poll loop (75ms) only forwards text chunks; it performs no DOM scans per token. - Selection re-anchor runs only at annotation save time, never per frame. ## Out of scope (v1) Native DSH ReferenceInsert, native quote chip, side-session fork, ConversationNode, DSH message actions, native history events, persistent SessionEvent memory, workspace-shared memory, export/import Chrome memory.