New Features
-
Windows on ARM support — npm installs now select a native
aarch64-pc-windows-msvcbinary from thejscpd-windows-arm64-msvcplatform package on Windows ARM64. -
Clone baseline (
--baseline,--update-baseline,--fail-on-new-clones) — gate CI on new duplication only. A committed baseline file (e.g..jscpd-baseline.json) records content-hash fingerprints of accepted clones (the same hash the SARIF reporter emits aspartialFingerprints["jscpdCloneHash/v1"], with a multiplicity count per fingerprint); clones absent from it are reported as new, and--fail-on-new-clones[=N]exits 1 when more than N (default 0) new clones are found — independently of--threshold, so legacy duplication is tolerated while regressions fail the build.--update-baselinerewrites the file from the current run (creating it if missing) and prints added/removed fingerprint counts so baseline growth stays visible in CI logs and PR review. The baseline file is versioned, sorted one fingerprint per line for reviewable diffs and trivial merges, and configurable via thebaseline/failOnNewClonesconfig keys. New-clone info flows through the reporters:[NEW]markers and a "(N new)" found-count inconsole/console-full, per-cloneisNewplus thenewClones/newDuplicatedLinesstatistics injson, levelerrorinsarif, andjscpd_new_clones/jscpd_new_duplicated_linesgauges inopenmetrics. (#944) -
Ephemeral baseline from a git ref (
--baseline-from-ref) — stateless variant of the clone baseline for PR gates without a committed file:cpd --baseline-from-ref origin/main --fail-on-new-clones .checks the base ref's tree out into a temporary detached git worktree (removed afterwards; shells out togitlike blame does), scans it with the same detection configuration, and compares the current run against that in-memory fingerprint set — clones absent from the base ref are new. Costs a second scan of the corpus, where the committed--baselinefile needs only one. When the ref is missing (shallow CI checkout) it fails with a clear hint togit fetch origin mainor usefetch-depth: 0. Config keybaselineFromRef; conflicts with--baseline/--update-baseline. (#944) -
OpenMetrics reporter (
--reporters openmetrics) — writesjscpd-metrics.txtin the OpenMetrics text exposition format, ready to be declared as a GitLab CIartifacts:reports:metricsartifact so merge requests show duplication metric changes against the target branch. Exposes gauges for files/lines/tokens analyzed, clones found, duplicated lines/tokens with percentages (project total plus aformat-labeled sample per format), and detection duration in seconds. (#422) -
CodeClimate / GitLab Code Quality reporter (
--reporters codeclimate, aliasgitlab) — writesgl-code-quality-report.json(the filename GitLab's docs use) in the CodeClimate issue format, restricted to the subset GitLab defines as its Code Quality report format, ready to be declared as anartifacts:reports:codequalityartifact so duplicates appear as code quality issues in merge requests — unlike the SARIF reporter, which GitLab ingests as security vulnerability findings. Each clone yields an issue per fragment (each describing the other location, plus the CodeClimateother_locationsfield), with a deterministic fingerprint derived from the clone's content hash so GitLab can tell new issues from pre-existing ones across pipeline runs. Severity isminor, escalating tomajorfor clones absent from a configured baseline or when the run exceeds--threshold. (#958) -
Config discovery in
.config/(dot-config convention) — auto-discovery now also checks.config/jscpd.json(and.config/.jscpd.json) per the dot-config convention, between the root.jscpd.jsonand thepackage.jsonjscpdkey. A root.jscpd.jsonstill wins, so existing setups are unaffected; paths inside the config resolve against the working directory, as with other auto-discovered sources. (#979)
Bug Fixes
- Unknown
--formatvalues warn instead of silently matching nothing — a typo like--format cs(instead ofcsharp) used to scan 0 files and exit 0, indistinguishable from a clean codebase in CI. The CLI now prints a stderr warning naming the unsupported value and pointing to--list; custom formats declared via--formats-extsstay accepted. (#964) - Nix flake builds again — the flake pinned the hash of the mutable
channel-rust-1.97.tomlmanifest, which broke with a fixed-output hash mismatch when Rust 1.97.1 was published. The toolchain is now pinned to the exact patch version (immutable manifest), so the hash can no longer drift. (#976) - Windows:
--baseline-from-refno longer reports every clone as new — the format-suffix stripper treated the drive colon in Windows verbatim paths (\\?\C:\..., the formcanonicalizereturns) as a:formatsuffix and truncated the base scan's source ids to\\?\C, so every snippet read behind the fingerprint computation failed silently and the ephemeral baseline never matched. A colon followed by a path separator is now recognized as structural. Clone fingerprints are also line-ending agnostic now (CR stripped before hashing), so committed baselines survive CRLF/LF differences between platforms.
Other
- Glama MCP listing — the repository now ships a
glama.jsonmaintainer manifest and aDockerfilethat runs the stdio MCP server (jscpd --mcp), used by Glama to build and score the server listing - Signed releases — release artifacts are signed with SLSA provenance, and piped downloads in workflows are pinned (OpenSSF Scorecard)
Dependencies
- Bump Rust toolchain to 1.97.1 and
oxccrates to 0.147 in/rust - Bump
thiserrorto 2.0.20,globsetto 0.4.20,ignoreto 0.4.33,logto 0.4.34 in/rust
Thank You ❤️
- @luchsamapparat for contributing Windows on ARM support (#963)
- @dmromanov for proposing the OpenMetrics reporter (#422)
- @beanaroo for proposing the GitLab / CodeClimate Code Quality report format (#958)
- @MRDGH2821 for proposing config discovery from the
.config/subfolder (#979) - @zbcoding for reporting the silent unknown-
--formatbehavior (#964) - @eaves-dropper for reporting the Nix build failure (#976)
Published Packages
cpd-core@0.1.10on crates.iocpd-finder@0.1.12on crates.iocpd-reporter@0.1.10on crates.iocpd-tokenizer@0.1.11on crates.iojscpd@5.1.0on crates.iocpd@5.1.0on npmjscpd@5.1.0on npmjscpd-darwin-arm64@5.1.0on npmjscpd-darwin-x64@5.1.0on npmjscpd-linux-x64-gnu@5.1.0on npmjscpd-linux-arm64-gnu@5.1.0on npmjscpd-linux-x64-musl@5.1.0on npmjscpd-windows-x64-msvc@5.1.0on npmjscpd-windows-arm64-msvc@5.1.0on npm