jscpd-rs 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.3 - 2026-06-01
4
+
5
+ ### Changed
6
+
7
+ - Tighten GitHub Release publication gates: npm and crates.io publication now
8
+ run the release-candidate gate before publishing.
9
+ - Block the main npm package publication if any configured prebuilt platform
10
+ package is missing or failed to publish.
11
+ - Add a core coverage gate to the release-candidate flow.
12
+ - Add an advisory server benchmark for comparing native and upstream
13
+ `/api/check` latency.
14
+ - Refresh npm, prebuilt-binary, release-readiness, and README documentation for
15
+ the prebuilt-first install path.
16
+
17
+ ## 0.1.2 - 2026-06-01
18
+
19
+ ### Changed
20
+
21
+ - Rename the Windows prebuilt npm package to `jscpd-rs-win` to avoid npm
22
+ registry spam-policy false positives on the previous machine-generated name.
23
+ - Move the Linux arm64 prebuilt build to the Ubuntu 22.04 ARM runner for a more
24
+ stable native ARM publication path and older glibc baseline.
25
+ - Allow npm release workflow reruns for a single prebuilt target without
26
+ republishing the already-published main package.
27
+
3
28
  ## 0.1.1 - 2026-06-01
4
29
 
5
30
  ### Added
package/Cargo.lock CHANGED
@@ -483,7 +483,7 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
483
483
 
484
484
  [[package]]
485
485
  name = "jscpd-rs"
