Skip to content

Releases: Dantwz7/dsh-doc-router

v0.6.3

Choose a tag to compare

@Dantwz7 Dantwz7 released this 26 Oct 12:15

A stdout-contract fix. No routing verdict changed.

pymupdf 2.0 pulls in pymupdf-layout and an ONNX runtime, and those print banners and progress lines to stdout. The plugin spawns lib/docprobe.py and parses its stdout as exactly one JSON object, so that noise made every conversion fail with:

Unexpected token '=', "=== Docume"... is not valid JSON

main() now saves the real stdout, points sys.stdout at stderr for the whole run, and writes its own payload through the saved handle. Third-party chatter can no longer reach the channel the plugin parses.

Changed

  • lib/docprobe.py isolates library stdout: the plugin's JSON goes to the real stdout, everything else goes to stderr.

Verified against pymupdf 2.0 in an isolated venv

  • npm test — 102/102 pass
  • npm run fixtures — self-check passes, every fixture routes as expected
  • route, markdown, missing-file and --pages paths all emit clean JSON
  • Layout detection still reports columns: "multi-column", column_estimate: 2

Install: npm install dsh-doc-router@0.6.3

v0.6.2

Choose a tag to compare

@Dantwz7 Dantwz7 released this 26 Oct 10:47

An install-command fix. No code changed and no verdict changed.

pymupdf4llm 2.0 is an empty placeholder. Upstream moved the 4llm code into pymupdf 2.0 itself, and the shim exists only so that upgrading from pymupdf 1.x does not break pip. So pip install pymupdf4llm now installs nothing usable: import pymupdf fails, layout detection silently degrades to "format known, layout unknown", and the CI fixture step fails outright.

Every install hint now reads pip install -U pymupdf pymupdf4llm. Both names are needed because pymupdf 2.0 requires Python 3.11-3.15 while this plugin still supports 3.9: on 3.11+ the pair resolves to pymupdf 2.0 (which ships 4llm) plus the empty shim, and on 3.9/3.10 it resolves to pymupdf 1.x plus the real pymupdf4llm 1.x. One command covers both eras.

Note that pymupdf 2.0 also pulls pymupdf-layout, onnxruntime and numpy, so a fresh install is considerably larger than it used to be.

Changed

  • README.md, README.zh.md, CONTRIBUTING.md, .github/workflows/ci.yml, tests/fixtures/generate.py and the runtime PYMUPDF_HINT in lib/docprobe.py all give the two-package install command.

Install: npm install dsh-doc-router@0.6.2

v0.6.1

Choose a tag to compare

@Dantwz7 Dantwz7 released this 26 Oct 10:47

A compatibility-range fix. No code changed and no verdict changed.

engines.dsh and the @deepseek-ai/dsh-tools peer declared >=0.2.0-rc.1 <0.3.0-0. Under node-semver a prerelease version satisfies a range only when some comparator carries a prerelease and shares its [major, minor, patch] tuple. That range therefore accepts 0.2.1 while silently excluding every prerelease of 0.2.1 - including 0.2.1-rc.3, the DSH version this plugin was developed and verified on. Both fields now enumerate the tested line:

>=0.2.0-rc.1 <0.3.0-0 || >=0.2.1-rc.1 <0.3.0-0

0.2.2-rc.x stays excluded until it is tested. The range is a claim about what was run, not a switch, so it is widened only as far as the evidence goes.

Changed

  • engines.dsh and the @deepseek-ai/dsh-tools peer now accept the 0.2.1 prerelease line.
  • CONTRIBUTING.md section 5 records the prerelease-tuple rule, so the next peer range is not written as a single open-ended range.

Install: npm install dsh-doc-router@0.6.1

v0.6.0

Choose a tag to compare

@Dantwz7 Dantwz7 released this 04 Oct 11:33

[0.6.0] — 2026-10-04

A contract-and-coverage release. Routing verdicts are unchanged — the full
71-paper corpus re-runs to the same per-file table — but the places where the
plugin could quietly paper over a broken contract now fail loudly, and the format
branches that had no fixture are covered.

