gapit 0.2.2__tar.gz

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.
Files changed (224) hide show
  1. gapit-0.2.2/.gitattributes +2 -0
  2. gapit-0.2.2/.github/workflows/ci.yml +43 -0
  3. gapit-0.2.2/.github/workflows/docs.yml +44 -0
  4. gapit-0.2.2/.github/workflows/release.yml +28 -0
  5. gapit-0.2.2/.github/workflows/snapshot-refresh.yml +129 -0
  6. gapit-0.2.2/.gitignore +21 -0
  7. gapit-0.2.2/AGENTS.md +197 -0
  8. gapit-0.2.2/CHANGELOG.md +133 -0
  9. gapit-0.2.2/LICENSE +21 -0
  10. gapit-0.2.2/PKG-INFO +183 -0
  11. gapit-0.2.2/PLAN.md +166 -0
  12. gapit-0.2.2/README.md +153 -0
  13. gapit-0.2.2/SPEC.md +470 -0
  14. gapit-0.2.2/docs/agents.md +198 -0
  15. gapit-0.2.2/docs/custom-db.md +399 -0
  16. gapit-0.2.2/docs/databases.md +527 -0
  17. gapit-0.2.2/docs/faq.md +111 -0
  18. gapit-0.2.2/docs/index.md +46 -0
  19. gapit-0.2.2/docs/installation.md +91 -0
  20. gapit-0.2.2/docs/mcp.md +311 -0
  21. gapit-0.2.2/docs/outputs.md +440 -0
  22. gapit-0.2.2/docs/quickstart.md +142 -0
  23. gapit-0.2.2/docs/reads.md +588 -0
  24. gapit-0.2.2/docs/screen.md +205 -0
  25. gapit-0.2.2/docs/summary.md +183 -0
  26. gapit-0.2.2/mkdocs.yml +36 -0
  27. gapit-0.2.2/pixi.lock +4428 -0
  28. gapit-0.2.2/pixi.toml +59 -0
  29. gapit-0.2.2/pyproject.toml +73 -0
  30. gapit-0.2.2/recipe/meta.yaml +74 -0
  31. gapit-0.2.2/src/gapit/__init__.py +3 -0
  32. gapit-0.2.2/src/gapit/blast.py +239 -0
  33. gapit-0.2.2/src/gapit/cli.py +128 -0
  34. gapit-0.2.2/src/gapit/cmd_db.py +113 -0
  35. gapit-0.2.2/src/gapit/cmd_db_build.py +72 -0
  36. gapit-0.2.2/src/gapit/cmd_db_install.py +126 -0
  37. gapit-0.2.2/src/gapit/cmd_db_outdated.py +51 -0
  38. gapit-0.2.2/src/gapit/cmd_db_search.py +66 -0
  39. gapit-0.2.2/src/gapit/cmd_screen.py +214 -0
  40. gapit-0.2.2/src/gapit/cmd_summary.py +65 -0
  41. gapit-0.2.2/src/gapit/config.py +51 -0
  42. gapit-0.2.2/src/gapit/data/snapshots/card.tar.gz +0 -0
  43. gapit-0.2.2/src/gapit/data/snapshots/vfdb.tar.gz +0 -0
  44. gapit-0.2.2/src/gapit/db.py +226 -0
  45. gapit-0.2.2/src/gapit/db_build_ops.py +210 -0
  46. gapit-0.2.2/src/gapit/db_ops.py +128 -0
  47. gapit-0.2.2/src/gapit/db_query_ops.py +252 -0
  48. gapit-0.2.2/src/gapit/dbbuild.py +207 -0
  49. gapit-0.2.2/src/gapit/dbcodec.py +117 -0
  50. gapit-0.2.2/src/gapit/dispatch.py +31 -0
  51. gapit-0.2.2/src/gapit/errors.py +87 -0
  52. gapit-0.2.2/src/gapit/fasta.py +123 -0
  53. gapit-0.2.2/src/gapit/formats/__init__.py +1 -0
  54. gapit-0.2.2/src/gapit/formats/json.py +309 -0
  55. gapit-0.2.2/src/gapit/formats/md.py +190 -0
  56. gapit-0.2.2/src/gapit/formats/schemas.py +30 -0
  57. gapit-0.2.2/src/gapit/formats/summary.py +103 -0
  58. gapit-0.2.2/src/gapit/formats/tsv.py +45 -0
  59. gapit-0.2.2/src/gapit/hits.py +107 -0
  60. gapit-0.2.2/src/gapit/mcp.py +158 -0
  61. gapit-0.2.2/src/gapit/mcp_schemas.py +123 -0
  62. gapit-0.2.2/src/gapit/mcp_tools.py +289 -0
  63. gapit-0.2.2/src/gapit/minimap.py +20 -0
  64. gapit-0.2.2/src/gapit/minimap2_run.py +114 -0
  65. gapit-0.2.2/src/gapit/paf.py +115 -0
  66. gapit-0.2.2/src/gapit/proctools.py +24 -0
  67. gapit-0.2.2/src/gapit/providers/__init__.py +39 -0
  68. gapit-0.2.2/src/gapit/providers/argannot.py +94 -0
  69. gapit-0.2.2/src/gapit/providers/bacmet2.py +59 -0
  70. gapit-0.2.2/src/gapit/providers/card.py +150 -0
  71. gapit-0.2.2/src/gapit/providers/common.py +245 -0
  72. gapit-0.2.2/src/gapit/providers/ecoh.py +63 -0
  73. gapit-0.2.2/src/gapit/providers/ecoli_vf.py +74 -0
  74. gapit-0.2.2/src/gapit/providers/megares.py +71 -0
  75. gapit-0.2.2/src/gapit/providers/ncbi.py +103 -0
  76. gapit-0.2.2/src/gapit/providers/plasmidfinder.py +69 -0
  77. gapit-0.2.2/src/gapit/providers/resfinder.py +123 -0
  78. gapit-0.2.2/src/gapit/providers/snapshots.py +119 -0
  79. gapit-0.2.2/src/gapit/providers/upec_expec_vf.py +85 -0
  80. gapit-0.2.2/src/gapit/providers/vfdb.py +92 -0
  81. gapit-0.2.2/src/gapit/providers/victors.py +109 -0
  82. gapit-0.2.2/src/gapit/py.typed +0 -0
  83. gapit-0.2.2/src/gapit/reads.py +221 -0
  84. gapit-0.2.2/src/gapit/records.py +152 -0
  85. gapit-0.2.2/src/gapit/report.py +25 -0
  86. gapit-0.2.2/src/gapit/screening.py +145 -0
  87. gapit-0.2.2/src/gapit/screening_reads.py +255 -0
  88. gapit-0.2.2/src/gapit/seqconvert.py +203 -0
  89. gapit-0.2.2/src/gapit/summary.py +151 -0
  90. gapit-0.2.2/tests/data/contigs/full.fa +3 -0
  91. gapit-0.2.2/tests/data/contigs/gap.fa +3 -0
  92. gapit-0.2.2/tests/data/contigs/none.fa +3 -0
  93. gapit-0.2.2/tests/data/contigs/partial.fa +2 -0
  94. gapit-0.2.2/tests/data/contigs/sort.fa +11 -0
  95. gapit-0.2.2/tests/data/convert/sample.embl +20 -0
  96. gapit-0.2.2/tests/data/convert/sample.embl.bz2 +0 -0
  97. gapit-0.2.2/tests/data/convert/sample.fa +6 -0
  98. gapit-0.2.2/tests/data/convert/sample.fa.gz +0 -0
  99. gapit-0.2.2/tests/data/convert/sample.fq +8 -0
  100. gapit-0.2.2/tests/data/convert/sample.gbk +19 -0
  101. gapit-0.2.2/tests/data/convert/sample.gbk.gz +0 -0
  102. gapit-0.2.2/tests/data/db/tinyamr/sequences +9 -0
  103. gapit-0.2.2/tests/data/providers/argannot/ARG-ANNOT_NT_V6_July2019.txt +7 -0
  104. gapit-0.2.2/tests/data/providers/bacmet2/BacMet2_EXP_database.fasta +6 -0
  105. gapit-0.2.2/tests/data/providers/card/card.json +132 -0
  106. gapit-0.2.2/tests/data/providers/ecoh/EcOH.fasta +8 -0
  107. gapit-0.2.2/tests/data/providers/ecoli_vf/repaired_ecoli_vfs_shortnames.ffn +6 -0
  108. gapit-0.2.2/tests/data/providers/megares/megares_drugs_demo.fasta +6 -0
  109. gapit-0.2.2/tests/data/providers/ncbi/AMR_CDS.fa +14 -0
  110. gapit-0.2.2/tests/data/providers/ncbi/ReferenceGeneCatalog.txt +7 -0
  111. gapit-0.2.2/tests/data/providers/plasmidfinder/plasmids_a.fsa +4 -0
  112. gapit-0.2.2/tests/data/providers/plasmidfinder/plasmids_b.fsa +2 -0
  113. gapit-0.2.2/tests/data/providers/resfinder/aminoglycoside.fsa +6 -0
  114. gapit-0.2.2/tests/data/providers/resfinder/beta-lactam.fsa +4 -0
  115. gapit-0.2.2/tests/data/providers/resfinder/phenotypes.txt +5 -0
  116. gapit-0.2.2/tests/data/providers/upec_expec_vf/UPEC_ExPEC_VF.tsv +5 -0
  117. gapit-0.2.2/tests/data/providers/vfdb/VFDB_setA_nt.fas +6 -0
  118. gapit-0.2.2/tests/data/providers/victors/gen_downloads.php +6 -0
  119. gapit-0.2.2/tests/data/providers/victors/gen_downloads_protein.php +6 -0
  120. gapit-0.2.2/tests/data/reads/bla_partial.fq +4 -0
  121. gapit-0.2.2/tests/data/reads/junk.fq +8 -0
  122. gapit-0.2.2/tests/data/reads/suly_partial.fq +12 -0
  123. gapit-0.2.2/tests/data/reads/tetx_R1.fq +24 -0
  124. gapit-0.2.2/tests/data/reads/tetx_R2.fq +24 -0
  125. gapit-0.2.2/tests/data/reads/tetx_full.fq +48 -0
  126. gapit-0.2.2/tests/data/reads/tetx_full.fq.gz +0 -0
  127. gapit-0.2.2/tests/data/reads/tetx_lane1.fq +24 -0
  128. gapit-0.2.2/tests/data/reads/tetx_lane2.fq +24 -0
  129. gapit-0.2.2/tests/data/reads/tetx_pe1_R1.fq +12 -0
  130. gapit-0.2.2/tests/data/reads/tetx_pe1_R2.fq +12 -0
  131. gapit-0.2.2/tests/data/reads/tetx_pe2_R1.fq +12 -0
  132. gapit-0.2.2/tests/data/reads/tetx_pe2_R2.fq +12 -0
  133. gapit-0.2.2/tests/data/reads2/ont_homologs.fq +120 -0
  134. gapit-0.2.2/tests/data/reads2/sr_homologs.fq +400 -0
  135. gapit-0.2.2/tests/data/reads2_db/homologs/sequences +4 -0
  136. gapit-0.2.2/tests/data/reads_db/tinyreads/sequences +4 -0
  137. gapit-0.2.2/tests/data/summary/empty.tsv +1 -0
  138. gapit-0.2.2/tests/data/summary/multi_sample.tsv +4 -0
  139. gapit-0.2.2/tests/data/summary/sample_a.csv +4 -0
  140. gapit-0.2.2/tests/data/summary/sample_a.tsv +4 -0
  141. gapit-0.2.2/tests/data/summary/sample_b.csv +3 -0
  142. gapit-0.2.2/tests/data/summary/sample_b.tsv +3 -0
  143. gapit-0.2.2/tests/golden/reads_tinyamr.json +35 -0
  144. gapit-0.2.2/tests/golden/reads_tinyamr.md +20 -0
  145. gapit-0.2.2/tests/golden/screen_multi.json +131 -0
  146. gapit-0.2.2/tests/golden/screen_multi.md +39 -0
  147. gapit-0.2.2/tests/golden/summary_dutch.tsv +4 -0
  148. gapit-0.2.2/tests/golden/summary_multi.csv +3 -0
  149. gapit-0.2.2/tests/golden/summary_multi.json +48 -0
  150. gapit-0.2.2/tests/golden/summary_multi.md +17 -0
  151. gapit-0.2.2/tests/golden/summary_multi.tsv +4 -0
  152. gapit-0.2.2/tests/golden/tinyamr_multi_nopath.csv +7 -0
  153. gapit-0.2.2/tests/golden/tinyamr_multi_nopath.tsv +7 -0
  154. gapit-0.2.2/tests/parity/corpus/01_exact_and_junk.fa +34 -0
  155. gapit-0.2.2/tests/parity/corpus/02_mutated.fa +28 -0
  156. gapit-0.2.2/tests/parity/corpus/03_truncated.fa +17 -0
  157. gapit-0.2.2/tests/parity/make_corpus.py +114 -0
  158. gapit-0.2.2/tests/parity/run_parity.py +119 -0
  159. gapit-0.2.2/tests/parity/run_summary_parity.py +141 -0
  160. gapit-0.2.2/tests/test_blast_parse.py +78 -0
  161. gapit-0.2.2/tests/test_blast_pipeline.py +100 -0
  162. gapit-0.2.2/tests/test_cli_aligner.py +404 -0
  163. gapit-0.2.2/tests/test_cli_completion.py +61 -0
  164. gapit-0.2.2/tests/test_cli_db_build.py +450 -0
  165. gapit-0.2.2/tests/test_cli_db_fetch.py +353 -0
  166. gapit-0.2.2/tests/test_cli_db_query.py +506 -0
  167. gapit-0.2.2/tests/test_cli_list.py +153 -0
  168. gapit-0.2.2/tests/test_cli_reads.py +503 -0
  169. gapit-0.2.2/tests/test_cli_reads2.py +367 -0
  170. gapit-0.2.2/tests/test_cli_schema.py +48 -0
  171. gapit-0.2.2/tests/test_cli_screen.py +280 -0
  172. gapit-0.2.2/tests/test_cli_screen_jobs.py +108 -0
  173. gapit-0.2.2/tests/test_cli_summary.py +201 -0
  174. gapit-0.2.2/tests/test_config.py +47 -0
  175. gapit-0.2.2/tests/test_db.py +89 -0
  176. gapit-0.2.2/tests/test_db_fetch.py +128 -0
  177. gapit-0.2.2/tests/test_db_headers.py +60 -0
  178. gapit-0.2.2/tests/test_dbbuild.py +275 -0
  179. gapit-0.2.2/tests/test_dbcodec.py +205 -0
  180. gapit-0.2.2/tests/test_error_envelope.py +122 -0
  181. gapit-0.2.2/tests/test_fasta.py +172 -0
  182. gapit-0.2.2/tests/test_gapit_db_e2e.py +140 -0
  183. gapit-0.2.2/tests/test_hits.py +278 -0
  184. gapit-0.2.2/tests/test_json_format.py +146 -0
  185. gapit-0.2.2/tests/test_mcp.py +265 -0
  186. gapit-0.2.2/tests/test_mcp_db_tools.py +422 -0
  187. gapit-0.2.2/tests/test_mcp_protocol.py +60 -0
  188. gapit-0.2.2/tests/test_mcp_reads.py +279 -0
  189. gapit-0.2.2/tests/test_md_format.py +204 -0
  190. gapit-0.2.2/tests/test_minimap.py +59 -0
  191. gapit-0.2.2/tests/test_mol_type.py +38 -0
  192. gapit-0.2.2/tests/test_oversubscription.py +110 -0
  193. gapit-0.2.2/tests/test_paf.py +75 -0
  194. gapit-0.2.2/tests/test_paf_identity.py +133 -0
  195. gapit-0.2.2/tests/test_provider_argannot.py +85 -0
  196. gapit-0.2.2/tests/test_provider_bacmet2.py +104 -0
  197. gapit-0.2.2/tests/test_provider_card.py +169 -0
  198. gapit-0.2.2/tests/test_provider_ecoh.py +97 -0
  199. gapit-0.2.2/tests/test_provider_ecoli_vf.py +124 -0
  200. gapit-0.2.2/tests/test_provider_megares.py +79 -0
  201. gapit-0.2.2/tests/test_provider_ncbi.py +102 -0
  202. gapit-0.2.2/tests/test_provider_plasmidfinder.py +111 -0
  203. gapit-0.2.2/tests/test_provider_resfinder.py +161 -0
  204. gapit-0.2.2/tests/test_provider_upec_expec_vf.py +150 -0
  205. gapit-0.2.2/tests/test_provider_vfdb.py +101 -0
  206. gapit-0.2.2/tests/test_provider_victors.py +116 -0
  207. gapit-0.2.2/tests/test_providers_common.py +314 -0
  208. gapit-0.2.2/tests/test_reads2_homologs.py +135 -0
  209. gapit-0.2.2/tests/test_reads2_model.py +158 -0
  210. gapit-0.2.2/tests/test_reads_aggregate.py +129 -0
  211. gapit-0.2.2/tests/test_reads_integration.py +240 -0
  212. gapit-0.2.2/tests/test_reads_interval_union.py +269 -0
  213. gapit-0.2.2/tests/test_reads_streaming.py +174 -0
  214. gapit-0.2.2/tests/test_records.py +218 -0
  215. gapit-0.2.2/tests/test_report.py +71 -0
  216. gapit-0.2.2/tests/test_screen_integration.py +128 -0
  217. gapit-0.2.2/tests/test_screening_reads_unit.py +57 -0
  218. gapit-0.2.2/tests/test_seqconvert.py +252 -0
  219. gapit-0.2.2/tests/test_seqconvert_differential.py +79 -0
  220. gapit-0.2.2/tests/test_snapshots.py +204 -0
  221. gapit-0.2.2/tests/test_summary.py +291 -0
  222. gapit-0.2.2/tests/test_summary_formats.py +119 -0
  223. gapit-0.2.2/tests/test_tsv.py +144 -0
  224. gapit-0.2.2/tests/test_version.py +35 -0
