dsh-paper-search 0.1.1 → 0.1.2

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
@@ -4,7 +4,7 @@
4
4
 
5
5
  | dsh-paper-search | DeepSeek Harness | Diuji pada |
6
6
  |---|---|---|
7
- | 0.1.1 | 0.1.7-rc.2 | 28 Sep 2026, Windows, Node 24 |
7
+ | 0.1.2 | 0.1.7-rc.2 | 28 Sep 2026, Windows, Node 24 |
8
8
  | ~~0.1.0~~ | — | **JANGAN DIPAKAI — plugin gagal dimuat, lihat 0.1.1** |
9
9
 
10
10
  Paket ini tidak memakai API internal DSH selain `ctx.tools.register` dan
@@ -12,6 +12,40 @@ Paket ini tidak memakai API internal DSH selain `ctx.tools.register` dan
12
12
  berjalan di profil ini (`dsh-search-cascade`), jadi titik patahnya sama dan sudah
13
13
  diketahui.
14
14
 
15
+ ## [0.1.2] - 2026-09-28
16
+
17
+ ### Fixed
18
+
19
+ - **Judul Garuda masih bisa terduplikasi.** Perbaikan di rilis sebelumnya baru
20
+ menangani pengulangan **persis** (`X X X`). Setelah mengukur **50 judul
21
+ sungguhan** (5 kueri, diambil apa adanya dari halaman Garuda), ternyata ada
22
+ **empat** bentuk pengulangan, bukan satu:
23
+
24
+ | Bentuk | Contoh | Panjang |
25
+ |---|---|---|
26
+ | A — periode persis | `X X X X X X` | 255 → 43 |
27
+ | B — diulang sesudah `": "` | `X: X` | 194 → 96 |
28
+ | C — awalan lalu `X: X` | `NLP, Machine Learning X: X` | 270 → 145 |
29
+ | D — frasa diulang di awal | `IMPLEMENTASI PENDIDIKAN KARAKTER IMPLEMENTASI …` | 306 → 295 |
30
+
31
+ `runtuhkanPeriodik()` diganti **`runtuhkanJudul()`** yang menangani keempatnya,
32
+ termasuk pengulangan dengan **kapitalisasi berbeda** (252 → 125) — Garuda
33
+ memang sering mengulang judul dalam huruf besar lalu huruf kecil.
34
+
35
+ **Yang paling penting, dan inilah yang diuji:** judul **sah** berformat
36
+ `Judul: subjudul`, `Judul: (studi kasus)`, dan `Judul: kata kunci` **tidak**
37
+ ikut terpotong. Karena itu aturannya menuntut bagian sesudah `": "` benar-benar
38
+ **sama** dengan akhiran bagian sebelumnya — bukan sekadar ada titik dua. Pada
39
+ 50 judul itu hasilnya: **14 diringkas, 36 dibiarkan, 0 cacat**, dan **15 judul
40
+ bertitik dua tetap utuh**.
41
+
42
+ ### Added
43
+
44
+ - **11 asersi regresi baru** di `test/uji-sumber.mjs`, memakai teks yang diambil
45
+ apa adanya dari Garuda. Lima di antaranya justru menjaga agar judul **sah**
46
+ tidak terpotong — tanpa itu, aturannya bisa "lulus" hanya dengan memotong
47
+ setiap judul yang bertitik dua.
48
+
15
49
  ## [0.1.1] - 2026-09-28
16
50
 
17
51
  ### Fixed
package/lib/sources.js CHANGED
@@ -74,26 +74,56 @@ function normDoi(doi) {
74
74
  }
75
75
 
