vecnode/vn-code--packages-dsh-editor ↗★ 9
dsh-editor
Editor: the tab type for text and code - a vendored CodeMirror 6 fetched lazily - with create-on-save inside the session workspace through this package's own authenticated routes. Markdown is claimed too, and hands off to the shipped preview. 适合需要在右侧栏直接编辑工作区文本和代码文件并保存的用户。
Other repositories with this package name
Install
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:vecnode/vn-code#066e7396f8c7d4abd3132329f32c1b7c9ad8c1fa&path:packages/dsh-editorREADME
Read the full README ↗dsh-editor (alpha.13)
A CodeMirror 6 tab type for the pack's right bar (dsh-rightbar) that opens text files editable. It registers the id dsh-editor and the kind editor through the bar's own tab-type registry, with its body and chip title in the keyed sidebar.right.pane.tab / sidebar.right.pane.tab.title seats and a guide entry at order: 20 for the "+" control. It is text-only (strict UTF-8, binary refused), starts blank documents, and writes through authenticated Node routes because remote.workspaceFiles exposes no mutation operation.
What it adds
- Text files open editable.
patterns: ['dsh-resource://file/**']in theextensionband, which outranks every shipped viewer, with acanOpenthat vetoes what a text editor has nothing to add to (.html, images, PDF, office/archive/media, binary) and paths outside the session workspace, including the session-lessabsolute/…form. - Markdown is claimed too (
.md,.markdown,.mdown). The toolbar's Preview button reads the shipped document preview's kind out of the tab registry (never hardcoded) and callsctx.get('sidebarRight').openResource(address, { kind, replaceTab }), so Edit ⇄ Preview is one tab on the same file. It is refused while the document has unsaved edits, because the preview reads from disk. - "+" → Editor opens a blank document. Save (or Ctrl/Cmd+S) asks for the file name with its extension through the shared
dsh-modalmodalsservice and creates it in the conversation's workspace folder; the parent folder must already exist and a taken name answers409 EXISTSinside the dialog. - Saving is optimistic and atomic. The panel PUTs the whole document with the mtime/size it opened with, and a file that moved on disk offers Reload / Save anyway rather than a silent clobber. Unsaved work is lost on tab close or restart.
- The language map. Every extension is mapped in
languageExtensionForand every lookup goes through a guard, so an engine older than the bundle opens the document unhighlighted rather than killing the tab. Lezer factories (function shape) viaengineLanguagecover javascript (js/mjs/cjs/jsx/ts/tsx), json (json/jsonc), markdown (md/markdown/mdown), python (py/pyw), html (html/htm/xhtml), css and yaml (yaml/yml). CM5-style StreamParser objects (found by theirtoken(), viaengineStreamMode) cover shell (sh/bash/zsh/ksh/dash), powerShell (ps1/psm1/psd1), batch (bat/cmd, from the pack's ownvendor/batch-mode.js), rust (rs) and toml (toml) from the vendored@codemirror/legacy-modes. Each returnsnullplus one console warning naming the missing factory and the rebuild command, solanguageExtensionForhas no directCM.(...)call. - The palette follows the app's theme: oneDark only while the app is dark, a token-driven transparent light layer otherwise, switched live through a CodeMirror
Compartmentreconfigured offctx.get('theme')/theme/change, withbody[data-ds-dark-theme]as the fallback. Both theme services are resolved lazily. - The rendered Markdown body is shadowed. The keyed
sidebar.right.tab.documentslot is registered atpriority: -10(lowest renders), so only the page body is this package's while the shipped preview keeps its chrome; uninstalling brings the shipped body back. That body carries an Edit pill back to the editor and undoes what the preview's plain-text scrollport imposes (white-space:preand the mono stack).
How it plugs in
| Route | What it does |
|---|---|
GET /api/dsh-editor/file?session=&path= | read one text file (strict UTF-8, no NUL, ≤ 2 MiB; HEAD answers headers and no body) |
PUT /api/dsh-editor/file | save {session, path, text, expected?: {mtimeMs, size}} - atomic temp+rename, 409 when the file moved on disk |
PUT /api/dsh-editor/file with {create: true} | create a file: the parent must exist inside the workspace and is realpath-checked, the target must not exist - 409 EXISTS, create-exclusive |
GET /api/dsh-editor/vendor?v= | the vendored CodeMirror 6 classic bundle (window.DSHEditorCM), fetched lazily on first open |
The workspace root is resolved host-side (live session header first, session persistence second, typed NO_WORKSPACE otherwise) from the session id the tab's address already carries, dsh-resource://file/session// ; the client never names a root. The engine request is version-qualified, and the route answers cache-control: no-cache over a content-hash ETag, re-stating the artifact per request, so a rebuild needs no restart.
Limits
- Text only: strict UTF-8, no NUL, ≤ 2 MiB read and save.
- No folder browser and no binary editing;
canOpenrefuses any address outside a session workspace. - Create-on-save, never overwrite: a create is create-exclusive.
- Unsaved work is lost on tab close or restart.
Verify
node scripts/checks/check-client-bundles.mjs
node scripts/checks/check-node-routes.mjs
check-client-bundles.mjs drives the browser half through a real React runtime: the registration and guide order, the seats, the shadowed document body, the language-map guard and the Preview hand-off. check-node-routes.mjs drives the routes against a scratch workspace.
Install
The launcher (scripts\setup\install.bat / ./scripts/setup/install.sh) auto-discovers the package as a standard dsh.bundle, and the uninstall twins do the same. It is a live link in the web profile, so code edits need a restart of npx @deepseek-ai/dsh web plus a hard refresh.