486
- version = "0.1.1"
486
+ version = "0.1.3"
487
487
  dependencies = [
488
488
  "anyhow",
489
489
  "axum",
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "jscpd-rs"
3
- version = "0.1.1"
3
+ version = "0.1.3"
4
4
  edition = "2024"
5
5
  rust-version = "1.93"
6
6
  license = "MIT"
@@ -20,6 +20,7 @@ include = [
20
20
  "/examples/**",
21
21
  "/skills/**",
22
22
  "/src/**",
23
+ "/tests/**",
23
24
  ]
24
25
 
25
26
  [[bin]]
package/README.md CHANGED
@@ -48,7 +48,7 @@ npx jscpd-rs .
48
48
  Current npm packaging note: `jscpd-rs` installs prebuilt Linux, macOS, and
49
49
  Windows binaries where available, then falls back to building from source with
50
50
  Cargo for unsupported platforms. The original `0.1.0` npm package was
51
- source-build only; use `0.1.1+` for the prebuilt-first path. See
51
+ source-build only; use `0.1.2+` for the full prebuilt-first path. See
52
52
  [docs/prebuilt-binaries.md](docs/prebuilt-binaries.md).
53
53
 
54
54
  From this repository:
@@ -138,7 +138,6 @@ jobs:
138
138
  runs-on: ubuntu-latest
139
139
  steps:
140
140
  - uses: actions/checkout@v5
141
- - uses: dtolnay/rust-toolchain@stable
142
141
  - uses: actions/setup-node@v5
143
142
  with:
144
143
  node-version: 22
@@ -235,11 +234,20 @@ Latest recorded public benchmark baseline for duplicate-code detection:
235
234
  Reproduce the public benchmark and coverage suite:
236
235
 
237
236
  ```bash
238
- PUBLIC=1 PUBLIC_RUNS=3 scripts/release-gate.sh
237
+ scripts/release-candidate.sh
238
+ ```
239
+
240
+ Benchmark native server snippet checks against upstream:
241
+
242
+ ```bash
243
+ RUNS=20 scripts/bench-server.sh
239
244
  ```
240
245
 
241
246
  Release-candidate workflows rerun the public suite before each new publication
242
- so README numbers stay tied to a concrete commit and gate output.
247
+ and enforce the core coverage gate, so README numbers stay tied to a concrete
248
+ commit and gate output. The public release gate fails below a 45x speedup on
249
+ the default benchmark cases to prevent silent performance regressions while
250
+ preserving room for normal runner noise.
243
251
 
244
252
  ## Library API
245
253
 
@@ -319,6 +327,19 @@ scripts/compat-reporters.sh
319
327
  STRICT=coverage scripts/compat-matrix.sh
320
328
  ```
321
329
 
330
+ Rust code coverage is optional and intentionally kept out of the default fast
331
+ gate:
332
+
333
+ ```bash
334
+ cargo install cargo-llvm-cov --locked
335
+ SUMMARY=1 scripts/coverage.sh
336
+ SCOPE=core SUMMARY=1 scripts/coverage.sh
337
+ SCOPE=core FAIL_UNDER_LINES=93 scripts/coverage.sh
338
+ ```
339
+
340
+ Black-box behavior tests that exercise the public API live in `tests/`. Small
341
+ private-helper tests stay next to the module they protect.
342
+
322
343
  Known upstream bug candidates and intentional compatibility exceptions are
323
344
  tracked in [docs/upstream-bugs.md](docs/upstream-bugs.md). GitHub-ready issue
324
345
  drafts are prepared in
@@ -332,6 +353,9 @@ Fast local gate:
332
353
  scripts/release-gate.sh
333
354
  ```
334
355
 
356
+ The fast gate includes `cargo fmt`, `cargo test`, shell syntax checks,
357
+ `shellcheck`, package/install checks, and the focused compatibility gates.
358
+
335
359
  Package/install gate:
336
360
 
337
361
  ```bash
@@ -353,7 +377,7 @@ FULL=1 scripts/release-gate.sh
353
377
  Public benchmark and coverage gate:
354
378
 
355
379
  ```bash
356
- PUBLIC=1 PUBLIC_RUNS=3 scripts/release-gate.sh
380
+ scripts/release-candidate.sh
357
381
  ```
358
382
 
359
383
  Release candidate gate:
@@ -127,7 +127,7 @@ These are intentional first-release limits:
127
127
  tokenizer is needed;
128
128
  - the Rust crate exposes a native Rust API, not the upstream JavaScript package
129
129
  API;
130
- - `jscpd-rs@0.1.1+` npm packaging uses prebuilt binaries on supported Linux,
130
+ - `jscpd-rs@0.1.2+` npm packaging uses prebuilt binaries on supported Linux,
131
131
  macOS, and Windows targets, with a Cargo source-build fallback for
132
132
  unsupported platforms. The original `0.1.0` npm package was source-build
133
133
  only.
@@ -192,7 +192,7 @@ npm/npx-based `jscpd-rs` CI:
192
192
  - run: npx jscpd-rs src --reporters console,json --threshold 5 --exitCode 1
193
193
  ```
194
194
 
195
- `jscpd-rs@0.1.1+` npm installs use prebuilt binaries where available and fall
195
+ `jscpd-rs@0.1.2+` npm installs use prebuilt binaries where available and fall
196
196
  back to Cargo source-build on unsupported platforms. The original `0.1.0` npm
197
197
  package still needs Rust available during installation; see the
198
198
  [prebuilt binary distribution plan](prebuilt-binaries.md).
@@ -3,15 +3,17 @@
3
3
  Current npm readiness snapshot:
4
4
 
5
5
  - Date: 2026-06-01.
6
- - Baseline commit: `e343350`; rerun `scripts/npm-package-check.sh` on the
7
- exact checkout before npm publish.
8
- - GitHub Actions `release-gate`: passed on run `26743839098`.
9
- - Local checks passed: `cargo test`, `scripts/package-check.sh`,
10
- `scripts/npm-package-check.sh`, local `npx --no-install` smoke for
11
- `jscpd-rs`, `jscpd`, and `jscpd-server`.
12
- - Package name status: `npm view jscpd-rs version` returned `E404`.
13
- - Packed artifact audit: `jscpd-rs-0.1.0.tgz`, 96 files, about 169 KiB packed,
14
- about 708 KiB unpacked.
6
+ - Current published version: `jscpd-rs@0.1.3`.
7
+ - Latest npm publish workflow: `v0.1.3` GitHub Release workflow.
8
+ - Published platform packages: `jscpd-rs-linux-x64-gnu`,
9
+ `jscpd-rs-linux-arm64-gnu`, `jscpd-rs-darwin-x64`,
10
+ `jscpd-rs-darwin-arm64`, and `jscpd-rs-win`.
11
+ - Post-publication smoke passed from clean temporary directories:
12
+ `npm install jscpd-rs@0.1.3`, `jscpd-rs --version`, `jscpd --version`,
13
+ `jscpd-server --version`, and
14
+ `npx --package jscpd-rs@0.1.3 jscpd-rs --version`.
15
+ - Rerun `scripts/npm-package-check.sh` on the exact checkout before publishing
16
+ any new npm version.
15
17
 
16
18
  The npm package is `jscpd-rs`. It exposes these bin commands:
17
19
 
@@ -19,7 +21,7 @@ The npm package is `jscpd-rs`. It exposes these bin commands:
19
21
  - `jscpd`: installed alias for the native `jscpd` CLI.
20
22
  - `jscpd-server`: installed alias for the native server binary.
21
23
 
22
- `jscpd-rs@0.1.1+` publishes prebuilt platform packages before the main
24
+ `jscpd-rs@0.1.2+` publishes prebuilt platform packages before the main
23
25
  `jscpd-rs` package. The CLI behavior stays the same, and the source-build path
24
26
  remains the fallback for unsupported platforms. The original `0.1.0` package
25
27
  was source-build only; see the
@@ -57,7 +59,7 @@ Before actual publication, run:
57
59
  git status --short
58
60
  npm whoami
59
61
  scripts/npm-package-check.sh
60
- npm view jscpd-rs version
62
+ npm view jscpd-rs@X.Y.Z version
61
63
  ```
62
64
 
63
65
  For a new version, `npm view jscpd-rs@X.Y.Z version` should fail before the
@@ -70,14 +72,8 @@ crate and GitHub tag have already been published: that script is the full
70
72
  Cargo/GitHub first-publication gate and intentionally checks that the crate name
71
73
  and release tag are still available.
72
74
 
73
- If the package name is still free and the npm account is logged in:
74
-
75
- ```bash
76
- scripts/npm-package-check.sh
77
- npm publish --access public
78
- ```
79
-
80
- If the account requires a one-time password for publish:
75
+ If an emergency manual fallback is approved and the npm account requires a
76
+ one-time password for publish:
81
77
 
82
78
  ```bash
83
79
  npm publish --access public --otp 123456
@@ -97,11 +93,17 @@ This repository provides a publish workflow:
97
93
  ```
98
94
 
99
95
  The workflow runs automatically when a non-draft, non-prerelease GitHub Release
100
- is published. It checks out the release tag, verifies that the tag matches the
101
- `package.json` version, verifies that the main npm version is not already
102
- published, builds platform packages in a native runner matrix, publishes those
103
- platform packages first, runs `scripts/npm-package-check.sh`, and then
104
- publishes the main `jscpd-rs` package.
96
+ is published. It checks out the release tag, runs `scripts/release-candidate.sh`
97
+ as a preflight, verifies that the tag matches the `package.json` version,
98
+ verifies that the main npm version is not already published, builds platform
99
+ packages in a native runner matrix, publishes those platform packages first,
100
+ verifies that every optional platform package exists for the release version,
101
+ runs `scripts/npm-package-check.sh`, and then publishes the main `jscpd-rs`
102
+ package.
103
+
104
+ The main package is blocked when any configured platform package fails or is
105
+ missing. For a target-only rerun, set `publish_main=false`; using `target` with
106
+ `publish_main=true` is rejected by the workflow.
105
107
 
106
108
  It can also be run manually from GitHub Actions as a fallback by entering
107
109
  `jscpd-rs` in the confirmation input.
@@ -127,13 +129,15 @@ Then publish automatically from GitHub:
127
129
  4. Create and publish a GitHub Release with tag `vX.Y.Z`.
128
130
  5. GitHub Actions will run `npm-publish` from that release tag.
129
131
 
130
- Manual fallback:
132
+ Manual workflow fallback:
131
133
 
132
134
  1. Open GitHub Actions.
133
135
  2. Select the `npm-publish` workflow.
134
136
  3. Click **Run workflow** on `main`.
135
137
  4. Enter `jscpd-rs` for `package_name`.
136
- 5. Run the workflow.
138
+ 5. Optionally enter a single target key such as `linux-arm64-gnu` and set
139
+ `publish_main=false` when only one prebuilt package needs a rerun.
140
+ 6. Run the workflow.
137
141
 
138
142
  If npm does not allow Trusted Publishing configuration before a platform package
139
143
  version exists, add a short-lived `NPM_TOKEN` GitHub secret for the first
@@ -1,6 +1,6 @@
1
1
  # Prebuilt Binary Distribution
2
2
 
3
- `jscpd-rs` is a native Rust CLI. Starting with `jscpd-rs@0.1.1`, npm
3
+ `jscpd-rs` is a native Rust CLI. Starting with `jscpd-rs@0.1.2`, npm
4
4
  distribution uses a small main package plus platform-specific optional
5
5
  packages. The original `0.1.0` npm package was source-build only.
6
6
 
@@ -28,10 +28,10 @@ The target matrix is defined in `npm/prebuilt-targets.json`.
28
28
  | Package | Rust target | Runner |
29
29
  | --- | --- | --- |
30
30
  | `jscpd-rs-linux-x64-gnu` | `x86_64-unknown-linux-gnu` | `ubuntu-24.04` |
31
- | `jscpd-rs-linux-arm64-gnu` | `aarch64-unknown-linux-gnu` | `ubuntu-24.04-arm` |
31
+ | `jscpd-rs-linux-arm64-gnu` | `aarch64-unknown-linux-gnu` | `ubuntu-22.04-arm` |
32
32
  | `jscpd-rs-darwin-x64` | `x86_64-apple-darwin` | `macos-15-intel` |
33
33
  | `jscpd-rs-darwin-arm64` | `aarch64-apple-darwin` | `macos-15` |
34
- | `jscpd-rs-win32-x64-msvc` | `x86_64-pc-windows-msvc` | `windows-2025` |
34
+ | `jscpd-rs-win` | `x86_64-pc-windows-msvc` | `windows-2025` |
35
35
 
36
36
  Consider Linux musl and Windows arm64 only after install data or user reports
37
37
  show demand.
@@ -54,12 +54,20 @@ show demand.
54
54
  The GitHub Release workflow in `.github/workflows/npm-publish.yml` publishes in
55
55
  this order:
56
56
 
57
- 1. Verify that the GitHub Release tag matches `package.json`.
58
- 2. Build platform packages in a native runner matrix.
59
- 3. Smoke-test `jscpd --version` and `jscpd-server --version` for each package.
60
- 4. Publish the platform packages.
61
- 5. Run `scripts/npm-package-check.sh`.
62
- 6. Publish the main `jscpd-rs` package.
57
+ 1. Run `scripts/release-candidate.sh`, including the full compatibility
58
+ matrix, public speed gate, and core coverage gate.
59
+ 2. Verify that the GitHub Release tag matches `package.json`.
60
+ 3. Build platform packages in a native runner matrix.
61
+ 4. Smoke-test `jscpd --version` and `jscpd-server --version` for each package.
62
+ 5. Publish the platform packages.
63
+ 6. Verify every optional platform package is published for the release version.
64
+ 7. Run `scripts/npm-package-check.sh`.
65
+ 8. Publish the main `jscpd-rs` package.
66
+
67
+ The main npm package is intentionally blocked when any configured platform
68
+ package fails or is missing. Manual target-only reruns must set
69
+ `publish_main=false`; the main package should not be published with an
70
+ accidental source-build fallback on a supported platform.
63
71
 
64
72
  The workflow publishes with npm provenance enabled. It is designed for Trusted
65
73
  Publishing, but `NPM_TOKEN` can be kept as a temporary bootstrap fallback for
@@ -83,7 +91,7 @@ Packages:
83
91
  - `jscpd-rs-linux-arm64-gnu`
84
92
  - `jscpd-rs-darwin-x64`
85
93
  - `jscpd-rs-darwin-arm64`
86
- - `jscpd-rs-win32-x64-msvc`
94
+ - `jscpd-rs-win`
87
95
 
88
96
  If a temporary npm token is used for the first platform-package bootstrap,
89
97
  revoke it after Trusted Publishing succeeds.
@@ -31,7 +31,7 @@ Usage:
31
31
  LIST=1 scripts/public-bench-suite.sh
32
32
  CASES=react,next RUNS=3 scripts/public-bench-suite.sh
33
33
  CHECK_COMPAT=1 CASES=react scripts/public-bench-suite.sh
34
- MIN_SPEEDUP=10 CASES=react,next RUNS=3 scripts/public-bench-suite.sh
34
+ MIN_SPEEDUP=45 CASES=react,next RUNS=3 scripts/public-bench-suite.sh
35
35
  UPSTREAM_TIMEOUT=600s CASES=vscode RUNS=1 scripts/public-bench-suite.sh
36
36
  PUBLIC=1 PUBLIC_CASES=react,next PUBLIC_RUNS=3 scripts/release-gate.sh
37
37
  ```
@@ -47,6 +47,10 @@ bounded by `UPSTREAM_TIMEOUT` (`600s` by default) so optional stress cases canno
47
47
  hang a release gate indefinitely; set `RUST_TIMEOUT` or `UPSTREAM_TIMEOUT` to an
48
48
  empty value to disable that side's timeout.
49
49
 
50
+ The release gate uses `PUBLIC_MIN_SPEEDUP=45` by default. This intentionally
51
+ locks the 50x+ product baseline with enough headroom for normal runner noise;
52
+ lowering that threshold requires an explicit release decision.
53
+
50
54
  When `CHECK_COMPAT=1` is enabled, the suite runs the same coverage-first report
51
55
  comparison used by the fixture gates. `react`, `next`, and `prometheus` include
52
56
  narrow allowlists for upstream overextended ranges documented in
@@ -79,6 +79,8 @@ Before publishing, all of these must be true:
79
79
  - `git submodule status jscpd` points at the reviewed upstream reference.
80
80
  - `scripts/release-candidate.sh` passes on the exact code commit being tagged.
81
81
  - GitHub Actions `release-gate` passes on the pushed commit.
82
+ - GitHub Actions `crates-publish` and `npm-publish` release jobs are allowed to
83
+ run their own release-candidate preflight before publishing.
82
84
  - `scripts/package-check.sh` passes and the package file list excludes
83
85
  `jscpd/`, `target/`, `node_modules/`, and `scripts/`.
84
86
  - `scripts/npm-package-check.sh` passes, including `npm pack`,
@@ -89,9 +91,12 @@ Before publishing, all of these must be true:
89
91
  - `README.md`, `docs/compat-baseline.md`, and
90
92
  `docs/public-benchmark-suite.md` contain the same recorded public benchmark
91
93
  numbers.
92
- - For the first publication, the `jscpd-rs` crate and npm package names are
93
- still available or already owned by this project, and `v0.1.0` does not
94
- already exist locally or on the remote.
94
+ - For a new publication, the target crate version, npm package versions, and
95
+ `vX.Y.Z` Git tag are not already published, unless an explicitly documented
96
+ target-only npm rerun is being used for a prebuilt package.
97
+ - For npm publication, every configured prebuilt optional package is published
98
+ before the main `jscpd-rs` package; target-only reruns use
99
+ `publish_main=false`.
95
100
  - `docs/upstream-bugs.md` contains concrete repro commands for upstream issues
96
101
  we plan to file.
97
102
  - `docs/upstream-issue-drafts.md` contains reviewed issue drafts ready to
@@ -140,18 +145,20 @@ scripts/prepublish-check.sh
140
145
  ```
141
146
 
142
147
  The script checks clean git state, the reviewed `jscpd` submodule reference,
143
- local and remote tag availability, exact crate-name availability through
144
- `cargo search`, exact npm package-name availability through `npm view`,
148
+ local and remote tag availability, exact crate version availability through
149
+ `cargo info`, exact npm package version availability through `npm view`,
145
150
  benchmark-number consistency across release docs, the full release-candidate
146
151
  gate, package/install validation, npm pack/npx validation, and
147
- `cargo publish --dry-run --locked`. Set `RUN_RELEASE_CANDIDATE=0` only when the
148
- same code commit already has fresh local and CI release-candidate evidence.
152
+ `cargo publish --dry-run --locked`. The npm availability check covers the main
153
+ package and every prebuilt optional package. Set
154
+ `RUN_RELEASE_CANDIDATE=0` only when the same code commit already has fresh
155
+ local and CI release-candidate evidence.
149
156
 
150
157
  Then push the exact release commit and verify the GitHub Actions
151
158
  `release-gate` result. Use the workflow dispatch `release_candidate` input for a
152
159
  full CI-side release-candidate run when needed.
153
160
 
154
- For the first publication candidate checked on 2026-05-31, local and remote
161
+ Historical first publication candidate checked on 2026-05-31: local and remote
155
162
  `v0.1.0` tag lookups returned no entries. `cargo search jscpd-rs --limit 5`
156
163
  returned no exact crate, `npm view jscpd-rs version` returned `E404`, and the
157
164
  sparse crates.io index path
@@ -178,8 +185,8 @@ two explicit commands above are a manual smoke equivalent for post-tag checks.
178
185
  Track these after the first release candidate:
179
186
 
180
187
  - Reduce noisy extra Rust findings where they are user-visible false positives.
181
- - Verify the first npm prebuilt platform-package publication before broad npm
182
- promotion so Node users can install without Cargo; see the
188
+ - Monitor npm prebuilt install behavior and add Linux musl or Windows arm64
189
+ packages only when install data or user reports show demand; see the
183
190
  [prebuilt binary distribution plan](prebuilt-binaries.md).
184
191
  - Add native persistent store/cache only if release-scale benchmark data needs
185
192
  it.
@@ -77,8 +77,14 @@ choice insufficient.
77
77
 
78
78
  - Performance remains a product requirement. Public benchmark runs should be
79
79
  repeated before publication with pinned commits and recorded speedups.
80
+ - Refactors, simplifications, compatibility fixes, and dependency swaps must not
81
+ introduce sustained speed regressions. If a change touches discovery,
82
+ tokenization, matching, source loading, reporter hot paths, or server snippet
83
+ checks, rerun the affected benchmark case before treating the core as stable.
80
84
  - The aspirational target is 50x on representative cases, but release gating
81
- should use measured thresholds from the selected public benchmark suite.
85
+ should use measured thresholds from the selected public benchmark suite. The
86
+ default public release gate currently fails below 45x to preserve the 50x+
87
+ baseline while leaving room for runner noise.
82
88
 
83
89
  ## Approved Complex Feature Choices
84
90
 
@@ -23,7 +23,9 @@ current implementation status.
23
23
  | Native Rust API | ready | `jscpd`, `jscpd_with_exit_callback`, `Tokenizer`, `Detector`, `Statistic`, `MemoryStore`, `detect_clones`, `detect_clones_and_statistic`, `detect_clones_and_statistics`, `detect_source_files`, default options, argv option parsing, supported formats, and format lookup helpers expose the app, tokenizer, detector, statistics, and store core for path-based and in-memory integrations. See `docs/api-parity.md`. |
24
24
  | Native server | partial | `jscpd-server` exposes `/`, `/api/health`, `/api/stats`, `/api/check`, `/api/recheck`, and `/mcp`; exact help text, stable CLI, HTTP success/error, and MCP contracts are gated; `/api/check` reuses prepared project token maps; exact upstream Streamable HTTP SDK behavior remains follow-up. |
25
25
  | Performance harness | ready | Local benchmark script and public benchmark suite with pinned output recording and speedup gates. |
26
- | Release gates | ready | Default CI gate, full compatibility matrix, Cargo/npm package checks, reporter/config/CLI/blame gates. The default gate now prints per-step timings, caches Cargo/pnpm/upstream build artifacts, and uses target-reuse npm package smoke in push/PR CI while keeping cold npm source-build in release-candidate/prepublish gates. |
26
+ | Server benchmark harness | ready | `scripts/bench-server.sh` compares native and upstream `/api/check` latency on the same initialized project and snippet payload. Keep it advisory until real server usage needs a blocking gate. |
27
+ | Release gates | ready | Default CI gate, full compatibility matrix, Cargo/npm package checks, reporter/config/CLI/blame gates. The default gate prints per-step timings, caches Cargo/pnpm/upstream build artifacts, and uses target-reuse npm package smoke in push/PR CI while keeping cold npm source-build in release-candidate/prepublish gates. GitHub npm/crates publish workflows now run `scripts/release-candidate.sh` before publishing. |
28
+ | Code coverage tooling | ready | One script: `scripts/coverage.sh`. Use `SCOPE=full` for the full advisory report and `SCOPE=core` for core coverage that runs all test targets while excluding CLI/server glue from the report. Local baseline on 2026-06-01: full 91.54% line / 90.13% region coverage; core 93.18% line / 91.39% region coverage. `scripts/release-candidate.sh` enforces `SCOPE=core FAIL_UNDER_LINES=93 scripts/coverage.sh` by default. |
27
29
 
28
30
  ## Partial Or Follow-Up
29
31
 
@@ -35,8 +37,8 @@ current implementation status.
35
37
  | HTML reporter polish | practical parity | Keep self-contained HTML stable. Do not chase pixel-perfect upstream parity for the first release. |
36
38
  | Terminal cosmetics | practical parity | Important messages are gated; exact wrapping/order remains lower priority. |
37
39
  | Upstream JavaScript API parity | follow-up | Native Rust helpers cover the practical app/tokenizer/detector/statistics/store concepts, including an embeddable argv runner and tokenizer map generation; exact JS package export shape is not implemented in the Rust crate. See `docs/api-parity.md`. |
38
- | Server snippet matching | optimized baseline | Native `/api/check` and MCP `check_duplication` are functional and reuse project token maps from the last scan; add a dedicated window index only if real server benchmarks require it. |
39
- | Npm prebuilt binaries | ready for 0.1.1 | Platform-specific optional package metadata, runtime prebuilt resolution, prebuilt/fallback package checks, and GitHub Release publishing automation are wired for `jscpd-rs@0.1.1+`. See the [prebuilt binary distribution plan](prebuilt-binaries.md). |
40
+ | Server snippet matching | optimized baseline | Native `/api/check` and MCP `check_duplication` are functional and reuse project token maps from the last scan; use `scripts/bench-server.sh` before adding a dedicated window index. |
41
+ | Npm prebuilt binaries | ready | Platform-specific optional package metadata, runtime prebuilt resolution, prebuilt/fallback package checks, and GitHub Release publishing automation are wired for `jscpd-rs@0.1.2+`. The main npm package is blocked if any configured platform package fails or is missing. See the [prebuilt binary distribution plan](prebuilt-binaries.md). |
40
42
  | Latest full publication gate | ready | `scripts/prepublish-check.sh` passed locally on code commit `8c3da0e`, including `scripts/release-candidate.sh`, package/install verification, crate/tag availability checks, npm package/name/npx verification, and `cargo publish --dry-run --locked`. GitHub Actions default `release-gate` passed on code commit `8c3da0e` in run `26710762680`. After benchmark documentation updates, `RUN_RELEASE_CANDIDATE=0 scripts/prepublish-check.sh` is the package/dry-run refresh gate for the exact package contents being tagged. |
41
43
 
42
44
  ## Post-MVP
@@ -49,3 +51,4 @@ current implementation status.
49
51
  | MCP endpoint polish | Core native endpoint exists; tighten exact SDK edge cases only when MCP client compatibility demands it. |
50
52
  | Persistent cache/store backends | Add only if public benchmark data proves the in-memory path is insufficient. |
51
53
  | Full Prism grammar port | Do not rewrite all grammars eagerly; use native crates or small scanners only for proven gaps. |
54
+ | CI coverage enforcement | Keep coverage out of the default fast gate until CI runtime is measured; the core coverage gate now runs in release-candidate flows. |
@@ -29,7 +29,7 @@ npm install -g jscpd-rs
29
29
  npx jscpd-rs --version
30
30
  ```
31
31
 
32
- `jscpd-rs@0.1.1+` installs prebuilt Linux, macOS, and Windows binaries where
32
+ `jscpd-rs@0.1.2+` installs prebuilt Linux, macOS, and Windows binaries where
33
33
  available and falls back to building from source with Cargo for unsupported
34
34
  platforms. The original `0.1.0` npm package was source-build only. See the
35
35
  [prebuilt binary distribution plan](prebuilt-binaries.md).
@@ -15,7 +15,7 @@
15
15
  "cpu": "arm64",
16
16
  "libc": "glibc",
17
17
  "rustTarget": "aarch64-unknown-linux-gnu",
18
- "runner": "ubuntu-24.04-arm"
18
+ "runner": "ubuntu-22.04-arm"
19
19
  },
