npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-fluxion

v0.0.4

Published

dsh-fluxion — a monochrome microkernel desktop for the DeepSeek Harness: free windows, a shared AI terminal, pluggable APPs.

Readme

dsh-fluxion

A monochrome AI-development cockpit for the DeepSeek Harness Web GUI: a microkernel desktop on DeskPane where every panel is a pluggable APP, plus a shared terminal that the AI and you take turns driving.

npm i -g @deepseek-ai/dsh          # if you do not have the CLI yet
dsh plugin --profile web add dsh-fluxion

Then reload the GUI. The package declares dsh.bundle.patch, so the install also inserts its loader row — no manual YAML.

If you install it by hand instead, add the row yourself:

- insert:
    - id: dsh-fluxion
      name: dsh-fluxion

The package ships exactly that row in its own cordis.patch.yml. The DSH Desktop app has no dsh plugin path while it is running, so there the row is added to %DSH_HOME%\profiles\desktop\cordis.patch.yml once, by hand.

Once loaded, the desktop opens over the stock interface; 退出 Flux in the rail header puts the stock GUI back and remembers the choice, so the next launch is yours to decide.

What works today

| APP | Default | State | |---|---|---| | 终端 | tiled, open | Real PTY over remote.terminal.*: create → follow → write → close. 打断 sends Ctrl+C; 强杀 closes the process group. | | 代码编辑器 | tiled, open | Editable buffer, VS Code-style tabs, line numbers, centred column, completion popup. Monaco later. | | AI 对话 | tiled, open | Sends into the current DSH session through ctx.conversation.send, so replies land in the real conversation. | | Activity Monitor | tiled, open | AI commands / file changes as a live log with filter, follow-tail, and double-click edit. Seeded demo rows until the Host event bridge exists. | | 节点工作流 | disabled | Real graph: add/delete nodes, connect, rewire, Kahn topological dry run. Off by default; the rail switch turns it on. | | Live2D Stage | closed | Reserved seam for the separate dsh-flux-live2d plugin. |

Boot lands on the desktop, not the stock chat — "开启即 Flux" — while the stock GUI stays one click away and the preference is remembered.

Layout

There is no slot system. Slots needed occupancy tables, reflow, and conflict resolution, and produced more bugs than order. Instead:

  1. gridRects() lays the startup windows out once, then stops meddling.
  2. Windows are free: drag, resize, close, whoever wants.
  3. Snapping is decided by the pointer position at drag start/end — left/right half, four quarters, top-maximize — not by the window rect. DeskPane clamps dragged windows inside the canvas, so a rect-based edge test is unreachable.
  4. Released in the middle → the window stays put; it does not bounce back.

The rail collapses to icons; expanding it is an overlay above the canvas, so it never squeezes the windows beside it. The bottom panel sits under the canvas in normal flow.

Build from source

npm install
npm run typecheck
npm run build            # DSH plugin → lib/
npm run build:preview    # standalone demo → preview/

preview/index.html is self-contained (no server). It renders the same shell with the kernel's local stand-ins, so you can look at the UI without a Host.

Build contract (important)

DSH loads each browser plugin as a classic script that registers itself:

window.__ModuleLoader__.load({ id: 'dsh-fluxion', factory: (require) => { /* … */ } })

Dependencies (react, react-dom, react/jsx-runtime) come from the injected require. A plain ESM bundle is loaded as a script, its import statements cannot resolve, and DSH reports dsh-fluxion: import failed. tsdown.config.ts emits CJS for the client half and wraps it in that envelope; do not "simplify" it back to ESM.

src/styles/mono.ts is generated from flux.css by scripts/sync-css.mjs on every build, because the client bundle has no CSS pipeline. That script also strips a leading BOM: a U+FEFF byte turns .flux-shell into \uFEFF.flux-shell, which silently disables the entire stylesheet.

Architecture

src/
  index.ts                     DSH Host entry (no-op)
  client.tsx                   browser entry: shell.overlay + session probe
  preview.tsx                  standalone preview entry
  core/
    types.ts                   FluxApp / FluxAppProps contract
    kernel.ts                  registry + windows + activity + bridges
    event-bus.ts               typed domain bus
    activity-store.ts          AI-activity ring buffer
    hooks.ts                   useApps / useOpenWindows
    register-apps.tsx          built-in APP catalogue
  components/Tabs.tsx          reusable VS Code-style tab strip
  shell/
    FluxRoot.tsx               kernel lifetime; publishes it for other plugins
    FluxDesktop.tsx            DeskPane + portals + rail + bottom panel
    snap.ts                    grid math + pointer-based edge targeting
    window-geometry.ts         setBounds shim over DeskPane internals
  apps/
    terminal/                  driver (who may type) + pty (the bytes)
    chat/                      session-bound prompt sender
    editor/                    tabs, tokenizer, diagnostics, completion
    graph/ monitor/ live2d/
  plugins/live2d-placeholder.tsx
  styles/                      flux.css → mono.ts (generated) → install.ts

