dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Minecraft 26.3 mod 开发工具:按 JSON 实例登记启动真实的专用服与客户端,通过带鉴权的 HTTP 探针驱动两端,并对世界、UI 与日志状态做断言,覆盖 Fabric / Forge / NeoForge;每轮运行留下取证目录,且不随包分发任何游戏或加载器文件。需 JDK 25 与 Minecraft 26.3 实例。
English | 简体中文 | Status | Architecture | Deployment topology
Turn "the AI finished writing a mod, and now a human has to click through the game" into one executable pipeline: start a real test server → start a real client → connect + op → run a scenario JSON → collect evidence → tear down, across Fabric / Forge / NeoForge.
Target: Minecraft 26.3, Java 25, Windows.
This is development tooling, not a mod for players. The probe mod it ships exists only so that an agent can see and drive a real game.
lab/shared/.../ProbeServer.java): state, commands, blocks / NBT, drops, logs, tick control, action backend; block reads and writes take a dim parameter (unknown dimension → 400).lab/shared/.../ClientProbeServer.java + action/ClientActionBackend.java): UI widget tree, slots, scripted input (click / right-click / keys), screenshots, chat commands, /chat/tail (the chat and actionbar the client is currently showing, so you can assert "it really appeared on the player's screen").scripts/devrun.ps1): read the instance registry → start the server → wait for readiness → start the client → connect and op → run the scenario step by step → collect evidence → tear down; non-zero exit code on failure. Steps support retry (wait for a state to appear); assertions support exact match (json), field contains substring (contains), field does not contain substring (notContains), raw response body contains substring (text), and body does not contain substring (textNot); both probes expose GET /mods, which is how a cross-loader setup proves what each side actually loaded. LWJGL natives are extracted once into .cache/natives/<mc version>-<arch>/ (guarded by a file lock), so an evidence directory stays at a few dozen KB of logs instead of ~18 MB.tools/dsh-plugin/mcdev-devrun/): wraps the same orchestration as the mcdev_devrun / mcdev_scenarios tools, so an agent can call it directly.It provides capabilities, not answers to "what should be tested".
scenarios/ are examples and self-checks, not a coverage promise and not a recommended list.No server, client, or loader files. You prepare those on your own machine, then register them with the wizard:
instances/ (instance registry, contains local absolute paths) is not committed; scripts/setup-wizard.ps1 or scripts/register-instance.ps1 generates it locally.dist/ (build output), tmp/, lab/*/build/, lab/*/.gradle/ are ignored too.This repository continues the work of yan-mc/minecraft-mod-dev, and that must be stated explicitly:
| Item | Detail |
|---|---|
| Upstream tool | yan-mc/minecraft-mod-dev |
| Upstream license | MIT, Copyright (c) 2026 yan-mc (full text reproduced in NOTICE) |
| Inherited and rewritten | the probe Java in lab/shared/ + lab/{fabric,forge,neoforge}/ (from upstream lab/mcdev-probe/); tools/dsh-plugin/ (from upstream plugin/minecraft-mod-dev/) |
| Upstream shape | MC 1.20.1 + Forge only + Java 17; tool surface was mcdev_build / mcdev_prepare / mcdev_ui / mcdev_click |
| What changed here | MC 26.3; Fabric / Forge / NeoForge; Java 25; "start server + start client + connect + run scenario + collect evidence" collapsed into one devrun orchestration layer, with the tool surface mcdev_devrun / mcdev_scenarios |
Also:
fabric-example-mod (CC0 1.0), Forge MDK (LGPL 2.1), NeoForge MDK (MIT). The LICENSE / LICENSE.txt / TEMPLATE_LICENSE.txt files inside those skeletons are kept verbatim and are not relicensed under this repository's Apache-2.0.Requirements: JDK 25; a Minecraft 26.3 server directory you installed yourself (the level that contains eula.txt and server.properties).
Client-only setups do not need a server directory — that is what side: client in the instance registry is for.
Where the probe jar comes from (devrun copies it into the server's mods\; the client side goes through install-probe.ps1):
lab\fabric\gradlew.bat build (same for forge / neoforge); the artifact lands in lab\<loader>\build\libs\mcdev_probe-*.jar.-ProbeJar <path>, or set probeJar in the instance JSON.# 1) Register an instance (interactive wizard, or straight from the command line)
pwsh -NoProfile -File scripts\setup-wizard.ps1
pwsh -NoProfile -File scripts\register-instance.ps1 -Name local -Dir '<your server dir>' -Loader fabric
# 2) Environment check only (no game processes)
pwsh -NoProfile -File scripts\devrun.ps1 -Family fabric -PreflightOnly
# 3) Run the smoke scenario
pwsh -NoProfile -File scripts\devrun.ps1 -Instance local -Scenario scenarios\smoke.json
Install into DSH (optional; restart DSH afterwards so the plugin loads):
pwsh -NoProfile -File scripts\install-dsh-plugin.ps1 -Mode install
This repository is also a DSH plugin package (package.json declares dsh.bundle, and the repository root has cordis.patch.yml):
dsh plugin add github:7starsseeker/MCModsDevBridge
Or install the published npm package — a prebuilt tarball, so it needs no build approval step:
dsh plugin add mcmodsdevbridge
scripts/, scenarios/ and tools/ are installed together with the package, and the package root is the workspace root — the plugin finds it on its own (you can also point MCDEV_ROOT somewhere else). Restart DSH after installing. The package still contains no Minecraft server / client / loader files: register an instance as described above, or point -ProbeJar at a probe jar.
There are three client modes; pick one and write it into the instance registry's client.mode:
client.mode | Who starts the client | Good for |
|---|---|---|
gradle | The suite runs this repository's lab\<loader> runClient task | Changing the probe or the mod inside this repo; edits take effect immediately |
standalone | The suite builds a java command line from the version manifest your launcher left behind | Suite users: you only have an installed client, no gradle project |
external | You start it yourself | Any launcher, any shape; the suite just waits for the probe to come up |
standalone is "the launcher's last step", not another launcher: it reads versions\<version>\<version>.json (the self-contained manifest a launcher writes after merging), filters libraries by rules, expands ${...} placeholders, assembles the classpath and arguments, then starts java. It downloads nothing and fails loudly when a library is missing.
# Install the probe into a client game directory (mods/, config/mcdev-probe.properties, install manifest)
pwsh -NoProfile -File scripts\install-probe.ps1 -Side client -Loader fabric -Target '<TARGET_DIR>\client'
# Uninstall (only files recorded in the manifest whose sha256 still matches; nothing else is touched)
pwsh -NoProfile -File scripts\remove-probe.ps1 -Target '<TARGET_DIR>\client'
# Register an instance: server + standalone client
pwsh -NoProfile -File scripts\register-instance.ps1 -Name local -Dir '<server dir>' -Side both `
-Client standalone -ClientRoot '<HMCL_HOME>' -ClientVersion '26.3-Fabric' `
-ClientGameDir '<TARGET_DIR>\client-fabric'
Cross-loader setups (fabric server + forge client, or the reverse) need an explicit "loader": "forge" inside the client block:
"client": { "mode": "standalone", "loader": "forge", "version": "26.3-Forge-test", "root": "<HMCL_HOME>" }
Without it the client loader defaults to the server loader. It decides three things: which lab\<loader> project the gradle mode runs, which -Loader the install hint tells you to use, and the runtime warning when "the client probe reports loader X but the instance declares Y". The loader is not part of the protocol, so cross-loader connections do work — but the mod under test must exist for that loader, and a jar for the wrong loader is silently skipped. Only a /mods assertion on both sides can catch that.
Things already learned the hard way:
devrun clears stale listeners before starting).devrun checks <client dir>\config\mcdev-probe.manifest.json; if it is missing it fails immediately and tells you to run install-probe.ps1 first — "client started but probe not installed" would otherwise show up as a probe timeout, which is far more expensive to diagnose.devrun dismisses them according to each screen's own semantics before connecting, without writing your options.txt, without blind coordinate clicks, and without touching screens it does not recognise.side decides who is present: server (server only) / client (client only, nothing to start server-side) / both. If a scenario contains steps for a side that is not present, devrun fails at load time, not halfway through."Client-only mods" and "behaviour in singleplayer" cannot be verified on a dedicated server — in singleplayer the client starts an integrated server. The client probe exposes two generic endpoints (nothing mod-specific):
| Endpoint | Purpose |
|---|---|
POST /world/singleplayer?name=<id>&mode=normal|flat&gamemode=survival|creative&allowCommands=…&seed=…&reuse=true&backup=ask|skip|do | Create or open a singleplayer world; returns levelId / worldDir / renamed / openedExisting / backupAction |
POST /world/leave | Save and return to the title screen |
mode=flat uses the FLAT_ALL_DIMENSIONS preset: flat terrain, fast generation, good for tests; normal is regular terrain.reuse=true, an existing world of that name is opened (same data reused, so saves does not grow on every run); otherwise a new one is created, and a name collision gets -2 / -3 with renamed: true./status inWorld field until it is ready (scenarios/singleplayer.json is the example).backup=ask, devrun asks you the question (three options: write skip / write do / click it yourself), and results.json's nextStep.backup carries the same question — the suite never chooses for you. The deployment wizard (setup-wizard.ps1) states this rule up front in its completion banner.BackupConfirmScreen ("back up then join / skip and join"). backup=ask (the default) clicks nothing — whether to back up is your call; skip skips the backup and joins (use this in automated scenarios); do performs one backup. The action actually taken is reported as backupAction (ask / no-screen / skipped / backed-up / still-blocked).environment: "*" mods, so it proves "this works when installed in this client" — it does not prove "what happens when the dedicated server does not have this mod". For that you need two instances (each only sees its own /mods).# Client-only instance (no server to start; -Dir may be omitted)
pwsh -NoProfile -File scripts\register-instance.ps1 -Name sp -Side client -Loader fabric `
-Client standalone -ClientRoot '<HMCL_HOME>' -ClientVersion '26.3-Fabric' `
-ClientGameDir '<TARGET_DIR>\client'
pwsh -NoProfile -File scripts\devrun.ps1 -Instance sp -Scenario scenarios\singleplayer.json
devrun -Mods copies jars in for one run; it keeps no ledger and removes nothing. Run a second case and the jars from the previous one are still in mods\, so the new assertions no longer know what they are testing. Two scripts close that gap:
scripts/install-mod.ps1: installs the mod jar(s) under test into a target directory and records each file's sha256 in <dir>\config\mcdev-mods.manifest.json; -Remove deletes only files that were recorded and whose sha256 still matches (it stops if someone swapped the file; -Force overrides); -List shows the current state. It also reads Fabric's environment field and warns when you install onto the wrong side (for example a environment: "client" jar into a server).scripts/devrun-matrix.ps1 -Cases <file>: runs cases serially — install server/client mods → start devrun for that scenario → uninstall precisely → read the PASS=n FAIL=m line from summary.md to decide green/red.A case file looks like this (instance is the name you registered earlier):
{
"cases": [
{
"name": "fixture-both",
"instance": "fam-fabric",
"scenario": "scenarios/fixtures/fixture-both.json",
"serverMods": ["lab/fixtures/fixture/build/libs/mcdev_fixture-1.0.0.jar"],
"clientMods": ["lab/fixtures/fixture/build/libs/mcdev_fixture-1.0.0.jar"],
"note": "both sides installed: the handshake works in both directions"
},
{
"name": "expect-missing-half",
"instance": "fam-fabric",
"scenario": "scenarios/fixtures/fixture-client-missing.json",
"serverMods": ["lab/fixtures/fixture/build/libs/mcdev_fixture-1.0.0.jar"],
"expectFail": true
}
]
}
Fields: name / instance / scenario are required; serverMods / clientMods are jar paths relative to the repository root; expectFail: true means "this case is supposed to be red", and only red counts as expected (that is how you state "it must report an error when one half is missing"); note only shows up in the summary table. Evidence for each case lands in <EvidenceDir>\<case name>\, plus a matrix-summary.md at the root. Exit code 0 means every case matched its expectation.
Measured (2026-10-20): the three fixture cases were 3/3 as expected (tmp\matrix-fixtures); a deliberately inverted expectation reported "turned green unexpectedly", and a case with a missing jar was recorded as "crashed" while the run continued (tmp\matrix-negative). After every case both mods\ directories are back to their baseline and no manifest file is left behind.
The scripts assume no fixed paths; scripts/lib/Env.ps1 resolves everything:
| Value | Resolution order |
|---|---|
| java.exe | -JavaExe → $env:JAVA_HOME\bin\java.exe → PATH |
| proxy | -Proxy → the registry's proxy (asked during deployment) → $env:HTTPS_PROXY / $env:HTTP_PROXY → the IE proxy from the registry; -NoProxy or noProxy: true forces a direct connection |
The proxy is asked once, during deployment — never guessed, never hard-coded: step 4 of setup-wizard.ps1 asks "direct / through a proxy (enter the address) / use the system proxy", and the answer is stored in instances\<name>.json (proxy / noProxy); devrun and packaging reuse it. Anyone who can get this suite usually already has a proxy, but the port differs per machine — asking once beats guessing.
| Path | Contents |
|---|---|
lab/shared/ | The probe implementation shared by all three loaders (server / client / action backend / commands) |
lab/fabric/ lab/forge/ lab/neoforge/ | Build skeletons and entry classes for the three loaders |
scripts/ | devrun orchestration, devrun-matrix case matrix, instance registration, deployment wizard, probe install/remove (install-probe / remove-probe), mod-under-test install/remove (install-mod), packaging, DSH plugin install |
scripts/lib/ | Env.ps1 (java / proxy resolution), Launch.ps1 (builds a client command line from a version manifest) |
scenarios/ | Scenario JSON (smoke / server-only / actions / capabilities / singleplayer; capabilities is the suite's own self-check, covering cross-dimension block access, client chat/actionbar assertions and log-substring assertions) |
scenarios/fixtures/ | Six sample scenarios paired with lab/fixtures/ (both sides required / one side missing × client-only / server-only); only used to verify the suite's own assertion abilities |
tools/dsh-plugin/ | The DSH plugin (mcdev_devrun / mcdev_scenarios) |
docs/ | Feasibility study, phase-by-phase port records, deployment topology, status overview |
docs/examples/ | Reference material, not a capability list: one concrete mod demonstrating how to turn "features" into "assertable steps" (see below) |
lab/fixtures/ | The suite's own self-test samples (five minimal mods: both-sides-required 1, client-only 1, server-only 1, plus Forge/NeoForge builds of the same sample). Their only purpose is to prove that "which side it is installed on" can be asserted as PASS/FAIL; they are not templates and not example mods — see lab/fixtures/README.md |
Start with docs/STATE.md for current progress; docs/architecture.md covers the design; docs/deployment-topology.md covers instances and port allocation.
docs/examples/pairedportals/ is reference material: it takes one concrete mod (custom portals paired by sign text) and shows one way to think when translating features into automatically assertable steps — how to group them, where assertions belong, how to wait for timing, and what has to be checked by eye. Every step carries a note saying what it verifies.
It is not part of the suite and is not run by devrun by default: the suite only provides capabilities, it does not dictate what you test. Before writing cases for another mod, confirm with the user "which features to test, what observable change means success, and what can only be judged by eye", then write the steps.
Judgement comes only from the probes / logs / APIs (block state, command feedback, mod logs, client coordinates, …). This tooling does the first-round judgement; it does not replace hands-on testing — sound, animation and feel have no data channel and stay with the human.
This suite is the first-round automated test for DSH: it finishes the part that can be judged through probes / logs / APIs and leaves the part that needs eyes to the human. computer use is an official optional DSH plugin (@deepseek-ai/dsh-computer-use plus its cua-driver MCP provider) — it is not a capability of this suite. This suite does not implement screenshots, and does not pretend to simulate a human.
setup-wizard.ps1 checks whether it is enabled in <DSH_HOME>\profiles\*\cordis.patch.yml, records the result as computerUse in the instance JSON (enabled / disabled / absent / unknown), and prints the enablement hint (both package names); register-instance.ps1 -ComputerUse auto|on|off sets it explicitly. If DSH home cannot be found, pass -DshHome or set DSH_HOME.devrun.ps1 prints a "next step" and writes the same content into results.json's nextStep (ask=true means you should ask the user) — go straight to manual testing, or run another round with computer use (real mouse, real window, real screenshots).devrun -KeepRunning leaves the server and client running, th