20
20
  "darwin-x64": {
21
21
  "packageName": "jscpd-rs-darwin-x64",
@@ -34,8 +34,8 @@
34
34
  "runner": "macos-15"
35
35
  },
36
36
  "win32-x64-msvc": {
37
- "packageName": "jscpd-rs-win32-x64-msvc",
38
- "description": "Prebuilt Windows x64 MSVC binaries for jscpd-rs",
37
+ "packageName": "jscpd-rs-win",
38
+ "description": "Prebuilt Windows x64 binaries for jscpd-rs",
39
39
  "os": "win32",
40
40
  "cpu": "x64",
41
41
  "rustTarget": "x86_64-pc-windows-msvc",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jscpd-rs",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "50x+ faster duplicate-code detector for CI/CD; jscpd-compatible CLI, SARIF, JSON, HTML reports",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,11 +28,11 @@
28
28
  "cli"
29
29
  ],
30
30
  "optionalDependencies": {
31
- "jscpd-rs-darwin-arm64": "0.1.1",
32
- "jscpd-rs-darwin-x64": "0.1.1",
33
- "jscpd-rs-linux-arm64-gnu": "0.1.1",
34
- "jscpd-rs-linux-x64-gnu": "0.1.1",
35
- "jscpd-rs-win32-x64-msvc": "0.1.1"
31
+ "jscpd-rs-darwin-arm64": "0.1.3",
32
+ "jscpd-rs-darwin-x64": "0.1.3",
33
+ "jscpd-rs-linux-arm64-gnu": "0.1.3",
34
+ "jscpd-rs-linux-x64-gnu": "0.1.3",
35
+ "jscpd-rs-win": "0.1.3"
36
36
  },
