跳到主要内容
Supermarket
返回能力市场
MCP Server
programming
MIT

jscpd

Copy/paste detector for source code. 220+ languages, Rust engine, SARIF/HTML/badge reporters, GitHub Action, MCP server for AI agents.

kucherenkokucherenko
59/ 100

公开评测 · 综合采用结论

存在需要人工复核的风险或证据不足

查看评测依据 评测我的项目基于公开项目证据,非安全认证或安装推荐
6.5kstars
272forks
最近更新 15天前
评测生成时间(北京时间)
本报告引擎
v3.17.3
当前引擎
v3.17.3

规则版本一致,但报告只反映生成时的证据,不代表项目代码和安全状态始终不变。

重新评测此项目

进入后确认来源与额度,提交才会创建任务。

核对代码版本与送评文本摘要

仅记录实际送评的受限文本,不是完整仓库审计、安装结果或运行时安全保证。Stars、下载量和仓库元数据为采集时的独立信号,不属于此 commit 快照。

kucherenko/jscpd @ 3b636df0261bd8b5f606e65b5491270506b6557e

目录树:a3f9b961498cd060aac6630bb3f5521cb769d49e

README 来源:README.md

  • README.md · 35302 字符
    SHA-256: e5c87a5c6845686b0b5bf07da774c4f28485ef6d1f736da012dbb9d02097df8c
  • skills/code-migration/SKILL.md · 19885 字符
    SHA-256: be844a0ce56058fa9ed408916e6d62f827b8b43195eb3c91a8ab5700ab451acb
  • skills/codebase-refactoring/SKILL.md · 10199 字符
    SHA-256: 5eab466b683f1710f3dcb0aedb59acb399c5d1a8fc04c4082609c3715466fe45
  • skills/compare-codebases/SKILL.md · 13037 字符
    SHA-256: 06a2f10a84fe95e6d0d99026a4c8e8956c385b8922c5e8ee7833417a057566eb
  • skills/dry-refactoring/SKILL.md · 8447 字符
    SHA-256: 246f191f6af247b383eb4625f8d687ab3d4ddde4e2722d13a059caaa91074a1e
  • skills/jscpd/SKILL.md · 18341 字符
    SHA-256: f52d35538532f45e5b8aac5271ba27e88753eb3e2188ba987ab8ca86b0c10562
  • Dockerfile · 3043 字符
    SHA-256: 59836a6ab3ca1c79c07000866d3265c4e44c13dac7ca6fc7c5323d563c0f3e2a
  • pyproject.toml · 674 字符
    SHA-256: 98f1c6ed81646223aa25076381e9333133e89e19103bce53a7faa26e2378ea65
  • SECURITY.md · 1278 字符
    SHA-256: 5ccb001199ce962391cbc4c4bf4796dc1c1aae697fe82dbb0b3ead41de217f58
  • rust/package.json · 1054 字符
    SHA-256: 17312f8d0eb83877240558f7446fb6cc10e8ea3beab2afa7b9d34983f7f57268
  • benchmark/tools/package.json · 299 字符
    SHA-256: 9dc3b0d5e7d1390d8ef5e24fb125778bb105d1bc3e3d346b691758d3ad7fbb18
  • fixtures/dashboard-demo/package.json · 75 字符
    SHA-256: 2ff066bc4f782ed3854b1f7bdcdcfff0dd7fd8bdb062ee15c0a70d5cbdbcfa52
  • rust/basta/package.json · 1201 字符
    SHA-256: 44de33d2b3d770b0c9982e3295d96ca50d580ade1f0f56ff545c648088c9fd13
  • rust/jscpd/package.json · 1361 字符
    SHA-256: 12892635eec069500e683a6347e7c9659dac857c9a3b41dc3941a70f6648731c
  • fixtures/dead-code-demo/bundler/package.json · 105 字符
    SHA-256: 7b51418845b7602edf21395589347219bc0cc97cbe65d1509a3823d6b1f3a486
  • fixtures/dead-code-demo/components/package.json · 77 字符
    SHA-256: dccefbcf8cb547d798e7c58ca08a5d9301d1a6a9a02cfd3fdd4d4f62361b5d02
  • fixtures/dead-code-demo/config/package.json · 155 字符
    SHA-256: b7e2b33ecb434d533a4d343f42ad9aa1ebe2465fd7822bcfd2b9cbe311fdf32e
  • fixtures/dead-code-demo/monorepo/package.json · 59 字符
    SHA-256: b5540cf7528af83a49385d089d170406f553ffb559fe48ff765cf64404a116c1
  • fixtures/dead-code-demo/python/pyproject.toml · 99 字符
    SHA-256: 0228f7fe8d21ccf3ff8139f5ae5a50657142a3b543f8590dbde643b2724eff7b
  • fixtures/dead-code-demo/typescript/package.json · 100 字符
    SHA-256: 592f59d6b17217e0eb1fa13b164dd08e9c5cb6013ce808624d7cd9cf34a2b375
  • rust/npm/jscpd-darwin-arm64/package.json · 281 字符
    SHA-256: 5874ed2348b7a8c7cd4e3f7651832d03159eda61ca2350f3a82bd363d7feb9fb
  • rust/npm/jscpd-darwin-x64/package.json · 275 字符
    SHA-256: 5211e3894ddda1d2f2a487525b6b8196f93752bd82fe8cc10b1febc3d86c27cc
  • rust/npm/jscpd-linux-arm64-gnu/package.json · 308 字符
    SHA-256: 2df1be744d6bede61708000aeea51ff766abcfe4e1d9819aab9121e276122941
  • rust/npm/jscpd-linux-arm64-musl/package.json · 341 字符
    SHA-256: d062ec781f1f6908610b76bffbbeff6be8a22292e9845db9cdc2470313d27ce5
  • rust/npm/jscpd-linux-x64-gnu/package.json · 302 字符
    SHA-256: 1b44de485bedb738348e93ec60ad43e8128b90b19c4d46dadc7a5b8d153959ff