@@ -0,0 +1,2 @@
1
+ # SCM syntax highlighting & preventing 3-way merges
2
+ pixi.lock merge=binary linguist-language=YAML linguist-generated=true -diff
@@ -0,0 +1,43 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ jobs:
13
+ gates:
14
+ name: gates (${{ matrix.env }})
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ env: [default, py311, py313]
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: prefix-dev/setup-pixi@v0.8.1
23
+ with:
24
+ cache: true
25
+ - run: pixi run -e ${{ matrix.env }} lint
26
+ - run: pixi run -e ${{ matrix.env }} fmt -- --check
27
+ - run: pixi run -e ${{ matrix.env }} typecheck
28
+ - run: pixi run -e ${{ matrix.env }} test
29
+
30
+ # Independent of gates: the bioconda solve is slow and orthogonal to the
31
+ # python matrix. Needs BOTH envs installed — the harness runs on the default
32
+ # env's python and invokes .pixi/envs/default/bin/gapit while parity env
33
+ # supplies abricate (see pixi.toml parity feature).
34
+ parity:
35
+ runs-on: ubuntu-latest
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - uses: prefix-dev/setup-pixi@v0.8.1
39
+ with:
40
+ cache: true
41
+ - run: pixi install -e default -e parity
42
+ - run: pixi run -e parity parity
43
+ - run: pixi run -e parity summary-parity
@@ -0,0 +1,44 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - docs/**
8
+ - mkdocs.yml
9
+ - pixi.toml
10
+ - pixi.lock
11
+ - .github/workflows/docs.yml
12
+ workflow_dispatch:
13
+
14
+ permissions:
15
+ contents: read
16
+ pages: write
17
+ id-token: write
18
+
19
+ concurrency:
20
+ group: pages
21
+ cancel-in-progress: true
22
+
23
+ jobs:
24
+ build:
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+ - uses: prefix-dev/setup-pixi@v0.8.1
29
+ with:
30
+ cache: true
31
+ - run: pixi run -e docs mkdocs build --strict
32
+ - uses: actions/upload-pages-artifact@v3
33
+ with:
34
+ path: site
35
+
36
+ deploy:
37
+ needs: build
38
+ runs-on: ubuntu-latest
39
+ environment:
40
+ name: github-pages
41
+ url: ${{ steps.deployment.outputs.page_url }}
42
+ steps:
43
+ - id: deployment
44
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,28 @@
1
+ name: Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ tags: ["v*"]
7
+
8
+ permissions:
9
+ # OIDC token for PyPI trusted publishing (pypa/gh-action-pypi-publish).
10
+ id-token: write
11
+
12
+ jobs:
13
+ publish:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.13"
21
+
22
+ - name: Build sdist and wheel
23
+ run: |
24
+ python -m pip install --upgrade pip build
25
+ python -m build
26
+
27
+ - name: Publish to PyPI
28
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,129 @@
1
+ name: Snapshot refresh
2
+
3
+ # Monthly: re-fetch card + vfdb from upstream and regenerate the bundled
4
+ # snapshot tars, so the wheel's zero-network defaults do not rot. A PR is the
5
+ # review gate (license/provenance hygiene); `gapit db fetch <db> --from-source`
6
+ # remains the manual path outside Actions.
7
+ on:
8
+ schedule:
9
+ - cron: "0 3 1 * *"
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ contents: write
14
+ pull-requests: write
15
+ issues: write
16
+
17
+ concurrency:
18
+ group: snapshot-refresh
19
+ cancel-in-progress: true
20
+
21
+ jobs:
22
+ refresh:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: prefix-dev/setup-pixi@v0.8.1
27
+ with:
28
+ cache: true
29
+ - run: pixi install
30
+ - name: Refresh card and vfdb snapshots from upstream
31
+ id: refresh
32
+ run: |
33
+ pixi run python - <<'PY'
34
+ import hashlib
35
+ import os
36
+ from datetime import UTC, datetime
37
+ from pathlib import Path
38
+ from tempfile import TemporaryDirectory
39
+
40
+ from gapit.providers import REGISTRY
41
+ from gapit.providers.common import fetch_provider
42
+ from gapit.providers.snapshots import extract_snapshot, make_snapshot
43
+
44
+ # Local verification reruns this exact script against a scratch dir
45
+ # via GAPIT_SNAPSHOT_REFRESH_DIR; the committed tars stay untouched.
46
+ snapshot_dir = Path(os.environ.get("GAPIT_SNAPSHOT_REFRESH_DIR", "src/gapit/data/snapshots"))
47
+ now = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
48
+
49
+
50
+ def sha256(path: Path) -> str:
51
+ digest = hashlib.sha256()
52
+ with path.open("rb") as handle:
53
+ for chunk in iter(lambda: handle.read(1 << 20), b""):
54
+ digest.update(chunk)
55
+ return digest.hexdigest()
56
+
57
+
58
+ def emit(key: str, value: str) -> None:
59
+ target = os.environ.get("GITHUB_OUTPUT")
60
+ if target:
61
+ with open(target, "a", encoding="utf-8") as handle:
62
+ print(f"{key}<<EOF", value, "EOF", sep="\n", file=handle)
63
+
64
+
65
+ rows = []
66
+ with TemporaryDirectory(prefix="gapit-snapshot-refresh.") as scratch:
67
+ for name in ("card", "vfdb"):
68
+ db_dir = Path(scratch) / name
69
+ manifest = fetch_provider(
70
+ REGISTRY[name], db_dir, fetched_at=now, from_source=True, quiet=False
71
+ )
72
+ dest = snapshot_dir / f"{name}.tar.gz"
73
+ before = sha256(dest) if dest.is_file() else "-"
74
+ # The tar turns over only when the records changed: the
75
+ # archived manifest carries fetched_at, so an unconditional
76
+ # rebuild would rewrite bytes (and open a PR) on every run
77
+ # even with identical upstream content.
78
+ changed = True
79
+ if dest.is_file():
80
+ bundled = Path(scratch) / f"{name}-bundled"
81
+ bundled.mkdir()
82
+ extract_snapshot(dest, bundled)
83
+ changed = (bundled / "records.jsonl").read_bytes() != (
84
+ db_dir / "records.jsonl"
85
+ ).read_bytes()
86
+ if changed:
87
+ snapshot_dir.mkdir(parents=True, exist_ok=True)
88
+ make_snapshot(db_dir, dest)
89
+ after = sha256(dest)
90
+ rows.append((name, manifest.n_records, before, after, changed))
91
+ verdict = "changed" if changed else "unchanged"
92
+ print(f"{name}: {manifest.n_records} records, tar sha256 {before} -> {after} ({verdict})")
93
+
94
+ summary = "\n".join(
95
+ [
96
+ "Monthly upstream refresh of the bundled card and vfdb snapshots.",
97
+ "",
98
+ "The snapshot carries `records.jsonl` plus the manifest; the BLAST index",
99
+ "rebuilds locally on install (deterministic, matches the installed BLAST).",
100
+ "",
101
+ "| db | records | tar sha256 before | tar sha256 after | changed |",
102
+ "|---|---|---|---|---|",
103
+ *(
104
+ f"| {name} | {records} | `{before}` | `{after}` | {'yes' if changed else 'no'} |"
105
+ for name, records, before, after, changed in rows
106
+ ),
107
+ ]
108
+ )
109
+ print()
110
+ print(summary)
111
+ emit("month", f"{datetime.now(UTC):%Y-%m}")
112
+ emit("summary", summary)
113
+ PY
114
+ - name: Open snapshot refresh pull request
115
+ uses: peter-evans/create-pull-request@v7
116
+ with:
117
+ branch: chore/snapshot-refresh
118
+ title: "data: refresh card and vfdb snapshots (${{ steps.refresh.outputs.month }})"
119
+ body: ${{ steps.refresh.outputs.summary }}
120
+ commit-message: "data: refresh card and vfdb snapshots"
121
+ delete-branch: true
122
+ - name: Open failure issue
123
+ if: failure() && github.event_name == 'schedule'
124
+ env:
125
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
126
+ run: |
127
+ gh issue create --repo "$GITHUB_REPOSITORY" \
128
+ --title "snapshot-refresh failed (run ${{ github.run_id }})" \
129
+ --body "Scheduled snapshot refresh failed. Check the [run log](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}). Common cause: upstream source outage (card.mcmaster.ca / mgc.ac.cn)."
gapit-0.2.2/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ # pixi environments
2
+ .pixi/*
3
+ !.pixi/config.toml
4
+
5
+ # agent session tooling
6
+ .omo/
7
+
8
+ # python
9
+ __pycache__/
10
+ *.py[cod]
11
+ *.egg-info/
12
+ .pytest_cache/
13
+ .ruff_cache/
14
+ dist/
15
+ build/
16
+
17
+ # opencode
18
+ .omo/
19
+
20
+ # mkdocs rendered site
21
+ site/
gapit-0.2.2/AGENTS.md ADDED
@@ -0,0 +1,197 @@
1
+ # AGENTS.md — gapit
2
+
3
+ > Python reimplementation of [abricate](https://github.com/tseemann/abricate): mass screening of
4
+ > contigs for antimicrobial resistance and virulence genes. **Agent-first**: every output is
5
+ > machine-readable (JSON / Markdown) by design, not as an afterthought.
6
+
7
+ ## 1. Mission
8
+
9
+ `gapit` answers one question: **which known genes are present in this assembly, and how confident
10
+ are we?** It replaces abricate (Perl) with a modern, typed, testable Python tool that:
11
+
12
+ 1. Produces byte-compatible TSV with abricate (drop-in replacement for existing pipelines).
13
+ 2. Adds first-class **JSON** and **Markdown** outputs so LLM agents and humans can consume
14
+ results without parsing tab-delimited text.
15
+ 3. Exposes stable, versioned output contracts (schemas, exit codes, error envelopes) that
16
+ autonomous agents can rely on.
17
+
18
+ ## 2. Environment & toolchain
19
+
20
+ - **Environment manager**: [pixi](https://pixi.sh) (conda-forge channel). Never use pip/conda
21
+ directly; add dependencies to `pixi.toml` (`pixi add <pkg>` for conda, `pixi add --pypi <pkg>`
22
+ for PyPI).
23
+ - **Python**: 3.14 in the pixi dev env (current stable); the package declares
24
+ `requires-python = ">=3.11"` and CI tests 3.11 / 3.13 / 3.14.
25
+ - **External binaries**: BLAST+ (`blastn`, `blastx`, `makeblastdb`, `blastdbcmd`) and `minimap2`
26
+ (FASTQ read screening, SPEC.md §10), all from conda-forge/bioconda. Invoked only via `subprocess`
27
+ with an argument list — never `shell=True`. Input normalization (fa/fq/gbk/embl, gz/bz2) is
28
+ native (`seqconvert.py`); `any2fasta` is no longer a gapit dependency anywhere — the
29
+ differential-validation oracle binary arrives transitively via abricate in the opt-in
30
+ `parity` pixi env (prepend `.pixi/envs/parity/bin` to PATH for the differential test).
31
+ - **Core libraries**: `typer` (CLI), `pydantic` v2 (data models / JSON schema), `rich` (terminal
32
+ output). No biopython — FASTA I/O is a small streaming parser we own.
33
+ - **Quality gates**: `ruff` (lint + format), `basedpyright` (strict mode), `pytest`.
34
+
35
+ ### Commands (pixi tasks)
36
+
37
+ ```bash
38
+ pixi run lint # ruff check
39
+ pixi run fmt # ruff format
40
+ pixi run typecheck # basedpyright --strict
41
+ pixi run test # pytest (unit, offline)
42
+ pixi run gapit # the CLI itself
43
+ pixi run -e parity parity # byte-diff screening vs real abricate (abricate-only env)
44
+ pixi run -e parity summary-parity # byte-diff summary vs real abricate
45
+ ```
46
+
47
+ Every change must leave `lint`, `typecheck`, and `test` green.
48
+
49
+ ## 3. Repository layout
50
+
51
+ ```
52
+ gapit/
53
+ ├── AGENTS.md # this file
54
+ ├── PLAN.md # development roadmap (phase-gated)
55
+ ├── SPEC.md # distilled abricate behavior spec (source of truth for parity)
56
+ ├── pixi.toml
57
+ ├── recipe/
58
+ │ └── meta.yaml # conda recipe (submission deferred)
59
+ ├── .github/workflows/
60
+ │ └── ci.yml # gates matrix 3.11/3.13/3.14 + parity job
61
+ ├── src/gapit/
62
+ │ ├── __init__.py
63
+ │ ├── cli.py # typer entrypoint: screen / summary / db / list / setupdb / schema / mcp
64
+ │ ├── config.py # datadir resolution, defaults, env vars
65
+ │ ├── dispatch.py # shared CLI dispatch (error envelope → exit codes) + --datadir option
66
+ │ ├── proctools.py # external-tool plumbing: argv subprocess runner + stderr notes
67
+ │ ├── fasta.py # streaming FASTA reader + shared gz/bz2 text opener
68
+ │ ├── seqconvert.py # native input normalization: fa/fq/gbk/embl (±gz/bz2) → FASTA
69
+ │ ├── db.py # database discovery, header parsing, makeblastdb wrapper
70
+ │ ├── dbcodec.py # gapit/v1 tagged-header codec (percent-encoded ids)
71
+ │ ├── records.py # records.jsonl truth store + gapit.manifest/1 provenance
72
+ │ ├── dbbuild.py # deterministic native-db build pipeline with self-check
73
+ │ ├── db_ops.py # db use-cases: provider fetch + list (shared CLI + MCP; no typer)
74
+ │ ├── db_query_ops.py # db use-cases: search + outdated over installed DBs (shared CLI + MCP)
75
+ │ ├── db_build_ops.py # db use-case: custom FASTA+TSV → native db build (shared CLI + MCP)
76
+ │ ├── blast.py # blastn invocation + tabular output parsing
77
+ │ ├── hits.py # Hit model, identity/coverage computation, filtering, dedup
78
+ │ ├── minimap.py # COVERAGE_MAP construction (exact abricate arithmetic)
79
+ │ ├── minimap2_run.py # minimap2 invocation layer for reads mode (streaming PAF, --cs/NM tags)
80
+ │ ├── paf.py # PAF row parsing + interval arithmetic (minimap2 output boundary)
81
+ │ ├── report.py # Report model: the canonical in-memory result
82
+ │ ├── screening.py # blastn screen use-case + shared engine helpers (OutputFormat, AlignerEnum)
83
+ │ ├── screening_reads.py # minimap2 use-cases: --r1/--r2 reads + --aligner minimap2 assemblies
84
+ │ ├── reads.py # FASTQ mode: minimap2 PAF parsing, coverage breadth/depth, presence
85
+ │ ├── summary.py # summary core: parse report tables into a gene matrix
86
+ │ ├── cmd_screen.py # `gapit screen` CLI (registered from cli.py)
87
+ │ ├── cmd_summary.py # `gapit summary` CLI (registered from cli.py)
88
+ │ ├── cmd_db.py # `gapit db` command group (fetch | list; registers the subcommands)
89
+ │ ├── cmd_db_install.py # `gapit db install`: SHA256-verified local-file install
90
+ │ ├── cmd_db_build.py # `gapit db build` CLI (custom FASTA → native db)
91
+ │ ├── cmd_db_search.py # `gapit db search` CLI (records.jsonl lookup)
92
+ │ ├── cmd_db_outdated.py # `gapit db outdated` CLI (staleness report)
93
+ │ ├── mcp.py # MCP stdio server (hand-rolled JSON-RPC 2.0); backs gapit-mcp
94
+ │ ├── mcp_tools.py # MCP tool implementations (call the shared use-cases)
95
+ │ ├── mcp_schemas.py # MCP tools/list declarations (names, descriptions, inputSchemas)
96
+ │ ├── errors.py # typed errors + JSON error envelope
97
+ │ ├── formats/
98
+ │ │ ├── tsv.py # abricate-compatible TSV/CSV
99
+ │ │ ├── json.py # versioned JSON (gapit.report/1 et al.)
100
+ │ │ ├── md.py # Markdown (human + agent readable, YAML frontmatter)
101
+ │ │ ├── schemas.py # registered output models behind `gapit schema`
102
+ │ │ └── summary.py # summary matrix renderers (TSV/CSV/JSON/MD)
103
+ │ ├── providers/ # 12 DB providers + common.py helpers + snapshots.py loader
104
+ │ ├── data/snapshots/ # bundled card + vfdb snapshot archives (.tar.gz)
105
+ │ └── py.typed
106
+ └── tests/
107
+ ├── data/ # tiny synthetic db + contigs + reads (fast, offline)
108
+ ├── golden/ # expected outputs incl. abricate reference TSVs
109
+ ├── parity/ # corpus + run_parity.py / run_summary_parity.py (opt-in env)
110
+ └── test_*.py # unit + CLI + provider + integration tests
111
+ ```
112
+
113
+ One file, one responsibility. Target ≤ 250 LOC per module; split before it hurts.
114
+
115
+ ## 4. Coding conventions
116
+
117
+ - **Strict typing everywhere.** basedpyright strict; no `Any` unless isolated and justified in a
118
+ comment. No `# type: ignore`, no `cast` to silence real errors.
119
+ - **Parse, don't validate.** BLAST rows, FASTA records, and db headers become typed models at the
120
+ boundary; the core logic never touches raw strings.
121
+ - **No silent failures.** Errors are typed (`errors.py`), carry context, and map to documented
122
+ exit codes. Empty `except` blocks are forbidden.
123
+ - **Deterministic output.** Stable sort orders, no wall-clock timestamps inside data payloads
124
+ (metadata block only), LF line endings, UTF-8.
125
+ - **TDD for core logic.** hit filtering, merging, and coverage-map math are written test-first.
126
+ - Match the style of the file you are editing; when in doubt, `ruff format` decides.
127
+
128
+ ## 5. The agent-facing output contract (design center)
129
+
130
+ This is what distinguishes gapit from abricate. Treat it as a public API.
131
+
132
+ - **Formats**: `--format tsv|csv|json|md` (default `tsv` for abricate compatibility).
133
+ - **JSON**: top-level `"schema": "gapit.report/1"`; schema introspectable via
134
+ `gapit schema report | reads | reads2 | summary | list | error | version`. Keys are snake_case,
135
+ units explicit (`identity_pct`, `coverage_pct`). Semver the schema; never rename or
136
+ retype a field in a minor bump.
137
+ - **Markdown**: YAML frontmatter (tool version, db, params, ISO-8601 UTC timestamp) + tables a
138
+ human can read and an agent can regex reliably.
139
+ - **Errors**: failures print a JSON envelope to stderr
140
+ `{"schema": "gapit.error/1", "code": "...", "message": "...", "context": {...}}` and exit with a
141
+ documented non-zero code (2 = usage, 3 = missing dependency, 4 = db error, 5 = input error).
142
+ - **DB acquisition** `[gapit-extension]`: `gapit db fetch|list|search|outdated|build|install` —
143
+ provider fetch (bundled card/vfdb snapshots install offline; `--from-source` forces upstream),
144
+ provider listing, records.jsonl gene search, staleness report, custom FASTA→native-db build,
145
+ and SHA256-verified local-file install.
146
+ - **MCP** `[gapit-extension]`: `gapit mcp` / `gapit-mcp` stdio server exposing nine tools:
147
+ read-only `screen` (incl. `aligner minimap2` assembly survey), `screen_reads` (FASTQ via
148
+ minimap2), `summary`, `schema`, `db_list`, `db_search`, `db_outdated`, plus the datadir-mutating
149
+ `db_fetch` (installs provider databases; may download) and `db_build` (writes a custom db);
150
+ tool failures carry the `gapit.error/1` envelope.
151
+ - **stdout purity**: data on stdout, diagnostics on stderr, always. `--quiet` only affects stderr.
152
+ - **Self-description**: `gapit --version --json`, `gapit list --json`, `gapit schema` — an agent
153
+ must be able to discover everything without reading docs.
154
+
155
+ ## 6. Testing strategy
156
+
157
+ - **Unit**: pure functions (coverage %, merge rules, header parsing) — no I/O beyond `tests/data`.
158
+ - **Golden files**: fixed tiny db + fixed contigs → expected TSV/JSON/MD committed; update the
159
+ committed files deliberately and review diffs like code.
160
+ - **Parity harness**: `pixi run -e parity parity` (and `summary-parity`) runs real abricate
161
+ (conda) and gapit over a small genome corpus and diffs the gene calls byte-for-byte (file,
162
+ gene, %identity, %coverage). Parity on the corpus is the release gate for v1.0.
163
+ - Full suite + CI matrix 3.11/3.13/3.14; parity byte-diff is opt-in via the `parity` pixi env.
164
+ Offline tests stay fast.
165
+
166
+ ## 7. Domain knowledge (abridged; full detail in SPEC.md)
167
+
168
+ - A **database** is a directory `<datadir>/<dbname>/sequences`: a nucleotide FASTA whose headers
169
+ encode `>~~~GENE~~~PRODUCT` (and accession / resistance metadata depending on the source db).
170
+ `makeblastdb -dbtype nucl` builds the index. gapit also writes its own native `gapit/v1`
171
+ tagged-header format (SPEC §11), whose `func` key carries a locked per-provider function
172
+ vocabulary (antibiotic classes, `virulence`, `replicon`, ...); abricate cannot read
173
+ gapit-native databases.
174
+ - Screening = native normalize (`seqconvert.py`, any2fasta-equivalent semantics) → `blastn` of
175
+ query contigs against one db → 15-field
176
+ tabular hits → filter by identity / coverage thresholds → **dedup hits sharing identical
177
+ `(contig, qstart, qend)`** (first/best BLAST row wins) → one TSV row per surviving hit.
178
+ abricate does **not** merge overlapping intervals — do not "improve" this on the default path.
179
+ - Key computed fields: `%COVERAGE = 100*(length-gaps)/slen` (filtered unrounded, displayed
180
+ `%.2f`), `%IDENTITY` (BLAST pident, never post-filtered), `COVERAGE_MAP` (15-char minimap),
181
+ `GAPS`. Exact formulas, the dedup rule, and the minimap arithmetic live in `SPEC.md` — when
182
+ abricate and intuition disagree, **abricate wins** (parity is a feature).
183
+
184
+ ## 8. Git & workflow
185
+
186
+ - Conventional Commits (`feat:`, `fix:`, `test:`, `docs:`, `refactor:`).
187
+ - Never commit unless the user explicitly asks. Never force-push.
188
+ - `PLAN.md` tracks phases; update it when scope changes, not retroactively.
189
+
190
+ ## 9. For agents working in this repo
191
+
192
+ 1. Read `SPEC.md` before touching `blast.py`, `hits.py`, or `minimap.py`.
193
+ 2. Public contract changes (JSON schema, exit codes, CLI flags) require a schema version bump and
194
+ a note in `PLAN.md`.
195
+ 3. Do not add dependencies without checking this file's §2 first — the list is intentionally short.
196
+ 4. Verification is part of the task: `pixi run lint && pixi run typecheck && pixi run test` before
197
+ declaring done.
@@ -0,0 +1,133 @@
1
+ # Changelog
2
+
3
+ All notable changes to gapit are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
6
+ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.2] - 2026-09-24
9
+
10
+ ### Security
11
+
12
+ - minimap2 input paths are passed as absolute paths, so a file named like an option
13
+ (e.g. `-d`) can no longer inject minimap2 flags; the child process no longer inherits
14
+ stdin (the MCP protocol stream).
15
+
16
+ ### Changed
17
+
18
+ - `--minid`/`--mincov` with `--aligner minimap2` or `--r1/--r2` are now a usage error
19
+ (exit 2) instead of being silently ignored.
20
+ - MCP `screen` (blastn) reuses the CLI use-case; its validation messages now match the CLI.
21
+ - MCP `screen_reads` passes read arrays natively, so filenames containing commas work.
22
+
23
+ ### Fixed
24
+
25
+ - MCP server replies `-32600`/`-32602` to malformed requests that carry an `id` instead of
26
+ silently dropping them.
27
+ - A truncated gzip reads file raises a typed `INVALID_READS_FORMAT` error (exit 5) instead
28
+ of `UNEXPECTED` (exit 1).
29
+
30
+ ## [0.2.1] - 2026-09-22
31
+
32
+ ### Changed
33
+
34
+ - License changed from GPL-2.0-only to MIT (rightsholder decision; behavioral
35
+ reimplementation status unchanged).
36
+
37
+ ## [0.2.0] - 2026-09-22
38
+
39
+ Development window: 2026-09-15 to 2026-09-22 (PLAN.md Phases 1 through 8 and post-phase
40
+ hardening).
41
+
42
+ ### Added
43
+
44
+ - Screening core: `any2fasta` to `blastn` pipeline with SPEC-exact hit processing, and
45
+ byte-compatible TSV against abricate 1.4.0 (PLAN Phases 1-3, 2026-09-15). Parity is
46
+ checked on a genome corpus with `pixi run -e parity parity` (6/6 byte-identical).
47
+ - Agent-facing outputs: `--format json|md` with versioned schemas (`gapit.report/1`,
48
+ `gapit.reads/1`, `gapit.summary/1`, `gapit.list/1`, `gapit.version/1`), the
49
+ `gapit.error/1` stderr envelope with documented exit codes, and introspection via
50
+ `gapit schema report|reads|summary|list|error|version` (2026-09-16).
51
+ - FASTQ reads mode via minimap2: `gapit screen --r1/--r2 --read-type sr|map-ont|map-hifi`;
52
+ presence is called on alignment breadth (2026-09-16).
53
+ - Summary matrix mode: `gapit summary` emits TSV/CSV/JSON/MD; byte parity with
54
+ `abricate --summary` via `pixi run -e parity summary-parity` (2026-09-17).
55
+ - `gapit db install`: checksum-verified (SHA256), atomic local-file installation
56
+ (2026-09-17).
57
+ - Native `gapit/v1` database format: tagged-header codec, `records.jsonl` truth store
58
+ with `gapit.manifest/1` provenance, deterministic build pipeline with self-check, and
59
+ `.mmi` BLAST index build with version-gated reuse (2026-09-18).
60
+ - 12 database providers (ncbi, card, resfinder, argannot, plasmidfinder, megares, ecoh,
61
+ vfdb, ecoli_vf, bacmet2, victors, upec_expec_vf) with offline-tested transforms
62
+ (2026-09-18).
63
+ - Bundled card and vfdb snapshots: a bare `gapit db fetch` installs the default set with
64
+ zero network; `--from-source` forces upstream download (2026-09-18).
65
+ - CLI hardening: shell completions, `--debug` argv echo on stderr, and `--jobs` parallel
66
+ screening across inputs with input-order stdout (2026-09-18).
67
+ - CI: gates matrix (lint, fmt, typecheck, test on Python 3.11 / 3.13 / 3.14) plus a
68
+ parity job that byte-diffs against real abricate (2026-09-18).
69
+ - MCP stdio server: `gapit mcp` subcommand and `gapit-mcp` console script, hand-rolled
70
+ JSON-RPC 2.0 with zero new dependencies; read-only tools `screen`, `summary`,
71
+ `schema`, `db_list` (2026-09-18).
72
+ - Conda recipe (`recipe/meta.yaml`) for PyPI/bioconda packaging (2026-09-18).
73
+ - Custom database construction: `gapit db build NAME FASTA` builds a screening-ready native
74
+ database from plain, abricate `~~~`, or `gapit|` FASTA (auto-detected), with optional
75
+ `--tsv` metadata (accession, function classes) and `--dbtype` override; guide with worked
76
+ examples in `docs/custom-db.md` (2026-09-19).
77
+ - `--aligner blastn|minimap2` engine selector on `gapit screen`: defaults follow the input
78
+ (blastn for contig files, minimap2 for `--r1`/`--r2` reads); `--aligner minimap2` screens
79
+ positional assembly FASTA through the minimap2 engine, `--aligner blastn` with `--r1`/`--r2`
80
+ is a usage error (2026-09-19).
81
+ - `gapit db outdated`: staleness report over installed databases (age vs `--days`, newer
82
+ bundled snapshot) as a TSV table or `gapit.dboutdated/1` JSON document (2026-09-20).
83
+ - `gapit db search TERM`: case-insensitive gene/accession/function/product lookup across
84
+ installed databases' `records.jsonl`, with `--field`, `--exact`, `--db`, `--limit` and
85
+ JSONL output (2026-09-20).
86
+ - MCP database tools `db_fetch`, `db_build`, `db_search`, `db_outdated`: the MCP server now
87
+ exposes the `db` commands alongside the analysis tools, so agents can self-provision and
88
+ inspect databases mid-session; `mcp.py` split into protocol (`mcp.py`) and tool
89
+ implementations (`mcp_tools.py`) with zero wire change for the existing tools (2026-09-20).
90
+ - CI snapshot refresh: monthly scheduled workflow (`.github/workflows/snapshot-refresh.yml`)
91
+ re-fetching card and vfdb from upstream, regenerating the bundled tars only when the
92
+ records changed, and opening a review PR (2026-09-20).
93
+ - Reads-mode opt-in alignment filtering: `gapit screen --min-identity/--min-mapq` (reads
94
+ engine only) drops PAF alignments below the thresholds before aggregation and emits the new
95
+ `gapit.reads/2` document (params gain both thresholds; gene entries gain
96
+ `mean_identity_pct`, the alignment-length-weighted mean identity; introspectable via
97
+ `gapit schema reads2`). Both flags off keeps `gapit.reads/1` byte-identical, and the
98
+ identity floor fixes the documented family-splitting over-calls on homologous genes
99
+ (2026-09-20).
100
+ - MCP reads tools: new `screen_reads` tool (FASTQ lanes via minimap2 → `gapit.reads/1`,
101
+ `min_identity`/`min_mapq` > 0 → `gapit.reads/2`) and new `screen` arguments
102
+ `aligner`/`min_breadth`/`min_identity`/`min_mapq` (`aligner minimap2` = fast assembly
103
+ survey). Both delegate to the shared reads use-cases with `quiet` stderr; additive
104
+ `gapit.mcp` contract — nine tools, the other eight wire-identical, no output-schema
105
+ version bump (2026-09-22).
106
+
107
+ ### Changed
108
+
109
+ - `any2fasta` is no longer a runtime dependency: input normalization (FASTA/FASTQ/GenBank/EMBL,
110
+ plain/gz/bz2 → FASTA) is native (`seqconvert.py`, perl-extracted semantics) and blastn reads the
111
+ converted FASTA on stdin. Parsed-record equivalence with the binary is differentially tested
112
+ with the parity env on PATH (abricate provides any2fasta transitively), and `.fa` parity
113
+ remains byte-identical (2026-09-21).
114
+ - Screening and reads paths route `gapit/v1` tagged headers to the native codec; legacy
115
+ abricate `~~~` headers keep the frozen parser, so abricate-built datadirs screen
116
+ identically. The reverse does not hold: gapit-built databases are unreadable by
117
+ abricate (accepted trade-off).
118
+ - A bare `gapit db fetch` installs the bundled default set (card, vfdb) instead of
119
+ downloading; `--from-source` restores the upstream fetch path.
120
+ - `gapit setupdb` honors the `gapit.manifest/1` dbtype on reindex (manifest-less abricate
121
+ dirs keep the mol_type heuristic), and reads/minimap2-assembly screening now rejects the
122
+ blastn-only flags `--fofn`, `--noheader`, `--nopath`, `--jobs N>1` with usage errors
123
+ (exit 2) instead of silently ignoring them (2026-09-22).
124
+
125
+ ### Removed
126
+
127
+ - `--csv` flag on `gapit screen`; use `--format csv` instead (breaking: the flag is now
128
+ rejected as an unknown option, exit 2) (2026-09-19).
129
+
130
+ ### Fixed
131
+
132
+ - Summary mode auto-detects TSV vs CSV per input file, avoiding the upstream quirk where
133
+ a global `--csv` flag mangles mixed-format input sets.
gapit-0.2.2/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 indexofire
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.