37
37
  "bin": {
38
38
  "jscpd-rs": "npm/bin/jscpd-rs.js",
@@ -3,7 +3,7 @@ use std::path::PathBuf;
3
3
 
4
4
  use anyhow::{Result, bail};
5
5
  use clap::Parser;
6
- use jscpd_rs::cli::{Cli, Options};
6
+ use jscpd_rs::{Cli, Options};
7
7
 
8
8
  #[tokio::main]
9
9
  async fn main() {
package/src/blame.rs CHANGED
@@ -94,6 +94,10 @@ fn blame_line_regex() -> &'static Regex {
94
94
  #[cfg(test)]
95
95
  mod tests {
96
96
  use super::*;
97
+ use crate::tokenizer::Location;
98
+ use std::fs;
99
+ use std::path::{Path, PathBuf};
100
+ use std::time::{SystemTime, UNIX_EPOCH};
97
101
 
98
102
  #[test]
99
103
  fn parses_git_blame_lines() {
@@ -127,4 +131,116 @@ cccccccc (Carol 2024-01-03 00:00:00 +0000 3) third
127
131
  assert_eq!(sliced["2"].author, "Bob");
128
132
  assert_eq!(sliced["3"].author, "Carol");
129
133
  }
134
+
135
+ #[test]
136
+ fn ignores_malformed_git_blame_lines() {
137
+ let blame = parse_git_blame(
138
+ "\
139
+ not blame output
140
+ aaaaaaaa (Alice 2024-01-01 00:00:00 +0000 1) first
141
+ bbbbbbbb (Bob 2024-01-02 00:00 +0000 2) bad date
142
+ ",
143
+ );
144
+
145
+ assert_eq!(blame.len(), 1);
146
+ assert_eq!(blame["1"].author, "Alice");
147
+ }
148
+
149
+ #[test]
150
+ fn applies_cached_blame_to_fragment_range() {
151
+ let mut cache = HashMap::from([(
152
+ "src/a.js".to_string(),
153
+ Some(parse_git_blame(
154
+ "\
155
+ aaaaaaaa (Alice 2024-01-01 00:00:00 +0000 1) first
156
+ bbbbbbbb (Bob 2024-01-02 00:00:00 +0000 2) second
157
+ cccccccc (Carol 2024-01-03 00:00:00 +0000 3) third
158
+ ",
159
+ )),
160
+ )]);
161
+ let mut fragment = fragment("src/a.js", 2, 3);
162
+
163
+ apply_fragment_blame(&mut fragment, &mut cache);
164
+
165
+ let blame = fragment.blame.expect("fragment blame");
166
+ assert_eq!(blame.keys().cloned().collect::<Vec<_>>(), vec!["2", "3"]);
167
+ assert_eq!(blame["2"].author, "Bob");
168
+ assert_eq!(blame["3"].author, "Carol");
169
+ }
170
+
171
+ #[test]
172
+ fn omits_cached_blame_when_file_or_range_has_no_blame() {
173
+ let mut cache = HashMap::from([
174
+ ("missing.js".to_string(), None),
175
+ (
176
+ "src/a.js".to_string(),
177
+ Some(parse_git_blame(
178
+ "aaaaaaaa (Alice 2024-01-01 00:00:00 +0000 10) tenth\n",
179
+ )),
180
+ ),
181
+ ]);
182
+ let mut missing = fragment("missing.js", 1, 1);
183
+ let mut outside_range = fragment("src/a.js", 1, 2);
184
+
185
+ apply_fragment_blame(&mut missing, &mut cache);
186
+ apply_fragment_blame(&mut outside_range, &mut cache);
187
+
188
+ assert!(missing.blame.is_none());
189
+ assert!(outside_range.blame.is_none());
190
+ }
191
+
192
+ #[test]
193
+ fn reads_git_blame_for_tracked_file() {
194
+ let repo = unique_temp_dir("blame-repo");
195
+ fs::create_dir_all(&repo).unwrap();
196
+ git(&repo, &["init", "-q"]);
197
+ git(&repo, &["config", "user.email", "jscpd-rs@example.test"]);
198
+ git(&repo, &["config", "user.name", "Jscpd Rs"]);
199
+ let path = repo.join("tracked.js");
200
+ fs::write(&path, "const first = 1;\nconst second = 2;\n").unwrap();
201
+ git(&repo, &["add", "tracked.js"]);
202
+ git(&repo, &["commit", "--no-gpg-sign", "-q", "-m", "initial"]);
203
+
204
+ let blame = blame_file(path.to_str().unwrap()).expect("git blame output");
205
+ let _ = fs::remove_dir_all(&repo);
206
+
207
+ assert_eq!(blame.len(), 2);
208
+ assert_eq!(blame["1"].author, "Jscpd Rs");
209
+ assert_eq!(blame["2"].line, "2");
210
+ }
211
+
212
+ fn fragment(source_id: &str, start_line: usize, end_line: usize) -> Fragment {
213
+ Fragment {
214
+ source_id: source_id.to_string(),
215
+ start: location(start_line),
216
+ end: location(end_line),
217
+ range: [0, 0],
218
+ blame: None,
219
+ }
220
+ }
221
+
222
+ fn location(line: usize) -> Location {
223
+ Location {
224
+ line,
225
+ column: 1,
226
+ position: 0,
227
+ }
228
+ }
229
+
230
+ fn git(repo: &Path, args: &[&str]) {
231
+ let status = Command::new("git")
232
+ .args(args)
233
+ .current_dir(repo)
234
+ .status()
235
+ .expect("run git");
236
+ assert!(status.success(), "git {args:?} failed");
237
+ }
238
+
239
+ fn unique_temp_dir(label: &str) -> PathBuf {
240
+ let suffix = SystemTime::now()
241
+ .duration_since(UNIX_EPOCH)
242
+ .unwrap()
243
+ .as_nanos();
244
+ std::env::temp_dir().join(format!("jscpd-rs-{label}-{}-{suffix}", std::process::id()))
245
+ }
130
246
  }