摘要对应送评 UTF-8 文本,可能为限额节选,不等于 Git blob SHA。来源由采集方提供,摘要本身不证明来源真实性。

Evaluation report

综合采用结论

59
D
满分 100 · 静态采用参考
谨慎采用高风险
决策摘要

存在需要人工复核的风险或证据不足

100%
高置信度
100
文档
78
安全
88
质量
100
活跃
60
采用
  • 基础评测完成+25/25确定性评分与静态安全扫描已完成
  • README 有效证据+25/2529,866 个去重后的有效字符
  • 独立证据来源+20/209 类非重复证据,重复文件不叠加
  • 仓库元数据+10/10已取得仓库状态与采用数据
  • 活跃记录+5/5已取得最近提交时间
  • AI 复核+15/15已完成结构化 AI 证据复核

本报告评了什么

综合分用于静态采用筛选,不是任务成功率,也不代表使用 Skill 后的能力提升。

静态检查范围
记录 25 个文件 · 116,298 字符
只检查采集到的受限文本与已知风险模式;未读取的脚本、依赖和运行环境不在结论内。
AI 内容复核
已使用
复核送评文本的说明和设计,不是安装测试或实际任务执行。记录缺失时不推断已使用或未使用。
真实任务效果
本报告未提供实测证据
没有使用/不使用 Skill 的任务对照、重复运行或耗时与 token 成本结果。采用前仍需在隔离环境验证自己的任务。

脚本引用覆盖

已纳入文本静态扫描 0 项/未纳入 7 项

被选 Skill:skills/code-migration/SKILL.md

仅检查被选 Skill 的直接脚本引用,一跳读取,不跟进 imports 或依赖;不执行脚本,脚本文本不送入 AI 质量复核。已纳入只表示文本已扫描,不代表安全。

仅统计本记录中的可识别引用;未纳入或未记录的部分保持未知,不按安全通过处理。

