[{"data":1,"prerenderedAt":2028},["ShallowReactive",2],{"navigation_docs":3,"-guides-agents":239,"-guides-agents-surround":2023},[4,29,94,114,184],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"Start",false,"\u002Fstart","1.start",[10,14,19,24],{"title":11,"path":7,"stem":12,"icon":13},"What jscpd finds","1.start\u002Findex","i-lucide-house",{"title":15,"path":16,"stem":17,"icon":18},"Installation","\u002Fstart\u002Finstallation","1.start\u002F2.installation","i-lucide-download",{"title":20,"path":21,"stem":22,"icon":23},"Quickstart","\u002Fstart\u002Fquickstart","1.start\u002F3.quickstart","i-lucide-rocket",{"title":25,"path":26,"stem":27,"icon":28},"Configuration basics","\u002Fstart\u002Fconfiguration","1.start\u002F4.configuration","i-lucide-settings-2",{"title":30,"icon":6,"path":31,"stem":32,"children":33,"page":6},"Guides","\u002Fguides","2.guides",[34,39,44,49,54,59,64,69,74,79,84,89],{"title":35,"path":36,"stem":37,"icon":38},"Use jscpd in CI","\u002Fguides\u002Fci","2.guides\u002F01.ci","i-lucide-github",{"title":40,"path":41,"stem":42,"icon":43},"Pre-commit hooks","\u002Fguides\u002Fpre-commit","2.guides\u002F02.pre-commit","i-lucide-git-commit",{"title":45,"path":46,"stem":47,"icon":48},"Fail only on new duplication","\u002Fguides\u002Fbaseline","2.guides\u002F03.baseline","i-lucide-git-compare",{"title":50,"path":51,"stem":52,"icon":53},"Monorepos","\u002Fguides\u002Fmonorepos","2.guides\u002F04.monorepos","i-lucide-folder-tree",{"title":55,"path":56,"stem":57,"icon":58},"Cross-format detection","\u002Fguides\u002Fcross-format","2.guides\u002F05.cross-format","i-lucide-layers",{"title":60,"path":61,"stem":62,"icon":63},"Agents","\u002Fguides\u002Fagents","2.guides\u002F06.agents","i-lucide-cpu",{"title":65,"path":66,"stem":67,"icon":68},"Editors","\u002Fguides\u002Feditors","2.guides\u002F07.editors","i-lucide-code",{"title":70,"path":71,"stem":72,"icon":73},"Duplication over git history","\u002Fguides\u002Fhistory","2.guides\u002F08.history","i-lucide-chart-no-axes-combined",{"title":75,"path":76,"stem":77,"icon":78},"Dashboard and health score","\u002Fguides\u002Fdashboard","2.guides\u002F09.dashboard","i-lucide-layout-dashboard",{"title":80,"path":81,"stem":82,"icon":83},"Dead code","\u002Fguides\u002Fdead-code","2.guides\u002F10.dead-code","i-lucide-ghost",{"title":85,"path":86,"stem":87,"icon":88},"Comparing two codebases","\u002Fguides\u002Fcompare","2.guides\u002F11.compare","i-lucide-git-compare-arrows",{"title":90,"path":91,"stem":92,"icon":93},"Semantic clones","\u002Fguides\u002Fsemantic-clones","2.guides\u002F12.semantic-clones","i-lucide-brain-circuit",{"title":95,"icon":6,"path":96,"stem":97,"children":98,"page":6},"Concepts","\u002Fconcepts","3.concepts",[99,104,109],{"title":100,"path":101,"stem":102,"icon":103},"Types of code clones","\u002Fconcepts\u002Fclone-types","3.concepts\u002F1.clone-types","i-lucide-copy",{"title":105,"path":106,"stem":107,"icon":108},"How detection works","\u002Fconcepts\u002Fhow-detection-works","3.concepts\u002F2.how-detection-works","i-lucide-scan-search",{"title":110,"path":111,"stem":112,"icon":113},"The health score","\u002Fconcepts\u002Fhealth-score","3.concepts\u002F3.health-score","i-lucide-heart-pulse",{"title":115,"icon":6,"path":116,"stem":117,"children":118,"page":6},"Reference","\u002Freference","4.reference",[119,124,129,134,171,176,180],{"title":120,"path":121,"stem":122,"icon":123},"CLI options","\u002Freference\u002Fcli","4.reference\u002F1.cli","i-lucide-terminal",{"title":125,"path":126,"stem":127,"icon":128},"The config file","\u002Freference\u002Fconfig-file","4.reference\u002F2.config-file","i-lucide-settings",{"title":130,"path":131,"stem":132,"icon":133},"Exit codes","\u002Freference\u002Fexit-codes","4.reference\u002F3.exit-codes","i-lucide-log-out",{"title":135,"icon":6,"path":136,"stem":137,"children":138},"Reporters","\u002Freference\u002Freporters","4.reference\u002F4.reporters\u002Findex",[139,141,146,151,156,161,166],{"title":135,"path":136,"stem":137,"icon":140},"i-lucide-file-chart-column",{"title":142,"path":143,"stem":144,"icon":145},"HTML reporter","\u002Freference\u002Freporters\u002Fhtml","4.reference\u002F4.reporters\u002F2.html","i-lucide-file-code",{"title":147,"path":148,"stem":149,"icon":150},"JSON reporter","\u002Freference\u002Freporters\u002Fjson","4.reference\u002F4.reporters\u002F3.json","i-lucide-braces",{"title":152,"path":153,"stem":154,"icon":155},"Badge reporter","\u002Freference\u002Freporters\u002Fbadge","4.reference\u002F4.reporters\u002F4.badge","i-lucide-award",{"title":157,"path":158,"stem":159,"icon":160},"SARIF reporter","\u002Freference\u002Freporters\u002Fsarif","4.reference\u002F4.reporters\u002F5.sarif","i-lucide-shield-check",{"title":162,"path":163,"stem":164,"icon":165},"CodeClimate reporter","\u002Freference\u002Freporters\u002Fcodeclimate","4.reference\u002F4.reporters\u002F6.codeclimate","i-lucide-flag-triangle-right",{"title":167,"path":168,"stem":169,"icon":170},"OpenMetrics reporter","\u002Freference\u002Freporters\u002Fopenmetrics","4.reference\u002F4.reporters\u002F7.openmetrics","i-lucide-activity",{"title":172,"path":173,"stem":174,"icon":175},"Supported formats","\u002Freference\u002Fsupported-formats","4.reference\u002F5.supported-formats","i-lucide-languages",{"title":177,"path":178,"stem":179,"icon":38},"GitHub Action","\u002Freference\u002Fgithub-action","4.reference\u002F6.github-action",{"title":181,"path":182,"stem":183,"icon":68},"Rust crates","\u002Freference\u002Frust-crates","4.reference\u002F7.rust-crates",{"title":185,"icon":6,"path":186,"stem":187,"children":188,"page":6},"Project","\u002Fproject","5.project",[189,194,199,204,229,234],{"title":190,"path":191,"stem":192,"icon":193},"Changelog","\u002Fproject\u002Fchangelog","5.project\u002F1.changelog","i-lucide-scroll-text",{"title":195,"path":196,"stem":197,"icon":198},"Migrating from v4 to v5","\u002Fproject\u002Fmigration","5.project\u002F2.migration","i-lucide-arrow-right-left",{"title":200,"path":201,"stem":202,"icon":203},"jscpd v4 (TypeScript)","\u002Fproject\u002Fv4","5.project\u002F3.v4","i-simple-icons-typescript",{"title":205,"icon":6,"path":206,"stem":207,"children":208},"Benchmarks","\u002Fproject\u002Fbenchmarks","5.project\u002F4.benchmarks\u002Findex",[209,211,216,220,225],{"title":205,"path":206,"stem":207,"icon":210},"i-lucide-gauge",{"title":212,"path":213,"stem":214,"icon":215},"Detection Speed","\u002Fproject\u002Fbenchmarks\u002Fdetection-speed","5.project\u002F4.benchmarks\u002F2.detection-speed","i-lucide-zap",{"title":217,"path":218,"stem":219,"icon":58},"Multi-Format Detection","\u002Fproject\u002Fbenchmarks\u002Fcross-format","5.project\u002F4.benchmarks\u002F3.cross-format",{"title":221,"path":222,"stem":223,"icon":224},"AI Token Efficiency","\u002Fproject\u002Fbenchmarks\u002Fai-token-efficiency","5.project\u002F4.benchmarks\u002F4.ai-token-efficiency","i-lucide-sparkles",{"title":226,"path":227,"stem":228,"icon":93},"Embedding Models","\u002Fproject\u002Fbenchmarks\u002Fembedding-models","5.project\u002F4.benchmarks\u002F5.embedding-models",{"title":230,"path":231,"stem":232,"icon":233},"Research","\u002Fproject\u002Fresearch","5.project\u002F5.research","i-lucide-graduation-cap",{"title":235,"path":236,"stem":237,"icon":238},"Articles","\u002Fproject\u002Farticles","5.project\u002F6.articles","i-lucide-newspaper",{"id":240,"title":60,"body":241,"description":2014,"extension":2015,"links":2016,"meta":2017,"navigation":2018,"path":61,"seo":2019,"stem":62,"__hash__":2022},"docs\u002F2.guides\u002F06.agents.md",{"type":242,"value":243,"toc":1990},"minimark",[244,253,288,334,339,344,354,485,553,666,669,699,702,710,714,725,791,812,818,822,847,853,863,867,883,889,899,905,940,944,962,966,977,983,992,998,1002,1208,1214,1218,1237,1273,1279,1372,1374,1406,1408,1414,1495,1512,1514,1517,1540,1546,1568,1570,1607,1641,1647,1649,1659,1680,1684,1691,1707,1713,1726,1730,1751,1757,1791,1795,1801,1825,1831,1853,1859,1877,1883,1906,1910,1955,1959,1986],[245,246,247,248,252],"p",{},"A coding assistant meets jscpd in three places. As an MCP server, jscpd runs inside the client (Claude Desktop, Claude Code, Cursor, Copilot and others) and answers questions about the project it scanned: whether a snippet already exists, which clones a file takes part in. As a set of skills, it gives the agent tested workflows that run the command line, from removing clones to porting a library. And whatever starts jscpd, the ",[249,250,251],"code",{},"ai"," reporter prints the result in the fewest tokens.",[254,255,256,257,260,261,264,265,268,269,272,273,276,277,280,281,284,285,287],"note",{},"The MCP server is built into jscpd since 5.0.16 and needs ",[249,258,259],{},"jscpd"," on the ",[249,262,263],{},"PATH"," of the machine the client runs on (",[266,267,15],"a",{"href":16},"). The skills install with ",[249,270,271],{},"npx skills add"," and run jscpd through ",[249,274,275],{},"npx jscpd",", so they need Node.js; ",[249,278,279],{},"compare-codebases"," and ",[249,282,283],{},"code-migration"," came with jscpd 5.4.0. The ",[249,286,251],{}," reporter has been part of jscpd since 4.1.0.",[289,290,291,304],"table",{},[292,293,294],"thead",{},[295,296,297,301],"tr",{},[298,299,300],"th",{},"You want",[298,302,303],{},"Use",[305,306,307,316,324],"tbody",{},[295,308,309,313],{},[310,311,312],"td",{},"The assistant checks code against the project while it writes, inside the editor",[310,314,315],{},"the MCP server",[295,317,318,321],{},[310,319,320],{},"The assistant runs a whole task, such as removing the clones or porting a library",[310,322,323],{},"a skill",[295,325,326,329],{},[310,327,328],{},"A script or a prompt reads a jscpd report",[310,330,331],{},[249,332,333],{},"--reporters ai",[335,336,338],"h2",{"id":337},"the-mcp-server","The MCP server",[340,341,343],"h3",{"id":342},"connect-a-client","Connect a client",[245,345,346,347,353],{},"jscpd speaks the ",[266,348,352],{"href":349,"rel":350},"https:\u002F\u002Fmodelcontextprotocol.io\u002F",[351],"nofollow","Model Context Protocol"," over stdio. The client starts the process and talks to it on stdin and stdout, so there is no port and nothing to install besides jscpd. Claude Desktop, Claude Code and Cursor read the same shape of configuration:",[355,356,362],"pre",{"className":357,"code":358,"filename":359,"language":360,"meta":361,"style":361},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"mcpServers\": {\n    \"jscpd\": {\n      \"command\": \"jscpd\",\n      \"args\": [\"--mcp\", \"\u002Fpath\u002Fto\u002Fproject\"]\n    }\n  }\n}\n",".mcp.json","json","",[249,363,364,373,392,407,432,467,473,479],{"__ignoreMap":361},[365,366,369],"span",{"class":367,"line":368},"line",1,[365,370,372],{"class":371},"sMK4o","{\n",[365,374,376,379,383,386,389],{"class":367,"line":375},2,[365,377,378],{"class":371},"  \"",[365,380,382],{"class":381},"spNyl","mcpServers",[365,384,385],{"class":371},"\"",[365,387,388],{"class":371},":",[365,390,391],{"class":371}," {\n",[365,393,395,398,401,403,405],{"class":367,"line":394},3,[365,396,397],{"class":371},"    \"",[365,399,259],{"class":400},"sBMFI",[365,402,385],{"class":371},[365,404,388],{"class":371},[365,406,391],{"class":371},[365,408,410,413,417,419,421,424,427,429],{"class":367,"line":409},4,[365,411,412],{"class":371},"      \"",[365,414,416],{"class":415},"sbssI","command",[365,418,385],{"class":371},[365,420,388],{"class":371},[365,422,423],{"class":371}," \"",[365,425,259],{"class":426},"sfazB",[365,428,385],{"class":371},[365,430,431],{"class":371},",\n",[365,433,435,437,440,442,444,447,449,452,454,457,459,462,464],{"class":367,"line":434},5,[365,436,412],{"class":371},[365,438,439],{"class":415},"args",[365,441,385],{"class":371},[365,443,388],{"class":371},[365,445,446],{"class":371}," [",[365,448,385],{"class":371},[365,450,451],{"class":426},"--mcp",[365,453,385],{"class":371},[365,455,456],{"class":371},",",[365,458,423],{"class":371},[365,460,461],{"class":426},"\u002Fpath\u002Fto\u002Fproject",[365,463,385],{"class":371},[365,465,466],{"class":371},"]\n",[365,468,470],{"class":367,"line":469},6,[365,471,472],{"class":371},"    }\n",[365,474,476],{"class":367,"line":475},7,[365,477,478],{"class":371},"  }\n",[365,480,482],{"class":367,"line":481},8,[365,483,484],{"class":371},"}\n",[289,486,487,497],{},[292,488,489],{},[295,490,491,494],{},[298,492,493],{},"Client",[298,495,496],{},"Where the configuration lives",[305,498,499,514,527,542],{},[295,500,501,504],{},[310,502,503],{},"Claude Desktop",[310,505,506,509,510,513],{},[249,507,508],{},"~\u002FLibrary\u002FApplication Support\u002FClaude\u002Fclaude_desktop_config.json"," on macOS, ",[249,511,512],{},"%APPDATA%\\Claude\\claude_desktop_config.json"," on Windows",[295,515,516,519],{},[310,517,518],{},"Claude Code",[310,520,521,523,524],{},[249,522,359],{}," in the project, or one command: ",[249,525,526],{},"claude mcp add --scope project jscpd -- jscpd --mcp \u002Fpath\u002Fto\u002Fproject",[295,528,529,532],{},[310,530,531],{},"Cursor",[310,533,534,537,538,541],{},[249,535,536],{},".cursor\u002Fmcp.json"," in the project, or ",[249,539,540],{},"~\u002F.cursor\u002Fmcp.json"," for every project",[295,543,544,547],{},[310,545,546],{},"VS Code with Copilot",[310,548,549,552],{},[249,550,551],{},".vscode\u002Fmcp.json",", with the shape below",[355,554,556],{"className":357,"code":555,"filename":551,"language":360,"meta":361,"style":361},"{\n  \"servers\": {\n    \"jscpd\": {\n      \"type\": \"stdio\",\n      \"command\": \"jscpd\",\n      \"args\": [\"--mcp\", \"\u002Fpath\u002Fto\u002Fproject\"]\n    }\n  }\n}\n",[249,557,558,562,575,587,607,625,653,657,661],{"__ignoreMap":361},[365,559,560],{"class":367,"line":368},[365,561,372],{"class":371},[365,563,564,566,569,571,573],{"class":367,"line":375},[365,565,378],{"class":371},[365,567,568],{"class":381},"servers",[365,570,385],{"class":371},[365,572,388],{"class":371},[365,574,391],{"class":371},[365,576,577,579,581,583,585],{"class":367,"line":394},[365,578,397],{"class":371},[365,580,259],{"class":400},[365,582,385],{"class":371},[365,584,388],{"class":371},[365,586,391],{"class":371},[365,588,589,591,594,596,598,600,603,605],{"class":367,"line":409},[365,590,412],{"class":371},[365,592,593],{"class":415},"type",[365,595,385],{"class":371},[365,597,388],{"class":371},[365,599,423],{"class":371},[365,601,602],{"class":426},"stdio",[365,604,385],{"class":371},[365,606,431],{"class":371},[365,608,609,611,613,615,617,619,621,623],{"class":367,"line":434},[365,610,412],{"class":371},[365,612,416],{"class":415},[365,614,385],{"class":371},[365,616,388],{"class":371},[365,618,423],{"class":371},[365,620,259],{"class":426},[365,622,385],{"class":371},[365,624,431],{"class":371},[365,626,627,629,631,633,635,637,639,641,643,645,647,649,651],{"class":367,"line":469},[365,628,412],{"class":371},[365,630,439],{"class":415},[365,632,385],{"class":371},[365,634,388],{"class":371},[365,636,446],{"class":371},[365,638,385],{"class":371},[365,640,451],{"class":426},[365,642,385],{"class":371},[365,644,456],{"class":371},[365,646,423],{"class":371},[365,648,461],{"class":426},[365,650,385],{"class":371},[365,652,466],{"class":371},[365,654,655],{"class":367,"line":475},[365,656,472],{"class":371},[365,658,659],{"class":367,"line":481},[365,660,478],{"class":371},[365,662,664],{"class":367,"line":663},9,[365,665,484],{"class":371},[245,667,668],{},"Give the project as an absolute path: the MCP documentation asks for absolute paths in Claude Desktop's configuration, and an absolute path works in every client. The detection options of a normal run apply to the scan and to every snippet check, so pass the ones your CI uses and the answers match its reports:",[355,670,675],{"className":671,"code":672,"filename":673,"language":674,"meta":361,"style":361},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","jscpd --mcp --min-tokens 30 --format javascript,typescript \u002Fpath\u002Fto\u002Fproject\n","Terminal","bash",[249,676,677],{"__ignoreMap":361},[365,678,679,681,684,687,690,693,696],{"class":367,"line":368},[365,680,259],{"class":400},[365,682,683],{"class":426}," --mcp",[365,685,686],{"class":426}," --min-tokens",[365,688,689],{"class":415}," 30",[365,691,692],{"class":426}," --format",[365,694,695],{"class":426}," javascript,typescript",[365,697,698],{"class":426}," \u002Fpath\u002Fto\u002Fproject\n",[245,700,701],{},"jscpd scans the paths once at start, reports the scan on stderr and then waits for the client. stdout carries protocol messages only.",[355,703,708],{"className":704,"code":706,"language":707,"meta":361},[705],"language-text","jscpd MCP server (stdio): scanned 12 files, 6 clones in 20ms — waiting for client\n","text",[249,709,706],{"__ignoreMap":361},[340,711,713],{"id":712},"try-it-from-a-shell","Try it from a shell",[245,715,716,717,724],{},"The server reads one JSON-RPC message per line, the way a client sends them. On ",[266,718,721],{"href":719,"rel":720},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Ftree\u002Fmaster\u002Ffixtures\u002Ftype3-demo",[351],[249,722,723],{},"fixtures\u002Ftype3-demo"," of the jscpd repository, this asks for the clones of one file:",[355,726,728],{"className":671,"code":727,"filename":673,"language":674,"meta":361,"style":361},"cd fixtures\u002Ftype3-demo\nprintf '%s\\n' '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-06-18\",\"capabilities\":{},\"clientInfo\":{\"name\":\"shell\",\"version\":\"0\"}}}' '{\"jsonrpc\":\"2.0\",\"method\":\"notifications\u002Finitialized\"}' '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools\u002Fcall\",\"params\":{\"name\":\"get_file_clones\",\"arguments\":{\"path\":\"inserted-line\u002Fsave-user.js\"}}}' | jscpd --mcp . 2>\u002Fdev\u002Fnull\n",[249,729,730,739],{"__ignoreMap":361},[365,731,732,736],{"class":367,"line":368},[365,733,735],{"class":734},"s2Zo4","cd",[365,737,738],{"class":426}," fixtures\u002Ftype3-demo\n",[365,740,741,744,747,750,753,755,758,760,762,765,767,769,772,774,777,780,782,785,788],{"class":367,"line":375},[365,742,743],{"class":734},"printf",[365,745,746],{"class":371}," '",[365,748,749],{"class":426},"%s\\n",[365,751,752],{"class":371},"'",[365,754,746],{"class":371},[365,756,757],{"class":426},"{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-06-18\",\"capabilities\":{},\"clientInfo\":{\"name\":\"shell\",\"version\":\"0\"}}}",[365,759,752],{"class":371},[365,761,746],{"class":371},[365,763,764],{"class":426},"{\"jsonrpc\":\"2.0\",\"method\":\"notifications\u002Finitialized\"}",[365,766,752],{"class":371},[365,768,746],{"class":371},[365,770,771],{"class":426},"{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools\u002Fcall\",\"params\":{\"name\":\"get_file_clones\",\"arguments\":{\"path\":\"inserted-line\u002Fsave-user.js\"}}}",[365,773,752],{"class":371},[365,775,776],{"class":371}," |",[365,778,779],{"class":400}," jscpd",[365,781,683],{"class":426},[365,783,784],{"class":426}," .",[365,786,787],{"class":371}," 2>",[365,789,790],{"class":426},"\u002Fdev\u002Fnull\n",[245,792,793,794,797,798,280,801,804,805,807,808,811],{},"The first line of the answer is the ",[249,795,796],{},"initialize"," result, with ",[249,799,800],{},"\"protocolVersion\": \"2025-06-18\"",[249,802,803],{},"serverInfo"," (",[249,806,259],{},", version ",[249,809,810],{},"5.4.0","). The second is the tool result, whose text content is this JSON:",[355,813,816],{"className":814,"code":815,"language":707,"meta":361},[705],"{\n  \"clones\": 2,\n  \"duplications\": [\n    {\n      \"endA\": 12,\n      \"endB\": 11,\n      \"fileA\": \"inserted-line\u002Fsave-account.js\",\n      \"fileB\": \"inserted-line\u002Fsave-user.js\",\n      \"format\": \"javascript\",\n      \"lines\": 6,\n      \"startA\": 6,\n      \"startB\": 5,\n      \"tokens\": 100\n    },\n    {\n      \"endA\": 6,\n      \"endB\": 6,\n      \"fileA\": \"inserted-line\u002Fsave-account.js\",\n      \"fileB\": \"inserted-line\u002Fsave-user.js\",\n      \"format\": \"javascript\",\n      \"lines\": 5,\n      \"startA\": 1,\n      \"startB\": 1,\n      \"tokens\": 60\n    }\n  ],\n  \"file\": \"inserted-line\u002Fsave-user.js\",\n  \"returned\": 2\n}\n",[249,817,815],{"__ignoreMap":361},[340,819,821],{"id":820},"reading-the-answers","Reading the answers",[245,823,824,825,828,829,832,833,836,837,839,840,842,843,846],{},"Every tool answers with compact JSON in one text content item. Clone lists come biggest first and are cut at ",[249,826,827],{},"limit"," entries, 100 unless the call says otherwise; the count next to a list (",[249,830,831],{},"clones",", ",[249,834,835],{},"count",") is always the whole number, and a cut list carries a ",[249,838,254],{}," that says so. Paths are relative to the scan root, in the form the other tools accept. When a call cannot use its arguments, such as a missing ",[249,841,249],{}," or an unknown format, the server answers with a tool error (",[249,844,845],{},"isError: true",") and a message that says what to fix:",[355,848,851],{"className":849,"code":850,"language":707,"meta":361},[705],"{\"error\": \"unknown format 'klingon': run `cpd --list` for supported formats\"}\n",[249,852,850],{"__ignoreMap":361},[245,854,855,856,858,859,862],{},"An unknown tool name gets a JSON-RPC error. All four tools are read-only and never change the project's files. The ",[249,857,796],{}," result also carries ",[249,860,861],{},"instructions",", a short text that tells the assistant when to call which tool.",[340,864,866],{"id":865},"check-a-snippet-before-writing-it","Check a snippet before writing it",[245,868,869,872,873,876,877,280,879,882],{},[249,870,871],{},"check_duplication"," compares a snippet with the scanned project, so the assistant can reuse the existing copy. With the body of ",[249,874,875],{},"inserted-line\u002Fsave-account.js"," as ",[249,878,249],{},[249,880,881],{},"\"format\": \"js\"",", the demo answers:",[355,884,887],{"className":885,"code":886,"language":707,"meta":361},[705],"{\n  \"count\": 1,\n  \"duplications\": [\n    {\n      \"file\": \"inserted-line\u002Fsave-account.js\",\n      \"fileEndLine\": 12,\n      \"fileStartLine\": 1,\n      \"snippetEndLine\": 12,\n      \"snippetStartLine\": 1,\n      \"tokens\": 172\n    }\n  ],\n  \"format\": \"javascript\",\n  \"returned\": 1\n}\n",[249,888,886],{"__ignoreMap":361},[245,890,891,892,895,896,388],{},"A snippet shorter than ",[249,893,894],{},"--min-tokens"," cannot match and says why instead of answering with an empty list. For ",[249,897,898],{},"let x = 1;",[355,900,903],{"className":901,"code":902,"language":707,"meta":361},[705],"{\n  \"count\": 0,\n  \"duplications\": [],\n  \"format\": \"javascript\",\n  \"note\": \"snippet has 5 tokens, below the detection threshold of 50 (--min-tokens)\"\n}\n",[249,904,902],{"__ignoreMap":361},[245,906,907,908,911,912,915,916,919,920,923,924,927,928,931,932,935,936,939],{},"With ",[249,909,910],{},"\"similarity\": 0.85"," the answer also lists project functions whose syntax-tree shape resembles each function of the snippet, under ",[249,913,914],{},"similar"," with a ",[249,917,918],{},"similarCount","; each entry has the ",[249,921,922],{},"file",", its line range, the project function's ",[249,925,926],{},"name",", the ",[249,929,930],{},"snippetName"," and a ",[249,933,934],{},"similarity"," ratio. This part works for JavaScript and TypeScript only, and ",[249,937,938],{},"1"," turns it off.",[340,941,943],{"id":942},"see-a-files-clones-before-refactoring-it","See a file's clones before refactoring it",[245,945,946,949,950,953,954,957,958,961],{},[249,947,948],{},"get_file_clones"," lists every clone of one file, as the shell example above shows. The file you ask about can be ",[249,951,952],{},"fileA"," or ",[249,955,956],{},"fileB"," of a clone. A path that was not part of the scan answers with ",[249,959,960],{},"clones: 0",".",[340,963,965],{"id":964},"scan-again-after-the-assistant-edits-files","Scan again after the assistant edits files",[245,967,968,969,972,973,976],{},"The other tools answer from the scan made at start. ",[249,970,971],{},"check_current_directory"," scans the configured paths again, replaces that scan and returns the new counts and clone list. With ",[249,974,975],{},"\"limit\": 2"," on the demo:",[355,978,981],{"className":979,"code":980,"language":707,"meta":361},[705],"{\n  \"clones\": 6,\n  \"duplicatedLines\": 42,\n  \"duplications\": [\n    {\n      \"endA\": 15,\n      \"endB\": 14,\n      \"fileA\": \"long-line\u002Ftheme-branded.js\",\n      \"fileB\": \"long-line\u002Ftheme-default.js\",\n      \"format\": \"javascript\",\n      \"lines\": 7,\n      \"startA\": 8,\n      \"startB\": 7,\n      \"tokens\": 117\n    },\n    {\n      \"endA\": 12,\n      \"endB\": 11,\n      \"fileA\": \"inserted-line\u002Fsave-account.js\",\n      \"fileB\": \"inserted-line\u002Fsave-user.js\",\n      \"format\": \"javascript\",\n      \"lines\": 6,\n      \"startA\": 6,\n      \"startB\": 5,\n      \"tokens\": 100\n    }\n  ],\n  \"files\": 12,\n  \"note\": \"clone list truncated to 2; pass a higher 'limit' for more\",\n  \"percentage\": 9.051724137931034,\n  \"returned\": 2\n}\n",[249,982,980],{"__ignoreMap":361},[245,984,985,988,989,976],{},[249,986,987],{},"get_statistics"," returns the totals of the last scan and the same numbers per format, so the assistant can compare a project before and after a refactoring. Its ",[249,990,991],{},"statistics.total",[355,993,996],{"className":994,"code":995,"language":707,"meta":361},[705],"{\n  \"clones\": 6,\n  \"duplicatedLines\": 42,\n  \"duplicatedTokens\": 528,\n  \"lines\": 464,\n  \"newClones\": 0,\n  \"newDuplicatedLines\": 0,\n  \"percentage\": 9.051724137931034,\n  \"percentageTokens\": 11.865168539325843,\n  \"sources\": 12,\n  \"tokens\": 4450\n}\n",[249,997,995],{"__ignoreMap":361},[340,999,1001],{"id":1000},"tools","Tools",[289,1003,1004,1017],{},[292,1005,1006],{},[295,1007,1008,1011,1014],{},[298,1009,1010],{},"Tool",[298,1012,1013],{},"Arguments",[298,1015,1016],{},"Answer",[305,1018,1019,1090,1137,1181],{},[295,1020,1021,1025,1051],{},[310,1022,1023],{},[249,1024,871],{},[310,1026,1027,1029,1030,1033,1034,1037,1038,1041,1042,832,1044,1046,1047,1050],{},[249,1028,249],{}," (required), ",[249,1031,1032],{},"format"," (required; a format name such as ",[249,1035,1036],{},"javascript"," or an extension such as ",[249,1039,1040],{},"js","), ",[249,1043,827],{},[249,1045,934],{}," (a ratio in ",[249,1048,1049],{},"(0, 1]",")",[310,1052,1053,832,1055,832,1057,832,1060,1063,1064,832,1066,832,1069,832,1072,832,1075,832,1078,1081,1082,1084,1085,280,1088],{},[249,1054,1032],{},[249,1056,835],{},[249,1058,1059],{},"returned",[249,1061,1062],{},"duplications[]"," with ",[249,1065,922],{},[249,1067,1068],{},"fileStartLine",[249,1070,1071],{},"fileEndLine",[249,1073,1074],{},"snippetStartLine",[249,1076,1077],{},"snippetEndLine",[249,1079,1080],{},"tokens","; with ",[249,1083,934],{}," below 1 also ",[249,1086,1087],{},"similar[]",[249,1089,918],{},[295,1091,1092,1096,1104],{},[310,1093,1094],{},[249,1095,948],{},[310,1097,1098,1101,1102],{},[249,1099,1100],{},"path"," (required; relative to the scan root or absolute), ",[249,1103,827],{},[310,1105,1106,832,1108,832,1110,832,1112,1063,1114,832,1116,832,1118,832,1121,832,1124,832,1126,832,1129,832,1132,832,1135],{},[249,1107,922],{},[249,1109,831],{},[249,1111,1059],{},[249,1113,1062],{},[249,1115,1032],{},[249,1117,952],{},[249,1119,1120],{},"startA",[249,1122,1123],{},"endA",[249,1125,956],{},[249,1127,1128],{},"startB",[249,1130,1131],{},"endB",[249,1133,1134],{},"lines",[249,1136,1080],{},[295,1138,1139,1143,1146],{},[310,1140,1141],{},[249,1142,987],{},[310,1144,1145],{},"none",[310,1147,1148,832,1151,832,1153,1063,1156,1159,1160,832,1163,832,1165,832,1167,832,1169,832,1172,832,1175,832,1178],{},[249,1149,1150],{},"files",[249,1152,831],{},[249,1154,1155],{},"statistics",[249,1157,1158],{},"total"," and one object per format: ",[249,1161,1162],{},"sources",[249,1164,1134],{},[249,1166,1080],{},[249,1168,831],{},[249,1170,1171],{},"duplicatedLines",[249,1173,1174],{},"duplicatedTokens",[249,1176,1177],{},"percentage",[249,1179,1180],{},"percentageTokens",[295,1182,1183,1187,1191],{},[310,1184,1185],{},[249,1186,971],{},[310,1188,1189],{},[249,1190,827],{},[310,1192,1193,832,1195,832,1197,832,1199,832,1201,832,1203,1205,1206],{},[249,1194,1150],{},[249,1196,831],{},[249,1198,1171],{},[249,1200,1177],{},[249,1202,1059],{},[249,1204,1062],{}," in the shape of ",[249,1207,948],{},[245,1209,1210,1211,1213],{},"The server answers ",[249,1212,796],{}," with protocol revision 2025-06-18 and also accepts clients of 2025-03-26 and 2024-11-05; a request for any other revision gets 2025-06-18.",[335,1215,1217],{"id":1216},"the-skills","The skills",[245,1219,1220,1221,1224,1225,1230,1231,1236],{},"A skill is a folder with a ",[249,1222,1223],{},"SKILL.md"," that an assistant reads when a task matches its description, so the agent runs jscpd with the right options and follows a tested workflow. jscpd ships five of them for ",[266,1226,1229],{"href":1227,"rel":1228},"https:\u002F\u002Fskills.sh\u002Fkucherenko\u002Fjscpd",[351],"skills.sh","; the sources are in ",[266,1232,1235],{"href":1233,"rel":1234},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Ftree\u002Fmaster\u002Fskills",[351],"skills\u002F"," of the repository.",[355,1238,1240],{"className":671,"code":1239,"filename":673,"language":674,"meta":361,"style":361},"npx skills add kucherenko\u002Fjscpd\nnpx skills add kucherenko\u002Fjscpd --skill dry-refactoring\n",[249,1241,1242,1256],{"__ignoreMap":361},[365,1243,1244,1247,1250,1253],{"class":367,"line":368},[365,1245,1246],{"class":400},"npx",[365,1248,1249],{"class":426}," skills",[365,1251,1252],{"class":426}," add",[365,1254,1255],{"class":426}," kucherenko\u002Fjscpd\n",[365,1257,1258,1260,1262,1264,1267,1270],{"class":367,"line":375},[365,1259,1246],{"class":400},[365,1261,1249],{"class":426},[365,1263,1252],{"class":426},[365,1265,1266],{"class":426}," kucherenko\u002Fjscpd",[365,1268,1269],{"class":426}," --skill",[365,1271,1272],{"class":426}," dry-refactoring\n",[245,1274,1275,1276,1278],{},"The first line installs all five, the second one of them. Every skill runs jscpd through ",[249,1277,275],{},", so the agent needs no global install. Once a skill is installed, a request in its words is enough: \"find and fix code duplication\" runs the first two, \"clean up this codebase\" the third, \"port this library to Rust\" the last two.",[289,1280,1281,1294],{},[292,1282,1283],{},[295,1284,1285,1288,1291],{},[298,1286,1287],{},"Skill",[298,1289,1290],{},"What it does",[298,1292,1293],{},"When the agent needs it",[305,1295,1296,1311,1324,1341,1357],{},[295,1297,1298,1302,1308],{},[310,1299,1300],{},[249,1301,259],{},[310,1303,1304,1305,1307],{},"The reference for jscpd itself: the flags, the passes for each kind of clone, the ",[249,1306,251],{}," reporter's format, the config file",[310,1309,1310],{},"Any run of jscpd",[295,1312,1313,1318,1321],{},[310,1314,1315],{},[249,1316,1317],{},"dry-refactoring",[310,1319,1320],{},"Removes the clones jscpd found: reads each pair, triages it, picks a strategy, applies it, checks the clone is gone",[310,1322,1323],{},"\"Find and fix code duplication\"",[295,1325,1326,1331,1338],{},[310,1327,1328],{},[249,1329,1330],{},"codebase-refactoring",[310,1332,1333,1334,1337],{},"A pass over duplication, dead code and complexity, measured with ",[249,1335,1336],{},"--health"," before and after",[310,1339,1340],{},"\"Clean up this codebase\", \"pay down tech debt\"",[295,1342,1343,1347,1354],{},[310,1344,1345],{},[249,1346,279],{},[310,1348,1349,1350,1353],{},"Compares two folders function by function with ",[249,1351,1352],{},"--compare"," and explains the result (5.4.0+)",[310,1355,1356],{},"\"How far is the port?\", \"What does the Android app have that iOS lacks?\"",[295,1358,1359,1363,1369],{},[310,1360,1361],{},[249,1362,283],{},[310,1364,1365,1366,1368],{},"Ports a codebase to another language or framework, tests first, with ",[249,1367,1352],{}," as the progress measure (5.4.0+)",[310,1370,1371],{},"\"Port this Python library to TypeScript\"",[340,1373,259],{"id":259},[245,1375,1376,1377,1379,1380,280,1383,1386,1387,1390,1391,1394,1395,1398,1399,1402,1403,961],{},"The reference the other skills build on. It tells the agent to scan with the ",[249,1378,251],{}," reporter, to scope a run with ",[249,1381,1382],{},"--ignore",[249,1384,1385],{},"--format",", and how to read each line of the report. It describes the default scan, which reports exact copies, and two noisier passes to run after those are dealt with: ",[249,1388,1389],{},"--ignore-identifiers --min-tokens 70"," for copies that differ only in names and values, and ",[249,1392,1393],{},"--max-gap-lines 1 --similarity 0.85"," for copies with a few edited lines or the same function structure. It also covers ",[249,1396,1397],{},"--summary"," for a hotspot ranking, ",[249,1400,1401],{},"--complexity"," for the complexity ranking alone, and the keys of ",[249,1404,1405],{},".jscpd.json",[340,1407,1317],{"id":1317},[245,1409,1410,1411,1413],{},"The workflow for removing clones. The agent runs jscpd with ",[249,1412,333],{},", reads both fragments of each clone, works out what the code does, and triages renamed and similar clones before touching them: a pair whose two sides do different things, intentional boilerplate, generated code, a pair that would need a vague name, or a pair under about ten lines is skipped and reported as skipped. The kind of clone picks the strategy, and the agent runs jscpd again with the same flags to confirm the clone is gone, highest impact first.",[289,1415,1416,1426],{},[292,1417,1418],{},[295,1419,1420,1423],{},[298,1421,1422],{},"Strategy",[298,1424,1425],{},"When",[305,1427,1428,1436,1444,1452,1460,1472,1483],{},[295,1429,1430,1433],{},[310,1431,1432],{},"Extract function",[310,1434,1435],{},"The duplicate is a block of logic",[295,1437,1438,1441],{},[310,1439,1440],{},"Extract module or utility",[310,1442,1443],{},"The duplicate spans files in different domains",[295,1445,1446,1449],{},[310,1447,1448],{},"Extract constant or config",[310,1450,1451],{},"The duplicate is repeated data or configuration",[295,1453,1454,1457],{},[310,1455,1456],{},"Template or base class",[310,1458,1459],{},"The duplicate is a repeated class shape",[295,1461,1462,1465],{},[310,1463,1464],{},"Parameterize",[310,1466,1467,1468,1471],{},"A ",[249,1469,1470],{},"(renamed)"," clone: the same algorithm over different names or values",[295,1473,1474,1477],{},[310,1475,1476],{},"Unify near-miss copies",[310,1478,1467,1479,1482],{},[249,1480,1481],{},"[gap]"," clone: extract the common body and pass the divergence in",[295,1484,1485,1488],{},[310,1486,1487],{},"Merge similar functions",[310,1489,1490,1491,1494],{},"An ",[249,1492,1493],{},"[ast]"," clone: extract the shared skeleton and inject what differs",[245,1496,1497,1498,931,1501,1504,1505,1508,1509,1511],{},"Two of its tips save time on real projects. A clone between a ",[249,1499,1500],{},".js",[249,1502,1503],{},".ts"," file, found with ",[249,1506,1507],{},"--cross-formats",", usually means code was ported without deleting the original, so the fix is one implementation. Many ",[249,1510,1470],{}," clones in one file usually point at one missing abstraction, and many across test files usually mean nothing, since test cases are supposed to look alike.",[340,1513,1330],{"id":1330},[245,1515,1516],{},"Starts from one number and works where it is lowest:",[355,1518,1520],{"className":671,"code":1519,"filename":673,"language":674,"meta":361,"style":361},"npx jscpd --health --reporters ai .\u002Fsrc\n",[249,1521,1522],{"__ignoreMap":361},[365,1523,1524,1526,1528,1531,1534,1537],{"class":367,"line":368},[365,1525,1246],{"class":400},[365,1527,779],{"class":426},[365,1529,1530],{"class":426}," --health",[365,1532,1533],{"class":426}," --reporters",[365,1535,1536],{"class":426}," ai",[365,1538,1539],{"class":426}," .\u002Fsrc\n",[355,1541,1544],{"className":1542,"code":1543,"language":707,"meta":361},[705],"health 74 B (duplication 74, dead-code 72, complexity 76; 93 code lines)\n",[249,1545,1543],{"__ignoreMap":361},[245,1547,1548,1549,1552,1553,1555,1556,1561,1562,1564,1565,1567],{},"The ",[266,1550,1551],{"href":111},"health score"," is a weighted mix of three sub-scores, and the lowest one names where the codebase hurts most. The skill then makes three passes in the order duplication, dead code, complexity: ",[249,1554,1317],{}," for the clones, ",[266,1557,1558],{"href":81},[249,1559,1560],{},"--dead-code"," for unused files, exports and imports (removed, or kept with a reason), and ",[249,1563,1401],{}," for the largest and most complex files, which get split or simplified. The order matters because an extraction moves call sites the dead-code pass would otherwise trace, and removed dead code changes which files rank as complex. After each pass the agent runs ",[249,1566,1336],{}," again and reports the change.",[340,1569,279],{"id":279},[245,1571,1572,1575,1576,1579,1580,1583,1584,832,1587,280,1590,1593,1594,953,1597,1599,1600,1603,1604,1606],{},[249,1573,1574],{},"jscpd --compare A B"," pairs every function of folder ",[249,1577,1578],{},"A"," with the function of folder ",[249,1581,1582],{},"B"," that does the same job, in one language or across two, and lists the functions that have no counterpart. The skill explains how the pairing works, by code with the embedding model and then by name, and what the ",[249,1585,1586],{},"high",[249,1588,1589],{},"medium",[249,1591,1592],{},"low"," levels mean. Its six steps: point at the code and keep vendored and generated files out with ",[249,1595,1596],{},".gitignore",[249,1598,1382],{},"; ask before the one-time ",[249,1601,1602],{},"npx jscpd --semantic-download"," (548 MB); read the overview; check a sample of pairs and every ",[249,1605,1592],{}," one; search the other folder for an unmatched function before calling it missing; and report the two percentages, the renamed pairs and the real gaps, with the HTML migration map for a reader who wants to explore.",[355,1608,1610],{"className":671,"code":1609,"filename":673,"language":674,"meta":361,"style":361},"npx jscpd --compare python\u002F typescript\u002F\nnpx jscpd --compare ios\u002F android\u002F\n",[249,1611,1612,1627],{"__ignoreMap":361},[365,1613,1614,1616,1618,1621,1624],{"class":367,"line":368},[365,1615,1246],{"class":400},[365,1617,779],{"class":426},[365,1619,1620],{"class":426}," --compare",[365,1622,1623],{"class":426}," python\u002F",[365,1625,1626],{"class":426}," typescript\u002F\n",[365,1628,1629,1631,1633,1635,1638],{"class":367,"line":375},[365,1630,1246],{"class":400},[365,1632,779],{"class":426},[365,1634,1620],{"class":426},[365,1636,1637],{"class":426}," ios\u002F",[365,1639,1640],{"class":426}," android\u002F\n",[245,1642,1643,1644,1646],{},"The first line measures a port, source first and target second; the second checks two implementations of one app for parity. ",[266,1645,85],{"href":86}," describes the reports.",[340,1648,283],{"id":283},[245,1650,1651,1652,1654,1655,1658],{},"The port workflow, with ",[249,1653,1352],{}," as the progress measure and the source's tests as the definition of done. The agent first builds a map from each source function to the tests that cover it, from a per-test coverage report, so a function is ported together with the tests that prove it. Then it ports the tests, keeping inputs and expected values, and keeps them out of the build until their functions land; it writes no stubs, because a stub under the source's name can pair by name and count as ported. Then it ports the code one function at a time, starting from the report's ",[249,1656,1657],{},"readyToPort"," list (unmatched functions whose callees already have a counterpart), turns on each function's tests as it lands, checks with coverage that they reach the new code, and reruns the report after each batch. Progress is reported as two numbers, tests ported and passing, and functions ported, with the functions left out on purpose and why.",[245,1660,1661,1662,1667,1668,1673,1674,1679],{},"The skill was tested by porting fs-extra 11.4.1 to a Rust addon. The port is on npm as ",[266,1663,1666],{"href":1664,"rel":1665},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@jscpd\u002Ffs-extra",[351],"@jscpd\u002Ffs-extra",", with the code at ",[266,1669,1672],{"href":1670,"rel":1671},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Ffs-extra-rs",[351],"kucherenko\u002Ffs-extra-rs","; a run of the same task without the skill is kept at ",[266,1675,1678],{"href":1676,"rel":1677},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Ffs-extra-rs-plain",[351],"kucherenko\u002Ffs-extra-rs-plain"," for comparison.",[335,1681,1683],{"id":1682},"the-ai-reporter","The ai reporter",[245,1685,1548,1686,1688,1689,388],{},[249,1687,251],{}," reporter prints one line per clone and a summary, with no code fragments and no colors. On ",[249,1690,723],{},[355,1692,1694],{"className":671,"code":1693,"filename":673,"language":674,"meta":361,"style":361},"jscpd . --reporters ai\n",[249,1695,1696],{"__ignoreMap":361},[365,1697,1698,1700,1702,1704],{"class":367,"line":368},[365,1699,259],{"class":400},[365,1701,784],{"class":426},[365,1703,1533],{"class":426},[365,1705,1706],{"class":426}," ai\n",[355,1708,1711],{"className":1709,"code":1710,"language":707,"meta":361},[705],"Clones:\ninserted-line\u002F save-account.js:1-6 ~ save-user.js:1-6\ninserted-line\u002F save-account.js:6-12 ~ save-user.js:5-11\nlong-line\u002F theme-branded.js:1-8 ~ theme-default.js:1-8\nlong-line\u002F theme-branded.js:8-15 ~ theme-default.js:7-14\nwide-gap\u002F place-order-guarded.js:1-6 ~ place-order.js:1-6\nwide-gap\u002F place-order-guarded.js:9-15 ~ place-order.js:6-12\n---\n6 clones · 9.1% duplication\ntime: 5.439ms\n",[249,1712,1710],{"__ignoreMap":361},[245,1714,1715,1716,1718,1719,1722,1723,1725],{},"On this demo the console reporter prints 2,099 characters and the ",[249,1717,251],{}," reporter 394. On the repository's fixture corpus of 212 clones, ",[266,1720,1721],{"href":222},"the benchmark"," measured about 2,800 tokens for the ",[249,1724,251],{}," reporter against about 23,000 for the console reporter, and compares it with other detectors.",[340,1727,1729],{"id":1728},"reading-a-clone-line","Reading a clone line",[245,1731,1732,1733,1736,1737,1740,1741,280,1743,1746,1747,1750],{},"The two fragments stand on either side of ",[249,1734,1735],{},"~",". A directory the two files share is written once, followed by a space, so ",[249,1738,1739],{},"inserted-line\u002F save-account.js:1-6 ~ save-user.js:1-6"," names ",[249,1742,875],{},[249,1744,1745],{},"inserted-line\u002Fsave-user.js",". A clone within one file gives the path once and two ranges: ",[249,1748,1749],{},"file.js 10-25 ~ 45-60",". No suffix means an exact copy. The passes that find the other kinds add one:",[355,1752,1755],{"className":1753,"code":1754,"language":707,"meta":361},[705],"identifiers\u002F basket.js:1-9 ~ cart.js:1-9 (renamed)\ninserted-line\u002F save-account.js:1-12 ~ save-user.js:1-11 [~0.91 gap]\nrenamed-halves\u002F sync-contacts.js:1-13 ~ sync-leads.js:1-14 [~0.88 ast]\n",[249,1756,1754],{"__ignoreMap":361},[245,1758,1759,1761,1762,832,1765,953,1768,1771,1772,1775,1776,1779,1780,1783,1784,1787,1788,1790],{},[249,1760,1470],{}," is a copy that differs only in identifiers, literals or annotations, reported with ",[249,1763,1764],{},"--ignore-identifiers",[249,1766,1767],{},"--ignore-literals",[249,1769,1770],{},"--ignore-annotations",". ",[249,1773,1774],{},"[~0.91 gap]"," is two exact clones merged across up to ",[249,1777,1778],{},"--max-gap-lines"," unmatched lines; the number is the share of matched tokens over the merged span. ",[249,1781,1782],{},"[~0.88 ast]"," is a pair of JavaScript or TypeScript functions whose syntax trees overlap at least ",[249,1785,1786],{},"--similarity","; names and literal values do not count. ",[266,1789,100],{"href":101}," explains the kinds.",[340,1792,1794],{"id":1793},"with-the-other-modes","With the other modes",[245,1796,1797,1798,388],{},"The reporter keeps the same shape in the other modes, measured here on ",[249,1799,1800],{},"fixtures\u002Fdashboard-demo",[355,1802,1804],{"className":671,"code":1803,"filename":673,"language":674,"meta":361,"style":361},"jscpd . --reporters ai --summary --summary-top 3\n",[249,1805,1806],{"__ignoreMap":361},[365,1807,1808,1810,1812,1814,1816,1819,1822],{"class":367,"line":368},[365,1809,259],{"class":400},[365,1811,784],{"class":426},[365,1813,1533],{"class":426},[365,1815,1536],{"class":426},[365,1817,1818],{"class":426}," --summary",[365,1820,1821],{"class":426}," --summary-top",[365,1823,1824],{"class":415}," 3\n",[355,1826,1829],{"className":1827,"code":1828,"language":707,"meta":361},[705],"Clones:\nsrc\u002F checks.ts:8-13 ~ labels.ts:4-9\n---\n1 clones · 1.9% duplication\n---\nSummary by tokens (6 files, 3 folders):\nfiles (tokens\u002Flines\u002Fsize\u002Fcx\u002Fdup%):\nREADME.md 1289\u002F163\u002F8.0K\u002F0\u002F0.0%\nsrc\u002Frates.ts 182\u002F35\u002F757\u002F11\u002F0.0%\nsrc\u002Fchecks.ts 169\u002F21\u002F665\u002F6\u002F28.6%\nfolders (files\u002Ftokens\u002Flines\u002Fsize):\n. 1\u002F1289\u002F163\u002F8.0K\nsrc 4\u002F557\u002F83\u002F2.2K\nsrc\u002Flegacy 1\u002F113\u002F10\u002F430\ntime: 4.073ms\n",[249,1830,1828],{"__ignoreMap":361},[355,1832,1834],{"className":671,"code":1833,"filename":673,"language":674,"meta":361,"style":361},"jscpd . --reporters ai --complexity --summary-top 3\n",[249,1835,1836],{"__ignoreMap":361},[365,1837,1838,1840,1842,1844,1846,1849,1851],{"class":367,"line":368},[365,1839,259],{"class":400},[365,1841,784],{"class":426},[365,1843,1533],{"class":426},[365,1845,1536],{"class":426},[365,1847,1848],{"class":426}," --complexity",[365,1850,1821],{"class":426},[365,1852,1824],{"class":415},[355,1854,1857],{"className":1855,"code":1856,"language":707,"meta":361},[705],"Complexity by complexity (6 files, 3 folders):\nfiles (tokens\u002Flines\u002Fsize\u002Fcx):\nsrc\u002Frates.ts 182\u002F35\u002F757\u002F11\nsrc\u002Fchecks.ts 169\u002F21\u002F665\u002F6\nsrc\u002Flabels.ts 109\u002F11\u002F409\u002F3\nfolders (files\u002Ftokens\u002Flines\u002Fsize\u002Fmean cx):\nsrc 4\u002F557\u002F83\u002F2.2K\u002F5\nsrc\u002Flegacy 1\u002F113\u002F10\u002F430\u002F3\n. 1\u002F1289\u002F163\u002F8.0K\u002F0\ntime: 3.009ms\n",[249,1858,1856],{"__ignoreMap":361},[355,1860,1862],{"className":671,"code":1861,"filename":673,"language":674,"meta":361,"style":361},"jscpd . --reporters ai --dead-code\n",[249,1863,1864],{"__ignoreMap":361},[365,1865,1866,1868,1870,1872,1874],{"class":367,"line":368},[365,1867,259],{"class":400},[365,1869,784],{"class":426},[365,1871,1533],{"class":426},[365,1873,1536],{"class":426},[365,1875,1876],{"class":426}," --dead-code\n",[355,1878,1881],{"className":1879,"code":1880,"language":707,"meta":361},[705],"basta dead code report — 2 findings across 5 files (14.0% of 93 lines)\nConfidence is 0-100; anything below 90 has a listed reason it may be wrong. Verify a finding before deleting the code.\nunused-file src\u002Flegacy\u002Fmanifest.ts:1:1 confidence=95 src\u002Flegacy\u002Fmanifest.ts is never imported and is not an entry point\nunused-export src\u002Fchecks.ts:19:17 confidence=85 exported function `checkBatch` is never imported\n",[249,1882,1880],{"__ignoreMap":361},[245,1884,1885,1888,1889,1892,1893,1063,1895,1898,1899,1902,1903,1905],{},[249,1886,1887],{},"--health --reporters ai"," prints the one-line form shown under ",[266,1890,1330],{"href":1891},"#codebase-refactoring",". To hand an agent one kind of clone, combine ",[249,1894,333],{},[249,1896,1897],{},"--kind",", for example ",[249,1900,1901],{},"--ignore-identifiers --kind renamed"," for the renamed copies alone. ",[266,1904,135],{"href":136}," lists every reporter and the files the others write.",[335,1907,1909],{"id":1908},"limits","Limits",[1911,1912,1913,1920,1931,1949],"ul",{},[1914,1915,1916,1917,1919],"li",{},"The MCP tools answer from the last scan. After the assistant edits files, ",[249,1918,971],{}," is the call that refreshes them; it scans synchronously and can take seconds on a large project.",[1914,1921,1922,1924,1925,1927,1928,1930],{},[249,1923,871],{}," needs a snippet of at least ",[249,1926,894],{}," tokens (50 by default) and compares tokens, so it finds exact copies and, with the server's normalization options, renamed ones. The ",[249,1929,934],{}," argument works for JavaScript and TypeScript only.",[1914,1932,1933,1934,1937,1938,1945,1946,961],{},"The MCP server has no HTTP transport. ",[249,1935,1936],{},"jscpd-server",", MCP over HTTP with a REST API, belongs to v4 and is maintained on the ",[266,1939,1942],{"href":1940,"rel":1941},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Ftree\u002Fmaster-v4",[351],[249,1943,1944],{},"master-v4"," branch; see ",[266,1947,1948],{"href":201},"v4",[1914,1950,1951,1952,1954],{},"The port skills need the embedding model or an embeddings API, and the first comparison of two folders embeds every function, which can take minutes. ",[266,1953,90],{"href":91}," covers the model.",[335,1956,1958],{"id":1957},"related","Related",[1911,1960,1961,1969,1974,1979],{},[1914,1962,1963,1965,1966,961],{},[266,1964,65],{"href":66}," shows the same findings as diagnostics while you type, through ",[249,1967,1968],{},"jscpd --lsp",[1914,1970,1971,1973],{},[266,1972,135],{"href":136}," lists the reporters and the files they write.",[1914,1975,1976,1978],{},[266,1977,85],{"href":86}," explains the reports the two port skills read.",[1914,1980,1981,1983,1984,961],{},[266,1982,80],{"href":81}," covers the second pass of ",[249,1985,1330],{},[1987,1988,1989],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"title":361,"searchDepth":375,"depth":375,"links":1991},[1992,2001,2008,2012,2013],{"id":337,"depth":375,"text":338,"children":1993},[1994,1995,1996,1997,1998,1999,2000],{"id":342,"depth":394,"text":343},{"id":712,"depth":394,"text":713},{"id":820,"depth":394,"text":821},{"id":865,"depth":394,"text":866},{"id":942,"depth":394,"text":943},{"id":964,"depth":394,"text":965},{"id":1000,"depth":394,"text":1001},{"id":1216,"depth":375,"text":1217,"children":2002},[2003,2004,2005,2006,2007],{"id":259,"depth":394,"text":259},{"id":1317,"depth":394,"text":1317},{"id":1330,"depth":394,"text":1330},{"id":279,"depth":394,"text":279},{"id":283,"depth":394,"text":283},{"id":1682,"depth":375,"text":1683,"children":2009},[2010,2011],{"id":1728,"depth":394,"text":1729},{"id":1793,"depth":394,"text":1794},{"id":1908,"depth":375,"text":1909},{"id":1957,"depth":375,"text":1958},"Give Claude, Cursor, Copilot and other coding agents jscpd through the MCP server, five installable skills and the ai reporter.","md",null,{},{"icon":63},{"title":2020,"description":2021},"jscpd for AI agents","Run jscpd as an MCP server inside Claude, Cursor or Copilot, install the five agent skills, and hand clone reports to a model with the token-saving ai reporter.","Vi1BO7_QB9Nic-lT7T79FNtdXIrPZ6BdAex2yEgbcfg",[2024,2026],{"title":55,"path":56,"stem":57,"description":2025,"icon":58,"children":-1},"Find clones between JavaScript and TypeScript files with --cross-formats, and inside Vue, Svelte, Astro and Markdown files, whose blocks are scanned under their own formats.",{"title":65,"path":66,"stem":67,"description":2027,"icon":68,"children":-1},"Run jscpd --lsp as a language server so Neovim, Helix, Sublime Text, Emacs, JetBrains IDEs and VS Code show clones, dead code and complexity as diagnostics while you type.",1791302983721]