dsh-semver

August 27, 2026 · View on GitHub

Semantic versioning toolbox for DeepSeek Harness (dsh) — parse, compare, range-check, increment, diff and sort semver strings. Zero runtime dependencies, pure logic, fully deterministic.

Agents are bad at version arithmetic. "Is 2.1.0-rc.1 newer than 2.1.0-beta.11?", "does 1.2.4-beta.1 satisfy ^1.2.3?" and "what does 1.2.4-beta.0 + prerelease become?" are exactly the questions LLMs get wrong — prerelease ordering, tuple-lock, caret/tilde upper bounds and prerelease bump rules are easy to misremember. This plugin turns those questions into deterministic tool calls.

Tools

ToolDescription
semver_parseParse a semver 2.0.0 string into major / minor / patch / prerelease / build, with a precise rejection reason for malformed input (1.2, 1.2.3.4, leading zeros, 1.2.3-01, …)
semver_compareCompare two versions → lt / eq / gt plus a human verdict (2.1.0 > 2.0.3). Build metadata is ignored for precedence (1.0.0+build.1 == 1.0.0)
semver_satisfiesCheck a version against an npm-style range, with the matched range normalized in the explanation
semver_incIncrement a version following npm semver.inc rules: major / minor / patch / premajor / preminor / prepatch / prerelease, with an optional prerelease identifier
semver_diffRelease-type difference between two versions (npm semver.diff): major / minor / patch / premajor / preminor / prepatch / prerelease
semver_sortSort a list of versions by precedence, ascending or descending, with build metadata as tie-break (npm semver.sort / rsort)

semver_inc — npm increment semantics (v0.2.0)

  • Plain bumps: 1.2.3 + major2.0.0, + minor1.3.0, + patch1.2.4.
  • Pre bumps with identifier: 1.2.3 + preminor (rc) → 1.3.0-rc.0; without identifier → 1.3.0-0.
  • Prerelease counter: 1.2.4-beta.0 + prerelease1.2.4-beta.1; 1.2.4-beta + prerelease1.2.4-beta.0; switching identifier restarts the counter (prerelease with rc1.2.4-rc.0).
  • npm quirks preserved: a pre-major/pre-minor/pre-patch version releases without incrementing (1.0.0-5 + major1.0.0); 1.2.0-5 + prerelease1.2.0-6 (no patch bump); build metadata is dropped; dotted identifiers are allowed (premajor with beta.12.0.0-beta.1.0); identifiers with leading zeros are rejected.

semver_diff — npm difference semantics (v0.2.0)

1.2.32.0.0 = major; 1.2.32.0.0-beta.1 = premajor; 1.2.4-beta.11.2.4-beta.2 = prerelease. npm special cases preserved: 1.2.3 vs 1.2.3-beta.1patch, 1.0.0-1 vs 1.0.0major. Equal precedence (build metadata ignored) → equal: true with no difference key.

Supported range syntax (npm-compatible subset)

  • Exact: 1.2.3, =1.2.3
  • Comparisons: >1.2.0, >=1.2.0, <2.0.0, <=2.0.0
  • Caret: ^1.2.3>=1.2.3 <2.0.0, with the 0.x rules (^0.2.3>=0.2.3 <0.3.0, ^0.0.3>=0.0.3 <0.0.4)
  • Tilde: ~1.2.3>=1.2.3 <1.3.0, ~1.2>=1.2.0 <1.3.0, ~1>=1.0.0 <2.0.0
  • Wildcards: 1.2.x, 1.x, * (bare partials 1.2 / 1 behave the same)
  • Hyphen ranges: 1.2.3 - 2.3.4 (inclusive endpoints; partial upper endpoints like 1.2.3 - 2.3<2.4.0)
  • AND / OR: >=1.2.0 <2.0.0, ^1.2.3 || >=3.0.0

Prerelease semantics (npm tuple-lock)

  • A plain range never matches prerelease versions: 1.2.4-beta.1 does not satisfy ^1.2.3.
  • A range with a prerelease lower bound only matches prereleases of the same [major, minor, patch] tuple: 1.2.3-beta.5 satisfies ^1.2.3-beta.2, but 1.2.4-beta.1 does not (releases like 1.2.3 still match).
  • Set includePrerelease: true (tool parameter or plugin config) to relax both rules.

Install

# into the web profile (dsh plugin has no default profile — always pass --profile)
dsh plugin --profile web add github:TYEclipse/dsh-semver

Verify the layer mounted:

dsh --profile web --dump-config | grep '== dsh-semver'

Usage examples

semver_parse("2.1.0-rc.1+build.42")
  → major 2, minor 1, patch 0, prerelease [rc, 1], build [build, 42]

semver_compare("2.1.0", "2.0.3")
  → "2.1.0 > 2.0.3" (gt)

semver_satisfies("1.2.4-beta.1", "^1.2.3")
  → false — prerelease does not match a plain range

semver_inc("1.2.4-beta.0", "prerelease", "beta")
  → 1.2.4-beta.1

semver_inc("1.2.3", "preminor", "rc")
  → 1.3.0-rc.0

semver_diff("1.2.3", "2.0.0-beta.1")
  → premajor

semver_sort(["1.2.3", "1.2.10", "1.0.0"], "desc")
  → ["1.2.10", "1.2.3", "1.0.0"]

Safety

All six tools are pure and offline: no network, no filesystem access, no shell, no dynamic evaluation. Inputs are validated with strict regexes and numeric checks; malformed versions, ranges and identifiers return explicit reasons instead of throwing.

Development

pnpm install        # dev dependencies only (esbuild allowBuilds is pre-configured)
pnpm build          # tsc → dist/ (committed; git installs do not run build scripts)
pnpm test           # vitest — 114 tests; anchors generated by npm semver 7.7.4 (independent oracle)
pnpm lint           # oxlint (src + test only)

License

MIT


中文简介

dsh-semver 是 DeepSeek Harness 的语义化版本号工具箱:解析(semver_parse)、比较(semver_compare,遵循 semver 2.0.0 优先级规则,build 元数据不影响比较)、范围匹配(semver_satisfies,支持 ^/~/>=/<=/通配符/连字符区间/||,含 npm 的 prerelease tuple-lock 语义),以及 v0.2.0 新增的版本号递增semver_inc,npm semver.inc 全规则:major/minor/patch/premajor/preminor/prepatch/prerelease + 可选预发布标识符)、版本差异判定semver_diff,npm semver.diff 语义,含 prerelease 特殊分支)与版本列表排序semver_sort,升/降序,build 元数据作次序裁决)。零运行时依赖、纯逻辑、确定性输出——LLM 经常算错的版本号问题(如 1.0.0-beta.11 > 1.0.0-beta.21.2.4-beta.0 递增后是 beta.1 而非 beta.011.2.4-beta.1 不满足 ^1.2.3)交给工具一次性算对。