Tools & Capabilities

dsh-plugin-gomoku

intelligent-guoxin/dsh-plugin-gomoku · ★ 0

intelligent-guoxin

A client-and-host Gomoku plugin for the DeepSeek Harness Web UI with LAN online play, vs-AI, AI-vs-AI, and hot-seat modes.

License
MIT
Added
2026-08-23
Maintenance
active
Install kind
github

No manifest check is available; listing does not imply compatibility or security review.

安装

dsh plugin --profile web add github:intelligent-guoxin/dsh-plugin-gomoku

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: en · Read Chinese README

Table of contents
  1. What it does
  2. How to play on the LAN
  3. Relay
  4. Package layout
  5. Install
  6. For other DeepSeek Harness users
  7. On this machine (development install)
  8. Tests
  9. Notes / known limits

English | 简体中文

Gomoku (五子棋) with LAN online play, vs-AI, AI-vs-AI and hot-seat modes — a client + host plugin for the DeepSeek Harness web UI.

What it does

  • Adds a floating 五 button (bottom-right of the chat UI) that toggles a draggable Gomoku window, plus a second launcher entry in the sidebar footer actions slot.
  • LAN online (联机对战): the host half (lib/index.js) starts a self-contained WebSocket relay (RFC 6455, zero dependencies) on port 34567 (configurable). Two browsers on the same LAN (or the same machine) play against each other: one creates a room and gets a 4-character code, the other joins with that code. The relay is authoritative — it validates turns and moves, detects five-in-a-row and draws, and supports resign, rematch (colors swap each game), disconnect handling and a small chat.
  • vs AI (人机对战): a greedy pattern-scoring AI (attack + defense).
  • AI vs AI (巅峰对决): watch two AIs play each other move by move, with replay speed control (slow / medium / fast) and pause/resume, so you can study openings and tactics at your own pace. The AI adds a small random jitter to near-equal moves, so every game is different — while it never gives up an immediate win or block.
  • Hot-seat (本机双人): two players, one screen.
  • Canvas board with wood texture, star points, last-move marker, win-line highlight and hover ghost stone. The window is draggable; Esc closes it.
  • Panel and inputs use fixed light-on-dark colors (independent of the host theme), so text is always readable.

How to play on the LAN

The DSH web GUI intentionally refuses --host 0.0.0.0 ("would expose remote code execution to the network"), so the web UI stays on loopback. LAN play is handled by the relay's standalone page on port 34567 instead — the partner needs no DSH install and the GUI is never exposed:

  1. Start the server normally (dsh web). The relay binds 0.0.0.0:34567 (Windows Firewall rules dsh-gomoku-34567 / dsh-gomoku-3080 are added on install; re-add them in an elevated shell if missing).
  2. Machine A (the host): open the DSH GUI, click 五 → 联机对战 → 连接 → 创建房间. Note the room code (e.g. K7QX).
  3. Tell your partner two things: the LAN address http://192.168.x.x:34567/ (find it via the relay's /info, or the panel's chat log after connecting) and the room code.
  4. Machine B: open http://<server-lan-ip>:34567/ in any browser (this is the standalone game page served by the relay — no DSH GUI, no install), enter a nickname, click 连接, type the room code, click 加入房间.
  5. Black moves first (the room creator). 认输 to resign; after a finished game 再来一局 requests a rematch — when both players agree, a new game starts with colors swapped.

Two players on the same machine can also play: one tab creates a room, a second tab (or another browser) joins with the code.

Optional: if you accept exposing the entire DSH web UI to the LAN, you may instead bind to the specific LAN interface with dsh web --host 192.168.x.x and have the partner use the full GUI at http://192.168.x.x:3080.

