clincalc 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 (169) hide show
  1. clincalc-0.2.2/.github/FUNDING.yml +15 -0
  2. clincalc-0.2.2/.github/dependabot.yml +15 -0
  3. clincalc-0.2.2/.github/workflows/auto-tag.yml +122 -0
  4. clincalc-0.2.2/.github/workflows/ci.yml +65 -0
  5. clincalc-0.2.2/.github/workflows/docs.yml +94 -0
  6. clincalc-0.2.2/.github/workflows/publish-crates.yml +66 -0
  7. clincalc-0.2.2/.github/workflows/publish-python.yml +132 -0
  8. clincalc-0.2.2/.github/workflows/release.yml +378 -0
  9. clincalc-0.2.2/.gitignore +48 -0
  10. clincalc-0.2.2/AGENTS.md +94 -0
  11. clincalc-0.2.2/CHANGELOG.md +159 -0
  12. clincalc-0.2.2/CLAUDE.md +3 -0
  13. clincalc-0.2.2/Cargo.lock +1071 -0
  14. clincalc-0.2.2/Cargo.toml +98 -0
  15. clincalc-0.2.2/LICENSE +661 -0
  16. clincalc-0.2.2/PKG-INFO +83 -0
  17. clincalc-0.2.2/README.md +152 -0
  18. clincalc-0.2.2/cliff.toml +64 -0
  19. clincalc-0.2.2/clincalc/__init__.py +60 -0
  20. clincalc-0.2.2/clincalc/pandas.py +85 -0
  21. clincalc-0.2.2/clincalc/py.typed +0 -0
  22. clincalc-0.2.2/clincalc-web/README.md +25 -0
  23. clincalc-0.2.2/clincalc-web/calculators/adhd-questionnaire-asrs111.html +650 -0
  24. clincalc-0.2.2/clincalc-web/calculators/feverpain.html +839 -0
  25. clincalc-0.2.2/clincalc-web/clinical-source-references/adhd-questionnaire-asrs111.pdf +0 -0
  26. clincalc-0.2.2/clincalc-web/index.html +187 -0
  27. clincalc-0.2.2/clincalc-web/serve.sh +14 -0
  28. clincalc-0.2.2/clincalc-web/shared/gitehr-bridge.js +166 -0
  29. clincalc-0.2.2/clincalc-web/shared/styles.css +138 -0
  30. clincalc-0.2.2/clinical-safety/HAZARD-LOG.md +296 -0
  31. clincalc-0.2.2/clinical-safety/SAFETY-CASE.md +235 -0
  32. clincalc-0.2.2/clinical-safety/SAFETY.md +79 -0
  33. clincalc-0.2.2/docs/assets/logo.svg +11 -0
  34. clincalc-0.2.2/docs/calculators.md +171 -0
  35. clincalc-0.2.2/docs/cli-reference.md +222 -0
  36. clincalc-0.2.2/docs/how-it-works.md +144 -0
  37. clincalc-0.2.2/docs/index.md +88 -0
  38. clincalc-0.2.2/docs/install.md +75 -0
  39. clincalc-0.2.2/docs/mcp.md +149 -0
  40. clincalc-0.2.2/docs/python.md +77 -0
  41. clincalc-0.2.2/docs/stylesheets/extra.css +51 -0
  42. clincalc-0.2.2/docs/walkthrough.md +246 -0
  43. clincalc-0.2.2/examples/README.md +17 -0
  44. clincalc-0.2.2/examples/auditc.json +4 -0
  45. clincalc-0.2.2/examples/energy_requirement.json +9 -0
  46. clincalc-0.2.2/examples/feverpain.json +7 -0
  47. clincalc-0.2.2/examples/gad7.json +3 -0
  48. clincalc-0.2.2/examples/news2.json +10 -0
  49. clincalc-0.2.2/gui/README.md +101 -0
  50. clincalc-0.2.2/gui/index.html +20 -0
  51. clincalc-0.2.2/gui/package-lock.json +2555 -0
  52. clincalc-0.2.2/gui/package.json +31 -0
  53. clincalc-0.2.2/gui/public/logo.svg +14 -0
  54. clincalc-0.2.2/gui/src/App.css +56 -0
  55. clincalc-0.2.2/gui/src/App.tsx +313 -0
  56. clincalc-0.2.2/gui/src/ErrorBoundary.tsx +131 -0
  57. clincalc-0.2.2/gui/src/api/calc.ts +62 -0
  58. clincalc-0.2.2/gui/src/calculators/Cha2ds2Vasc.tsx +388 -0
  59. clincalc-0.2.2/gui/src/calculators/FeverPain.tsx +365 -0
  60. clincalc-0.2.2/gui/src/calculators/Qrisk3.tsx +590 -0
  61. clincalc-0.2.2/gui/src/main.tsx +34 -0
  62. clincalc-0.2.2/gui/src/vite-env.d.ts +8 -0
  63. clincalc-0.2.2/gui/tsconfig.json +21 -0
  64. clincalc-0.2.2/gui/tsconfig.node.json +11 -0
  65. clincalc-0.2.2/gui/vite.config.ts +38 -0
  66. clincalc-0.2.2/mkdocs.yml +104 -0
  67. clincalc-0.2.2/pyproject.toml +37 -0
  68. clincalc-0.2.2/python/.gitignore +28 -0
  69. clincalc-0.2.2/python/Cargo.lock +214 -0
  70. clincalc-0.2.2/python/Cargo.toml +21 -0
  71. clincalc-0.2.2/python/README.md +64 -0
  72. clincalc-0.2.2/python/src/lib.rs +135 -0
  73. clincalc-0.2.2/regulatory/mdr-classification.md +413 -0
  74. clincalc-0.2.2/regulatory/position-published-source-not-a-device.md +132 -0
  75. clincalc-0.2.2/requirements.txt +4 -0
  76. clincalc-0.2.2/s/README.md +71 -0
  77. clincalc-0.2.2/s/docs +111 -0
  78. clincalc-0.2.2/s/gui-dev +32 -0
  79. clincalc-0.2.2/s/install +19 -0
  80. clincalc-0.2.2/s/test +18 -0
  81. clincalc-0.2.2/s/version++ +193 -0
  82. clincalc-0.2.2/spec/calculator-input-definitions.md +91 -0
  83. clincalc-0.2.2/spec/calculator-roadmap.md +63 -0
  84. clincalc-0.2.2/spec/calculators.md +283 -0
  85. clincalc-0.2.2/spec/gui.md +58 -0
  86. clincalc-0.2.2/spec/mcp.md +262 -0
  87. clincalc-0.2.2/spec/multilingual.md +136 -0
  88. clincalc-0.2.2/spec/roadmap.md +251 -0
  89. clincalc-0.2.2/src/api.rs +315 -0
  90. clincalc-0.2.2/src/calculator.rs +86 -0
  91. clincalc-0.2.2/src/calculators/abcd2.rs +496 -0
  92. clincalc-0.2.2/src/calculators/abpi.rs +511 -0
  93. clincalc-0.2.2/src/calculators/alcohol_units.rs +195 -0
  94. clincalc-0.2.2/src/calculators/alvarado.rs +208 -0
  95. clincalc-0.2.2/src/calculators/amts.rs +337 -0
  96. clincalc-0.2.2/src/calculators/anion_gap.rs +180 -0
  97. clincalc-0.2.2/src/calculators/apache2.rs +473 -0
  98. clincalc-0.2.2/src/calculators/asa_physical_status.rs +143 -0
  99. clincalc-0.2.2/src/calculators/ascvd.rs +275 -0
  100. clincalc-0.2.2/src/calculators/asrs.rs +298 -0
  101. clincalc-0.2.2/src/calculators/audit.rs +338 -0
  102. clincalc-0.2.2/src/calculators/auditc.rs +431 -0
  103. clincalc-0.2.2/src/calculators/barthel.rs +302 -0
  104. clincalc-0.2.2/src/calculators/basdai.rs +153 -0
  105. clincalc-0.2.2/src/calculators/bmi.rs +161 -0
  106. clincalc-0.2.2/src/calculators/bode.rs +476 -0
  107. clincalc-0.2.2/src/calculators/body_fat_circumference.rs +315 -0
  108. clincalc-0.2.2/src/calculators/braden.rs +393 -0
  109. clincalc-0.2.2/src/calculators/caprini.rs +494 -0
  110. clincalc-0.2.2/src/calculators/centor.rs +254 -0
  111. clincalc-0.2.2/src/calculators/cha2ds2_va.rs +246 -0
  112. clincalc-0.2.2/src/calculators/cha2ds2vasc.rs +460 -0
  113. clincalc-0.2.2/src/calculators/chalice.rs +668 -0
  114. clincalc-0.2.2/src/calculators/charlson.rs +410 -0
  115. clincalc-0.2.2/src/calculators/child_pugh.rs +706 -0
  116. clincalc-0.2.2/src/calculators/ckd_risk.rs +500 -0
  117. clincalc-0.2.2/src/calculators/cockcroft_gault.rs +344 -0
  118. clincalc-0.2.2/src/calculators/corrected_calcium.rs +191 -0
  119. clincalc-0.2.2/src/calculators/curb65.rs +502 -0
  120. clincalc-0.2.2/src/calculators/das28.rs +458 -0
  121. clincalc-0.2.2/src/calculators/egfr.rs +375 -0
  122. clincalc-0.2.2/src/calculators/ehra.rs +241 -0
  123. clincalc-0.2.2/src/calculators/energy_requirement.rs +788 -0
  124. clincalc-0.2.2/src/calculators/epds.rs +366 -0
  125. clincalc-0.2.2/src/calculators/euroscore2.rs +864 -0
  126. clincalc-0.2.2/src/calculators/familial_hypercholesterolaemia.rs +420 -0
  127. clincalc-0.2.2/src/calculators/fena.rs +256 -0
  128. clincalc-0.2.2/src/calculators/feverpain.rs +285 -0
  129. clincalc-0.2.2/src/calculators/fib4.rs +298 -0
  130. clincalc-0.2.2/src/calculators/findrisc.rs +369 -0
  131. clincalc-0.2.2/src/calculators/fourat.rs +458 -0
  132. clincalc-0.2.2/src/calculators/gad7.rs +298 -0
  133. clincalc-0.2.2/src/calculators/gleason.rs +370 -0
  134. clincalc-0.2.2/src/calculators/grace.rs +730 -0
  135. clincalc-0.2.2/src/calculators/hasbled.rs +506 -0
  136. clincalc-0.2.2/src/calculators/heart.rs +530 -0
  137. clincalc-0.2.2/src/calculators/ipss.rs +386 -0
  138. clincalc-0.2.2/src/calculators/max_heart_rate.rs +291 -0
  139. clincalc-0.2.2/src/calculators/meld.rs +425 -0
  140. clincalc-0.2.2/src/calculators/mod.rs +77 -0
  141. clincalc-0.2.2/src/calculators/mrc_dyspnoea.rs +270 -0
  142. clincalc-0.2.2/src/calculators/news2.rs +770 -0
  143. clincalc-0.2.2/src/calculators/nhfs.rs +511 -0
  144. clincalc-0.2.2/src/calculators/npi.rs +388 -0
  145. clincalc-0.2.2/src/calculators/one_rep_max.rs +263 -0
  146. clincalc-0.2.2/src/calculators/padua.rs +515 -0
  147. clincalc-0.2.2/src/calculators/phq9.rs +328 -0
  148. clincalc-0.2.2/src/calculators/qfracture.rs +1253 -0
  149. clincalc-0.2.2/src/calculators/qrisk3.rs +951 -0
  150. clincalc-0.2.2/src/calculators/qsofa.rs +420 -0
  151. clincalc-0.2.2/src/calculators/sofa.rs +750 -0
  152. clincalc-0.2.2/src/calculators/timi.rs +480 -0
  153. clincalc-0.2.2/src/calculators/uacr.rs +476 -0
  154. clincalc-0.2.2/src/calculators/ukeld.rs +474 -0
  155. clincalc-0.2.2/src/calculators/waist_to_height_ratio.rs +201 -0
  156. clincalc-0.2.2/src/calculators/waterlow.rs +873 -0
  157. clincalc-0.2.2/src/calculators/wells_dvt.rs +510 -0
  158. clincalc-0.2.2/src/calculators/wells_pe.rs +505 -0
  159. clincalc-0.2.2/src/cli.rs +1201 -0
  160. clincalc-0.2.2/src/lib.rs +218 -0
  161. clincalc-0.2.2/src/license.rs +27 -0
  162. clincalc-0.2.2/src/main.rs +327 -0
  163. clincalc-0.2.2/src/mcp.rs +259 -0
  164. clincalc-0.2.2/src/proprietary.rs +278 -0
  165. clincalc-0.2.2/src/response.rs +45 -0
  166. clincalc-0.2.2/src/tags.rs +259 -0
  167. clincalc-0.2.2/src/template.rs +247 -0
  168. clincalc-0.2.2/tests/completions.rs +332 -0
  169. clincalc-0.2.2/wix/main.wxs +228 -0