Added

  • scripts/check-readme-facts.mjs, wired into verify:docs and CI. The
    READMEs' per-fixture verdict table was the one claim check-doc-links.mjs never
    checked: renaming a fixture or moving a column estimate updated one side and
    silently rotted the other. The script parses EXPECTED out of
    tests/fixtures/generate.py with Node only (the docs CI job installs no
    Python) and asserts, for both READMEs, that every named fixture exists in
    EXPECTED, that est N / 估 N 栏 equals its column_estimate, and that the
    pipeline cell names exactly its recommend tokens. It found a real gap on its
    first run: sample.txt, sample.csv, sample.json and sample.html were
    fixtures but had never been listed in EXPECTED.
  • scripts/validate-routing.py, the corpus validator the READMEs referenced but
    the repository never contained. Both of them told readers to run
    _verify/validate_routing.py — a maintainer-only path that was never committed —
    so the "re-runnable in one command" claim could not be followed from a clone. The
    script now ships at scripts/validate-routing.py, takes the corpus root as an
    argument (the papers cannot be redistributed), imports the same lib/docprobe.py
    the tool uses, and is read-only on the corpus. Run against the recorded 71-PDF
    library it reproduces the manifest file for file: 71 files, 0 diffs.
  • Nineteen fixtures for format branches that had no coverage, generated
    targetedly rather than by re-running generate.py (a full run rewrites every
    binary, because PyMuPDF stamps each PDF with a random /ID and ZIP entries
    carry timestamps): sample.tsv / sample.xml / sample.ipynb (the
    _TEXT_EXT mappings), sample.md / sample-noext (plain text), the
    UTF-16/UTF-32 pairs with and without a BOM, sample-empty.txt,
    nul-bytes.bin / random-binary.bin (the control-character guard),
    magic-jpeg.jpg / magic-gif.gif / magic-webp.webp, sample.odt /
    sample.epub (the two _sniff_zip branches that had never executed, not
    even in CI) and sample.mp3.
  • UTF-16 and UTF-32 plain text are now recognised. The sniffer only ever tried
    UTF-8, so a UTF-16 file fell into unknown — whose advice ("try it, then use
    human judgement") is actively misleading for a file that is simply text.
    sniff_format now checks the UTF-8/UTF-16/UTF-32 BOMs and, with none, tries
    utf-8 → utf-16-le → utf-16-be. The order is load-bearing: a UTF-32LE BOM
    (FF FE 00 00) begins with the UTF-16LE BOM (FF FE).

Changed

  • doc_route throws when the probe returns no recommend, instead of guessing.
    It used to fall back to ['markitdown'], which dressed a broken contract up as a
    normal result — in the one direction the asymmetric bet forbids. The error names
    the probe script so the failure is diagnosable, and a test asserts that nothing
    is returned in that case.
  • pdf_markdown's non-PDF refusal follows noteLanguage. The probe has always
    produced a Chinese and an English note, but this one message was hardcoded
    English, so a zh session got a mixed-language result.
  • The doc-routing skill body follows noteLanguage. The most important text
    the model reads was a fixed Chinese template while noteLanguage defaulted to
    en. Description, whenToUse and content are now each available in both
    languages and selected together, so an English session no longer receives a
    Chinese skill. The English body is asserted to contain no CJK.
  • CI's integration job now runs on Windows as well as Linux. The unit job
    already covered Windows, but it uses local stubs and never starts Python —
    interpreter resolution, non-ASCII paths and backslash separators had zero CI
    coverage on the platform the plugin is developed on. The interpreter is resolved
    with sys.executable, because Windows has no python3 and a bare python can
    be the Microsoft Store alias.

Fixed

  • tests/manual/real-loader.mjs no longer resolves nothing when
    DSH_ASAR_DSH_ROOT is set without a trailing slash.
    createRequire reads such
    a path as a file and looks for node_modules one level up, where
    @deepseek-ai/dsh-tools does not exist; every lookup came back empty and the only
    symptom was an ERR_MODULE_NOT_FOUND for the plugin's own import. Both spellings
    now work, so the override documented in tests/manual/README.md is safe to use
    verbatim.

Notes

  • The UTF-16/UTF-32 detection is a heuristic, not a proof. A binary that
    happens to be valid UTF-16 and carries few control characters can still slip
    through; nul-bytes.bin pins the guard's direct case and random-binary.bin the
    other. Both directions are asserted, not every possible input.
  • Still unverified: the CI matrix needs a push to GitHub to be confirmed —
    locally only the YAML and the Windows $env:GITHUB_ENV step were exercised. As
    before, how npm renders > [!NOTE] alerts and <details> remains unknown
    (npmjs.com returns HTTP 403), and the npm package page's handling of relative
    tarball links is unverified.