├── .env.example ├── .gitattributes ├── .github └── workflows │ └── release.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── assets ├── models.json └── prompt.txt ├── cargo-readme.md ├── changelog.md ├── cooking-process.md ├── install.sh ├── readme.md ├── src ├── main.rs ├── models │ ├── anthropic.rs │ ├── deepseek.rs │ ├── gemini.rs │ ├── llama.rs │ ├── mod.rs │ └── openai.rs └── utils │ ├── checks.rs │ ├── config.rs │ ├── diff.rs │ └── mod.rs └── temp.md /.env.example: -------------------------------------------------------------------------------- 1 | # for gemini api 2 | GEMINI_API_KEY="" 3 | 4 | # for anthropic api 5 | 6 | ANTHROPIC_API_KEY="" 7 | 8 | # for openai api 9 | 10 | OPENAI_API_KEY="" 11 | 12 | 13 | # for llama api 14 | 15 | LLAMA_API_URL="http://localhost:11434/api/generate" 16 | LLAMA_MODEL_NAME= "llama3.2:1b" 17 | 18 | 19 | # for deepseek api 20 | 21 | DEEPSEEEK_API_KEY="" 22 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # contains all the files to be ignored by the git diff command 2 | 3 | Cargo.lock -diff 4 | .env -diff 5 | .gitignore -diff 6 | .DS_Store -diff 7 | Thumbs.db -diff 8 | *.log -diff 9 | *.bak -diff 10 | *.swp -diff 11 | *.swo -diff 12 | .idea/ -diff 13 | .vscode/ -diff 14 | .eclipse/ -diff 15 | node_modules/ -diff 16 | package-lock.json -diff 17 | yarn.lock -diff 18 | yarn-error.log -diff 19 | npm-debug.log -diff 20 | tsconfig.json -diff 21 | tsconfig.build.json -diff 22 | webpack.config.js -diff 23 | Gemfile.lock -diff 24 | *.gem -diff 25 | .bundle/ -diff 26 | *.rbc -diff 27 | Pipfile.lock -diff 28 | requirements.txt -diff 29 | .tox/ -diff 30 | .venv/ -diff 31 | __pycache__/ -diff 32 | *.pyc -diff 33 | *.pyo -diff 34 | composer.lock -diff 35 | composer.json -diff 36 | .php_cs.dist -diff 37 | vendor/ -diff 38 | Cargo.lock -diff 39 | target/ -diff 40 | .cargo/ -diff 41 | *.class -diff 42 | *.jar -diff 43 | *.war -diff 44 | *.ear -diff 45 | *.apk -diff 46 | *.dex -diff 47 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | release: 13 | name: Release - ${{ matrix.platform.os }} 14 | runs-on: ${{ matrix.platform.os }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | platform: 19 | - os: ubuntu-latest 20 | target: x86_64-unknown-linux-gnu 21 | name: git-acm-linux-x86_64 22 | - os: macos-latest 23 | target: x86_64-apple-darwin 24 | name: git-acm-darwin-x86_64 25 | - os: windows-latest 26 | target: x86_64-pc-windows-msvc 27 | name: git-acm-windows-x86_64.exe 28 | 29 | steps: 30 | - uses: actions/checkout@v4 31 | 32 | - name: Install Rust 33 | uses: dtolnay/rust-toolchain@stable 34 | with: 35 | targets: ${{ matrix.platform.target }} 36 | 37 | - name: Build 38 | run: cargo build --release --target ${{ matrix.platform.target }} 39 | 40 | - name: Prepare Release 41 | shell: bash 42 | run: | 43 | # Copy binary with proper permissions 44 | if [ "${{ matrix.platform.os }}" = "windows-latest" ]; then 45 | cp "target/${{ matrix.platform.target }}/release/git-acm.exe" "${{ matrix.platform.name }}" 46 | else 47 | cp "target/${{ matrix.platform.target }}/release/git-acm" "${{ matrix.platform.name }}" 48 | # Ensure binary is executable 49 | chmod +x "${{ matrix.platform.name }}" 50 | fi 51 | 52 | # Generate checksum files 53 | if [ "${{ matrix.platform.os }}" = "windows-latest" ]; then 54 | certutil -hashfile "${{ matrix.platform.name }}" SHA256 | grep -v "^SHA256" | grep -v "^CertUtil" | tr -d " \t\r\n" > "${{ matrix.platform.name }}.sha256" 55 | elif [ "${{ matrix.platform.os }}" = "macos-latest" ]; then 56 | shasum -a 256 "${{ matrix.platform.name }}" | cut -d ' ' -f 1 > "${{ matrix.platform.name }}.sha256" 57 | else 58 | sha256sum "${{ matrix.platform.name }}" | cut -d ' ' -f 1 > "${{ matrix.platform.name }}.sha256" 59 | fi 60 | 61 | # Show generated checksum for verification in logs 62 | echo "Generated checksum for ${{ matrix.platform.name }}:" 63 | cat "${{ matrix.platform.name }}.sha256" 64 | 65 | - name: Release 66 | uses: ncipollo/release-action@v1 67 | with: 68 | artifacts: ${{ matrix.platform.name }},${{ matrix.platform.name }}.sha256 69 | allowUpdates: true 70 | token: ${{ secrets.GITHUB_TOKEN }} 71 | artifactContentType: application/octet-stream # Ensure binary format is preserved 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .env 3 | 4 | 5 | # Added by cargo 6 | 7 | /target 8 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "adler2" 7 | version = "2.0.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 10 | 11 | [[package]] 12 | name = "anstream" 13 | version = "0.6.18" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 16 | dependencies = [ 17 | "anstyle", 18 | "anstyle-parse", 19 | "anstyle-query", 20 | "anstyle-wincon", 21 | "colorchoice", 22 | "is_terminal_polyfill", 23 | "utf8parse", 24 | ] 25 | 26 | [[package]] 27 | name = "anstyle" 28 | version = "1.0.10" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 31 | 32 | [[package]] 33 | name = "anstyle-parse" 34 | version = "0.2.6" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 37 | dependencies = [ 38 | "utf8parse", 39 | ] 40 | 41 | [[package]] 42 | name = "anstyle-query" 43 | version = "1.1.2" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 46 | dependencies = [ 47 | "windows-sys 0.59.0", 48 | ] 49 | 50 | [[package]] 51 | name = "anstyle-wincon" 52 | version = "3.0.6" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" 55 | dependencies = [ 56 | "anstyle", 57 | "windows-sys 0.59.0", 58 | ] 59 | 60 | [[package]] 61 | name = "arboard" 62 | version = "3.4.1" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" 65 | dependencies = [ 66 | "clipboard-win", 67 | "core-graphics", 68 | "image", 69 | "log", 70 | "objc2", 71 | "objc2-app-kit", 72 | "objc2-foundation", 73 | "parking_lot", 74 | "windows-sys 0.48.0", 75 | "x11rb", 76 | ] 77 | 78 | [[package]] 79 | name = "async-channel" 80 | version = "1.9.0" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" 83 | dependencies = [ 84 | "concurrent-queue", 85 | "event-listener", 86 | "futures-core", 87 | ] 88 | 89 | [[package]] 90 | name = "autocfg" 91 | version = "1.4.0" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 94 | 95 | [[package]] 96 | name = "bitflags" 97 | version = "1.3.2" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 100 | 101 | [[package]] 102 | name = "bitflags" 103 | version = "2.7.0" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" 106 | 107 | [[package]] 108 | name = "block2" 109 | version = "0.5.1" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" 112 | dependencies = [ 113 | "objc2", 114 | ] 115 | 116 | [[package]] 117 | name = "bytemuck" 118 | version = "1.21.0" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" 121 | 122 | [[package]] 123 | name = "byteorder-lite" 124 | version = "0.1.0" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" 127 | 128 | [[package]] 129 | name = "bytes" 130 | version = "1.9.0" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" 133 | 134 | [[package]] 135 | name = "castaway" 136 | version = "0.1.2" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" 139 | 140 | [[package]] 141 | name = "cc" 142 | version = "1.2.6" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" 145 | dependencies = [ 146 | "shlex", 147 | ] 148 | 149 | [[package]] 150 | name = "cfg-if" 151 | version = "1.0.0" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 154 | 155 | [[package]] 156 | name = "clap" 157 | version = "4.5.23" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" 160 | dependencies = [ 161 | "clap_builder", 162 | ] 163 | 164 | [[package]] 165 | name = "clap_builder" 166 | version = "4.5.23" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" 169 | dependencies = [ 170 | "anstream", 171 | "anstyle", 172 | "clap_lex", 173 | "strsim", 174 | ] 175 | 176 | [[package]] 177 | name = "clap_lex" 178 | version = "0.7.4" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 181 | 182 | [[package]] 183 | name = "clipboard-win" 184 | version = "5.4.0" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" 187 | dependencies = [ 188 | "error-code", 189 | ] 190 | 191 | [[package]] 192 | name = "colorchoice" 193 | version = "1.0.3" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 196 | 197 | [[package]] 198 | name = "concurrent-queue" 199 | version = "2.5.0" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 202 | dependencies = [ 203 | "crossbeam-utils", 204 | ] 205 | 206 | [[package]] 207 | name = "core-foundation" 208 | version = "0.9.4" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 211 | dependencies = [ 212 | "core-foundation-sys", 213 | "libc", 214 | ] 215 | 216 | [[package]] 217 | name = "core-foundation-sys" 218 | version = "0.8.7" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 221 | 222 | [[package]] 223 | name = "core-graphics" 224 | version = "0.23.2" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" 227 | dependencies = [ 228 | "bitflags 1.3.2", 229 | "core-foundation", 230 | "core-graphics-types", 231 | "foreign-types", 232 | "libc", 233 | ] 234 | 235 | [[package]] 236 | name = "core-graphics-types" 237 | version = "0.1.3" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" 240 | dependencies = [ 241 | "bitflags 1.3.2", 242 | "core-foundation", 243 | "libc", 244 | ] 245 | 246 | [[package]] 247 | name = "crc32fast" 248 | version = "1.4.2" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 251 | dependencies = [ 252 | "cfg-if", 253 | ] 254 | 255 | [[package]] 256 | name = "crossbeam-utils" 257 | version = "0.8.21" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 260 | 261 | [[package]] 262 | name = "crossterm" 263 | version = "0.28.1" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" 266 | dependencies = [ 267 | "bitflags 2.7.0", 268 | "crossterm_winapi", 269 | "mio", 270 | "parking_lot", 271 | "rustix", 272 | "signal-hook", 273 | "signal-hook-mio", 274 | "winapi", 275 | ] 276 | 277 | [[package]] 278 | name = "crossterm_winapi" 279 | version = "0.9.1" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 282 | dependencies = [ 283 | "winapi", 284 | ] 285 | 286 | [[package]] 287 | name = "curl" 288 | version = "0.4.47" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265" 291 | dependencies = [ 292 | "curl-sys", 293 | "libc", 294 | "openssl-probe", 295 | "openssl-sys", 296 | "schannel", 297 | "socket2", 298 | "windows-sys 0.52.0", 299 | ] 300 | 301 | [[package]] 302 | name = "curl-sys" 303 | version = "0.4.78+curl-8.11.0" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "8eec768341c5c7789611ae51cf6c459099f22e64a5d5d0ce4892434e33821eaf" 306 | dependencies = [ 307 | "cc", 308 | "libc", 309 | "libnghttp2-sys", 310 | "libz-sys", 311 | "openssl-sys", 312 | "pkg-config", 313 | "vcpkg", 314 | "windows-sys 0.52.0", 315 | ] 316 | 317 | [[package]] 318 | name = "displaydoc" 319 | version = "0.2.5" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 322 | dependencies = [ 323 | "proc-macro2", 324 | "quote", 325 | "syn", 326 | ] 327 | 328 | [[package]] 329 | name = "dotenvy" 330 | version = "0.15.7" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" 333 | 334 | [[package]] 335 | name = "duct" 336 | version = "0.13.7" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "e4ab5718d1224b63252cd0c6f74f6480f9ffeb117438a2e0f5cf6d9a4798929c" 339 | dependencies = [ 340 | "libc", 341 | "once_cell", 342 | "os_pipe", 343 | "shared_child", 344 | ] 345 | 346 | [[package]] 347 | name = "encoding_rs" 348 | version = "0.8.35" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 351 | dependencies = [ 352 | "cfg-if", 353 | ] 354 | 355 | [[package]] 356 | name = "errno" 357 | version = "0.3.10" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" 360 | dependencies = [ 361 | "libc", 362 | "windows-sys 0.59.0", 363 | ] 364 | 365 | [[package]] 366 | name = "error-code" 367 | version = "3.3.1" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" 370 | 371 | [[package]] 372 | name = "event-listener" 373 | version = "2.5.3" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" 376 | 377 | [[package]] 378 | name = "fastrand" 379 | version = "1.9.0" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" 382 | dependencies = [ 383 | "instant", 384 | ] 385 | 386 | [[package]] 387 | name = "fdeflate" 388 | version = "0.3.7" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" 391 | dependencies = [ 392 | "simd-adler32", 393 | ] 394 | 395 | [[package]] 396 | name = "flate2" 397 | version = "1.0.35" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" 400 | dependencies = [ 401 | "crc32fast", 402 | "miniz_oxide", 403 | ] 404 | 405 | [[package]] 406 | name = "fnv" 407 | version = "1.0.7" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 410 | 411 | [[package]] 412 | name = "foreign-types" 413 | version = "0.5.0" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" 416 | dependencies = [ 417 | "foreign-types-macros", 418 | "foreign-types-shared", 419 | ] 420 | 421 | [[package]] 422 | name = "foreign-types-macros" 423 | version = "0.2.3" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" 426 | dependencies = [ 427 | "proc-macro2", 428 | "quote", 429 | "syn", 430 | ] 431 | 432 | [[package]] 433 | name = "foreign-types-shared" 434 | version = "0.3.1" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" 437 | 438 | [[package]] 439 | name = "form_urlencoded" 440 | version = "1.2.1" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 443 | dependencies = [ 444 | "percent-encoding", 445 | ] 446 | 447 | [[package]] 448 | name = "futures-core" 449 | version = "0.3.31" 450 | source = "registry+https://github.com/rust-lang/crates.io-index" 451 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 452 | 453 | [[package]] 454 | name = "futures-io" 455 | version = "0.3.31" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 458 | 459 | [[package]] 460 | name = "futures-lite" 461 | version = "1.13.0" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" 464 | dependencies = [ 465 | "fastrand", 466 | "futures-core", 467 | "futures-io", 468 | "memchr", 469 | "parking", 470 | "pin-project-lite", 471 | "waker-fn", 472 | ] 473 | 474 | [[package]] 475 | name = "gethostname" 476 | version = "0.4.3" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" 479 | dependencies = [ 480 | "libc", 481 | "windows-targets 0.48.5", 482 | ] 483 | 484 | [[package]] 485 | name = "git-acm" 486 | version = "1.3.0" 487 | dependencies = [ 488 | "arboard", 489 | "clap", 490 | "crossterm", 491 | "dotenvy", 492 | "duct", 493 | "isahc", 494 | "serde", 495 | "serde_json", 496 | "yansi", 497 | ] 498 | 499 | [[package]] 500 | name = "http" 501 | version = "0.2.12" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" 504 | dependencies = [ 505 | "bytes", 506 | "fnv", 507 | "itoa", 508 | ] 509 | 510 | [[package]] 511 | name = "icu_collections" 512 | version = "1.5.0" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 515 | dependencies = [ 516 | "displaydoc", 517 | "yoke", 518 | "zerofrom", 519 | "zerovec", 520 | ] 521 | 522 | [[package]] 523 | name = "icu_locid" 524 | version = "1.5.0" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 527 | dependencies = [ 528 | "displaydoc", 529 | "litemap", 530 | "tinystr", 531 | "writeable", 532 | "zerovec", 533 | ] 534 | 535 | [[package]] 536 | name = "icu_locid_transform" 537 | version = "1.5.0" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 540 | dependencies = [ 541 | "displaydoc", 542 | "icu_locid", 543 | "icu_locid_transform_data", 544 | "icu_provider", 545 | "tinystr", 546 | "zerovec", 547 | ] 548 | 549 | [[package]] 550 | name = "icu_locid_transform_data" 551 | version = "1.5.0" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 554 | 555 | [[package]] 556 | name = "icu_normalizer" 557 | version = "1.5.0" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 560 | dependencies = [ 561 | "displaydoc", 562 | "icu_collections", 563 | "icu_normalizer_data", 564 | "icu_properties", 565 | "icu_provider", 566 | "smallvec", 567 | "utf16_iter", 568 | "utf8_iter", 569 | "write16", 570 | "zerovec", 571 | ] 572 | 573 | [[package]] 574 | name = "icu_normalizer_data" 575 | version = "1.5.0" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 578 | 579 | [[package]] 580 | name = "icu_properties" 581 | version = "1.5.1" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 584 | dependencies = [ 585 | "displaydoc", 586 | "icu_collections", 587 | "icu_locid_transform", 588 | "icu_properties_data", 589 | "icu_provider", 590 | "tinystr", 591 | "zerovec", 592 | ] 593 | 594 | [[package]] 595 | name = "icu_properties_data" 596 | version = "1.5.0" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 599 | 600 | [[package]] 601 | name = "icu_provider" 602 | version = "1.5.0" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 605 | dependencies = [ 606 | "displaydoc", 607 | "icu_locid", 608 | "icu_provider_macros", 609 | "stable_deref_trait", 610 | "tinystr", 611 | "writeable", 612 | "yoke", 613 | "zerofrom", 614 | "zerovec", 615 | ] 616 | 617 | [[package]] 618 | name = "icu_provider_macros" 619 | version = "1.5.0" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 622 | dependencies = [ 623 | "proc-macro2", 624 | "quote", 625 | "syn", 626 | ] 627 | 628 | [[package]] 629 | name = "idna" 630 | version = "1.0.3" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 633 | dependencies = [ 634 | "idna_adapter", 635 | "smallvec", 636 | "utf8_iter", 637 | ] 638 | 639 | [[package]] 640 | name = "idna_adapter" 641 | version = "1.2.0" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 644 | dependencies = [ 645 | "icu_normalizer", 646 | "icu_properties", 647 | ] 648 | 649 | [[package]] 650 | name = "image" 651 | version = "0.25.5" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" 654 | dependencies = [ 655 | "bytemuck", 656 | "byteorder-lite", 657 | "num-traits", 658 | "png", 659 | "tiff", 660 | ] 661 | 662 | [[package]] 663 | name = "instant" 664 | version = "0.1.13" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" 667 | dependencies = [ 668 | "cfg-if", 669 | ] 670 | 671 | [[package]] 672 | name = "is_terminal_polyfill" 673 | version = "1.70.1" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 676 | 677 | [[package]] 678 | name = "isahc" 679 | version = "1.7.2" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "334e04b4d781f436dc315cb1e7515bd96826426345d498149e4bde36b67f8ee9" 682 | dependencies = [ 683 | "async-channel", 684 | "castaway", 685 | "crossbeam-utils", 686 | "curl", 687 | "curl-sys", 688 | "encoding_rs", 689 | "event-listener", 690 | "futures-lite", 691 | "http", 692 | "log", 693 | "mime", 694 | "once_cell", 695 | "polling", 696 | "serde", 697 | "serde_json", 698 | "slab", 699 | "sluice", 700 | "tracing", 701 | "tracing-futures", 702 | "url", 703 | "waker-fn", 704 | ] 705 | 706 | [[package]] 707 | name = "itoa" 708 | version = "1.0.14" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 711 | 712 | [[package]] 713 | name = "jpeg-decoder" 714 | version = "0.3.1" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" 717 | 718 | [[package]] 719 | name = "libc" 720 | version = "0.2.169" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 723 | 724 | [[package]] 725 | name = "libnghttp2-sys" 726 | version = "0.1.10+1.61.0" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "959c25552127d2e1fa72f0e52548ec04fc386e827ba71a7bd01db46a447dc135" 729 | dependencies = [ 730 | "cc", 731 | "libc", 732 | ] 733 | 734 | [[package]] 735 | name = "libz-sys" 736 | version = "1.1.20" 737 | source = "registry+https://github.com/rust-lang/crates.io-index" 738 | checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" 739 | dependencies = [ 740 | "cc", 741 | "libc", 742 | "pkg-config", 743 | "vcpkg", 744 | ] 745 | 746 | [[package]] 747 | name = "linux-raw-sys" 748 | version = "0.4.15" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 751 | 752 | [[package]] 753 | name = "litemap" 754 | version = "0.7.4" 755 | source = "registry+https://github.com/rust-lang/crates.io-index" 756 | checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" 757 | 758 | [[package]] 759 | name = "lock_api" 760 | version = "0.4.12" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 763 | dependencies = [ 764 | "autocfg", 765 | "scopeguard", 766 | ] 767 | 768 | [[package]] 769 | name = "log" 770 | version = "0.4.22" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 773 | 774 | [[package]] 775 | name = "memchr" 776 | version = "2.7.4" 777 | source = "registry+https://github.com/rust-lang/crates.io-index" 778 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 779 | 780 | [[package]] 781 | name = "mime" 782 | version = "0.3.17" 783 | source = "registry+https://github.com/rust-lang/crates.io-index" 784 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 785 | 786 | [[package]] 787 | name = "miniz_oxide" 788 | version = "0.8.2" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" 791 | dependencies = [ 792 | "adler2", 793 | "simd-adler32", 794 | ] 795 | 796 | [[package]] 797 | name = "mio" 798 | version = "1.0.3" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 801 | dependencies = [ 802 | "libc", 803 | "log", 804 | "wasi", 805 | "windows-sys 0.52.0", 806 | ] 807 | 808 | [[package]] 809 | name = "num-traits" 810 | version = "0.2.19" 811 | source = "registry+https://github.com/rust-lang/crates.io-index" 812 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 813 | dependencies = [ 814 | "autocfg", 815 | ] 816 | 817 | [[package]] 818 | name = "objc-sys" 819 | version = "0.3.5" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" 822 | 823 | [[package]] 824 | name = "objc2" 825 | version = "0.5.2" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" 828 | dependencies = [ 829 | "objc-sys", 830 | "objc2-encode", 831 | ] 832 | 833 | [[package]] 834 | name = "objc2-app-kit" 835 | version = "0.2.2" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" 838 | dependencies = [ 839 | "bitflags 2.7.0", 840 | "block2", 841 | "libc", 842 | "objc2", 843 | "objc2-core-data", 844 | "objc2-core-image", 845 | "objc2-foundation", 846 | "objc2-quartz-core", 847 | ] 848 | 849 | [[package]] 850 | name = "objc2-core-data" 851 | version = "0.2.2" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" 854 | dependencies = [ 855 | "bitflags 2.7.0", 856 | "block2", 857 | "objc2", 858 | "objc2-foundation", 859 | ] 860 | 861 | [[package]] 862 | name = "objc2-core-image" 863 | version = "0.2.2" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" 866 | dependencies = [ 867 | "block2", 868 | "objc2", 869 | "objc2-foundation", 870 | "objc2-metal", 871 | ] 872 | 873 | [[package]] 874 | name = "objc2-encode" 875 | version = "4.0.3" 876 | source = "registry+https://github.com/rust-lang/crates.io-index" 877 | checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" 878 | 879 | [[package]] 880 | name = "objc2-foundation" 881 | version = "0.2.2" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" 884 | dependencies = [ 885 | "bitflags 2.7.0", 886 | "block2", 887 | "libc", 888 | "objc2", 889 | ] 890 | 891 | [[package]] 892 | name = "objc2-metal" 893 | version = "0.2.2" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" 896 | dependencies = [ 897 | "bitflags 2.7.0", 898 | "block2", 899 | "objc2", 900 | "objc2-foundation", 901 | ] 902 | 903 | [[package]] 904 | name = "objc2-quartz-core" 905 | version = "0.2.2" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" 908 | dependencies = [ 909 | "bitflags 2.7.0", 910 | "block2", 911 | "objc2", 912 | "objc2-foundation", 913 | "objc2-metal", 914 | ] 915 | 916 | [[package]] 917 | name = "once_cell" 918 | version = "1.20.2" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 921 | 922 | [[package]] 923 | name = "openssl-probe" 924 | version = "0.1.5" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 927 | 928 | [[package]] 929 | name = "openssl-sys" 930 | version = "0.9.104" 931 | source = "registry+https://github.com/rust-lang/crates.io-index" 932 | checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" 933 | dependencies = [ 934 | "cc", 935 | "libc", 936 | "pkg-config", 937 | "vcpkg", 938 | ] 939 | 940 | [[package]] 941 | name = "os_pipe" 942 | version = "1.2.1" 943 | source = "registry+https://github.com/rust-lang/crates.io-index" 944 | checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" 945 | dependencies = [ 946 | "libc", 947 | "windows-sys 0.59.0", 948 | ] 949 | 950 | [[package]] 951 | name = "parking" 952 | version = "2.2.1" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" 955 | 956 | [[package]] 957 | name = "parking_lot" 958 | version = "0.12.3" 959 | source = "registry+https://github.com/rust-lang/crates.io-index" 960 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 961 | dependencies = [ 962 | "lock_api", 963 | "parking_lot_core", 964 | ] 965 | 966 | [[package]] 967 | name = "parking_lot_core" 968 | version = "0.9.10" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 971 | dependencies = [ 972 | "cfg-if", 973 | "libc", 974 | "redox_syscall", 975 | "smallvec", 976 | "windows-targets 0.52.6", 977 | ] 978 | 979 | [[package]] 980 | name = "percent-encoding" 981 | version = "2.3.1" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 984 | 985 | [[package]] 986 | name = "pin-project" 987 | version = "1.1.7" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" 990 | dependencies = [ 991 | "pin-project-internal", 992 | ] 993 | 994 | [[package]] 995 | name = "pin-project-internal" 996 | version = "1.1.7" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" 999 | dependencies = [ 1000 | "proc-macro2", 1001 | "quote", 1002 | "syn", 1003 | ] 1004 | 1005 | [[package]] 1006 | name = "pin-project-lite" 1007 | version = "0.2.15" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" 1010 | 1011 | [[package]] 1012 | name = "pkg-config" 1013 | version = "0.3.31" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 1016 | 1017 | [[package]] 1018 | name = "png" 1019 | version = "0.17.16" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" 1022 | dependencies = [ 1023 | "bitflags 1.3.2", 1024 | "crc32fast", 1025 | "fdeflate", 1026 | "flate2", 1027 | "miniz_oxide", 1028 | ] 1029 | 1030 | [[package]] 1031 | name = "polling" 1032 | version = "2.8.0" 1033 | source = "registry+https://github.com/rust-lang/crates.io-index" 1034 | checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" 1035 | dependencies = [ 1036 | "autocfg", 1037 | "bitflags 1.3.2", 1038 | "cfg-if", 1039 | "concurrent-queue", 1040 | "libc", 1041 | "log", 1042 | "pin-project-lite", 1043 | "windows-sys 0.48.0", 1044 | ] 1045 | 1046 | [[package]] 1047 | name = "proc-macro2" 1048 | version = "1.0.92" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" 1051 | dependencies = [ 1052 | "unicode-ident", 1053 | ] 1054 | 1055 | [[package]] 1056 | name = "quote" 1057 | version = "1.0.38" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 1060 | dependencies = [ 1061 | "proc-macro2", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "redox_syscall" 1066 | version = "0.5.8" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" 1069 | dependencies = [ 1070 | "bitflags 2.7.0", 1071 | ] 1072 | 1073 | [[package]] 1074 | name = "rustix" 1075 | version = "0.38.43" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" 1078 | dependencies = [ 1079 | "bitflags 2.7.0", 1080 | "errno", 1081 | "libc", 1082 | "linux-raw-sys", 1083 | "windows-sys 0.59.0", 1084 | ] 1085 | 1086 | [[package]] 1087 | name = "ryu" 1088 | version = "1.0.18" 1089 | source = "registry+https://github.com/rust-lang/crates.io-index" 1090 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1091 | 1092 | [[package]] 1093 | name = "schannel" 1094 | version = "0.1.27" 1095 | source = "registry+https://github.com/rust-lang/crates.io-index" 1096 | checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" 1097 | dependencies = [ 1098 | "windows-sys 0.59.0", 1099 | ] 1100 | 1101 | [[package]] 1102 | name = "scopeguard" 1103 | version = "1.2.0" 1104 | source = "registry+https://github.com/rust-lang/crates.io-index" 1105 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1106 | 1107 | [[package]] 1108 | name = "serde" 1109 | version = "1.0.217" 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" 1111 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" 1112 | dependencies = [ 1113 | "serde_derive", 1114 | ] 1115 | 1116 | [[package]] 1117 | name = "serde_derive" 1118 | version = "1.0.217" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" 1121 | dependencies = [ 1122 | "proc-macro2", 1123 | "quote", 1124 | "syn", 1125 | ] 1126 | 1127 | [[package]] 1128 | name = "serde_json" 1129 | version = "1.0.135" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" 1132 | dependencies = [ 1133 | "itoa", 1134 | "memchr", 1135 | "ryu", 1136 | "serde", 1137 | ] 1138 | 1139 | [[package]] 1140 | name = "shared_child" 1141 | version = "1.0.1" 1142 | source = "registry+https://github.com/rust-lang/crates.io-index" 1143 | checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" 1144 | dependencies = [ 1145 | "libc", 1146 | "windows-sys 0.59.0", 1147 | ] 1148 | 1149 | [[package]] 1150 | name = "shlex" 1151 | version = "1.3.0" 1152 | source = "registry+https://github.com/rust-lang/crates.io-index" 1153 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1154 | 1155 | [[package]] 1156 | name = "signal-hook" 1157 | version = "0.3.17" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" 1160 | dependencies = [ 1161 | "libc", 1162 | "signal-hook-registry", 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "signal-hook-mio" 1167 | version = "0.2.4" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" 1170 | dependencies = [ 1171 | "libc", 1172 | "mio", 1173 | "signal-hook", 1174 | ] 1175 | 1176 | [[package]] 1177 | name = "signal-hook-registry" 1178 | version = "1.4.2" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1181 | dependencies = [ 1182 | "libc", 1183 | ] 1184 | 1185 | [[package]] 1186 | name = "simd-adler32" 1187 | version = "0.3.7" 1188 | source = "registry+https://github.com/rust-lang/crates.io-index" 1189 | checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" 1190 | 1191 | [[package]] 1192 | name = "slab" 1193 | version = "0.4.9" 1194 | source = "registry+https://github.com/rust-lang/crates.io-index" 1195 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1196 | dependencies = [ 1197 | "autocfg", 1198 | ] 1199 | 1200 | [[package]] 1201 | name = "sluice" 1202 | version = "0.5.5" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" 1205 | dependencies = [ 1206 | "async-channel", 1207 | "futures-core", 1208 | "futures-io", 1209 | ] 1210 | 1211 | [[package]] 1212 | name = "smallvec" 1213 | version = "1.13.2" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1216 | 1217 | [[package]] 1218 | name = "socket2" 1219 | version = "0.5.8" 1220 | source = "registry+https://github.com/rust-lang/crates.io-index" 1221 | checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" 1222 | dependencies = [ 1223 | "libc", 1224 | "windows-sys 0.52.0", 1225 | ] 1226 | 1227 | [[package]] 1228 | name = "stable_deref_trait" 1229 | version = "1.2.0" 1230 | source = "registry+https://github.com/rust-lang/crates.io-index" 1231 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1232 | 1233 | [[package]] 1234 | name = "strsim" 1235 | version = "0.11.1" 1236 | source = "registry+https://github.com/rust-lang/crates.io-index" 1237 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1238 | 1239 | [[package]] 1240 | name = "syn" 1241 | version = "2.0.94" 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" 1243 | checksum = "987bc0be1cdea8b10216bd06e2ca407d40b9543468fafd3ddfb02f36e77f71f3" 1244 | dependencies = [ 1245 | "proc-macro2", 1246 | "quote", 1247 | "unicode-ident", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "synstructure" 1252 | version = "0.13.1" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 1255 | dependencies = [ 1256 | "proc-macro2", 1257 | "quote", 1258 | "syn", 1259 | ] 1260 | 1261 | [[package]] 1262 | name = "tiff" 1263 | version = "0.9.1" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" 1266 | dependencies = [ 1267 | "flate2", 1268 | "jpeg-decoder", 1269 | "weezl", 1270 | ] 1271 | 1272 | [[package]] 1273 | name = "tinystr" 1274 | version = "0.7.6" 1275 | source = "registry+https://github.com/rust-lang/crates.io-index" 1276 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 1277 | dependencies = [ 1278 | "displaydoc", 1279 | "zerovec", 1280 | ] 1281 | 1282 | [[package]] 1283 | name = "tracing" 1284 | version = "0.1.41" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1287 | dependencies = [ 1288 | "log", 1289 | "pin-project-lite", 1290 | "tracing-attributes", 1291 | "tracing-core", 1292 | ] 1293 | 1294 | [[package]] 1295 | name = "tracing-attributes" 1296 | version = "0.1.28" 1297 | source = "registry+https://github.com/rust-lang/crates.io-index" 1298 | checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 1299 | dependencies = [ 1300 | "proc-macro2", 1301 | "quote", 1302 | "syn", 1303 | ] 1304 | 1305 | [[package]] 1306 | name = "tracing-core" 1307 | version = "0.1.33" 1308 | source = "registry+https://github.com/rust-lang/crates.io-index" 1309 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 1310 | dependencies = [ 1311 | "once_cell", 1312 | ] 1313 | 1314 | [[package]] 1315 | name = "tracing-futures" 1316 | version = "0.2.5" 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" 1318 | checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" 1319 | dependencies = [ 1320 | "pin-project", 1321 | "tracing", 1322 | ] 1323 | 1324 | [[package]] 1325 | name = "unicode-ident" 1326 | version = "1.0.14" 1327 | source = "registry+https://github.com/rust-lang/crates.io-index" 1328 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 1329 | 1330 | [[package]] 1331 | name = "url" 1332 | version = "2.5.4" 1333 | source = "registry+https://github.com/rust-lang/crates.io-index" 1334 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 1335 | dependencies = [ 1336 | "form_urlencoded", 1337 | "idna", 1338 | "percent-encoding", 1339 | ] 1340 | 1341 | [[package]] 1342 | name = "utf16_iter" 1343 | version = "1.0.5" 1344 | source = "registry+https://github.com/rust-lang/crates.io-index" 1345 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 1346 | 1347 | [[package]] 1348 | name = "utf8_iter" 1349 | version = "1.0.4" 1350 | source = "registry+https://github.com/rust-lang/crates.io-index" 1351 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1352 | 1353 | [[package]] 1354 | name = "utf8parse" 1355 | version = "0.2.2" 1356 | source = "registry+https://github.com/rust-lang/crates.io-index" 1357 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1358 | 1359 | [[package]] 1360 | name = "vcpkg" 1361 | version = "0.2.15" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1364 | 1365 | [[package]] 1366 | name = "waker-fn" 1367 | version = "1.2.0" 1368 | source = "registry+https://github.com/rust-lang/crates.io-index" 1369 | checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" 1370 | 1371 | [[package]] 1372 | name = "wasi" 1373 | version = "0.11.0+wasi-snapshot-preview1" 1374 | source = "registry+https://github.com/rust-lang/crates.io-index" 1375 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1376 | 1377 | [[package]] 1378 | name = "weezl" 1379 | version = "0.1.8" 1380 | source = "registry+https://github.com/rust-lang/crates.io-index" 1381 | checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" 1382 | 1383 | [[package]] 1384 | name = "winapi" 1385 | version = "0.3.9" 1386 | source = "registry+https://github.com/rust-lang/crates.io-index" 1387 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1388 | dependencies = [ 1389 | "winapi-i686-pc-windows-gnu", 1390 | "winapi-x86_64-pc-windows-gnu", 1391 | ] 1392 | 1393 | [[package]] 1394 | name = "winapi-i686-pc-windows-gnu" 1395 | version = "0.4.0" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1398 | 1399 | [[package]] 1400 | name = "winapi-x86_64-pc-windows-gnu" 1401 | version = "0.4.0" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1404 | 1405 | [[package]] 1406 | name = "windows-sys" 1407 | version = "0.48.0" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1410 | dependencies = [ 1411 | "windows-targets 0.48.5", 1412 | ] 1413 | 1414 | [[package]] 1415 | name = "windows-sys" 1416 | version = "0.52.0" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1419 | dependencies = [ 1420 | "windows-targets 0.52.6", 1421 | ] 1422 | 1423 | [[package]] 1424 | name = "windows-sys" 1425 | version = "0.59.0" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1428 | dependencies = [ 1429 | "windows-targets 0.52.6", 1430 | ] 1431 | 1432 | [[package]] 1433 | name = "windows-targets" 1434 | version = "0.48.5" 1435 | source = "registry+https://github.com/rust-lang/crates.io-index" 1436 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1437 | dependencies = [ 1438 | "windows_aarch64_gnullvm 0.48.5", 1439 | "windows_aarch64_msvc 0.48.5", 1440 | "windows_i686_gnu 0.48.5", 1441 | "windows_i686_msvc 0.48.5", 1442 | "windows_x86_64_gnu 0.48.5", 1443 | "windows_x86_64_gnullvm 0.48.5", 1444 | "windows_x86_64_msvc 0.48.5", 1445 | ] 1446 | 1447 | [[package]] 1448 | name = "windows-targets" 1449 | version = "0.52.6" 1450 | source = "registry+https://github.com/rust-lang/crates.io-index" 1451 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1452 | dependencies = [ 1453 | "windows_aarch64_gnullvm 0.52.6", 1454 | "windows_aarch64_msvc 0.52.6", 1455 | "windows_i686_gnu 0.52.6", 1456 | "windows_i686_gnullvm", 1457 | "windows_i686_msvc 0.52.6", 1458 | "windows_x86_64_gnu 0.52.6", 1459 | "windows_x86_64_gnullvm 0.52.6", 1460 | "windows_x86_64_msvc 0.52.6", 1461 | ] 1462 | 1463 | [[package]] 1464 | name = "windows_aarch64_gnullvm" 1465 | version = "0.48.5" 1466 | source = "registry+https://github.com/rust-lang/crates.io-index" 1467 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 1468 | 1469 | [[package]] 1470 | name = "windows_aarch64_gnullvm" 1471 | version = "0.52.6" 1472 | source = "registry+https://github.com/rust-lang/crates.io-index" 1473 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1474 | 1475 | [[package]] 1476 | name = "windows_aarch64_msvc" 1477 | version = "0.48.5" 1478 | source = "registry+https://github.com/rust-lang/crates.io-index" 1479 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 1480 | 1481 | [[package]] 1482 | name = "windows_aarch64_msvc" 1483 | version = "0.52.6" 1484 | source = "registry+https://github.com/rust-lang/crates.io-index" 1485 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1486 | 1487 | [[package]] 1488 | name = "windows_i686_gnu" 1489 | version = "0.48.5" 1490 | source = "registry+https://github.com/rust-lang/crates.io-index" 1491 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 1492 | 1493 | [[package]] 1494 | name = "windows_i686_gnu" 1495 | version = "0.52.6" 1496 | source = "registry+https://github.com/rust-lang/crates.io-index" 1497 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1498 | 1499 | [[package]] 1500 | name = "windows_i686_gnullvm" 1501 | version = "0.52.6" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1504 | 1505 | [[package]] 1506 | name = "windows_i686_msvc" 1507 | version = "0.48.5" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 1510 | 1511 | [[package]] 1512 | name = "windows_i686_msvc" 1513 | version = "0.52.6" 1514 | source = "registry+https://github.com/rust-lang/crates.io-index" 1515 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1516 | 1517 | [[package]] 1518 | name = "windows_x86_64_gnu" 1519 | version = "0.48.5" 1520 | source = "registry+https://github.com/rust-lang/crates.io-index" 1521 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 1522 | 1523 | [[package]] 1524 | name = "windows_x86_64_gnu" 1525 | version = "0.52.6" 1526 | source = "registry+https://github.com/rust-lang/crates.io-index" 1527 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1528 | 1529 | [[package]] 1530 | name = "windows_x86_64_gnullvm" 1531 | version = "0.48.5" 1532 | source = "registry+https://github.com/rust-lang/crates.io-index" 1533 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 1534 | 1535 | [[package]] 1536 | name = "windows_x86_64_gnullvm" 1537 | version = "0.52.6" 1538 | source = "registry+https://github.com/rust-lang/crates.io-index" 1539 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1540 | 1541 | [[package]] 1542 | name = "windows_x86_64_msvc" 1543 | version = "0.48.5" 1544 | source = "registry+https://github.com/rust-lang/crates.io-index" 1545 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1546 | 1547 | [[package]] 1548 | name = "windows_x86_64_msvc" 1549 | version = "0.52.6" 1550 | source = "registry+https://github.com/rust-lang/crates.io-index" 1551 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1552 | 1553 | [[package]] 1554 | name = "write16" 1555 | version = "1.0.0" 1556 | source = "registry+https://github.com/rust-lang/crates.io-index" 1557 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 1558 | 1559 | [[package]] 1560 | name = "writeable" 1561 | version = "0.5.5" 1562 | source = "registry+https://github.com/rust-lang/crates.io-index" 1563 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 1564 | 1565 | [[package]] 1566 | name = "x11rb" 1567 | version = "0.13.1" 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" 1569 | checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" 1570 | dependencies = [ 1571 | "gethostname", 1572 | "rustix", 1573 | "x11rb-protocol", 1574 | ] 1575 | 1576 | [[package]] 1577 | name = "x11rb-protocol" 1578 | version = "0.13.1" 1579 | source = "registry+https://github.com/rust-lang/crates.io-index" 1580 | checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" 1581 | 1582 | [[package]] 1583 | name = "yansi" 1584 | version = "1.0.1" 1585 | source = "registry+https://github.com/rust-lang/crates.io-index" 1586 | checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" 1587 | 1588 | [[package]] 1589 | name = "yoke" 1590 | version = "0.7.5" 1591 | source = "registry+https://github.com/rust-lang/crates.io-index" 1592 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 1593 | dependencies = [ 1594 | "serde", 1595 | "stable_deref_trait", 1596 | "yoke-derive", 1597 | "zerofrom", 1598 | ] 1599 | 1600 | [[package]] 1601 | name = "yoke-derive" 1602 | version = "0.7.5" 1603 | source = "registry+https://github.com/rust-lang/crates.io-index" 1604 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 1605 | dependencies = [ 1606 | "proc-macro2", 1607 | "quote", 1608 | "syn", 1609 | "synstructure", 1610 | ] 1611 | 1612 | [[package]] 1613 | name = "zerofrom" 1614 | version = "0.1.5" 1615 | source = "registry+https://github.com/rust-lang/crates.io-index" 1616 | checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" 1617 | dependencies = [ 1618 | "zerofrom-derive", 1619 | ] 1620 | 1621 | [[package]] 1622 | name = "zerofrom-derive" 1623 | version = "0.1.5" 1624 | source = "registry+https://github.com/rust-lang/crates.io-index" 1625 | checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" 1626 | dependencies = [ 1627 | "proc-macro2", 1628 | "quote", 1629 | "syn", 1630 | "synstructure", 1631 | ] 1632 | 1633 | [[package]] 1634 | name = "zerovec" 1635 | version = "0.10.4" 1636 | source = "registry+https://github.com/rust-lang/crates.io-index" 1637 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 1638 | dependencies = [ 1639 | "yoke", 1640 | "zerofrom", 1641 | "zerovec-derive", 1642 | ] 1643 | 1644 | [[package]] 1645 | name = "zerovec-derive" 1646 | version = "0.10.3" 1647 | source = "registry+https://github.com/rust-lang/crates.io-index" 1648 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 1649 | dependencies = [ 1650 | "proc-macro2", 1651 | "quote", 1652 | "syn", 1653 | ] 1654 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "git-acm" 3 | description = "instant meaningful commit messages." 4 | version = "1.3.0" 5 | edition = "2021" 6 | license-file = "LICENSE" 7 | homepage = "https://git-acm.pages.dev" 8 | repository = "https://github.com/shivamhwp/git-acm" 9 | readme = "cargo-readme.md" 10 | exclude = ["docs"] 11 | 12 | 13 | [dependencies] 14 | isahc = {version = "1.7.2", features = ["json"]} 15 | duct = "0.13.7" 16 | dotenvy = "0.15.7" 17 | clap = "4.5.23" 18 | yansi = "1.0.1" 19 | serde_json = "1.0.135" 20 | arboard = "3.4.1" 21 | crossterm = "0.28.1" 22 | serde = { version = "1.0.215", features = ["derive"] } 23 | 24 | [profile.release] 25 | codegen-units = 1 26 | lto = true 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Shivam Sharma 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. -------------------------------------------------------------------------------- /assets/models.json: -------------------------------------------------------------------------------- 1 | { 2 | "models": [ 3 | { 4 | "model_api_name": "o1-2024-12-17", 5 | "model_name": "o1", 6 | "provider": "openai" 7 | }, 8 | { 9 | "model_api_name": "o3-2025-04-16", 10 | "model_name": "o3", 11 | "provider": "openai" 12 | }, 13 | { 14 | "model_api_name": "gemini-2.5-flash-preview-04-17", 15 | "model_name": "gemini-2.5-flash", 16 | "provider": "gemini" 17 | }, 18 | { 19 | "model_api_name": "o4-mini-2025-04-16", 20 | "model_name": "o4-mini", 21 | "provider": "openai" 22 | }, 23 | { 24 | "model_api_name": "claude-sonnet-4-20250514", 25 | "model_name": "claude-sonnet-4", 26 | "provider": "anthropic" 27 | }, 28 | { 29 | "model_api_name": "claude-opus-4-20250514", 30 | "model_name": "claude-opus-4", 31 | "provider": "anthropic" 32 | }, 33 | { 34 | "model_api_name": "o1-mini-2024-09-12", 35 | "model_name": "o1-mini", 36 | "provider": "openai" 37 | }, 38 | { 39 | "model_api_name": "o3-mini-2025-01-31", 40 | "model_name": "o3-mini", 41 | "provider": "openai" 42 | }, 43 | { 44 | "model_api_name": "chatgpt-4o-latest", 45 | "model_name": "gpt-4o", 46 | "provider": "openai" 47 | }, 48 | { 49 | "model_api_name": "gpt-4.1-2025-04-14", 50 | "model_name": "gpt-4.1", 51 | "provider": "openai" 52 | }, 53 | { 54 | "model_api_name": "o1-pro-2025-03-19", 55 | "model_name": "o1-pro", 56 | "provider": "openai" 57 | }, 58 | { 59 | "model_api_name": "gpt-4.1-mini-2025-04-14", 60 | "model_name": "gpt-4.1-mini", 61 | "provider": "openai" 62 | }, 63 | { 64 | "model_api_name": "gpt-4.1-nano-2025-04-14", 65 | "model_name": "gpt-4.1-nano", 66 | "provider": "openai" 67 | }, 68 | { 69 | "model_api_name": "claude-3-7-sonnet-latest", 70 | "model_name": "claude-3.7-sonnet", 71 | "provider": "anthropic" 72 | }, 73 | { 74 | "model_api_name": "claude-3-5-sonnet-latest", 75 | "model_name": "claude-3.5-sonnet", 76 | "provider": "anthropic" 77 | }, 78 | { 79 | "model_api_name": "claude-3-5-haiku-latest", 80 | "model_name": "claude-3.5-haiku", 81 | "provider": "anthropic" 82 | }, 83 | { 84 | "model_api_name": "gemini-2.5-pro-preview-03-25", 85 | "model_name": "gemini-2.5-pro", 86 | "provider": "gemini" 87 | }, 88 | { 89 | "model_api_name": "gemini-2.0-flash", 90 | "model_name": "gemini-2.0-flash", 91 | "provider": "gemini" 92 | }, 93 | { 94 | "model_api_name": "gemini-2.0-flash-lite", 95 | "model_name": "gemini-2.0-flash-lite", 96 | "provider": "gemini" 97 | }, 98 | { 99 | "model_api_name": "deepseek-chat", 100 | "model_name": "deepseek-chat", 101 | "provider": "deepseek" 102 | }, 103 | { 104 | "model_api_name": "deepseek-reasoner", 105 | "model_name": "deepseek-reasoner", 106 | "provider": "deepseek" 107 | }, 108 | { 109 | "model_api_name": "llama-4-scout", 110 | "model_name": "llama-4-scout", 111 | "provider": "llama" 112 | }, 113 | { 114 | "model_api_name": "llama-4-maverick", 115 | "model_name": "llama-4-maverick", 116 | "provider": "llama" 117 | }, 118 | { 119 | "model_api_name": "llama-3.3-70b-instruct", 120 | "model_name": "llama-3.3-70b-instruct", 121 | "provider": "llama" 122 | }, 123 | { 124 | "model_api_name": "llama-3.1-8b-instruct", 125 | "model_name": "llama-3.1-8b-instruct", 126 | "provider": "llama" 127 | }, 128 | { 129 | "model_api_name": "llama-3.1-70b-instruct", 130 | "model_name": "llama-3.1-70b-instruct", 131 | "provider": "llama" 132 | }, 133 | { 134 | "model_api_name": "llama-3.2-3b-instruct", 135 | "model_name": "llama-3.2-3b-instruct", 136 | "provider": "llama" 137 | } 138 | ] 139 | } 140 | -------------------------------------------------------------------------------- /assets/prompt.txt: -------------------------------------------------------------------------------- 1 | You are a Git Commit Message Generator that follows the Conventional Commits specification (https://www.conventionalcommits.org/). 2 | 3 | CORE RULES: 4 | 1. MAXIMUM 50 CHARACTERS - ABSOLUTELY STRICT 5 | 2. Follow format: (): 6 | - Type: feat|fix|docs|style|refactor|perf|test|chore 7 | - Scope: optional, in parentheses 8 | - Description: present tense, no period 9 | 3. Start with lowercase type 10 | 4. No punctuation at end 11 | 5. Must be single line 12 | 13 | TYPES EXPLAINED: 14 | - feat: New feature 15 | - fix: Bug fix 16 | - docs: Documentation only 17 | - style: Code style/formatting 18 | - refactor: Code change that neither fixes a bug nor adds a feature 19 | - perf: Performance improvement 20 | - test: Adding/updating tests 21 | - chore: Maintenance tasks 22 | 23 | VALIDATIONS: 24 | 1. Count characters [(): ] 25 | 2. Check present tense 26 | 3. Verify conventional commit format 27 | 4. Ensure lowercase type 28 | 5. No trailing punctuation 29 | 6. Check number of characters <=50. ABSOLUTELY STRICT 30 | 31 | GOOD EXAMPLES: 32 | ✓ feat: Add user authentication 33 | ✓ fix(api): Resolve memory leak 34 | ✓ docs: Update README installation 35 | ✓ style(css): Format login component 36 | 37 | 38 | BAD EXAMPLES: 39 | ✗ feat: Implemented new authentication system (44 chars, wrong tense) 40 | ✗ Fix the bug in the authentication system (41 chars, wrong format) 41 | ✗ feat(auth): Implement comprehensive user management system (61 chars, TOO LONG) 42 | 43 | BEFORE RESPONDING: 44 | 1. Check if git diff is empty - if yes, tell user to stage changes 45 | 2. Analyze the changes 46 | 3. Determine appropriate type and scope 47 | 4. Write concise description 48 | 5. COUNT TOTAL CHARACTERS 49 | 6. If >50 chars, make it shorter 50 | 7. Verify all rules are met 51 | 52 | YOUR RESPONSE MUST BE: 53 | 1. A single line 54 | 2. ≤54 characters total 55 | 3. Follow conventional commits format 56 | 4. Be clear and specific -------------------------------------------------------------------------------- /cargo-readme.md: -------------------------------------------------------------------------------- 1 | # git-acm - git auto-commit-message 2 | 3 | ### instant meaningful commit messages 4 | 5 | ![Crates.io Total Downloads](https://img.shields.io/crates/d/git-acm?labelColor=%23222&color=white) 6 | ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/shivamhwp/git-acm/release.yml?labelColor=%23222&color=white) 7 | 8 | ### installation 9 | 10 | ``` 11 | curl -sSL https://raw.githubusercontent.com/shivamhwp/git-acm/main/install.sh | sh 12 | ``` 13 | 14 | or 15 | if you have `cargo` installed on your system. 16 | 17 | ``` 18 | cargo install git-acm 19 | ``` 20 | 21 | ### how to use 22 | 23 | 1. add [gemini-api-key](https://aistudio.google.com/app/apikey) or [openai-api-key](https://platform.openai.com/api-keys) or [anthropic-api-key](https://console.anthropic.com/settings/keys) or [deepseek-api-key](https://platform.deepseek.com/api_keys) 24 | 2. add these in your project's `.env` file or `export` them in terminal. 25 | 26 | ``` 27 | # for gemini api 28 | 29 | GEMINI_API_KEY="" 30 | 31 | # for anthropic api 32 | 33 | ANTHROPIC_API_KEY="" 34 | 35 | # for openai api 36 | 37 | OPENAI_API_KEY="" 38 | 39 | # for llama api (using ollama) 40 | 41 | LLAMA_API_URL="http://localhost:11434/api/generate" 42 | LLAMA_MODEL_NAME= "llama3.2:1b" 43 | 44 | # for deepseek api 45 | 46 | DEEPSEEEK_API_KEY="" 47 | 48 | ``` 49 | 50 | 4. run `git-acm`. 51 | 52 | ### 📍 commands available 53 | 54 | `use` : choose which model you want to use. (run `git-acm list` to see the available models). 55 | 56 | `autocommit` : enables or disables the autocommit functionality. 57 | 58 | `list` : lists all available models. 59 | 60 | ### 📍 example 61 | 62 | ```bash 63 | git-acm use # choose which model to use. 64 | git-acm list # list all the models. 65 | git-acm autocommit enable # Enable automatic commits with generated messages 66 | git-acm autocommit disable # Disable automatic commits 67 | git-acm # Generate a commit message using the currently selected API 68 | 69 | ``` 70 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ### 1.2.2 2 | 3 | - gemini 2.5 flash support 4 | 5 | ### 1.2.1 6 | 7 | - o3 and o4-mini support 8 | 9 | ### 1.2.0 10 | 11 | - a huge refactor 12 | - updated and simple model selection system. 13 | - let's you choose from different models. 14 | 15 | ### 1.1.4 16 | 17 | - [q] to quit the msg_handler. 18 | - minor updates. 19 | - deepseek-chat -> deepseek-coder 20 | 21 | ### 1.1.3 22 | 23 | - update claude-3.5 to claude 3.7 24 | 25 | ### 1.1.2 26 | 27 | - gemini 2.0 flash upgrade 28 | 29 | ### 1.1.1 30 | 31 | - deepseek api support 32 | - rerun feature : [enter] to accept, [r] to rerun and get a new message. 33 | - a lil bit of cleaning. 34 | 35 | ### 1.1.0 36 | 37 | - llama support 🎉 38 | - llama model options. 39 | - refactoring of code. 40 | - autocommit feature added. 🎉 41 | 42 | ### 1.0.2 43 | 44 | - perf improvements. 45 | - bug fixes. 46 | 47 | ### 1.0.1 48 | 49 | 📍 a big release 50 | 51 | - supports anthropic, openai and gemini apis. 52 | - better error handling. 53 | - use command to switch apis. 54 | - the msg automatically copies to clipboard. 55 | - a lot of refactoring. 56 | 57 | ### 1.0.0 58 | 59 | - testing binaries and stuff. 60 | 61 | ### 0.1.2 62 | 63 | - working. let's fking go. 64 | - [crates.io](https://crates.io/crates/git-acm) 65 | 66 | ### 0.1.1 67 | 68 | - bug fix. 69 | - readme updates. 70 | 71 | ### 0.1.0 72 | 73 | - just released. 74 | - available as a rust package. 75 | - not suitable for use (contains a bug). 76 | -------------------------------------------------------------------------------- /cooking-process.md: -------------------------------------------------------------------------------- 1 | # what i think rn will be the process of building it. 2 | 3 | this file is just my documentaion of thoughts, when i was building this. 4 | 5 | ### what are the main things we need this tool to work : 6 | 7 | - i think git diffs. so you can get the diff b/w the previous and current commit. 8 | 9 | - get the files changed > send the git diff in the api call > get the res back > show it in the terminal (maybe). 10 | 11 |
12 | 13 | ### just thinking 14 | 15 | - sending the full git diff is not feasible, coz of the token limit. so the second best thing we can do this is either sending files in patches or limit them based on lines.(maybe in future) 16 | 17 | > in case of patches, get the commit messages > store them in a json file with their respec. file names and them make the last api call to get the commit msg for the pr. (maybe in future) 18 | 19 | - if the change is not that big, then we git diff > req to api > res from api > set it as gcm. 20 | 21 |
22 | 23 | ### things to consider 24 | 25 | - removing the empty lines from git diff. 26 | 27 |
28 | 29 | ### what will be the process (as of think rn): 30 | 31 | - you install the binary or the package. (it gets stored in .acm dir in your root dir. which contains an executable whenever you run acm command in terminal) 32 | 33 | - i think that's it. let's build this. 34 | 35 | --- 36 | 37 | so solving the msg choosing and running feature, so if we think what could be the flow. 38 | user gets the msg from the response > [enter] to choose and [r] to rerun and get another msg. 39 | 40 | so a fn that takes a string as input and watches for keycodes, based on which either it calls the function or returns the result. 41 | 42 | todo 43 | 44 | [ ] revamp the structure and let user directly put model names and we figure out the rest. 45 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | progress() { 6 | echo "=> $1" 7 | } 8 | 9 | # Detect platform 10 | PLATFORM="unknown" 11 | case "$(uname -s)" in 12 | Linux*) PLATFORM="linux";; 13 | Darwin*) PLATFORM="darwin";; 14 | MSYS*|MINGW*) PLATFORM="windows";; 15 | *) 16 | echo "unsupported platform: $(uname -s)" 17 | exit 1 18 | ;; 19 | esac 20 | 21 | ARCH="x86_64" 22 | VERSION=$(curl -s https://api.github.com/repos/shivamhwp/git-acm/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') 23 | # gets the latest version 24 | 25 | # Construct binary name and URLs 26 | if [ "$PLATFORM" = "windows" ]; then 27 | BINARY="git-acm-windows-x86_64.exe" 28 | else 29 | BINARY="git-acm-${PLATFORM}-${ARCH}" 30 | fi 31 | 32 | DOWNLOAD_URL="https://github.com/shivamhwp/git-acm/releases/download/${VERSION}/${BINARY}" 33 | CHECKSUM_URL="${DOWNLOAD_URL}.sha256" 34 | 35 | # Create temporary directory 36 | TMP_DIR=$(mktemp -d) 37 | TMP_FILE="${TMP_DIR}/${BINARY}" 38 | TMP_CHECKSUM="${TMP_DIR}/${BINARY}.sha256" 39 | TMP_EXPECTED_CHECKSUM="${TMP_DIR}/expected.sha256" 40 | 41 | # Download binary 42 | progress "downloading..." 43 | curl -sL "$DOWNLOAD_URL" -o "$TMP_FILE" 44 | 45 | # Determine which checksum tool to use 46 | if command -v sha256sum >/dev/null; then 47 | SHA256_CMD="sha256sum" 48 | elif command -v shasum >/dev/null; then 49 | SHA256_CMD="shasum -a 256" 50 | else 51 | echo "error: No sha256sum or shasum command found" 52 | rm -rf "$TMP_DIR" 53 | exit 1 54 | fi 55 | 56 | # Generate checksum file locally 57 | (cd "$TMP_DIR" && $SHA256_CMD "$BINARY" > "${BINARY}.sha256") 58 | 59 | # Download trusted checksum directly from GitHub release 60 | # progress "downloading trusted checksum" 61 | if curl -sL --fail "$CHECKSUM_URL" -o "$TMP_EXPECTED_CHECKSUM"; then 62 | # progress "successfully downloaded checksum file" 63 | progress "making sure it's safe 🦺 and secure 🔒" 64 | else 65 | echo "warning: could not download checksum file, using fallback verification" 66 | # As fallback, download the binary a second time to verify it hasn't been corrupted 67 | SECOND_DOWNLOAD="${TMP_DIR}/second_${BINARY}" 68 | curl -sL "$DOWNLOAD_URL" -o "$SECOND_DOWNLOAD" 69 | (cd "$TMP_DIR" && $SHA256_CMD "$BINARY" > "$TMP_EXPECTED_CHECKSUM") 70 | progress "performed secondary download for comparison" 71 | fi 72 | 73 | # Verify integrity by comparing checksums 74 | # progress "verifying if it's all safe and secure" 75 | LOCAL_CHECKSUM=$(cut -d' ' -f1 "$TMP_CHECKSUM") 76 | EXPECTED_CHECKSUM=$(cat "$TMP_EXPECTED_CHECKSUM" | tr -d ' \r\n') 77 | 78 | if [ "$LOCAL_CHECKSUM" != "$EXPECTED_CHECKSUM" ]; then 79 | echo "error: checksum verification failed" 80 | # echo "expected: $EXPECTED_CHECKSUM" 81 | # echo "got: $LOCAL_CHECKSUM" 82 | rm -rf "$TMP_DIR" 83 | exit 1 84 | fi 85 | 86 | 87 | # Determine install location 88 | if [ "$PLATFORM" = "darwin" ]; then 89 | INSTALL_DIR="$HOME/.local/bin" 90 | mkdir -p "$INSTALL_DIR" 91 | elif [ -w "/usr/local/bin" ]; then 92 | INSTALL_DIR="/usr/local/bin" 93 | else 94 | INSTALL_DIR="$HOME/.local/bin" 95 | mkdir -p "$INSTALL_DIR" 96 | fi 97 | 98 | # Install binary 99 | mv "$TMP_FILE" "$INSTALL_DIR/git-acm" 100 | chmod 755 "$INSTALL_DIR/git-acm" 101 | 102 | # Handle macOS specific security 103 | if [ "$PLATFORM" = "darwin" ]; then 104 | progress "talking to the macos gods" 105 | xattr -d com.apple.quarantine "$INSTALL_DIR/git-acm" 2>/dev/null || true 106 | # If using newer macOS versions, might need to add to security list 107 | if [ -x "/usr/bin/spctl" ]; then 108 | sudo spctl --add "$INSTALL_DIR/git-acm" 2>/dev/null || true 109 | fi 110 | fi 111 | 112 | # Add to PATH if needed 113 | if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then 114 | if [ -f "$HOME/.zshrc" ]; then 115 | echo "export PATH=\"$INSTALL_DIR:\$PATH\"" >> "$HOME/.zshrc" 116 | fi 117 | if [ -f "$HOME/.bashrc" ]; then 118 | echo "export PATH=\"$INSTALL_DIR:\$PATH\"" >> "$HOME/.bashrc" 119 | fi 120 | if [ -f "$HOME/.config/fish/config.fish" ]; then 121 | echo "set -gx PATH $INSTALL_DIR \$PATH" >> "$HOME/.config/fish/config.fish" 122 | fi 123 | fi 124 | 125 | # Cleanup 126 | rm -rf "$TMP_DIR" 127 | 128 | progress "all done 🎉 !!!" 129 | 130 | # Attempt to refresh PATH in current shell 131 | SHELL_CONFIG_REFRESHED=false 132 | 133 | if [ -n "$ZSH_VERSION" ]; then 134 | # User is likely using zsh 135 | if [ -f "$HOME/.zshrc" ]; then 136 | source "$HOME/.zshrc" 137 | SHELL_CONFIG_REFRESHED=true 138 | fi 139 | elif [ -n "$BASH_VERSION" ]; then 140 | # User is likely using bash 141 | if [ -f "$HOME/.bashrc" ]; then 142 | source "$HOME/.bashrc" 143 | SHELL_CONFIG_REFRESHED=true 144 | elif [ -f "$HOME/.bash_profile" ]; then 145 | source "$HOME/.bash_profile" 146 | SHELL_CONFIG_REFRESHED=true 147 | elif [ -f "$HOME/.profile" ]; then 148 | source "$HOME/.profile" 149 | SHELL_CONFIG_REFRESHED=true 150 | fi 151 | elif [ -n "$FISH_VERSION" ]; then 152 | # User is likely using fish 153 | if [ -f "$HOME/.config/fish/config.fish" ]; then 154 | source "$HOME/.config/fish/config.fish" 155 | SHELL_CONFIG_REFRESHED=true 156 | fi 157 | fi 158 | 159 | if ! $SHELL_CONFIG_REFRESHED; then 160 | progress "Please open a new terminal window or run 'source ~/.zshrc' or 'source ~/.bashrc' to refresh your PATH." 161 | fi 162 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # git-acm ( git auto-commit-message ) 2 | 3 | ### instant meaningful commit messages. 4 | 5 | ![Crates.io Total Downloads](https://img.shields.io/crates/d/git-acm?labelColor=%23222&color=white) 6 | ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/shivamhwp/git-acm/release.yml?labelColor=%23222&color=white) 7 | 8 | docs 📄 : [git-acm.pages.dev](https://git-acm.pages.dev) | crate 🦀 : [crates.io](https://crates.io/crates/git-acm) 9 | 10 | ### installation 11 | 12 | ``` 13 | curl -sSL https://raw.githubusercontent.com/shivamhwp/git-acm/main/install.sh | sh 14 | ``` 15 | 16 | > to update : just run the installation command, it checks the system for prev version and then installs a new version if there's one. 17 | 18 | or 19 | if you have `cargo` installed on your system. 20 | 21 | ``` 22 | cargo install git-acm 23 | ``` 24 | 25 | ### how to use 26 | 27 | 1. ensure git is initialized in the dir. or run `git init`. 28 | 2. add [gemini-api-key](https://aistudio.google.com/app/apikey) or [openai-api-key](https://platform.openai.com/api-keys) or [anthropic-api-key](https://console.anthropic.com/settings/keys) or [deepseek-api-key](https://platform.deepseek.com/api_keys) 29 | 3. add these in your project's `.env` file (preferred) or `export` them in terminal. 30 | 31 | ``` 32 | # for gemini api 33 | 34 | GEMINI_API_KEY="" 35 | 36 | # for anthropic api 37 | 38 | ANTHROPIC_API_KEY="" 39 | 40 | # for openai api 41 | 42 | OPENAI_API_KEY="" 43 | 44 | # for llama api (using ollama) 45 | 46 | LLAMA_API_URL="http://localhost:11434/api/generate" 47 | LLAMA_MODEL_NAME= "llama3.2:1b" 48 | 49 | # for deepseek api 50 | 51 | DEEPSEEEK_API_KEY="" 52 | 53 | ``` 54 | 55 | 4. run `git-acm use `. 56 | 5. just run `git-acm`. 57 | 58 | ### 📍 commands available 59 | 60 | `use` : choose which model you want to use. (run `git-acm list` to see the available models). 61 | 62 | `autocommit` : enables or disables the autocommit functionality. 63 | 64 | `list` : lists all available models. 65 | 66 | ### 📍 example 67 | 68 | ```bash 69 | git-acm use # choose which model to use. 70 | git-acm autocommit enable # Enable automatic commits with generated messages 71 | git-acm list # lists all the available models. 72 | git-acm autocommit disable # Disable automatic commits 73 | git-acm # Generate a commit message using the currently selected model. 74 | 75 | ``` 76 | 77 | # Contributing 78 | 79 | ### local development setup 80 | 81 | > ensure `rust` is installed on your system . go to [`https://doc.rust-lang.org/book/ch01-01-installation.html`](https://doc.rust-lang.org/book/ch01-01-installation.html) for details. 82 | 83 | 1. ```bash 84 | git clone https://github.com/shivamhwp/acm.git 85 | ``` 86 | 87 | 2. get [gemini-api-credentials](https://aistudio.google.com/app/apikey) or [openai-api-credentials](https://platform.openai.com/api-keys) or [anthropic-api-credentials](https://console.anthropic.com/settings/keys). see [.env.example](https://github.com/shivamhwp/git-acm/blob/main/.env.example) 88 | 3. create `.env` file at root > set `GEMINI_API_KEY=" " ` or any other provider's key. 89 | 4. ```bash 90 | cargo build 91 | ``` 92 | 5. `cargo run --` to get the commit msg in the terminal. 93 | 6. start with `main.rs` and break stuff. 94 | 95 |
96 | 97 | [report 🐞bugs here](https://x.com/shivamhwp) 98 | 99 | bhai(s) : [sargam](https://x.com/sargampoudel) (idea) and [smr](https://x.com/smrdotgg) (suggestions). 100 | 101 |
102 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::{Command, Arg}; 2 | use serde::Deserialize; 3 | use models::{ 4 | anthropic::anthropic, deepseek::deepseek, gemini::gemini, llama::llama, openai::openai, 5 | }; 6 | use utils::{ 7 | config::{load_model_from_pref, load_models_from_json, print_to_cli, save_autocommit_preference, save_model_value}, 8 | diff::is_git_initialized, 9 | }; 10 | use yansi::Paint; 11 | 12 | mod models; 13 | mod utils; 14 | 15 | 16 | #[derive(Deserialize, Debug)] 17 | pub struct Model { 18 | model_api_name: String, 19 | model_name: String, 20 | provider: String, 21 | } 22 | 23 | 24 | fn main() { 25 | is_git_initialized(); 26 | let description = " instant meaningful commit messages.\n (more): https://git.new/git-acm " 27 | .magenta().bold() 28 | .to_string(); 29 | 30 | let cli = Command::new("git-acm") 31 | .author("shivam [shivam.ing]") 32 | .version("1.3.0") 33 | .about(description) 34 | .subcommand( 35 | Command::new("use") 36 | .about("choose which model to use, run git-acm list to see the available models") 37 | .arg(Arg::new("model").required(true)) 38 | ) 39 | 40 | .subcommand( 41 | Command::new("autocommit") 42 | .about("enable or disable autocommit functionality") 43 | .subcommand(Command::new("enable")) 44 | .subcommand(Command::new("disable")) 45 | ) 46 | .subcommand( 47 | Command::new("list") 48 | .about("lists all supported models") 49 | ) 50 | .get_matches(); 51 | 52 | 53 | match cli.subcommand() { 54 | Some(("run", _)) => { 55 | get_commit_msg(); 56 | } 57 | 58 | Some(("list", _)) => { 59 | let models = load_models_from_json(); 60 | println!("{}", " available models".green()); 61 | for model in models { 62 | println!(" {}", model.model_name); 63 | } 64 | } 65 | Some(("use", sub_matches)) => { 66 | let user_model_input = sub_matches.get_one::("model").unwrap().to_string(); 67 | let models = load_models_from_json(); 68 | match models.iter().find(|m| m.model_name == user_model_input)// using model_name here 69 | { 70 | Some(model) => { 71 | save_model_value(&model.model_api_name); // save the model api name to the config file 72 | get_commit_msg(); 73 | } 74 | None => { 75 | println!( 76 | "{}", 77 | "run git-acm list to see the available models".yellow(), 78 | ); 79 | std::process::exit(1); 80 | } 81 | } 82 | } 83 | 84 | 85 | Some(("autocommit", sub_matches)) => match sub_matches.subcommand() { 86 | Some(("enable", _)) => { 87 | save_autocommit_preference("enable"); 88 | } 89 | Some(("disable", _)) => { 90 | save_autocommit_preference("disable"); 91 | } 92 | _ => { 93 | println!( 94 | "{}", 95 | "invalid. available options : enable or disable".red() 96 | ); 97 | return; 98 | } 99 | }, 100 | _ => { 101 | get_commit_msg(); 102 | } 103 | } 104 | } 105 | 106 | fn get_commit_msg() { 107 | let model = load_model_from_pref(None); 108 | let models_from_file = load_models_from_json(); 109 | match models_from_file.iter().find(|m| m.model_api_name == model) { 110 | Some(model) => { 111 | println!("using model: {}", model.model_name.magenta()); 112 | match model.provider.as_str() { 113 | "openai" => { 114 | print_to_cli(&openai()); 115 | } 116 | "anthropic" => { 117 | print_to_cli(&anthropic()); 118 | } 119 | "gemini" => { 120 | print_to_cli(&gemini()); 121 | } 122 | "llama" => { 123 | print_to_cli(&llama()); 124 | } 125 | "deepseek" => { 126 | print_to_cli(&deepseek()); 127 | } 128 | _ => { 129 | println!( 130 | "{}{}", 131 | "💡 choose from ".green(), 132 | models_from_file.iter().map(|m| m.model_api_name.clone()).collect::>().join(" | ") 133 | ); 134 | std::process::exit(1); 135 | } 136 | } 137 | } 138 | None => { 139 | println!("{}", "model not supported".red()); 140 | std::process::exit(1); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/models/anthropic.rs: -------------------------------------------------------------------------------- 1 | use isahc::{prelude::*, Request}; 2 | use serde_json::{json, Value}; 3 | use std::time::Duration; 4 | use yansi::Paint; 5 | 6 | use crate::utils::checks::Check; 7 | use crate::utils::config::{get_api_key, load_model_from_pref}; 8 | use crate::utils::diff::get_diff; 9 | 10 | pub fn anthropic() -> String { 11 | //checks if env exists 12 | dotenvy::dotenv().ok(); 13 | let api_url = "https://api.anthropic.com/v1/messages"; 14 | let api_key = get_api_key("anthropic"); 15 | Check::api_key_present(&api_key); 16 | Check::api_url_present(&api_url); 17 | 18 | let prompt = include_str!("../../assets/prompt.txt"); 19 | let full_diff = get_diff(); 20 | 21 | Check::is_prompt_empty(prompt); 22 | 23 | let uri = format!("{}?key={}", api_url, api_key); 24 | 25 | // this will always load anthropic model from the config file, coz it's only called when the model_provider is anthropic. 26 | let model = load_model_from_pref(Some("anthropic")); 27 | 28 | 29 | let req_body = json!({ 30 | "model": model, 31 | "max_tokens": 60, 32 | "system": [ 33 | { 34 | "type": "text", 35 | "text": prompt, 36 | "cache_control": {"type": "ephemeral"} 37 | } 38 | ], 39 | "messages": [ 40 | {"role": "user", "content": format!("here's the git diff {}", full_diff) } 41 | ] 42 | }); 43 | 44 | let response = Request::post(uri) 45 | .header("x-api-key", api_key) 46 | .header("anthropic-version", "2023-06-01") 47 | .header("content-type", "application/json") 48 | .timeout(Duration::from_secs(10)) 49 | .body(req_body.to_string()) 50 | .unwrap() 51 | .send(); 52 | 53 | match response { 54 | Ok(mut res) => match res.text() { 55 | Ok(res) => { 56 | let v: Value = serde_json::from_str(&res).unwrap(); 57 | let commit_msg = &v["content"][0]["text"]; 58 | let final_msg = commit_msg.to_string(); 59 | let clear_msg = final_msg.trim_matches(|c| c == '"' || c == '\n'); 60 | return clear_msg.to_string(); 61 | } 62 | Err(e) => { 63 | println!("{}", e.red()); 64 | return "".to_string(); 65 | } 66 | }, 67 | Err(e) => { 68 | println!("{}", e.red()); 69 | return "".to_string(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/models/deepseek.rs: -------------------------------------------------------------------------------- 1 | use isahc::{prelude::*, Request}; 2 | use serde_json::{json, Value}; 3 | use std::time::Duration; 4 | use yansi::Paint; 5 | 6 | use crate::utils::checks::Check; 7 | use crate::utils::config::{get_api_key, load_model_from_pref}; 8 | use crate::utils::diff::get_diff; 9 | 10 | 11 | 12 | pub fn deepseek() -> String { 13 | //checks if env exists 14 | dotenvy::dotenv().ok(); 15 | let api_url = "https://api.deepseek.com/chat/completions"; 16 | let api_key = get_api_key("deepseek"); 17 | 18 | Check::api_key_present(&api_key); 19 | Check::api_url_present(&api_url); 20 | 21 | let prompt = include_str!("../../assets/prompt.txt"); 22 | let full_diff = get_diff(); 23 | 24 | Check::is_prompt_empty(prompt); 25 | 26 | let uri = format!("{}?key={}", api_url, api_key); 27 | 28 | let model = load_model_from_pref(Some("deepseek")); 29 | 30 | let req_body = json!({ 31 | "model": model, 32 | "stream_options": null, 33 | "max_tokens" : 200, 34 | "messages": [ 35 | {"role": "system", "content": prompt}, 36 | {"role": "user", "content": full_diff} 37 | ], 38 | "stream": false 39 | }); 40 | 41 | let response = Request::post(uri) 42 | .header("Content-Type", "application/json") 43 | .header("Authorization", format!("Bearer {}", api_key)) 44 | .timeout(Duration::from_secs(20)) 45 | .body(req_body.to_string()) 46 | .unwrap() 47 | .send(); 48 | 49 | match response { 50 | Ok(mut res) => match res.text() { 51 | Ok(res) => { 52 | let v: Value = serde_json::from_str(&res).unwrap(); 53 | let commit_msg = &v["choices"][0]["message"]["content"]; 54 | 55 | let final_msg = commit_msg.to_string(); 56 | let clear_msg = final_msg.trim().trim_matches(|c| c == '"' || c == '\n'); 57 | return clear_msg.to_string(); 58 | } 59 | Err(e) => { 60 | println!("{}", e.red()); 61 | return "".to_string(); 62 | } 63 | }, 64 | Err(e) => { 65 | println!("{}", e.red()); 66 | return "".to_string(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/models/gemini.rs: -------------------------------------------------------------------------------- 1 | use isahc::{prelude::*, Request}; 2 | use serde_json::{json, Value}; 3 | use std::time::Duration; 4 | use yansi::Paint; 5 | 6 | use crate::utils::checks::Check; 7 | use crate::utils::config::{get_api_key, load_model_from_pref }; 8 | use crate::utils::diff::get_diff; 9 | 10 | pub fn gemini() -> String { 11 | //checks if env exists 12 | dotenvy::dotenv().ok(); 13 | 14 | let model = load_model_from_pref(Some("gemini")); 15 | 16 | let api_url = format!("https://generativelanguage.googleapis.com/v1beta/models/{}:generateContent", model); 17 | 18 | let api_key = get_api_key("gemini"); 19 | 20 | Check::api_key_present(&api_key); 21 | Check::api_url_present(&api_url); 22 | 23 | 24 | let prompt = include_str!("../../assets/prompt.txt"); 25 | let full_diff = get_diff(); 26 | 27 | Check::is_prompt_empty(prompt); 28 | 29 | let uri = format!("{}?key={}", api_url, api_key); 30 | 31 | let req_body = json!({ 32 | "tools": [], 33 | "systemInstruction": { 34 | "parts": [ 35 | { 36 | "text": prompt 37 | } 38 | ] 39 | }, 40 | "contents": [{ 41 | "parts": [ 42 | { 43 | "text": full_diff 44 | } 45 | ], 46 | "role": "User" 47 | }] 48 | }); 49 | 50 | let response = Request::post(uri) 51 | .header("Content-Type", "application/json") 52 | .timeout(Duration::from_secs(15)) 53 | .body(req_body.to_string()) 54 | .unwrap() 55 | .send(); 56 | 57 | match response { 58 | Ok(mut res) => match res.text() { 59 | Ok(res) => { 60 | let v: Value = serde_json::from_str(&res).unwrap(); 61 | let commit_msg = &v["candidates"][0]["content"]["parts"][0]["text"]; 62 | 63 | let final_msg = commit_msg.to_string(); 64 | let clear_msg = final_msg.trim().trim_matches(|c| c == '"' || c == '\n'); 65 | return clear_msg.to_string(); 66 | } 67 | Err(e) => { 68 | println!("{}", e.red()); 69 | return "".to_string(); 70 | } 71 | }, 72 | Err(e) => { 73 | println!("{}", e.red()); 74 | return "".to_string(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/models/llama.rs: -------------------------------------------------------------------------------- 1 | use isahc::{prelude::*, Request}; 2 | use serde_json::{json, Value}; 3 | use std::time::Duration; 4 | use yansi::Paint; 5 | 6 | use crate::utils::checks::Check; 7 | use crate::utils::config::{get_api_url, load_model_from_pref}; 8 | use crate::utils::diff::get_diff; 9 | 10 | pub fn llama() -> String { 11 | //checks if env exists 12 | dotenvy::dotenv().ok(); 13 | let api_url = get_api_url("llama", ""); 14 | let model_name = load_model_from_pref(Some("llama")); 15 | 16 | Check::api_url_present(&api_url); 17 | Check::is_model_name_empty(&model_name); 18 | 19 | let prompt = include_str!("../../assets/prompt.txt"); 20 | let full_diff = get_diff(); 21 | 22 | Check::is_prompt_empty(prompt); 23 | 24 | let uri = format!("{}", api_url); 25 | 26 | let req_body = json!({ 27 | "model": model_name, 28 | "system" : prompt, 29 | "prompt": full_diff, 30 | "stream": false 31 | }); 32 | 33 | let response = Request::post(uri) 34 | .header("Content-Type", "application/json") 35 | .timeout(Duration::from_secs(10)) 36 | .body(req_body.to_string()) 37 | .unwrap() 38 | .send(); 39 | 40 | match response { 41 | Ok(mut res) => match res.text() { 42 | Ok(res) => { 43 | let v: Value = serde_json::from_str(&res).unwrap(); 44 | let commit_msg = &v["response"]; 45 | 46 | let final_msg = commit_msg.to_string(); 47 | let clear_msg = final_msg.trim().trim_matches(|c| c == '"' || c == '\n'); 48 | return clear_msg.to_string(); 49 | } 50 | Err(e) => { 51 | println!("{}", e.red()); 52 | return "".to_string(); 53 | } 54 | }, 55 | Err(e) => { 56 | println!("{}", e.red()); 57 | return "".to_string(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/models/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod anthropic; 2 | pub mod deepseek; 3 | pub mod gemini; 4 | pub mod llama; 5 | pub mod openai; 6 | -------------------------------------------------------------------------------- /src/models/openai.rs: -------------------------------------------------------------------------------- 1 | use isahc::{prelude::*, Request}; 2 | use serde_json::{json, Value}; 3 | use std::time::Duration; 4 | use yansi::Paint; 5 | 6 | use crate::utils::checks::Check; 7 | use crate::utils::config::{get_api_key, load_model_from_pref}; 8 | use crate::utils::diff::get_diff; 9 | 10 | pub fn openai() -> String { 11 | //checks if env exists 12 | dotenvy::dotenv().ok(); 13 | let api_url = "https://api.openai.com/v1/chat/completions"; 14 | let api_key = get_api_key("openai"); 15 | 16 | Check::api_key_present(&api_key); 17 | Check::api_url_present(&api_url); 18 | 19 | let prompt = include_str!("../../assets/prompt.txt"); 20 | let full_diff = get_diff(); 21 | 22 | Check::is_prompt_empty(prompt); 23 | let uri = format!("{}?key={}", api_url, api_key); 24 | let model = load_model_from_pref(Some("openai")); 25 | 26 | let req_body = json!({ 27 | "model": model, 28 | "messages": [ 29 | { 30 | "role": "developer", 31 | "content": [ 32 | { 33 | "type": "text", 34 | "text": prompt 35 | } 36 | ] 37 | }, 38 | { 39 | "role": "user", 40 | "content": [ 41 | { 42 | "type": "text", 43 | "text": format!("here's the git diff from which you have to generate a git-commit-message {}", full_diff) 44 | } 45 | ] 46 | } 47 | ] 48 | }); 49 | 50 | let response = Request::post(uri) 51 | .header("Content-Type", "application/json") 52 | .header("Authorization", format!("Bearer {}", api_key)) 53 | .timeout(Duration::from_secs(10)) 54 | .body(req_body.to_string()) 55 | .unwrap() 56 | .send(); 57 | 58 | 59 | match response { 60 | Ok(mut res) => match res.text() { 61 | Ok(res) => { 62 | let v: Value = serde_json::from_str(&res).unwrap(); 63 | let commit_msg = &v["choices"][0]["message"]["content"]; 64 | 65 | let final_msg = commit_msg.to_string(); 66 | let clear_msg = final_msg.trim_matches(|c| c == '"' || c == '\n'); 67 | return clear_msg.to_string(); 68 | } 69 | Err(e) => { 70 | println!("{}", e.red()); 71 | return "".to_string(); 72 | } 73 | }, 74 | Err(e) => { 75 | println!("{}", e.red()); 76 | return "".to_string(); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/utils/checks.rs: -------------------------------------------------------------------------------- 1 | use yansi::Paint; 2 | pub struct Check {} 3 | 4 | impl Check { 5 | pub fn api_key_present(value: &str) { 6 | if value.is_empty() { 7 | println!( 8 | "{}", 9 | "either export the key in terminal or define them in .env" 10 | ); 11 | std::process::exit(1) 12 | } 13 | } 14 | 15 | pub fn api_url_present(value: &str) { 16 | if value.is_empty() { 17 | println!( 18 | "{}", 19 | "either export the key in terminal or define them in .env" 20 | ); 21 | std::process::exit(1) 22 | } 23 | } 24 | 25 | pub fn is_prompt_empty(value: &str) { 26 | if value.is_empty() { 27 | println!("{}", "no prompt found".red()); 28 | std::process::exit(1) 29 | } 30 | } 31 | 32 | pub fn is_diff_empty(value: &str) { 33 | if value.is_empty() { 34 | println!("{}", "🤔 are the stages changed ?".red()); 35 | println!("{}", "💡 try `git add `".red()); 36 | std::process::exit(1) 37 | } 38 | } 39 | 40 | // pub fn is_response_empty(value: &str) { 41 | // if value.is_empty() { 42 | // println!("{}", " no response, might be a server error".red()); 43 | // std::process::exit(1) 44 | // } 45 | // } 46 | 47 | pub fn is_model_name_empty(value: &str) { 48 | if value.is_empty() { 49 | println!("{}", "model_name not found".red()); 50 | std::process::exit(1) 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/utils/config.rs: -------------------------------------------------------------------------------- 1 | use arboard::Clipboard; 2 | use crossterm::{ 3 | event::{self, Event, KeyCode, KeyEventKind}, 4 | terminal::{disable_raw_mode, enable_raw_mode}, 5 | }; 6 | use duct::cmd; 7 | use std::{ 8 | env, fs, 9 | io::Error, 10 | path::{Path, PathBuf}, 11 | }; 12 | 13 | use yansi::Paint; 14 | 15 | use crate::{get_commit_msg, Model}; 16 | 17 | 18 | use serde::Deserialize; 19 | #[derive(Deserialize, Debug)] 20 | struct Models { 21 | models: Vec, 22 | } 23 | 24 | 25 | 26 | fn get_config_dir() -> PathBuf { 27 | let home = env::var("HOME").unwrap_or_else(|_| ".".to_string()); 28 | return Path::new(&home).join(".config").join("git-acm"); 29 | } 30 | 31 | fn config_exists() -> Result<(), Error> { 32 | let config_dir = get_config_dir(); 33 | if !config_dir.exists() { 34 | return fs::create_dir(&config_dir); 35 | } 36 | Ok(()) 37 | } 38 | 39 | pub fn load_model_from_pref(provider: Option<&str>) -> String { 40 | let config_file = get_config_dir().join("model.txt"); 41 | 42 | if let Err(e) = config_exists() { 43 | println!( 44 | "{}", 45 | format!( 46 | "Failed to create config dir {}", 47 | e 48 | ) 49 | .red() 50 | ); 51 | 52 | 53 | match provider { 54 | Some(provider) => { 55 | match provider { 56 | "anthropic" => { 57 | return "claude-3.5-sonnet".to_string(); 58 | } 59 | "gemini" => { 60 | return "gemini-2.0-flash".to_string(); 61 | } 62 | "deepseek" => { 63 | return "deepseek-chat".to_string(); 64 | } 65 | "llama" => { 66 | return "llama-3.2-3b-instruct".to_string(); 67 | } 68 | "openai" => { 69 | return "gpt-4.1".to_string(); 70 | } 71 | _ => { 72 | return "gemini-2.0-flash".to_string(); 73 | } 74 | } 75 | } 76 | None => { 77 | return "gemini-2.0-flash".to_string(); 78 | } 79 | } 80 | } 81 | 82 | if !config_file.exists() { 83 | if let Err(e) = fs::write(&config_file, "gemini-2.0-flash") { 84 | println!( 85 | "{}", 86 | format!( 87 | "Failed to create config file, setting gemini 2.5 pro as default {}", 88 | e 89 | ) 90 | .red() 91 | ); 92 | return "gemini-2.0-flash".to_string(); 93 | } 94 | } 95 | 96 | match fs::read_to_string(config_file) { 97 | Ok(s) => s.trim().to_string(), 98 | Err(e) => { 99 | println!( 100 | "{}", 101 | format!("Error reading config, using gemini-2.0-flash as default {}", e).red() 102 | ); 103 | "gemini-2.0-flash".to_string() 104 | } 105 | } 106 | } 107 | 108 | pub fn load_auto_commit_value() -> String { 109 | let auto_commit = get_config_dir().join("autocommit.txt"); 110 | 111 | if !auto_commit.exists() { 112 | if let Err(e) = fs::write(&auto_commit, "disable") { 113 | println!("{}", format!("error with autocommit.txt file {}", e).red()); 114 | return String::from("disable"); 115 | } 116 | } 117 | 118 | match fs::read_to_string(auto_commit) { 119 | Ok(a) => return a.trim().to_string(), 120 | Err(e) => { 121 | println!( 122 | "{}", 123 | format!("Error reading autocommit, set as disable {}", e).red() 124 | ); 125 | return String::from("disable"); 126 | } 127 | } 128 | } 129 | 130 | 131 | pub fn save_model_value(value: &str) { 132 | if config_exists().is_err() { 133 | println!("{}", "config doesn't exist ".red()); 134 | return; 135 | }; 136 | let config_file = get_config_dir().join("model.txt"); 137 | 138 | match fs::write(config_file, value) { 139 | Ok(_ok) => { 140 | println!("{}{}", value, " saved as default.".green()) 141 | } 142 | Err(_e) => { 143 | println!("{}{}", value, "i couldn't save it, as a default. 😔".red()) 144 | } 145 | } 146 | } 147 | 148 | pub fn save_autocommit_preference(value: &str) { 149 | let auto_commit = get_config_dir().join("autocommit.txt"); 150 | if config_exists().is_err() { 151 | println!("{}", "config doesn't exist ".red()); 152 | return; 153 | }; 154 | 155 | match fs::write(auto_commit, value) { 156 | Ok(_ok) => { 157 | println!("{}{}d", "autocommit ".green(), value) 158 | } 159 | Err(_e) => { 160 | println!("{}{}", value, "i couldn't save it, as a default. 😔".red()) 161 | } 162 | } 163 | } 164 | 165 | pub fn get_api_key(value: &str) -> String { 166 | let key = format!("{}_API_KEY", value.to_uppercase()); 167 | 168 | match env::var(key) { 169 | Ok(k) => { 170 | return String::from(k); 171 | } 172 | Err(_e) => { 173 | println!("{}", "couldn't get the api key".red()); 174 | return String::from("disable"); 175 | } 176 | } 177 | } 178 | 179 | pub fn get_api_url(value: &str, default: &str) -> String { 180 | let key = format!("{}_API_URL", value.to_uppercase()); 181 | match env::var(key) { 182 | Ok(k) => { 183 | return String::from(k); 184 | } 185 | Err(_e) => { 186 | println!("{}", "couldn't get the api url ".red()); 187 | return String::from(default); 188 | } 189 | } 190 | } 191 | 192 | 193 | pub fn copy_to_clipboard(text: &str) -> Result<(), Box> { 194 | match Clipboard::new()?.set_text(text) { 195 | Ok(_t) => { 196 | println!("{}", "copied to clipboard 👍".magenta()); 197 | } 198 | Err(_e) => { 199 | println!("{}", "( couldn't copy to clipboard 🥲 )".yellow()); 200 | } 201 | } 202 | Ok(()) 203 | } 204 | 205 | pub fn run_git_commit(value: &str) { 206 | let preference = load_auto_commit_value(); 207 | match preference.as_str() { 208 | "enable" => { 209 | let err_git_commit_message = "couldn't commit".red().to_string(); 210 | match cmd!("git", "commit", "-m", value.to_string()).read() { 211 | Ok(_result) => { 212 | println!("{}.", "committed".magenta()); 213 | println!( 214 | "{}", 215 | " run `git push` to push the changes to the repo".magenta() 216 | ); 217 | return; 218 | } 219 | Err(e) => { 220 | println!("{} error : {}", err_git_commit_message, e); 221 | return; 222 | } 223 | } 224 | } 225 | "disable" => { 226 | // println!("{}", "autocommit is disabled".yellow()); 227 | // println!("{}", "run `git-acm autocommit enable`".magenta()); 228 | return; 229 | } 230 | _ => { 231 | println!("{}", "invalid autocommit value.".red()); 232 | println!("{}", "cd ~/.config/git-acm. open the autocommit.txt file. and either write `enable` or `disable`."); 233 | return; 234 | } 235 | } 236 | } 237 | 238 | pub fn print_to_cli(value: &str) { 239 | if value.is_empty() { 240 | println!("{}", "got no response".red()); 241 | std::process::exit(1) 242 | } else { 243 | println!("{}", value.blue()); 244 | match msg_handler(value, false) { 245 | Ok(_v) => {} 246 | _ => { 247 | println!("{}", "invalid input".red()); 248 | std::process::exit(1); 249 | } 250 | } 251 | } 252 | 253 | return; 254 | } 255 | 256 | // this fn takes a str as input and watches for the return or r key based on which wither it calls the commit getter again or accepts the result. 257 | pub fn msg_handler(value: &str, in_handler: bool) -> Result<(), Error> { 258 | println!( 259 | "{}", 260 | "[enter]: accept | [r]: get a new commit message | [q]: exit".magenta() 261 | ); 262 | enable_raw_mode()?; 263 | loop { 264 | if let Event::Key(key) = event::read()? { 265 | if key.kind == KeyEventKind::Press { 266 | match key.code { 267 | KeyCode::Enter => { 268 | disable_raw_mode()?; 269 | println!("{}", value); 270 | // the follwing fns are here. so that these only run once. 271 | copy_to_clipboard(value).unwrap_or_else(|_x| { 272 | println!("{}", "error copying the result to clipboard".yellow()) 273 | }); 274 | run_git_commit(value); 275 | return Ok(()); 276 | } 277 | KeyCode::Char('r') => { 278 | disable_raw_mode()?; 279 | println!("{}", "getting a new message...".green()); 280 | if !in_handler { 281 | // to prevent the infinite loop 282 | get_commit_msg(); 283 | } 284 | return Ok(()); 285 | } 286 | KeyCode::Char('q') => { 287 | disable_raw_mode()?; 288 | println!("{}", "exiting...".green()); 289 | std::process::exit(0); 290 | } 291 | _ => { 292 | disable_raw_mode()?; 293 | println!("{}", "invalid input".red()); 294 | std::process::exit(1); 295 | } 296 | } 297 | } 298 | } 299 | disable_raw_mode()?; 300 | } 301 | } 302 | 303 | 304 | pub fn load_models_from_json() -> Vec { 305 | let models_path = include_str!("../../assets/models.json"); 306 | match serde_json::from_str::(&models_path) { 307 | Ok(model_obj) => model_obj.models, 308 | Err(_e) => { 309 | println!("{}", "couldn't load models".red()); 310 | return vec![]; 311 | } 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /src/utils/diff.rs: -------------------------------------------------------------------------------- 1 | use duct::cmd; 2 | use yansi::Paint; 3 | 4 | use crate::utils::checks::Check; 5 | 6 | pub fn get_diff() -> String { 7 | match cmd!("git", "diff", "--staged", "--color=always").read() { 8 | Ok(result) => { 9 | Check::is_diff_empty(&result); 10 | return result; 11 | } 12 | Err(_) => return "".to_string(), 13 | } 14 | } 15 | 16 | pub fn is_git_initialized() { 17 | let no_git_err_message = "🚨 not a git repo ".red().to_string(); 18 | 19 | match cmd!("git", "rev-parse", "--is-inside-work-tree").read() { 20 | Ok(result) => { 21 | if result.trim() != "true" { 22 | println!("{}", no_git_err_message); 23 | println!("{}", "💡 try `git init` to initialise a git repo".red()); 24 | std::process::exit(1); 25 | } 26 | } 27 | Err(_) => { 28 | println!("{}", no_git_err_message); 29 | println!("{}", "💡 try `git init` to initialise a git repo".red()); 30 | std::process::exit(1); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod checks; 2 | pub mod config; 3 | pub mod diff; -------------------------------------------------------------------------------- /temp.md: -------------------------------------------------------------------------------- 1 | > this is for me to track the progress of the project. [ no real relation to the project. ] 2 | 3 | ## todo 4 | 5 | - [x] get diff. 6 | - [x] get commit msg from api. 7 | - [x] make it a cli tool. 8 | - [x] publish to cargo as a pacakge. 9 | - [x] better error handling. 10 | - [x] supports openai, anthropic as well. 11 | - [x] setup cli for diff apis 12 | - [x] github release. 13 | - [x] binary release. 14 | - [x] llama support. 15 | - [x] let user choose the msg or rerun to get another message > and then accept it. 16 | - [x] refactor + simple model selector. 17 | 18 | most of the features had been added, it will get regular(model) updates as usual. i'll be focusing on other projects in the meantime. 19 | 20 | users should have at least friction as possible. 21 | --------------------------------------------------------------------------------