core/ imports no React components; apps/ never import DeskPane directly. APPs receive { kernel } and reach the desktop only through it.

Adding an APP

One call, no shell edits:

kernel.apps.register({
  id: 'bilibili',
  title: 'B站播放器',
  icon: '▷',
  hint: '悬停说明,也是侧栏副标题',
  component: BilibiliApp,
  placement: 'floating',   // or 'tiled'
  openByDefault: false,
});

The rail entry, the window, and portal mounting all derive from that record. register returns a disposer that unregisters the APP and closes its window.

Shared terminal: the rules

The terminal is one PTY with two possible drivers. TerminalDriver owns who may type; pty.ts owns the bytes.

  • States are 空闲 / AI 执行中 / 你。The header always shows which.
  • You always win. A keystroke hands you control immediately.
  • The AI can never take it back. It must ask, or wait for the idle timer.
  • Idle 1 minute hands control back to the AI — but only when no user process is in the foreground; a running npm test you started is not "idle".
  • AI input is written as whole atomic lines, never partial keystrokes.
  • A command refused because you took over is reported to the AI as not run, never as a result.
  • Ctrl+C is the interrupt; 强杀 closes the process group. Both are buttons.
  • Your commands are fed back to the session as command + exit code + last 20 lines, truncated.

Terminal wire contract (verified against dsh-api-terminal-controller):

environment(sessionId, signal)              -> RemoteResult<TerminalEnvironment>
create(sessionId, {id, cols, rows})         -> RemoteResult<WebTerminalInfo>
follow(sessionId, id, attachmentId, signal) -> AsyncIterable<TerminalFrame>
write(sessionId, id, attachmentId, data)    -> RemoteResult<void>
close(sessionId, id)                        -> RemoteResult<void>

Every non-stream call resolves to {ok:true,value} or {ok:false,error}, so the caller must unwrap. Frames are snapshot (full screen), output (incremental bytes) and state (process info). create rejects dimensions above environment().maxCols/maxRows, which is why the bridge asks first. We drive the Remote namespace directly instead of ctx.webTerminals.view() because a view binds an xterm emulator and requires acknowledging every render frame; these panes render plain text.

Session identity

shell.overlay runs at root scope and therefore has no Session. Terminals, prompt sending and model switching all need a sessionId, so the plugin also registers an invisible, session-scoped probe in conversation.session.header.actions; it reports the active session into the kernel. Without a session the terminal says 未绑定会话 and refuses to pretend.

Live2D: separate plugin

plugins/live2d-placeholder.tsx registers the stage so the seam is visibly reserved. The real package replaces that one call:

// dsh-flux-live2d
export function register(kernel: FluxKernel) {
  return kernel.apps.register({ id: 'live2d.stage', /* ... */ });
}

The kernel is published as window.__dshFluxKernel for exactly this case: a separately built plugin cannot import this module instance, so it reads the kernel from that key. Nothing in the shell, rail, or window manager changes.

Windows

Rail click toggles a window. DeskPane provides drag, edge resize, maximize, minimize, and edge snapping; React content is portalled into the window body. deskpane exports no React adapter and no public programmatic setBounds/unmaximize — window-geometry.ts writes its internal state and verifies the private shape at runtime, falling back to style-only writes.

Style

Pure black/white/grey — no hue anywhere, including DeskPane's snap guides, which are overridden to monochrome. Colours live in --flux-* tokens, so a theme preset is a token swap rather than a rewrite. The boot animation is reserved for the same layer.

Not implemented (and not faked)

  • Host event bridge: the DSH remote allowlist exposes no raw terminal/file events, so the Activity Monitor's live rows are seeded demo data.
  • File tree and md/image/video preview: needs a Host file bridge first.
  • AI background terminal, git UI, /plan /spec /goal, in-app browser console → AI, Ctrl+Alt+↑/↓ multi-cursor, theme presets, boot animation.

See docs/backlog.md for the full list and docs/dsh-plugin-contract.md for the hard-won plugin contracts.