zhang24xiao/dsh-snippets ↗★ 0

dsh-snippets

CSS and JS snippet manager for the DeepSeek Harness web GUI. A sidebar-footer quick toggle opens a manager panel, and Settings gains a card under Plugins; enabled CSS is injected as style elements and enabled JS runs in the page, so only trusted code should be enabled. Also mirrors a local folder of .css/.js files and publishes or imports a library through the GitHub Gist API. · DSH Web 代码片段管理器:侧栏底部快捷开关打开管理面板,设置里在「插件」下新增一张卡片;启用的 CSS 注入为 style 元素,启用的 JS 在页面内执行(无沙箱,只启用可信代码);并支持本地文件夹监听与 Gist 同步。 适合需自定义界面样式或脚本的用户,仅应启用可信代码。

パッケージ
dsh-snippets
互換性
未検証
バージョン
0.1.0
ライセンス
MIT
最終更新
2026/09/14

同名パッケージの別リポジトリ

インストール

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:zhang24xiao/dsh-snippets

ドキュメント

README 全文を読む ↗

dsh-snippets

CSS and JS code snippets for the DeepSeek Harness web GUI.

A quick toggle in the sidebar footer beside Settings opens a manager panel — the same seat @linxin666/dsh-remote-web-ui uses for its phone entry — and Settings → Code Snippets is an independent page with the full set of preferences. Enabled CSS is injected into the page immediately; enabled JS runs after the page loads.

Inspired by TCOTC/snippets, the SiYuan note-taking app's snippet manager, and adapted to the DSH plugin contract.

简体中文

Screenshots

The quick toggle sits in the sidebar footer, in the same row as Settings, and opens the manager panel:

The snippet manager panel, opened from the sidebar footer beside Settings

Settings → Plugins → Plugin configuration carries the card, beside every other plugin's settings:

The editor is CodeMirror 6 — line numbers, CSS/JS highlighting, search and replace — sized to the viewport, with live CSS preview:

The snippet editor, showing a CSS snippet with syntax highlighting

Features

Managing snippets

  • CSS / JS tabs with live counts, one master switch per type, and search across titles, code, or both
  • Lives with the other plugin settings, in Settings → Plugins → Plugin configuration
  • Add, edit, duplicate, delete, enable/disable, and drag to reorder
  • Ten sort orders (custom, enabled-first, title A→Z / natural, oldest/newest)
  • Per-row edit / duplicate / delete buttons, each individually hideable
  • One-click Reload the interface for changes only a reload can apply

Editing

  • CodeMirror 6: line numbers, CSS/JS syntax highlighting, bracket matching, fold gutter, search & replace, history

  • Configurable indent unit, font size and soft wrap; the theme follows the app, including dark mode

  • Live CSS preview — see the page change while you type, without saving

  • The editor dialog sizes itself to the viewport (up to 1040×760) instead of the shell's 380px form card, and the code area absorbs the leftover height, so a long snippet scrolls inside the card rather than pushing the dialog past the window edge

  • Best-effort re-indent that only ever rewrites leading whitespace

  • Content guards: CSS containing `` button in the SiYuan original. The tooltip carries the name and the live counts; the manager panel's footer carries them permanently.

  • The trigger's box is copied field for field from the neighbouring entry's own trigger, so the two hover surfaces agree: 36×36 with border-radius: 50% in the rail, and in the wide row padding: 0 10px with border-radius: 999px. That padding is what makes the wide box 36px around a 16px glyph — without it the box is 16px wide and reads as a narrow vertical pill beside the neighbour's circle. Gaps match too: 6px in the wide row, 4px in the rail.

  • The sidebar shell lays the foot out as a column but keeps sidebar.footer.action a row even when the column is collapsed to the 56px rail. With one action that is invisible; with two, the icons land side by side and overflow. This plugin therefore injects one narrowly scoped rule that makes the collapsed row a column again:

    html [class*='_footerActions']             { gap: 6px; }
    html [class*='_collapsed'] [class*='_footerActions'] { flex-direction: column; gap: 4px; … }
    

    The attribute-substring selectors are deliberate: if the shell's class hashes change, the rule simply stops matching and the rail falls back to the shipped layout instead of breaking.

How CSS and JS take effect

  • Each enabled CSS snippet becomes one "> element in ``. Toggling one adds or removes exactly that element, so CSS applies and reverts instantly with no reload.
  • Each enabled JS snippet is compiled with new Function and called once per page load. There is no sandbox and no undo — this is deliberately the same trust model as pasting the code into the browser console, which is the point of the feature. Disabling, editing or removing a JS snippet therefore reports that a reload is required, and autoReloadAfterJsEdit can do it for you.
  • window.__dshSnippets exposes { version, log, reload } for snippets that want an entry point.
  • Unloading the plugin removes every `` it injected. Executed JS is not undone; it cannot be.

Security notes

  • Snippet data travels only over the official settings wire. The plugin adds no browser-writable snippet endpoint, so on a LAN or tunneled deployment an unpaired visitor cannot reach a route that would inject code into a page.
  • The plugin's own endpoints (/snippets/api/*) do the three things a browser cannot: read the watched folder, call GitHub, and open the backups directory. They answer loopback requests only; over a LAN or tunnel those sections disable themselves and say so.
  • The GitHub token is stored on the host at $DSH_HOME/dsh-snippets/gist-token.json with mode 0600. It never enters the settings document, never reaches the browser, and the UI only ever learns whether one is configured.

Differences from TCOTC/snippets

Three settings describe SiYuan features that DSH does not have:

SiYuanDSH
Snippet "publish service" switchesRemoved — DSH has no publish concept
"Open the native snippet window"Replaced by "Open the backups folder"
Watched folder: relative paths onlyAbsolute paths and ~ are supported (the DSH host is a plain Node process)

Development

pnpm install
pnpm run check     # typecheck, build, and both test suites
pnpm run watch     # rebuild on change

npm run test runs two suites:

  • test/host.test.mjs — namespace registration, the loopback fence on every route, backups, the folder mirror (including id stability across scans), the Gist import plan, and the content guards.
  • test/client.test.mjs — loads the built client/client.js through window.__ModuleLoader__.load in jsdom and drives the runtime: an enabled CSS snippet produces exactly one ``, an enabled JS snippet runs exactly once, disabling removes only that element, the type master switch gates injection, and teardown leaves nothing behind. It then server-renders all three registered seats, so a broken render path fails here rather than in the GUI.

License

MIT