Relay

  • The relay listens on 0.0.0.0:34567 by default so LAN clients can reach it. Change the port with a loader config entry in cordis.patch.yml:
    - insert:
        - id: gomoku
          name: 'dsh-plugin-gomoku'
          config:
            port: 34568
    
  • http://<lan-ip>:34567/ (and /play) serves the standalone game page; http://<lan-ip>:34567/info returns JSON (host, port, active rooms / players).
  • Rooms are in-memory only: a waiting room expires after 60 minutes, and a game in progress ends (the remaining player wins) if an opponent disconnects.
  • Connections are long-lived: the server sends a keep-alive ping every 30 s (the browser auto-pongs), so an idle connection stays warm for hours; a connection that stops answering is reaped only after 90 minutes.
  • No authentication — it is a LAN game relay; do not expose port 34567 beyond your trusted network.

Package layout

package.json    dsh.client { platform: "web", inject: [@deepseek-ai/dsh-client-runtime] }
lib/index.js    host half — WebSocket relay server (node:http + node:crypto, no deps)
lib/client.js   browser half — hand-written bundle (no build step), the game
standalone/     gomoku.html — LAN client page served by the relay at /play
test/           engine + smoke + relay tests (run with `npm test`)

The client bundle is a factory registered via window.__ModuleLoader__.load and uses only platform seed modules (react, react/jsx-runtime, react-dom/client) plus the slots service, so it needs no bundler.

Install

For other DeepSeek Harness users

The plugin is a regular npm package with zero runtime dependencies (the host half uses only Node built-ins; the browser half uses the DSH platform's react seeds). Two ways to get it:

Option A — from the npm registry (once published):

dsh plugin --profile web add dsh-plugin-gomoku

Option B — directly from GitHub (no npm publish needed, repo must be public):

dsh plugin --profile web add github:Intelligent-GuoXin/dsh-plugin-gomoku

Then register the loader entry in the profile's patch layer (~/.dsh/profiles/web/cordis.patch.yml):

- insert:
    - id: gomoku
      name: 'dsh-plugin-gomoku'

Finally restart the server (dsh web), refresh the browser page, and the 五 button appears bottom-right of the chat UI. LAN play needs the firewall to allow inbound TCP on the relay port 34567 (and the standalone page is served by the relay at http://<lan-ip>:34567/).

If you fork or rename the package, update the entry's name to match, and dsh.client/exports["./client"] in package.json must stay intact for the browser half to load.

On this machine (development install)

  1. node_modules\dsh-plugin-gomoku is a junction to <profile>/dsh-plugin-gomoku; the profile package.json pins it with "dsh-plugin-gomoku": "file:./dsh-plugin-gomoku" so pnpm won't prune it.
  2. cordis.patch.yml inserts the loader entry:
    - insert:
        - id: gomoku
          name: 'dsh-plugin-gomoku'
    
  3. The host graph (and thus the relay) is loaded at server boot — restart the server (dsh --profile web / dsh web) once after installing, then refresh the browser page so the boot manifest includes the new row. (Patch hot-reload is unreliable mid-session: on the current instance the running server does not apply cordis.patch.yml changes live.)
  4. After that, editing lib/client.js hot-reloads via the client HMR chain; the host half still needs a restart for changes.

Tests

npm test                             # or run them individually:
node test/gomoku-engine.test.mjs     # pure engine: win detection, draw, AI
node test/gomoku-smoke.mjs           # client bundle: mount, slots, cleanup
node test/gomoku-relay.test.mjs      # host relay end-to-end: rooms, moves, win,
                                     # rematch, resign, leave, disconnect, dispose

Notes / known limits

  • Text inputs are uncontrolled so typing (including IME Chinese input) can never be reset by re-renders; nothing steals focus from them.
  • Keyboard input is ignored while typing in the composer / any input.
  • The relay is plain WebSocket (ws://); a page served over https:// would need wss:// (not supported by the built-in relay) — serve DSH over http on the LAN.
  • If you edit lib/index.js, standalone/ or the profile wiring, restart the server; lib/client.js changes apply on the next page refresh.