medsci-skills 5.9.0 → 5.9.1
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/README.md
CHANGED
|
@@ -57,7 +57,9 @@ rather than reimplementing the ecosystem. Clinical AI model research
|
|
|
57
57
|
engineering is in scope; it is **not** a diagnostic tool, an autonomous author, or a
|
|
58
58
|
general AI-scientist platform, and every output requires human-expert verification.
|
|
59
59
|
New here? See the [3 workflows below](#start-here-3-workflows), the
|
|
60
|
-
[FAQ](docs/faq.md),
|
|
60
|
+
[FAQ](docs/faq.md), the
|
|
61
|
+
[research connectors it calls](docs/connectors.md) (keyless public APIs — nothing to set
|
|
62
|
+
up in the common case), and the
|
|
61
63
|
[scope boundary](ROADMAP.md#not-planned--explicitly-out-of-scope).
|
|
62
64
|
|
|
63
65
|
---
|
|
@@ -1578,8 +1578,8 @@
|
|
|
1578
1578
|
},
|
|
1579
1579
|
{
|
|
1580
1580
|
"path": "skills/fulltext-retrieval/fetch_oa.py",
|
|
1581
|
-
"size":
|
|
1582
|
-
"sha256": "
|
|
1581
|
+
"size": 24810,
|
|
1582
|
+
"sha256": "12bfbf094d338ac461267cea133c0a63a66bc0d2dadd28727921149bc5b72855"
|
|
1583
1583
|
},
|
|
1584
1584
|
{
|
|
1585
1585
|
"path": "skills/fulltext-retrieval/fetch_oa_report_challenge/expected/projection.json",
|
|
@@ -3853,8 +3853,8 @@
|
|
|
3853
3853
|
},
|
|
3854
3854
|
{
|
|
3855
3855
|
"path": "skills/verify-refs/scripts/verify_refs.py",
|
|
3856
|
-
"size":
|
|
3857
|
-
"sha256": "
|
|
3856
|
+
"size": 41415,
|
|
3857
|
+
"sha256": "4377e25e6b125ace31fd35df9ffdd21a413f0f70ba1e429e5bfcf50c0a29510e"
|
|
3858
3858
|
},
|
|
3859
3859
|
{
|
|
3860
3860
|
"path": "skills/verify-refs/skill.yml",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "medsci-skills",
|
|
3
|
-
"version": "5.9.
|
|
3
|
+
"version": "5.9.1",
|
|
4
4
|
"description": "MedSci Skills — a medical/scientific research skill suite for AI coding agents (Claude Code, Codex, Cursor, Copilot). The npm package is a terminal-friendly installer shortcut; the canonical distribution remains the GitHub repository and the Claude Code plugin marketplace.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"homepage": "https://github.com/Aperivue/medsci-skills#readme",
|
|
@@ -21,6 +21,7 @@ import csv
|
|
|
21
21
|
import io
|
|
22
22
|
import json
|
|
23
23
|
import logging
|
|
24
|
+
import os
|
|
24
25
|
import re
|
|
25
26
|
import shutil
|
|
26
27
|
import subprocess
|
|
@@ -562,8 +563,9 @@ def main():
|
|
|
562
563
|
"with a DOI column (optional PMID, Title)")
|
|
563
564
|
parser.add_argument("-o", "--output", type=Path, default=Path("pdfs"),
|
|
564
565
|
help="Output directory (default: pdfs/)")
|
|
565
|
-
parser.add_argument("-e", "--email",
|
|
566
|
-
help="Contact email (required by Unpaywall TOS)"
|
|
566
|
+
parser.add_argument("-e", "--email", default=os.environ.get("MEDSCI_CONTACT_EMAIL"),
|
|
567
|
+
help="Contact email (required by Unpaywall TOS). "
|
|
568
|
+
"Falls back to the MEDSCI_CONTACT_EMAIL environment variable.")
|
|
567
569
|
parser.add_argument("--report", type=Path, default=None,
|
|
568
570
|
help="Path for the JSON retrieval report "
|
|
569
571
|
"(default: <output>/retrieval_report.json)")
|
|
@@ -571,6 +573,10 @@ def main():
|
|
|
571
573
|
help="Show debug messages")
|
|
572
574
|
args = parser.parse_args()
|
|
573
575
|
|
|
576
|
+
if not args.email:
|
|
577
|
+
parser.error("a contact email is required (Unpaywall TOS): pass --email you@lab.org "
|
|
578
|
+
"or set MEDSCI_CONTACT_EMAIL")
|
|
579
|
+
|
|
574
580
|
logging.basicConfig(
|
|
575
581
|
level=logging.DEBUG if args.verbose else logging.WARNING,
|
|
576
582
|
format="%(levelname)s: %(message)s",
|
|
@@ -13,6 +13,7 @@ import argparse
|
|
|
13
13
|
import csv
|
|
14
14
|
import html
|
|
15
15
|
import json
|
|
16
|
+
import os
|
|
16
17
|
import re
|
|
17
18
|
import sys
|
|
18
19
|
import time
|
|
@@ -372,8 +373,30 @@ def guess_title(raw: str) -> str:
|
|
|
372
373
|
return ""
|
|
373
374
|
|
|
374
375
|
|
|
376
|
+
def _contact_email() -> str:
|
|
377
|
+
"""User-supplied contact email (courtesy for NCBI/CrossRef), never a credential."""
|
|
378
|
+
return (os.environ.get("MEDSCI_CONTACT_EMAIL")
|
|
379
|
+
or os.environ.get("NCBI_EMAIL")
|
|
380
|
+
or "medsci-skills@users.noreply.github.com")
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def _user_agent() -> str:
|
|
384
|
+
return f"medsci-skills/verify-refs (mailto:{_contact_email()})"
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def _ncbi_extras() -> dict:
|
|
388
|
+
"""Optional NCBI E-utilities etiquette / rate-limit params, all from env.
|
|
389
|
+
Setting NCBI_API_KEY raises the PubMed rate limit from 3 to 10 requests/s;
|
|
390
|
+
absent it, the calls stay keyless. `tool`/`email` are NCBI-recommended courtesy."""
|
|
391
|
+
extra = {"tool": "medsci-skills", "email": _contact_email()}
|
|
392
|
+
key = os.environ.get("NCBI_API_KEY")
|
|
393
|
+
if key:
|
|
394
|
+
extra["api_key"] = key
|
|
395
|
+
return extra
|
|
396
|
+
|
|
397
|
+
|
|
375
398
|
def http_json(url: str, timeout: int) -> dict | None:
|
|
376
|
-
req = urllib.request.Request(url, headers={"User-Agent":
|
|
399
|
+
req = urllib.request.Request(url, headers={"User-Agent": _user_agent()})
|
|
377
400
|
try:
|
|
378
401
|
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
|
379
402
|
return json.loads(resp.read().decode("utf-8", "replace"))
|
|
@@ -421,7 +444,7 @@ def verify_pubmed_pmid(pmid: str, timeout: int) -> tuple[str, str, list]:
|
|
|
421
444
|
verify_pubmed_efetch().
|
|
422
445
|
"""
|
|
423
446
|
url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?" + urllib.parse.urlencode(
|
|
424
|
-
{"db": "pubmed", "id": pmid, "retmode": "json"}
|
|
447
|
+
{"db": "pubmed", "id": pmid, "retmode": "json", **_ncbi_extras()}
|
|
425
448
|
)
|
|
426
449
|
data = http_json(url, timeout)
|
|
427
450
|
if not data:
|
|
@@ -458,11 +481,11 @@ def verify_pubmed_efetch(pmid: str, timeout: int) -> tuple[str, str, list, list]
|
|
|
458
481
|
case: CrossRef "Vasileios" vs PubMed "Victoria" — PubMed is authoritative).
|
|
459
482
|
"""
|
|
460
483
|
url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?" + urllib.parse.urlencode(
|
|
461
|
-
{"db": "pubmed", "id": pmid, "retmode": "xml"}
|
|
484
|
+
{"db": "pubmed", "id": pmid, "retmode": "xml", **_ncbi_extras()}
|
|
462
485
|
)
|
|
463
486
|
req = urllib.request.Request(
|
|
464
487
|
url,
|
|
465
|
-
headers={"User-Agent":
|
|
488
|
+
headers={"User-Agent": _user_agent()},
|
|
466
489
|
)
|
|
467
490
|
try:
|
|
468
491
|
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
|
@@ -496,7 +519,7 @@ def verify_pubmed_title(title: str, timeout: int) -> tuple[str, str, list]:
|
|
|
496
519
|
if not title:
|
|
497
520
|
return "UNVERIFIED", "No DOI, PMID, or usable title", []
|
|
498
521
|
url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?" + urllib.parse.urlencode(
|
|
499
|
-
{"db": "pubmed", "term": title, "retmode": "json", "retmax": "3"}
|
|
522
|
+
{"db": "pubmed", "term": title, "retmode": "json", "retmax": "3", **_ncbi_extras()}
|
|
500
523
|
)
|
|
501
524
|
data = http_json(url, timeout)
|
|
502
525
|
if not data:
|