@@ -0,0 +1,15 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: bawmedical
4
+ patreon: # Replace with a single Patreon username
5
+ open_collective: # Replace with a single Open Collective username
6
+ ko_fi: # Replace with a single Ko-fi username
7
+ tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8
+ community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9
+ liberapay: # Replace with a single Liberapay username
10
+ issuehunt: # Replace with a single IssueHunt username
11
+ lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12
+ polar: # Replace with a single Polar username
13
+ buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14
+ thanks_dev: # Replace with a single thanks.dev username
15
+ custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
@@ -0,0 +1,15 @@
1
+ # Update schedule for GitHub Actions and Rust/Cargo dependencies.
2
+
3
+ version: 2
4
+ updates:
5
+ # GitHub Actions, weekly.
6
+ - package-ecosystem: "github-actions"
7
+ directory: "/"
8
+ schedule:
9
+ interval: "weekly"
10
+
11
+ # Rust/Cargo dependencies, daily.
12
+ - package-ecosystem: "cargo"
13
+ directory: "/"
14
+ schedule:
15
+ interval: "daily"
@@ -0,0 +1,122 @@
1
+ # SPDX-FileCopyrightText: 2026 Marcus Baw and Baw Medical Ltd
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ name: Auto-tag on version bump
5
+
6
+ # When a push to main bumps the workspace version in Cargo.toml, create and push
7
+ # the matching `v<version>` tag, then invoke the binary release, crates.io, and
8
+ # PyPI publish workflows with that tag.
9
+ #
10
+ # The downstream workflows are invoked via `workflow_call` rather than by relying
11
+ # on the tag push to trigger them, because pushes performed via the default
12
+ # GITHUB_TOKEN do not trigger downstream workflows (GitHub's anti-recursion
13
+ # guard). This is the auto-tag cascade documented in
14
+ # ~/code/house-style/distribution.md.
15
+
16
+ on:
17
+ push:
18
+ branches: [main]
19
+
20
+ concurrency:
21
+ group: auto-tag-${{ github.ref }}
22
+ cancel-in-progress: false
23
+
24
+ permissions:
25
+ contents: write
26
+ id-token: write
27
+
28
+ jobs:
29
+ tag:
30
+ name: Detect version bump and create tag
31
+ runs-on: ubuntu-latest
32
+ outputs:
33
+ tag: ${{ steps.bump.outputs.tag }}
34
+ bumped: ${{ steps.bump.outputs.bumped }}
35
+ created: ${{ steps.create.outputs.created }}
36
+
37
+ steps:
38
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
39
+ with:
40
+ fetch-depth: 2
41
+ persist-credentials: true
42
+
43
+ - name: Detect Cargo.toml version change
44
+ id: bump
45
+ run: |
46
+ new=$(grep -m1 '^version = "' Cargo.toml | cut -d'"' -f2)
47
+ old=$(git show HEAD~1:Cargo.toml 2>/dev/null \
48
+ | grep -m1 '^version = "' | cut -d'"' -f2 || echo "")
49
+
50
+ if [ -z "$new" ]; then
51
+ echo "::warning::Could not read version from Cargo.toml"
52
+ echo "bumped=false" >> "$GITHUB_OUTPUT"
53
+ exit 0
54
+ fi
55
+ if [ "$new" = "$old" ]; then
56
+ echo "No version change ($new == $old) - nothing to tag."
57
+ echo "bumped=false" >> "$GITHUB_OUTPUT"
58
+ exit 0
59
+ fi
60
+
61
+ tag="v$new"
62
+ if git ls-remote --exit-code --tags origin "refs/tags/$tag" >/dev/null 2>&1; then
63
+ echo "Tag $tag already exists on origin - assuming a previous run created it."
64
+ echo "bumped=false" >> "$GITHUB_OUTPUT"
65
+ exit 0
66
+ fi
67
+
68
+ echo "Cargo.toml: $old -> $new"
69
+ echo "tag=$tag" >> "$GITHUB_OUTPUT"
70
+ echo "bumped=true" >> "$GITHUB_OUTPUT"
71
+
72
+ - name: Create and push tag
73
+ id: create
74
+ if: steps.bump.outputs.bumped == 'true'
75
+ run: |
76
+ tag="${{ steps.bump.outputs.tag }}"
77
+ if git ls-remote --exit-code --tags origin "refs/tags/$tag" >/dev/null 2>&1; then
78
+ echo "Tag $tag already exists on origin - another run won the race."
79
+ echo "created=false" >> "$GITHUB_OUTPUT"
80
+ exit 0
81
+ fi
82
+
83
+ git config user.name "github-actions[bot]"
84
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
85
+ git tag -a "$tag" -m "Release $tag"
86
+
87
+ if git push origin "refs/tags/$tag"; then
88
+ echo "created=true" >> "$GITHUB_OUTPUT"
89
+ exit 0
90
+ fi
91
+
92
+ if git ls-remote --exit-code --tags origin "refs/tags/$tag" >/dev/null 2>&1; then
93
+ echo "Tag $tag now exists on origin - another run won the race."
94
+ echo "created=false" >> "$GITHUB_OUTPUT"
95
+ exit 0
96
+ fi
97
+
98
+ exit 1
99
+
100
+ release:
101
+ needs: tag
102
+ if: needs.tag.outputs.created == 'true'
103
+ uses: ./.github/workflows/release.yml
104
+ with:
105
+ tag: ${{ needs.tag.outputs.tag }}
106
+ secrets: inherit
107
+
108
+ publish-crates:
109
+ needs: tag
110
+ if: needs.tag.outputs.created == 'true'
111
+ uses: ./.github/workflows/publish-crates.yml
112
+ with:
113
+ tag: ${{ needs.tag.outputs.tag }}
114
+ secrets: inherit
115
+
116
+ publish-python:
117
+ needs: tag
118
+ if: needs.tag.outputs.created == 'true'
119
+ uses: ./.github/workflows/publish-python.yml
120
+ with:
121
+ tag: ${{ needs.tag.outputs.tag }}
122
+ secrets: inherit
@@ -0,0 +1,65 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ env:
13
+ CARGO_TERM_COLOR: always
14
+
15
+ jobs:
16
+ test:
17
+ name: fmt, clippy, test
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
21
+
22
+ - name: Install Rust toolchain (stable, with rustfmt and clippy)
23
+ uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 # stable
24
+ with:
25
+ toolchain: stable
26
+ components: rustfmt, clippy
27
+
28
+ - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
29
+
30
+ - name: Formatting
31
+ run: cargo fmt --all --check
32
+
33
+ - name: Clippy (default features)
34
+ run: cargo clippy --all-targets -- -D warnings
35
+
36
+ - name: Clippy (MCP feature)
37
+ run: cargo clippy --all-targets --features mcp -- -D warnings
38
+
39
+ - name: Tests (default features)
40
+ run: cargo test
41
+
42
+ - name: Tests (leaf engine)
43
+ run: cargo test --no-default-features
44
+
45
+ - name: Tests (MCP feature)
46
+ run: cargo test --features mcp
47
+
48
+ audit:
49
+ name: Security audit
50
+ runs-on: ubuntu-latest
51
+ steps:
52
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
53
+
54
+ # Prebuilt binary (seconds) rather than a from-source `cargo install`.
55
+ - name: Install cargo-audit
56
+ uses: taiki-e/install-action@16b05812d776ae1dfaabc8277e421fb6d2506419 # v2.82.7
57
+ with:
58
+ tool: cargo-audit
59
+
60
+ # Fails on any RustSec advisory affecting the locked tree, so a vulnerable
61
+ # dependency is caught here rather than waiting on a Dependabot email. A
62
+ # genuinely unfixable transitive advisory can be quarantined in audit.toml
63
+ # (`[advisories] ignore = ["RUSTSEC-XXXX-NNNN"]`) with a note.
64
+ - name: cargo audit
65
+ run: cargo audit
@@ -0,0 +1,94 @@
1
+ # Builds and deploys the clincalc documentation site to GitHub Pages.
2
+ #
3
+ # Method: artifact-based deploy (actions/upload-pages-artifact +
4
+ # actions/deploy-pages). The built site is handed straight to GitHub's Pages
5
+ # servers as a workflow artifact - there is no `gh-pages` branch, no orphan
6
+ # history, nothing in `git log --all` that did not come from a real commit.
7
+ #
8
+ # Repo prerequisite (one-off): Settings -> Pages -> Source must be set to
9
+ # "GitHub Actions". If it is set to "Deploy from a branch", deploy-pages
10
+ # fails with "Get Pages site failed". This is set once on the repo and
11
+ # persists.
12
+ #
13
+ # Action SHAs are copied from the sibling repos' docs workflows (the canonical
14
+ # living examples) and carry the matching `# vX.Y.Z` comment per house style.
15
+
16
+ name: docs
17
+
18
+ on:
19
+ push:
20
+ branches:
21
+ - main
22
+ paths:
23
+ - "docs/**"
24
+ - "examples/**"
25
+ - "mkdocs.yml"
26
+ - "requirements.txt"
27
+ - ".github/workflows/docs.yml"
28
+ workflow_dispatch:
29
+
30
+ permissions:
31
+ contents: read
32
+ pages: write
33
+ id-token: write
34
+
35
+ concurrency:
36
+ group: pages
37
+ cancel-in-progress: true
38
+
39
+ jobs:
40
+ build:
41
+ runs-on: ubuntu-latest
42
+ steps:
43
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
44
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
45
+ with:
46
+ python-version: "3.x"
47
+ - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
48
+ - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
49
+ - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
50
+ with:
51
+ key: zensical-${{ env.cache_id }}
52
+ path: ~/.cache
53
+ restore-keys: |
54
+ zensical-
55
+ - run: pip install -r requirements.txt
56
+ - run: zensical build --clean
57
+
58
+ # Drop installer proxies at the site root so users can do
59
+ # curl -LsSf https://pacharanero.github.io/clincalc/install.sh | sh
60
+ # instead of the full GitHub Releases URL. The scripts below simply
61
+ # re-fetch cargo-dist's real installer for the latest release, so they
62
+ # never go stale between docs deploys.
63
+ - name: Add installer proxies
64
+ run: |
65
+ cat > site/install.sh <<'EOF'
66
+ #!/bin/sh
67
+ # clincalc installer proxy - fetches the latest cargo-dist installer.
68
+ # Source: https://github.com/pacharanero/clincalc
69
+ set -eu
70
+ curl --proto '=https' --tlsv1.2 -LsSf \
71
+ https://github.com/pacharanero/clincalc/releases/latest/download/clincalc-installer.sh \
72
+ | sh
73
+ EOF
74
+ chmod +x site/install.sh
75
+
76
+ cat > site/install.ps1 <<'EOF'
77
+ # clincalc installer proxy - fetches the latest cargo-dist installer.
78
+ # Source: https://github.com/pacharanero/clincalc
79
+ irm https://github.com/pacharanero/clincalc/releases/latest/download/clincalc-installer.ps1 | iex
80
+ EOF
81
+
82
+ - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
83
+ with:
84
+ path: site
85
+
86
+ deploy:
87
+ needs: build
88
+ runs-on: ubuntu-latest
89
+ environment:
90
+ name: github-pages
91
+ url: ${{ steps.deployment.outputs.page_url }}
92
+ steps:
93
+ - id: deployment
94
+ uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
@@ -0,0 +1,66 @@
1
+ # SPDX-FileCopyrightText: 2026 Marcus Baw and Baw Medical Ltd
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ name: Publish to crates.io
5
+
6
+ # Publishes the `clincalc` crate to crates.io on a release tag. Invoked by
7
+ # auto-tag.yml via workflow_call (the cascade); also triggerable manually
8
+ # (workflow_dispatch) or by a `v*` tag push to re-publish a given tag.
9
+ #
10
+ # Needs the CARGO_REGISTRY_TOKEN secret on this repo.
11
+
12
+ on:
13
+ workflow_call:
14
+ inputs:
15
+ tag:
16
+ description: "Tag to publish, e.g. v0.1.0"
17
+ required: true
18
+ type: string
19
+ workflow_dispatch:
20
+ inputs:
21
+ tag:
22
+ description: "Tag to publish, e.g. v0.2.0"
23
+ required: true
24
+ type: string
25
+ push:
26
+ tags:
27
+ - "v*"
28
+
29
+ permissions:
30
+ contents: read
31
+
32
+ jobs:
33
+ publish:
34
+ name: Publish to crates.io
35
+ runs-on: ubuntu-latest
36
+ steps:
37
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
38
+ with:
39
+ ref: ${{ inputs.tag || github.ref }}
40
+
41
+ - name: Install Rust stable
42
+ uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 # stable
43
+ with:
44
+ toolchain: stable
45
+
46
+ - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
47
+
48
+ - name: Test before publishing (publish is irreversible)
49
+ run: cargo test --all-features
50
+
51
+ - name: Publish clincalc to crates.io
52
+ env:
53
+ CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
54
+ run: |
55
+ if cargo publish >publish.log 2>&1; then
56
+ exit 0
57
+ fi
58
+
59
+ if grep -Eqi "already uploaded|already exists on crates.io index" publish.log; then
60
+ echo "This crate version is already published on crates.io - treating as success."
61
+ cat publish.log
62
+ exit 0
63
+ fi
64
+
65
+ cat publish.log >&2
66
+ exit 1
@@ -0,0 +1,132 @@
1
+ # SPDX-FileCopyrightText: 2026 Marcus Baw and Baw Medical Ltd
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ name: Publish Python package to PyPI
5
+
6
+ # Builds and publishes the `clincalc` Python wheel/sdist for the tag. Invoked
7
+ # by auto-tag.yml via workflow_call (the cascade); also triggerable manually
8
+ # or by a `v*` tag push to re-publish a given tag.
9
+ #
10
+ # Publishes with PyPI Trusted Publishing via GitHub OIDC. PyPI must trust this
11
+ # repository and workflow; no long-lived API token is stored in GitHub.
12
+
13
+ on:
14
+ workflow_call:
15
+ inputs:
16
+ tag:
17
+ description: "Tag to publish, e.g. v0.1.0"
18
+ required: true
19
+ type: string
20
+ workflow_dispatch:
21
+ inputs:
22
+ tag:
23
+ description: "Tag to publish, e.g. v0.2.0"
24
+ required: true
25
+ type: string
26
+ push:
27
+ tags:
28
+ - "v*"
29
+
30
+ permissions:
31
+ contents: read
32
+
33
+ jobs:
34
+ linux:
35
+ runs-on: ubuntu-latest
36
+ strategy:
37
+ matrix:
38
+ target: [x86_64, aarch64]
39
+ steps:
40
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
41
+ with:
42
+ ref: ${{ inputs.tag || github.ref }}
43
+ - uses: PyO3/maturin-action@3e2bdf6ba6453a61e649744019b8a2d906c7eb38 # v1.51.0
44
+ with:
45
+ command: build
46
+ args: --release --locked --target ${{ matrix.target }}-unknown-linux-gnu --out dist --manifest-path Cargo.toml
47
+ manylinux: auto
48
+ working-directory: python
49
+ - name: Upload wheels
50
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
51
+ with:
52
+ name: wheels-linux-${{ matrix.target }}
53
+ path: python/dist
54
+
55
+ windows:
56
+ runs-on: windows-latest
57
+ strategy:
58
+ matrix:
59
+ target: [x64]
60
+ steps:
61
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
62
+ with:
63
+ ref: ${{ inputs.tag || github.ref }}
64
+ - uses: PyO3/maturin-action@3e2bdf6ba6453a61e649744019b8a2d906c7eb38 # v1.51.0
65
+ with:
66
+ command: build
67
+ args: --release --locked --target ${{ matrix.target }}-pc-windows-msvc --out dist --manifest-path Cargo.toml
68
+ working-directory: python
69
+ - name: Upload wheels
70
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
71
+ with:
72
+ name: wheels-windows-${{ matrix.target }}
73
+ path: python/dist
74
+
75
+ macos:
76
+ runs-on: macos-latest
77
+ strategy:
78
+ matrix:
79
+ target: [x86_64, aarch64]
80
+ steps:
81
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
82
+ with:
83
+ ref: ${{ inputs.tag || github.ref }}
84
+ - uses: PyO3/maturin-action@3e2bdf6ba6453a61e649744019b8a2d906c7eb38 # v1.51.0
85
+ with:
86
+ command: build
87
+ args: --release --locked --target ${{ matrix.target }}-apple-darwin --out dist --manifest-path Cargo.toml
88
+ working-directory: python
89
+ - name: Upload wheels
90
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
91
+ with:
92
+ name: wheels-macos-${{ matrix.target }}
93
+ path: python/dist
94
+
95
+ sdist:
96
+ runs-on: ubuntu-latest
97
+ steps:
98
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
99
+ with:
100
+ ref: ${{ inputs.tag || github.ref }}
101
+ - uses: PyO3/maturin-action@3e2bdf6ba6453a61e649744019b8a2d906c7eb38 # v1.51.0
102
+ with:
103
+ command: sdist
104
+ args: --out dist --manifest-path Cargo.toml
105
+ working-directory: python
106
+ - name: Upload sdist
107
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
108
+ with:
109
+ name: sdist
110
+ path: python/dist
111
+
112
+ release:
113
+ name: Release
114
+ runs-on: ubuntu-latest
115
+ needs: [linux, windows, macos, sdist]
116
+ permissions:
117
+ id-token: write
118
+ steps:
119
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
120
+ with:
121
+ path: dist
122
+ pattern: wheels-*
123
+ merge-multiple: true
124
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
125
+ with:
126
+ path: dist
127
+ pattern: sdist
128
+ merge-multiple: true
129
+ - name: Publish to PyPI
130
+ uses: pypa/gh-action-pypi-publish@6733eb7d741f0b11ec6a39b58540dab7590f9b7d # v1.14.0
131
+ with:
132
+ packages-dir: dist