76
76
  /**
77
- * Beberapa portal menulis judul di dalam elemen <xmp> dan MENGULANGNYA untuk
78
- * mengisi lebar tampilan. Terukur di Garuda 28 Sep 2026: judul
79
- * "PENDIDIKAN KARAKTER ANAK USIA SEKOLAH DASAR" (44 huruf) muncul sekitar enam
80
- * kali dalam satu <xmp> sehingga panjangnya 255 huruf.
77
+ * Garuda menulis judul di dalam elemen <xmp> dengan BEBERAPA bentuk pengulangan,
78
+ * dan mengulanginya untuk mengisi lebar tampilan. Keempatnya diukur 28 Sep 2026
79
+ * dari **50 judul sungguhan** (5 kueri):
81
80
  *
82
- * Fungsi ini mencari periode terkecil dan menyisakan SATU salinan. Ia hanya
83
- * bertindak bila pengulangannya PERSIS dari awal sampai akhir — kalau tidak,
84
- * teks dibiarkan apa adanya. Sengaja konservatif: lebih baik judul berlebihan
85
- * daripada judul yang terpotong salah.
81
+ * A. periode persis "X X X X X X" (255 huruf)
82
+ * B. diulang sesudah ": " "X: X" (194 huruf)
83
+ * C. awalan lalu "X: X" "NLP, Machine Learning X: X" (270 huruf)
84
+ * D. frasa diulang di awal "IMPLEMENTASI PENDIDIKAN KARAKTER IMPLEMENTASI …"
85
+ *
86
+ * Yang TIDAK boleh disentuh — dan sudah diperiksa pada 50 sampel itu: judul SAH
87
+ * berformat "Judul: subjudul", "Judul: (studi kasus)", dan "Judul: kata kunci".
88
+ * Karena itu aturan (c) menuntut bagian sesudah ": " benar-benar SAMA dengan
89
+ * akhiran bagian sebelumnya — bukan sekadar ada titik dua. Pada 50 sampel,
90
+ * tidak satu pun judul sah ikut terpotong.
91
+ *
92
+ * Sengaja konservatif: lebih baik judul berlebihan daripada judul terpotong salah.
86
93
  */
87
- function runtuhkanPeriodik(s) {
88
- const t = (s ?? '').trim();
89
- const n = t.length;
90
- if (n < 30) return t;
91
- for (let p = 10; p <= Math.floor(n / 2); p++) {
92
- let cocok = true;
93
- for (let i = p; i < n; i++) {
94
- if (t[i] !== t[i % p]) { cocok = false; break; }
94
+ export function runtuhkanJudul(s) {
95
+ let t = (s ?? '').trim();
96
+ for (let putaran = 0; putaran < 4; putaran++) {
97
+ const sebelum = t;
98
+
99
+ // (A) periode persis: cari periode terkecil, sisakan satu salinan.
100
+ const n = t.length;
101
+ for (let p = 10; p <= Math.floor(n / 2); p++) {
102
+ let cocok = true;
103
+ for (let i = p; i < n; i++) {
104
+ if (t[i] !== t[i % p]) { cocok = false; break; }
105
+ }
106
+ if (cocok) { t = t.slice(0, p).trim(); break; }
107
+ }
108
+
109
+ // (D) frasa yang diulang di awal: "A A sisa" -> "A sisa".
110
+ // `A` harus berakhir di batas kata, supaya tidak memotong di tengah kata.
111
+ for (let p = 8; p <= Math.floor(t.length / 2); p++) {
112
+ const a = t.slice(0, p);
113
+ if (!/[\s.)\]]$/.test(a)) continue;
114
+ if (t.startsWith(a + a)) { t = (a + t.slice(2 * p)).trim(); break; }
95
115
  }
96
- if (cocok) return t.slice(0, p).trim();
116
+
117
+ // (B)/(C) diulang sesudah ": " terakhir — dibandingkan TANPA peduli huruf
118
+ // besar/kecil, karena Garuda sering mengulang judul dengan kapitalisasi beda.
119
+ const pisah = t.lastIndexOf(': ');
120
+ if (pisah > 0) {
121
+ const ekor = t.slice(pisah + 2).trim();
122
+ const kepala = t.slice(0, pisah).trim();
123
+ if (ekor.length >= 20 && kepala.toLowerCase().endsWith(ekor.toLowerCase())) t = kepala;
124
+ }
125
+
126
+ if (t === sebelum) break;
97
127
  }
98
128
  return t;
99
129
  }
@@ -101,7 +131,7 @@ function runtuhkanPeriodik(s) {
101
131
  function buatPaper(p) {
102
132
  const doi = normDoi(p.doi);
103
133
  return {
104
- title: potong(runtuhkanPeriodik(bersihTeks(p.title) ?? ''), 300),
134
+ title: potong(runtuhkanJudul(bersihTeks(p.title) ?? ''), 300),
105
135
  authors: Array.isArray(p.authors) ? p.authors.map(bersihTeks).filter(Boolean).slice(0, 15) : [],
106
136
  year: Number.isFinite(Number(p.year)) && Number(p.year) > 1500 ? Number(p.year) : null,
107
137
  source: p.source,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-paper-search",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Literature search for DeepSeek Harness: thirteen international sources (Crossref, OpenAlex, DOAJ, Europe PMC, PubMed, PubMed Central, arXiv, Semantic Scholar, CORE, Zenodo, HAL, IACR ePrint, Unpaywall) and three Indonesian journal portals (Garuda, Sinta, IOS OneSearch), all native HTTP with no external CLI required, plus a status tool that reports which sources answer and which credentials are configured.",
5
5
  "license": "MIT",
6
6
  "type": "module",