查看 7 项引用明细
  1. 1. 未找到文件

    引用位置:skills/code-migration/SKILL.md:33

    目标路径:skills/code-migration/*_test.go

    固定版本中未找到对应文件。

  2. 2. 未找到文件

    引用位置:skills/code-migration/SKILL.md:33

    目标路径:skills/code-migration/test_*.py

    固定版本中未找到对应文件。

  3. 3. 未找到文件

    引用位置:skills/code-migration/SKILL.md:33

    目标路径:skills/code-migration/*.test.ts

    固定版本中未找到对应文件。

  4. 4. 未找到文件

    引用位置:skills/code-migration/SKILL.md:75

    目标路径:skills/code-migration/billing.py

    固定版本中未找到对应文件。

  5. 5. 未找到文件

    引用位置:skills/code-migration/SKILL.md:75

    目标路径:skills/code-migration/billing.ts

    固定版本中未找到对应文件。

  6. 6. 未找到文件

    引用位置:skills/code-migration/SKILL.md:76

    目标路径:skills/code-migration/shipping.py

    固定版本中未找到对应文件。

  7. 7. 未找到文件

    引用位置:skills/code-migration/SKILL.md:76

    目标路径:skills/code-migration/shipping.ts

    固定版本中未找到对应文件。

How it works · 流程图

jscpd 迁移度量流程

Skill 描述从下载模型、运行比较、读报告到分阶段移植的连续步骤

AI 提取 · 证据约束

左右滑动查看完整图示

jscpd 迁移度量流程Skill 描述从下载模型、运行比较、读报告到分阶段移植的连续步骤模型就绪后比较输出配对与未匹配Tests 块驱动测试就位后移植每批后重跑下载嵌入模型准备运行 --compare度量读取报告分析移植测试阶段一移植代码阶段二
图示依据
  • • Setup:npx jscpd --semantic-download 下载模型
  • • Measure:npx jscpd --compare billing-py/ billing-ts/ 输出进度
  • • Phase 2:rerun the report after each batch
五维表现
该 Skill 用 jscpd --compare 量化迁移进度,并给出“先测试后代码”的完整流程,价值明确;最大缺口是依赖 548MB 嵌入模型下载,且类型、常量、UI 等不在比较范围。
质量证据
  • 通过: Agent Skills 格式校验 5/5 个通过
  • 通过: 5 个有效 Skill 含可核实的指令步骤或示例
  • 质量评审选取 skills/code-migration/SKILL.md;其余 4 个仅做格式扫描
  • Setup 节:npx jscpd --semantic-download 下载 548 MB CodeRankEmbed,需先征得用户同意
  • Measure 节示例输出:71% 5 of 7 functions in billing-py/ have a counterpart
  • Misses 节:types、constants、enums、SQL、UI markup 不在报告中,匿名函数不参与
  • Options 节:--min-tokens 30、--min-lines 5 决定计入总数的函数
  • Rules 节:Never game the percentage: no stubs, no renames made only for jscpd
采用建议
优势
  • 问题与用途描述
  • 有效 README
  • 安装或接入步骤
  • 可执行示例
  • 通过: Agent Skills 格式校验 5/5 个通过
关注点
  • 发现高风险的一键下载执行或安装命令
  • skills/codebase-refactoring/SKILL.md:description 未清楚说明何时使用该 Skill
  • skills/dry-refactoring/SKILL.md:description 未清楚说明何时使用该 Skill
  • skills/jscpd/SKILL.md:description 未清楚说明何时使用该 Skill
  • --compare 依赖 548MB CodeRankEmbed 模型下载,首次运行成本高
适合

Java 到 Kotlin、JS 到 Rust 等逐函数移植项目、iOS 与 Android 双端功能对齐检查、需要量化“迁移完成度”的团队

不建议直接用于

需要精确语义等价证明的迁移验收、无法下载大模型或完全离线的环境、以 UI 布局、SQL 为主的迁移

也有自己的公开项目?先看完证据,再用当前规则生成独立报告。

评测我的项目 →
文档证据
100/100
问题与用途描述10 分
有效 README12 分
安装或接入步骤14 分
可执行示例16 分
输入、参数或工具说明11 分
输出或结果说明9 分
限制、权限或边界12 分
错误处理或排障8 分
许可证信息5 分
结构化章节3 分
安全证据
高风险
发现高风险的一键下载执行或安装命令
unsafe-install-commandREADME.md:28high confidence
curl -fsSL https://jscpd.dev/install.sh | bash

修复:固定版本与校验和,先下载审查再执行,避免管道直接交给 Shell。

优先改进清单
  1. 01固定版本与校验和,先下载审查再执行,避免管道直接交给 Shell。
  2. 02修复 skills/codebase-refactoring/SKILL.md:description 未清楚说明何时使用该 Skill
  3. 03修复 skills/dry-refactoring/SKILL.md:description 未清楚说明何时使用该 Skill
  4. 04修复 skills/jscpd/SKILL.md:description 未清楚说明何时使用该 Skill
方法、证据与局限展开
数据来源

GitHub Repository API

扫描范围

25 个文件 · 116,298 字符

评测引擎

v3.17.3 · AI 内容复核:已使用(deepseek-flash)

局限
  • 静态评测不会安装或执行项目代码
  • 安全扫描基于高信号文件与已知模式,不能替代人工审计
  • 流行度只反映采用程度,不代表安全或工程质量
  • 脚本覆盖仅针对被选 Skill 中可识别的直接引用;不递归分析依赖,不执行脚本,脚本未送入 AI 质量复核
  • 发现 5 个 Skill;质量复核只评审 skills/code-migration/SKILL.md,其余 4 个仅做格式扫描

30 天热度趋势

README

jscpd

npm version npm downloads skills.sh installs Crates.io Version NPM License jscpd CI Coverage Duplication in rust/ Socket Badge OpenSSF Scorecard OpenSSF Best Practices Follow on X

Duplicate code detector for 220+ languages — plus dead code, complexity hotspots, duplication and health trends over git history, and one health score for the whole codebase. Rust engine, self-contained binary, AI-ready with an MCP server and a token-efficient reporter.

Documentation: https://jscpd.dev

jscpd tokenizes each of its 224 supported formats the way that language defines it — its own comment and string rules, not generic text — then finds duplicated token sequences across files with a rolling Rabin-Karp hash. Opt-in passes catch copies that differ only in names or values (Type-2) or that have a few edited lines (Type-3), and an experimental one uses a code embedding model for functions that do the same thing written differently (Type-4). See How detection works for the full mechanism, and Supported formats for the full list.

Beyond duplicates, jscpd also finds dead code (--dead-code), ranks files by complexity (--complexity), tracks duplication and health over git history (--history), and rolls it all into one health score (--health) — see Features below.

Quick Start

# macOS / Linux
curl -fsSL https://jscpd.dev/install.sh | bash

# Windows (PowerShell)
irm https://jscpd.dev/install.ps1 | iex

# No install — run once with npx (Node.js)
npx jscpd .

Then scan a project:

jscpd /path/to/code

Other install methods

MethodCommandNotes
npmnpm install -g jscpdInstalls the jscpd command; prebuilt binary, no Node.js at runtime
npm (cpd command)npm install -g cpdSame binary, exposed as cpd
PyPIpip install jscpdPlatform wheels with both commands; also pipx install jscpd, uv tool install jscpd, or uvx jscpd . to run without installing
Cargocargo install jscpdBuilds from crates.io; installs both jscpd and cpd
Homebrewbrew install jscpdmacOS / Linux
Nixnix run github:kucherenko/jscpd -- /path/to/codeOr nix profile install github:kucherenko/jscpd
Dockerdocker run --rm -v "$PWD:/src" ghcr.io/kucherenko/jscpd .Multi-arch image built from the release binaries

GitHub Action

- uses: kucherenko/jscpd@v5
  with:
    threshold: 5

Uploads SARIF results to GitHub Code Scanning by default. See CI & Pre-Commit Hooks for all inputs and outputs.

Documentation

DocumentDescription
Rust engineInstallation, CLI reference, reporters, baseline, summary, complexity, dashboard, blame, config file
AI-ReadyAI reporter, agent skills, MCP server
Editorsjscpd --lsp, the language server: setup for Neovim, Helix, Sublime Text, Emacs and JetBrains IDEs
Programming APIRust API (cpd-finder crate)
CI & Pre-Commit HooksGitHub Action, Docker image, pre-commit hooks
Packagesnpm packages and crates that make up a release
Supported formatsAll 224 formats with their file extensions
Runnable demosOne fixtures/<feature>-demo/ directory per feature, each README lists the commands with their expected output

Features

jscpd v5 is a Rust engine that ships as a self-contained binary — no runtime required — under two npm names (jscpd installs the jscpd command, cpd installs cpd), on PyPI, crates.io, Homebrew, Nix, Docker, and as a GitHub Action.

Duplicate detection

  • Language-aware tokenization — per-format comment and string syntax for all 224 formats, the oxc parser for JavaScript/TypeScript/JSX/TSX, embedded-language extraction for Vue, Svelte, Astro, Markdown and Razor, and keyword/identifier/literal classification, so a clone is a repeated sequence of language tokens, never a repeated run of text (see How detection works)
  • 224 language formats, with cross-format detection (Vue SFC, Svelte, Astro, Markdown) and --cross-formats groups to match clones across JavaScript and TypeScript
  • Type-2 clones — --ignore-identifiers, --ignore-literals and --ignore-annotations find blocks that differ only in names, literal values or annotations, reported as renamed. A name must stand for one name on the other side, so x = x + x does not match d = a + b; --ignore-identifiers=blind matches any names, as 5.4 did (see docs)
  • Type-3 near-miss clones — --max-gap-lines N merges a copy with a few inserted or changed lines into one similar clone with a similarity score; --similarity compares whole functions of JavaScript, TypeScript, Python, Java, Kotlin, Scala, C#, Go, Rust, C, C++, PHP, Ruby, Swift and Clojure by the subtrees of their normalized syntax trees, in code blocks of Markdown and components as well: renamed locals (each standing for one name on the other side) and other literals match, other called functions or operators do not, and test files are left out; the edn reporter lists every pair with its score (see docs)
  • Type-4 semantic clones (experimental) — --semantic embeds the functions of JavaScript, TypeScript, Vue, Svelte, Astro, Python, Rust, Go, Java, Kotlin, C#, C, C++, PHP, Ruby, Scala and Swift files with a code embedding model, either one jscpd runs itself (after jscpd --semantic-download once) or any OpenAI-compatible API, and reports functions that do the same thing written differently: the same feature implemented twice in one language, or a rule your Rust backend enforces and your Svelte frontend repeats (see Semantic clones below)
  • Port progress and parity (experimental): jscpd --compare python/ typescript/ pairs the functions of two folders with the same model and lists which functions of each have a counterpart in the other: what is left to port to another language or platform, or what the Android version of an app has that the iOS one lacks (see Comparing two codebases below)
  • Boundaries: rules in .jscpd.json keep the code of a module, a folder, a file or a method inside its boundary, such as money that only the backend may calculate. A copy of it in a place a rule keeps it out of fails the run, whether someone copied it, edited the copy or wrote the logic again in another language (see Boundaries below)
  • Clone kinds everywhere — exact, renamed or similar in the console, JSON (kind, similarity, method), XML, HTML, Xcode, SARIF (jscpd/duplicate-code, jscpd/renamed-code, jscpd/similar-code, jscpd/similar-function, jscpd/semantic-code) and Code Climate output; default runs still report only exact clones
  • --kind — keep only the clone kinds you care about: --kind renamed, or --kind gap,ast for near-miss clones only. Statistics and --threshold follow the filter; a kind whose detector is off warns, an unknown kind errors (see docs)
  • 15 reporters: console, console-full, json, xml, csv, html, markdown, badge, sarif, codeclimate, openmetrics, ai, xcode, threshold, silent
  • Clone baseline — gate CI on new duplication only. --baseline .jscpd-baseline.json --fail-on-new-clones[=N] tolerates legacy clones and fails the build on regressions; --baseline-from-ref origin/main does the same without a committed file (see docs)
  • Only the files you changed — jscpd --changed . reports the clones of the files git status lists, matched against the whole project, and marks the ones HEAD didn't have as new; --changed-only compares the changed files only with one another. The baseline of HEAD is saved on the first run and built again after a commit (see docs)
  • Exit codes you can gate on — an unknown --format, a missing scan path or a reporter that can't write its file now exit 1 instead of passing with an empty report; --fail-on-empty fails a scan that analyzed no files (see Exit codes)
  • GitLab-ready reporters — codeclimate (gl-code-quality-report.json) and openmetrics (jscpd-metrics.txt) plug into artifacts:reports
  • Git blame with side-by-side author comparison (--blame --reporters console-full)
  • --skip-local — report only clones that cross the scan roots: jscpd packages/api packages/web --skip-local drops pairs inside either tree, keeping only api-to-web duplication
  • --skip-isolated — ignore duplication between monorepo folders owned by different teams (--skip-isolated "packages/team-a|packages/team-b")

Beyond duplication

  • --history — duplication and health trend over git history: jscpd --history scans the current folder over the last 30 commits of the branch, jscpd src --history v5.0.0..HEAD the commits of a range, a merged branch as its merge commit. It prints bar charts of the duplication percentage and the health score, a per-commit table with the change between points, the trends with the score of each health dimension at both ends, and how far --threshold could be tightened; --health and --dashboard print the series too (see docs)
  • --dead-code — find code nothing runs, not just code written twice: unused files, exports, declarations and imports across JavaScript, TypeScript and Python. Builds the import graph from your entry points (package.json, pyproject.toml, framework conventions) and walks it, so dead code cascades — a helper whose only caller is dead gets reported too, each finding with a confidence score and, below 100, why it might be wrong. Also ships standalone as basta (see docs)
  • --summary — refactoring hotspots straight from the scan: top files and folders by tokens, lines, size, and a complexity estimate (see docs)
  • --complexity — the complexity ranking alone, without clone detection: most complex files and folders from one tokenizing pass, in the console, ai or json (see docs)
  • --health — one 0-100 score with a grade, from the share of code that's duplicated, dead, or concentrated in complex files; size-aware, calibrated on 42 open-source projects, extensible with coverage, test or security metrics via --health-input. Console badge, JSON, SVG badge (see docs)
  • --dashboard — the whole picture on one screen, under the health badge: project size with the largest code files, duplication by clone kind with the most duplicated files, the most complex files, and dead code by category for JavaScript, TypeScript and Python (see docs)

AI and operations

  • --mcp — built-in MCP server over stdio with fully described tools: point your AI assistant at the binary and it can check a snippet against your codebase for all four types of clone (exact, renamed, near-miss and semantic), list a file's clones, and compare two folders function by function (see docs)
  • --lsp: a language server over stdio. Clones, similar functions, semantic clones, dead code and complexity show up as diagnostics in the files you edit and follow the text as you type, each analysis with a switch of its own (see Editors below)
  • AI reporter — token-efficient output for LLM pipelines (~79% fewer tokens than console)
  • Prebuilt for 8 platforms — macOS arm64/x64, Linux arm64/x64 (glibc and musl), Windows arm64/x64
  • --workers — control parallelism for file tokenization and detection (default: all CPU cores)
  • Config discovery — .jscpd.json, .config/jscpd.json, or the jscpd key in package.json
  • Symbolic links are skipped unless --follow-symlinks — v4 followed them by default. With the flag, a file reached through a link is reported by the path it was found at, and a file reachable through several paths is counted once
  • Quiet in pipelines — tips and sponsor lines print only on an interactive terminal; --no-tips, CI or JSCPD_NO_TIPS switch them off everywhere

See the Rust docs for the full CLI reference and rust/CHANGELOG.md for release notes.

Looking for v4?

jscpd v4 (TypeScript engine, Node.js API, LevelDB/Redis stores) is maintained on the master-v4 branch and published as jscpd@4 / the latest-4 dist-tag. README-v4.md describes it in one page (install, CLI, API, packages, maintenance policy); the same content is at https://jscpd.dev/getting-started/v4.

Packages

PackageRegistryDescription
jscpdnpmInstalls the jscpd command (prebuilt binary via platform packages)
cpdnpmInstalls the cpd command (same binary)
jscpd-<platform>npmPlatform binary packages pulled in as optional dependencies: jscpd-darwin-arm64, jscpd-darwin-x64, jscpd-linux-x64-gnu, jscpd-linux-arm64-gnu, jscpd-linux-x64-musl, jscpd-linux-arm64-musl, jscpd-windows-x64-msvc, jscpd-windows-arm64-msvc
jscpdPyPIPlatform wheels repacked from the release binaries; installs both jscpd and cpd commands
jscpdcrates.ioCLI crate; installs both jscpd and cpd binaries
cpd-corecrates.ioDetection algorithm (Rabin-Karp rolling hash), data models
cpd-tokenizercrates.ioSource code tokenization (224 formats)
cpd-similaritycrates.ioStructural similarity (--similarity): functions from tree-sitter syntax trees and a Clojure reader, normalized trees and their subtree fingerprints, and the exact search for pairs
cpd-findercrates.ioFile walking, orchestration, git blame — the library entry point
cpd-reportercrates.ioOutput formatting (15 reporters, duplication and dead code)
cpd-semanticcrates.ioSemantic clones (--semantic, experimental): function extraction, code embeddings from a model run in-process or an API, pairing
bastanpm / crates.ioDead code detection — unused files, exports, symbols and imports for JavaScript, TypeScript and Python. Installs the basta command; the same engine backs jscpd --dead-code

Who Uses jscpd

The jscpd npm package is downloaded 10M+ times per month, and ~5,000 repositories declare it on GitHub's dependents graph.

Bundled by analysis platforms:

  • GitHub Super Linter — official GitHub linter aggregator, bundles jscpd as its copy/paste detector and runs it by default; 15,500+ workflow files on GitHub reference Super Linter (as of Sep 2026)
  • MegaLinter — open-source linter aggregator for CI, ships jscpd in every flavor including ci_light
  • Codacy — automated code analysis platform, jscpd powers the duplication engine

Explicitly enabled in Super Linter (VALIDATE_JSCPD: true) by dozens of public repositories, including:

  • A2A — Google's Agent2Agent protocol (25k+ stars)
  • RimSort — mod manager for RimWorld (1.2k+ stars); also runs jscpd directly with its own .jscpd.json
  • Contact Center AI samples — official Google Cloud samples, with a dedicated jscpd config
  • Drifty — open-source download manager

Used in notable projects:

Recommended aggregator settings

Super Linter and MegaLinter both run jscpd with threshold: 0 by default, which fails a build on any duplication at all, including clones that were already there. That is the most common reason projects end up setting VALIDATE_JSCPD: false. Gate on new duplication instead, and leave the threshold out:

jscpd . --baseline-from-ref origin/main --fail-on-new-clones 0

--baseline-from-ref scans the base ref's tree with the same configuration and marks the clones that are absent from it as new, and --fail-on-new-clones 0 fails the run when there is one. Every clone is still reported, and --threshold still compares the duplication of the whole tree, so keep threshold: 0 out of the config, or the old clones fail the build as before. The base ref has to be in the checkout: with actions/checkout set fetch-depth: 0, or run git fetch origin main first, otherwise jscpd stops with an error. jscpd needs the whole tree to find clones, so VALIDATE_ALL_CODEBASE: false does not narrow the scan.

Super Linter takes the same gate from .github/linters/.jscpd.json, on v9.0.0 or later: see Using jscpd with Super Linter.

When several linters write into one reports directory, give jscpd its own file name so parallel runs cannot overwrite each other:

jscpd . --reporters json --output reports --report-name megalinter-jscpd
# -> reports/megalinter-jscpd.json

--report-name sets the base name for the json, xml, csv, html, markdown, sarif and edn reports, and defaults to jscpd-report. It can also be set as reportName in .jscpd.json, or with the report-name input of the GitHub Action. The name is a plain file name, so a path, an extension or an empty name is an error. The badge, OpenMetrics and CodeClimate files (jscpd-badge.svg, jscpd-metrics.txt, gl-code-quality-report.json) keep their names, so the pipelines that read them keep working. When two runs write those too, give each run its own --output.

Benchmark

Compared against other copy/paste detectors on the fixtures/ corpus (547 files, 150+ formats), default thresholds, wall-clock time on Apple Silicon:

ToolTimeFilesClonesDup Lines
jscpd84ms3472129,133
jscpd-rs111ms36022210,317
Duplo162ms31951813,049
Fallow dupes164ms34103,137
Simian964ms54742415,351
PMD CPD35.980s71562,267

Methodology, cross-format detection and AI-token-efficiency comparisons: benchmark/BENCHMARK.md. Re-run with benchmark/benchmark.sh.

Semantic clones (experimental)

Token matching finds code that someone copied. It cannot find two functions that do the same job with different code, such as a validation rule that a Rust backend enforces and a Svelte frontend writes again, or two helpers that two people wrote for the same task. --semantic looks for these pairs with a code embedding model. jscpd turns every function into a vector and reports two functions as a semantic clone when each is the other's closest match and their vectors are similar enough.

jscpd --semantic-download                                    # once: CodeRankEmbed, 548 MB, into the jscpd cache
jscpd --semantic src/                                        # pairs within one language and across languages
jscpd --semantic --semantic-scope cross backend/ frontend/   # only pairs across languages
jscpd --semantic --kind semantic -r ai .                     # only semantic clones, one line each

The model runs inside jscpd on the CPU, so a scan makes no network call. The default model is CodeRankEmbed (MIT), and jscpd can also run jina-embeddings-v2-base-code. jscpd --semantic-models lists nine models with the thresholds jscpd calibrated for each one, and --semantic-model picks one of them. To use a model that jscpd does not run itself, point --semantic-url at an OpenAI-compatible embeddings API such as Ollama, LM Studio or llama-server. jscpd reads an API key only from the JSCPD_SEMANTIC_API_KEY environment variable.

jscpd compares the functions of JavaScript, TypeScript, JSX, TSX, Vue, Svelte, Astro, Python, Rust, Go, Java, Kotlin, C#, C, C++, PHP, Ruby, Scala and Swift files. A pair within one language needs a higher similarity than a pair across languages, because code in one language resembles other code in that language whatever it does. With CodeRankEmbed the two thresholds are 0.4125 and 0.6375, and --semantic-threshold and --semantic-same-threshold change them. jscpd caches the vectors, so a second run embeds only the functions whose code changed.

The console, ai, JSON, SARIF and Code Climate reporters mark these clones as kind semantic with their similarity. The mode is experimental. Besides real duplicates it reports related code, such as a client function and the server endpoint it calls, so review a pair before you merge the two functions. The docs describe the rules, fixtures/semantic-demo is a runnable example with a Rust backend and a SvelteKit frontend, and Embedding Models compares the nine models.

Comparing two codebases (experimental)

--compare takes two folders and pairs their functions with the --semantic model. During a port, such as a library moving to another language or an iOS app moving to Android, it shows which functions of the source already have a version in the target and which are still to port. For two implementations of one app, such as the Android and the iOS one, it shows what both have and what only one of them has.

jscpd --compare python typescript        # progress of a port: the source first, the target second
jscpd --compare ios android -r console-full  # parity, with every pair and its similarity
Code
 71% 5 of 7 functions in python have a counterpart in typescript
 80% 4 of 5 functions in typescript have a counterpart in python

Paired under other names (1):
  python                        typescript              similarity
  billing.py:28 tax_for_region  billing.ts:27 salesTax  0.87 high

Only in python (2):
  billing.py (1)
    46  due_date                6 lines
  shipping.py (1)
    18  estimate_delivery_days  8 lines

Tests
 75% 3 of 4 tests in python have a counterpart in typescript
100% 3 of 3 tests in typescript have a counterpart in python

A function pairs with its counterpart when the model finds them each other's closest match. A short function the model cannot place pairs by name when the names match once case and underscores are ignored (encodeBinary, encode_binary) and the code is similar enough. jscpd measures tests and code in two blocks and pairs a test only with a test. It tells a test by the conventions of its language, such as *_test.go, test_*.py, *.test.ts, src/test/ or Rust's #[cfg(test)]. Every pair has its similarity and a level, high, medium or low, on the scale of the model, and the report lists the pairs under other names on their own, since nobody finds those by searching for a name. The console, JSON and Markdown reporters print the totals per side and per file with the mean similarity, the functions with no counterpart, and the pairs. -r html writes a migration map, a page that draws both sides as dependency graphs with the pairs bridging them and marks the functions ready to port, the ones whose callees all have a counterpart already. A second tab lists the same pairs as a table you can sort. The docs describe the rules and how they did on two real codebases, and fixtures/compare-demo is a runnable example.

Boundaries

Some code must stay where it is. In a bank or a shop only the backend calculates money, and a frontend that calculates it too shows one price and charges another as soon as the formula changes. A boundary rule names that code and the places its copies must stay out of:

{
  "boundaries": [
    {
      "name": "money",
      "code": ["backend/billing", "backend/loans/Interest.kt#monthlyPayment"],
      "notIn": ["web/**", "mobile/**"],
      "allow": ["web/e2e/**"]
    }
  ]
}

code takes modules, folders, files or methods, by name (#monthlyPayment) or by a pattern of names (#(*Payments)). Without notIn, every place outside code counts. Every clone run checks the rules with every method jscpd has: token clones for copy-paste, --similarity for an edited copy, and the model of --semantic for the same logic written again in another language, such as the annuity formula of a Kotlin backend in a TypeScript widget. A copy fails the run with exit code 1:

Boundaries:
money: 1 copy outside the boundary
  web/src/loan/payment.ts:4-14 monthlyPayment
    looks like backend/loans/Interest.kt:8-15 monthlyPayment (semantic ~0.82)

The logic written again in another language needs the embedding model, so run jscpd --semantic-download once, or point --semantic-url at an embeddings API. Without it jscpd prints a warning and still finds the copies and the edited copies. Each rule can set its own thresholds, and disable turns kinds of copies off: "disable": ["semantic"] for a rule that needs no model, or ["ast", "semantic"] for one that reports copy-paste only. The docs describe the rules, and fixtures/boundaries-demo is a runnable example.

Editors

jscpd --lsp runs jscpd as a language server. An editor starts it for a workspace, and the files you edit get what jscpd finds as diagnostics, updated as you type: clones by default, and similar functions, semantic clones, dead code and complexity when --lsp-analyses or the lsp section of .jscpd.json turns them on. A clone comes with "Go to the other copy" and "Ignore this clone" actions. In Neovim 0.11:

vim.lsp.config('jscpd', { cmd = { 'jscpd', '--lsp' }, root_markers = { '.jscpd.json', '.git' } })
vim.lsp.enable('jscpd')

Editors has the setup for Helix, Sublime Text, Emacs and JetBrains IDEs too, and fixtures/lsp-demo is a project that shows each analysis. Clients for VS Code and Zed will follow in a repository of their own.

AI-Ready Features

jscpd integrates into AI-powered workflows through three mechanisms:

AI Reporter

Token-efficient output for LLM pipelines (~79% fewer tokens than the default console reporter):

jscpd --reporters ai /path/to/source              # compact clone list
jscpd --reporters ai --summary /path/to/source    # + compact codebase summary
jscpd --reporters ai --complexity /path/to/source # most complex files, no clone detection

Agent Skills

Installable skills that teach AI coding assistants how to use jscpd, refactor detected duplications, and clean up a codebase more broadly:

SkillPurposeInstall
jscpdTool reference — CLI options, AI reporter format, config syntaxnpx skills add kucherenko/jscpd --skill jscpd
dry-refactoringGuided refactoring workflow — read clones, choose strategy, apply, verifynpx skills add kucherenko/jscpd --skill dry-refactoring
compare-codebasesHow --compare pairs the functions of two folders, and a step-by-step way to compare two folders and check the resultnpx skills add kucherenko/jscpd --skill compare-codebases
code-migrationPort a codebase to another language or framework, tests first and code second, with a coverage map binding functions to their tests and --compare as the progress measure; or check two implementations for paritynpx skills add kucherenko/jscpd --skill code-migration
codebase-refactoringBroader health pass — fix duplication, then remove/refactor dead code, then simplify the biggest/most complex files, prioritized from --healthnpx skills add kucherenko/jscpd --skill codebase-refactoring

After installation, ask your agent to "find and fix code duplication" and it will invoke jscpd with the right options and act on the results — or "clean up this codebase" for the broader pass, or "port this Python library to Rust" for a migration.

MCP Server

jscpd --mcp /path/to/project scans the project and serves the Model Context Protocol over stdio. An assistant can check a snippet against the codebase before writing it, list a file's clones, scan the working directory again and compare two folders function by function. The tools that find clones can look for exact (Type-1), renamed (Type-2), near-miss (Type-3) and semantic (Type-4) ones.

See AI-Ready docs for full details.

Citation

If jscpd is part of your research, cite it via the repository's CITATION.cff (GitHub's "Cite this repository" button produces BibTeX and APA) or with:

@software{jscpd,
  title        = {jscpd: copy/paste detector for programming source code},
  author       = {Kucherenko, Andrey},
  year         = {2026},
  version      = {5.3.0},
  license      = {MIT},
  url          = {https://github.com/kucherenko/jscpd},
}

Contributing

See CONTRIBUTING.md for the development setup, test policy, and pull request requirements. In short:

cd rust
cargo nextest run --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt --all --check

Security issues go through the security policy, not public issues.

Backers

Thank you to all our backers! 🙏 [Become a backer]

README 图片

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]

README 图片 README 图片 README 图片 README 图片 README 图片 README 图片 README 图片 README 图片 README 图片 README 图片

License

MIT © Andrey Kucherenko