chendefine/dsh-sidebar-vscode ↗★ 0
dsh-sidebar-vscode
DSH web plugin: an official right-Sidebar tab type ('vscode') that embeds the VS Code web workbench opened at the current session workspace — same-origin by default through the plugin's built-in reverse proxy (/sidebar/vscode), or via a gateway subpath / any configured editor base URL. Editor selections land as atomic reference chips whose canonical mentions the host half expands into <text-selection> context at agent/pre-step; explorer files/folders land as path-only resource chips expanded into content-less <file-selection>/<folder-selection> markers. Chat-originated file opens (the sidebarRight openResource funnel), the collapsed column's expand button, and the settings page's open-document button are taken over into the workbench behind the openAsDefault switch; its configuration derives from the plugin entry's volatile Config schema (namespace 'dsh-sidebar-vscode', edited on the Plugins page). 适合需要在对话中直接编辑代码并发送代码片段到会话的开发者。
Install
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:chendefine/dsh-sidebar-vscodeREADME
Read the full README ↗Usage
Opening the tab
Expand the right sidebar and pick the VSCode 工作台 / VSCode workbench entry box on the guide ("开始") page — it opens in the guide tab's place. The layout is in-memory: a page refresh folds every session back to its collapsed default. The toolbar shows the workspace path;「⧉ open in new window」pops a standalone one.
Sending a selection
- Select code in the embedded editor (multi-cursor = one chip each);
- Right-click → "DSH: Send Selection to Session", or press Ctrl/Cmd+Alt+C;
- The atomic chip
@src/main.ts L10-L12appears in the composer — success is silent (the chip is the feedback); only degradations/failures flash an amber notice in the toolbar; - Type and submit as usual. The chip is rewritten to the readable
@path L10-L12, and the `` context is injected right after the message.
Selection reference details:
- Dedup: within one step by
(path, start, end)— sending the same selection twice injects one context; the same range with different content (file changed) keeps the newest capture; - Freshness: at submit the disk range is re-read confined to the session cwd and hash-compared — a mismatch marks
stale="true"; a truncated snapshot instead verifies its kept head/tail halves (truncation alone never marks stale); an unsaved buffer marksdirty="true"; the snapshot text is always injected (no filesystem dependency), and the leading comment tells the model to re-read before editing; - Truncation: beyond
maxLines(default 200) /maxBytes(default 20000, guards minified single-line files) the head and tail halves are kept with the middle omitted inline as... (N lines omitted, L51-L150) ..., the tag carriestruncated="true", and the real line range is preserved; - The context message source is
{ kind: 'vscode-mention', form: 'notice', version: 1, path, startLine, endLine, language?, contentHash, bytes, truncated, dirty, stale }.
Sending files / folders
Select files/folders in the explorer (multi- and mixed-select work), right-click → Send File/Folder to Session (the entry sits near "Copy Path"). One chip per item: @src/main.ts (file icon) or @src (folder icon); the kind comes from the extension's workspace.fs.stat (symlinks classify by target). On submit each expands to / with source { kind: 'vscode-resource', form: 'notice', version: 1, path, type }. Resource references do no freshness check and ignore the truncation caps; within one step they dedupe by (path, kind), and a selection reference and a resource reference on the same path stay independent.
Managing references
- The rail above the composer lists every VS Code reference (truncated
…badge, folder icon, ×N count); a tag's × removes all chips of that reference at once; - One backspace deletes a whole chip; once no mention of a reference remains in the draft, submit injects nothing for it;
- Copying a (rendered) chip and pasting it back rebuilds atomic chips.
Settings
Settings derive from the plugin entry's volatile Config schema (src/config.ts) and are edited on the official Plugins page — 设置 → 插件 → dsh-sidebar-vscode 的配置区 (the bundle's own config form between its description and its rows) or the row's configure control: the settings service keys the derived section by the composition entry id dsh-sidebar-vscode, the browser half registers the SAME card in the two seats the Plugins page offers (plugins.bundle.config keyed by package name, plugins.row.config keyed #, both mounted while the Host serves the section), and every row commits through the shared config form (ctx.configForms: set/unset; the footer's "Reset to defaults" clears the user layer so each field re-inherits the composition base — the shipped base layer travels in cordis.patch.yml). Not hand-registered anywhere (pathMap below is served by the same section but deliberately has no card row):
| Key | Default | Description |
|---|---|---|
openAsDefault | false | Gates the three file-open takeovers (chat file clicks, the settings「打开配置文件」button, and the right-sidebar expand button). Off restores the official stock behavior everywhere |
openBlocklist | (unset = pdf, docx, xlsx, pptx, png, jpeg, jpg) | "File types never opened in VS Code": an array of extensions rendered as a tag editor (tags carry a × remove button; a free-form input adds entries on Enter/comma, with a dropdown suggesting common binary types). A chat click on a matching file is NOT taken over — it falls through to the stock routing, where the official sidebar's viewers claim it (the builtin text preview today; future viewer plugins register their own official tab types). Unset = the seven defaults; an emptied list stores [], letting VS Code open everything (distinct meanings). Matching is case-insensitive, by "base name ends with ." (a.notpdf does not match pdf; entries may contain inner dots, e.g. tar.gz; extension-less files never match); settings are read per click, so edits apply immediately. The settings「打开配置文件」takeover is deliberately not affected |
serverUrl | (empty = http://127.0.0.1:8000) | The full address code serve-web prints (base path and ?tkn= token included); empty = the default http://127.0.0.1:8000 (a bare local server). Whenever the proxy is reachable the workbench opens at the same-origin /sidebar/vscode/; a host-unreachable full URL falls back to a direct connection (same-origin bridge degrades); an explicit relative subpath (e.g. /vscode) is used with gateway semantics when the proxy is off |
pathMap | (empty = no mapping) | Document-only — no card row (rare, split-container deployments). DSH prefix → VS Code container prefix as src=dst pairs joined by ;; longest source prefix wins; a path already under a destination passes through unchanged. When empty, no mapping is applied at all — the session cwd and clicked files open at their raw absolute paths (the same-container default). Rules are prefix rewriters, not a whitelist: absolute paths no rule matches pass through as-is (VS Code itself reports a genuinely missing file) |
maxLines | 200 (range 1–2000) | Max rendered code lines per reference; overflow keeps head+tail halves and marks the omitted middle inline |
maxBytes | 20000 (range 1000–200000) | UTF-8 byte cap per reference (guards minified single-line files) |
(Selection injection itself is always on — no switch.) Number rows enforce their range as you type (red field + inline hint; out-of-range edits snap to the nearest bound on commit); text rows stack description-over-input; the openBlocklist row is tags + an inline input (junk flags a red hint, duplicate adds are silent no-ops). A read-only scope (memory-mode remote browser) disables every control and shows the effective values.
Troubleshooting
| Symptom | Fix |
|---|---|
| The tab stays blank / the loading hint never clears | Check serverUrl reachability; diagnose via "open in new window"; with a cross-origin URL the bridge is off by design (paste fallback still works). On the built-in proxy, confirm serve-web answers at the configured upstream (default http://127.0.0.1:8000; any base path works) |
A file matching openBlocklist opens in the stock viewer instead of VS Code | A blocklist hit falls through to the official routing — the builtin text preview (or a future viewer plugin's type) claims it, never the Host OS opener. Remove the extension from the list if you want VS Code to open that type |
| "Workspace path is not absolute…" notice | Fires only when the session cwd is not an absolute path (the workbench then opened its default view); healthy deployments never trigger it — no mapping needed |
| No DSH command in the context menu / palette | Extension not installed, serve-web not restarted (the manifest is scanned at startup only), or the workspace is untrusted (restricted mode) — see the FAQ in scripts/install-extension.md |
| No chip after sending; a code snippet appears on the clipboard | Landing failed and the readable fallback reached the clipboard (no composer / cross-origin); paste it into the composer to recover chips |
| "Injected as a text reference…" notice | The composer was mid-submit so the chip degraded to a plain-text mention — submitting works the same |
| Caret vanishes from the composer ~1s after creating a session, or focus jumps into the sidebar's open file after switching back from another workspace's session (older-version symptoms) | The booted workbench focuses itself (Getting Started page on render, a restored editor on workspace restore): a boot behind a collapsed panel stole the caret invisibly, and the re-insertion reload a workspace switch-back triggers landed focus in the restored file right after the composer was autofocused. Current versions guard it generically — the first load is deferred until the tab has been seen, and every boot of the frame gets a focus fence that bounces uninvited grabs back unless the user actually clicks into the workbench (see "Focus guards" below); the first workbench load on expansion arrives slightly later by design |