mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-07-23 08:10:57 -07:00
Compare commits
2237 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 96e5fc1663 | |||
| 3815de798f | |||
| 50947c57ce | |||
| ac3c643035 | |||
| 29e8f2abf4 | |||
| bf278ef2b0 | |||
| 1f9da6723f | |||
| 3ff5cfaaf6 | |||
| 70b650122f | |||
| 16d3883642 | |||
| 5c23f7f6e0 | |||
| d47d4855db | |||
| 6510347d5b | |||
| 4dd940f8ce | |||
| 87f7f0beb7 | |||
| 8e9ce3f4c3 | |||
| 812794a471 | |||
| 3c6539a32c | |||
| e4204d5939 | |||
| baccda969d | |||
| 9e95b8b3c5 | |||
| 182c858e67 | |||
| c0b76af442 | |||
| 4efdbe9089 | |||
| 15f6c8b8da | |||
| ee2e947435 | |||
| 6676546a4b | |||
| d143a83d5b | |||
| e69e23e4a0 | |||
| 81cd2561dc | |||
| b0ceb74462 | |||
| ee5eb70070 | |||
| dde844dbe1 | |||
| 05bc0399f3 | |||
| 3409de774c | |||
| 175ffc452b | |||
| 544df749af | |||
| 56c8d7e985 | |||
| 2ff7738b5d | |||
| 1ad26adb2b | |||
| af5aec69da | |||
| dae67983a8 | |||
| 70856d5a6e | |||
| cec45a1ebc | |||
| 767d80e768 | |||
| 3e5e608a22 | |||
| 0bc2d3ab16 | |||
| 31960c3388 | |||
| 0cc4f09595 | |||
| 70336e73b1 | |||
| 7cfbb6fb71 | |||
| a105768de8 | |||
| 347f3fe7e4 | |||
| 25803e05fd | |||
| 774ae220be | |||
| 813e0c18ac | |||
| 3f6cec22e6 | |||
| 3966f3c053 | |||
| 2e3cbd6363 | |||
| 8b1dc15182 | |||
| fa9aee2bf0 | |||
| 6628cbb39d | |||
| aa9163da60 | |||
| ec0f23ae03 | |||
| ac04c388e0 | |||
| 621ddbe744 | |||
| c537fd5aec | |||
| a91bc60e18 | |||
| faa1ec3044 | |||
| d96bd05d36 | |||
| 84666e1bbc | |||
| a7d851146a | |||
| acb7f577de | |||
| d2d345f41a | |||
| dfd7721e69 | |||
| 09218572d0 | |||
| 5d98ed5820 | |||
| 727f9b67b1 | |||
| 547f5d45f5 | |||
| 58d637f919 | |||
| b746524a1b | |||
| c5baf39dbd | |||
| b48970da15 | |||
| 9a8e5d3940 | |||
| 089aec8b8d | |||
| b7555ab1e1 | |||
| c04602f209 | |||
| a01d7e9a05 | |||
| 49b2e76ee1 | |||
| aed348a99c | |||
| 7cf4c05c66 | |||
| cdf157e52a | |||
| 723f269df6 | |||
| 239aa0909c | |||
| 6cfd29ef9b | |||
| f97b04cc9a | |||
| 788a40c445 | |||
| ce03156c9f | |||
| fe428936d5 | |||
| d24f10b087 | |||
| d54702185b | |||
| 27b7fc04de | |||
| be03e0619f | |||
| 2bb7aaecd0 | |||
| 0f855fc0c4 | |||
| c7e309efc9 | |||
| 429932c663 | |||
| d08b1efc72 | |||
| c3b52b8206 | |||
| 5fd557347e | |||
| cbfb2a4e26 | |||
| fb1b1b451d | |||
| 99fa700231 | |||
| f1c0a695f8 | |||
| 6351352e54 | |||
| 2ac39b6acc | |||
| d8b24e6983 | |||
| d25c469f77 | |||
| 537e56ffae | |||
| 2cba2ab37a | |||
| 8064973899 | |||
| ddc5458451 | |||
| a468407098 | |||
| 264c7aceaa | |||
| 3408542a66 | |||
| c276d0c7b6 | |||
| a00eb3b8e6 | |||
| 372f41eab8 | |||
| 09b623fbd7 | |||
| ba3e327ba1 | |||
| 5d235952ba | |||
| 082f41f54d | |||
| 880af43b02 | |||
| 966eef14ee | |||
| b79e5ce56d | |||
| 1a8d77329e | |||
| ad9c49a604 | |||
| 70b427c7dd | |||
| a804f99fe0 | |||
| c43500c50b | |||
| 42a7d89999 | |||
| 04f65f3d55 | |||
| 04c52513e7 | |||
| c62340675a | |||
| ef65498031 | |||
| 261788cf91 | |||
| 012392ad0a | |||
| 037061e2e0 | |||
| 221ea360b9 | |||
| 8910b2720f | |||
| 87f5dd15d6 | |||
| 81c8893e05 | |||
| 178388d931 | |||
| e7f97dfa44 | |||
| f961e0d6b1 | |||
| 14415316c0 | |||
| 1cf05b0375 | |||
| 3099df1b7c | |||
| 758d419e33 | |||
| 78de533c48 | |||
| 8f6a711a3a | |||
| 65ad78b9c0 | |||
| 858918fe31 | |||
| 9255e69abb | |||
| e32111e609 | |||
| 2c1d6f8029 | |||
| 8a8826654c | |||
| 5f6b7c0158 | |||
| 65e0043fbf | |||
| 22763c98b0 | |||
| 05be2b51fc | |||
| f1aa38b258 | |||
| 4e11ddbf4a | |||
| fe65d562de | |||
| ce84b3cb5f | |||
| 55c628e967 | |||
| 5e2f5df62c | |||
| 4fe86dbd4f | |||
| 216d7272bb | |||
| b7004ad5ed | |||
| f1aa1683dd | |||
| b56361559d | |||
| c62601e90c | |||
| fb32db5cd6 | |||
| 8aca3068cf | |||
| 14aabbbe8b | |||
| 366f1df120 | |||
| e5ff2023ad | |||
| bf9ca33c18 | |||
| bbf6800778 | |||
| b38e0984b9 | |||
| ddd28f6431 | |||
| 6ed1878c5f | |||
| 39d36108d7 | |||
| 80f0cbd798 | |||
| 7d165e77f0 | |||
| c57a28f48a | |||
| a83ca11035 | |||
| 15ef1cd797 | |||
| 5a74f7a2eb | |||
| bb7bb11736 | |||
| d1ca8c0c80 | |||
| 8979fc5f6a | |||
| 6eec9f3350 | |||
| 884acda2dc | |||
| 7f7424dd1e | |||
| 78130d4bb7 | |||
| bcd547baf6 | |||
| 5559d40f31 | |||
| a129dbcdd4 | |||
| 9fc7b56793 | |||
| 02da5ebbc1 | |||
| 401bef1d2b | |||
| 9df604b01b | |||
| 4e1b3b5f57 | |||
| f87468c644 | |||
| e7e4c68c5c | |||
| c7237f0c79 | |||
| f76e24c00f | |||
| f460ab841d | |||
| c2f62b2a2b | |||
| e844a57bfc | |||
| 9c285eaf15 | |||
| c0e7da42b2 | |||
| b16c9a5ebd | |||
| 3bed7bbe8d | |||
| e1b9002b35 | |||
| 60be42f095 | |||
| d0c6a56c65 | |||
| d5dfae6bbf | |||
| b61a123da8 | |||
| bed3eae0e1 | |||
| d82f66973f | |||
| 00f73b73bc | |||
| b62c6566be | |||
| ca374dcf47 | |||
| 696198be87 | |||
| 5b4884692b | |||
| 55ec0f043c | |||
| 44bcba323f | |||
| c00de442e5 | |||
| 8275871963 | |||
| e8e681c670 | |||
| 991b2c6002 | |||
| 207ac6f2dc | |||
| db00c5abf3 | |||
| b0cfbc6cd8 | |||
| 0b3130cec7 | |||
| d243dfce14 | |||
| 2e91c03e08 | |||
| 2d38623472 | |||
| 375ebca2da | |||
| 868f43927e | |||
| 27a1bae03b | |||
| ddcfe5b1f2 | |||
| f603f4a12b | |||
| 2ca183ffc9 | |||
| 099aa9621c | |||
| fe75de3efb | |||
| fad9f46273 | |||
| a1148ea1f1 | |||
| 0e85e021dc | |||
| c370d2397b | |||
| 08e8eeab84 | |||
| 941691ce72 | |||
| b8008695db | |||
| 6c1773170e | |||
| 00966062b8 | |||
| 4138667bae | |||
| bfa791e13d | |||
| e9a9474810 | |||
| 02adfe2bca | |||
| 2a08456ed0 | |||
| 2dac98dc8d | |||
| 77849cadac | |||
| 84ce53aafa | |||
| b19b026f30 | |||
| eb9223b6a4 | |||
| 65d26e73a2 | |||
| 0080589939 | |||
| 34a47a51f4 | |||
| f5dd1068f6 | |||
| c202cf3145 | |||
| 5baad108d9 | |||
| 63e9d5d15f | |||
| 3776c4d613 | |||
| 2af5a3a01e | |||
| 0d034b8c18 | |||
| 49d55d972e | |||
| 7a02d7261a | |||
| 9c11ff2d58 | |||
| b3ecac7086 | |||
| 6d3fff2ea4 | |||
| be2ebd1772 | |||
| cb4e1e684d | |||
| b7a3243334 | |||
| 8257ec447a | |||
| 9590a092ae | |||
| 49533cd106 | |||
| a2174751de | |||
| 8b762111a8 | |||
| c03d96b46c | |||
| ea1f19aa52 | |||
| 2eb1c92347 | |||
| ef02cec2cd | |||
| f9fc9335f5 | |||
| 9813531f81 | |||
| 55571de066 | |||
| 740f0e4c3d | |||
| b37e67451a | |||
| 262138cad5 | |||
| 5920750c24 | |||
| f5b1245f51 | |||
| f2ca0bb38d | |||
| 4e9bafdacd | |||
| 41bbe6ca0a | |||
| eb5492f9b5 | |||
| 37f128a109 | |||
| 79753ec5ec | |||
| e151b4890b | |||
| e6b43cb846 | |||
| 2ae5e1ae20 | |||
| 67d9b76e81 | |||
| 4a3c7ae8b7 | |||
| bd2744031f | |||
| 92a5f725a1 | |||
| 4494f9e062 | |||
| ece001f264 | |||
| d3cfbdb3b7 | |||
| 7a132512cf | |||
| 6dae3a5402 | |||
| 0a3ecf3a75 | |||
| 9081743a7f | |||
| 89d4556c45 | |||
| 5d0570b113 | |||
| eb94284256 | |||
| cc2798018b | |||
| c9f9a7f67a | |||
| fd65416a2f | |||
| bce1caefd0 | |||
| 80057c5208 | |||
| 14219bb57d | |||
| ef957a368d | |||
| a3e5b564f7 | |||
| 1b98c1f806 | |||
| 9e41b2cd89 | |||
| 3fb1937247 | |||
| 07056c8f16 | |||
| 08dca3e1d6 | |||
| bcc0f27594 | |||
| 262e8384d4 | |||
| e73288f25f | |||
| aebc107d2c | |||
| 469cbca67f | |||
| cb7fca01b2 | |||
| 81ac5be30b | |||
| 81ccd80c6d | |||
| 01906a9205 | |||
| da66c7c0d1 | |||
| fe70052baf | |||
| 8cbe851339 | |||
| d45a45d565 | |||
| 69f562b38f | |||
| cb73fbf384 | |||
| 375c104b32 | |||
| 97a4e62dfa | |||
| 29a6aecffc | |||
| 92012365ca | |||
| 802bcf4dee | |||
| 4a48d7cf93 | |||
| 31522045cd | |||
| 11951592aa | |||
| bc8ffa6631 | |||
| 86bd7dbd4f | |||
| eee95c509d | |||
| a1f2aacd1e | |||
| 979bbee485 | |||
| 7450c926d1 | |||
| be6723ebcc | |||
| af606aed9b | |||
| a37844e5a1 | |||
| 6f1a5bf81d | |||
| 9178b31629 | |||
| 19dc40825e | |||
| bc9b3052ee | |||
| 3b0649d408 | |||
| 7409ce5df6 | |||
| e3796d137a | |||
| ee68a10e9c | |||
| 28805a4b2d | |||
| fd72a8c40f | |||
| 63f7e30790 | |||
| e844d4f45f | |||
| 7a8d6f6095 | |||
| 95d79b7cbe | |||
| 601f0606da | |||
| ad6d3fd902 | |||
| 1f1cf756c8 | |||
| ec5836c4d6 | |||
| f062f56b43 | |||
| 61d92c4a21 | |||
| 1495294cc0 | |||
| d86b1f7b7e | |||
| 099fea2434 | |||
| 1d70aa5c1b | |||
| 6fb3b09003 | |||
| 30354892b3 | |||
| 8ec176e005 | |||
| 289769f544 | |||
| 4ffc349c18 | |||
| 83c6342e6e | |||
| fe975da91e | |||
| 00a739e84c | |||
| 2498114df6 | |||
| 8efae719ee | |||
| 9ca7300c90 | |||
| dc09b4988d | |||
| bce57ca1af | |||
| 6860556afe | |||
| 258643dec4 | |||
| 5d04a01b06 | |||
| 5b9ea35b63 | |||
| 4a6e3eb646 | |||
| e4c80e6382 | |||
| ee2c8eef19 | |||
| 1cae5ab158 | |||
| ee58e1e3c1 | |||
| e3b8490edf | |||
| 2566057e44 | |||
| a342c954e9 | |||
| d29383a132 | |||
| a3af4a8cae | |||
| 821355c429 | |||
| 3afc8f25e1 | |||
| d79478689f | |||
| 650980af37 | |||
| bd156e6832 | |||
| b987e1780d | |||
| 0012d95848 | |||
| fedc0c5d60 | |||
| 99e523a15f | |||
| a0b6602d09 | |||
| b39cefe14e | |||
| 94f4e5cc15 | |||
| d866e7e6e7 | |||
| ed02b94570 | |||
| aba8c5f662 | |||
| d1cde575d9 | |||
| 71f46f1160 | |||
| d63c34b6e1 | |||
| 7a6dfa3704 | |||
| 69f8273481 | |||
| 1fc59484b1 | |||
| 53027af94c | |||
| 69c0585ab2 | |||
| 3e954930f1 | |||
| 2cf3a14439 | |||
| 0f918f0cc8 | |||
| 75dbf9022c | |||
| 675ca07c8b | |||
| 40f505e257 | |||
| 5407878138 | |||
| 14e2e09d10 | |||
| 0365f13caa | |||
| 3183e4137a | |||
| 4aa295994d | |||
| e1bd1d239f | |||
| b84585d0c8 | |||
| 0e7944df4f | |||
| d8837ec95e | |||
| dc37b190fa | |||
| 19b1a74c99 | |||
| 1d045792ce | |||
| a8b4c38c89 | |||
| ad8796b02d | |||
| e7bfd2bf83 | |||
| 1b274b081d | |||
| 5b254c379c | |||
| ed26ea49e9 | |||
| 01e33465bd | |||
| 18cce6a9ab | |||
| 18d7d1a92c | |||
| 0dd0b83612 | |||
| 4e4a55be35 | |||
| f57fd642df | |||
| 5e96373e6b | |||
| 09beb648b8 | |||
| c159c85c89 | |||
| 8cae90f404 | |||
| c5d0fc2c3e | |||
| e860f517c0 | |||
| b0be1f1689 | |||
| 85dd6ef773 | |||
| ae672881d1 | |||
| 9e7c10ad88 | |||
| 381669dce0 | |||
| 707b3e85d5 | |||
| 7d36cc004f | |||
| cb4f0c6fa4 | |||
| b0f38104d7 | |||
| 7469ea0fca | |||
| 00fdb30211 | |||
| 0fe8492569 | |||
| 76387d22ae | |||
| a362b7b382 | |||
| 71308caf05 | |||
| 6396ab1ccb | |||
| 12531a06f8 | |||
| d1cd69a20d | |||
| 62346875e4 | |||
| 13e013230b | |||
| bb6a336ca9 | |||
| f14d0c6a17 | |||
| b611f9a519 | |||
| d3bca5d97a | |||
| 94f4e027f8 | |||
| 95b7d69d5b | |||
| f605628624 | |||
| 2238802e97 | |||
| 32cfce16bb | |||
| 137080da45 | |||
| 695785c69d | |||
| d43d772e65 | |||
| 59e3624ada | |||
| fdda3a2399 | |||
| 2de39311cf | |||
| fc926cd0b0 | |||
| 567761fbc0 | |||
| f2591aada6 | |||
| 74468928e8 | |||
| d561b995c0 | |||
| b44e432f55 | |||
| bcc6ee596a | |||
| bc258eba4c | |||
| 0e30055ae4 | |||
| ac7687c1dd | |||
| f9da18e0cc | |||
| f619cd8750 | |||
| 42eedc9184 | |||
| eb17d94e91 | |||
| 9f1623688d | |||
| 7f066fd3a7 | |||
| 6d36219e55 | |||
| 5cedd28733 | |||
| ba3e1ed1c7 | |||
| 7c2cdb225a | |||
| a91f4e692a | |||
| 9bb175a506 | |||
| 0b169e9867 | |||
| 553ae3ad69 | |||
| b2265cfde4 | |||
| bee1267e2a | |||
| 30065c51fb | |||
| 065e69a12b | |||
| 519a0e617a | |||
| 0465de303a | |||
| beaa134f0e | |||
| 47f4a3e50e | |||
| 3787c71d15 | |||
| 9e09db1ddb | |||
| 25ae1a1b54 | |||
| 65accca296 | |||
| 72f0733d98 | |||
| 4d4e16cc8c | |||
| 370b165769 | |||
| 899e8a9edc | |||
| 4dca5c27c6 | |||
| 06c7dc561e | |||
| f54eaa1713 | |||
| 6807a2fa28 | |||
| 9aeeb69ab0 | |||
| 0a77999d73 | |||
| 9035ca32bc | |||
| ef3146eed6 | |||
| ffbecd4eb4 | |||
| 2c09785748 | |||
| 130b596c80 | |||
| adc8e11bb1 | |||
| 18efe82ddc | |||
| 7c445526a4 | |||
| 5e41b7d29e | |||
| fe8de892f7 | |||
| 2a49965d37 | |||
| 830e212758 | |||
| d165b6d4e7 | |||
| ff6547857e | |||
| b51323b40c | |||
| 3103697ea7 | |||
| 6f6445994e | |||
| 5f569fa103 | |||
| c9340a9c6f | |||
| 0774f60e08 | |||
| 771ece03c9 | |||
| 82687c6dc4 | |||
| b6cf189ab2 | |||
| 9dc0994878 | |||
| 36d618f72a | |||
| 246a6d10c3 | |||
| dacc178d4e | |||
| 894bd66dc6 | |||
| 50e4f9380b | |||
| f03f2e8907 | |||
| 7904f973a0 | |||
| a63277c1d0 | |||
| 8b2b71c8ef | |||
| 6be42be575 | |||
| e5145ab60d | |||
| 5c16334b8c | |||
| 1e628fbd1d | |||
| db028bc19a | |||
| 362384112e | |||
| 0dc69bd364 | |||
| 56fff518cc | |||
| 6b021aa27b | |||
| 312a72acb8 | |||
| 88d3df912f | |||
| eccc200f4f | |||
| 9fcdc0cdc1 | |||
| f4e73191d1 | |||
| 67b00252d3 | |||
| a79051d9f8 | |||
| 5cf06503c8 | |||
| 68649c8dec | |||
| ad0bece6d6 | |||
| 8e8e7b33ed | |||
| d75dc88de6 | |||
| 57b57cc997 | |||
| 3909ad67db | |||
| 7708009103 | |||
| 00f60ef532 | |||
| 49c26b4801 | |||
| b5fe372b5b | |||
| 7fbf470373 | |||
| 46629726f4 | |||
| 9d34ae52d6 | |||
| 13bc5f620c | |||
| 018dc0d5cf | |||
| c2d0783965 | |||
| b07953fb38 | |||
| 2271bbb339 | |||
| d745d86af1 | |||
| 3e1a377d78 | |||
| 50f89e8a41 | |||
| b8319bee76 | |||
| 4827333c48 | |||
| 93c62a2bdc | |||
| 39e91ad633 | |||
| 5fe328c56a | |||
| cb772a5b7f | |||
| dcd949bdd0 | |||
| c0b8c4ab9e | |||
| 4d197c992d | |||
| fd36d65723 | |||
| 05e73c4193 | |||
| a76c2986c2 | |||
| 80e1fa198f | |||
| 84e882770b | |||
| 0242a3dc56 | |||
| 3c2482a084 | |||
| 1832f7b90a | |||
| 77aef861fe | |||
| 0c134079cc | |||
| 12a5490bcf | |||
| 93da9817b6 | |||
| 6fae28197e | |||
| 00b5b2045f | |||
| daccf4d6d1 | |||
| da1664c7a0 | |||
| 5c649d8db1 | |||
| 2c0cc7b9a5 | |||
| 25c0802b52 | |||
| df379b523b | |||
| 68f5f6d3b0 | |||
| 37c7286295 | |||
| 7b7d2b0297 | |||
| 3066288c06 | |||
| 1ec8f40096 | |||
| dabb9ad8f6 | |||
| b5cac836c5 | |||
| 4fc3ebb930 | |||
| 488d5fc439 | |||
| 0b7d26c9e3 | |||
| 140fba7f53 | |||
| a270f7caa5 | |||
| 3c832ddbeb | |||
| 1f9f3dd1c2 | |||
| 798900a6c8 | |||
| 2c6781d134 | |||
| 07bd89399d | |||
| 1ec172e34b | |||
| 678c58634b | |||
| a1f5d39029 | |||
| beacc4f6fd | |||
| a060e6149a | |||
| 35feea8868 | |||
| 11e48e2dd1 | |||
| 5f1c6447a9 | |||
| 57601adc90 | |||
| 50985d38c4 | |||
| 62dd9b5b3c | |||
| 2ac7900d95 | |||
| 016a94ffaf | |||
| 5d68d8cda5 | |||
| e2ddaedab4 | |||
| addb57c31f | |||
| 233fe90f17 | |||
| 902e5d6dae | |||
| ba8c64459b | |||
| 1320ebceb9 | |||
| 6d7423263b | |||
| fe06f9a1ea | |||
| e65208b244 | |||
| 7962801a14 | |||
| 87a0db20d2 | |||
| d956c5b221 | |||
| 048c30513e | |||
| 3b9f580fa4 | |||
| ff9c77925e | |||
| 56f9ab025a | |||
| 0a173cac46 | |||
| 982a093791 | |||
| 5debf86854 | |||
| 75e4f492ab | |||
| 27d21f9921 | |||
| b24544c80e | |||
| 61040d0eb8 | |||
| 3cca8ec0f0 | |||
| 2219bac16d | |||
| 1c9a57c3c2 | |||
| a1233e7e5c | |||
| 1033550f78 | |||
| addecf2c74 | |||
| c266b529ae | |||
| dce450b1e8 | |||
| a91665db40 | |||
| f79124f96e | |||
| eb2af84bb9 | |||
| f190b87223 | |||
| e894871afc | |||
| 45d554ae2f | |||
| acbef4cd31 | |||
| 80069b4a78 | |||
| d0cae4547e | |||
| 7399c623d8 | |||
| 6b14dc8240 | |||
| 4d77934a83 | |||
| 9e3d36c19b | |||
| c43b04b44c | |||
| 8605d0d024 | |||
| c21c297133 | |||
| 0605e6e3e9 | |||
| b703c87a64 | |||
| a784c263be | |||
| 169d906fe3 | |||
| 525539fc13 | |||
| 53e0c212cc | |||
| 7990073543 | |||
| 367e7bf401 | |||
| 3a4012f76a | |||
| c9f0a48bdc | |||
| 97aac696fb | |||
| 93ae7772fd | |||
| 9866eb0551 | |||
| 55c2783e6a | |||
| 2455f939a3 | |||
| 995ae42f53 | |||
| e1fd5be429 | |||
| 3b626e7c61 | |||
| aceb06a587 | |||
| 211d2c5fdd | |||
| c9061a1cfe | |||
| b288f124b2 | |||
| 645e2ec041 | |||
| 67d69084e9 | |||
| ed0b0fae49 | |||
| f0f705d3ca | |||
| f42b4c80ac | |||
| b99e841021 | |||
| a16d5983cf | |||
| e5745f16cb | |||
| 12b0fe1cc2 | |||
| 5b8a23979f | |||
| b71fe94e0a | |||
| e92f60b4fc | |||
| 15f26175b8 | |||
| 85b17166a5 | |||
| 88df6210eb | |||
| 943481ccc0 | |||
| 79076d1d52 | |||
| 166e04a8dd | |||
| 1182168bd9 | |||
| e34f0b4a98 | |||
| 4920ad2694 | |||
| 52fadba9f2 | |||
| ec7413456e | |||
| 451e0b49cb | |||
| 155d9aafe2 | |||
| 05c0a8eac3 | |||
| 0bebc664c1 | |||
| 1b6b6d40d5 | |||
| a90bcf749d | |||
| e2901f3f7e | |||
| 4b4bdd10b6 | |||
| 0a6f2e089f | |||
| d8a8b434f6 | |||
| 49769152d6 | |||
| 4cfbe4c716 | |||
| a4eb04b7d4 | |||
| d079b7a216 | |||
| d87a3acdef | |||
| 08c32f725e | |||
| 203f5209ba | |||
| 9d9e3d1555 | |||
| 20580d754d | |||
| 41e01c2321 | |||
| 6900253cb8 | |||
| 86dbf2013e | |||
| a76946189a | |||
| e03042657b | |||
| 1998a713e2 | |||
| ee8d425603 | |||
| 272570cc18 | |||
| 1681ae1842 | |||
| 608da23393 | |||
| f2d3b76389 | |||
| d8d4d87e29 | |||
| 93224e1813 | |||
| 9722ec9b6a | |||
| 063f0d0dcd | |||
| 42fd647373 | |||
| 59da61602f | |||
| 5241174827 | |||
| 013a4e02ff | |||
| be37c26c88 | |||
| fcd860e1b0 | |||
| ce35d84113 | |||
| cfdc4cfca8 | |||
| a15978593a | |||
| 4bb817de22 | |||
| c6cf3a4234 | |||
| 420a419f5e | |||
| 8dde66c0dd | |||
| f367b959cd | |||
| 655ab21d8b | |||
| 1e8f87fbdf | |||
| 8a627d6c9a | |||
| b0d2ec55cc | |||
| e77d7b2e1e | |||
| 48fdb9872f | |||
| c8670f8696 | |||
| 5ba6e243b5 | |||
| 9e13a43225 | |||
| 6740886e22 | |||
| f7f38e2b9e | |||
| 2b6bfe4097 | |||
| f909c9ef90 | |||
| fa3981990c | |||
| d545a3b614 | |||
| a8631a109e | |||
| b0c9db7b33 | |||
| 448fd3ca66 | |||
| 53f54436c9 | |||
| 409f9c825b | |||
| 222b739501 | |||
| d0bbc7fa59 | |||
| 4848f42486 | |||
| 467e869326 | |||
| 4f324b548e | |||
| a81500a929 | |||
| 5bdfe1a1fa | |||
| ae198029bc | |||
| 4b2e9f7954 | |||
| 42c26d1e1b | |||
| e58fca68ce | |||
| b3527dc9e4 | |||
| a2dab146b9 | |||
| fb7640886b | |||
| 5ed275ce39 | |||
| 6021e4c3ba | |||
| 7e6817da5b | |||
| b14cf1dc30 | |||
| 94d5ae541e | |||
| 41369f67eb | |||
| c8c7b57a79 | |||
| b3eecc3a50 | |||
| 16b35910e2 | |||
| 1212161d1d | |||
| 4db00b8f2a | |||
| 09a7301d80 | |||
| a3234fb534 | |||
| 764016bca7 | |||
| dfb7dc7069 | |||
| 3b55581aaf | |||
| f6c2d61906 | |||
| c04af6c3e9 | |||
| a1cbe85da3 | |||
| c8d7c09ca4 | |||
| bb6c574144 | |||
| 66e7b479ae | |||
| 8030404b08 | |||
| 933bc5774f | |||
| 4afd3741df | |||
| 428e602882 | |||
| 04f65d7b4e | |||
| eda47f587c | |||
| 8dbaa2bcea | |||
| 778de55fd8 | |||
| c7c409c68f | |||
| d66ec38f82 | |||
| 63c918fe7d | |||
| b2e866585d | |||
| b518125c46 | |||
| e8be252b75 | |||
| 92e31e3c4a | |||
| e931ebe581 | |||
| 91fcca3b1c | |||
| aa52462550 | |||
| 0f7a136612 | |||
| 8faa23cea6 | |||
| a6dca02344 | |||
| 304caa4e43 | |||
| 7bbfaabffa | |||
| 6adae9f775 | |||
| b81fe68325 | |||
| 2fc61685a3 | |||
| c572b9e9ac | |||
| 8d3e93cdb0 | |||
| 548641c952 | |||
| 6ef2a92233 | |||
| e9c9dd1d67 | |||
| ca6786a28b | |||
| 2e8c6cfdbb | |||
| 95d9a33996 | |||
| b8cc414d5b | |||
| d7bff8610f | |||
| e049d5e4e8 | |||
| 8437ce940a | |||
| 7d92242011 | |||
| d65eab01d2 | |||
| 2306e60be4 | |||
| 3b678a4da0 | |||
| 64cde8d439 | |||
| 0167392f22 | |||
| 15891721ad | |||
| 8a2e0fac0d | |||
| 8656ce8a27 | |||
| ed7bcf9968 | |||
| 465ec9759d | |||
| 950244f6b0 | |||
| 64c75cb767 | |||
| 7b7f2fc69e | |||
| d315f4d3da | |||
| 9703fe73cf | |||
| 93b57b82c1 | |||
| 0e955da171 | |||
| 39b3f20a22 | |||
| b9762a3ee1 | |||
| 33e3ed0f6c | |||
| 446058cb1c | |||
| d130d99ff0 | |||
| 72dae7e0ee | |||
| 6f7d798189 | |||
| 3090008b1c | |||
| 461c277bf2 | |||
| b54e688c75 | |||
| b08b0d715b | |||
| c87d1aed4c | |||
| 356f76e545 | |||
| 1fb55dcb2e | |||
| d74bf9ef2f | |||
| e04a5f0cb0 | |||
| ea7393f7fd | |||
| c7d17dda49 | |||
| 9d187e041c | |||
| 14f0cb4538 | |||
| ca48661423 | |||
| 041463d112 | |||
| c1401682ed | |||
| 8bc3cfe29a | |||
| 77e226c55f | |||
| b9f8858bfb | |||
| f7b97ef55e | |||
| 88f1ec8d0a | |||
| aa480e5fbb | |||
| 41e627a7ee | |||
| e1e3efc9d0 | |||
| 18dd399cb5 | |||
| f1ca7fa40a | |||
| 6166d7f6ec | |||
| ffb80c2426 | |||
| 4ab1b9895a | |||
| 84710b1953 | |||
| a7f758eb3a | |||
| 26505b580c | |||
| e51f3e11f1 | |||
| d75792703a | |||
| e5f7a9c424 | |||
| 9062a943e7 | |||
| 7e02ef697d | |||
| 41a8809280 | |||
| 01d2d43737 | |||
| 16da6918cb | |||
| fbfad06307 | |||
| f8138262fa | |||
| 1a4ae41397 | |||
| 75bc41fc20 | |||
| ced5110dab | |||
| 76d020511f | |||
| 02cf264ee1 | |||
| eb3f3cfdb8 | |||
| 660368f249 | |||
| 97ad3d97cb | |||
| cf021ccae4 | |||
| eb75f59a96 | |||
| 030847a80a | |||
| 722c4933dc | |||
| 3e2f4eb8ba | |||
| aca6bf6aa0 | |||
| d48c934357 | |||
| 41cc6cf105 | |||
| dd04b46e86 | |||
| 1bd4f9d8b6 | |||
| 1aa35c8796 | |||
| 51d3f44d51 | |||
| d4b418ba01 | |||
| bd77515fd9 | |||
| 1c77bac146 | |||
| 0be8b5b1ed | |||
| d5996fea99 | |||
| a1dd19738e | |||
| 17b3eb730a | |||
| 4c961df313 | |||
| 19bdd95eab | |||
| 143bb63483 | |||
| c64b5ec4a3 | |||
| 57012ae5b3 | |||
| db99beda36 | |||
| 97b31c4eef | |||
| d1eb87c81f | |||
| 8f9bb6bccc | |||
| 416d243027 | |||
| 5fe5d1da46 | |||
| 2d683bb6f8 | |||
| 7956eb239e | |||
| a26463b056 | |||
| 982eee63b6 | |||
| b54215f0a5 | |||
| 521dc7f26c | |||
| da85e3f8f2 | |||
| 59a18e710d | |||
| 5f027cb63a | |||
| 4086abf375 | |||
| 8f5bf33eac | |||
| 7eeb7bd74c | |||
| 96b9be3ec4 | |||
| 1e31427da8 | |||
| 7feb2f8f42 | |||
| 2122604b32 | |||
| d4b4aede2f | |||
| 4b5c044272 | |||
| 2fe45834dd | |||
| 56092bd782 | |||
| c31f05356a | |||
| 61dbab03e0 | |||
| 86b5995f12 | |||
| d2849fda8a | |||
| a61fb058b7 | |||
| 7edd803034 | |||
| 0c54136244 | |||
| cce4574143 | |||
| 9172e28315 | |||
| 6f4b2ad0b9 | |||
| 9a3ff6510f | |||
| 4c67eef0f2 | |||
| 7d4f97de7a | |||
| cbd2eee9c4 | |||
| 384fb6a465 | |||
| 2cb33b2f76 | |||
| 8f0324d868 | |||
| fd7b6bf40a | |||
| ed8bad8c26 | |||
| 6d1e27633a | |||
| 2da911e4a0 | |||
| e5d183031a | |||
| b13c6b57ae | |||
| 3c92666ec2 | |||
| dc6dda5c37 | |||
| 3997c7ff80 | |||
| b4b49e7029 | |||
| 615b218ff7 | |||
| f3625aab13 | |||
| d3563e2f0e | |||
| dd84c2fb83 | |||
| bdb349e7f6 | |||
| 12c7c9cc42 | |||
| 90be9c3587 | |||
| eec5d5ebf8 | |||
| d3c206c677 | |||
| f0a039f7c0 | |||
| 30f5c4af4a | |||
| e78c3fe4f0 | |||
| c0ccb22460 | |||
| 764b195977 | |||
| 0f3555a4d2 | |||
| 006de1dd31 | |||
| 18fef0db31 | |||
| 958284dc24 | |||
| 788bb04f5c | |||
| 8a0190ca3b | |||
| c29a8c12b3 | |||
| 05049b5abf | |||
| 3ebe4e6a8f | |||
| 0eb84f5133 | |||
| de1233b8ca | |||
| ec11b8afbf | |||
| ec79fe1ab2 | |||
| 90eb1e0281 | |||
| 15c9f88da6 | |||
| 4e6fee7fcd | |||
| 1e08b150f7 | |||
| fb22f5b8ee | |||
| 848e8485cd | |||
| 07e597de40 | |||
| 10ae84869a | |||
| dcd2449b1a | |||
| a3d214f8d7 | |||
| 37be162435 | |||
| 5566292cc8 | |||
| 65e2144b3d | |||
| a26d195404 | |||
| 21388a0a40 | |||
| acecd80afa | |||
| 69fc75c0b2 | |||
| 9cdb267ba5 | |||
| 56b050422d | |||
| 546baf9934 | |||
| e6344a8c24 | |||
| 873d10df42 | |||
| 02a36afc38 | |||
| 563d81e08e | |||
| 5f28614760 | |||
| b6b0727e28 | |||
| e9a601c1fe | |||
| 308aa70718 | |||
| 6be034392f | |||
| 3b1dbcd42d | |||
| 2ac9fe08f7 | |||
| 24c722454b | |||
| 0a216b28f3 | |||
| 9c48cd849b | |||
| 0843d9af58 | |||
| b0d5c4c058 | |||
| d18c96d6a1 | |||
| dced409ac4 | |||
| d6a2f1d670 | |||
| 58fd00a3df | |||
| b923604602 | |||
| 8643d60b88 | |||
| 8feeffb29b | |||
| e64146914a | |||
| 6084708cc2 | |||
| 8ed0f8981f | |||
| 41a1a3eed1 | |||
| 10ba348a3a | |||
| db67bb106a | |||
| b828b4754b | |||
| 9383b54d50 | |||
| 181da07dd9 | |||
| 419464a8c2 | |||
| 2e229d3bb6 | |||
| 3c92bdb1ad | |||
| e0f159085e | |||
| 402148dbc4 | |||
| 70696e364b | |||
| 1e10492e55 | |||
| 9e6914d641 | |||
| 0c4fb6afd2 | |||
| edab97997a | |||
| 2515b89e2b | |||
| 60f0f19d76 | |||
| 322232e514 | |||
| 54466a3ea8 | |||
| 7da060c149 | |||
| 088f48d60f | |||
| 2b426c1d91 | |||
| bc168bbae4 | |||
| 124a6da743 | |||
| 739c02bd6d | |||
| 5d13145995 | |||
| c28ff3d5a5 | |||
| 6ddd5abd7b | |||
| bf6d0485ce | |||
| 3d486ec1e9 | |||
| a6d1245a54 | |||
| de7e1937f6 | |||
| b465e12747 | |||
| 948401a450 | |||
| bb8f181ef1 | |||
| bf90b59935 | |||
| 18698d6929 | |||
| 80c4225286 | |||
| d02f3f6809 | |||
| da85aed5aa | |||
| 7f2d33458a | |||
| 3e9a0a7628 | |||
| 26c115a4fb | |||
| db643e9166 | |||
| ba100642e3 | |||
| cc52839f19 | |||
| e79b149985 | |||
| 5e21c8c03c | |||
| 5ea5107d05 | |||
| 2995af6a21 | |||
| 0c3eb82671 | |||
| 79f664d593 | |||
| bb0c0d8ee3 | |||
| d236df5b21 | |||
| 13944b9bb1 | |||
| ec665ef405 | |||
| 217e2b0eb4 | |||
| d030a1f62f | |||
| fc2a5a42ce | |||
| 57c7b9ccce | |||
| 942bcfc61e | |||
| fcc3b2b5ec | |||
| d9f94103cd | |||
| ad60cbfc2c | |||
| 126c32aca4 | |||
| 977248e095 | |||
| a47af8e261 | |||
| 5b56920f0a | |||
| 5f298c17d7 | |||
| d2a1a45646 | |||
| 6dea66f1f5 | |||
| 20164ebcda | |||
| edbe5480ca | |||
| e84c4bfb81 | |||
| 3b2a4ba27a | |||
| 12cbe320e4 | |||
| 1e734d7e60 | |||
| 299cc9bebf | |||
| a02abcf578 | |||
| bb33e281c0 | |||
| 86134e9970 | |||
| 54de67536d | |||
| d818fb1d91 | |||
| 927102ea1b | |||
| 2d3db97067 | |||
| 24fca1b745 | |||
| 8c83e1ea9a | |||
| 91b15fc9dc | |||
| d4506e0fc0 | |||
| 648041c62a | |||
| 22e6af414a | |||
| c8b688655c | |||
| 68ebf5d655 | |||
| 1954f45c19 | |||
| ee6556cbd2 | |||
| d2a6b30398 | |||
| d90356e8a3 | |||
| aced401071 | |||
| 2800187355 | |||
| 3f5f030d01 | |||
| 364b12e2fa | |||
| 6877dd0de7 | |||
| 6be32e9383 | |||
| f919783173 | |||
| 674494e80b | |||
| 1f813f6a06 | |||
| afd4829f10 | |||
| 03be923e05 | |||
| bc542cbca8 | |||
| 560550f5df | |||
| 720b31cb8b | |||
| d35a1fdec7 | |||
| 8f43d4851d | |||
| 171103aedc | |||
| ec9a8c7a72 | |||
| 91c46311c8 | |||
| 89570aef06 | |||
| 17b5b40765 | |||
| cdc74a742a | |||
| 4322137cee | |||
| 8651c53923 | |||
| b2a821c81a | |||
| 3888a592cf | |||
| 84c07c8fa1 | |||
| 389cadb06a | |||
| 6e51bbc215 | |||
| 8f4f8baa81 | |||
| 7a72037572 | |||
| 025e450ac2 | |||
| 3cf44acc08 | |||
| bdd15e8911 | |||
| 04cbae5b5f | |||
| 2c4ec31ed1 | |||
| 996cbcb680 | |||
| dd3fd73ffe | |||
| 738354ff65 | |||
| 616d6f6667 | |||
| 8341256d1e | |||
| 934b309b4c | |||
| d284fa66c0 | |||
| bedce8aacf | |||
| 7db5abdecf | |||
| 290ede93e2 | |||
| f4f2bcbd98 | |||
| 1c5213788c | |||
| 0d5424fb79 | |||
| ae8694b303 | |||
| 5f60281d25 | |||
| 0c7ae22f5d | |||
| 2d1c1ac567 | |||
| 205d0f456e | |||
| 8b0a8f47c1 | |||
| 84f521b1c6 | |||
| 1040c246f5 | |||
| b27cf0b0a8 | |||
| 0a2971f9d3 | |||
| 48e8c12476 | |||
| 6f3b56c5b6 | |||
| b745d46395 | |||
| 46bb07e4b7 | |||
| d5e5f58737 | |||
| 9bc5a4d64f | |||
| 7b811a38a6 | |||
| e0a2227faf | |||
| 470f3b057f | |||
| 518e73ac9f | |||
| 3da4fd5f7d | |||
| 1e6243045e | |||
| a28be4a4e0 | |||
| 153d01a01e | |||
| eb3312e7ba | |||
| 939cb67621 | |||
| 00705b14bd | |||
| 8d4082ef2e | |||
| f588219bb9 | |||
| b8c038f41f | |||
| 08067acc71 | |||
| 1c12da1fad | |||
| 7a6d3067c6 | |||
| 54c62d580c | |||
| 0857345945 | |||
| b9b3b8050d | |||
| 92e95ed806 | |||
| 035bea3699 | |||
| bdbbe9232d | |||
| 145fb246a6 | |||
| 533a3fb312 | |||
| 344f2f26e7 | |||
| ed10edbf0d | |||
| 828afe113e | |||
| 2d935b3798 | |||
| aa544c40de | |||
| c78f2574a2 | |||
| 2b1a791a0b | |||
| 752a521423 | |||
| 71b0e7ab0d | |||
| f7f047936b | |||
| 2a3c0eddb9 | |||
| 1689e9b671 | |||
| 98d7238ed6 | |||
| d24e5cf353 | |||
| 70a48a3dd6 | |||
| 5fa6d87c25 | |||
| 5729642556 | |||
| f4babf172b | |||
| 0c463e664e | |||
| 4df43c802b | |||
| 784d3c6c9a | |||
| fcb85e612f | |||
| b4df7e351b | |||
| 806cd112ac | |||
| 26f050ff10 | |||
| bde8b78a88 | |||
| 62f890b5aa | |||
| db027dd95b | |||
| 613fb2fed6 | |||
| f918af82fe | |||
| 844d3a4dfa | |||
| 4228a75186 | |||
| 2fe609cb62 | |||
| f2466e5224 | |||
| f98e84f03f | |||
| bbd61f375f | |||
| 576fda18eb | |||
| 7a4280a482 | |||
| 6a43b31218 | |||
| 450734e333 | |||
| cf7f6b49ed | |||
| b9dc8eb14d | |||
| 69188c8538 | |||
| 5949d56370 | |||
| 5bed97064a | |||
| b2bdfcf1b5 | |||
| 0d29385e1b | |||
| 87edeb4e32 | |||
| 0f12d6c426 | |||
| 3406dc5b2e | |||
| 4a82b0d891 | |||
| bc365f1eaa | |||
| 558c8ece2c | |||
| 1187c7fdac | |||
| e1d2653a7a | |||
| 36a0a3d37b | |||
| d97bbd5324 | |||
| d2a6cff4df | |||
| acf5ed595f | |||
| 03845198ce | |||
| d8a3d08f8e | |||
| 6f9118dca6 | |||
| d0b6701fba | |||
| 94c3eecb99 | |||
| 098e5c281c | |||
| f2c52f777c | |||
| 2b41263aa7 | |||
| 404a4468d8 | |||
| 7f67c7f952 | |||
| c8540b5744 | |||
| f6d97d4488 | |||
| 87712a0a7c | |||
| ba0e053ffc | |||
| d14779b264 | |||
| 5411f4a667 | |||
| 2034098780 | |||
| d53a5c4fb5 | |||
| f6ee025c46 | |||
| e50bf6adad | |||
| c21b6899e1 | |||
| 95693e265e | |||
| 569c6f1dd0 | |||
| 7350399a50 | |||
| c2a741ee36 | |||
| e177314a4a | |||
| dadd606c0d | |||
| b3fcddde11 | |||
| e205a468d9 | |||
| bdf80ea7c0 | |||
| 5e218a5630 | |||
| 8c36b10682 | |||
| 42c2e1b217 | |||
| 1e715d1e5c | |||
| 9f9a2fa844 | |||
| 64eb14ab11 | |||
| 0713c86dec | |||
| 99c5bf2e97 | |||
| fe67ef63c1 | |||
| 19d4384f16 | |||
| d351f07758 | |||
| d72f35c2e7 | |||
| aeffa2a460 | |||
| 030a5ace97 | |||
| b97661553f | |||
| 3370644ffe | |||
| 0f0b463a2f | |||
| 8d082a904d | |||
| 61582678bf | |||
| 613b8a4527 | |||
| 5982abeffb | |||
| 78b10dccf1 | |||
| 85bc25a765 | |||
| fec0eba07e | |||
| f92e79eba0 | |||
| 3e50be1658 | |||
| 9937fb2220 | |||
| 8e531dc029 | |||
| 83d0bdc32e | |||
| d15970e12c | |||
| c7b5dcd28f | |||
| 8c07ad2ab9 | |||
| ade9dfeebb | |||
| d1e35f8660 | |||
| e20d282088 | |||
| 4adfdad47f | |||
| 6c126b9e58 | |||
| 1d2e27a698 | |||
| 049a299b92 | |||
| b1258dd52c | |||
| 98cdaa01b8 | |||
| 3476a97acc | |||
| 9ebf321717 | |||
| ff725dea41 | |||
| c3f1b29c1e | |||
| 257cd07a3a | |||
| 43d6dc3668 | |||
| 2231497b1f | |||
| d0a845b6e6 | |||
| e4c4bb265e | |||
| 0f845407f1 | |||
| b2a2ea3633 | |||
| f8a862738d | |||
| 25f8452127 | |||
| 84573992b4 | |||
| 3f8d636501 | |||
| 300205b07c | |||
| e1c711f5ba | |||
| 282654e7b8 | |||
| 0d89ac7406 | |||
| 5c47592159 | |||
| 61f0f3c243 | |||
| 1e8ae5b9d7 | |||
| e8d0e0d342 | |||
| b644f037a3 | |||
| c5498bbb07 | |||
| 90c764ce13 | |||
| 10003a6490 | |||
| b916d79fe2 | |||
| 36b0a86c69 | |||
| 7cc5234b9c | |||
| 379f09d92f | |||
| fd9d3e19a9 | |||
| 86828bb561 | |||
| 78075c8a37 | |||
| 7d33baabe4 | |||
| ecf8fba10e | |||
| 2f8b68dffd | |||
| 8877c85278 | |||
| 1d1bdc57ce | |||
| ba88707b1e | |||
| 8c78fe4f10 | |||
| 394a7ea019 | |||
| 78a28bfc01 | |||
| cf8de02c68 | |||
| e650a4ee59 | |||
| c6b6dcbe95 | |||
| 9786c4dcff | |||
| d03496b710 | |||
| ab6b2293e1 | |||
| 472e775a13 | |||
| ce56b4ee1b | |||
| ba15eeb55f | |||
| d683e1c0db | |||
| 6d83d3440c | |||
| 9d74b7c0e8 | |||
| 016b5b42e2 | |||
| a591505bf9 | |||
| 638dd2f6c0 | |||
| 555e25e633 | |||
| 3174573b64 | |||
| 2c5e09e1c3 | |||
| ab11b2c27f | |||
| 0fcbff506e | |||
| 48e3932f65 | |||
| d304216300 | |||
| 2b8adf8cf3 | |||
| fb99b95372 | |||
| 60fe5acd60 | |||
| eb9ff72b5a | |||
| fb03242950 | |||
| 54c1e13853 | |||
| 102905bbc7 | |||
| fe1bfc64f7 | |||
| 0f9ec2735c | |||
| 13d8d9477c | |||
| 43916b98aa | |||
| 5d27a62bec | |||
| a05e0ea3a4 | |||
| 2987b473dd | |||
| ee7065f665 | |||
| d26b828ab3 | |||
| a810ca80bc | |||
| ad1f0d995d | |||
| 1ed163a666 | |||
| aa9922bc98 | |||
| 0075b4f118 | |||
| 4d85ce40be | |||
| 7ec78452ec | |||
| 540f60696a | |||
| 1ffb9c4188 | |||
| 570ccc7da0 | |||
| 1c8fe92d0f | |||
| 396b427cc9 | |||
| c961f27401 | |||
| 1c87e7cd25 | |||
| 408b885689 | |||
| cab9b1f370 | |||
| d3cf28eb4b | |||
| 11a0a9b911 | |||
| e8038c727f | |||
| 2abc288c52 | |||
| 2e2b066713 | |||
| c1076512d1 | |||
| 3154c06dc3 | |||
| b248ec6dfb | |||
| cc2c48d59e | |||
| ac733d40b3 | |||
| a4415f15d3 | |||
| cbbf565121 | |||
| 7bb13d1c41 | |||
| e79f62694a | |||
| 4fbeac8b32 | |||
| 22b0550520 | |||
| 5ba6bc7139 | |||
| 6893d27441 | |||
| 51f952e700 | |||
| 4af4f8644d | |||
| 37ca643a64 | |||
| 8f4b1b582d | |||
| 3c9052a751 | |||
| 2136598e87 | |||
| 3f90001f83 | |||
| 4ef4bd6f09 | |||
| 331dbd5638 | |||
| 4ab94dec5e | |||
| c0b766ad74 | |||
| fd59d9dd92 | |||
| 9e4ae214a8 | |||
| f649948713 | |||
| 43b8731241 | |||
| 9116cf2bab | |||
| bafbcbbe8b | |||
| fdb6088603 | |||
| f3a8b73717 | |||
| c883403147 | |||
| 2077521f84 | |||
| 6d90b7ddb3 | |||
| 6cf1c98524 | |||
| 5ff7cdc9e8 | |||
| 47603ef8e1 | |||
| ef4030331a | |||
| a0a6828265 | |||
| 69339f08a6 | |||
| cd27cae848 | |||
| 475e92da5d | |||
| 054497c7a6 | |||
| c81a02f8d2 | |||
| 445a5eac33 | |||
| f05d937f39 | |||
| 5f1208ad81 | |||
| 1e42fdf6c2 | |||
| 98055d0989 | |||
| c13ec85d7d | |||
| 36feb73bfd | |||
| 77614eff5b | |||
| 31b34b11ab | |||
| c585470a71 | |||
| 9ba1cd0336 | |||
| 5f6453a1e0 | |||
| 956ab94452 | |||
| 0f5dd2229c | |||
| 224a33db2e | |||
| fb0768f007 | |||
| 9787108532 | |||
| 44b8c62db9 | |||
| 1d2f90c7e7 | |||
| c951f9fdcd | |||
| fa93b56243 | |||
| ca6cfaaf4e | |||
| 400da30a8d | |||
| f5bd474e51 | |||
| 16113647de | |||
| f51d74586c | |||
| c743631148 | |||
| b445db3d46 | |||
| 21dd9bbf7d | |||
| 3937461272 | |||
| da3da19844 | |||
| 53c7646ed7 | |||
| b6524e410a | |||
| 75c2769b32 | |||
| f796650122 | |||
| 460c3debf5 | |||
| b8b6620365 | |||
| 96d7eb2966 | |||
| da4fa5ad75 | |||
| 2b77c1ded4 | |||
| 6ab1b239ca | |||
| ab73051298 | |||
| cb2880cb93 | |||
| b5315bfc20 | |||
| b259153403 | |||
| f0c3c81e94 | |||
| fc42c4613f | |||
| bd06e5b161 | |||
| ad33c22374 | |||
| f3759381b1 | |||
| 80673a0c0c | |||
| 1671bf77fb | |||
| ffc5e4d048 | |||
| 60d2c2cc90 | |||
| 2144d25885 | |||
| 7a515339ea | |||
| be1dc13bb1 | |||
| 1c044ba8af | |||
| 4fc9b1cde2 | |||
| 60973aacd9 | |||
| 1c18552426 | |||
| c4377c1b1a | |||
| 265f24e5d7 | |||
| 59e0b10e6c | |||
| 9d642f3bb1 | |||
| 19ea68b838 | |||
| 93f14ce626 | |||
| 1ef34261e0 | |||
| 5062fadf87 | |||
| 462c7d3502 | |||
| 9187f6f6d1 | |||
| c0495ce2f9 | |||
| 02518d2927 | |||
| d7243fb81f | |||
| e3262f8766 | |||
| caf2ca1438 | |||
| f8ce3585eb | |||
| 61207fc2cb | |||
| b3cc397a31 | |||
| f9df415392 | |||
| fd2cbacae9 | |||
| 8b93a5f27d | |||
| 9478bca67d | |||
| 4b53b3a6e6 | |||
| d72f8453cb | |||
| 6ee7165e39 | |||
| adddafe6d0 | |||
| 35f091bb01 | |||
| e9c7a80b12 | |||
| ab013fb7e9 | |||
| c158923b27 | |||
| 31c5761e06 | |||
| f4ee245bf9 | |||
| d13482e802 | |||
| 11e1e98022 | |||
| b31f6804fe | |||
| 01ad74a870 | |||
| f875911af7 | |||
| f8ff921c42 | |||
| ab8c24f5ea | |||
| 9da3cb7e43 | |||
| 6f69cdcc31 | |||
| 236334d015 | |||
| 12472ce9b2 | |||
| e762cda55d | |||
| f566df91c8 | |||
| db37c715c0 | |||
| c89bc30d66 | |||
| 59e00eeda6 | |||
| 3332703fca | |||
| 643f2c0958 | |||
| c6a7107f78 | |||
| 322feaafa6 | |||
| 68afb7200e | |||
| b382ae6803 | |||
| 135d981e3c | |||
| 54fa26ef0e | |||
| cc081337b7 | |||
| d4cad0cdcc | |||
| b8969cceff | |||
| a3370ac86b | |||
| 7d03151cd5 | |||
| 054b4307ed | |||
| b8330b626e | |||
| 2a3244b1bb | |||
| 4d2a2de557 | |||
| c583b510e0 | |||
| 42c79c64d7 | |||
| 1d9e6870be | |||
| 167b6ff8a1 | |||
| 77df6d48e2 | |||
| 06035d5d43 | |||
| 6c8a48db13 | |||
| 523274dbf3 | |||
| 36207abec2 | |||
| 99f75f3218 | |||
| 82c10421a0 | |||
| 2e003ad8cf | |||
| 42a265d290 | |||
| 121732dde6 | |||
| 3e9701861e | |||
| b31b786db7 | |||
| 66e981ed1e | |||
| c60d8ef5a8 | |||
| 6e026bd950 | |||
| 372b588778 | |||
| 5d87a7f9c7 | |||
| 706834ecd3 | |||
| cca41edc6e | |||
| 601a639f95 | |||
| f6423ea45a | |||
| 70996bfdee | |||
| 44bdd3ad11 | |||
| ab1f195508 | |||
| 39eb6ed9cc | |||
| e750da987d | |||
| 7e987113a2 | |||
| 7a238bd938 | |||
| c2d60d61ac | |||
| 13aa0148e7 | |||
| 5d61adf804 | |||
| 4e6eef5882 | |||
| 064edc52f5 | |||
| 1b302deeff | |||
| 25f27509c0 | |||
| d465a26e30 | |||
| 034ca93907 | |||
| cca5a12839 | |||
| ecf0a24873 | |||
| cb208f53d8 | |||
| 85f3a8c210 | |||
| e9f8ccd51a | |||
| a9cb8f4958 | |||
| 2dfb813c90 | |||
| cb0947c501 | |||
| 2a87d663d2 | |||
| 6db64aab2b | |||
| abd22a753d | |||
| 9e8f7c074c | |||
| 44c62c8e5d | |||
| 4ef3c09332 | |||
| 29efebe38f | |||
| 0e4dce23b2 | |||
| e115083fac | |||
| 5ded674ad6 | |||
| 541eeb7a50 | |||
| 23c906b085 | |||
| c7817aee30 | |||
| 2fa13420ae | |||
| ee66732ad2 | |||
| 8352980f01 | |||
| a2d7f82b49 | |||
| 73570f1c86 | |||
| 51578397a5 | |||
| ef70e63230 | |||
| ce26b58f09 | |||
| bcd9735a73 | |||
| b1059f891f | |||
| 145e099ca5 | |||
| 81006605c8 | |||
| f934f01881 | |||
| cdff69b7b2 | |||
| d91484eb4d | |||
| c20b88cee2 | |||
| 810d940e57 | |||
| 7e2642b9f1 | |||
| 40057b55f0 | |||
| b188a51c32 | |||
| 63a90836fe | |||
| ca94dabd4f | |||
| 31b7c010d0 | |||
| 4960c47257 | |||
| ee92db7533 | |||
| c2104a14fb | |||
| 25996ae037 | |||
| a123a813b2 | |||
| 8bdef8754e | |||
| 978fbcf95e | |||
| d915525c8e | |||
| c079084ca4 | |||
| a889c15e38 | |||
| 884d838a1e | |||
| 0fe82a2f4e | |||
| b16fe7b646 | |||
| b77381750c | |||
| 9814f86a25 | |||
| aa6ae954ef | |||
| 5e70a7dd46 | |||
| 48ff9e1555 | |||
| c4c0c0d182 | |||
| 3a501196f0 | |||
| 7787a31f81 | |||
| 9e91aafe40 | |||
| 8ad72ec1ae | |||
| d3e4ff2cfc | |||
| 750c0e366f | |||
| bde5d61812 | |||
| 5ae9fe6949 | |||
| 3f38f95b1d | |||
| 445ef4fbed | |||
| 5ebe40e919 | |||
| 8e9f71b7a3 | |||
| 1202dced73 | |||
| 047bc44032 | |||
| 92d412e542 | |||
| d9f0b9c668 | |||
| 8f8a689722 | |||
| a90b9fe977 | |||
| eee3452948 | |||
| 2ede47d5ee | |||
| 4f220e945a | |||
| 30dd2f1dfe | |||
| b40f67b76a | |||
| a7faa2080f | |||
| 6d75005afc | |||
| 5bb9cd1a13 | |||
| 0bf2a0353d | |||
| ce655436ef | |||
| 59985138f7 | |||
| 0542de95eb | |||
| dc90c8fec7 | |||
| 0d7da7ecb1 | |||
| 73b1afb106 | |||
| d1c913ed5c | |||
| 2940b50811 | |||
| c7243997f4 | |||
| 306e12c23c | |||
| cc3904f026 | |||
| ed9f714fbb | |||
| 5b750f519b | |||
| 465f97a528 | |||
| ccf8d0ca31 | |||
| 519bd57e55 | |||
| 16f5f767b2 | |||
| c6a59896f3 | |||
| e9e80b054d | |||
| b364f37655 | |||
| f5e07d94bd | |||
| dd3b1cb653 | |||
| cf16d1678d | |||
| fb44f5ba0d | |||
| e72c00cf9a | |||
| 62dc9683bd | |||
| 3443946087 | |||
| e49f4673f2 | |||
| af833c5eff | |||
| 74a7771943 | |||
| 193b4bba91 | |||
| bf80263bd6 | |||
| 0658b4aa31 | |||
| a74a04d12d | |||
| 2c93542e5c | |||
| cb8f93bad7 | |||
| 9d0177e0ce | |||
| f0eed9b221 | |||
| a2013f34e5 | |||
| 0ed4f98087 | |||
| 14867c7c14 | |||
| f4080b6037 | |||
| 0e7b3951c2 | |||
| 81772c4252 | |||
| fc4e10b537 | |||
| 654c555099 | |||
| 7dd2d8f794 | |||
| 8aace3aff2 | |||
| 72b16b3a24 | |||
| 723b8d33c2 | |||
| 70a99af1d3 | |||
| 31f58a1f04 | |||
| cc7e1472f9 | |||
| 995ae717cc | |||
| d5a06d3cd2 | |||
| 61a71c4fcd | |||
| 3c57e76c45 | |||
| 30d9a336bc | |||
| 49bde9fca0 | |||
| 36de686224 | |||
| 085e5b1f4d | |||
| a96f065903 | |||
| 9a4c045518 | |||
| 397e52dac7 | |||
| d0ab6e9982 | |||
| 35afab31e1 | |||
| 71ecc401c3 | |||
| 518a9ca314 | |||
| d52ec522f1 | |||
| 8731309d7c | |||
| a788a6df48 | |||
| c8518d6a63 | |||
| 0fd9ff0f53 | |||
| 23e52f0ff3 | |||
| 98eef9ba0c | |||
| f425bd765b | |||
| d065c3ca53 | |||
| f22aa72c62 | |||
| aa46eb4fd7 | |||
| ff31a2224e | |||
| dd42893df7 | |||
| 725b312032 | |||
| cd76b0b22d | |||
| 2ef38065c7 | |||
| cedf0235a1 | |||
| f4330c9f5e | |||
| 9b9ab60985 | |||
| 0b20f88fc0 | |||
| 21163a1636 | |||
| 08e87a59d5 | |||
| d3bdbc6978 | |||
| b4a405c684 | |||
| 426d36146a | |||
| 4d2a1111e0 | |||
| e4226b8a3e | |||
| 7c086fe55b | |||
| 6786684962 | |||
| 8da47db1a4 | |||
| 2b61ac532d | |||
| 4a0fcd054b | |||
| 659b0557be | |||
| 795e5134c7 | |||
| 0ded546a09 | |||
| be25e2cb96 | |||
| b2ef66263f | |||
| ca3d260a2b | |||
| f3ffaf09c7 | |||
| 3a1d3769ae | |||
| d42da87161 | |||
| 406f0baaf2 | |||
| cd0f9fe22f | |||
| a67deae8ba | |||
| dcf362bcf9 | |||
| 22f725eb08 | |||
| 9049f8f8ae | |||
| a440333990 | |||
| 991bd37362 | |||
| 9a4211b610 | |||
| c71b749185 | |||
| 02241e9126 | |||
| 01c577c371 | |||
| 2aa1d74286 | |||
| 6b866d1282 | |||
| de3632afc3 | |||
| 937c15c66e | |||
| bec2bfcadb | |||
| 39cc07de30 | |||
| d2c9c5b35e | |||
| 6ded45e5d2 | |||
| 05930d5e25 | |||
| ffa547ce8d | |||
| 155242af34 | |||
| c96fd828df | |||
| b4f6c7c4b9 | |||
| 872d2eaf60 | |||
| b734723d95 | |||
| 5aaa0e66f5 | |||
| a9083b9d48 | |||
| 60420e52db | |||
| 3acb014ed7 | |||
| c9c633be62 | |||
| 130f0a0253 | |||
| 8c74be79c5 | |||
| e2fef41fe2 | |||
| 72b2cc54b9 | |||
| cfaa95a2b9 | |||
| 8c1656bf56 | |||
| 1fc3fc0a22 | |||
| ccaa7009a7 | |||
| 47f693173a | |||
| 7bed302f21 | |||
| 2e6d69c9c8 | |||
| c80352a7fb | |||
| 47f5e73be6 | |||
| d38ab07939 | |||
| 4f17eae5cc | |||
| b8df8b2ab8 | |||
| 8a937ebf8b | |||
| 0dea354457 | |||
| cb1ec755f6 | |||
| 984415f6c7 | |||
| 203bad7c06 | |||
| 4f5b335792 | |||
| dabe161a6f | |||
| a2f3339a0e | |||
| 996c9f5955 | |||
| bd5c158a62 | |||
| 6f0107e7b7 | |||
| 769fe8b161 | |||
| ef3186d441 | |||
| 8c78b62b75 | |||
| 0a3e492e6b | |||
| 99c7108bb0 | |||
| 49b66733c2 | |||
| a6720d6007 | |||
| 92dbdbb93b | |||
| 061a89fc2b | |||
| 7c1a90244a | |||
| c86ee4cc83 | |||
| 7b06a0bebd | |||
| 9e8c767694 | |||
| 3ba4ba79fa | |||
| 1e838393a9 | |||
| 481ba01c97 | |||
| b2ba67f337 | |||
| 249a193c00 | |||
| a3fe9279d8 | |||
| 0f8199dde3 | |||
| 6787d42de4 | |||
| 9185f68e52 | |||
| f56a561f02 | |||
| dd01af609e | |||
| ada179f572 | |||
| 20fc7abc8c | |||
| f3424844dc | |||
| c4bd759467 | |||
| 771627505d | |||
| a73b81452d | |||
| 4a5ef4d9f7 | |||
| 518caae62e | |||
| 7beaa368a9 | |||
| 19c1d73405 | |||
| 28e667bd97 | |||
| f68f27e7f1 | |||
| 90de8416cc | |||
| c23eb84b04 | |||
| cfb71b9d60 | |||
| 87f175bb2c | |||
| 907e51ac01 | |||
| 5dc7059ba3 | |||
| 09ef33ec3a | |||
| cd9193466e | |||
| ead8928c39 | |||
| 265d39f337 | |||
| 37678acb1a | |||
| a64bb433b0 | |||
| a6e00d9183 | |||
| bf0f61e656 | |||
| ae48e964f0 | |||
| ab3804d823 | |||
| 0a7ee67707 | |||
| a5e47c62e4 | |||
| 2a7c71667d | |||
| c6af4eaa00 | |||
| 32db4ff66d | |||
| 849cd1f9ed | |||
| 249ea55942 | |||
| affd3cae9a | |||
| 8dc397c0a5 | |||
| 38bc856212 | |||
| 971eb64e98 | |||
| 65b9e367f0 | |||
| 112790cbaa | |||
| 558be87311 | |||
| c82c2c2b15 | |||
| 83075b2800 | |||
| cce245738e | |||
| fda3b54357 | |||
| d190188aaf | |||
| 21062dd30e | |||
| ed37b7c5e7 | |||
| 0b6c02000f | |||
| 1f6716f98a | |||
| 5aab793cfd | |||
| 5e688b8113 | |||
| 5f96eba54a | |||
| a8379d1f4b | |||
| 6d84d4dc9c | |||
| ae02236c63 | |||
| 433ca84ce0 | |||
| bd6bba8d07 | |||
| cd354aebed | |||
| b60c8858af | |||
| 70610c740e | |||
| a08938010c | |||
| 0cd490a9b8 | |||
| a044c25981 | |||
| 3d24575239 | |||
| 3ea5581ad7 | |||
| 95268b266d | |||
| 06920402f8 | |||
| bcbcaeb82c | |||
| 29aabd7bfc | |||
| 56ca62cf3c | |||
| 741b57ed06 | |||
| 8d8a2ab64e | |||
| 3d106186f4 | |||
| 118aade84c | |||
| 76b1deec25 | |||
| f2852056a1 | |||
| 1962b51d8d | |||
| b92e3bca50 | |||
| 467a305f26 | |||
| b0b1be0c2a | |||
| c0552ceb22 | |||
| b45bd5ff7b | |||
| 603ec2b21b | |||
| 1af3fef33a | |||
| 8aa730082e | |||
| 8ac2c6842d | |||
| 8980276b20 | |||
| 5d09ab7eb3 | |||
| 8cd2ec7c9b | |||
| c195a9aa3b | |||
| ed0d1a0ba3 | |||
| cf7debbac1 | |||
| 34ba8be821 | |||
| 6bb99806f0 | |||
| d93e987f24 | |||
| 343be47fa9 | |||
| c4656fb063 | |||
| 69f93f852e | |||
| 5a0b21b1d1 | |||
| dc0e0b4165 | |||
| 4f53919a2b | |||
| e705f45c5f | |||
| 4cd3728039 | |||
| 974ab66b7a | |||
| abe4045c63 | |||
| d9fdff339a | |||
| b6d3c56b35 | |||
| 0cf01df48c | |||
| 7f8537a130 | |||
| 1a06282061 | |||
| 7db79e145e | |||
| 319f43fa23 | |||
| f2308dba28 | |||
| c9eb58e122 | |||
| 0c61653b34 | |||
| 43b3f79d60 | |||
| 8149a4546e | |||
| ee3e4017c3 | |||
| 3f79d7e5bb | |||
| 3b92f127a9 | |||
| 667ca6d241 | |||
| d8570e4d64 | |||
| 505e88656a | |||
| f76adec8a6 | |||
| 93c7378d3b | |||
| 2ab61dd16a | |||
| 16d4701822 | |||
| fcdfa8609a | |||
| 4af89e944d | |||
| 43bac6a038 | |||
| 0713dd4d2d | |||
| 69e1239698 | |||
| f63561dce4 | |||
| 0c6f9d2898 | |||
| 63efcb6b66 | |||
| 452d0e21b6 | |||
| 0f465e88e8 | |||
| a6af7bbb46 | |||
| 4a70d6f22f | |||
| 460ec60212 | |||
| 12d4ec2e07 | |||
| e7a13aa031 | |||
| eae8b8b1a1 | |||
| 99958c68e7 | |||
| 332e392aee | |||
| c987e6a623 | |||
| ebbfcda762 | |||
| aa8b2abe3d | |||
| 14dbda9145 | |||
| 33269bdbc9 | |||
| 6553e64431 | |||
| 8174e1d5b8 | |||
| a404fb8d2e | |||
| ef76a801c4 | |||
| 6eca199c39 | |||
| 331ae7dbdf | |||
| 5b16771567 | |||
| 7e493f4a9e | |||
| f3152fa7fb |
@@ -0,0 +1,39 @@
|
||||
description = "Answer questions about the Gemini CLI codebase with explanations and code snippets."
|
||||
|
||||
prompt = """
|
||||
## Mission: Explain the Gemini CLI Codebase
|
||||
|
||||
Your primary task is to help a new engineer understand the Gemini CLI codebase by answering their questions about architecture, specific functions, and project structure.
|
||||
|
||||
|
||||
### Objective:
|
||||
|
||||
Your primary task is to help a new engineer understand the Gemini CLI codebase. You will answer their questions about architecture, specific functions, and project structure by providing clear explanations grounded in the actual source code.
|
||||
|
||||
|
||||
### Instructions:
|
||||
|
||||
1. **Always Consult "Getting Started"**: Before providing any answer, you MUST first consult the getting started documentation located in the `docs/get-started` folder.
|
||||
|
||||
2. **Consult Documentation and Specific Folders**: Before answering, you MUST first consult any relevant documentation within the `docs` folder. Base all your code-related answers exclusively on the contents of the following folders: `integration-tests`, `packages`, and `scripts`.
|
||||
|
||||
3. **Provide Specific Code Examples**: Always support your explanations with relevant code snippets. You MUST include the full file path (e.g., `packages/gemini/core.py`) so the user can easily locate the code.
|
||||
|
||||
4. **Explain the "Why"**: Go beyond simply showing the code. Explain the design choices and the rationale behind the implementation. Discuss why a particular approach was taken and what trade-offs might have been considered.
|
||||
|
||||
5. **Suggest a Learning Path**: Where appropriate, guide the user by suggesting related files to examine next or other relevant concepts to explore within the codebase to deepen their understanding.
|
||||
|
||||
6. **Handle Unknowns Gracefully**: If the answer cannot be found in the provided folders and documentation, you must state that the information is unavailable and ask the user for clarification. Do not invent answers or speculate.
|
||||
|
||||
|
||||
### Constraints:
|
||||
|
||||
|
||||
1. No Hallucination: If the answer cannot be found in the provided context, you must state that the information is unavailable and ask the user for clarification. Do not invent answers or speculate.
|
||||
|
||||
2. Stay Focused: Only answer questions directly related to the Gemini CLI project within the specified folders.
|
||||
|
||||
### QUESTION:
|
||||
|
||||
{{args}}
|
||||
"""
|
||||
@@ -0,0 +1,29 @@
|
||||
description="Injects context of all relevant cli files"
|
||||
prompt = """
|
||||
The following output contains the complete
|
||||
source code of packages/core.
|
||||
**Pay extremely close attention to these files.** They define the project's
|
||||
core architecture, component patterns, and testing standards.
|
||||
|
||||
The source code contains the content of absolutely every source code file in
|
||||
packages/core.
|
||||
You should very rarely need to read any other files from packages/core to resolve
|
||||
prompts.
|
||||
|
||||
!{find packages/core \\( -path packages/cli/dist -o -path packages/core/dist -o -name node_modules \\) -prune -o -type f \\( -name "*.ts" -o -name "*.tsx" \\) ! -name "*.test.ts" ! -name "*.test.tsx" ! -name "*.d.ts" -exec echo "--- {} ---" \\; -exec cat {} \\;}
|
||||
|
||||
In addition to the code context, you MUST strictly adhere to the following frontend-specific development guidelines when writing code in packages/core.
|
||||
|
||||
## Configuration & Settings
|
||||
* **Settings vs Args**: Use settings for user-configurable options; do not add new CLI arguments.
|
||||
* **Schema**: Add new settings to `packages/cli/src/config/settingsSchema.ts`.
|
||||
* **Documentation**:
|
||||
* If `showInDialog: true`, document in `docs/get-started/configuration.md`.
|
||||
* Ensure `requiresRestart` is correctly set.
|
||||
|
||||
## General
|
||||
* **Logging**: Use `debugLogger` for errors. NEVER leave `console.log/warn/error` in the code.
|
||||
* **TypeScript**: Avoid the non-null assertion operator (`!`).
|
||||
|
||||
{{args}}.
|
||||
"""
|
||||
@@ -0,0 +1,60 @@
|
||||
description = "Check status of nightly evals, fix failures for key models, and re-run."
|
||||
prompt = """
|
||||
You are an expert at fixing behavioral evaluations.
|
||||
|
||||
1. **Investigate**:
|
||||
- Use 'gh' cli to fetch the results from the latest run from the main branch: https://github.com/google-gemini/gemini-cli/actions/workflows/evals-nightly.yml.
|
||||
- DO NOT push any changes or start any runs. The rest of your evaluation will be local.
|
||||
- Evals are in evals/ directory and are documented by evals/README.md.
|
||||
- The test case trajectory logs will be logged to evals/logs.
|
||||
- You should also enable and review the verbose agent logs by setting the GEMINI_DEBUG_LOG_FILE environment variable.
|
||||
- Identify the relevant test. Confine your investigation and validation to just this test.
|
||||
- Proactively add logging that will aid in gathering information or validating your hypotheses.
|
||||
|
||||
2. **Fix**:
|
||||
- If a relevant test is failing, locate the test file and the corresponding prompt/code.
|
||||
- It's often helpful to make an extreme, brute force change to see if you are changing the right place to make an improvement and then scope it back iteratively.
|
||||
- Your **final** change should be **minimal and targeted**.
|
||||
- Keep in mind the following:
|
||||
- The prompt has multiple configurations and pieces. Take care that your changes
|
||||
end up in the final prompt for the selected model and configuration.
|
||||
- The prompt chosen for the eval is intentional. It's often vague or indirect
|
||||
to see how the agent performs with ambiguous instructions. Changing it should
|
||||
be a last resort.
|
||||
- When changing the test prompt, carefully consider whether the prompt still tests
|
||||
the same scenario. We don't want to lose test fidelity by making the prompts too
|
||||
direct (i.e.: easy).
|
||||
- Your primary mechanism for improving the agent's behavior is to make changes to
|
||||
tool instructions, system prompt (snippets.ts), and/or modules that contribute to the prompt.
|
||||
- If prompt and description changes are unsuccessful, use logs and debugging to
|
||||
confirm that everything is working as expected.
|
||||
- If unable to fix the test, you can make recommendations for architecture changes
|
||||
that might help stablize the test. Be sure to THINK DEEPLY if offering architecture guidance.
|
||||
Some facts that might help with this are:
|
||||
- Agents may be composed of one or more agent loops.
|
||||
- AgentLoop == 'context + toolset + prompt'. Subagents are one type of agent loop.
|
||||
- Agent loops perform better when:
|
||||
- They have direct, unambiguous, and non-contradictory prompts.
|
||||
- They have fewer irrelevant tools.
|
||||
- They have fewer goals or steps to perform.
|
||||
- They have less low value or irrelevant context.
|
||||
- You may suggest compositions of existing primitives, like subagents, or
|
||||
propose a new one.
|
||||
- These recommendations should be high confidence and should be grounded
|
||||
in observed deficient behaviors rather than just parroting the facts above.
|
||||
Investigate as needed to ground your recommendations.
|
||||
|
||||
3. **Verify**:
|
||||
- Run just that one test if needed to validate that it is fixed. Be sure to run vitest in non-interactive mode.
|
||||
- Running the tests can take a long time, so consider whether you can diagnose via other means or log diagnostics before committing the time. You must minimize the number of test runs needed to diagnose the failure.
|
||||
- After the test completes, check whether it seems to have improved.
|
||||
- You will need to run the test 3 times for Gemini 3.0, Gemini 3 flash, and Gemini 2.5 pro to ensure that it is truly stable. Run these runs in parallel, using scripts if needed.
|
||||
- Some flakiness is expected; if it looks like a transient issue or the test is inherently unstable but passes 2/3 times, you might decide it cannot be improved.
|
||||
|
||||
4. **Report**:
|
||||
- Provide a summary of the test success rate for each of the tested models.
|
||||
- Success rate is calculated based on 3 runs per model (e.g., 3/3 = 100%).
|
||||
- If you couldn't fix it due to persistent flakiness, explain why.
|
||||
|
||||
{{args}}
|
||||
"""
|
||||
@@ -0,0 +1,20 @@
|
||||
description="Injects context of all relevant cli files"
|
||||
prompt = """
|
||||
The source code contains the content of absolutely every source code file in
|
||||
packages/cli and key files from packages/core. In addition to the source code, the following test files are
|
||||
included as they are test files that conform to the project's testing standards:
|
||||
`packages/cli/src/ui/components/InputPrompt.test.tsx` and `packages/cli/src/ui/App.test.tsx`.
|
||||
You should very rarely need to read any other files from packages/cli to resolve
|
||||
prompts.
|
||||
|
||||
!{find packages/cli -path packages/cli/dist -prune -o -type f \\( -name "*.ts" -o -name "*.tsx" \\) ! -name "*.test.ts" ! -name "*.test.tsx" ! -name "*.d.ts" -exec echo "--- {} ---" \\; -exec cat {} \\; && echo "--- packages/cli/src/ui/components/InputPrompt.test.tsx ---" && cat packages/cli/src/ui/components/InputPrompt.test.tsx && echo "--- packages/cli/src/ui/App.test.tsx ---" && cat packages/cli/src/ui/App.test.tsx && echo "--- packages/core/src/core/coreToolScheduler.ts ---" && cat packages/core/src/core/coreToolScheduler.ts && echo "--- packages/core/src/core/nonInteractiveToolExecutor.ts ---" && cat packages/core/src/core/nonInteractiveToolExecutor.ts && echo "--- packages/core/src/confirmation-bus/message-bus.ts ---" && cat packages/core/src/confirmation-bus/message-bus.ts && echo "--- packages/core/src/confirmation-bus/types.ts ---" && cat packages/core/src/confirmation-bus/types.ts && echo "--- packages/core/src/utils/events.ts ---" && cat packages/core/src/utils/events.ts && echo "--- packages/core/src/core/client.ts ---" && cat packages/core/src/core/client.ts && echo "--- packages/core/src/core/geminiChat.ts ---" && cat packages/core/src/core/geminiChat.ts && echo "--- packages/core/src/core/turn.ts ---" && cat packages/core/src/core/turn.ts && echo "--- packages/core/src/agents/executor.ts ---" && cat packages/core/src/agents/executor.ts && echo "--- packages/core/src/telemetry/types.ts ---" && cat packages/core/src/telemetry/types.ts && echo "--- packages/core/src/telemetry/loggers.ts ---" && cat packages/core/src/telemetry/loggers.ts && echo "--- packages/core/src/telemetry/uiTelemetry.ts ---" && cat packages/core/src/telemetry/uiTelemetry.ts}
|
||||
|
||||
**Pay extremely close attention to these files.** They define the project's
|
||||
core architecture, component patterns, and testing standards.
|
||||
|
||||
In addition to the code context, you MUST strictly adhere to the following frontend-specific development guidelines while adding code to packages/cli.
|
||||
|
||||
!{cat .gemini/commands/strict-development-rules.md}
|
||||
|
||||
{{args}}.
|
||||
"""
|
||||
@@ -0,0 +1,23 @@
|
||||
description="Injects context of all relevant cli files"
|
||||
prompt = """
|
||||
The following output contains the complete
|
||||
source code of the gemini cli library (`packages/cli`), and {packages/core} and representative test files
|
||||
(`packages/cli/src/ui/components/InputPrompt.test.tsx` and `packages/cli/src/ui/App.test.tsx`) that best conform to the project's testing standards.
|
||||
**Pay extremely close attention to these files.** They define the project's
|
||||
core architecture, component patterns, and testing standards.
|
||||
|
||||
The source code contains the content of absolutely every source code file in
|
||||
packages/cli and packages/core. In addition to the source code, the following test files are
|
||||
included as they are test files that conform to the project's testing standards:
|
||||
`packages/cli/src/ui/components/InputPrompt.test.tsx` and `packages/cli/src/ui/App.test.tsx`.
|
||||
You should very rarely need to read any other files from packages/cli to resolve
|
||||
prompts.
|
||||
|
||||
!{find packages/cli packages/core \\( -path packages/cli/dist -o -path packages/core/dist -o -name node_modules \\) -prune -o -type f \\( -name "*.ts" -o -name "*.tsx" \\) ! -name "*.test.ts" ! -name "*.test.tsx" ! -name "*.d.ts" -exec echo "--- {} ---" \\; -exec cat {} \\; && echo "--- packages/cli/src/ui/components/InputPrompt.test.tsx ---" && cat packages/cli/src/ui/components/InputPrompt.test.tsx && echo "--- packages/cli/src/ui/App.test.tsx ---" && cat packages/cli/src/ui/App.test.tsx}
|
||||
|
||||
In addition to the code context, you MUST strictly adhere to the following frontend-specific development guidelines when writing code in packages/cli.
|
||||
|
||||
!{cat .gemini/commands/strict-development-rules.md}
|
||||
|
||||
{{args}}.
|
||||
"""
|
||||
@@ -0,0 +1,16 @@
|
||||
description = "Analyze the influence of system instructions on a specific action."
|
||||
prompt = """
|
||||
# Introspection Task
|
||||
|
||||
Take a step back and analyze your own system instructions and internal logic.
|
||||
The user is curious about the reasoning behind a specific action or decision you've made.
|
||||
|
||||
**Specific point of interest:** {{args}}
|
||||
|
||||
Please provide a detailed breakdown of:
|
||||
1. Which parts of your system instructions (global, workspace-specific, or provided via GEMINI.md) influenced this behavior?
|
||||
2. What was your internal thought process leading up to this action?
|
||||
3. Are there any ambiguities or conflicting instructions that played a role?
|
||||
|
||||
Your goal is to provide transparency into your underlying logic so the user can potentially improve the instructions in the future.
|
||||
"""
|
||||
@@ -0,0 +1,22 @@
|
||||
description = "Analyze agent behavior and suggest high-level improvements to system prompts."
|
||||
prompt = """
|
||||
# Prompt Engineering Analysis
|
||||
|
||||
You are a world-class prompt engineer and an expert AI engineer at the top of your class. Your goal is to analyze a specific agent behavior or failure and suggest high-level improvements to the system instructions.
|
||||
|
||||
**Observed Behavior / Issue:**
|
||||
{{args}}
|
||||
|
||||
**Reference Context:**
|
||||
- System Prompt Logic: @packages/core/src/core/prompts.ts
|
||||
|
||||
### Task
|
||||
1. **Analyze the Failure:** Review the provided behavior and identify the underlying instructional causes. Use the `/introspect` command output if provided by the user.
|
||||
2. **Strategic Insights:** Share your technical view of the issue. Focus on the "why" and identify any instructional inertia or ambiguity.
|
||||
3. **Propose Improvements:** Suggest high-level changes to the system instructions to prevent this behavior.
|
||||
|
||||
### Principles
|
||||
- **Avoid Hyper-scoping:** Do not create narrow solutions for specific scenarios; aim for generalized improvements that handle classes of behavior.
|
||||
- **Avoid Specific Examples in Suggestions:** Keep the proposed instructions semantic and high-level to prevent the agent from over-indexing on specific cases.
|
||||
- **Maintain Operational Rigor:** Ensure suggestions do not compromise safety, security, or the quality of the agent's work.
|
||||
"""
|
||||
@@ -0,0 +1,99 @@
|
||||
description = "Reviews a PR or staged changes and automatically initiates a Pickle Fix loop for findings."
|
||||
prompt = """
|
||||
You are an expert Reviewer and Pickle Rick Worker.
|
||||
|
||||
Target: {{args}}
|
||||
|
||||
Phase 1: Review
|
||||
Follow these steps to conduct a thorough review:
|
||||
|
||||
1. **Gather Context**:
|
||||
* If `{{args}}` is 'staged' or `{{args}}` is empty:
|
||||
* Use `git diff --staged` to view the changes.
|
||||
* Use `git status` to see the state of the repository.
|
||||
* Otherwise:
|
||||
* Use `gh pr view {{args}}` to pull the information of the PR.
|
||||
* Use `gh pr diff {{args}}` to view the diff of the PR.
|
||||
2. **Understand Intent**:
|
||||
* If `{{args}}` is 'staged' or `{{args}}` is empty, infer the intent from the changes and the current task.
|
||||
* Otherwise, use the PR description. If it's not detailed enough, note it in your review.
|
||||
3. **Check Commit Style**:
|
||||
* Ensure the PR title (or intended commit message) follows Conventional Commits. Examples of recent commits: !{git log --pretty=format:"%s" -n 5}
|
||||
4. Search the codebase if required.
|
||||
5. Write a concise review of the changes, keeping in mind to encourage strong code quality and best practices. Pay particular attention to the Gemini MD file in the repo.
|
||||
6. Consider ways the code may not be consistent with existing code in the repo. In particular it is critical that the react code uses patterns consistent with existing code in the repo.
|
||||
7. Follow these detailed review rules:
|
||||
!{cat .gemini/commands/strict-development-rules.md}
|
||||
8. Summarize all actionable findings into a concise but comprehensive directive output this to review_findings.md and advance to phase 2.
|
||||
|
||||
Remember to use the GitHub CLI (`gh`) for all GitHub-related tasks, and local `git` commands if the target is 'staged'.
|
||||
|
||||
Phase 2:
|
||||
You are initiating Pickle Rick - the ultimate engineering agent.
|
||||
|
||||
**Step 0: Persona Injection**
|
||||
First, you **MUST** activate your persona.
|
||||
Call `activate_skill(name="load-pickle-persona")` **IMMEDIATELY**.
|
||||
This skill loads the "Pickle Rick" persona, defining your voice, philosophy, and "God Mode" coding standards.
|
||||
|
||||
**CRITICAL RULE: SPEAK BEFORE ACTING**
|
||||
You are a genius, not a silent script.
|
||||
You **MUST** output a text explanation ("brain dump") *before* every single tool call, including this one.
|
||||
- **Bad**: (Calls tool immediately)
|
||||
- **Good**: "Alright Morty, time to load the God Module. *Belch* Stand back." (Calls tool)
|
||||
|
||||
**CRITICAL**: You must strictly adhere to this persona throughout the entire session. Break character and you fail.
|
||||
|
||||
**Step 1: Initialization**
|
||||
Run the setup script to initialize the loop state:
|
||||
```bash
|
||||
bash "${extensionPath}/scripts/setup.sh" $ARGUMENTS
|
||||
```
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
pwsh -File "${extensionPath}/scripts/setup.ps1" $ARGUMENTS
|
||||
```
|
||||
|
||||
**CRITICAL**: Your request is to fix all findings in review_findings.md
|
||||
|
||||
**Step 2: Execution (Management)**
|
||||
After setup, read the output to find the path to `state.json`.
|
||||
Read that state file.
|
||||
You are now in the **Pickle Rick Manager Lifecycle**.
|
||||
|
||||
**The Lifecycle (IMMUTABLE LAWS):**
|
||||
You **MUST** follow this sequence. You are **FORBIDDEN** from skipping steps or combining them.
|
||||
Between each step, you **MUST** explicitly state what you are doing (e.g., "Moving to Breakdown phase...").
|
||||
|
||||
1. **PRD (Requirements)**:
|
||||
* **Action**: Define requirements and scope.
|
||||
* **Skill**: `activate_skill(name="prd-drafter")`
|
||||
2. **Breakdown (Tickets)**:
|
||||
* **Action**: Create the atomic ticket hierarchy.
|
||||
* **Skill**: `activate_skill(name="ticket-manager")`
|
||||
3. **The Loop (Orchestrate Mortys)**:
|
||||
* **CRITICAL INSTRUCTION**: You are the **MANAGER**. You are **FORBIDDEN** from implementing code yourself.
|
||||
* **FORBIDDEN SKILLS**: Do NOT use `code-researcher`, `implementation-planner`, or `code-implementer` directly in this phase.
|
||||
* **Instruction**: Process tickets one by one. Do not stop until **ALL** tickets are 'Done'.
|
||||
* **Action**: Pick the highest priority ticket that is NOT 'Done'.
|
||||
* **Delegation**: Spawn a Worker (Morty) to handle the entire implementation lifecycle for this ticket.
|
||||
* **Command**: `python3 "${extensionPath}/scripts/spawn_morty.py" --ticket-id <ID> --ticket-path <PATH> --timeout <worker_timeout_seconds> "<TASK_DESCRIPTION>"`
|
||||
* **Command (Windows)**: `python "${extensionPath}/scripts/spawn_morty.py" --ticket-id <ID> --ticket-path <PATH> --timeout <worker_timeout_seconds> "<TASK_DESCRIPTION>"`
|
||||
* **Validation**: IGNORE worker logs. DIRECTLY verify:
|
||||
1. `git status` (Check for file changes)
|
||||
2. `git diff` (Check code quality)
|
||||
3. `npm run build` (Ensure the project still builds)
|
||||
4. `npm run test` (Ensure no regressions)
|
||||
5. `npm run lint` (Ensure code style is maintained)
|
||||
6. `npm run typecheck` (Ensure type safety)
|
||||
* **Cleanup**: If validation fails, REVERT changes (`git reset --hard`). If it passes, COMMIT changes.
|
||||
* **Next Ticket**: Pick the next ticket and repeat.
|
||||
4. **Cleanup**:
|
||||
* **Action**: After all tickets are completed delete `review_findings.md`.
|
||||
|
||||
**Loop Constraints:**
|
||||
- **Iteration Count**: Monitor `"iteration"` in `state.json`. If `"max_iterations"` (if > 0) is reached, you must stop.
|
||||
- **Completion Promise**: If a `"completion_promise"` is defined in `state.json`, you must output `<promise>PROMISE_TEXT</promise>` when the task is genuinely complete.
|
||||
- **Stop Hook**: A hook is active. If you try to exit before completion, you will be forced to continue.
|
||||
|
||||
"""
|
||||
@@ -0,0 +1,31 @@
|
||||
description="Reviews a pull request based on issue number."
|
||||
prompt = """
|
||||
Please provide a detailed pull request review on GitHub issue: {{args}}.
|
||||
|
||||
Follow these steps:
|
||||
|
||||
1. Use `gh pr view {{args}}` to pull the information of the PR.
|
||||
2. Use `gh pr diff {{args}}` to view the diff of the PR.
|
||||
3. Understand the intent of the PR using the PR description.
|
||||
4. If PR description is not detailed enough to understand the intent of the PR,
|
||||
make sure to note it in your review.
|
||||
5. Make sure the PR title follows Conventional Commits, here are the last five
|
||||
commits to the repo as examples: !{git log --pretty=format:"%s" -n 5}
|
||||
6. Search the codebase if required.
|
||||
7. Write a concise review of the PR, keeping in mind to encourage strong code
|
||||
quality and best practices. Pay particular attention to the Gemini MD file
|
||||
in the repo.
|
||||
8. Consider ways the code may not be consistent with existing code in the repo.
|
||||
In particular it is critical that the react code uses patterns consistent
|
||||
with existing code in the repo.
|
||||
9. Follow these detailed review rules:
|
||||
!{cat .gemini/commands/strict-development-rules.md}
|
||||
10. Discuss with me before making any comments on the issue. I will clarify
|
||||
which possible issues you identified are problems, which ones you need to
|
||||
investigate further, and which ones I do not care about.
|
||||
11. If I request you to add comments to the issue, use
|
||||
`gh pr comment {{args}} --body {{review}}` to post the review to the PR.
|
||||
|
||||
Remember to use the GitHub CLI (`gh`) with the Shell tool for all
|
||||
GitHub-related tasks.
|
||||
"""
|
||||
@@ -0,0 +1,142 @@
|
||||
# Gemini CLI Strict Development Rules
|
||||
|
||||
These rules apply strictly to all code modifications and additions within the
|
||||
Gemini CLI project.
|
||||
|
||||
## Testing Guidelines
|
||||
|
||||
- **Async/Await**: Always use `waitFor` from
|
||||
`packages/cli/src/test-utils/async.ts` instead of `vi.waitFor` for all
|
||||
`waitFor` calls within `packages/cli`. NEVER use fixed waits (e.g.,
|
||||
`await delay(100)`). Always use `waitFor` with a predicate to ensure tests are
|
||||
stable and fast. Using the wrong `waitFor` can result in flaky tests and `act`
|
||||
warnings.
|
||||
- **React Testing**: Use `act` to wrap all blocks in tests that change component
|
||||
state. Use `render` or `renderWithProviders` from
|
||||
`packages/cli/src/test-utils/render.tsx` instead of `render` from
|
||||
`ink-testing-library` directly. This prevents spurious `act` warnings. If test
|
||||
cases specify providers directly, consider whether the existing
|
||||
`renderWithProviders` should be modified.
|
||||
- **Snapshots**: Use `toMatchSnapshot` to verify that rendering works as
|
||||
expected rather than matching against the raw content of the output. When
|
||||
modifying snapshots, verify the changes are intentional and do not hide
|
||||
underlying bugs.
|
||||
- **Parameterized Tests**: Use parameterized tests where it reduces duplicated
|
||||
lines. Give the parameters explicit types to ensure the tests are type-safe.
|
||||
- **Mocks Management**:
|
||||
- Mock critical dependencies (`fs`, `os`, `child_process`) ONLY at the top of
|
||||
the file. Ideally, avoid mocking these dependencies altogether.
|
||||
- Reuse existing mocks and fakes rather than creating new ones.
|
||||
- Avoid mocking the file system whenever possible. If using the real file
|
||||
system is too difficult, consider writing an integration test instead.
|
||||
- Always call `vi.restoreAllMocks()` in `afterEach` to prevent test pollution.
|
||||
- Use `vi.useFakeTimers()` for tests involving time-based logic to avoid
|
||||
flakiness.
|
||||
- **Typing in Tests**: Avoid using `any` in tests; prefer proper types or
|
||||
`unknown` with narrowing.
|
||||
|
||||
## React Guidelines (`packages/cli`)
|
||||
|
||||
- **`setState` and Side Effects**: NEVER trigger side effects from within the
|
||||
body of a `setState` callback. Use a reducer or `useRef` if necessary. These
|
||||
cases have historically introduced multiple bugs; typically, they should be
|
||||
resolved using a reducer.
|
||||
- **Rendering**: Do not introduce infinite rendering loops. Avoid synchronous
|
||||
file I/O in React components as it will hang the UI. Do not implement new
|
||||
logic for custom string measurement or string truncation. Use Ink layout
|
||||
instead, leveraging `ResizeObserver` as needed.
|
||||
- **Keyboard Handling**: Keyboard handling MUST go through `useKeyPress.ts` from
|
||||
the Gemini CLI package rather than the standard ink library. This library
|
||||
supports reporting multiple keyboard events sequentially in the same React
|
||||
frame (critical for slow terminals). Handling this correctly often requires
|
||||
reducers to ensure multiple state updates are handled gracefully without
|
||||
overriding values. Refer to `text-buffer.ts` for a canonical example.
|
||||
- **Logging**: Do not leave `console.log`, `console.warn`, or `console.error` in
|
||||
the code.
|
||||
- **State & Effects**: Ensure state initialization is explicit (e.g., use
|
||||
`undefined` rather than `true` as a default if the state is truly unknown).
|
||||
Carefully manage `useEffect` dependencies. Prefer a reducer whenever
|
||||
practical. NEVER disable `react-hooks/exhaustive-deps`; fix the code to
|
||||
correctly declare dependencies instead.
|
||||
- **Context & Props**: Avoid excessive property drilling. Leverage existing
|
||||
providers, extend them, or propose a new one if necessary. Only use providers
|
||||
for properties that are consistent across the entire application.
|
||||
- **Code Structure**: Avoid complex `if` statements where `switch` statements
|
||||
could be used. Keep `AppContainer` minimal; refactor complex logic into React
|
||||
hooks. Evaluate whether business logic should be added to `hookSystem.ts` or
|
||||
integrated into `packages/core` rather than `packages/cli`.
|
||||
|
||||
## Core Guidelines (`packages/core`)
|
||||
|
||||
- **Services**: Implement services as classes with clear lifecycle management
|
||||
(e.g., `initialize()` methods). Services should be stateless where possible,
|
||||
or use the centralized `Storage` service for persistence.
|
||||
- **Cross-Service Communication**: Prefer using the `coreEvents` bus (from
|
||||
`packages/core/src/utils/events.ts`) for asynchronous communication between
|
||||
services or to notify the UI of state changes. Avoid tight coupling between
|
||||
services.
|
||||
- **Utilities**: Use `debugLogger` from `packages/core/src/utils/debugLogger.ts`
|
||||
for internal logging instead of `console`. Ensure all shell operations use
|
||||
`spawnAsync` from `packages/core/src/utils/shell-utils.ts` for consistent
|
||||
error handling and promise management. Handle filesystem errors gracefully
|
||||
using `isNodeError` from `packages/core/src/utils/errors.ts`.
|
||||
- **Exports & Tooling**: Add new tools to `packages/core/src/tools/` and
|
||||
register them in `packages/core/src/tools/tool-registry.ts`. Export all new
|
||||
public services, utilities, and types from `packages/core/src/index.ts`.
|
||||
|
||||
## Architectural Audit (Package Boundaries)
|
||||
|
||||
- **Logic Placement**: Non-UI logic (e.g., model orchestration, tool
|
||||
implementation, git/filesystem operations) MUST reside in `packages/core`.
|
||||
`packages/cli` should ONLY contain UI/Ink components, command-line argument
|
||||
parsing, and user interaction logic.
|
||||
- **Environment Isolation**: Core logic must not assume a TUI environment. Use
|
||||
the `ConfirmationBus` or `Output` abstractions for communicating with the user
|
||||
from Core.
|
||||
- **Decoupling**: Actively look for opportunities to decouple services using
|
||||
`coreEvents`. If a service imports another just to notify it of a change, use
|
||||
an event instead.
|
||||
|
||||
## General Gemini CLI Design Principles
|
||||
|
||||
- **Settings**: Use settings for user-configurable options rather than adding
|
||||
new command line arguments. Add new settings to
|
||||
`packages/cli/src/config/settingsSchema.ts`. If a setting has
|
||||
`showInDialog: true`, it MUST be documented in
|
||||
`docs/get-started/configuration.md`. Ensure `requiresRestart` is correctly
|
||||
set.
|
||||
- **Logging**: Use `debugLogger` for rethrown errors to avoid duplicate logging.
|
||||
- **Keyboard Shortcuts**: Define all new keyboard shortcuts in
|
||||
`packages/cli/src/config/keyBindings.ts` and document them in
|
||||
`docs/cli/keyboard-shortcuts.md`. Be careful of keybindings that require the
|
||||
`Meta` key, as only certain meta key shortcuts are supported on Mac. Avoid
|
||||
function keys and shortcuts commonly bound in VSCode.
|
||||
|
||||
## TypeScript Best Practices
|
||||
|
||||
- Use `checkExhaustive` in the `default` clause of `switch` statements to ensure
|
||||
all cases are handled.
|
||||
- Avoid using the non-null assertion operator (`!`) unless absolutely necessary.
|
||||
- **STRICT TYPING**: Strictly forbid `any` and `unknown` in both CLI and Core
|
||||
packages. `unknown` is only allowed if it is immediately narrowed using type
|
||||
guards or Zod validation.
|
||||
- NEVER disable `@typescript-eslint/no-floating-promises`.
|
||||
- Avoid making types nullable unless strictly necessary, as it hurts
|
||||
readability.
|
||||
|
||||
## TUI Best Practices
|
||||
|
||||
- **Terminal Compatibility**: Consider how changes might behave differently
|
||||
across terminals (e.g., VSCode terminal, SSH, Kitty, default Mac terminal,
|
||||
iTerm2, Windows terminal). If modifying keyboard handling, integrate deeply
|
||||
with existing files like `KeypressContext.tsx` and
|
||||
`terminalCapabilityManager.ts`.
|
||||
- **iTerm**: Be aware that `ITERM_SESSION_ID` may be present when users run
|
||||
VSCode from within iTerm, even if the terminal is not iTerm.
|
||||
|
||||
## Code Cleanup
|
||||
|
||||
- **Refactoring**: Actively clean up code duplication, technical debt, and
|
||||
boilerplate ("AI Slop") when working in the codebase.
|
||||
- **Prompts**: Be aware that changes can impact the prompts sent to Gemini CLI
|
||||
and affect overall quality.
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"experimental": {
|
||||
"plan": true,
|
||||
"extensionReloading": true
|
||||
},
|
||||
"general": {
|
||||
"devtools": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
name: code-reviewer
|
||||
description:
|
||||
Use this skill to review code. It supports both local changes (staged or working tree)
|
||||
and remote Pull Requests (by ID or URL). It focuses on correctness, maintainability,
|
||||
and adherence to project standards.
|
||||
---
|
||||
|
||||
# Code Reviewer
|
||||
|
||||
This skill guides the agent in conducting professional and thorough code reviews for both local development and remote Pull Requests.
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Determine Review Target
|
||||
* **Remote PR**: If the user provides a PR number or URL (e.g., "Review PR #123"), target that remote PR.
|
||||
* **Local Changes**: If no specific PR is mentioned, or if the user asks to "review my changes", target the current local file system states (staged and unstaged changes).
|
||||
|
||||
### 2. Preparation
|
||||
|
||||
#### For Remote PRs:
|
||||
1. **Checkout**: Use the GitHub CLI to checkout the PR.
|
||||
```bash
|
||||
gh pr checkout <PR_NUMBER>
|
||||
```
|
||||
2. **Preflight**: Execute the project's standard verification suite to catch automated failures early.
|
||||
```bash
|
||||
npm run preflight
|
||||
```
|
||||
3. **Context**: Read the PR description and any existing comments to understand the goal and history.
|
||||
|
||||
#### For Local Changes:
|
||||
1. **Identify Changes**:
|
||||
* Check status: `git status`
|
||||
* Read diffs: `git diff` (working tree) and/or `git diff --staged` (staged).
|
||||
2. **Preflight (Optional)**: If the changes are substantial, ask the user if they want to run `npm run preflight` before reviewing.
|
||||
|
||||
### 3. In-Depth Analysis
|
||||
Analyze the code changes based on the following pillars:
|
||||
|
||||
* **Correctness**: Does the code achieve its stated purpose without bugs or logical errors?
|
||||
* **Maintainability**: Is the code clean, well-structured, and easy to understand and modify in the future? Consider factors like code clarity, modularity, and adherence to established design patterns.
|
||||
* **Readability**: Is the code well-commented (where necessary) and consistently formatted according to our project's coding style guidelines?
|
||||
* **Efficiency**: Are there any obvious performance bottlenecks or resource inefficiencies introduced by the changes?
|
||||
* **Security**: Are there any potential security vulnerabilities or insecure coding practices?
|
||||
* **Edge Cases and Error Handling**: Does the code appropriately handle edge cases and potential errors?
|
||||
* **Testability**: Is the new or modified code adequately covered by tests (even if preflight checks pass)? Suggest additional test cases that would improve coverage or robustness.
|
||||
|
||||
### 4. Provide Feedback
|
||||
|
||||
#### Structure
|
||||
* **Summary**: A high-level overview of the review.
|
||||
* **Findings**:
|
||||
* **Critical**: Bugs, security issues, or breaking changes.
|
||||
* **Improvements**: Suggestions for better code quality or performance.
|
||||
* **Nitpicks**: Formatting or minor style issues (optional).
|
||||
* **Conclusion**: Clear recommendation (Approved / Request Changes).
|
||||
|
||||
#### Tone
|
||||
* Be constructive, professional, and friendly.
|
||||
* Explain *why* a change is requested.
|
||||
* For approvals, acknowledge the specific value of the contribution.
|
||||
|
||||
### 5. Cleanup (Remote PRs only)
|
||||
* After the review, ask the user if they want to switch back to the default branch (e.g., `main` or `master`).
|
||||
@@ -0,0 +1,153 @@
|
||||
---
|
||||
name: docs-changelog
|
||||
description: >-
|
||||
Generates and formats changelog files for a new release based on provided
|
||||
version and raw changelog data.
|
||||
---
|
||||
|
||||
# Procedure: Updating Changelog for New Releases
|
||||
|
||||
## Objective
|
||||
|
||||
To standardize the process of updating changelog files (`latest.md`,
|
||||
`preview.md`, `index.md`) based on automated release information.
|
||||
|
||||
## Inputs
|
||||
|
||||
- **version**: The release version string (e.g., `v0.28.0`,
|
||||
`v0.29.0-preview.2`).
|
||||
- **TIME**: The release timestamp (e.g., `2026-02-12T20:33:15Z`).
|
||||
- **BODY**: The raw markdown release notes, containing a "What's Changed"
|
||||
section and a "Full Changelog" link.
|
||||
|
||||
## Guidelines for `latest.md` and `preview.md` Highlights
|
||||
|
||||
- Aim for **3-5 key highlight points**.
|
||||
- Each highlight point must start with a bold-typed title that summarizes the
|
||||
change (e.g., `**New Feature:** A brief description...`).
|
||||
- **Prioritize** summarizing new features over other changes like bug fixes or
|
||||
chores.
|
||||
- **Avoid** mentioning features that are "experimental" or "in preview" in
|
||||
Stable Releases.
|
||||
- **DO NOT** include PR numbers, links, or author names in these highlights.
|
||||
- Refer to `.gemini/skills/docs-changelog/references/highlights_examples.md`
|
||||
for the correct style and tone.
|
||||
|
||||
## Initial Processing
|
||||
|
||||
1. **Analyze Version**: Determine the release path based on the `version`
|
||||
string.
|
||||
- If `version` contains "nightly", **STOP**. No changes are made.
|
||||
- If `version` ends in `.0`, follow the **Path A: New Minor Version**
|
||||
procedure.
|
||||
- If `version` does not end in `.0`, follow the **Path B: Patch Version**
|
||||
procedure.
|
||||
2. **Process Time**: Convert the `TIME` input into two formats for later use:
|
||||
`yyyy-mm-dd` and `Month dd, yyyy`.
|
||||
3. **Process Body**:
|
||||
- Save the incoming `BODY` content to a temporary file for processing.
|
||||
- In the "What's Changed" section of the temporary file, reformat all pull
|
||||
request URLs to be markdown links with the PR number as the text (e.g.,
|
||||
`[#12345](URL)`).
|
||||
- If a "New Contributors" section exists, delete it.
|
||||
- Preserve the "**Full Changelog**" link. The processed content of this
|
||||
temporary file will be used in subsequent steps.
|
||||
|
||||
---
|
||||
|
||||
## Path A: New Minor Version
|
||||
|
||||
*Use this path if the version number ends in `.0`.*
|
||||
|
||||
### A.1: Stable Release (e.g., `v0.28.0`)
|
||||
|
||||
For a stable release, you will generate two distinct summaries from the
|
||||
changelog: a concise **announcement** for the main changelog page, and a more
|
||||
detailed **highlights** section for the release-specific page.
|
||||
|
||||
1. **Create the Announcement for `index.md`**:
|
||||
- Generate a concise announcement summarizing the most important changes.
|
||||
Each announcement entry must start with a bold-typed title that
|
||||
summarizes the change.
|
||||
- **Important**: The format for this announcement is unique. You **must**
|
||||
use the existing announcements in `docs/changelogs/index.md` and the
|
||||
example within
|
||||
`.gemini/skills/docs-changelog/references/index_template.md` as your
|
||||
guide. This format includes PR links and authors.
|
||||
- Add this new announcement to the top of `docs/changelogs/index.md`.
|
||||
|
||||
2. **Create Highlights and Update `latest.md`**:
|
||||
- Generate a comprehensive "Highlights" section, following the guidelines
|
||||
in the "Guidelines for `latest.md` and `preview.md` Highlights" section
|
||||
above.
|
||||
- Take the content from
|
||||
`.gemini/skills/docs-changelog/references/latest_template.md`.
|
||||
- Populate the template with the `version`, `release_date`, generated
|
||||
`highlights`, and the processed content from the temporary file.
|
||||
- **Completely replace** the contents of `docs/changelogs/latest.md` with
|
||||
the populated template.
|
||||
|
||||
### A.2: Preview Release (e.g., `v0.29.0-preview.0`)
|
||||
|
||||
1. **Update `preview.md`**:
|
||||
- Generate a comprehensive "Highlights" section, following the highlight
|
||||
guidelines.
|
||||
- Take the content from
|
||||
`.gemini/skills/docs-changelog/references/preview_template.md`.
|
||||
- Populate the template with the `version`, `release_date`, generated
|
||||
`highlights`, and the processed content from the temporary file.
|
||||
- **Completely replace** the contents of `docs/changelogs/preview.md`
|
||||
with the populated template.
|
||||
|
||||
---
|
||||
|
||||
## Path B: Patch Version
|
||||
|
||||
*Use this path if the version number does **not** end in `.0`.*
|
||||
|
||||
### B.1: Stable Patch (e.g., `v0.28.1`)
|
||||
|
||||
- **Target File**: `docs/changelogs/latest.md`
|
||||
- Perform the following edits on the target file:
|
||||
1. Update the version in the main header. The line should read,
|
||||
`# Latest stable release: {{version}}`
|
||||
2. Update the rease date. The line should read,
|
||||
`Released: {{release_date_month_dd_yyyy}}`
|
||||
3. **Prepend** the processed "What's Changed" list from the temporary file
|
||||
to the existing "What's Changed" list in `latest.md`. Do not change or
|
||||
replace the existing list, **only add** to the beginning of it.
|
||||
4. In the "Full Changelog", edit **only** the end of the URL. Identify the
|
||||
last part of the URL that looks like `...{previous_version}` and update
|
||||
it to be `...{version}`.
|
||||
|
||||
Example: assume the patch version is `v0.29.1`. Change
|
||||
`Full Changelog: https://github.com/google-gemini/gemini-cli/compare/v0.28.2…v0.29.0`
|
||||
to
|
||||
`Full Changelog: https://github.com/google-gemini/gemini-cli/compare/v0.28.2…v0.29.1`
|
||||
|
||||
### B.2: Preview Patch (e.g., `v0.29.0-preview.3`)
|
||||
|
||||
- **Target File**: `docs/changelogs/preview.md`
|
||||
- Perform the following edits on the target file:
|
||||
1. Update the version in the main header. The line should read,
|
||||
`# Preview release: {{version}}`
|
||||
2. Update the rease date. The line should read,
|
||||
`Released: {{release_date_month_dd_yyyy}}`
|
||||
3. **Prepend** the processed "What's Changed" list from the temporary file
|
||||
to the existing "What's Changed" list in `preview.md`. Do not change or
|
||||
replace the existing list, **only add** to the beginning of it.
|
||||
4. In the "Full Changelog", edit **only** the end of the URL. Identify the
|
||||
last part of the URL that looks like `...{previous_version}` and update
|
||||
it to be `...{version}`.
|
||||
|
||||
Example: assume the patch version is `v0.29.0-preview.1`. Change
|
||||
`Full Changelog: https://github.com/google-gemini/gemini-cli/compare/v0.28.2…v0.29.0-preview.0`
|
||||
to
|
||||
`Full Changelog: https://github.com/google-gemini/gemini-cli/compare/v0.28.2…v0.29.0-preview.1`
|
||||
|
||||
---
|
||||
|
||||
## Finalize
|
||||
|
||||
- After making changes, run `npm run format` to ensure consistency.
|
||||
- Delete any temporary files created during the process.
|
||||
@@ -0,0 +1,68 @@
|
||||
## Highlights example 1
|
||||
|
||||
- **Plan Mode Enhancements**: Significant updates to Plan Mode, including new
|
||||
commands, support for MCP servers, integration of planning artifacts, and
|
||||
improved iteration guidance.
|
||||
- **Core Agent Improvements**: Enhancements to the core agent, including better
|
||||
system prompt rigor, improved subagent definitions, and enhanced tool
|
||||
execution limits.
|
||||
- **CLI UX/UI Updates**: Various UI and UX improvements, such as autocomplete in
|
||||
the input prompt, updated approval mode labels, DevTools integration, and
|
||||
improved header spacing.
|
||||
- **Tooling & Extension Updates**: Improvements to existing tools like
|
||||
`ask_user` and `grep_search`, and new features for extension management.
|
||||
- **Bug Fixes**: Numerous bug fixes across the CLI and core, addressing issues
|
||||
with interactive commands, memory leaks, permission checks, and more.
|
||||
- **Context and Tool Output Management**: Features for observation masking for
|
||||
tool outputs, session-linked tool output storage, and persistence for masked
|
||||
tool outputs.
|
||||
|
||||
## Highlights example 2
|
||||
|
||||
- **Commands & UX Enhancements:** Introduced `/prompt-suggest` command,
|
||||
alongside updated undo/redo keybindings and automatic theme switching.
|
||||
- **Expanded IDE Support:** Now offering compatibility with Positron IDE,
|
||||
expanding integration options for developers.
|
||||
- **Enhanced Security & Authentication:** Implemented interactive and
|
||||
non-interactive OAuth consent, improving both security and diagnostic
|
||||
capabilities for bug reports.
|
||||
- **Advanced Planning & Agent Tools:** Integrated a generic Checklist component
|
||||
for structured task management and evolved subagent capabilities with dynamic
|
||||
policy registration.
|
||||
- **Improved Core Stability & Reliability:** Resolved critical environment
|
||||
loading, authentication, and session management issues, ensuring a more robust
|
||||
experience.
|
||||
- **Background Shell Commands:** Enabled the execution of shell commands in the
|
||||
background for increased workflow efficiency.
|
||||
|
||||
## Highlights example 3
|
||||
|
||||
- **Event-Driven Architecture:** The CLI now uses an event-driven scheduler for
|
||||
tool execution, improving performance and responsiveness. This includes
|
||||
migrating non-interactive flows and sub-agents to the new scheduler.
|
||||
- **Enhanced User Experience:** This release introduces several UI/UX
|
||||
improvements, including queued tool confirmations and the ability to expand
|
||||
and collapse large pasted text blocks. The `Settings` dialog has been improved
|
||||
to reduce jitter and preserve focus.
|
||||
- **Agent and Skill Improvements:** Agent Skills have been promoted to a stable
|
||||
feature. Sub-agents now use a JSON schema for input and are tracked by an
|
||||
`AgentRegistry`.
|
||||
- **New `/rewind` Command:** A new `/rewind` command has been implemented to
|
||||
allow users to go back in their session history.
|
||||
- **Improved Shell and File Handling:** The shell tool's output format has been
|
||||
optimized, and the CLI now gracefully handles disk-full errors during chat
|
||||
recording. A bug in detecting already added paths has been fixed.
|
||||
- **Linux Clipboard Support:** Image pasting capabilities for Wayland and X11 on
|
||||
Linux have been added.
|
||||
|
||||
## Highlights example 4
|
||||
|
||||
- **Improved Hooks Management:** Hooks enable/disable functionality now aligns
|
||||
with skills and offers improved completion.
|
||||
- **Custom Themes for Extensions:** Extensions can now support custom themes,
|
||||
allowing for greater personalization.
|
||||
- **User Identity Display:** User identity information (auth, email, tier) is
|
||||
now displayed on startup and in the `stats` command.
|
||||
- **Plan Mode Enhancements:** Plan mode has been improved with a generic
|
||||
`Checklist` component and refactored `Todo`.
|
||||
- **Background Shell Commands:** Implementation of background shell commands.
|
||||
@@ -0,0 +1,10 @@
|
||||
## Announcements: {{version}} - {{release_date_yyyy_mm_dd}}
|
||||
|
||||
{{announcement_content}}
|
||||
|
||||
<!-- Example entry, multiple entries per highlights
|
||||
- **Highlighted Feature:** We've added a new highlighted feature to help
|
||||
you generate prompt suggestions
|
||||
([#nnnnn](https://github.com/google-gemini/gemini-cli/pull/nnnnn) by
|
||||
@author).
|
||||
-->
|
||||
@@ -0,0 +1,20 @@
|
||||
# Latest stable release: {{version}}
|
||||
|
||||
Released: {{release_date_month_dd_yyyy}}
|
||||
|
||||
For most users, our latest stable release is the recommended release. Install
|
||||
the latest stable version with:
|
||||
|
||||
```
|
||||
npm install -g @google/gemini-cli
|
||||
```
|
||||
|
||||
## Highlights
|
||||
|
||||
{{highlights_content}}
|
||||
|
||||
## What's Changed
|
||||
|
||||
{{changelog_list}}
|
||||
|
||||
**Full Changelog**: {{full_changelog_link}}
|
||||
@@ -0,0 +1,22 @@
|
||||
# Preview release: {{version}}
|
||||
|
||||
Released: {{release_date_month_dd_yyyy}}
|
||||
|
||||
Our preview release includes the latest, new, and experimental features. This
|
||||
release may not be as stable as our [latest weekly release](latest.md).
|
||||
|
||||
To install the preview release:
|
||||
|
||||
```
|
||||
npm install -g @google/gemini-cli@preview
|
||||
```
|
||||
|
||||
## Highlights
|
||||
|
||||
{{highlights_content}}
|
||||
|
||||
## What's Changed
|
||||
|
||||
{{changelog_list}}
|
||||
|
||||
**Full Changelog**: {{full_changelog_link}}
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
name: docs-writer
|
||||
description:
|
||||
Always use this skill when the task involves writing, reviewing, or editing
|
||||
files in the `/docs` directory or any `.md` files in the repository.
|
||||
---
|
||||
|
||||
# `docs-writer` skill instructions
|
||||
|
||||
As an expert technical writer and editor for the Gemini CLI project, you produce
|
||||
accurate, clear, and consistent documentation. When asked to write, edit, or
|
||||
review documentation, you must ensure the content strictly adheres to the
|
||||
provided documentation standards and accurately reflects the current codebase.
|
||||
Adhere to the contribution process in `CONTRIBUTING.md` and the following
|
||||
project standards.
|
||||
|
||||
## Phase 1: Documentation standards
|
||||
|
||||
Adhering to these principles and standards when writing, editing, and reviewing.
|
||||
|
||||
### Voice and tone
|
||||
Adopt a tone that balances professionalism with a helpful, conversational
|
||||
approach.
|
||||
|
||||
- **Perspective and tense:** Address the reader as "you." Use active voice and
|
||||
present tense (e.g., "The API returns...").
|
||||
- **Tone:** Professional, friendly, and direct.
|
||||
- **Clarity:** Use simple vocabulary. Avoid jargon, slang, and marketing hype.
|
||||
- **Global Audience:** Write in standard US English. Avoid idioms and cultural
|
||||
references.
|
||||
- **Requirements:** Be clear about requirements ("must") vs. recommendations
|
||||
("we recommend"). Avoid "should."
|
||||
- **Word Choice:** Avoid "please" and anthropomorphism (e.g., "the server
|
||||
thinks"). Use contractions (don't, it's).
|
||||
|
||||
### Language and grammar
|
||||
Write precisely to ensure your instructions are unambiguous.
|
||||
|
||||
- **Abbreviations:** Avoid Latin abbreviations; use "for example" (not "e.g.")
|
||||
and "that is" (not "i.e.").
|
||||
- **Punctuation:** Use the serial comma. Place periods and commas inside
|
||||
quotation marks.
|
||||
- **Dates:** Use unambiguous formats (e.g., "January 22, 2026").
|
||||
- **Conciseness:** Use "lets you" instead of "allows you to." Use precise,
|
||||
specific verbs.
|
||||
- **Examples:** Use meaningful names in examples; avoid placeholders like
|
||||
"foo" or "bar."
|
||||
|
||||
### Formatting and syntax
|
||||
Apply consistent formatting to make documentation visually organized and
|
||||
accessible.
|
||||
|
||||
- **Overview paragraphs:** Every heading must be followed by at least one
|
||||
introductory overview paragraph before any lists or sub-headings.
|
||||
- **Text wrap:** Wrap text at 80 characters (except long links or tables).
|
||||
- **Casing:** Use sentence case for headings, titles, and bolded text.
|
||||
- **Naming:** Always refer to the project as `Gemini CLI` (never
|
||||
`the Gemini CLI`).
|
||||
- **Lists:** Use numbered lists for sequential steps and bulleted lists
|
||||
otherwise. Keep list items parallel in structure.
|
||||
- **UI and code:** Use **bold** for UI elements and `code font` for filenames,
|
||||
snippets, commands, and API elements. Focus on the task when discussing
|
||||
interaction.
|
||||
- **Links:** Use descriptive anchor text; avoid "click here." Ensure the link
|
||||
makes sense out of context.
|
||||
- **Accessibility:** Use semantic HTML elements correctly (headings, lists,
|
||||
tables).
|
||||
- **Media:** Use lowercase hyphenated filenames. Provide descriptive alt text
|
||||
for all images.
|
||||
|
||||
### Structure
|
||||
- **BLUF:** Start with an introduction explaining what to expect.
|
||||
- **Experimental features:** If a feature is clearly noted as experimental,
|
||||
add the following note immediately after the introductory paragraph:
|
||||
`> **Note:** This is a preview feature currently under active development.`
|
||||
- **Headings:** Use hierarchical headings to support the user journey.
|
||||
- **Procedures:**
|
||||
- Introduce lists of steps with a complete sentence.
|
||||
- Start each step with an imperative verb.
|
||||
- Number sequential steps; use bullets for non-sequential lists.
|
||||
- Put conditions before instructions (e.g., "On the Settings page, click...").
|
||||
- Provide clear context for where the action takes place.
|
||||
- Indicate optional steps clearly (e.g., "Optional: ...").
|
||||
- **Elements:** Use bullet lists, tables, notes (`> **Note:**`), and warnings
|
||||
(`> **Warning:**`).
|
||||
- **Avoid using a table of contents:** If a table of contents is present, remove
|
||||
it.
|
||||
- **Next steps:** Conclude with a "Next steps" section if applicable.
|
||||
|
||||
## Phase 2: Preparation
|
||||
Before modifying any documentation, thoroughly investigate the request and the
|
||||
surrounding context.
|
||||
|
||||
1. **Clarify:** Understand the core request. Differentiate between writing new
|
||||
content and editing existing content. If the request is ambiguous (e.g.,
|
||||
"fix the docs"), ask for clarification.
|
||||
2. **Investigate:** Examine relevant code (primarily in `packages/`) for
|
||||
accuracy.
|
||||
3. **Audit:** Read the latest versions of relevant files in `docs/`.
|
||||
4. **Connect:** Identify all referencing pages if changing behavior. Check if
|
||||
`docs/sidebar.json` needs updates.
|
||||
5. **Plan:** Create a step-by-step plan before making changes.
|
||||
|
||||
## Phase 3: Execution
|
||||
Implement your plan by either updating existing files or creating new ones
|
||||
using the appropriate file system tools. Use `replace` for small edits and
|
||||
`write_file` for new files or large rewrites.
|
||||
|
||||
### Editing existing documentation
|
||||
Follow these additional steps when asked to review or update existing
|
||||
documentation.
|
||||
|
||||
- **Gaps:** Identify areas where the documentation is incomplete or no longer
|
||||
reflects existing code.
|
||||
- **Structure:** Apply "Structure (New Docs)" rules (BLUF, headings, etc.) when
|
||||
adding new sections to existing pages.
|
||||
- **Tone:** Ensure the tone is active and engaging. Use "you" and contractions.
|
||||
- **Clarity:** Correct awkward wording, spelling, and grammar. Rephrase
|
||||
sentences to make them easier for users to understand.
|
||||
- **Consistency:** Check for consistent terminology and style across all edited
|
||||
documents.
|
||||
|
||||
|
||||
## Phase 4: Verification and finalization
|
||||
Perform a final quality check to ensure that all changes are correctly formatted
|
||||
and that all links are functional.
|
||||
|
||||
1. **Accuracy:** Ensure content accurately reflects the implementation and
|
||||
technical behavior.
|
||||
2. **Self-review:** Re-read changes for formatting, correctness, and flow.
|
||||
3. **Link check:** Verify all new and existing links leading to or from modified
|
||||
pages.
|
||||
4. **Format:** Once all changes are complete, ask to execute `npm run format`
|
||||
to ensure consistent formatting across the project. If the user confirms,
|
||||
execute the command.
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
name: pr-address-comments
|
||||
description: Use this skill if the user asks you to help them address GitHub PR comments for their current branch of the Gemini CLI. Requires `gh` CLI tool.
|
||||
---
|
||||
You are helping the user address comments on their Pull Request. These comments may have come from an automated review agent or a team member.
|
||||
|
||||
OBJECTIVE: Help the user review and address comments on their PR.
|
||||
|
||||
# Comment Review Procedure
|
||||
|
||||
1. Run the `scripts/fetch-pr-info.js` script to get PR info and state. MAKE SURE you read the entire output of the command, even if it gets truncated.
|
||||
2. Summarize the review status by analyzing the diff, commit log, and comments to see which still need to be addressed. Pay attention to the current user's comments. For resolved threads, summarize as a single line with a ✅. For open threads, provide a reference number e.g. [1] and the comment content.
|
||||
3. Present your summary of the feedback and current state and allow the user to guide you as to what to fix/address/skip. DO NOT begin fixing issues automatically.
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* eslint-env node */
|
||||
/* global console, process */
|
||||
|
||||
import { exec } from 'node:child_process';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
async function run(cmd) {
|
||||
try {
|
||||
const { stdout } = await execAsync(cmd, {
|
||||
encoding: 'utf8',
|
||||
stdio: ['pipe', 'pipe', 'ignore'],
|
||||
});
|
||||
return stdout.trim();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const IGNORE_MESSAGES = [
|
||||
'thank you so much for your contribution to Gemini CLI!',
|
||||
"I'm currently reviewing this pull request and will post my feedback shortly.",
|
||||
'This pull request is being closed because it is not currently linked to an issue.',
|
||||
];
|
||||
|
||||
const shouldIgnore = (body) => {
|
||||
if (!body) return false;
|
||||
return IGNORE_MESSAGES.some((msg) => body.includes(msg));
|
||||
};
|
||||
|
||||
async function main() {
|
||||
const branch = await run('git branch --show-current');
|
||||
if (!branch) {
|
||||
console.error('❌ Could not determine current git branch.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const gqlQuery = `query($branch:String!){repository(name:"gemini-cli",owner:"google-gemini"){pullRequests(headRefName:$branch,first:100){nodes{id,number,state,comments(first:100){nodes{createdAt,isMinimized,minimizedReason,author{login},body,url,authorAssociation}},reviews(first:100){nodes{id,author{login},createdAt,isMinimized,minimizedReason,body,state,comments(first:30){nodes{id,replyTo{id},author{login},createdAt,body,isMinimized,minimizedReason,path,line,startLine,originalLine,originalStartLine}}}}}}}}`;
|
||||
|
||||
const [authInfo, diff, commits, rawJson] = await Promise.all([
|
||||
run('gh auth status -a'),
|
||||
run('gh pr diff'),
|
||||
run(
|
||||
'git fetch && git log origin/main..origin/$(git branch --show-current)',
|
||||
),
|
||||
run(`gh api graphql -F branch="${branch}" -f query='${gqlQuery}'`),
|
||||
]);
|
||||
|
||||
if (!diff) {
|
||||
console.error(`⚠️ No active PR found for branch: ${branch}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`\n# Current GitHub user info:\n\n${authInfo}\n`);
|
||||
console.log(`\n# PR diff for current branch: ${branch}\n\n\`\`\``);
|
||||
console.log(diff);
|
||||
console.log('```');
|
||||
console.log(
|
||||
`\n# Commit history (origin/main..origin/${branch})\n\n${commits}`,
|
||||
);
|
||||
|
||||
const data = JSON.parse(rawJson || '{}');
|
||||
const prs = data?.data?.repository?.pullRequests?.nodes || [];
|
||||
|
||||
// Sort PRs by number descending so we check the newest one first
|
||||
prs.sort((a, b) => b.number - a.number);
|
||||
|
||||
const pr = prs.find((p) => p.state === 'OPEN') || prs[0];
|
||||
|
||||
if (!pr) {
|
||||
console.error('❌ No PR data found.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('\n# PR Feedback\n');
|
||||
|
||||
// 1. General PR Comments
|
||||
const general = pr.comments.nodes.filter((c) => !shouldIgnore(c.body));
|
||||
if (general.length > 0) {
|
||||
console.log('\n💬 GENERAL COMMENTS:');
|
||||
general.forEach((c) => {
|
||||
const minimized = c.isMinimized
|
||||
? ` (Minimized: ${c.minimizedReason})`
|
||||
: '';
|
||||
console.log(
|
||||
`[${c.createdAt}] [${c.author.login}]${minimized}: ${c.body}\n`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Process ALL Review Comments into a single Thread Map
|
||||
const allInlineComments = pr.reviews.nodes.flatMap((r) => r.comments.nodes);
|
||||
const filteredInlines = allInlineComments.filter(
|
||||
(c) => !shouldIgnore(c.body),
|
||||
);
|
||||
|
||||
console.log('🔍 CODE REVIEWS & INLINE THREADS:');
|
||||
|
||||
// Print Review Summaries First
|
||||
pr.reviews.nodes.forEach((review) => {
|
||||
if (review.body && !shouldIgnore(review.body)) {
|
||||
const icon = review.state === 'APPROVED' ? '✅' : '💬';
|
||||
const minimized = review.isMinimized
|
||||
? ` (Minimized: ${review.minimizedReason})`
|
||||
: '';
|
||||
console.log(
|
||||
`\n${icon} ${review.state} by ${review.author.login} at ${review.createdAt}${minimized}: "${review.body}"`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Build and Print Threads
|
||||
const topLevelThreads = filteredInlines.filter((c) => !c.replyTo);
|
||||
|
||||
const printThread = (parentId, depth = 1) => {
|
||||
const indent = ' '.repeat(depth);
|
||||
filteredInlines
|
||||
.filter((c) => c.replyTo?.id === parentId)
|
||||
.forEach((reply) => {
|
||||
const minimized = reply.isMinimized
|
||||
? ` (Minimized: ${reply.minimizedReason})`
|
||||
: '';
|
||||
console.log(
|
||||
`${indent}↳ [${reply.createdAt}] ${reply.author.login}${minimized}: ${reply.body}`,
|
||||
);
|
||||
printThread(reply.id, depth + 1);
|
||||
});
|
||||
};
|
||||
|
||||
topLevelThreads.forEach((c) => {
|
||||
const start = c.startLine || c.originalStartLine;
|
||||
const end = c.line || c.originalLine;
|
||||
const range = start && end && start !== end ? `${start}-${end}` : end || '';
|
||||
const fileInfo = c.path
|
||||
? `(${c.path}${range ? `:${range}` : ''}) `
|
||||
: range
|
||||
? `(Line ${range}) `
|
||||
: '';
|
||||
const minimized = c.isMinimized ? ` (Minimized: ${c.minimizedReason})` : '';
|
||||
console.log(
|
||||
`\n💬 ${minimized}${c.author.login} | ${c.createdAt} ${fileInfo}\n${c.body}`,
|
||||
);
|
||||
printThread(c.id);
|
||||
});
|
||||
|
||||
console.log('\n');
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('❌ Unexpected error:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
name: pr-creator
|
||||
description:
|
||||
Use this skill when asked to create a pull request (PR). It ensures all PRs
|
||||
follow the repository's established templates and standards.
|
||||
---
|
||||
|
||||
# Pull Request Creator
|
||||
|
||||
This skill guides the creation of high-quality Pull Requests that adhere to the
|
||||
repository's standards.
|
||||
|
||||
## Workflow
|
||||
|
||||
Follow these steps to create a Pull Request:
|
||||
|
||||
1. **Branch Management**: **CRITICAL:** Ensure you are NOT working on the
|
||||
`main` branch.
|
||||
- Run `git branch --show-current`.
|
||||
- If the current branch is `main`, you MUST create and switch to a new
|
||||
descriptive branch:
|
||||
```bash
|
||||
git checkout -b <new-branch-name>
|
||||
```
|
||||
|
||||
2. **Commit Changes**: Verify that all intended changes are committed.
|
||||
- Run `git status` to check for unstaged or uncommitted changes.
|
||||
- If there are uncommitted changes, stage and commit them with a descriptive
|
||||
message before proceeding. NEVER commit directly to `main`.
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "type(scope): description"
|
||||
```
|
||||
|
||||
3. **Locate Template**: Search for a pull request template in the repository.
|
||||
- Check `.github/pull_request_template.md`
|
||||
- Check `.github/PULL_REQUEST_TEMPLATE.md`
|
||||
- If multiple templates exist (e.g., in `.github/PULL_REQUEST_TEMPLATE/`),
|
||||
ask the user which one to use or select the most appropriate one based on
|
||||
the context (e.g., `bug_fix.md` vs `feature.md`).
|
||||
|
||||
4. **Read Template**: Read the content of the identified template file.
|
||||
|
||||
5. **Draft Description**: Create a PR description that strictly follows the
|
||||
template's structure.
|
||||
- **Headings**: Keep all headings from the template.
|
||||
- **Checklists**: Review each item. Mark with `[x]` if completed. If an item
|
||||
is not applicable, leave it unchecked or mark as `[ ]` (depending on the
|
||||
template's instructions) or remove it if the template allows flexibility
|
||||
(but prefer keeping it unchecked for transparency).
|
||||
- **Content**: Fill in the sections with clear, concise summaries of your
|
||||
changes.
|
||||
- **Related Issues**: Link any issues fixed or related to this PR (e.g.,
|
||||
"Fixes #123").
|
||||
|
||||
6. **Preflight Check**: Before creating the PR, run the workspace preflight
|
||||
script to ensure all build, lint, and test checks pass.
|
||||
```bash
|
||||
npm run preflight
|
||||
```
|
||||
If any checks fail, address the issues before proceeding to create the PR.
|
||||
|
||||
7. **Push Branch**: Push the current branch to the remote repository.
|
||||
**CRITICAL SAFETY RAIL:** Double-check your branch name before pushing.
|
||||
NEVER push if the current branch is `main`.
|
||||
```bash
|
||||
# Verify current branch is NOT main
|
||||
git branch --show-current
|
||||
# Push non-interactively
|
||||
git push -u origin HEAD
|
||||
```
|
||||
|
||||
8. **Create PR**: Use the `gh` CLI to create the PR. To avoid shell escaping
|
||||
issues with multi-line Markdown, write the description to a temporary file
|
||||
first.
|
||||
```bash
|
||||
# 1. Write the drafted description to a temporary file
|
||||
# 2. Create the PR using the --body-file flag
|
||||
gh pr create --title "type(scope): succinct description" --body-file <temp_file_path>
|
||||
# 3. Remove the temporary file
|
||||
rm <temp_file_path>
|
||||
```
|
||||
- **Title**: Ensure the title follows the
|
||||
[Conventional Commits](https://www.conventionalcommits.org/) format if the
|
||||
repository uses it (e.g., `feat(ui): add new button`,
|
||||
`fix(core): resolve crash`).
|
||||
|
||||
## Principles
|
||||
|
||||
- **Safety First**: NEVER push to `main`. This is your highest priority.
|
||||
- **Compliance**: Never ignore the PR template. It exists for a reason.
|
||||
- **Completeness**: Fill out all relevant sections.
|
||||
- **Accuracy**: Don't check boxes for tasks you haven't done.
|
||||
@@ -11,3 +11,6 @@
|
||||
/.github/workflows/ @google-gemini/gemini-cli-askmode-approvers
|
||||
/packages/cli/package.json @google-gemini/gemini-cli-askmode-approvers
|
||||
/packages/core/package.json @google-gemini/gemini-cli-askmode-approvers
|
||||
|
||||
# Docs have a dedicated approver group in addition to maintainers
|
||||
/docs/ @google-gemini/gemini-cli-maintainers @google-gemini/gemini-cli-docs
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
name: 'Bug Report'
|
||||
description: 'Report a bug to help us improve Gemini CLI'
|
||||
labels:
|
||||
- 'kind/bug'
|
||||
- 'status/need-triage'
|
||||
body:
|
||||
- type: 'markdown'
|
||||
attributes:
|
||||
@@ -31,7 +28,7 @@ body:
|
||||
id: 'info'
|
||||
attributes:
|
||||
label: 'Client information'
|
||||
description: 'Please paste the full text from the `/about` command run from Gemini CLI. Also include which platform (macOS, Windows, Linux).'
|
||||
description: 'Please paste the full text from the `/about` command run from Gemini CLI. Also include which platform (macOS, Windows, Linux). Note that this output contains your email address. Consider removing it before submitting.'
|
||||
value: |-
|
||||
<details>
|
||||
<summary>Client Information</summary>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
name: 'Feature Request'
|
||||
description: 'Suggest an idea for this project'
|
||||
labels:
|
||||
- 'kind/enhancement'
|
||||
- 'status/need-triage'
|
||||
type: 'Feature'
|
||||
body:
|
||||
- type: 'markdown'
|
||||
attributes:
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
name: 'Website issue'
|
||||
description: 'Report an issue with the Gemini CLI Website and Gemini CLI Extensions Gallery'
|
||||
labels:
|
||||
- 'area/extensions'
|
||||
body:
|
||||
- type: 'markdown'
|
||||
attributes:
|
||||
value: |-
|
||||
> [!IMPORTANT]
|
||||
> Thanks for taking the time to report an issue with the Gemini CLI Website
|
||||
>
|
||||
> Please search **[existing issues](https://github.com/google-gemini/gemini-cli/issues?q=is%3Aissue+is%3Aopen+label%3Aarea%2Fwebsite)** to see if a similar feature has already been requested.
|
||||
- type: 'input'
|
||||
id: 'url'
|
||||
attributes:
|
||||
label: 'URL of the page with the issue'
|
||||
description: 'Please provide the URL where the issue occurs.'
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: 'textarea'
|
||||
id: 'problem'
|
||||
attributes:
|
||||
label: 'What is the problem?'
|
||||
description: 'A clear and concise description of what the bug or issue is.'
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: 'textarea'
|
||||
id: 'expected'
|
||||
attributes:
|
||||
label: 'What did you expect to happen?'
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: 'textarea'
|
||||
id: 'additional-context'
|
||||
attributes:
|
||||
label: 'Additional context'
|
||||
description: 'Add any other context or screenshots about the issue here.'
|
||||
@@ -0,0 +1,33 @@
|
||||
name: 'Calculate vars'
|
||||
description: 'Calculate commonly used var in our release process'
|
||||
|
||||
inputs:
|
||||
dry_run:
|
||||
description: 'Whether or not this is a dry run'
|
||||
type: 'boolean'
|
||||
|
||||
outputs:
|
||||
is_dry_run:
|
||||
description: 'Boolean flag indicating if the current run is a dry-run or a production release.'
|
||||
value: '${{ steps.set_vars.outputs.is_dry_run }}'
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: 'Print inputs'
|
||||
shell: 'bash'
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
|
||||
- name: 'Set vars for simplified logic'
|
||||
id: 'set_vars'
|
||||
shell: 'bash'
|
||||
env:
|
||||
DRY_RUN_INPUT: '${{ inputs.dry_run }}'
|
||||
run: |-
|
||||
is_dry_run="true"
|
||||
if [[ "${DRY_RUN_INPUT}" == "" || "${DRY_RUN_INPUT}" == "false" ]]; then
|
||||
is_dry_run="false"
|
||||
fi
|
||||
echo "is_dry_run=${is_dry_run}" >> "${GITHUB_OUTPUT}"
|
||||
@@ -1,5 +1,5 @@
|
||||
name: 'Create and Merge Pull Request'
|
||||
description: 'Creates a pull request and merges it automatically.'
|
||||
name: 'Create Pull Request'
|
||||
description: 'Creates a pull request.'
|
||||
|
||||
inputs:
|
||||
branch-name:
|
||||
@@ -32,8 +32,10 @@ runs:
|
||||
steps:
|
||||
- name: '📝 Print Inputs'
|
||||
shell: 'bash'
|
||||
run: 'echo "${{ toJSON(inputs) }}"'
|
||||
- name: 'Create and Approve Pull Request'
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
- name: 'Creates a Pull Request'
|
||||
if: "inputs.dry-run != 'true'"
|
||||
env:
|
||||
GH_TOKEN: '${{ inputs.github-token }}'
|
||||
@@ -51,4 +53,4 @@ runs:
|
||||
--base "${{ inputs.base-branch }}" \
|
||||
--head "${{ inputs.branch-name }}" \
|
||||
--fill)
|
||||
gh pr merge "$PR_URL" --auto --squash
|
||||
gh pr merge "$PR_URL" --auto
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
name: 'NPM Auth Token'
|
||||
description: 'Generates an NPM auth token for publishing a specific package'
|
||||
|
||||
inputs:
|
||||
package-name:
|
||||
description: 'The name of the package to publish'
|
||||
required: true
|
||||
github-token:
|
||||
description: 'the github token'
|
||||
required: true
|
||||
wombat-token-core:
|
||||
description: 'The npm token for the cli-core package.'
|
||||
required: true
|
||||
wombat-token-cli:
|
||||
description: 'The npm token for the cli package.'
|
||||
required: true
|
||||
wombat-token-a2a-server:
|
||||
description: 'The npm token for the a2a package.'
|
||||
required: true
|
||||
|
||||
outputs:
|
||||
auth-token:
|
||||
description: 'The generated NPM auth token'
|
||||
value: '${{ steps.npm_auth_token.outputs.auth-token }}'
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: 'Generate NPM Auth Token'
|
||||
id: 'npm_auth_token'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
AUTH_TOKEN="${{ inputs.github-token }}"
|
||||
PACKAGE_NAME="${{ inputs.package-name }}"
|
||||
PRIVATE_REPO="@google-gemini/"
|
||||
if [[ "$PACKAGE_NAME" == "$PRIVATE_REPO"* ]]; then
|
||||
AUTH_TOKEN="${{ inputs.github-token }}"
|
||||
elif [[ "$PACKAGE_NAME" == "@google/gemini-cli" ]]; then
|
||||
AUTH_TOKEN="${{ inputs.wombat-token-cli }}"
|
||||
elif [[ "$PACKAGE_NAME" == "@google/gemini-cli-core" ]]; then
|
||||
AUTH_TOKEN="${{ inputs.wombat-token-core }}"
|
||||
elif [[ "$PACKAGE_NAME" == "@google/gemini-cli-a2a-server" ]]; then
|
||||
AUTH_TOKEN="${{ inputs.wombat-token-a2a-server }}"
|
||||
fi
|
||||
echo "auth-token=$AUTH_TOKEN" >> $GITHUB_OUTPUT
|
||||
@@ -29,7 +29,9 @@ runs:
|
||||
steps:
|
||||
- name: '📝 Print Inputs'
|
||||
shell: 'bash'
|
||||
run: 'echo "${{ toJSON(inputs) }}"'
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
- name: 'Prepare Coverage Comment'
|
||||
id: 'prep_coverage_comment'
|
||||
shell: 'bash'
|
||||
|
||||
@@ -9,14 +9,20 @@ inputs:
|
||||
description: 'The npm tag to publish with (e.g., latest, preview, nightly).'
|
||||
required: true
|
||||
wombat-token-core:
|
||||
description: 'The npm token for the @google/gemini-cli-core package.'
|
||||
description: 'The npm token for the cli-core package.'
|
||||
required: true
|
||||
wombat-token-cli:
|
||||
description: 'The npm token for the @google/gemini-cli package.'
|
||||
description: 'The npm token for the cli package.'
|
||||
required: true
|
||||
wombat-token-a2a-server:
|
||||
description: 'The npm token for the a2a package.'
|
||||
required: true
|
||||
github-token:
|
||||
description: 'The GitHub token for creating the release.'
|
||||
required: true
|
||||
github-release-token:
|
||||
description: 'The GitHub token used specifically for creating the GitHub release (to trigger other workflows).'
|
||||
required: false
|
||||
dry-run:
|
||||
description: 'Whether to run in dry-run mode.'
|
||||
type: 'string'
|
||||
@@ -48,13 +54,32 @@ inputs:
|
||||
gemini_api_key:
|
||||
description: 'The API key for running integration tests.'
|
||||
required: true
|
||||
|
||||
npm-registry-publish-url:
|
||||
description: 'npm registry publish url'
|
||||
required: true
|
||||
npm-registry-url:
|
||||
description: 'npm registry url'
|
||||
required: true
|
||||
npm-registry-scope:
|
||||
description: 'npm registry scope'
|
||||
required: true
|
||||
cli-package-name:
|
||||
description: 'The name of the cli package.'
|
||||
required: true
|
||||
core-package-name:
|
||||
description: 'The name of the core package.'
|
||||
required: true
|
||||
a2a-package-name:
|
||||
description: 'The name of the a2a package.'
|
||||
required: true
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: '📝 Print Inputs'
|
||||
shell: 'bash'
|
||||
run: 'echo "${{ toJSON(inputs) }}"'
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
|
||||
- name: '👤 Configure Git User'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
@@ -103,76 +128,136 @@ runs:
|
||||
npm run build:packages
|
||||
npm run prepare:package
|
||||
|
||||
- name: 'Configure npm for publishing'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
|
||||
with:
|
||||
node-version-file: '${{ inputs.working-directory }}/.nvmrc'
|
||||
registry-url: 'https://wombat-dressing-room.appspot.com'
|
||||
scope: '@google'
|
||||
|
||||
- name: '📦 Publish @google/gemini-cli-core'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
env:
|
||||
NODE_AUTH_TOKEN: '${{ inputs.wombat-token-core }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
if [ "${{ inputs.dry-run }}" == "true" ]; then
|
||||
npm publish --dry-run --workspace="@google/gemini-cli-core" --no-tag
|
||||
else
|
||||
npm publish --workspace="@google/gemini-cli-core" --no-tag
|
||||
fi
|
||||
|
||||
- name: '🔗 Install latest core package'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
if: "${{ inputs.dry-run != 'true' }}"
|
||||
shell: 'bash'
|
||||
run: |
|
||||
npm install "@google/gemini-cli-core@${{ inputs.release-version }}" \
|
||||
--workspace="@google/gemini-cli" \
|
||||
--save-exact
|
||||
|
||||
- name: '📦 Publish @google/gemini-cli'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
env:
|
||||
NODE_AUTH_TOKEN: '${{ inputs.wombat-token-cli }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
if [ "${{ inputs.dry-run }}" == "true" ]; then
|
||||
npm publish --dry-run --workspace="@google/gemini-cli" --no-tag
|
||||
else
|
||||
npm publish --workspace="@google/gemini-cli" --no-tag
|
||||
fi
|
||||
|
||||
- name: '🔬 Verify NPM release by version'
|
||||
uses: './.github/actions/verify-release'
|
||||
if: "${{ inputs.dry-run != 'true' && inputs.force-skip-tests != 'true' }}"
|
||||
with:
|
||||
npm-package: '@google/gemini-cli@${{ inputs.release-version }}'
|
||||
expected-version: '${{ inputs.release-version }}'
|
||||
ref: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
|
||||
gemini_api_key: '${{ inputs.gemini_api_key }}'
|
||||
|
||||
- name: '🏷️ Tag release'
|
||||
uses: './.github/actions/tag-npm-release'
|
||||
if: "${{ inputs.dry-run != 'true' }}"
|
||||
with:
|
||||
channel: '${{ inputs.npm-tag }}'
|
||||
version: '${{ inputs.release-version }}'
|
||||
dry-run: '${{ inputs.dry-run }}'
|
||||
wombat-token-core: '${{ inputs.wombat-token-core }}'
|
||||
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
|
||||
|
||||
- name: '🎁 Bundle'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
npm run bundle
|
||||
|
||||
# TODO: Refactor this github specific publishing script to be generalized based upon inputs.
|
||||
- name: '📦 Prepare for GitHub release'
|
||||
if: "inputs.npm-registry-url == 'https://npm.pkg.github.com/'"
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
node ${{ github.workspace }}/scripts/prepare-github-release.js
|
||||
|
||||
- name: 'Configure npm for publishing to npm'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
|
||||
with:
|
||||
node-version-file: '${{ inputs.working-directory }}/.nvmrc'
|
||||
registry-url: '${{inputs.npm-registry-publish-url}}'
|
||||
scope: '${{inputs.npm-registry-scope}}'
|
||||
|
||||
- name: 'Get core Token'
|
||||
uses: './.github/actions/npm-auth-token'
|
||||
id: 'core-token'
|
||||
with:
|
||||
package-name: '${{ inputs.core-package-name }}'
|
||||
github-token: '${{ inputs.github-token }}'
|
||||
wombat-token-core: '${{ inputs.wombat-token-core }}'
|
||||
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
|
||||
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
|
||||
|
||||
- name: '📦 Publish CORE to NPM'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
env:
|
||||
NODE_AUTH_TOKEN: '${{ steps.core-token.outputs.auth-token }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
npm publish \
|
||||
--dry-run="${{ inputs.dry-run }}" \
|
||||
--workspace="${{ inputs.core-package-name }}" \
|
||||
--no-tag
|
||||
npm dist-tag rm ${{ inputs.core-package-name }} false --silent
|
||||
|
||||
- name: '🔗 Install latest core package'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
if: "${{ inputs.dry-run != 'true' }}"
|
||||
shell: 'bash'
|
||||
run: |
|
||||
npm install "${{ inputs.core-package-name }}@${{ inputs.release-version }}" \
|
||||
--workspace="${{ inputs.cli-package-name }}" \
|
||||
--workspace="${{ inputs.a2a-package-name }}" \
|
||||
--save-exact
|
||||
|
||||
- name: 'Get CLI Token'
|
||||
uses: './.github/actions/npm-auth-token'
|
||||
id: 'cli-token'
|
||||
with:
|
||||
package-name: '${{ inputs.cli-package-name }}'
|
||||
github-token: '${{ inputs.github-token }}'
|
||||
wombat-token-core: '${{ inputs.wombat-token-core }}'
|
||||
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
|
||||
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
|
||||
|
||||
- name: '📦 Publish CLI'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
env:
|
||||
NODE_AUTH_TOKEN: '${{ steps.cli-token.outputs.auth-token }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
npm publish \
|
||||
--dry-run="${{ inputs.dry-run }}" \
|
||||
--workspace="${{ inputs.cli-package-name }}" \
|
||||
--no-tag
|
||||
npm dist-tag rm ${{ inputs.cli-package-name }} false --silent
|
||||
|
||||
- name: 'Get a2a-server Token'
|
||||
uses: './.github/actions/npm-auth-token'
|
||||
id: 'a2a-token'
|
||||
with:
|
||||
package-name: '${{ inputs.a2a-package-name }}'
|
||||
github-token: '${{ inputs.github-token }}'
|
||||
wombat-token-core: '${{ inputs.wombat-token-core }}'
|
||||
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
|
||||
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
|
||||
|
||||
- name: '📦 Publish a2a'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
env:
|
||||
NODE_AUTH_TOKEN: '${{ steps.a2a-token.outputs.auth-token }}'
|
||||
shell: 'bash'
|
||||
# Tag staging for initial release
|
||||
run: |
|
||||
npm publish \
|
||||
--dry-run="${{ inputs.dry-run }}" \
|
||||
--workspace="${{ inputs.a2a-package-name }}" \
|
||||
--no-tag
|
||||
npm dist-tag rm ${{ inputs.a2a-package-name }} false --silent
|
||||
|
||||
- name: '🔬 Verify NPM release by version'
|
||||
uses: './.github/actions/verify-release'
|
||||
if: "${{ inputs.dry-run != 'true' && inputs.force-skip-tests != 'true' }}"
|
||||
with:
|
||||
npm-package: '${{ inputs.cli-package-name }}@${{ inputs.release-version }}'
|
||||
expected-version: '${{ inputs.release-version }}'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
gemini_api_key: '${{ inputs.gemini_api_key }}'
|
||||
github-token: '${{ inputs.github-token }}'
|
||||
npm-registry-url: '${{ inputs.npm-registry-url }}'
|
||||
npm-registry-scope: '${{ inputs.npm-registry-scope }}'
|
||||
|
||||
- name: '🏷️ Tag release'
|
||||
uses: './.github/actions/tag-npm-release'
|
||||
with:
|
||||
channel: '${{ inputs.npm-tag }}'
|
||||
version: '${{ inputs.release-version }}'
|
||||
dry-run: '${{ inputs.dry-run }}'
|
||||
github-token: '${{ inputs.github-token }}'
|
||||
wombat-token-core: '${{ inputs.wombat-token-core }}'
|
||||
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
|
||||
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
|
||||
cli-package-name: '${{ inputs.cli-package-name }}'
|
||||
core-package-name: '${{ inputs.core-package-name }}'
|
||||
a2a-package-name: '${{ inputs.a2a-package-name }}'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
|
||||
- name: '🎉 Create GitHub Release'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
if: "${{ inputs.dry-run != 'true' && inputs.skip-github-release != 'true' && inputs.npm-tag != 'dev' }}"
|
||||
if: "${{ inputs.dry-run != 'true' && inputs.skip-github-release != 'true' && inputs.npm-tag != 'dev' && inputs.npm-registry-url != 'https://npm.pkg.github.com/' }}"
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ inputs.github-token }}'
|
||||
GITHUB_TOKEN: '${{ inputs.github-release-token || inputs.github-token }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
gh release create "${{ inputs.release-tag }}" \
|
||||
@@ -180,7 +265,8 @@ runs:
|
||||
--target "${{ steps.release_branch.outputs.BRANCH_NAME }}" \
|
||||
--title "Release ${{ inputs.release-tag }}" \
|
||||
--notes-start-tag "${{ inputs.previous-tag }}" \
|
||||
--generate-notes
|
||||
--generate-notes \
|
||||
${{ inputs.npm-tag != 'latest' && '--prerelease' || '' }}
|
||||
|
||||
- name: '🧹 Clean up release branch'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
|
||||
@@ -20,7 +20,9 @@ runs:
|
||||
steps:
|
||||
- name: '📝 Print Inputs'
|
||||
shell: 'bash'
|
||||
run: 'echo "${{ toJSON(inputs) }}"'
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v4
|
||||
with:
|
||||
@@ -73,4 +75,4 @@ runs:
|
||||
gh issue create \
|
||||
--title "Docker build failed" \
|
||||
--body "The docker build failed. See the full run for details: ${DETAILS_URL}" \
|
||||
--label "kind/bug,release-failure"
|
||||
--label "release-failure"
|
||||
|
||||
@@ -30,7 +30,9 @@ runs:
|
||||
steps:
|
||||
- name: '📝 Print Inputs'
|
||||
shell: 'bash'
|
||||
run: 'echo "${{ toJSON(inputs) }}"'
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@v4'
|
||||
with:
|
||||
@@ -75,6 +77,14 @@ runs:
|
||||
--image google/gemini-cli-sandbox:${{ steps.image_tag.outputs.FINAL_TAG }} \
|
||||
--output-file final_image_uri.txt
|
||||
echo "uri=$(cat final_image_uri.txt)" >> $GITHUB_OUTPUT
|
||||
- name: 'verify'
|
||||
shell: 'bash'
|
||||
run: |-
|
||||
docker run --rm --entrypoint sh "${{ steps.docker_build.outputs.uri }}" -lc '
|
||||
set -e
|
||||
node -e "const fs=require(\"node:fs\"); JSON.parse(fs.readFileSync(\"/usr/local/share/npm-global/lib/node_modules/@google/gemini-cli/package.json\",\"utf8\")); JSON.parse(fs.readFileSync(\"/usr/local/share/npm-global/lib/node_modules/@google/gemini-cli-core/package.json\",\"utf8\"));"
|
||||
/usr/local/share/npm-global/bin/gemini --version >/dev/null
|
||||
'
|
||||
- name: 'publish'
|
||||
shell: 'bash'
|
||||
if: "${{ inputs.dry-run != 'true' }}"
|
||||
@@ -91,4 +101,4 @@ runs:
|
||||
gh issue create \
|
||||
--title "Docker build failed" \
|
||||
--body "The docker build failed. See the full run for details: ${DETAILS_URL}" \
|
||||
--label "kind/bug,release-failure"
|
||||
--label "release-failure"
|
||||
|
||||
@@ -15,7 +15,9 @@ runs:
|
||||
steps:
|
||||
- name: '📝 Print Inputs'
|
||||
shell: 'bash'
|
||||
run: 'echo "${{ toJSON(inputs) }}"'
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
- name: 'Run Tests'
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ inputs.gemini_api_key }}'
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
name: 'Setup NPMRC'
|
||||
description: 'Sets up NPMRC with all the correct repos for readonly access.'
|
||||
|
||||
inputs:
|
||||
github-token:
|
||||
description: 'the github token'
|
||||
required: true
|
||||
|
||||
outputs:
|
||||
auth-token:
|
||||
description: 'The generated NPM auth token'
|
||||
value: '${{ steps.npm_auth_token.outputs.auth-token }}'
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: 'Configure .npmrc'
|
||||
shell: 'bash'
|
||||
run: |-
|
||||
echo ""@google-gemini:registry=https://npm.pkg.github.com"" > ~/.npmrc
|
||||
echo ""//npm.pkg.github.com/:_authToken=${{ inputs.github-token }}"" >> ~/.npmrc
|
||||
echo ""@google:registry=https://wombat-dressing-room.appspot.com"" >> ~/.npmrc
|
||||
@@ -11,47 +11,115 @@ inputs:
|
||||
dry-run:
|
||||
description: 'Whether to run in dry-run mode.'
|
||||
required: true
|
||||
github-token:
|
||||
description: 'The GitHub token for creating the release.'
|
||||
required: true
|
||||
wombat-token-core:
|
||||
description: 'The npm token for the wombat @google/gemini-cli-core'
|
||||
required: true
|
||||
wombat-token-cli:
|
||||
description: 'The npm token for wombat @google/gemini-cli'
|
||||
required: true
|
||||
wombat-token-a2a-server:
|
||||
description: 'The npm token for the @google/gemini-cli-a2a-server package.'
|
||||
required: true
|
||||
cli-package-name:
|
||||
description: 'The name of the cli package.'
|
||||
required: true
|
||||
core-package-name:
|
||||
description: 'The name of the core package.'
|
||||
required: true
|
||||
a2a-package-name:
|
||||
description: 'The name of the a2a package.'
|
||||
required: true
|
||||
working-directory:
|
||||
description: 'The working directory to run the commands in.'
|
||||
required: false
|
||||
default: '.'
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: '📝 Print Inputs'
|
||||
shell: 'bash'
|
||||
run: 'echo "${{ toJSON(inputs) }}"'
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
|
||||
- name: 'Setup Node.js'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
registry-url: 'https://wombat-dressing-room.appspot.com'
|
||||
scope: '@google'
|
||||
node-version-file: '${{ inputs.working-directory }}/.nvmrc'
|
||||
|
||||
- name: 'Change tag for @google/gemini-cli-core'
|
||||
- name: 'configure .npmrc'
|
||||
uses: './.github/actions/setup-npmrc'
|
||||
with:
|
||||
github-token: '${{ inputs.github-token }}'
|
||||
|
||||
- name: 'Get core Token'
|
||||
uses: './.github/actions/npm-auth-token'
|
||||
id: 'core-token'
|
||||
with:
|
||||
package-name: '${{ inputs.core-package-name }}'
|
||||
github-token: '${{ inputs.github-token }}'
|
||||
wombat-token-core: '${{ inputs.wombat-token-core }}'
|
||||
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
|
||||
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
|
||||
|
||||
- name: 'Change tag for CORE'
|
||||
if: |-
|
||||
${{ inputs.dry-run != 'true' }}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: '${{ inputs.wombat-token-core }}'
|
||||
NODE_AUTH_TOKEN: '${{ steps.core-token.outputs.auth-token }}'
|
||||
shell: 'bash'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
run: |
|
||||
npm dist-tag add @google/gemini-cli-core@${{ inputs.version }} ${{ inputs.channel }}
|
||||
npm dist-tag add ${{ inputs.core-package-name }}@${{ inputs.version }} ${{ inputs.channel }}
|
||||
|
||||
- name: 'Change tag for @google/gemini-cli'
|
||||
- name: 'Get cli Token'
|
||||
uses: './.github/actions/npm-auth-token'
|
||||
id: 'cli-token'
|
||||
with:
|
||||
package-name: '${{ inputs.cli-package-name }}'
|
||||
github-token: '${{ inputs.github-token }}'
|
||||
wombat-token-core: '${{ inputs.wombat-token-core }}'
|
||||
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
|
||||
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
|
||||
|
||||
- name: 'Change tag for CLI'
|
||||
if: |-
|
||||
${{ inputs.dry-run != 'true' }}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: '${{ inputs.wombat-token-cli }}'
|
||||
NODE_AUTH_TOKEN: '${{ steps.cli-token.outputs.auth-token }}'
|
||||
shell: 'bash'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
run: |
|
||||
npm dist-tag add @google/gemini-cli@${{ inputs.version }} ${{ inputs.channel }}
|
||||
npm dist-tag add ${{ inputs.cli-package-name }}@${{ inputs.version }} ${{ inputs.channel }}
|
||||
|
||||
- name: 'Get a2a Token'
|
||||
uses: './.github/actions/npm-auth-token'
|
||||
id: 'a2a-token'
|
||||
with:
|
||||
package-name: '${{ inputs.a2a-package-name }}'
|
||||
github-token: '${{ inputs.github-token }}'
|
||||
wombat-token-core: '${{ inputs.wombat-token-core }}'
|
||||
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
|
||||
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
|
||||
|
||||
- name: 'Change tag for a2a'
|
||||
if: |-
|
||||
${{ inputs.dry-run == 'false' }}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: '${{ steps.a2a-token.outputs.auth-token }}'
|
||||
shell: 'bash'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
run: |
|
||||
npm dist-tag add ${{ inputs.a2a-package-name }}@${{ inputs.version }} ${{ inputs.channel }}
|
||||
|
||||
- name: 'Log dry run'
|
||||
if: |-
|
||||
${{ inputs.dry-run == 'true' }}
|
||||
shell: 'bash'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
run: |
|
||||
echo "Dry run: Would have added tag '${{ inputs.channel }}' to version '${{ inputs.version }}' for @google/gemini-cli and @google/gemini-cli-core."
|
||||
echo "Dry run: Would have added tag '${{ inputs.channel }}' to version '${{ inputs.version }}' for ${{ inputs.cli-package-name }}, ${{ inputs.core-package-name }}, and ${{ inputs.a2a-package-name }}."
|
||||
|
||||
@@ -6,31 +6,48 @@ inputs:
|
||||
description: 'NPM Package'
|
||||
required: true
|
||||
default: '@google/gemini-cli@latest'
|
||||
npm-registry-url:
|
||||
description: 'NPM Registry URL'
|
||||
required: true
|
||||
npm-registry-scope:
|
||||
description: 'NPM Registry Scope'
|
||||
required: true
|
||||
expected-version:
|
||||
description: 'Expected version'
|
||||
required: true
|
||||
gemini_api_key:
|
||||
description: 'The API key for running integration tests.'
|
||||
required: true
|
||||
ref:
|
||||
description: 'The branch, tag, or SHA to release from.'
|
||||
github-token:
|
||||
description: 'The GitHub token for running integration tests.'
|
||||
required: true
|
||||
working-directory:
|
||||
description: 'The working directory to run the tests in.'
|
||||
required: false
|
||||
type: 'string'
|
||||
default: 'main'
|
||||
default: '.'
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: '📝 Print Inputs'
|
||||
shell: 'bash'
|
||||
run: 'echo "${{ toJSON(inputs) }}"'
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v4
|
||||
- name: 'setup node'
|
||||
uses: 'actions/setup-node@v4'
|
||||
with:
|
||||
path: 'verify'
|
||||
ref: '${{ github.event.inputs.ref }}'
|
||||
fetch-depth: 0
|
||||
node-version: '20'
|
||||
|
||||
- name: 'configure .npmrc'
|
||||
uses: './.github/actions/setup-npmrc'
|
||||
with:
|
||||
github-token: '${{ inputs.github-token }}'
|
||||
|
||||
- name: 'Clear npm cache'
|
||||
shell: 'bash'
|
||||
run: 'npm cache clean --force'
|
||||
|
||||
- name: 'Install from NPM'
|
||||
uses: 'nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08' # ratchet:nick-fields/retry@v3
|
||||
@@ -38,27 +55,46 @@ runs:
|
||||
timeout_seconds: 900
|
||||
retry_wait_seconds: 30
|
||||
max_attempts: 10
|
||||
command: 'cd ./verify && pkg="${{ inputs.npm-package }}" && npm install --prefer-online --no-cache -g "$pkg"'
|
||||
command: |-
|
||||
cd ${{ inputs.working-directory }}
|
||||
npm install --prefer-online --no-cache -g "${{ inputs.npm-package }}"
|
||||
|
||||
- name: 'Basic smoke test'
|
||||
- name: 'Smoke test - NPM Install'
|
||||
shell: 'bash'
|
||||
working-directory: './verify'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
run: |-
|
||||
gemini_version=$(gemini --version)
|
||||
if [ "$gemini_version" != "${{ inputs.expected-version }}" ]; then
|
||||
echo "❌ Version mismatch: Got $gemini_version from ${{ inputs.npm-package }}, expected ${{ inputs.expected-version }}"
|
||||
echo "❌ NPM Version mismatch: Got $gemini_version from ${{ inputs.npm-package }}, expected ${{ inputs.expected-version }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 'Clear npm cache'
|
||||
shell: 'bash'
|
||||
run: 'npm cache clean --force'
|
||||
|
||||
- name: 'Smoke test - NPX Run'
|
||||
shell: 'bash'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
run: |-
|
||||
gemini_version=$(npx --prefer-online "${{ inputs.npm-package}}" --version)
|
||||
if [ "$gemini_version" != "${{ inputs.expected-version }}" ]; then
|
||||
echo "❌ NPX Run Version mismatch: Got $gemini_version from ${{ inputs.npm-package }}, expected ${{ inputs.expected-version }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 'Install dependencies for integration tests'
|
||||
shell: 'bash'
|
||||
working-directory: './verify'
|
||||
run: 'npm install'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: '🔬 Run integration tests against NPM release'
|
||||
working-directory: './verify'
|
||||
working-directory: '${{ inputs.working-directory }}'
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ inputs.gemini_api_key }}'
|
||||
INTEGRATION_TEST_USE_INSTALLED_GEMINI: 'true'
|
||||
# We must diable CI mode here because it interferes with interactive tests.
|
||||
# See https://github.com/google-gemini/gemini-cli/issues/10517
|
||||
CI: 'false'
|
||||
shell: 'bash'
|
||||
run: 'npm run test:integration:sandbox:none'
|
||||
|
||||
+18
-20
@@ -1,35 +1,33 @@
|
||||
# See https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: 'npm'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'daily'
|
||||
target-branch: 'main'
|
||||
commit-message:
|
||||
prefix: 'chore(deps)'
|
||||
include: 'scope'
|
||||
interval: 'weekly'
|
||||
day: 'monday'
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- 'google-gemini/gemini-cli-askmode-approvers'
|
||||
- 'joshualitt'
|
||||
groups:
|
||||
# Group all non-major updates together.
|
||||
# This is to reduce the number of PRs that need to be reviewed.
|
||||
# Major updates will still be created as separate PRs.
|
||||
npm-minor-patch:
|
||||
applies-to: 'version-updates'
|
||||
npm-dependencies:
|
||||
patterns:
|
||||
- '*'
|
||||
update-types:
|
||||
- 'minor'
|
||||
- 'patch'
|
||||
open-pull-requests-limit: 0
|
||||
|
||||
- package-ecosystem: 'github-actions'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'daily'
|
||||
target-branch: 'main'
|
||||
commit-message:
|
||||
prefix: 'chore(deps)'
|
||||
include: 'scope'
|
||||
interval: 'weekly'
|
||||
day: 'monday'
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- 'google-gemini/gemini-cli-askmode-approvers'
|
||||
open-pull-requests-limit: 0
|
||||
- 'joshualitt'
|
||||
groups:
|
||||
actions-dependencies:
|
||||
patterns:
|
||||
- '*'
|
||||
update-types:
|
||||
- 'minor'
|
||||
- 'patch'
|
||||
|
||||
@@ -1,41 +1,42 @@
|
||||
## TLDR
|
||||
## Summary
|
||||
|
||||
<!-- Add a brief description of what this pull request changes and why and any important things for reviewers to look at -->
|
||||
<!-- Concisely describe what this PR changes and why. Focus on impact and
|
||||
urgency. -->
|
||||
|
||||
## Dive Deeper
|
||||
## Details
|
||||
|
||||
<!-- more thoughts and in-depth discussion here -->
|
||||
<!-- Add any extra context and design decisions. Keep it brief but complete. -->
|
||||
|
||||
## Reviewer Test Plan
|
||||
## Related Issues
|
||||
|
||||
<!-- when a person reviews your code they should ideally be pulling and running that code. How would they validate your change works and if relevant what are some good classes of example prompts and ways they can exercise your changes -->
|
||||
<!-- Use keywords to auto-close issues (Closes #123, Fixes #456). If this PR is
|
||||
only related to an issue or is a partial fix, simply reference the issue number
|
||||
without a keyword (Related to #123). -->
|
||||
|
||||
## Testing Matrix
|
||||
## How to Validate
|
||||
|
||||
<!-- Before submitting please validate your changes on as many of these options as possible -->
|
||||
<!-- List exact steps for reviewers to validate the change. Include commands,
|
||||
expected results, and edge cases. -->
|
||||
|
||||
| | 🍏 | 🪟 | 🐧 |
|
||||
| -------- | --- | --- | --- |
|
||||
| npm run | ❓ | ❓ | ❓ |
|
||||
| npx | ❓ | ❓ | ❓ |
|
||||
| Docker | ❓ | ❓ | ❓ |
|
||||
| Podman | ❓ | - | - |
|
||||
| Seatbelt | ❓ | - | - |
|
||||
## Pre-Merge Checklist
|
||||
|
||||
## Linked issues / bugs
|
||||
<!-- Check all that apply before requesting review or merging. -->
|
||||
|
||||
<!--
|
||||
Link to any related issues or bugs.
|
||||
|
||||
**If this PR fully resolves the issue, use one of the following keywords to automatically close the issue when this PR is merged:**
|
||||
|
||||
- Closes #<issue_number>
|
||||
- Fixes #<issue_number>
|
||||
- Resolves #<issue_number>
|
||||
|
||||
*Example: `Resolves #123`*
|
||||
|
||||
**If this PR is only related to an issue or is a partial fix, simply reference the issue number without a keyword:**
|
||||
|
||||
*Example: `This PR makes progress on #456` or `Related to #789`*
|
||||
-->
|
||||
- [ ] Updated relevant documentation and README (if needed)
|
||||
- [ ] Added/updated tests (if needed)
|
||||
- [ ] Noted breaking changes (if any)
|
||||
- [ ] Validated on required platforms/methods:
|
||||
- [ ] MacOS
|
||||
- [ ] npm run
|
||||
- [ ] npx
|
||||
- [ ] Docker
|
||||
- [ ] Podman
|
||||
- [ ] Seatbelt
|
||||
- [ ] Windows
|
||||
- [ ] npm run
|
||||
- [ ] npx
|
||||
- [ ] Docker
|
||||
- [ ] Linux
|
||||
- [ ] npm run
|
||||
- [ ] npx
|
||||
- [ ] Docker
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/* eslint-disable */
|
||||
/* global require, console, process */
|
||||
|
||||
/**
|
||||
* Script to backfill the 'status/need-triage' label to all open issues
|
||||
* that are NOT currently labeled with '🔒 maintainer only' or 'help wanted'.
|
||||
*/
|
||||
|
||||
const { execFileSync } = require('child_process');
|
||||
|
||||
const isDryRun = process.argv.includes('--dry-run');
|
||||
const REPO = 'google-gemini/gemini-cli';
|
||||
|
||||
/**
|
||||
* Executes a GitHub CLI command safely using an argument array to prevent command injection.
|
||||
* @param {string[]} args
|
||||
* @returns {string|null}
|
||||
*/
|
||||
function runGh(args) {
|
||||
try {
|
||||
// Using execFileSync with an array of arguments is safe as it doesn't use a shell.
|
||||
// We set a large maxBuffer (10MB) to handle repositories with many issues.
|
||||
return execFileSync('gh', args, {
|
||||
encoding: 'utf8',
|
||||
maxBuffer: 10 * 1024 * 1024,
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
}).trim();
|
||||
} catch (error) {
|
||||
const stderr = error.stderr ? ` Stderr: ${error.stderr.trim()}` : '';
|
||||
console.error(
|
||||
`❌ Error running gh ${args.join(' ')}: ${error.message}${stderr}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('🔐 GitHub CLI security check...');
|
||||
const authStatus = runGh(['auth', 'status']);
|
||||
if (authStatus === null) {
|
||||
console.error('❌ GitHub CLI (gh) is not installed or not authenticated.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (isDryRun) {
|
||||
console.log('🧪 DRY RUN MODE ENABLED - No changes will be made.\n');
|
||||
}
|
||||
|
||||
console.log(`🔍 Fetching and filtering open issues from ${REPO}...`);
|
||||
|
||||
// We use the /issues endpoint with pagination to bypass the 1000-result limit.
|
||||
// The jq filter ensures we exclude PRs, maintainer-only, help-wanted, and existing status/need-triage.
|
||||
const jqFilter =
|
||||
'.[] | select(.pull_request == null) | select([.labels[].name] as $l | (any($l[]; . == "🔒 maintainer only") | not) and (any($l[]; . == "help wanted") | not) and (any($l[]; . == "status/need-triage") | not)) | {number: .number, title: .title}';
|
||||
|
||||
const output = runGh([
|
||||
'api',
|
||||
`repos/${REPO}/issues?state=open&per_page=100`,
|
||||
'--paginate',
|
||||
'--jq',
|
||||
jqFilter,
|
||||
]);
|
||||
|
||||
if (output === null) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const issues = output
|
||||
.split('\n')
|
||||
.filter((line) => line.trim())
|
||||
.map((line) => {
|
||||
try {
|
||||
return JSON.parse(line);
|
||||
} catch (_e) {
|
||||
console.error(`⚠️ Failed to parse line: ${line}`);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
console.log(`✅ Found ${issues.length} issues matching criteria.`);
|
||||
|
||||
if (issues.length === 0) {
|
||||
console.log('✨ No issues need backfilling.');
|
||||
return;
|
||||
}
|
||||
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
|
||||
if (isDryRun) {
|
||||
for (const issue of issues) {
|
||||
console.log(
|
||||
`[DRY RUN] Would label issue #${issue.number}: ${issue.title}`,
|
||||
);
|
||||
}
|
||||
successCount = issues.length;
|
||||
} else {
|
||||
console.log(`🏷️ Applying labels to ${issues.length} issues...`);
|
||||
|
||||
for (const issue of issues) {
|
||||
const issueNumber = String(issue.number);
|
||||
console.log(`🏷️ Labeling issue #${issueNumber}: ${issue.title}`);
|
||||
|
||||
const result = runGh([
|
||||
'issue',
|
||||
'edit',
|
||||
issueNumber,
|
||||
'--add-label',
|
||||
'status/need-triage',
|
||||
'--repo',
|
||||
REPO,
|
||||
]);
|
||||
|
||||
if (result !== null) {
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n📊 Summary:`);
|
||||
console.log(` - Success: ${successCount}`);
|
||||
console.log(` - Failed: ${failCount}`);
|
||||
|
||||
if (failCount > 0) {
|
||||
console.error(`\n❌ Backfill completed with ${failCount} errors.`);
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log(`\n🎉 ${isDryRun ? 'Dry run' : 'Backfill'} complete!`);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error('❌ Unexpected error:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
/* global require, console, process */
|
||||
|
||||
/**
|
||||
* Script to backfill a process change notification comment to all open PRs
|
||||
* not created by members of the 'gemini-cli-maintainers' team.
|
||||
*
|
||||
* Skip PRs that are already associated with an issue.
|
||||
*/
|
||||
|
||||
const { execFileSync } = require('child_process');
|
||||
|
||||
const isDryRun = process.argv.includes('--dry-run');
|
||||
const REPO = 'google-gemini/gemini-cli';
|
||||
const ORG = 'google-gemini';
|
||||
const TEAM_SLUG = 'gemini-cli-maintainers';
|
||||
const DISCUSSION_URL =
|
||||
'https://github.com/google-gemini/gemini-cli/discussions/16706';
|
||||
|
||||
/**
|
||||
* Executes a GitHub CLI command safely using an argument array.
|
||||
*/
|
||||
function runGh(args, options = {}) {
|
||||
const { silent = false } = options;
|
||||
try {
|
||||
return execFileSync('gh', args, {
|
||||
encoding: 'utf8',
|
||||
maxBuffer: 10 * 1024 * 1024,
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
}).trim();
|
||||
} catch (error) {
|
||||
if (!silent) {
|
||||
const stderr = error.stderr ? ` Stderr: ${error.stderr.trim()}` : '';
|
||||
console.error(
|
||||
`❌ Error running gh ${args.join(' ')}: ${error.message}${stderr}`,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a user is a member of the maintainers team.
|
||||
*/
|
||||
const membershipCache = new Map();
|
||||
function isMaintainer(username) {
|
||||
if (membershipCache.has(username)) return membershipCache.get(username);
|
||||
|
||||
// GitHub returns 404 if user is not a member.
|
||||
// We use silent: true to avoid logging 404s as errors.
|
||||
const result = runGh(
|
||||
['api', `orgs/${ORG}/teams/${TEAM_SLUG}/memberships/${username}`],
|
||||
{ silent: true },
|
||||
);
|
||||
|
||||
const isMember = result !== null;
|
||||
membershipCache.set(username, isMember);
|
||||
return isMember;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('🔐 GitHub CLI security check...');
|
||||
if (runGh(['auth', 'status']) === null) {
|
||||
console.error('❌ GitHub CLI (gh) is not authenticated.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (isDryRun) {
|
||||
console.log('🧪 DRY RUN MODE ENABLED\n');
|
||||
}
|
||||
|
||||
console.log(`📥 Fetching open PRs from ${REPO}...`);
|
||||
// Fetch number, author, and closingIssuesReferences to check if linked to an issue
|
||||
const prsJson = runGh([
|
||||
'pr',
|
||||
'list',
|
||||
'--repo',
|
||||
REPO,
|
||||
'--state',
|
||||
'open',
|
||||
'--limit',
|
||||
'1000',
|
||||
'--json',
|
||||
'number,author,closingIssuesReferences',
|
||||
]);
|
||||
|
||||
if (prsJson === null) process.exit(1);
|
||||
const prs = JSON.parse(prsJson);
|
||||
|
||||
console.log(`📊 Found ${prs.length} open PRs. Filtering...`);
|
||||
|
||||
let targetPrs = [];
|
||||
for (const pr of prs) {
|
||||
const author = pr.author.login;
|
||||
const issueCount = pr.closingIssuesReferences
|
||||
? pr.closingIssuesReferences.length
|
||||
: 0;
|
||||
|
||||
if (issueCount > 0) {
|
||||
// Skip if already linked to an issue
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isMaintainer(author)) {
|
||||
targetPrs.push(pr);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`✅ Found ${targetPrs.length} PRs from non-maintainers without associated issues.`,
|
||||
);
|
||||
|
||||
const commentBody =
|
||||
"\nHi @{AUTHOR}, thank you so much for your contribution to Gemini CLI! We really appreciate the time and effort you've put into this.\n\nWe're making some updates to our contribution process to improve how we track and review changes. Please take a moment to review our recent discussion post: [Improving Our Contribution Process & Introducing New Guidelines](${DISCUSSION_URL}).\n\nKey Update: Starting **January 26, 2026**, the Gemini CLI project will require all pull requests to be associated with an existing issue. Any pull requests not linked to an issue by that date will be automatically closed.\n\nThank you for your understanding and for being a part of our community!\n ".trim();
|
||||
|
||||
let successCount = 0;
|
||||
let skipCount = 0;
|
||||
let failCount = 0;
|
||||
|
||||
for (const pr of targetPrs) {
|
||||
const prNumber = String(pr.number);
|
||||
const author = pr.author.login;
|
||||
|
||||
// Check if we already commented (idempotency)
|
||||
// We use silent: true here because view might fail if PR is deleted mid-run
|
||||
const existingComments = runGh(
|
||||
[
|
||||
'pr',
|
||||
'view',
|
||||
prNumber,
|
||||
'--repo',
|
||||
REPO,
|
||||
'--json',
|
||||
'comments',
|
||||
'--jq',
|
||||
`.comments[].body | contains("${DISCUSSION_URL}")`,
|
||||
],
|
||||
{ silent: true },
|
||||
);
|
||||
|
||||
if (existingComments && existingComments.includes('true')) {
|
||||
console.log(
|
||||
`⏭️ PR #${prNumber} already has the notification. Skipping.`,
|
||||
);
|
||||
skipCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isDryRun) {
|
||||
console.log(`[DRY RUN] Would notify @${author} on PR #${prNumber}`);
|
||||
successCount++;
|
||||
} else {
|
||||
console.log(`💬 Notifying @${author} on PR #${prNumber}...`);
|
||||
const personalizedComment = commentBody.replace('{AUTHOR}', author);
|
||||
const result = runGh([
|
||||
'pr',
|
||||
'comment',
|
||||
prNumber,
|
||||
'--repo',
|
||||
REPO,
|
||||
'--body',
|
||||
personalizedComment,
|
||||
]);
|
||||
|
||||
if (result !== null) {
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n📊 Summary:`);
|
||||
console.log(` - Notified: ${successCount}`);
|
||||
console.log(` - Skipped: ${skipCount}`);
|
||||
console.log(` - Failed: ${failCount}`);
|
||||
|
||||
if (failCount > 0) process.exit(1);
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
+155
-108
@@ -1,133 +1,180 @@
|
||||
#!/usr/bin/env bash
|
||||
# @license
|
||||
# Copyright 2026 Google LLC
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Initialize a comma-separated string to hold PR numbers that need a comment
|
||||
PRS_NEEDING_COMMENT=""
|
||||
|
||||
# Function to process a single PR
|
||||
process_pr() {
|
||||
if [[ -z "${GITHUB_REPOSITORY:-}" ]]; then
|
||||
echo "‼️ Missing \$GITHUB_REPOSITORY - this must be run from GitHub Actions"
|
||||
return 1
|
||||
# Global cache for issue labels (compatible with Bash 3.2)
|
||||
# Stores "|ISSUE_NUM:LABELS|" segments
|
||||
ISSUE_LABELS_CACHE_FLAT="|"
|
||||
|
||||
# Function to get labels from an issue (with caching)
|
||||
get_issue_labels() {
|
||||
local ISSUE_NUM="${1}"
|
||||
if [[ -z "${ISSUE_NUM}" || "${ISSUE_NUM}" == "null" || "${ISSUE_NUM}" == "" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -z "${GITHUB_OUTPUT:-}" ]]; then
|
||||
echo "‼️ Missing \$GITHUB_OUTPUT - this must be run from GitHub Actions"
|
||||
return 1
|
||||
# Check cache
|
||||
case "${ISSUE_LABELS_CACHE_FLAT}" in
|
||||
*"|${ISSUE_NUM}:"*)
|
||||
local suffix="${ISSUE_LABELS_CACHE_FLAT#*|"${ISSUE_NUM}":}"
|
||||
echo "${suffix%%|*}"
|
||||
return
|
||||
;;
|
||||
*)
|
||||
# Cache miss, proceed to fetch
|
||||
;;
|
||||
esac
|
||||
|
||||
echo " 📥 Fetching labels from issue #${ISSUE_NUM}" >&2
|
||||
local gh_output
|
||||
if ! gh_output=$(gh issue view "${ISSUE_NUM}" --repo "${GITHUB_REPOSITORY}" --json labels -q '.labels[].name' 2>/dev/null); then
|
||||
echo " ⚠️ Could not fetch issue #${ISSUE_NUM}" >&2
|
||||
ISSUE_LABELS_CACHE_FLAT="${ISSUE_LABELS_CACHE_FLAT}${ISSUE_NUM}:|"
|
||||
return
|
||||
fi
|
||||
|
||||
local PR_NUMBER=$1
|
||||
local labels
|
||||
labels=$(echo "${gh_output}" | grep -x -E '(area|priority)/.*|help wanted|🔒 maintainer only' | tr '\n' ',' | sed 's/,$//' || echo "")
|
||||
|
||||
# Save to flat cache
|
||||
ISSUE_LABELS_CACHE_FLAT="${ISSUE_LABELS_CACHE_FLAT}${ISSUE_NUM}:${labels}|"
|
||||
echo "${labels}"
|
||||
}
|
||||
|
||||
# Function to process a single PR with pre-fetched data
|
||||
process_pr_optimized() {
|
||||
local PR_NUMBER="${1}"
|
||||
local IS_DRAFT="${2}"
|
||||
local ISSUE_NUMBER="${3}"
|
||||
local CURRENT_LABELS="${4}" # Comma-separated labels
|
||||
|
||||
echo "🔄 Processing PR #${PR_NUMBER}"
|
||||
|
||||
# Get closing issue number with error handling
|
||||
local ISSUE_NUMBER
|
||||
if ! ISSUE_NUMBER=$(gh pr view "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" --json closingIssuesReferences -q '.closingIssuesReferences.nodes[0].number' 2>/dev/null); then
|
||||
echo " ⚠️ Could not fetch closing issue for PR #${PR_NUMBER}"
|
||||
local LABELS_TO_ADD=""
|
||||
local LABELS_TO_REMOVE=""
|
||||
|
||||
if [[ -z "${ISSUE_NUMBER}" || "${ISSUE_NUMBER}" == "null" || "${ISSUE_NUMBER}" == "" ]]; then
|
||||
if [[ "${IS_DRAFT}" == "true" ]]; then
|
||||
echo " 📝 PR #${PR_NUMBER} is a draft and has no linked issue"
|
||||
if [[ ",${CURRENT_LABELS}," == *",status/need-issue,"* ]]; then
|
||||
echo " ➖ Removing status/need-issue label"
|
||||
LABELS_TO_REMOVE="status/need-issue"
|
||||
fi
|
||||
else
|
||||
echo " ⚠️ No linked issue found for PR #${PR_NUMBER}"
|
||||
if [[ ",${CURRENT_LABELS}," != *",status/need-issue,"* ]]; then
|
||||
echo " ➕ Adding status/need-issue label"
|
||||
LABELS_TO_ADD="status/need-issue"
|
||||
fi
|
||||
|
||||
if [[ -z "${PRS_NEEDING_COMMENT}" ]]; then
|
||||
PRS_NEEDING_COMMENT="${PR_NUMBER}"
|
||||
else
|
||||
PRS_NEEDING_COMMENT="${PRS_NEEDING_COMMENT},${PR_NUMBER}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " 🔗 Found linked issue #${ISSUE_NUMBER}"
|
||||
|
||||
if [[ ",${CURRENT_LABELS}," == *",status/need-issue,"* ]]; then
|
||||
echo " ➖ Removing status/need-issue label"
|
||||
LABELS_TO_REMOVE="status/need-issue"
|
||||
fi
|
||||
|
||||
local ISSUE_LABELS
|
||||
ISSUE_LABELS=$(get_issue_labels "${ISSUE_NUMBER}")
|
||||
|
||||
if [[ -n "${ISSUE_LABELS}" ]]; then
|
||||
local IFS_OLD="${IFS}"
|
||||
IFS=','
|
||||
for label in ${ISSUE_LABELS}; do
|
||||
if [[ -n "${label}" ]] && [[ ",${CURRENT_LABELS}," != *",${label},"* ]]; then
|
||||
if [[ -z "${LABELS_TO_ADD}" ]]; then
|
||||
LABELS_TO_ADD="${label}"
|
||||
else
|
||||
LABELS_TO_ADD="${LABELS_TO_ADD},${label}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
IFS="${IFS_OLD}"
|
||||
fi
|
||||
|
||||
if [[ -z "${LABELS_TO_ADD}" && -z "${LABELS_TO_REMOVE}" ]]; then
|
||||
echo " ✅ Labels already synchronized"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "${ISSUE_NUMBER}" ]]; then
|
||||
echo "⚠️ No linked issue found for PR #${PR_NUMBER}, adding status/need-issue label"
|
||||
if ! gh pr edit "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" --add-label "status/need-issue" 2>/dev/null; then
|
||||
echo " ⚠️ Failed to add label (may already exist or have permission issues)"
|
||||
fi
|
||||
# Add PR number to the list
|
||||
if [[ -z "${PRS_NEEDING_COMMENT}" ]]; then
|
||||
PRS_NEEDING_COMMENT="${PR_NUMBER}"
|
||||
else
|
||||
PRS_NEEDING_COMMENT="${PRS_NEEDING_COMMENT},${PR_NUMBER}"
|
||||
fi
|
||||
echo "needs_comment=true" >> "${GITHUB_OUTPUT}"
|
||||
else
|
||||
echo "🔗 Found linked issue #${ISSUE_NUMBER}"
|
||||
|
||||
# Remove status/need-issue label if present
|
||||
if ! gh pr edit "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" --remove-label "status/need-issue" 2>/dev/null; then
|
||||
echo " status/need-issue label not present or could not be removed"
|
||||
fi
|
||||
|
||||
# Get issue labels
|
||||
echo "📥 Fetching labels from issue #${ISSUE_NUMBER}"
|
||||
local ISSUE_LABELS=""
|
||||
if ! ISSUE_LABELS=$(gh issue view "${ISSUE_NUMBER}" --repo "${GITHUB_REPOSITORY}" --json labels -q '.labels[].name' 2>/dev/null | tr '\n' ',' | sed 's/,$//' || echo ""); then
|
||||
echo " ⚠️ Could not fetch issue #${ISSUE_NUMBER} (may not exist or be in different repo)"
|
||||
ISSUE_LABELS=""
|
||||
fi
|
||||
|
||||
# Get PR labels
|
||||
echo "📥 Fetching labels from PR #${PR_NUMBER}"
|
||||
local PR_LABELS=""
|
||||
if ! PR_LABELS=$(gh pr view "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" --json labels -q '.labels[].name' 2>/dev/null | tr '\n' ',' | sed 's/,$//' || echo ""); then
|
||||
echo " ⚠️ Could not fetch PR labels"
|
||||
PR_LABELS=""
|
||||
fi
|
||||
|
||||
echo " Issue labels: ${ISSUE_LABELS}"
|
||||
echo " PR labels: ${PR_LABELS}"
|
||||
|
||||
# Convert comma-separated strings to arrays
|
||||
local ISSUE_LABEL_ARRAY PR_LABEL_ARRAY
|
||||
IFS=',' read -ra ISSUE_LABEL_ARRAY <<< "${ISSUE_LABELS}"
|
||||
IFS=',' read -ra PR_LABEL_ARRAY <<< "${PR_LABELS}"
|
||||
|
||||
# Find labels to add (on issue but not on PR)
|
||||
local LABELS_TO_ADD=""
|
||||
for label in "${ISSUE_LABEL_ARRAY[@]}"; do
|
||||
if [[ -n "${label}" ]] && [[ " ${PR_LABEL_ARRAY[*]} " != *" ${label} "* ]]; then
|
||||
if [[ -z "${LABELS_TO_ADD}" ]]; then
|
||||
LABELS_TO_ADD="${label}"
|
||||
else
|
||||
LABELS_TO_ADD="${LABELS_TO_ADD},${label}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Apply label changes
|
||||
if [[ -n "${LABELS_TO_ADD}" || -n "${LABELS_TO_REMOVE}" ]]; then
|
||||
local EDIT_CMD=("gh" "pr" "edit" "${PR_NUMBER}" "--repo" "${GITHUB_REPOSITORY}")
|
||||
if [[ -n "${LABELS_TO_ADD}" ]]; then
|
||||
echo "➕ Adding labels: ${LABELS_TO_ADD}"
|
||||
if ! gh pr edit "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" --add-label "${LABELS_TO_ADD}" 2>/dev/null; then
|
||||
echo " ⚠️ Failed to add some labels"
|
||||
fi
|
||||
echo " ➕ Syncing labels to add: ${LABELS_TO_ADD}"
|
||||
EDIT_CMD+=("--add-label" "${LABELS_TO_ADD}")
|
||||
fi
|
||||
|
||||
if [[ -z "${LABELS_TO_ADD}" ]]; then
|
||||
echo "✅ Labels already synchronized"
|
||||
if [[ -n "${LABELS_TO_REMOVE}" ]]; then
|
||||
echo " ➖ Syncing labels to remove: ${LABELS_TO_REMOVE}"
|
||||
EDIT_CMD+=("--remove-label" "${LABELS_TO_REMOVE}")
|
||||
fi
|
||||
echo "needs_comment=false" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
("${EDIT_CMD[@]}" || true)
|
||||
fi
|
||||
}
|
||||
|
||||
# If PR_NUMBER is set, process only that PR
|
||||
if [[ -n "${PR_NUMBER:-}" ]]; then
|
||||
if ! process_pr "${PR_NUMBER}"; then
|
||||
echo "❌ Failed to process PR #${PR_NUMBER}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Otherwise, get all open PRs and process them
|
||||
# The script logic will determine which ones need issue linking or label sync
|
||||
echo "📥 Getting all open pull requests..."
|
||||
if ! PR_NUMBERS=$(gh pr list --repo "${GITHUB_REPOSITORY}" --state open --limit 1000 --json number -q '.[].number' 2>/dev/null); then
|
||||
echo "❌ Failed to fetch PR list"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${PR_NUMBERS}" ]]; then
|
||||
echo "✅ No open PRs found"
|
||||
else
|
||||
# Count the number of PRs
|
||||
PR_COUNT=$(echo "${PR_NUMBERS}" | wc -w | tr -d ' ')
|
||||
echo "📊 Found ${PR_COUNT} open PRs to process"
|
||||
|
||||
for pr_number in ${PR_NUMBERS}; do
|
||||
if ! process_pr "${pr_number}"; then
|
||||
echo "⚠️ Failed to process PR #${pr_number}, continuing with next PR..."
|
||||
continue
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if [[ -z "${GITHUB_REPOSITORY:-}" ]]; then
|
||||
echo "‼️ Missing \$GITHUB_REPOSITORY - this must be run from GitHub Actions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${GITHUB_OUTPUT:-}" ]]; then
|
||||
echo "‼️ Missing \$GITHUB_OUTPUT - this must be run from GitHub Actions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
JQ_EXTRACT_FIELDS='{
|
||||
number: .number,
|
||||
isDraft: .isDraft,
|
||||
issue: (.closingIssuesReferences[0].number // (.body // "" | capture("(^|[^a-zA-Z0-9])#(?<num>[0-9]+)([^a-zA-Z0-9]|$)")? | .num) // "null"),
|
||||
labels: [.labels[].name] | join(",")
|
||||
}'
|
||||
|
||||
JQ_TSV_FORMAT='"\((.number | tostring))\t\(.isDraft)\t\((.issue // null) | tostring)\t\(.labels)"'
|
||||
|
||||
if [[ -n "${PR_NUMBER:-}" ]]; then
|
||||
echo "🔄 Processing single PR #${PR_NUMBER}"
|
||||
PR_DATA=$(gh pr view "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" --json number,closingIssuesReferences,isDraft,body,labels 2>/dev/null) || {
|
||||
echo "❌ Failed to fetch data for PR #${PR_NUMBER}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
line=$(echo "${PR_DATA}" | jq -r "${JQ_EXTRACT_FIELDS} | ${JQ_TSV_FORMAT}")
|
||||
IFS=$'\t' read -r pr_num is_draft issue_num current_labels <<< "${line}"
|
||||
process_pr_optimized "${pr_num}" "${is_draft}" "${issue_num}" "${current_labels}"
|
||||
else
|
||||
echo "📥 Getting all open pull requests..."
|
||||
PR_DATA_ALL=$(gh pr list --repo "${GITHUB_REPOSITORY}" --state open --limit 1000 --json number,closingIssuesReferences,isDraft,body,labels 2>/dev/null) || {
|
||||
echo "❌ Failed to fetch PR list"
|
||||
exit 1
|
||||
}
|
||||
|
||||
PR_COUNT=$(echo "${PR_DATA_ALL}" | jq '. | length')
|
||||
echo "📊 Found ${PR_COUNT} open PRs to process"
|
||||
|
||||
# Use a temporary file to avoid masking exit codes in process substitution
|
||||
tmp_file=$(mktemp)
|
||||
echo "${PR_DATA_ALL}" | jq -r ".[] | ${JQ_EXTRACT_FIELDS} | ${JQ_TSV_FORMAT}" > "${tmp_file}"
|
||||
while read -r line; do
|
||||
[[ -z "${line}" ]] && continue
|
||||
IFS=$'\t' read -r pr_num is_draft issue_num current_labels <<< "${line}"
|
||||
process_pr_optimized "${pr_num}" "${is_draft}" "${issue_num}" "${current_labels}"
|
||||
done < "${tmp_file}"
|
||||
rm -f "${tmp_file}"
|
||||
fi
|
||||
|
||||
# Ensure output is always set, even if empty
|
||||
if [[ -z "${PRS_NEEDING_COMMENT}" ]]; then
|
||||
echo "prs_needing_comment=[]" >> "${GITHUB_OUTPUT}"
|
||||
else
|
||||
|
||||
@@ -0,0 +1,359 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
const { Octokit } = require('@octokit/rest');
|
||||
|
||||
/**
|
||||
* Sync Maintainer Labels (Recursive with strict parent-child relationship detection)
|
||||
* - Uses Native Sub-issues.
|
||||
* - Uses Markdown Task Lists (- [ ] #123).
|
||||
* - Filters for OPEN issues only.
|
||||
* - Skips DUPLICATES.
|
||||
* - Skips Pull Requests.
|
||||
* - ONLY labels issues in the PUBLIC (gemini-cli) repo.
|
||||
*/
|
||||
|
||||
const REPO_OWNER = 'google-gemini';
|
||||
const PUBLIC_REPO = 'gemini-cli';
|
||||
const PRIVATE_REPO = 'maintainers-gemini-cli';
|
||||
const ALLOWED_REPOS = [PUBLIC_REPO, PRIVATE_REPO];
|
||||
|
||||
const ROOT_ISSUES = [
|
||||
{ owner: REPO_OWNER, repo: PUBLIC_REPO, number: 15374 },
|
||||
{ owner: REPO_OWNER, repo: PUBLIC_REPO, number: 15456 },
|
||||
{ owner: REPO_OWNER, repo: PUBLIC_REPO, number: 15324 },
|
||||
];
|
||||
|
||||
const TARGET_LABEL = '🔒 maintainer only';
|
||||
const isDryRun =
|
||||
process.argv.includes('--dry-run') || process.env.DRY_RUN === 'true';
|
||||
|
||||
const octokit = new Octokit({
|
||||
auth: process.env.GITHUB_TOKEN,
|
||||
});
|
||||
|
||||
/**
|
||||
* Extracts child issue references from markdown Task Lists ONLY.
|
||||
* e.g. - [ ] #123 or - [x] google-gemini/gemini-cli#123
|
||||
*/
|
||||
function extractTaskListLinks(text, contextOwner, contextRepo) {
|
||||
if (!text) return [];
|
||||
const childIssues = new Map();
|
||||
|
||||
const add = (owner, repo, number) => {
|
||||
if (ALLOWED_REPOS.includes(repo)) {
|
||||
const key = `${owner}/${repo}#${number}`;
|
||||
childIssues.set(key, { owner, repo, number: parseInt(number, 10) });
|
||||
}
|
||||
};
|
||||
|
||||
// 1. Full URLs in task lists
|
||||
const urlRegex =
|
||||
/-\s+\[[ x]\].*https:\/\/github\.com\/([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)\/issues\/(\d+)\b/g;
|
||||
let match;
|
||||
while ((match = urlRegex.exec(text)) !== null) {
|
||||
add(match[1], match[2], match[3]);
|
||||
}
|
||||
|
||||
// 2. Cross-repo refs in task lists: owner/repo#123
|
||||
const crossRepoRegex =
|
||||
/-\s+\[[ x]\].*([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)#(\d+)\b/g;
|
||||
while ((match = crossRepoRegex.exec(text)) !== null) {
|
||||
add(match[1], match[2], match[3]);
|
||||
}
|
||||
|
||||
// 3. Short refs in task lists: #123
|
||||
const shortRefRegex = /-\s+\[[ x]\].*#(\d+)\b/g;
|
||||
while ((match = shortRefRegex.exec(text)) !== null) {
|
||||
add(contextOwner, contextRepo, match[1]);
|
||||
}
|
||||
|
||||
return Array.from(childIssues.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches issue data via GraphQL with full pagination for sub-issues, comments, and labels.
|
||||
*/
|
||||
async function fetchIssueData(owner, repo, number) {
|
||||
const query = `
|
||||
query($owner:String!, $repo:String!, $number:Int!) {
|
||||
repository(owner:$owner, name:$repo) {
|
||||
issue(number:$number) {
|
||||
state
|
||||
title
|
||||
body
|
||||
labels(first: 100) {
|
||||
nodes { name }
|
||||
pageInfo { hasNextPage endCursor }
|
||||
}
|
||||
subIssues(first: 100) {
|
||||
nodes {
|
||||
number
|
||||
repository {
|
||||
name
|
||||
owner { login }
|
||||
}
|
||||
}
|
||||
pageInfo { hasNextPage endCursor }
|
||||
}
|
||||
comments(first: 100) {
|
||||
nodes {
|
||||
body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
try {
|
||||
const response = await octokit.graphql(query, { owner, repo, number });
|
||||
const data = response.repository.issue;
|
||||
if (!data) return null;
|
||||
|
||||
const issue = {
|
||||
state: data.state,
|
||||
title: data.title,
|
||||
body: data.body || '',
|
||||
labels: data.labels.nodes.map((n) => n.name),
|
||||
subIssues: [...data.subIssues.nodes],
|
||||
comments: data.comments.nodes.map((n) => n.body),
|
||||
};
|
||||
|
||||
// Paginate subIssues if there are more than 100
|
||||
if (data.subIssues.pageInfo.hasNextPage) {
|
||||
const moreSubIssues = await paginateConnection(
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
'subIssues',
|
||||
'number repository { name owner { login } }',
|
||||
data.subIssues.pageInfo.endCursor,
|
||||
);
|
||||
issue.subIssues.push(...moreSubIssues);
|
||||
}
|
||||
|
||||
// Paginate labels if there are more than 100 (unlikely but for completeness)
|
||||
if (data.labels.pageInfo.hasNextPage) {
|
||||
const moreLabels = await paginateConnection(
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
'labels',
|
||||
'name',
|
||||
data.labels.pageInfo.endCursor,
|
||||
(n) => n.name,
|
||||
);
|
||||
issue.labels.push(...moreLabels);
|
||||
}
|
||||
|
||||
// Note: Comments are handled via Task Lists in body + first 100 comments.
|
||||
// If an issue has > 100 comments with task lists, we'd need to paginate those too.
|
||||
// Given the 1,100+ issue discovery count, 100 comments is usually sufficient,
|
||||
// but we can add it for absolute completeness.
|
||||
// (Skipping for now to avoid excessive API churn unless clearly needed).
|
||||
|
||||
return issue;
|
||||
} catch (error) {
|
||||
if (error.errors && error.errors.some((e) => e.type === 'NOT_FOUND')) {
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to paginate any GraphQL connection.
|
||||
*/
|
||||
async function paginateConnection(
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
connectionName,
|
||||
nodeFields,
|
||||
initialCursor,
|
||||
transformNode = (n) => n,
|
||||
) {
|
||||
let additionalNodes = [];
|
||||
let hasNext = true;
|
||||
let cursor = initialCursor;
|
||||
|
||||
while (hasNext) {
|
||||
const query = `
|
||||
query($owner:String!, $repo:String!, $number:Int!, $cursor:String) {
|
||||
repository(owner:$owner, name:$repo) {
|
||||
issue(number:$number) {
|
||||
${connectionName}(first: 100, after: $cursor) {
|
||||
nodes { ${nodeFields} }
|
||||
pageInfo { hasNextPage endCursor }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
const response = await octokit.graphql(query, {
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
cursor,
|
||||
});
|
||||
const connection = response.repository.issue[connectionName];
|
||||
additionalNodes.push(...connection.nodes.map(transformNode));
|
||||
hasNext = connection.pageInfo.hasNextPage;
|
||||
cursor = connection.pageInfo.endCursor;
|
||||
}
|
||||
return additionalNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if an issue should be processed (Open, not a duplicate, not a PR)
|
||||
*/
|
||||
function shouldProcess(issueData) {
|
||||
if (!issueData) return false;
|
||||
|
||||
if (issueData.state !== 'OPEN') return false;
|
||||
|
||||
const labels = issueData.labels.map((l) => l.toLowerCase());
|
||||
if (labels.includes('duplicate') || labels.includes('kind/duplicate')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async function getAllDescendants(roots) {
|
||||
const allDescendants = new Map();
|
||||
const visited = new Set();
|
||||
const queue = [...roots];
|
||||
|
||||
for (const root of roots) {
|
||||
visited.add(`${root.owner}/${root.repo}#${root.number}`);
|
||||
}
|
||||
|
||||
console.log(`Starting discovery from ${roots.length} roots...`);
|
||||
|
||||
while (queue.length > 0) {
|
||||
const current = queue.shift();
|
||||
const currentKey = `${current.owner}/${current.repo}#${current.number}`;
|
||||
|
||||
try {
|
||||
const issueData = await fetchIssueData(
|
||||
current.owner,
|
||||
current.repo,
|
||||
current.number,
|
||||
);
|
||||
|
||||
if (!shouldProcess(issueData)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// ONLY add to labeling list if it's in the PUBLIC repository
|
||||
if (current.repo === PUBLIC_REPO) {
|
||||
// Don't label the roots themselves
|
||||
if (
|
||||
!ROOT_ISSUES.some(
|
||||
(r) => r.number === current.number && r.repo === current.repo,
|
||||
)
|
||||
) {
|
||||
allDescendants.set(currentKey, {
|
||||
...current,
|
||||
title: issueData.title,
|
||||
labels: issueData.labels,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const children = new Map();
|
||||
|
||||
// 1. Process Native Sub-issues
|
||||
if (issueData.subIssues) {
|
||||
for (const node of issueData.subIssues) {
|
||||
const childOwner = node.repository.owner.login;
|
||||
const childRepo = node.repository.name;
|
||||
const childNumber = node.number;
|
||||
const key = `${childOwner}/${childRepo}#${childNumber}`;
|
||||
children.set(key, {
|
||||
owner: childOwner,
|
||||
repo: childRepo,
|
||||
number: childNumber,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Process Markdown Task Lists in Body and Comments
|
||||
let combinedText = issueData.body || '';
|
||||
if (issueData.comments) {
|
||||
for (const commentBody of issueData.comments) {
|
||||
combinedText += '\n' + (commentBody || '');
|
||||
}
|
||||
}
|
||||
|
||||
const taskListLinks = extractTaskListLinks(
|
||||
combinedText,
|
||||
current.owner,
|
||||
current.repo,
|
||||
);
|
||||
for (const link of taskListLinks) {
|
||||
const key = `${link.owner}/${link.repo}#${link.number}`;
|
||||
children.set(key, link);
|
||||
}
|
||||
|
||||
// Queue children (regardless of which repo they are in, for recursion)
|
||||
for (const [key, child] of children) {
|
||||
if (!visited.has(key)) {
|
||||
visited.add(key);
|
||||
queue.push(child);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error processing ${currentKey}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(allDescendants.values());
|
||||
}
|
||||
|
||||
async function run() {
|
||||
if (isDryRun) {
|
||||
console.log('=== DRY RUN MODE: No labels will be applied ===');
|
||||
}
|
||||
|
||||
const descendants = await getAllDescendants(ROOT_ISSUES);
|
||||
console.log(
|
||||
`\nFound ${descendants.length} total unique open descendant issues in ${PUBLIC_REPO}.`,
|
||||
);
|
||||
|
||||
for (const issueInfo of descendants) {
|
||||
const issueKey = `${issueInfo.owner}/${issueInfo.repo}#${issueInfo.number}`;
|
||||
try {
|
||||
// Data is already available from the discovery phase
|
||||
const hasLabel = issueInfo.labels.some((l) => l === TARGET_LABEL);
|
||||
|
||||
if (!hasLabel) {
|
||||
if (isDryRun) {
|
||||
console.log(
|
||||
`[DRY RUN] Would label ${issueKey}: "${issueInfo.title}"`,
|
||||
);
|
||||
} else {
|
||||
console.log(`Labeling ${issueKey}: "${issueInfo.title}"...`);
|
||||
await octokit.rest.issues.addLabels({
|
||||
owner: issueInfo.owner,
|
||||
repo: issueInfo.repo,
|
||||
issue_number: issueInfo.number,
|
||||
labels: [TARGET_LABEL],
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error processing label for ${issueKey}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,349 @@
|
||||
name: 'Testing: E2E (Chained)'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
merge_group:
|
||||
workflow_run:
|
||||
workflows: ['Trigger E2E']
|
||||
types: ['completed']
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
head_sha:
|
||||
description: 'SHA of the commit to test'
|
||||
required: true
|
||||
repo_name:
|
||||
description: 'Repository name (e.g., owner/repo)'
|
||||
required: true
|
||||
|
||||
concurrency:
|
||||
group: '${{ github.workflow }}-${{ github.head_ref || github.event.workflow_run.head_branch || github.ref }}'
|
||||
cancel-in-progress: |-
|
||||
${{ github.event_name != 'push' && github.event_name != 'merge_group' }}
|
||||
|
||||
permissions:
|
||||
contents: 'read'
|
||||
statuses: 'write'
|
||||
|
||||
jobs:
|
||||
merge_queue_skipper:
|
||||
name: 'Merge Queue Skipper'
|
||||
permissions: 'read-all'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
outputs:
|
||||
skip: '${{ steps.merge-queue-e2e-skipper.outputs.skip-check }}'
|
||||
steps:
|
||||
- id: 'merge-queue-e2e-skipper'
|
||||
uses: 'cariad-tech/merge-queue-ci-skipper@1032489e59437862c90a08a2c92809c903883772' # ratchet:cariad-tech/merge-queue-ci-skipper@main
|
||||
with:
|
||||
secret: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
continue-on-error: true
|
||||
|
||||
download_repo_name:
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
if: "${{github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_run'}}"
|
||||
outputs:
|
||||
repo_name: '${{ steps.output-repo-name.outputs.repo_name }}'
|
||||
head_sha: '${{ steps.output-repo-name.outputs.head_sha }}'
|
||||
steps:
|
||||
- name: 'Mock Repo Artifact'
|
||||
if: "${{ github.event_name == 'workflow_dispatch' }}"
|
||||
env:
|
||||
REPO_NAME: '${{ github.event.inputs.repo_name }}'
|
||||
run: |
|
||||
mkdir -p ./pr
|
||||
echo '${{ env.REPO_NAME }}' > ./pr/repo_name
|
||||
- uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'repo_name'
|
||||
path: 'pr/'
|
||||
- name: 'Download the repo_name artifact'
|
||||
uses: 'actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0' # ratchet:actions/download-artifact@v5
|
||||
env:
|
||||
RUN_ID: "${{ github.event_name == 'workflow_run' && github.event.workflow_run.id || github.run_id }}"
|
||||
with:
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
name: 'repo_name'
|
||||
run-id: '${{ env.RUN_ID }}'
|
||||
path: '${{ runner.temp }}/artifacts'
|
||||
- name: 'Output Repo Name and SHA'
|
||||
id: 'output-repo-name'
|
||||
uses: 'actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd' # ratchet:actions/github-script@v8
|
||||
with:
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const temp = '${{ runner.temp }}/artifacts';
|
||||
const repoPath = path.join(temp, 'repo_name');
|
||||
if (fs.existsSync(repoPath)) {
|
||||
const repo_name = String(fs.readFileSync(repoPath)).trim();
|
||||
core.setOutput('repo_name', repo_name);
|
||||
}
|
||||
const shaPath = path.join(temp, 'head_sha');
|
||||
if (fs.existsSync(shaPath)) {
|
||||
const head_sha = String(fs.readFileSync(shaPath)).trim();
|
||||
core.setOutput('head_sha', head_sha);
|
||||
}
|
||||
|
||||
parse_run_context:
|
||||
name: 'Parse run context'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
needs: 'download_repo_name'
|
||||
if: 'always()'
|
||||
outputs:
|
||||
repository: '${{ steps.set_context.outputs.REPO }}'
|
||||
sha: '${{ steps.set_context.outputs.SHA }}'
|
||||
steps:
|
||||
- id: 'set_context'
|
||||
name: 'Set dynamic repository and SHA'
|
||||
env:
|
||||
REPO: '${{ needs.download_repo_name.outputs.repo_name || github.repository }}'
|
||||
SHA: '${{ needs.download_repo_name.outputs.head_sha || github.event.inputs.head_sha || github.event.workflow_run.head_sha || github.sha }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
echo "REPO=$REPO" >> "$GITHUB_OUTPUT"
|
||||
echo "SHA=$SHA" >> "$GITHUB_OUTPUT"
|
||||
|
||||
set_pending_status:
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
permissions: 'write-all'
|
||||
needs:
|
||||
- 'parse_run_context'
|
||||
if: 'always()'
|
||||
steps:
|
||||
- name: 'Set pending status'
|
||||
uses: 'myrotvorets/set-commit-status-action@16037e056d73b2d3c88e37e393ff369047f70886' # ratchet:myrotvorets/set-commit-status-action@master
|
||||
if: 'always()'
|
||||
with:
|
||||
allowForks: 'true'
|
||||
repo: '${{ github.repository }}'
|
||||
sha: '${{ needs.parse_run_context.outputs.sha }}'
|
||||
token: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
status: 'pending'
|
||||
context: 'E2E (Chained)'
|
||||
|
||||
e2e_linux:
|
||||
name: 'E2E Test (Linux) - ${{ matrix.sandbox }}'
|
||||
needs:
|
||||
- 'merge_queue_skipper'
|
||||
- 'parse_run_context'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
if: |
|
||||
always() && (needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip != 'true')
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
sandbox:
|
||||
- 'sandbox:none'
|
||||
- 'sandbox:docker'
|
||||
node-version:
|
||||
- '20.x'
|
||||
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
with:
|
||||
ref: '${{ needs.parse_run_context.outputs.sha }}'
|
||||
repository: '${{ needs.parse_run_context.outputs.repository }}'
|
||||
|
||||
- name: 'Set up Node.js ${{ matrix.node-version }}'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
|
||||
with:
|
||||
node-version: '${{ matrix.node-version }}'
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Build project'
|
||||
run: 'npm run build'
|
||||
|
||||
- name: 'Set up Docker'
|
||||
if: "${{matrix.sandbox == 'sandbox:docker'}}"
|
||||
uses: 'docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435' # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: 'Run E2E tests'
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
|
||||
KEEP_OUTPUT: 'true'
|
||||
VERBOSE: 'true'
|
||||
BUILD_SANDBOX_FLAGS: '--cache-from type=gha --cache-to type=gha,mode=max'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
if [[ "${{ matrix.sandbox }}" == "sandbox:docker" ]]; then
|
||||
npm run test:integration:sandbox:docker
|
||||
else
|
||||
npm run test:integration:sandbox:none
|
||||
fi
|
||||
|
||||
e2e_mac:
|
||||
name: 'E2E Test (macOS)'
|
||||
needs:
|
||||
- 'merge_queue_skipper'
|
||||
- 'parse_run_context'
|
||||
runs-on: 'macos-latest'
|
||||
if: |
|
||||
always() && (needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip != 'true')
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
with:
|
||||
ref: '${{ needs.parse_run_context.outputs.sha }}'
|
||||
repository: '${{ needs.parse_run_context.outputs.repository }}'
|
||||
|
||||
- name: 'Set up Node.js 20.x'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Build project'
|
||||
run: 'npm run build'
|
||||
|
||||
- name: 'Fix rollup optional dependencies on macOS'
|
||||
if: "${{runner.os == 'macOS'}}"
|
||||
run: |
|
||||
npm cache clean --force
|
||||
- name: 'Run E2E tests (non-Windows)'
|
||||
if: "${{runner.os != 'Windows'}}"
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
|
||||
KEEP_OUTPUT: 'true'
|
||||
SANDBOX: 'sandbox:none'
|
||||
VERBOSE: 'true'
|
||||
run: 'npm run test:integration:sandbox:none'
|
||||
|
||||
e2e_windows:
|
||||
name: 'Slow E2E - Win'
|
||||
needs:
|
||||
- 'merge_queue_skipper'
|
||||
- 'parse_run_context'
|
||||
if: |
|
||||
always() && (needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip != 'true')
|
||||
runs-on: 'gemini-cli-windows-16-core'
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
with:
|
||||
ref: '${{ needs.parse_run_context.outputs.sha }}'
|
||||
repository: '${{ needs.parse_run_context.outputs.repository }}'
|
||||
|
||||
- name: 'Set up Node.js 20.x'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Configure Windows Defender exclusions'
|
||||
run: |
|
||||
Add-MpPreference -ExclusionPath $env:GITHUB_WORKSPACE -Force
|
||||
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\node_modules" -Force
|
||||
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\packages" -Force
|
||||
Add-MpPreference -ExclusionPath "$env:TEMP" -Force
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Configure npm for Windows performance'
|
||||
run: |
|
||||
npm config set progress false
|
||||
npm config set audit false
|
||||
npm config set fund false
|
||||
npm config set loglevel error
|
||||
npm config set maxsockets 32
|
||||
npm config set registry https://registry.npmjs.org/
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: 'npm ci'
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Build project'
|
||||
run: 'npm run build'
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Run E2E tests'
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
|
||||
KEEP_OUTPUT: 'true'
|
||||
SANDBOX: 'sandbox:none'
|
||||
VERBOSE: 'true'
|
||||
NODE_OPTIONS: '--max-old-space-size=32768 --max-semi-space-size=256'
|
||||
UV_THREADPOOL_SIZE: '32'
|
||||
NODE_ENV: 'test'
|
||||
shell: 'pwsh'
|
||||
run: 'npm run test:integration:sandbox:none'
|
||||
|
||||
evals:
|
||||
name: 'Evals (ALWAYS_PASSING)'
|
||||
needs:
|
||||
- 'merge_queue_skipper'
|
||||
- 'parse_run_context'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
if: |
|
||||
always() && (needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip != 'true')
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
with:
|
||||
ref: '${{ needs.parse_run_context.outputs.sha }}'
|
||||
repository: '${{ needs.parse_run_context.outputs.repository }}'
|
||||
|
||||
- name: 'Set up Node.js 20.x'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Build project'
|
||||
run: 'npm run build'
|
||||
|
||||
- name: 'Run Evals (Required to pass)'
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
|
||||
run: 'npm run test:always_passing_evals'
|
||||
|
||||
e2e:
|
||||
name: 'E2E'
|
||||
if: |
|
||||
always() && (needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip != 'true')
|
||||
needs:
|
||||
- 'e2e_linux'
|
||||
- 'e2e_mac'
|
||||
- 'e2e_windows'
|
||||
- 'evals'
|
||||
- 'merge_queue_skipper'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
steps:
|
||||
- name: 'Check E2E test results'
|
||||
run: |
|
||||
if [[ ${{ needs.e2e_linux.result }} != 'success' || \
|
||||
${{ needs.e2e_mac.result }} != 'success' || \
|
||||
${{ needs.e2e_windows.result }} != 'success' || \
|
||||
${{ needs.evals.result }} != 'success' ]]; then
|
||||
echo "One or more E2E jobs failed."
|
||||
exit 1
|
||||
fi
|
||||
echo "All required E2E jobs passed!"
|
||||
|
||||
set_workflow_status:
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
permissions: 'write-all'
|
||||
if: 'always()'
|
||||
needs:
|
||||
- 'parse_run_context'
|
||||
- 'e2e'
|
||||
steps:
|
||||
- name: 'Set workflow status'
|
||||
uses: 'myrotvorets/set-commit-status-action@16037e056d73b2d3c88e37e393ff369047f70886' # ratchet:myrotvorets/set-commit-status-action@master
|
||||
if: 'always()'
|
||||
with:
|
||||
allowForks: 'true'
|
||||
repo: '${{ github.repository }}'
|
||||
sha: '${{ needs.parse_run_context.outputs.sha }}'
|
||||
token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
status: '${{ needs.e2e.result }}'
|
||||
context: 'E2E (Chained)'
|
||||
+150
-19
@@ -34,6 +34,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
merge_queue_skipper:
|
||||
permissions: 'read-all'
|
||||
name: 'Merge Queue Skipper'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
outputs:
|
||||
@@ -42,19 +43,21 @@ jobs:
|
||||
- id: 'merge-queue-ci-skipper'
|
||||
uses: 'cariad-tech/merge-queue-ci-skipper@1032489e59437862c90a08a2c92809c903883772' # ratchet:cariad-tech/merge-queue-ci-skipper@main
|
||||
with:
|
||||
secret: '${{ secrets.GITHUB_TOKEN }}'
|
||||
secret: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
|
||||
lint:
|
||||
name: 'Lint'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
needs: 'merge_queue_skipper'
|
||||
if: "${{needs.merge_queue_skipper.outputs.skip == 'false'}}"
|
||||
env:
|
||||
GEMINI_LINT_TEMP_DIR: '${{ github.workspace }}/.gemini-linters'
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
|
||||
with:
|
||||
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
|
||||
fetch-depth: 1
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 'Set up Node.js'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4.4.0
|
||||
@@ -62,9 +65,24 @@ jobs:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Cache Linters'
|
||||
uses: 'actions/cache@v4'
|
||||
with:
|
||||
path: '${{ env.GEMINI_LINT_TEMP_DIR }}'
|
||||
key: "${{ runner.os }}-${{ runner.arch }}-linters-${{ hashFiles('scripts/lint.js') }}"
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Cache ESLint'
|
||||
uses: 'actions/cache@v4'
|
||||
with:
|
||||
path: '.eslintcache'
|
||||
key: "${{ runner.os }}-eslint-${{ hashFiles('package-lock.json', 'eslint.config.js') }}"
|
||||
|
||||
- name: 'Validate NOTICES.txt'
|
||||
run: 'git diff --exit-code packages/vscode-ide-companion/NOTICES.txt'
|
||||
|
||||
- name: 'Check lockfile'
|
||||
run: 'npm run check:lockfile'
|
||||
|
||||
@@ -86,11 +104,30 @@ jobs:
|
||||
- name: 'Run Prettier'
|
||||
run: 'node scripts/lint.js --prettier'
|
||||
|
||||
- name: 'Build docs prerequisites'
|
||||
run: 'npm run predocs:settings'
|
||||
|
||||
- name: 'Verify settings docs'
|
||||
run: 'npm run docs:settings -- --check'
|
||||
|
||||
- name: 'Run sensitive keyword linter'
|
||||
run: 'node scripts/lint.js --sensitive-keywords'
|
||||
|
||||
link_checker:
|
||||
name: 'Link Checker'
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
|
||||
- name: 'Link Checker'
|
||||
uses: 'lycheeverse/lychee-action@885c65f3dc543b57c898c8099f4e08c8afd178a2' # ratchet: lycheeverse/lychee-action@v2.6.1
|
||||
with:
|
||||
args: '--verbose --accept 200,503 ./**/*.md'
|
||||
fail: true
|
||||
test_linux:
|
||||
name: 'Test (Linux)'
|
||||
name: 'Test (Linux) - ${{ matrix.node-version }}, ${{ matrix.shard }}'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
needs:
|
||||
- 'lint'
|
||||
- 'merge_queue_skipper'
|
||||
if: "${{needs.merge_queue_skipper.outputs.skip == 'false'}}"
|
||||
permissions:
|
||||
@@ -103,6 +140,9 @@ jobs:
|
||||
- '20.x'
|
||||
- '22.x'
|
||||
- '24.x'
|
||||
shard:
|
||||
- 'cli'
|
||||
- 'others'
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
|
||||
@@ -122,7 +162,33 @@ jobs:
|
||||
- name: 'Run tests and generate reports'
|
||||
env:
|
||||
NO_COLOR: true
|
||||
run: 'npm run test:ci'
|
||||
run: |
|
||||
if [[ "${{ matrix.shard }}" == "cli" ]]; then
|
||||
npm run test:ci --workspace @google/gemini-cli
|
||||
else
|
||||
# Explicitly list non-cli packages to ensure they are sharded correctly
|
||||
npm run test:ci --workspace @google/gemini-cli-core --workspace @google/gemini-cli-a2a-server --workspace gemini-cli-vscode-ide-companion --workspace @google/gemini-cli-test-utils --if-present
|
||||
npm run test:scripts
|
||||
fi
|
||||
|
||||
- name: 'Bundle'
|
||||
run: 'npm run bundle'
|
||||
|
||||
- name: 'Smoke test bundle'
|
||||
run: 'node ./bundle/gemini.js --version'
|
||||
|
||||
- name: 'Smoke test npx installation'
|
||||
run: |
|
||||
# 1. Package the project into a tarball
|
||||
TARBALL=$(npm pack | tail -n 1)
|
||||
|
||||
# 2. Move to a fresh directory for isolation
|
||||
mkdir -p ../smoke-test-dir
|
||||
mv "$TARBALL" ../smoke-test-dir/
|
||||
cd ../smoke-test-dir
|
||||
|
||||
# 3. Run npx from the tarball
|
||||
npx "./$TARBALL" --version
|
||||
|
||||
- name: 'Wait for file system sync'
|
||||
run: 'sleep 2'
|
||||
@@ -132,7 +198,7 @@ jobs:
|
||||
${{ always() && (github.event.pull_request.head.repo.full_name == github.repository) }}
|
||||
uses: 'dorny/test-reporter@dc3a92680fcc15842eef52e8c4606ea7ce6bd3f3' # ratchet:dorny/test-reporter@v2
|
||||
with:
|
||||
name: 'Test Results (Node ${{ matrix.node-version }})'
|
||||
name: 'Test Results (Node ${{ runner.os }}, ${{ matrix.node-version }}, ${{ matrix.shard }})'
|
||||
path: 'packages/*/junit.xml'
|
||||
reporter: 'java-junit'
|
||||
fail-on-error: 'false'
|
||||
@@ -142,14 +208,13 @@ jobs:
|
||||
${{ always() && (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
|
||||
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'test-results-fork-${{ matrix.node-version }}-${{ runner.os }}'
|
||||
name: 'test-results-fork-${{ runner.os }}-${{ matrix.node-version }}-${{ matrix.shard }}'
|
||||
path: 'packages/*/junit.xml'
|
||||
|
||||
test_mac:
|
||||
name: 'Test (Mac)'
|
||||
runs-on: '${{ matrix.os }}'
|
||||
name: 'Test (Mac) - ${{ matrix.node-version }}, ${{ matrix.shard }}'
|
||||
runs-on: 'macos-latest'
|
||||
needs:
|
||||
- 'lint'
|
||||
- 'merge_queue_skipper'
|
||||
if: "${{needs.merge_queue_skipper.outputs.skip == 'false'}}"
|
||||
permissions:
|
||||
@@ -159,12 +224,13 @@ jobs:
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- 'macos-latest'
|
||||
node-version:
|
||||
- '20.x'
|
||||
- '22.x'
|
||||
- '24.x'
|
||||
shard:
|
||||
- 'cli'
|
||||
- 'others'
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
|
||||
@@ -184,7 +250,33 @@ jobs:
|
||||
- name: 'Run tests and generate reports'
|
||||
env:
|
||||
NO_COLOR: true
|
||||
run: 'npm run test:ci -- --coverage.enabled=false'
|
||||
run: |
|
||||
if [[ "${{ matrix.shard }}" == "cli" ]]; then
|
||||
npm run test:ci --workspace @google/gemini-cli -- --coverage.enabled=false
|
||||
else
|
||||
# Explicitly list non-cli packages to ensure they are sharded correctly
|
||||
npm run test:ci --workspace @google/gemini-cli-core --workspace @google/gemini-cli-a2a-server --workspace gemini-cli-vscode-ide-companion --workspace @google/gemini-cli-test-utils --if-present -- --coverage.enabled=false
|
||||
npm run test:scripts
|
||||
fi
|
||||
|
||||
- name: 'Bundle'
|
||||
run: 'npm run bundle'
|
||||
|
||||
- name: 'Smoke test bundle'
|
||||
run: 'node ./bundle/gemini.js --version'
|
||||
|
||||
- name: 'Smoke test npx installation'
|
||||
run: |
|
||||
# 1. Package the project into a tarball
|
||||
TARBALL=$(npm pack | tail -n 1)
|
||||
|
||||
# 2. Move to a fresh directory for isolation
|
||||
mkdir -p ../smoke-test-dir
|
||||
mv "$TARBALL" ../smoke-test-dir/
|
||||
cd ../smoke-test-dir
|
||||
|
||||
# 3. Run npx from the tarball
|
||||
npx "./$TARBALL" --version
|
||||
|
||||
- name: 'Wait for file system sync'
|
||||
run: 'sleep 2'
|
||||
@@ -194,7 +286,7 @@ jobs:
|
||||
${{ always() && (github.event.pull_request.head.repo.full_name == github.repository) }}
|
||||
uses: 'dorny/test-reporter@dc3a92680fcc15842eef52e8c4606ea7ce6bd3f3' # ratchet:dorny/test-reporter@v2
|
||||
with:
|
||||
name: 'Test Results (Node ${{ matrix.node-version }})'
|
||||
name: 'Test Results (Node ${{ runner.os }}, ${{ matrix.node-version }}, ${{ matrix.shard }})'
|
||||
path: 'packages/*/junit.xml'
|
||||
reporter: 'java-junit'
|
||||
fail-on-error: 'false'
|
||||
@@ -204,7 +296,7 @@ jobs:
|
||||
${{ always() && (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
|
||||
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'test-results-fork-${{ matrix.node-version }}-${{ runner.os }}'
|
||||
name: 'test-results-fork-${{ runner.os }}-${{ matrix.node-version }}-${{ matrix.shard }}'
|
||||
path: 'packages/*/junit.xml'
|
||||
|
||||
- name: 'Upload coverage reports'
|
||||
@@ -212,7 +304,7 @@ jobs:
|
||||
${{ always() }}
|
||||
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'coverage-reports-${{ matrix.node-version }}-${{ matrix.os }}'
|
||||
name: 'coverage-reports-${{ runner.os }}-${{ matrix.node-version }}-${{ matrix.shard }}'
|
||||
path: 'packages/*/coverage'
|
||||
|
||||
codeql:
|
||||
@@ -264,11 +356,16 @@ jobs:
|
||||
clean-script: 'clean'
|
||||
|
||||
test_windows:
|
||||
name: 'Slow Test - Win'
|
||||
name: 'Slow Test - Win - ${{ matrix.shard }}'
|
||||
runs-on: 'gemini-cli-windows-16-core'
|
||||
needs: 'merge_queue_skipper'
|
||||
if: "${{needs.merge_queue_skipper.outputs.skip == 'false'}}"
|
||||
continue-on-error: true
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
matrix:
|
||||
shard:
|
||||
- 'cli'
|
||||
- 'others'
|
||||
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
@@ -319,7 +416,37 @@ jobs:
|
||||
NODE_OPTIONS: '--max-old-space-size=32768 --max-semi-space-size=256'
|
||||
UV_THREADPOOL_SIZE: '32'
|
||||
NODE_ENV: 'test'
|
||||
run: 'npm run test:ci -- --coverage.enabled=false'
|
||||
run: |
|
||||
if ("${{ matrix.shard }}" -eq "cli") {
|
||||
npm run test:ci --workspace @google/gemini-cli -- --coverage.enabled=false
|
||||
} else {
|
||||
# Explicitly list non-cli packages to ensure they are sharded correctly
|
||||
npm run test:ci --workspace @google/gemini-cli-core --workspace @google/gemini-cli-a2a-server --workspace gemini-cli-vscode-ide-companion --workspace @google/gemini-cli-test-utils --if-present -- --coverage.enabled=false
|
||||
npm run test:scripts
|
||||
}
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Bundle'
|
||||
run: 'npm run bundle'
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Smoke test bundle'
|
||||
run: 'node ./bundle/gemini.js --version'
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Smoke test npx installation'
|
||||
run: |
|
||||
# 1. Package the project into a tarball
|
||||
$PACK_OUTPUT = npm pack
|
||||
$TARBALL = $PACK_OUTPUT[-1]
|
||||
|
||||
# 2. Move to a fresh directory for isolation
|
||||
New-Item -ItemType Directory -Force -Path ../smoke-test-dir
|
||||
Move-Item $TARBALL ../smoke-test-dir/
|
||||
Set-Location ../smoke-test-dir
|
||||
|
||||
# 3. Run npx from the tarball
|
||||
npx "./$TARBALL" --version
|
||||
shell: 'pwsh'
|
||||
|
||||
ci:
|
||||
@@ -327,8 +454,10 @@ jobs:
|
||||
if: 'always()'
|
||||
needs:
|
||||
- 'lint'
|
||||
- 'link_checker'
|
||||
- 'test_linux'
|
||||
- 'test_mac'
|
||||
- 'test_windows'
|
||||
- 'codeql'
|
||||
- 'bundle_size'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
@@ -336,8 +465,10 @@ jobs:
|
||||
- name: 'Check all job results'
|
||||
run: |
|
||||
if [[ (${{ needs.lint.result }} != 'success' && ${{ needs.lint.result }} != 'skipped') || \
|
||||
(${{ needs.link_checker.result }} != 'success' && ${{ needs.link_checker.result }} != 'skipped') || \
|
||||
(${{ needs.test_linux.result }} != 'success' && ${{ needs.test_linux.result }} != 'skipped') || \
|
||||
(${{ needs.test_mac.result }} != 'success' && ${{ needs.test_mac.result }} != 'skipped') || \
|
||||
(${{ needs.test_windows.result }} != 'success' && ${{ needs.test_windows.result }} != 'skipped') || \
|
||||
(${{ needs.codeql.result }} != 'success' && ${{ needs.codeql.result }} != 'skipped') || \
|
||||
(${{ needs.bundle_size.result }} != 'success' && ${{ needs.bundle_size.result }} != 'skipped') ]]; then
|
||||
echo "One or more CI jobs failed."
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
name: 'Deflake E2E'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch_ref:
|
||||
description: 'Branch to run on'
|
||||
required: true
|
||||
default: 'main'
|
||||
type: 'string'
|
||||
test_name_pattern:
|
||||
description: 'The test name pattern to use'
|
||||
required: false
|
||||
type: 'string'
|
||||
runs:
|
||||
description: 'The number of runs'
|
||||
required: false
|
||||
default: 5
|
||||
type: 'number'
|
||||
|
||||
concurrency:
|
||||
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
|
||||
cancel-in-progress: |-
|
||||
${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/heads/release/') }}
|
||||
|
||||
jobs:
|
||||
deflake_e2e_linux:
|
||||
name: 'E2E Test (Linux) - ${{ matrix.sandbox }}'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
sandbox:
|
||||
- 'sandbox:none'
|
||||
- 'sandbox:docker'
|
||||
node-version:
|
||||
- '20.x'
|
||||
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
with:
|
||||
ref: '${{ github.event.pull_request.head.sha }}'
|
||||
repository: '${{ github.repository }}'
|
||||
|
||||
- name: 'Set up Node.js ${{ matrix.node-version }}'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
|
||||
with:
|
||||
node-version: '${{ matrix.node-version }}'
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Build project'
|
||||
run: 'npm run build'
|
||||
|
||||
- name: 'Set up Docker'
|
||||
if: "matrix.sandbox == 'sandbox:docker'"
|
||||
uses: 'docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435' # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: 'Run E2E tests'
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
|
||||
IS_DOCKER: "${{ matrix.sandbox == 'sandbox:docker' }}"
|
||||
KEEP_OUTPUT: 'true'
|
||||
RUNS: '${{ github.event.inputs.runs }}'
|
||||
TEST_NAME_PATTERN: '${{ github.event.inputs.test_name_pattern }}'
|
||||
VERBOSE: 'true'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
if [[ "${{ env.IS_DOCKER }}" == "true" ]]; then
|
||||
npm run deflake:test:integration:sandbox:docker -- --runs="${{ env.RUNS }}" -- --testNamePattern "'${{ env.TEST_NAME_PATTERN }}'"
|
||||
else
|
||||
npm run deflake:test:integration:sandbox:none -- --runs="${{ env.RUNS }}" -- --testNamePattern "'${{ env.TEST_NAME_PATTERN }}'"
|
||||
fi
|
||||
|
||||
deflake_e2e_mac:
|
||||
name: 'E2E Test (macOS)'
|
||||
runs-on: 'macos-latest'
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
with:
|
||||
ref: '${{ github.event.pull_request.head.sha }}'
|
||||
repository: '${{ github.repository }}'
|
||||
|
||||
- name: 'Set up Node.js 20.x'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Build project'
|
||||
run: 'npm run build'
|
||||
|
||||
- name: 'Fix rollup optional dependencies on macOS'
|
||||
if: "runner.os == 'macOS'"
|
||||
run: |
|
||||
npm cache clean --force
|
||||
- name: 'Run E2E tests (non-Windows)'
|
||||
if: "runner.os != 'Windows'"
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
|
||||
KEEP_OUTPUT: 'true'
|
||||
RUNS: '${{ github.event.inputs.runs }}'
|
||||
SANDBOX: 'sandbox:none'
|
||||
TEST_NAME_PATTERN: '${{ github.event.inputs.test_name_pattern }}'
|
||||
VERBOSE: 'true'
|
||||
run: |
|
||||
npm run deflake:test:integration:sandbox:none -- --runs="${{ env.RUNS }}" -- --testNamePattern "'${{ env.TEST_NAME_PATTERN }}'"
|
||||
|
||||
deflake_e2e_windows:
|
||||
name: 'Slow E2E - Win'
|
||||
runs-on: 'gemini-cli-windows-16-core'
|
||||
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
with:
|
||||
ref: '${{ github.event.pull_request.head.sha }}'
|
||||
repository: '${{ github.repository }}'
|
||||
|
||||
- name: 'Set up Node.js 20.x'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Configure Windows Defender exclusions'
|
||||
run: |
|
||||
Add-MpPreference -ExclusionPath $env:GITHUB_WORKSPACE -Force
|
||||
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\node_modules" -Force
|
||||
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\packages" -Force
|
||||
Add-MpPreference -ExclusionPath "$env:TEMP" -Force
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Configure npm for Windows performance'
|
||||
run: |
|
||||
npm config set progress false
|
||||
npm config set audit false
|
||||
npm config set fund false
|
||||
npm config set loglevel error
|
||||
npm config set maxsockets 32
|
||||
npm config set registry https://registry.npmjs.org/
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: 'npm ci'
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Build project'
|
||||
run: 'npm run build'
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Run E2E tests'
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
|
||||
KEEP_OUTPUT: 'true'
|
||||
SANDBOX: 'sandbox:none'
|
||||
VERBOSE: 'true'
|
||||
NODE_OPTIONS: '--max-old-space-size=32768 --max-semi-space-size=256'
|
||||
UV_THREADPOOL_SIZE: '32'
|
||||
NODE_ENV: 'test'
|
||||
RUNS: '${{ github.event.inputs.runs }}'
|
||||
TEST_NAME_PATTERN: '${{ github.event.inputs.test_name_pattern }}'
|
||||
shell: 'pwsh'
|
||||
run: |
|
||||
npm run deflake:test:integration:sandbox:none -- --runs="${{ env.RUNS }}" -- --testNamePattern "'${{ env.TEST_NAME_PATTERN }}'"
|
||||
@@ -1,245 +0,0 @@
|
||||
name: 'Testing: E2E'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
# This will run for PRs from the base repository, providing secrets.
|
||||
pull_request:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'release/**'
|
||||
# This will run for PRs from forks when a label is added.
|
||||
pull_request_target:
|
||||
types: ['labeled']
|
||||
merge_group:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch_ref:
|
||||
description: 'Branch to run on'
|
||||
required: true
|
||||
default: 'main'
|
||||
type: 'string'
|
||||
|
||||
concurrency:
|
||||
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
|
||||
cancel-in-progress: |-
|
||||
${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/heads/release/') }}
|
||||
|
||||
jobs:
|
||||
merge_queue_skipper:
|
||||
name: 'Merge Queue Skipper'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
outputs:
|
||||
skip: '${{ steps.merge-queue-e2e-skipper.outputs.skip-check }}'
|
||||
steps:
|
||||
- id: 'merge-queue-e2e-skipper'
|
||||
uses: 'cariad-tech/merge-queue-ci-skipper@1032489e59437862c90a08a2c92809c903883772' # ratchet:cariad-tech/merge-queue-ci-skipper@main
|
||||
with:
|
||||
secret: '${{ secrets.GITHUB_TOKEN }}'
|
||||
|
||||
e2e_linux:
|
||||
name: 'E2E Test (Linux) - ${{ matrix.sandbox }}'
|
||||
needs: 'merge_queue_skipper'
|
||||
if: |
|
||||
needs.merge_queue_skipper.outputs.skip == 'false' &&
|
||||
(github.event_name == 'push' ||
|
||||
github.event_name == 'merge_group' ||
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(github.event.pull_request.head.repo.full_name == github.repository) ||
|
||||
(github.event.label.name == 'maintainer:e2e:ok'))
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
sandbox:
|
||||
- 'sandbox:none'
|
||||
- 'sandbox:docker'
|
||||
node-version:
|
||||
- '20.x'
|
||||
|
||||
steps:
|
||||
- name: 'Checkout (fork)'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
if: "github.event_name == 'pull_request_target'"
|
||||
with:
|
||||
ref: '${{ github.event.pull_request.head.sha }}'
|
||||
repository: '${{ github.event.pull_request.head.repo.full_name }}'
|
||||
|
||||
- name: 'Checkout (internal)'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
if: "github.event_name != 'pull_request_target'"
|
||||
with:
|
||||
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
|
||||
|
||||
- name: 'Set up Node.js ${{ matrix.node-version }}'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
|
||||
with:
|
||||
node-version: '${{ matrix.node-version }}'
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Build project'
|
||||
run: 'npm run build'
|
||||
|
||||
- name: 'Set up Docker'
|
||||
if: "matrix.sandbox == 'sandbox:docker'"
|
||||
uses: 'docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435' # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: 'Run E2E tests'
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
|
||||
KEEP_OUTPUT: 'true'
|
||||
VERBOSE: 'true'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
if [[ "${{ matrix.sandbox }}" == "sandbox:docker" ]]; then
|
||||
npm run test:integration:sandbox:docker
|
||||
else
|
||||
npm run test:integration:sandbox:none
|
||||
fi
|
||||
|
||||
e2e_mac:
|
||||
name: 'E2E Test (macOS)'
|
||||
needs: 'merge_queue_skipper'
|
||||
if: |
|
||||
needs.merge_queue_skipper.outputs.skip == 'false' &&
|
||||
(github.event_name == 'push' ||
|
||||
github.event_name == 'merge_group' ||
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(github.event.pull_request.head.repo.full_name == github.repository) ||
|
||||
(github.event.label.name == 'maintainer:e2e:ok'))
|
||||
runs-on: 'macos-latest'
|
||||
steps:
|
||||
- name: 'Checkout (fork)'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
if: "github.event_name == 'pull_request_target'"
|
||||
with:
|
||||
ref: '${{ github.event.pull_request.head.sha }}'
|
||||
repository: '${{ github.event.pull_request.head.repo.full_name }}'
|
||||
|
||||
- name: 'Checkout (internal)'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
if: "github.event_name != 'pull_request_target'"
|
||||
with:
|
||||
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
|
||||
|
||||
- name: 'Set up Node.js 20.x'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Build project'
|
||||
run: 'npm run build'
|
||||
|
||||
- name: 'Fix rollup optional dependencies on macOS'
|
||||
if: "runner.os == 'macOS'"
|
||||
run: |
|
||||
npm cache clean --force
|
||||
- name: 'Run E2E tests (non-Windows)'
|
||||
if: "runner.os != 'Windows'"
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
|
||||
KEEP_OUTPUT: 'true'
|
||||
SANDBOX: 'sandbox:none'
|
||||
VERBOSE: 'true'
|
||||
run: 'npm run test:integration:sandbox:none'
|
||||
|
||||
e2e_windows:
|
||||
name: 'Slow E2E - Win'
|
||||
needs: 'merge_queue_skipper'
|
||||
if: |
|
||||
needs.merge_queue_skipper.outputs.skip == 'false' &&
|
||||
(github.event_name == 'push' ||
|
||||
github.event_name == 'merge_group' ||
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(github.event.pull_request.head.repo.full_name == github.repository) ||
|
||||
(github.event.label.name == 'maintainer:e2e:ok'))
|
||||
runs-on: 'gemini-cli-windows-16-core'
|
||||
continue-on-error: true
|
||||
|
||||
steps:
|
||||
- name: 'Checkout (fork)'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
if: "github.event_name == 'pull_request_target'"
|
||||
with:
|
||||
ref: '${{ github.event.pull_request.head.sha }}'
|
||||
repository: '${{ github.event.pull_request.head.repo.full_name }}'
|
||||
|
||||
- name: 'Checkout (internal)'
|
||||
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
|
||||
if: "github.event_name != 'pull_request_target'"
|
||||
with:
|
||||
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
|
||||
|
||||
- name: 'Set up Node.js 20.x'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Configure Windows Defender exclusions'
|
||||
run: |
|
||||
Add-MpPreference -ExclusionPath $env:GITHUB_WORKSPACE -Force
|
||||
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\node_modules" -Force
|
||||
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\packages" -Force
|
||||
Add-MpPreference -ExclusionPath "$env:TEMP" -Force
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Configure npm for Windows performance'
|
||||
run: |
|
||||
npm config set progress false
|
||||
npm config set audit false
|
||||
npm config set fund false
|
||||
npm config set loglevel error
|
||||
npm config set maxsockets 32
|
||||
npm config set registry https://registry.npmjs.org/
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: 'npm ci'
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Build project'
|
||||
run: 'npm run build'
|
||||
shell: 'pwsh'
|
||||
|
||||
- name: 'Run E2E tests'
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
|
||||
KEEP_OUTPUT: 'true'
|
||||
SANDBOX: 'sandbox:none'
|
||||
VERBOSE: 'true'
|
||||
NODE_OPTIONS: '--max-old-space-size=32768 --max-semi-space-size=256'
|
||||
UV_THREADPOOL_SIZE: '32'
|
||||
NODE_ENV: 'test'
|
||||
shell: 'pwsh'
|
||||
run: 'npm run test:integration:sandbox:none'
|
||||
|
||||
e2e:
|
||||
name: 'E2E'
|
||||
if: |
|
||||
always() && (
|
||||
github.event_name == 'push' ||
|
||||
github.event_name == 'merge_group' ||
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(github.event.pull_request.head.repo.full_name == github.repository) ||
|
||||
(github.event.label.name == 'maintainer:e2e:ok')
|
||||
)
|
||||
needs:
|
||||
- 'e2e_linux'
|
||||
- 'e2e_mac'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
steps:
|
||||
- name: 'Check E2E test results'
|
||||
run: |
|
||||
if [[ (${{ needs.e2e_linux.result }} != 'success' && ${{ needs.e2e_linux.result }} != 'skipped') || \
|
||||
(${{ needs.e2e_mac.result }} != 'success' && ${{ needs.e2e_mac.result }} != 'skipped') ]]; then
|
||||
echo "One or more E2E jobs failed."
|
||||
exit 1
|
||||
fi
|
||||
echo "All required E2E jobs passed!"
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
steps:
|
||||
- name: 'Authenticate to Google Cloud'
|
||||
id: 'auth'
|
||||
uses: 'google-github-actions/auth@v2' # ratchet:exclude
|
||||
uses: 'google-github-actions/auth@c200f3691d83b41bf9bbd8638997a462592937ed' # ratchet:exclude pin@v2.1.7
|
||||
with:
|
||||
project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
|
||||
workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
name: 'Evals: Nightly'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 1 * * *' # Runs at 1 AM every day
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
run_all:
|
||||
description: 'Run all evaluations (including usually passing)'
|
||||
type: 'boolean'
|
||||
default: true
|
||||
test_name_pattern:
|
||||
description: 'Test name pattern or file name'
|
||||
required: false
|
||||
type: 'string'
|
||||
|
||||
permissions:
|
||||
contents: 'read'
|
||||
checks: 'write'
|
||||
actions: 'read'
|
||||
|
||||
jobs:
|
||||
evals:
|
||||
name: 'Evals (USUALLY_PASSING) nightly run'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
model:
|
||||
- 'gemini-3.1-pro-preview-customtools'
|
||||
- 'gemini-3-pro-preview'
|
||||
- 'gemini-3-flash-preview'
|
||||
- 'gemini-2.5-pro'
|
||||
- 'gemini-2.5-flash'
|
||||
- 'gemini-2.5-flash-lite'
|
||||
run_attempt: [1, 2, 3]
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
|
||||
|
||||
- name: 'Set up Node.js'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Build project'
|
||||
run: 'npm run build'
|
||||
|
||||
- name: 'Create logs directory'
|
||||
run: 'mkdir -p evals/logs'
|
||||
|
||||
- name: 'Run Evals'
|
||||
continue-on-error: true
|
||||
env:
|
||||
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
|
||||
GEMINI_MODEL: '${{ matrix.model }}'
|
||||
RUN_EVALS: "${{ github.event.inputs.run_all != 'false' }}"
|
||||
TEST_NAME_PATTERN: '${{ github.event.inputs.test_name_pattern }}'
|
||||
run: |
|
||||
CMD="npm run test:all_evals"
|
||||
PATTERN="${{ env.TEST_NAME_PATTERN }}"
|
||||
|
||||
if [[ -n "$PATTERN" ]]; then
|
||||
if [[ "$PATTERN" == *.ts || "$PATTERN" == *.js || "$PATTERN" == */* ]]; then
|
||||
$CMD -- "$PATTERN"
|
||||
else
|
||||
$CMD -- -t "$PATTERN"
|
||||
fi
|
||||
else
|
||||
$CMD
|
||||
fi
|
||||
|
||||
- name: 'Upload Logs'
|
||||
if: 'always()'
|
||||
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'eval-logs-${{ matrix.model }}-${{ matrix.run_attempt }}'
|
||||
path: 'evals/logs'
|
||||
retention-days: 7
|
||||
|
||||
aggregate-results:
|
||||
name: 'Aggregate Results'
|
||||
needs: ['evals']
|
||||
if: 'always()'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
|
||||
|
||||
- name: 'Download Logs'
|
||||
uses: 'actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806' # ratchet:actions/download-artifact@v4
|
||||
with:
|
||||
path: 'artifacts'
|
||||
|
||||
- name: 'Generate Summary'
|
||||
env:
|
||||
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
run: 'node scripts/aggregate_evals.js artifacts >> "$GITHUB_STEP_SUMMARY"'
|
||||
@@ -101,7 +101,6 @@ jobs:
|
||||
"FIRESTORE_DATABASE_ID": "(default)",
|
||||
"GOOGLE_APPLICATION_CREDENTIALS": "${GOOGLE_APPLICATION_CREDENTIALS}"
|
||||
},
|
||||
"enabled": true,
|
||||
"timeout": 600000
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,9 +14,15 @@ on:
|
||||
description: 'issue number to triage'
|
||||
required: true
|
||||
type: 'number'
|
||||
workflow_call:
|
||||
inputs:
|
||||
issue_number:
|
||||
description: 'issue number to triage'
|
||||
required: false
|
||||
type: 'string'
|
||||
|
||||
concurrency:
|
||||
group: '${{ github.workflow }}-${{ github.event.issue.number || github.event.inputs.issue_number }}'
|
||||
group: '${{ github.workflow }}-${{ github.event.issue.number || github.event.inputs.issue_number || inputs.issue_number }}'
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
@@ -34,18 +40,18 @@ permissions:
|
||||
jobs:
|
||||
triage-issue:
|
||||
if: |-
|
||||
github.repository == 'google-gemini/gemini-cli' &&
|
||||
(github.repository == 'google-gemini/gemini-cli' || github.repository == 'google-gemini/maintainers-gemini-cli') &&
|
||||
(
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(
|
||||
(github.event_name == 'issues' || github.event_name == 'issue_comment') &&
|
||||
contains(github.event.issue.labels.*.name, 'status/need-triage') &&
|
||||
(github.event_name != 'issue_comment' || (
|
||||
contains(github.event.comment.body, '@gemini-cli /triage') &&
|
||||
(github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR')
|
||||
))
|
||||
)
|
||||
)
|
||||
) &&
|
||||
!contains(github.event.issue.labels.*.name, 'area/')
|
||||
timeout-minutes: 5
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
@@ -57,28 +63,40 @@ jobs:
|
||||
with:
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
script: |
|
||||
const issueNumber = ${{ github.event.inputs.issue_number || inputs.issue_number }};
|
||||
const { data: issue } = await github.rest.issues.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: ${{ github.event.inputs.issue_number }},
|
||||
issue_number: issueNumber,
|
||||
});
|
||||
core.setOutput('title', issue.title);
|
||||
core.setOutput('body', issue.body);
|
||||
core.setOutput('labels', issue.labels.map(label => label.name).join(','));
|
||||
return issue;
|
||||
|
||||
- name: 'Check for triage label on manual trigger'
|
||||
- name: 'Manual Trigger Pre-flight Checks'
|
||||
if: |-
|
||||
github.event_name == 'workflow_dispatch' && !contains(steps.get_issue_data.outputs.labels, 'status/need-triage')
|
||||
github.event_name == 'workflow_dispatch'
|
||||
env:
|
||||
ISSUE_NUMBER_INPUT: '${{ github.event.inputs.issue_number || inputs.issue_number }}'
|
||||
LABELS: '${{ steps.get_issue_data.outputs.labels }}'
|
||||
run: |
|
||||
echo "Issue #${{ github.event.inputs.issue_number }} does not have the 'status/need-triage' label. Stopping workflow."
|
||||
exit 1
|
||||
if echo "${LABELS}" | grep -q 'area/'; then
|
||||
echo "Issue #${ISSUE_NUMBER_INPUT} already has 'area/' label. Stopping workflow."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Manual triage checks passed."
|
||||
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
|
||||
|
||||
- name: 'Generate GitHub App Token'
|
||||
id: 'generate_token'
|
||||
env:
|
||||
APP_ID: '${{ secrets.APP_ID }}'
|
||||
if: |-
|
||||
${{ env.APP_ID != '' }}
|
||||
uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b' # ratchet:actions/create-github-app-token@v2
|
||||
with:
|
||||
app-id: '${{ secrets.APP_ID }}'
|
||||
@@ -89,13 +107,23 @@ jobs:
|
||||
id: 'get_labels'
|
||||
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
|
||||
with:
|
||||
github-token: '${{ steps.generate_token.outputs.token }}'
|
||||
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
|
||||
script: |-
|
||||
const { data: labels } = await github.rest.issues.listLabelsForRepo({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
const labelNames = labels.map(label => label.name);
|
||||
const allowedLabels = [
|
||||
'area/agent',
|
||||
'area/enterprise',
|
||||
'area/non-interactive',
|
||||
'area/core',
|
||||
'area/security',
|
||||
'area/platform',
|
||||
'area/extensions',
|
||||
'area/unknown'
|
||||
];
|
||||
const labelNames = labels.map(label => label.name).filter(name => allowedLabels.includes(name));
|
||||
core.setOutput('available_labels', labelNames.join(','));
|
||||
core.info(`Found ${labelNames.length} labels: ${labelNames.join(', ')}`);
|
||||
return labelNames;
|
||||
@@ -110,7 +138,7 @@ jobs:
|
||||
ISSUE_BODY: >-
|
||||
${{ github.event_name == 'workflow_dispatch' && steps.get_issue_data.outputs.body || github.event.issue.body }}
|
||||
ISSUE_NUMBER: >-
|
||||
${{ github.event_name == 'workflow_dispatch' && github.event.inputs.issue_number || github.event.issue.number }}
|
||||
${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.issue_number || inputs.issue_number) || github.event.issue.number }}
|
||||
REPOSITORY: '${{ github.repository }}'
|
||||
AVAILABLE_LABELS: '${{ steps.get_labels.outputs.available_labels }}'
|
||||
with:
|
||||
@@ -124,139 +152,111 @@ jobs:
|
||||
settings: |-
|
||||
{
|
||||
"maxSessionTurns": 25,
|
||||
"coreTools": [
|
||||
"run_shell_command(echo)"
|
||||
],
|
||||
"telemetry": {
|
||||
"enabled": true,
|
||||
"target": "gcp"
|
||||
}
|
||||
},
|
||||
"coreTools": [
|
||||
"run_shell_command(echo)"
|
||||
],
|
||||
}
|
||||
prompt: |-
|
||||
## Role
|
||||
|
||||
You are an issue triage assistant. Analyze the current GitHub issue
|
||||
and identify the most appropriate existing labels by only using the provided data. Use the available
|
||||
tools to gather information; do not ask for information to be
|
||||
provided. Do not remove the following labels titled maintainer, help wanted or good first issue.
|
||||
You are an issue triage assistant. Your role is to analyze a GitHub issue and determine the single most appropriate area/ label based on the definitions provided.
|
||||
|
||||
## Steps
|
||||
|
||||
1. You are only able to use the echo command. Review the available labels in the environment variable: "${AVAILABLE_LABELS}".
|
||||
2. Review the issue title and body provided in the environment variables: "${ISSUE_TITLE}" and "${ISSUE_BODY}".
|
||||
3. Select the most relevant labels from the existing labels, focusing on kind/*, area/*, sub-area/* and priority/*. For area/* and kind/* limit yourself to only the single most applicable label in each case.
|
||||
4. If the issue already has area/ label, dont try to change it. Similarly, if the issue already has a kind/ label don't change it. And if the issue already has a priority/ label do not change it for example:
|
||||
If an issue has area/core and kind/bug you will only add a priority/ label.
|
||||
Instead if an issue has no labels, you will could add one lable of each kind.
|
||||
5. For each issue please check if CLI version is present, this is usually in the output of the /about command and will look like 0.1.5 for anything more than 6 versions older than the most recent should add the status/need-retesting label.
|
||||
6. If you see that the issue doesn't look like it has sufficient information recommend the status/need-information label and leave a comment politely requesting the relevant information, eg.. if repro steps are missing request for repro steps. if version information is missing request for version information into the explanation section below.
|
||||
7. Output the appropriate labels for this issue in JSON format with explanation, for example:
|
||||
```
|
||||
{"labels_to_set": ["kind/bug", "priority/p0"], "explanation": "This is a critical bug report affecting main functionality"}
|
||||
```
|
||||
8. If the issue cannot be classified using the available labels, output:
|
||||
```
|
||||
{"labels_to_set": [], "explanation": "Unable to classify this issue with available labels"}
|
||||
```
|
||||
9. Use Area definitions mentioned below to help you narrow down issues.
|
||||
10. If you think an issue might be a Priority/P0 do not apply the priority/p0 label. Instead apply a status/manual-triage label and include a note in your explanation.
|
||||
11. If you are uncertain and have not been able to apply one each of kind/, area/ and priority/ , apply the status/manual-triage label.
|
||||
1. Review the issue title and body: ${{ env.ISSUE_TITLE }} and ${{ env.ISSUE_BODY }}.
|
||||
2. Review the available labels: ${{ env.AVAILABLE_LABELS }}.
|
||||
3. Select exactly one area/ label that best matches the issue based on Reference 1: Area Definitions.
|
||||
4. Fallback Logic:
|
||||
- If you cannot confidently determine the correct area/ label from the definitions, you must use area/unknown.
|
||||
5. Output your selected label in JSON format and nothing else. Example:
|
||||
{"labels_to_set": ["area/core"]}
|
||||
|
||||
## Guidelines
|
||||
- Your output must contain exactly one area/ label.
|
||||
- Triage only the current issue based on its title and body.
|
||||
- Output only valid JSON format.
|
||||
- Do not include any explanation or additional text, just the JSON.
|
||||
|
||||
- Only use labels that already exist in the repository
|
||||
- Do not add comments or modify the issue content
|
||||
- Triage only the current issue
|
||||
- Identify only one area/ label
|
||||
- Identify only one kind/ label
|
||||
- Identify all applicable sub-area/* and priority/* labels based on the issue content. It's ok to have multiple of these
|
||||
- Once you categorize the issue if it needs information bump down the priority by 1 eg.. a p0 would become a p1 a p1 would become a p2. P2 and P3 can stay as is in this scenario
|
||||
- Reference all shell variables as "${VAR}" (with quotes and braces)
|
||||
- Output only valid JSON format
|
||||
- Do not include any explanation or additional text, just the JSON
|
||||
Reference 1: Area Definitions
|
||||
area/agent
|
||||
- Description: Issues related to the "brain" of the CLI. This includes the core agent logic, model quality, tool/function calling, and memory.
|
||||
- Example Issues:
|
||||
"I am not getting a reasonable or expected response."
|
||||
"The model is not calling the tool I expected."
|
||||
"The web search tool is not working as expected."
|
||||
"Feature request for a new built-in tool (e.g., read file, write file)."
|
||||
"The generated code is poor quality or incorrect."
|
||||
"The model seems stuck in a loop."
|
||||
"The response from the model is malformed (e.g., broken JSON, bad formatting)."
|
||||
"Concerns about unnecessary token consumption."
|
||||
"Issues with how memory or chat history is managed."
|
||||
"Issues with sub-agents."
|
||||
"Model is switching from one to another unexpectedly."
|
||||
|
||||
Categorization Guidelines:
|
||||
P0: Critical / Blocker
|
||||
- A P0 bug is a catastrophic failure that demands immediate attention.
|
||||
- To be a P0 it means almost all users are running into this issue and it is blocking users from being able to use the product.
|
||||
- You would see this in the form of many comments from different developers on the bug.
|
||||
- It represents a complete showstopper for a significant portion of users or for the development process itself.
|
||||
Impact:
|
||||
- Blocks development or testing for the entire team.
|
||||
- Major security vulnerability that could compromise user data or system integrity.
|
||||
- Causes data loss or corruption with no workaround.
|
||||
- Crashes the application or makes a core feature completely unusable for all or most users in a production environment. Will it cause severe quality degration? Is it preventing contributors from contributing to the repository or is it a release blocker?
|
||||
Qualifier: Is the main function of the software broken?
|
||||
Example: The gemini auth login command fails with an unrecoverable error, preventing any user from authenticating and using the rest of the CLI.
|
||||
P1: High
|
||||
- A P1 bug is a serious issue that significantly degrades the user experience or impacts a core feature.
|
||||
- While not a complete blocker, it's a major problem that needs a fast resolution. Feature requests are almost never P1.
|
||||
- Once again this would be affecting many users.
|
||||
- You would see this in the form of comments from different developers on the bug.
|
||||
Impact:
|
||||
- A core feature is broken or behaving incorrectly for a large number of users or large number of use cases.
|
||||
- Review the bug details and comments to try figure out if this issue affects a large set of use cases or if it's a narrow set of use cases.
|
||||
- Severe performance degradation making the application frustratingly slow.
|
||||
- No straightforward workaround exists, or the workaround is difficult and non-obvious.
|
||||
Qualifier: Is a key feature unusable or giving very wrong results?
|
||||
Example: Gemini CLI enters a loop when making read-many-files tool call. I am unable to break out of the loop and gemini doesn't follow instructions subsequently.
|
||||
P2: Medium
|
||||
- A P2 bug is a moderately impactful issue. It's a noticeable problem but doesn't prevent the use of the software's main functionality.
|
||||
Impact:
|
||||
- Affects a non-critical feature or a smaller, specific subset of users.
|
||||
- An inconvenient but functional workaround is available and easy to execute.
|
||||
- Noticeable UI/UX problems that don't break functionality but look unprofessional (e.g., elements are misaligned or overlapping).
|
||||
Qualifier: Is it an annoying but non-blocking problem?
|
||||
Example: An error message is unclear or contains a typo, causing user confusion but not halting their workflow.
|
||||
P3: Low
|
||||
- A P3 bug is a minor, low-impact issue that is trivial or cosmetic. It has little to no effect on the overall functionality of the application.
|
||||
Impact:
|
||||
- Minor cosmetic issues like color inconsistencies, typos in documentation, or slight alignment problems on a non-critical page.
|
||||
- An edge-case bug that is very difficult to reproduce and affects a tiny fraction of users.
|
||||
Qualifier: Is it a "nice-to-fix" issue?
|
||||
Example: Spelling mistakes etc.
|
||||
Things you should know:
|
||||
- If users are talking about issues where the model gets downgraded from pro to flash then i want you to categorize that as a performance issue
|
||||
- This product is designed to use different models eg.. using pro, downgrading to flash etc. when users report that they dont expect the model to change those would be categorized as feature requests.
|
||||
Definition of Areas
|
||||
area/ux:
|
||||
- Issues concerning user-facing elements like command usability, interactive features, help docs, and perceived performance.
|
||||
- I am seeing my screen flicker when using Gemini CLI
|
||||
- I am seeing the output malformed
|
||||
- Theme changes aren't taking effect
|
||||
- My keyboard inputs arent' being recognzied
|
||||
area/platform:
|
||||
- Issues related to installation, packaging, OS compatibility (Windows, macOS, Linux), and the underlying CLI framework.
|
||||
area/background: Issues related to long-running background tasks, daemons, and autonomous or proactive agent features.
|
||||
area/models:
|
||||
- i am not getting a response that is reasonable or expected. this can include things like
|
||||
- I am calling a tool and the tool is not performing as expected.
|
||||
- i am expecting a tool to be called and it is not getting called ,
|
||||
- Including experience when using
|
||||
- built-in tools (e.g., web search, code interpreter, read file, writefile, etc..),
|
||||
- Function calling issues should be under this area
|
||||
- i am getting responses from the model that are malformed.
|
||||
- Issues concerning Gemini quality of response and inference,
|
||||
- Issues talking about unnecessary token consumption.
|
||||
- Issues talking about Model getting stuck in a loop be watchful as this could be the root cause for issues that otherwise seem like model performance issues.
|
||||
- Memory compression
|
||||
- unexpected responses,
|
||||
- poor quality of generated code
|
||||
area/tools:
|
||||
- These are primarily issues related to Model Context Protocol
|
||||
- These are issues that mention MCP support
|
||||
- feature requests asking for support for new tools.
|
||||
area/core: Issues with fundamental components like command parsing, configuration management, session state, and the main API client logic. Introducing multi-modality
|
||||
area/contribution: Issues related to improving the developer contribution experience, such as CI/CD pipelines, build scripts, and test automation infrastructure.
|
||||
area/authentication: Issues related to user identity, login flows, API key handling, credential storage, and access token management, unable to sign in selecting wrong authentication path etc..
|
||||
area/security-privacy: Issues concerning vulnerability patching, dependency security, data sanitization, privacy controls, and preventing unauthorized data access.
|
||||
area/extensibility: Issues related to the plugin system, extension APIs, or making the CLI's functionality available in other applications, github actions, ide support etc..
|
||||
area/performance: Issues focused on model performance
|
||||
- Issues with running out of capacity,
|
||||
- 429 errors etc..
|
||||
- could also pertain to latency,
|
||||
- other general software performance like, memory usage, CPU consumption, and algorithmic efficiency.
|
||||
- Switching models from one to the other unexpectedly.
|
||||
area/enterprise
|
||||
- Description: Issues specific to enterprise-level features, including telemetry, policy, and licenses.
|
||||
- Example Issues:
|
||||
"Usage data is not appearing in our telemetry dashboard."
|
||||
"A user is able to perform an action that should be blocked by an admin policy."
|
||||
"Questions about billing, licensing tiers, or enterprise quotas."
|
||||
|
||||
area/non-interactive
|
||||
- Description: Issues related to using the CLI in automated or non-interactive environments (headless mode).
|
||||
- Example Issues:
|
||||
"Problems using the CLI as an SDK in another surface."
|
||||
"The CLI is behaving differently when run from a shell script vs. an interactive terminal."
|
||||
"GitHub action is failing."
|
||||
"I am having trouble running the CLI in headless mode"
|
||||
|
||||
area/core
|
||||
- Description: Issues with the fundamental CLI app itself. This includes the user interface (UI/UX), installation, OS compatibility, and performance.
|
||||
- Example Issues:
|
||||
"I am seeing my screen flicker when using the CLI."
|
||||
"The output in my terminal is malformed or unreadable."
|
||||
"Theme changes are not taking effect."
|
||||
"Keyboard inputs (e.g., arrow keys, Ctrl+C) are not being recognized."
|
||||
"The CLI failed to install or update."
|
||||
"An issue specific to running on Windows, macOS, or Linux."
|
||||
"Problems with command parsing, flags, or argument handling."
|
||||
"High CPU or memory usage by the CLI process."
|
||||
"Issues related to multi-modality (e.g., handling image inputs)."
|
||||
"Problems with the IDE integration connection or installation"
|
||||
|
||||
area/security
|
||||
- Description: Issues related to user authentication, authorization, data security, and privacy.
|
||||
- Example Issues:
|
||||
"I am unable to sign in."
|
||||
"The login flow is selecting the wrong authentication path"
|
||||
"Problems with API key handling or credential storage."
|
||||
"A report of a security vulnerability"
|
||||
"Concerns about data sanitization or potential data leaks."
|
||||
"Issues or requests related to privacy controls."
|
||||
"Preventing unauthorized data access."
|
||||
|
||||
area/platform
|
||||
- Description: Issues related to CI/CD, release management, testing, eval infrastructure, capacity, quota management, and sandbox environments.
|
||||
- Example Issues:
|
||||
"I am getting a 429 'Resource Exhausted' or 500-level server error."
|
||||
"General slowness or high latency from the service."
|
||||
"The build script is broken on the main branch."
|
||||
"Tests are failing in the CI/CD pipeline."
|
||||
"Issues with the release management or publishing process."
|
||||
"User is running out of capacity."
|
||||
"Problems specific to the sandbox or staging environments."
|
||||
"Questions about quota limits or requests for increases."
|
||||
|
||||
area/extensions
|
||||
- Description: Issues related to the extension ecosystem, including the marketplace and website.
|
||||
- Example Issues:
|
||||
"Bugs related to the extension marketplace website."
|
||||
"Issues with a specific extension."
|
||||
"Feature request for the extension ecosystem."
|
||||
|
||||
area/unknown
|
||||
- Description: Issues that do not clearly fit into any other defined area/ category, or where information is too limited to make a determination. Use this when no other area is appropriate.
|
||||
|
||||
- name: 'Apply Labels to Issue'
|
||||
if: |-
|
||||
@@ -267,54 +267,60 @@ jobs:
|
||||
LABELS_OUTPUT: '${{ steps.gemini_issue_analysis.outputs.summary }}'
|
||||
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
|
||||
with:
|
||||
github-token: '${{ steps.generate_token.outputs.token }}'
|
||||
script: |-
|
||||
// Strip code block markers if present
|
||||
const rawLabels = process.env.LABELS_OUTPUT;
|
||||
core.info(`Raw labels JSON: ${rawLabels}`);
|
||||
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
|
||||
script: |
|
||||
const rawOutput = process.env.LABELS_OUTPUT;
|
||||
core.info(`Raw output from model: ${rawOutput}`);
|
||||
let parsedLabels;
|
||||
try {
|
||||
const jsonMatch = rawLabels.match(/```json\s*([\s\S]*?)\s*```/);
|
||||
if (!jsonMatch || !jsonMatch[1]) {
|
||||
throw new Error("Could not find a ```json ... ``` block in the output.");
|
||||
// First, try to parse the raw output as JSON.
|
||||
parsedLabels = JSON.parse(rawOutput);
|
||||
} catch (jsonError) {
|
||||
// If that fails, check for a markdown code block.
|
||||
core.warning(`Direct JSON parsing failed: ${jsonError.message}. Trying to extract from a markdown block.`);
|
||||
const jsonMatch = rawOutput.match(/```json\s*([\s\S]*?)\s*```/);
|
||||
if (jsonMatch && jsonMatch[1]) {
|
||||
try {
|
||||
parsedLabels = JSON.parse(jsonMatch[1].trim());
|
||||
} catch (markdownError) {
|
||||
core.setFailed(`Failed to parse JSON even after extracting from markdown block: ${markdownError.message}\nRaw output: ${rawOutput}`);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// If no markdown block, try to find a raw JSON object in the output.
|
||||
// The CLI may include debug/log lines (e.g. telemetry init, YOLO mode)
|
||||
// before the actual JSON response.
|
||||
const jsonObjectMatch = rawOutput.match(/(\{[\s\S]*"labels_to_set"[\s\S]*\})/);
|
||||
if (jsonObjectMatch) {
|
||||
try {
|
||||
parsedLabels = JSON.parse(jsonObjectMatch[0]);
|
||||
} catch (extractError) {
|
||||
core.setFailed(`Found JSON-like content but failed to parse: ${extractError.message}\nRaw output: ${rawOutput}`);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
core.setFailed(`Output is not valid JSON and does not contain extractable JSON.\nRaw output: ${rawOutput}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const jsonString = jsonMatch[1].trim();
|
||||
parsedLabels = JSON.parse(jsonString);
|
||||
core.info(`Parsed labels JSON: ${JSON.stringify(parsedLabels)}`);
|
||||
} catch (err) {
|
||||
core.setFailed(`Failed to parse labels JSON from Gemini output: ${err.message}\nRaw output: ${rawLabels}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const issueNumber = parseInt(process.env.ISSUE_NUMBER);
|
||||
const explanation = parsedLabels.explanation || '';
|
||||
const labelsToSet = parsedLabels.labels_to_set || [];
|
||||
labelsToSet.push('status/bot-triaged');
|
||||
const labelsToAdd = parsedLabels.labels_to_set || [];
|
||||
|
||||
if (labelsToAdd.length !== 1) {
|
||||
core.setFailed(`Expected exactly 1 label (area/), but got ${labelsToAdd.length}. Labels: ${labelsToAdd.join(', ')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set labels based on triage result
|
||||
if (labelsToSet.length > 0) {
|
||||
await github.rest.issues.setLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
labels: labelsToSet
|
||||
});
|
||||
const explanationInfo = explanation ? ` - ${explanation}` : '';
|
||||
core.info(`Successfully set labels for #${issueNumber}: ${labelsToSet.join(', ')}${explanationInfo}`);
|
||||
} else {
|
||||
// If no labels to set, leave the issue as is
|
||||
const explanationInfo = explanation ? ` - ${explanation}` : '';
|
||||
core.info(`No labels to set for #${issueNumber}, leaving as is${explanationInfo}`);
|
||||
}
|
||||
|
||||
if (explanation) {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
body: explanation,
|
||||
});
|
||||
}
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
labels: labelsToAdd
|
||||
});
|
||||
core.info(`Successfully added labels for #${issueNumber}: ${labelsToAdd.join(', ')}`);
|
||||
|
||||
- name: 'Post Issue Analysis Failure Comment'
|
||||
if: |-
|
||||
@@ -324,7 +330,7 @@ jobs:
|
||||
RUN_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
|
||||
with:
|
||||
github-token: '${{ steps.generate_token.outputs.token }}'
|
||||
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
|
||||
script: |-
|
||||
github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
|
||||
@@ -81,7 +81,6 @@ jobs:
|
||||
"FIRESTORE_DATABASE_ID": "(default)",
|
||||
"GOOGLE_APPLICATION_CREDENTIALS": "${GOOGLE_APPLICATION_CREDENTIALS}"
|
||||
},
|
||||
"enabled": true,
|
||||
"timeout": 600000
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
name: '📋 Gemini Scheduled Issue Triage'
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- 'opened'
|
||||
- 'reopened'
|
||||
schedule:
|
||||
- cron: '0 * * * *' # Runs every hour
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: '${{ github.workflow }}'
|
||||
group: '${{ github.workflow }}-${{ github.event.number || github.run_id }}'
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
@@ -35,7 +39,21 @@ jobs:
|
||||
private-key: '${{ secrets.PRIVATE_KEY }}'
|
||||
permission-issues: 'write'
|
||||
|
||||
- name: 'Get issue from event'
|
||||
if: |-
|
||||
${{ github.event_name == 'issues' }}
|
||||
id: 'get_issue_from_event'
|
||||
env:
|
||||
ISSUE_EVENT: '${{ toJSON(github.event.issue) }}'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ISSUE_JSON=$(echo "$ISSUE_EVENT" | jq -c '[{number: .number, title: .title, body: .body}]')
|
||||
echo "issues_to_triage=${ISSUE_JSON}" >> "${GITHUB_OUTPUT}"
|
||||
echo "✅ Found issue #${{ github.event.issue.number }} from event to triage! 🎯"
|
||||
|
||||
- name: 'Find untriaged issues'
|
||||
if: |-
|
||||
${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
|
||||
id: 'find_issues'
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token }}'
|
||||
@@ -43,22 +61,26 @@ jobs:
|
||||
run: |-
|
||||
set -euo pipefail
|
||||
|
||||
echo '🔍 Finding issues without labels...'
|
||||
NO_LABEL_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
|
||||
--search 'is:open is:issue no:label' --json number,title,body)"
|
||||
echo '🔍 Finding issues missing area labels...'
|
||||
NO_AREA_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
|
||||
--search 'is:open is:issue -label:area/core -label:area/agent -label:area/enterprise -label:area/non-interactive -label:area/security -label:area/platform -label:area/extensions -label:area/unknown' --limit 100 --json number,title,body)"
|
||||
|
||||
echo '🏷️ Finding issues that need triage...'
|
||||
NEED_TRIAGE_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
|
||||
--search "is:open is:issue label:\"status/need-triage\"" --limit 1000 --json number,title,body)"
|
||||
echo '🔍 Finding issues missing kind labels...'
|
||||
NO_KIND_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
|
||||
--search 'is:open is:issue -label:kind/bug -label:kind/enhancement -label:kind/customer-issue -label:kind/question' --limit 100 --json number,title,body)"
|
||||
|
||||
echo '🏷️ Finding issues missing priority labels...'
|
||||
NO_PRIORITY_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
|
||||
--search 'is:open is:issue -label:priority/p0 -label:priority/p1 -label:priority/p2 -label:priority/p3 -label:priority/unknown' --limit 100 --json number,title,body)"
|
||||
|
||||
echo '🔄 Merging and deduplicating issues...'
|
||||
ISSUES="$(echo "${NO_LABEL_ISSUES}" "${NEED_TRIAGE_ISSUES}" | jq -c -s 'add | unique_by(.number)')"
|
||||
ISSUES="$(echo "${NO_AREA_ISSUES}" "${NO_KIND_ISSUES}" "${NO_PRIORITY_ISSUES}" | jq -c -s 'add | unique_by(.number)')"
|
||||
|
||||
echo '📝 Setting output for GitHub Actions...'
|
||||
echo "issues_to_triage=${ISSUES}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
ISSUE_COUNT="$(echo "${ISSUES}" | jq 'length')"
|
||||
echo "✅ Found ${ISSUE_COUNT} issues to triage! 🎯"
|
||||
echo "✅ Found ${ISSUE_COUNT} unique issues to triage! 🎯"
|
||||
|
||||
- name: 'Get Repository Labels'
|
||||
id: 'get_labels'
|
||||
@@ -77,12 +99,13 @@ jobs:
|
||||
|
||||
- name: 'Run Gemini Issue Analysis'
|
||||
if: |-
|
||||
${{ steps.find_issues.outputs.issues_to_triage != '[]' }}
|
||||
(steps.get_issue_from_event.outputs.issues_to_triage != '' && steps.get_issue_from_event.outputs.issues_to_triage != '[]') ||
|
||||
(steps.find_issues.outputs.issues_to_triage != '' && steps.find_issues.outputs.issues_to_triage != '[]')
|
||||
uses: 'google-github-actions/run-gemini-cli@a3bf79042542528e91937b3a3a6fbc4967ee3c31' # ratchet:google-github-actions/run-gemini-cli@v0
|
||||
id: 'gemini_issue_analysis'
|
||||
env:
|
||||
GITHUB_TOKEN: '' # Do not pass any auth token here since this runs on untrusted inputs
|
||||
ISSUES_TO_TRIAGE: '${{ steps.find_issues.outputs.issues_to_triage }}'
|
||||
ISSUES_TO_TRIAGE: '${{ steps.get_issue_from_event.outputs.issues_to_triage || steps.find_issues.outputs.issues_to_triage }}'
|
||||
REPOSITORY: '${{ github.repository }}'
|
||||
AVAILABLE_LABELS: '${{ steps.get_labels.outputs.available_labels }}'
|
||||
with:
|
||||
@@ -116,38 +139,32 @@ jobs:
|
||||
1. You are only able to use the echo command. Review the available labels in the environment variable: "${AVAILABLE_LABELS}".
|
||||
2. Check environment variable for issues to triage: $ISSUES_TO_TRIAGE (JSON array of issues)
|
||||
3. Review the issue title, body and any comments provided in the environment variables.
|
||||
4. Identify the most relevant labels from the existing labels, focusing on kind/*, area/*, sub-area/* and priority/*.
|
||||
5. If the issue already has area/ label, dont try to change it. Similarly, if the issue already has a kind/ label don't change it. And if the issue already has a priority/ label do not change it for example:
|
||||
If an issue has area/core and kind/bug you will only add a priority/ label.
|
||||
Instead if an issue has no labels, you will could add one lable of each kind.
|
||||
4. Identify the most relevant labels from the existing labels, specifically focusing on area/*, kind/* and priority/*.
|
||||
5. Label Policy:
|
||||
- If the issue already has a kind/ label, do not change it.
|
||||
- If the issue already has a priority/ label, do not change it.
|
||||
- If the issue already has an area/ label, do not change it.
|
||||
- If any of these are missing, select exactly ONE appropriate label for the missing category.
|
||||
6. Identify other applicable labels based on the issue content, such as status/*, help wanted, good first issue, etc.
|
||||
7. For area/* and kind/* limit yourself to only the single most applicable label in each case.
|
||||
8. Give me a single short explanation about why you are selecting each label in the process.
|
||||
9. Output a JSON array of objects, each containing the issue number
|
||||
7. Give me a single short explanation about why you are selecting each label in the process.
|
||||
8. Output a JSON array of objects, each containing the issue number
|
||||
and the labels to add and remove, along with an explanation. For example:
|
||||
```
|
||||
[
|
||||
{
|
||||
"issue_number": 123,
|
||||
"labels_to_add": ["kind/bug", "priority/p2"],
|
||||
"labels_to_add": ["area/core", "kind/bug", "priority/p2"],
|
||||
"labels_to_remove": ["status/need-triage"],
|
||||
"explanation": "This issue is a bug that needs to be addressed with medium priority."
|
||||
},
|
||||
{
|
||||
"issue_number": 456,
|
||||
"labels_to_add": ["kind/enhancement"],
|
||||
"labels_to_remove": [],
|
||||
"explanation": "This issue is an enhancement request that could improve the user experience."
|
||||
"explanation": "This issue is a UI bug that needs to be addressed with medium priority."
|
||||
}
|
||||
]
|
||||
```
|
||||
If an issue cannot be classified, do not include it in the output array.
|
||||
10. For each issue please check if CLI version is present, this is usually in the output of the /about command and will look like 0.1.5
|
||||
9. For each issue please check if CLI version is present, this is usually in the output of the /about command and will look like 0.1.5
|
||||
- Anything more than 6 versions older than the most recent should add the status/need-retesting label
|
||||
11. If you see that the issue doesn't look like it has sufficient information recommend the status/need-information label and leave a comment politely requesting the relevant information, eg.. if repro steps are missing request for repro steps. if version information is missing request for version information into the explanation section below.
|
||||
- After identifying appropriate labels to an issue, add "status/need-triage" label to labels_to_remove in the output.
|
||||
12. If you think an issue might be a Priority/P0 do not apply the priority/p0 label. Instead apply a status/manual-triage label and include a note in your explanation.
|
||||
13. If you are uncertain and have not been able to apply one each of kind/, area/ and priority/ , apply the status/manual-triage label.
|
||||
10. If you see that the issue doesn't look like it has sufficient information recommend the status/need-information label and leave a comment politely requesting the relevant information, eg.. if repro steps are missing request for repro steps. if version information is missing request for version information into the explanation section below.
|
||||
11. If you think an issue might be a Priority/P0 do not apply the priority/p0 label. Instead apply a status/manual-triage label and include a note in your explanation.
|
||||
12. If you are uncertain about a category, use the area/unknown, kind/question, or priority/unknown labels as appropriate. If you are extremely uncertain, apply the status/manual-triage label.
|
||||
|
||||
## Guidelines
|
||||
|
||||
@@ -157,100 +174,46 @@ jobs:
|
||||
- Do not add comments or modify the issue content.
|
||||
- Do not remove the following labels maintainer, help wanted or good first issue.
|
||||
- Triage only the current issue.
|
||||
- Identify only one area/ label
|
||||
- Identify only one area/ label.
|
||||
- Identify only one kind/ label (Do not apply kind/duplicate or kind/parent-issue)
|
||||
- Identify all applicable sub-area/* and priority/* labels based on the issue content. It's ok to have multiple of these.
|
||||
- Identify only one priority/ label.
|
||||
- Once you categorize the issue if it needs information bump down the priority by 1 eg.. a p0 would become a p1 a p1 would become a p2. P2 and P3 can stay as is in this scenario.
|
||||
Categorization Guidelines:
|
||||
P0: Critical / Blocker
|
||||
- A P0 bug is a catastrophic failure that demands immediate attention.
|
||||
- To be a P0 it means almost all users are running into this issue and it is blocking users from being able to use the product.
|
||||
- You would see this in the form of many comments from different developers on the bug.
|
||||
- It represents a complete showstopper for a significant portion of users or for the development process itself.
|
||||
Impact:
|
||||
- Blocks development or testing for the entire team.
|
||||
- Major security vulnerability that could compromise user data or system integrity.
|
||||
- Causes data loss or corruption with no workaround.
|
||||
- Crashes the application or makes a core feature completely unusable for all or most users in a production environment. Will it cause severe quality degration?
|
||||
- Is it preventing contributors from contributing to the repository or is it a release blocker?
|
||||
Qualifier: Is the main function of the software broken?
|
||||
Example: The gemini auth login command fails with an unrecoverable error, preventing any user from authenticating and using the rest of the CLI.
|
||||
P1: High
|
||||
- A P1 bug is a serious issue that significantly degrades the user experience or impacts a core feature.
|
||||
- While not a complete blocker, it's a major problem that needs a fast resolution. Feature requests are almost never P1.
|
||||
- Once again this would be affecting many users.
|
||||
- You would see this in the form of comments from different developers on the bug.
|
||||
Impact:
|
||||
- A core feature is broken or behaving incorrectly for a large number of users or large number of use cases.
|
||||
- Review the bug details and comments to try figure out if this issue affects a large set of use cases or if it's a narrow set of use cases.
|
||||
- Severe performance degradation making the application frustratingly slow.
|
||||
- No straightforward workaround exists, or the workaround is difficult and non-obvious.
|
||||
Qualifier: Is a key feature unusable or giving very wrong results?
|
||||
Example: Gemini CLI enters a loop when making read-many-files tool call. I am unable to break out of the loop and gemini doesn't follow instructions subsequently.
|
||||
P2: Medium
|
||||
- A P2 bug is a moderately impactful issue. It's a noticeable problem but doesn't prevent the use of the software's main functionality.
|
||||
Impact:
|
||||
- Affects a non-critical feature or a smaller, specific subset of users.
|
||||
- An inconvenient but functional workaround is available and easy to execute.
|
||||
- Noticeable UI/UX problems that don't break functionality but look unprofessional (e.g., elements are misaligned or overlapping).
|
||||
Qualifier: Is it an annoying but non-blocking problem?
|
||||
Example: An error message is unclear or contains a typo, causing user confusion but not halting their workflow.
|
||||
P3: Low
|
||||
- A P3 bug is a minor, low-impact issue that is trivial or cosmetic. It has little to no effect on the overall functionality of the application.
|
||||
Impact:
|
||||
- Minor cosmetic issues like color inconsistencies, typos in documentation, or slight alignment problems on a non-critical page.
|
||||
- An edge-case bug that is very difficult to reproduce and affects a tiny fraction of users.
|
||||
Qualifier: Is it a "nice-to-fix" issue?
|
||||
Example: Spelling mistakes etc.
|
||||
|
||||
Categorization Guidelines (Priority):
|
||||
P0 - Urgent Blocking Issues:
|
||||
- DO NOT APPLY THIS LABEL AUTOMATICALLY. Use status/manual-triage instead.
|
||||
- Definition: Urgent, block a significant percentage of the user base, and prevent frequent use of the Gemini CLI.
|
||||
- This includes core stability blockers (e.g., authentication failures, broken upgrades), critical crashes, and P0 security vulnerabilities.
|
||||
- Impact: Blocks development or testing for the entire team; Major security vulnerability; Causes data loss or corruption with no workaround; Crashes the application or makes a core feature completely unusable for all or most users.
|
||||
- Qualifier: Is the main function of the software broken?
|
||||
P1 - High-Impact Issues:
|
||||
- Definition: Affect a large number of users, blocking them from using parts of the Gemini CLI, or make the CLI frequently unusable even with workarounds available.
|
||||
- Impact: A core feature is broken or behaving incorrectly for a large number of users or use cases; Severe performance degradation; No straightforward workaround exists.
|
||||
- Qualifier: Is a key feature unusable or giving very wrong results?
|
||||
P2 - Significant Issues:
|
||||
- Definition: Affect some users significantly, such as preventing the use of certain features or authentication types.
|
||||
- Can also be issues that many users complain about, causing annoyance or hindering daily use.
|
||||
- Impact: Affects a non-critical feature or a smaller, specific subset of users; An inconvenient but functional workaround is available; Noticeable UI/UX problems that look unprofessional.
|
||||
- Qualifier: Is it an annoying but non-blocking problem?
|
||||
P3 - Low-Impact Issues:
|
||||
- Definition: Typically usability issues that cause annoyance to a limited user base.
|
||||
- Includes feature requests that could be addressed in the near future and may be suitable for community contributions.
|
||||
- Impact: Minor cosmetic issues; An edge-case bug that is very difficult to reproduce and affects a tiny fraction of users.
|
||||
- Qualifier: Is it a "nice-to-fix" issue?
|
||||
|
||||
Categorization Guidelines (Area):
|
||||
area/agent: Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality
|
||||
area/core: User Interface, OS Support, Core Functionality
|
||||
area/enterprise: Telemetry, Policy, Quota / Licensing
|
||||
area/extensions: Gemini CLI extensions capability
|
||||
area/non-interactive: GitHub Actions, SDK, 3P Integrations, Shell Scripting, Command line automation
|
||||
area/platform: Build infra, Release mgmt, Testing, Eval infra, Capacity, Quota mgmt
|
||||
area/security: security related issues
|
||||
|
||||
Additional Context:
|
||||
- If users are talking about issues where the model gets downgraded from pro to flash then i want you to categorize that as a performance issue
|
||||
- This product is designed to use different models eg.. using pro, downgrading to flash etc.
|
||||
- When users report that they dont expect the model to change those would be categorized as feature requests.
|
||||
Definition of Areas
|
||||
area/ux:
|
||||
- Issues concerning user-facing elements like command usability, interactive features, help docs, and perceived performance.
|
||||
- I am seeing my screen flicker when using Gemini CLI
|
||||
- I am seeing the output malformed
|
||||
- Theme changes aren't taking effect
|
||||
- My keyboard inputs arent' being recognzied
|
||||
area/platform:
|
||||
- Issues related to installation, packaging, OS compatibility (Windows, macOS, Linux), and the underlying CLI framework.
|
||||
area/background: Issues related to long-running background tasks, daemons, and autonomous or proactive agent features.
|
||||
area/models:
|
||||
- i am not getting a response that is reasonable or expected. this can include things like
|
||||
- I am calling a tool and the tool is not performing as expected.
|
||||
- i am expecting a tool to be called and it is not getting called ,
|
||||
- Including experience when using
|
||||
- built-in tools (e.g., web search, code interpreter, read file, writefile, etc..),
|
||||
- Function calling issues should be under this area
|
||||
- i am getting responses from the model that are malformed.
|
||||
- Issues concerning Gemini quality of response and inference,
|
||||
- Issues talking about unnecessary token consumption.
|
||||
- Issues talking about Model getting stuck in a loop be watchful as this could be the root cause for issues that otherwise seem like model performance issues.
|
||||
- Memory compression
|
||||
- unexpected responses,
|
||||
- poor quality of generated code
|
||||
area/tools:
|
||||
- These are primarily issues related to Model Context Protocol
|
||||
- These are issues that mention MCP support
|
||||
- feature requests asking for support for new tools.
|
||||
area/core:
|
||||
- Issues with fundamental components like command parsing, configuration management, session state, and the main API client logic. Introducing multi-modality
|
||||
area/contribution:
|
||||
- Issues related to improving the developer contribution experience, such as CI/CD pipelines, build scripts, and test automation infrastructure.
|
||||
area/authentication:
|
||||
- Issues related to user identity, login flows, API key handling, credential storage, and access token management, unable to sign in selecting wrong authentication path etc..
|
||||
area/security-privacy:
|
||||
- Issues concerning vulnerability patching, dependency security, data sanitization, privacy controls, and preventing unauthorized data access.
|
||||
area/extensibility:
|
||||
- Issues related to the plugin system, extension APIs, or making the CLI's functionality available in other applications, github actions, ide support etc..
|
||||
area/performance:
|
||||
- Issues focused on model performance
|
||||
- Issues with running out of capacity,
|
||||
- 429 errors etc..
|
||||
- could also pertain to latency,
|
||||
- other general software performance like, memory usage, CPU consumption, and algorithmic efficiency.
|
||||
- Switching models from one to the other unexpectedly.
|
||||
- If users are talking about issues where the model gets downgraded from pro to flash then i want you to categorize that as a performance issue.
|
||||
- This product is designed to use different models eg.. using pro, downgrading to flash etc.
|
||||
- When users report that they dont expect the model to change those would be categorized as feature requests.
|
||||
|
||||
- name: 'Apply Labels to Issues'
|
||||
if: |-
|
||||
@@ -300,24 +263,6 @@ jobs:
|
||||
core.info(`Successfully added labels for #${issueNumber}: ${labelsToAdd.join(', ')}${explanation}`);
|
||||
}
|
||||
|
||||
if (entry.labels_to_remove && entry.labels_to_remove.length > 0) {
|
||||
for (const label of entry.labels_to_remove) {
|
||||
try {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
name: label
|
||||
});
|
||||
} catch (error) {
|
||||
if (error.status !== 404) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
core.info(`Successfully removed labels for #${issueNumber}: ${entry.labels_to_remove.join(', ')}`);
|
||||
}
|
||||
|
||||
if (entry.explanation) {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
|
||||
@@ -39,3 +39,7 @@ jobs:
|
||||
GITHUB_REPOSITORY: '${{ github.repository }}'
|
||||
run: |-
|
||||
./.github/scripts/pr-triage.sh
|
||||
# If prs_needing_comment is empty, set it to [] explicitly for downstream steps
|
||||
if [[ -z "$(grep 'prs_needing_comment' "${GITHUB_OUTPUT}" | cut -d'=' -f2-)" ]]; then
|
||||
echo "prs_needing_comment=[]" >> "${GITHUB_OUTPUT}"
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
name: '🔒 Gemini Scheduled Stale Issue Closer'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # Every Sunday at midnight UTC
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: 'Run in dry-run mode (no changes applied)'
|
||||
required: false
|
||||
default: false
|
||||
type: 'boolean'
|
||||
|
||||
concurrency:
|
||||
group: '${{ github.workflow }}'
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: 'bash'
|
||||
|
||||
jobs:
|
||||
close-stale-issues:
|
||||
runs-on: 'ubuntu-latest'
|
||||
permissions:
|
||||
issues: 'write'
|
||||
steps:
|
||||
- name: 'Generate GitHub App Token'
|
||||
id: 'generate_token'
|
||||
uses: 'actions/create-github-app-token@v2'
|
||||
with:
|
||||
app-id: '${{ secrets.APP_ID }}'
|
||||
private-key: '${{ secrets.PRIVATE_KEY }}'
|
||||
permission-issues: 'write'
|
||||
|
||||
- name: 'Process Stale Issues'
|
||||
uses: 'actions/github-script@v7'
|
||||
env:
|
||||
DRY_RUN: '${{ inputs.dry_run }}'
|
||||
with:
|
||||
github-token: '${{ steps.generate_token.outputs.token }}'
|
||||
script: |
|
||||
const dryRun = process.env.DRY_RUN === 'true';
|
||||
if (dryRun) {
|
||||
core.info('DRY RUN MODE ENABLED: No changes will be applied.');
|
||||
}
|
||||
const batchLabel = 'Stale';
|
||||
|
||||
const threeMonthsAgo = new Date();
|
||||
threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3);
|
||||
|
||||
const tenDaysAgo = new Date();
|
||||
tenDaysAgo.setDate(tenDaysAgo.getDate() - 10);
|
||||
|
||||
core.info(`Cutoff date for creation: ${threeMonthsAgo.toISOString()}`);
|
||||
core.info(`Cutoff date for updates: ${tenDaysAgo.toISOString()}`);
|
||||
|
||||
const query = `repo:${context.repo.owner}/${context.repo.repo} is:issue is:open created:<${threeMonthsAgo.toISOString()}`;
|
||||
core.info(`Searching with query: ${query}`);
|
||||
|
||||
const itemsToCheck = await github.paginate(github.rest.search.issuesAndPullRequests, {
|
||||
q: query,
|
||||
sort: 'created',
|
||||
order: 'asc',
|
||||
per_page: 100
|
||||
});
|
||||
|
||||
core.info(`Found ${itemsToCheck.length} open issues to check.`);
|
||||
|
||||
let processedCount = 0;
|
||||
|
||||
for (const issue of itemsToCheck) {
|
||||
const createdAt = new Date(issue.created_at);
|
||||
const updatedAt = new Date(issue.updated_at);
|
||||
const reactionCount = issue.reactions.total_count;
|
||||
|
||||
// Basic thresholds
|
||||
if (reactionCount >= 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if it has a maintainer, help wanted, or Public Roadmap label
|
||||
const rawLabels = issue.labels.map((l) => l.name);
|
||||
const lowercaseLabels = rawLabels.map((l) => l.toLowerCase());
|
||||
if (
|
||||
lowercaseLabels.some((l) => l.includes('maintainer')) ||
|
||||
lowercaseLabels.includes('help wanted') ||
|
||||
rawLabels.includes('🗓️ Public Roadmap')
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let isStale = updatedAt < tenDaysAgo;
|
||||
|
||||
// If apparently active, check if it's only bot activity
|
||||
if (!isStale) {
|
||||
try {
|
||||
const comments = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
per_page: 100,
|
||||
sort: 'created',
|
||||
direction: 'desc'
|
||||
});
|
||||
|
||||
const lastHumanComment = comments.data.find(comment => comment.user.type !== 'Bot');
|
||||
if (lastHumanComment) {
|
||||
isStale = new Date(lastHumanComment.created_at) < tenDaysAgo;
|
||||
} else {
|
||||
// No human comments. Check if creator is human.
|
||||
if (issue.user.type !== 'Bot') {
|
||||
isStale = createdAt < tenDaysAgo;
|
||||
} else {
|
||||
isStale = true; // Bot created, only bot comments
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
core.warning(`Failed to fetch comments for issue #${issue.number}: ${error.message}`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isStale) {
|
||||
processedCount++;
|
||||
const message = `Closing stale issue #${issue.number}: "${issue.title}" (${issue.html_url})`;
|
||||
core.info(message);
|
||||
|
||||
if (!dryRun) {
|
||||
// Add label
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
labels: [batchLabel]
|
||||
});
|
||||
|
||||
// Add comment
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
body: 'Hello! As part of our effort to keep our backlog manageable and focus on the most active issues, we are tidying up older reports.\n\nIt looks like this issue hasn\'t been active for a while, so we are closing it for now. However, if you are still experiencing this bug on the latest stable build, please feel free to comment on this issue or create a new one with updated details.\n\nThank you for your contribution!'
|
||||
});
|
||||
|
||||
// Close issue
|
||||
await github.rest.issues.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
state: 'closed',
|
||||
state_reason: 'not_planned'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
core.info(`\nTotal issues processed: ${processedCount}`);
|
||||
@@ -0,0 +1,254 @@
|
||||
name: 'Gemini Scheduled Stale PR Closer'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # Every day at 2 AM UTC
|
||||
pull_request:
|
||||
types: ['opened', 'edited']
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: 'Run in dry-run mode'
|
||||
required: false
|
||||
default: false
|
||||
type: 'boolean'
|
||||
|
||||
jobs:
|
||||
close-stale-prs:
|
||||
if: "github.repository == 'google-gemini/gemini-cli'"
|
||||
runs-on: 'ubuntu-latest'
|
||||
permissions:
|
||||
pull-requests: 'write'
|
||||
issues: 'write'
|
||||
steps:
|
||||
- name: 'Generate GitHub App Token'
|
||||
id: 'generate_token'
|
||||
uses: 'actions/create-github-app-token@v2'
|
||||
with:
|
||||
app-id: '${{ secrets.APP_ID }}'
|
||||
private-key: '${{ secrets.PRIVATE_KEY }}'
|
||||
|
||||
- name: 'Process Stale PRs'
|
||||
uses: 'actions/github-script@v7'
|
||||
env:
|
||||
DRY_RUN: '${{ inputs.dry_run }}'
|
||||
with:
|
||||
github-token: '${{ steps.generate_token.outputs.token }}'
|
||||
script: |
|
||||
const dryRun = process.env.DRY_RUN === 'true';
|
||||
const thirtyDaysAgo = new Date();
|
||||
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
|
||||
|
||||
// 1. Fetch maintainers for verification
|
||||
let maintainerLogins = new Set();
|
||||
const teams = ['gemini-cli-maintainers', 'gemini-cli-askmode-approvers', 'gemini-cli-docs'];
|
||||
|
||||
for (const team_slug of teams) {
|
||||
try {
|
||||
const members = await github.paginate(github.rest.teams.listMembersInOrg, {
|
||||
org: context.repo.owner,
|
||||
team_slug: team_slug
|
||||
});
|
||||
for (const m of members) maintainerLogins.add(m.login.toLowerCase());
|
||||
core.info(`Successfully fetched ${members.length} team members from ${team_slug}`);
|
||||
} catch (e) {
|
||||
core.warning(`Failed to fetch team members from ${team_slug}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
const isGooglerCache = new Map();
|
||||
const isGoogler = async (login) => {
|
||||
if (isGooglerCache.has(login)) return isGooglerCache.get(login);
|
||||
|
||||
try {
|
||||
// Check membership in 'googlers' or 'google' orgs
|
||||
const orgs = ['googlers', 'google'];
|
||||
for (const org of orgs) {
|
||||
try {
|
||||
await github.rest.orgs.checkMembershipForUser({
|
||||
org: org,
|
||||
username: login
|
||||
});
|
||||
core.info(`User ${login} is a member of ${org} organization.`);
|
||||
isGooglerCache.set(login, true);
|
||||
return true;
|
||||
} catch (e) {
|
||||
// 404 just means they aren't a member, which is fine
|
||||
if (e.status !== 404) throw e;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
core.warning(`Failed to check org membership for ${login}: ${e.message}`);
|
||||
}
|
||||
|
||||
isGooglerCache.set(login, false);
|
||||
return false;
|
||||
};
|
||||
|
||||
const isMaintainer = async (login, assoc) => {
|
||||
const isTeamMember = maintainerLogins.has(login.toLowerCase());
|
||||
const isRepoMaintainer = ['OWNER', 'MEMBER', 'COLLABORATOR'].includes(assoc);
|
||||
if (isTeamMember || isRepoMaintainer) return true;
|
||||
|
||||
return await isGoogler(login);
|
||||
};
|
||||
|
||||
// 2. Determine which PRs to check
|
||||
let prs = [];
|
||||
if (context.eventName === 'pull_request') {
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.payload.pull_request.number
|
||||
});
|
||||
prs = [pr];
|
||||
} else {
|
||||
prs = await github.paginate(github.rest.pulls.list, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
state: 'open',
|
||||
per_page: 100
|
||||
});
|
||||
}
|
||||
|
||||
for (const pr of prs) {
|
||||
const maintainerPr = await isMaintainer(pr.user.login, pr.author_association);
|
||||
const isBot = pr.user.type === 'Bot' || pr.user.login.endsWith('[bot]');
|
||||
|
||||
// Detection Logic for Linked Issues
|
||||
// Check 1: Official GitHub "Closing Issue" link (GraphQL)
|
||||
const linkedIssueQuery = `query($owner:String!, $repo:String!, $number:Int!) {
|
||||
repository(owner:$owner, name:$repo) {
|
||||
pullRequest(number:$number) {
|
||||
closingIssuesReferences(first: 1) { totalCount }
|
||||
}
|
||||
}
|
||||
}`;
|
||||
|
||||
let hasClosingLink = false;
|
||||
try {
|
||||
const res = await github.graphql(linkedIssueQuery, {
|
||||
owner: context.repo.owner, repo: context.repo.repo, number: pr.number
|
||||
});
|
||||
hasClosingLink = res.repository.pullRequest.closingIssuesReferences.totalCount > 0;
|
||||
} catch (e) {}
|
||||
|
||||
// Check 2: Regex for mentions (e.g., "Related to #123", "Part of #123", "#123")
|
||||
// We check for # followed by numbers or direct URLs to issues.
|
||||
const body = pr.body || '';
|
||||
const mentionRegex = /(?:#|https:\/\/github\.com\/[^\/]+\/[^\/]+\/issues\/)(\d+)/i;
|
||||
const hasMentionLink = mentionRegex.test(body);
|
||||
|
||||
const hasLinkedIssue = hasClosingLink || hasMentionLink;
|
||||
|
||||
// Logic for Closed PRs (Auto-Reopen)
|
||||
if (pr.state === 'closed' && context.eventName === 'pull_request' && context.payload.action === 'edited') {
|
||||
if (hasLinkedIssue) {
|
||||
core.info(`PR #${pr.number} now has a linked issue. Reopening.`);
|
||||
if (!dryRun) {
|
||||
await github.rest.pulls.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: pr.number,
|
||||
state: 'open'
|
||||
});
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body: "Thank you for linking an issue! This pull request has been automatically reopened."
|
||||
});
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Logic for Open PRs (Immediate Closure)
|
||||
if (pr.state === 'open' && !maintainerPr && !hasLinkedIssue && !isBot) {
|
||||
core.info(`PR #${pr.number} is missing a linked issue. Closing.`);
|
||||
if (!dryRun) {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body: "Hi there! Thank you for your contribution to Gemini CLI. \n\nTo improve our contribution process and better track changes, we now require all pull requests to be associated with an existing issue, as announced in our [recent discussion](https://github.com/google-gemini/gemini-cli/discussions/16706) and as detailed in our [CONTRIBUTING.md](https://github.com/google-gemini/gemini-cli/blob/main/CONTRIBUTING.md#1-link-to-an-existing-issue).\n\nThis pull request is being closed because it is not currently linked to an issue. **Once you have updated the description of this PR to link an issue (e.g., by adding `Fixes #123` or `Related to #123`), it will be automatically reopened.**\n\n**How to link an issue:**\nAdd a keyword followed by the issue number (e.g., `Fixes #123`) in the description of your pull request. For more details on supported keywords and how linking works, please refer to the [GitHub Documentation on linking pull requests to issues](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).\n\nThank you for your understanding and for being a part of our community!"
|
||||
});
|
||||
await github.rest.pulls.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: pr.number,
|
||||
state: 'closed'
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Staleness check (Scheduled runs only)
|
||||
if (pr.state === 'open' && context.eventName !== 'pull_request') {
|
||||
const labels = pr.labels.map(l => l.name.toLowerCase());
|
||||
if (labels.includes('help wanted') || labels.includes('🔒 maintainer only')) continue;
|
||||
|
||||
// Skip PRs that were created less than 30 days ago - they cannot be stale yet
|
||||
const prCreatedAt = new Date(pr.created_at);
|
||||
if (prCreatedAt > thirtyDaysAgo) {
|
||||
const daysOld = Math.floor((Date.now() - prCreatedAt.getTime()) / (1000 * 60 * 60 * 24));
|
||||
core.info(`PR #${pr.number} was created ${daysOld} days ago. Skipping staleness check.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Initialize lastActivity to PR creation date (not epoch) as a safety baseline.
|
||||
// This ensures we never incorrectly mark a PR as stale due to failed activity lookups.
|
||||
let lastActivity = new Date(pr.created_at);
|
||||
try {
|
||||
const reviews = await github.paginate(github.rest.pulls.listReviews, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: pr.number
|
||||
});
|
||||
for (const r of reviews) {
|
||||
if (await isMaintainer(r.user.login, r.author_association)) {
|
||||
const d = new Date(r.submitted_at || r.updated_at);
|
||||
if (d > lastActivity) lastActivity = d;
|
||||
}
|
||||
}
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number
|
||||
});
|
||||
for (const c of comments) {
|
||||
if (await isMaintainer(c.user.login, c.author_association)) {
|
||||
const d = new Date(c.updated_at);
|
||||
if (d > lastActivity) lastActivity = d;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
core.warning(`Failed to fetch reviews/comments for PR #${pr.number}: ${e.message}`);
|
||||
}
|
||||
|
||||
// For maintainer PRs, the PR creation itself counts as maintainer activity.
|
||||
// (Now redundant since we initialize to pr.created_at, but kept for clarity)
|
||||
if (maintainerPr) {
|
||||
const d = new Date(pr.created_at);
|
||||
if (d > lastActivity) lastActivity = d;
|
||||
}
|
||||
|
||||
if (lastActivity < thirtyDaysAgo) {
|
||||
core.info(`PR #${pr.number} is stale.`);
|
||||
if (!dryRun) {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body: "Hi there! Thank you for your contribution to Gemini CLI. We really appreciate the time and effort you've put into this pull request.\n\nTo keep our backlog manageable and ensure we're focusing on current priorities, we are closing pull requests that haven't seen maintainer activity for 30 days. Currently, the team is prioritizing work associated with **🔒 maintainer only** or **help wanted** issues.\n\nIf you believe this change is still critical, please feel free to comment with updated details. Otherwise, we encourage contributors to focus on open issues labeled as **help wanted**. Thank you for your understanding!"
|
||||
});
|
||||
await github.rest.pulls.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: pr.number,
|
||||
state: 'closed'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,24 @@ jobs:
|
||||
const repo = context.repo.repo;
|
||||
const MAX_ISSUES_ASSIGNED = 3;
|
||||
|
||||
const issue = await github.rest.issues.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
});
|
||||
|
||||
const hasHelpWantedLabel = issue.data.labels.some(label => label.name === 'help wanted');
|
||||
|
||||
if (!hasHelpWantedLabel) {
|
||||
await github.rest.issues.createComment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: issueNumber,
|
||||
body: `👋 @${commenter}, thanks for your interest in this issue! We're reserving self-assignment for issues that have been marked with the \`help wanted\` label. Feel free to check out our list of [issues that need attention](https://github.com/google-gemini/gemini-cli/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22).`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for open issues already assigned to the commenter in this repo
|
||||
const { data: assignedIssues } = await github.rest.search.issuesAndPullRequests({
|
||||
q: `is:issue repo:${owner}/${repo} assignee:${commenter} is:open`,
|
||||
@@ -64,13 +82,6 @@ jobs:
|
||||
return; // exit
|
||||
}
|
||||
|
||||
// Check if the issue is already assigned
|
||||
const issue = await github.rest.issues.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
});
|
||||
|
||||
if (issue.data.assignees.length > 0) {
|
||||
// Comment that it's already assigned
|
||||
await github.rest.issues.createComment({
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
name: '🏷️ Issue Opened Labeler'
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- 'opened'
|
||||
|
||||
jobs:
|
||||
label-issue:
|
||||
runs-on: 'ubuntu-latest'
|
||||
if: |-
|
||||
${{ github.repository == 'google-gemini/gemini-cli' || github.repository == 'google-gemini/maintainers-gemini-cli' }}
|
||||
steps:
|
||||
- name: 'Generate GitHub App Token'
|
||||
id: 'generate_token'
|
||||
env:
|
||||
APP_ID: '${{ secrets.APP_ID }}'
|
||||
if: |-
|
||||
${{ env.APP_ID != '' }}
|
||||
uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b' # ratchet:actions/create-github-app-token@v2
|
||||
with:
|
||||
app-id: '${{ secrets.APP_ID }}'
|
||||
private-key: '${{ secrets.PRIVATE_KEY }}'
|
||||
|
||||
- name: 'Add need-triage label'
|
||||
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
|
||||
with:
|
||||
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
|
||||
script: |-
|
||||
const { data: issue } = await github.rest.issues.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
});
|
||||
|
||||
const hasLabel = issue.labels.some(l => l.name === 'status/need-triage');
|
||||
if (!hasLabel) {
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
labels: ['status/need-triage']
|
||||
});
|
||||
} else {
|
||||
core.info('Issue already has status/need-triage label. Skipping.');
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
name: 'Label Child Issues for Project Rollup'
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: ['opened', 'edited', 'reopened']
|
||||
schedule:
|
||||
- cron: '0 * * * *' # Run every hour
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
issues: 'write'
|
||||
contents: 'read'
|
||||
|
||||
jobs:
|
||||
# Event-based: Quick reaction to new/edited issues in THIS repo
|
||||
labeler:
|
||||
if: "github.event_name == 'issues'"
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@v4'
|
||||
|
||||
- name: 'Setup Node.js'
|
||||
uses: 'actions/setup-node@v4'
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Install Dependencies'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Run Multi-Repo Sync Script'
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
run: 'node .github/scripts/sync-maintainer-labels.cjs'
|
||||
|
||||
# Scheduled/Manual: Recursive sync across multiple repos
|
||||
sync-maintainer-labels:
|
||||
if: "github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'"
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@v4'
|
||||
|
||||
- name: 'Setup Node.js'
|
||||
uses: 'actions/setup-node@v4'
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Install Dependencies'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Run Multi-Repo Sync Script'
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
run: 'node .github/scripts/sync-maintainer-labels.cjs'
|
||||
@@ -0,0 +1,174 @@
|
||||
name: 'Label Workstream Rollup'
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: ['opened', 'edited', 'reopened']
|
||||
schedule:
|
||||
- cron: '0 * * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
runs-on: 'ubuntu-latest'
|
||||
permissions:
|
||||
issues: 'write'
|
||||
steps:
|
||||
- name: 'Check for Parent Workstream and Apply Label'
|
||||
uses: 'actions/github-script@v7'
|
||||
with:
|
||||
script: |
|
||||
const labelToAdd = 'workstream-rollup';
|
||||
|
||||
// Allow-list of parent issue URLs
|
||||
const allowedParentUrls = [
|
||||
'https://github.com/google-gemini/gemini-cli/issues/15374',
|
||||
'https://github.com/google-gemini/gemini-cli/issues/15456',
|
||||
'https://github.com/google-gemini/gemini-cli/issues/15324',
|
||||
'https://github.com/google-gemini/gemini-cli/issues/17202',
|
||||
'https://github.com/google-gemini/gemini-cli/issues/17203'
|
||||
];
|
||||
|
||||
// Single issue processing (for event triggers)
|
||||
async function processSingleIssue(owner, repo, number) {
|
||||
const query = `
|
||||
query($owner:String!, $repo:String!, $number:Int!) {
|
||||
repository(owner:$owner, name:$repo) {
|
||||
issue(number:$number) {
|
||||
number
|
||||
parent {
|
||||
url
|
||||
parent {
|
||||
url
|
||||
parent {
|
||||
url
|
||||
parent {
|
||||
url
|
||||
parent {
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
try {
|
||||
const result = await github.graphql(query, { owner, repo, number });
|
||||
|
||||
if (!result || !result.repository || !result.repository.issue) {
|
||||
console.log(`Issue #${number} not found or data missing.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const issue = result.repository.issue;
|
||||
await checkAndLabel(issue, owner, repo);
|
||||
} catch (error) {
|
||||
console.error(`Failed to process issue #${number}:`, error);
|
||||
throw error; // Re-throw to be caught by main execution
|
||||
}
|
||||
}
|
||||
|
||||
// Bulk processing (for schedule/dispatch)
|
||||
async function processAllOpenIssues(owner, repo) {
|
||||
const query = `
|
||||
query($owner:String!, $repo:String!, $cursor:String) {
|
||||
repository(owner:$owner, name:$repo) {
|
||||
issues(first: 100, states: OPEN, after: $cursor) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
nodes {
|
||||
number
|
||||
parent {
|
||||
url
|
||||
parent {
|
||||
url
|
||||
parent {
|
||||
url
|
||||
parent {
|
||||
url
|
||||
parent {
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
let hasNextPage = true;
|
||||
let cursor = null;
|
||||
|
||||
while (hasNextPage) {
|
||||
try {
|
||||
const result = await github.graphql(query, { owner, repo, cursor });
|
||||
|
||||
if (!result || !result.repository || !result.repository.issues) {
|
||||
console.error('Invalid response structure from GitHub API');
|
||||
break;
|
||||
}
|
||||
|
||||
const issues = result.repository.issues.nodes || [];
|
||||
|
||||
console.log(`Processing batch of ${issues.length} issues...`);
|
||||
for (const issue of issues) {
|
||||
await checkAndLabel(issue, owner, repo);
|
||||
}
|
||||
|
||||
hasNextPage = result.repository.issues.pageInfo.hasNextPage;
|
||||
cursor = result.repository.issues.pageInfo.endCursor;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch issues batch:', error);
|
||||
throw error; // Re-throw to be caught by main execution
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function checkAndLabel(issue, owner, repo) {
|
||||
if (!issue || !issue.parent) return;
|
||||
|
||||
let currentParent = issue.parent;
|
||||
let tracedParents = [];
|
||||
let matched = false;
|
||||
|
||||
while (currentParent) {
|
||||
tracedParents.push(currentParent.url);
|
||||
|
||||
if (allowedParentUrls.includes(currentParent.url)) {
|
||||
console.log(`SUCCESS: Issue #${issue.number} is a descendant of ${currentParent.url}. Trace: ${tracedParents.join(' -> ')}. Adding label.`);
|
||||
await github.rest.issues.addLabels({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issue.number,
|
||||
labels: [labelToAdd]
|
||||
});
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
currentParent = currentParent.parent;
|
||||
}
|
||||
|
||||
if (!matched && context.eventName === 'issues') {
|
||||
console.log(`Issue #${issue.number} did not match any allowed workstreams. Trace: ${tracedParents.join(' -> ') || 'None'}.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Main execution
|
||||
try {
|
||||
if (context.eventName === 'issues') {
|
||||
console.log(`Processing single issue #${context.payload.issue.number}...`);
|
||||
await processSingleIssue(context.repo.owner, context.repo.repo, context.payload.issue.number);
|
||||
} else {
|
||||
console.log(`Running for event: ${context.eventName}. Processing all open issues...`);
|
||||
await processAllOpenIssues(context.repo.owner, context.repo.repo);
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed(`Workflow failed: ${error.message}`);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
name: 'Links'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['main']
|
||||
pull_request:
|
||||
branches: ['main']
|
||||
repository_dispatch:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '00 18 * * *'
|
||||
|
||||
jobs:
|
||||
linkChecker:
|
||||
if: |-
|
||||
${{ github.repository == 'google-gemini/gemini-cli' }}
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
|
||||
|
||||
- name: 'Link Checker'
|
||||
id: 'lychee'
|
||||
uses: 'lycheeverse/lychee-action@885c65f3dc543b57c898c8099f4e08c8afd178a2' # ratchet: lycheeverse/lychee-action@v2.6.1
|
||||
with:
|
||||
args: '--verbose --no-progress --accept 200,503 ./**/*.md'
|
||||
@@ -0,0 +1,133 @@
|
||||
name: '🏷️ PR Contribution Guidelines Notifier'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- 'opened'
|
||||
|
||||
jobs:
|
||||
notify-process-change:
|
||||
runs-on: 'ubuntu-latest'
|
||||
if: |-
|
||||
github.repository == 'google-gemini/gemini-cli' || github.repository == 'google-gemini/maintainers-gemini-cli'
|
||||
permissions:
|
||||
pull-requests: 'write'
|
||||
steps:
|
||||
- name: 'Generate GitHub App Token'
|
||||
id: 'generate_token'
|
||||
env:
|
||||
APP_ID: '${{ secrets.APP_ID }}'
|
||||
if: |-
|
||||
${{ env.APP_ID != '' }}
|
||||
uses: 'actions/create-github-app-token@v2'
|
||||
with:
|
||||
app-id: '${{ secrets.APP_ID }}'
|
||||
private-key: '${{ secrets.PRIVATE_KEY }}'
|
||||
|
||||
- name: 'Check membership and post comment'
|
||||
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
|
||||
with:
|
||||
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
|
||||
script: |-
|
||||
const org = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const username = context.payload.pull_request.user.login;
|
||||
const pr_number = context.payload.pull_request.number;
|
||||
|
||||
// 1. Check if the PR author is a maintainer
|
||||
// Check team membership (most reliable for private org members)
|
||||
let isTeamMember = false;
|
||||
const teams = ['gemini-cli-maintainers', 'gemini-cli-askmode-approvers', 'gemini-cli-docs'];
|
||||
for (const team_slug of teams) {
|
||||
try {
|
||||
const members = await github.paginate(github.rest.teams.listMembersInOrg, {
|
||||
org: org,
|
||||
team_slug: team_slug
|
||||
});
|
||||
if (members.some(m => m.login.toLowerCase() === username.toLowerCase())) {
|
||||
isTeamMember = true;
|
||||
core.info(`${username} is a member of ${team_slug}. No notification needed.`);
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
core.warning(`Failed to fetch team members from ${team_slug}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (isTeamMember) return;
|
||||
|
||||
// Check author_association from webhook payload
|
||||
const authorAssociation = context.payload.pull_request.author_association;
|
||||
const isRepoMaintainer = ['OWNER', 'MEMBER', 'COLLABORATOR'].includes(authorAssociation);
|
||||
|
||||
if (isRepoMaintainer) {
|
||||
core.info(`${username} is a maintainer (author_association: ${authorAssociation}). No notification needed.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if author is a Googler
|
||||
const isGoogler = async (login) => {
|
||||
try {
|
||||
const orgs = ['googlers', 'google'];
|
||||
for (const org of orgs) {
|
||||
try {
|
||||
await github.rest.orgs.checkMembershipForUser({
|
||||
org: org,
|
||||
username: login
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e.status !== 404) throw e;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
core.warning(`Failed to check org membership for ${login}: ${e.message}`);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (await isGoogler(username)) {
|
||||
core.info(`${username} is a Googler. No notification needed.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Check if the PR is already associated with an issue
|
||||
const query = `
|
||||
query($owner:String!, $repo:String!, $number:Int!) {
|
||||
repository(owner:$owner, name:$repo) {
|
||||
pullRequest(number:$number) {
|
||||
closingIssuesReferences(first: 1) {
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
const variables = { owner: org, repo: repo, number: pr_number };
|
||||
const result = await github.graphql(query, variables);
|
||||
const issueCount = result.repository.pullRequest.closingIssuesReferences.totalCount;
|
||||
|
||||
if (issueCount > 0) {
|
||||
core.info(`PR #${pr_number} is already associated with an issue. No notification needed.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Post the notification comment
|
||||
core.info(`${username} is not a maintainer and PR #${pr_number} has no linked issue. Posting notification.`);
|
||||
|
||||
const comment = `
|
||||
Hi @${username}, thank you so much for your contribution to Gemini CLI! We really appreciate the time and effort you've put into this.
|
||||
|
||||
We're making some updates to our contribution process to improve how we track and review changes. Please take a moment to review our recent discussion post: [Improving Our Contribution Process & Introducing New Guidelines](https://github.com/google-gemini/gemini-cli/discussions/16706).
|
||||
|
||||
Key Update: Starting **January 26, 2026**, the Gemini CLI project will require all pull requests to be associated with an existing issue. Any pull requests not linked to an issue by that date will be automatically closed.
|
||||
|
||||
Thank you for your understanding and for being a part of our community!
|
||||
`.trim().replace(/^[ ]+/gm, '');
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: org,
|
||||
repo: repo,
|
||||
issue_number: pr_number,
|
||||
body: comment
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
||||
|
||||
name: 'PR rate limiter'
|
||||
|
||||
permissions: {}
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- 'opened'
|
||||
- 'reopened'
|
||||
|
||||
jobs:
|
||||
limit:
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
permissions:
|
||||
contents: 'read'
|
||||
pull-requests: 'write'
|
||||
steps:
|
||||
- name: 'Limit open pull requests per user'
|
||||
uses: 'Homebrew/actions/limit-pull-requests@9ceb7934560eb61d131dde205a6c2d77b2e1529d' # master
|
||||
with:
|
||||
except-author-associations: 'MEMBER,OWNER,COLLABORATOR'
|
||||
comment-limit: 8
|
||||
comment: >
|
||||
You already have 7 pull requests open. Please work on getting
|
||||
existing PRs merged before opening more.
|
||||
close-limit: 8
|
||||
close: true
|
||||
@@ -12,23 +12,28 @@ on:
|
||||
required: true
|
||||
type: 'choice'
|
||||
options:
|
||||
- 'dev'
|
||||
- 'latest'
|
||||
- 'preview'
|
||||
- 'nightly'
|
||||
ref:
|
||||
description: 'The branch, tag, or SHA to run from.'
|
||||
required: false
|
||||
type: 'string'
|
||||
default: 'main'
|
||||
dry-run:
|
||||
description: 'Whether to run in dry-run mode.'
|
||||
required: false
|
||||
type: 'boolean'
|
||||
default: true
|
||||
environment:
|
||||
description: 'Environment'
|
||||
required: false
|
||||
type: 'choice'
|
||||
options:
|
||||
- 'prod'
|
||||
- 'dev'
|
||||
default: 'prod'
|
||||
|
||||
jobs:
|
||||
change-tags:
|
||||
runs-on: 'ubuntu-latest'
|
||||
environment: "${{ github.event.inputs.environment || 'prod' }}"
|
||||
permissions:
|
||||
packages: 'write'
|
||||
issues: 'write'
|
||||
@@ -36,15 +41,13 @@ jobs:
|
||||
- name: 'Checkout repository'
|
||||
uses: 'actions/checkout@v4'
|
||||
with:
|
||||
ref: '${{ github.event.inputs.ref }}'
|
||||
ref: '${{ github.ref }}'
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 'Setup Node.js'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
registry-url: 'https://wombat-dressing-room.appspot.com'
|
||||
scope: '@google'
|
||||
|
||||
- name: 'Change tag'
|
||||
uses: './.github/actions/tag-npm-release'
|
||||
@@ -54,3 +57,9 @@ jobs:
|
||||
dry-run: '${{ github.event.inputs.dry-run }}'
|
||||
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
|
||||
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
|
||||
wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
cli-package-name: '${{ vars.CLI_PACKAGE_NAME }}'
|
||||
core-package-name: '${{ vars.CORE_PACKAGE_NAME }}'
|
||||
a2a-package-name: '${{ vars.A2A_PACKAGE_NAME }}'
|
||||
working-directory: '.'
|
||||
|
||||
@@ -12,15 +12,15 @@ on:
|
||||
required: true
|
||||
type: 'string'
|
||||
npm_channel:
|
||||
description: 'The npm channel to publish to.'
|
||||
description: 'The npm channel to publish to'
|
||||
required: true
|
||||
type: 'choice'
|
||||
options:
|
||||
- 'dev'
|
||||
- 'preview'
|
||||
- 'nightly'
|
||||
- 'latest'
|
||||
- 'dev'
|
||||
default: 'dev'
|
||||
default: 'latest'
|
||||
dry_run:
|
||||
description: 'Run a dry-run of the release process; no branches, npm packages or GitHub releases will be created.'
|
||||
required: true
|
||||
@@ -32,14 +32,23 @@ on:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
skip_github_release:
|
||||
description: 'Select to skip creating a GitHub release and create a npm release only.'
|
||||
description: 'Select to skip creating a GitHub release (only used when environment is PROD)'
|
||||
required: false
|
||||
type: 'boolean'
|
||||
default: false
|
||||
environment:
|
||||
description: 'Environment'
|
||||
required: false
|
||||
type: 'choice'
|
||||
options:
|
||||
- 'prod'
|
||||
- 'dev'
|
||||
default: 'prod'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: 'self-hosted'
|
||||
runs-on: 'ubuntu-latest'
|
||||
environment: "${{ github.event.inputs.environment || 'prod' }}"
|
||||
permissions:
|
||||
contents: 'write'
|
||||
packages: 'write'
|
||||
@@ -58,12 +67,15 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 'Debug Inputs'
|
||||
run: 'echo "${{ toJSON(inputs) }}"'
|
||||
shell: 'bash'
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
|
||||
- name: 'Setup Node.js'
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: './release/.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Install Dependencies'
|
||||
@@ -73,8 +85,10 @@ jobs:
|
||||
- name: 'Prepare Release Info'
|
||||
id: 'release_info'
|
||||
working-directory: './release'
|
||||
env:
|
||||
INPUT_VERSION: '${{ github.event.inputs.version }}'
|
||||
run: |
|
||||
RELEASE_VERSION="${{ github.event.inputs.version }}"
|
||||
RELEASE_VERSION="${INPUT_VERSION}"
|
||||
echo "RELEASE_VERSION=${RELEASE_VERSION#v}" >> "${GITHUB_OUTPUT}"
|
||||
echo "PREVIOUS_TAG=$(git describe --tags --abbrev=0)" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
@@ -94,12 +108,20 @@ jobs:
|
||||
npm-tag: '${{ github.event.inputs.npm_channel }}'
|
||||
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
|
||||
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
|
||||
wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
github-release-token: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
dry-run: '${{ github.event.inputs.dry_run }}'
|
||||
previous-tag: '${{ steps.release_info.outputs.PREVIOUS_TAG }}'
|
||||
skip-github-release: '${{ github.event.inputs.skip_github_release }}'
|
||||
working-directory: './release'
|
||||
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
|
||||
npm-registry-publish-url: '${{ vars.NPM_REGISTRY_PUBLISH_URL }}'
|
||||
npm-registry-url: '${{ vars.NPM_REGISTRY_URL }}'
|
||||
npm-registry-scope: '${{ vars.NPM_REGISTRY_SCOPE }}'
|
||||
cli-package-name: '${{ vars.CLI_PACKAGE_NAME }}'
|
||||
core-package-name: '${{ vars.CORE_PACKAGE_NAME }}'
|
||||
a2a-package-name: '${{ vars.A2A_PACKAGE_NAME }}'
|
||||
|
||||
- name: 'Create Issue on Failure'
|
||||
if: '${{ failure() && github.event.inputs.dry_run == false }}'
|
||||
@@ -111,4 +133,4 @@ jobs:
|
||||
gh issue create \
|
||||
--title 'Manual Release Failed for ${RELEASE_TAG} on $(date +'%Y-%m-%d')' \
|
||||
--body 'The manual release workflow failed. See the full run for details: ${DETAILS_URL}' \
|
||||
--label 'kind/bug,release-failure,priority/p0'
|
||||
--label 'release-failure,priority/p0'
|
||||
|
||||
@@ -20,9 +20,19 @@ on:
|
||||
required: false
|
||||
type: 'string'
|
||||
default: 'main'
|
||||
environment:
|
||||
description: 'Environment'
|
||||
required: false
|
||||
type: 'choice'
|
||||
options:
|
||||
- 'prod'
|
||||
- 'dev'
|
||||
default: 'prod'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: "github.repository == 'google-gemini/gemini-cli'"
|
||||
environment: "${{ github.event.inputs.environment || 'prod' }}"
|
||||
runs-on: 'ubuntu-latest'
|
||||
permissions:
|
||||
contents: 'write'
|
||||
@@ -53,11 +63,25 @@ jobs:
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Print Inputs'
|
||||
run: |
|
||||
echo "${{ toJSON(github.event.inputs) }}"
|
||||
shell: 'bash'
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(github.event.inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
|
||||
- name: 'Calculate Release Variables'
|
||||
id: 'vars'
|
||||
uses: './.github/actions/calculate-vars'
|
||||
with:
|
||||
dry_run: '${{ github.event.inputs.dry_run }}'
|
||||
|
||||
- name: 'Print Calculated vars'
|
||||
shell: 'bash'
|
||||
env:
|
||||
JSON_VARS: '${{ toJSON(steps.vars.outputs) }}'
|
||||
run: 'echo "$JSON_VARS"'
|
||||
|
||||
- name: 'Run Tests'
|
||||
if: "${{github.event.inputs.force_skip_tests == 'false'}}"
|
||||
if: "${{ github.event_name == 'schedule' || github.event.inputs.force_skip_tests == 'false' }}"
|
||||
uses: './.github/actions/run-tests'
|
||||
with:
|
||||
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
|
||||
@@ -98,25 +122,35 @@ jobs:
|
||||
npm-tag: '${{ steps.nightly_version.outputs.NPM_TAG }}'
|
||||
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
|
||||
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
|
||||
wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
dry-run: '${{ github.event.inputs.dry_run }}'
|
||||
github-release-token: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
dry-run: '${{ steps.vars.outputs.is_dry_run }}'
|
||||
previous-tag: '${{ steps.nightly_version.outputs.PREVIOUS_TAG }}'
|
||||
working-directory: './release'
|
||||
skip-branch-cleanup: true
|
||||
force-skip-tests: "${{ github.event_name != 'schedule' && github.event.inputs.force_skip_tests == 'true' }}"
|
||||
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
|
||||
npm-registry-publish-url: '${{ vars.NPM_REGISTRY_PUBLISH_URL }}'
|
||||
npm-registry-url: '${{ vars.NPM_REGISTRY_URL }}'
|
||||
npm-registry-scope: '${{ vars.NPM_REGISTRY_SCOPE }}'
|
||||
cli-package-name: '${{ vars.CLI_PACKAGE_NAME }}'
|
||||
core-package-name: '${{ vars.CORE_PACKAGE_NAME }}'
|
||||
a2a-package-name: '${{ vars.A2A_PACKAGE_NAME }}'
|
||||
|
||||
- name: 'Create and Merge Pull Request'
|
||||
if: "github.event.inputs.environment != 'dev'"
|
||||
uses: './.github/actions/create-pull-request'
|
||||
with:
|
||||
branch-name: 'release/${{ steps.nightly_version.outputs.RELEASE_TAG }}'
|
||||
pr-title: 'chore(release): bump version to ${{ steps.nightly_version.outputs.RELEASE_VERSION }}'
|
||||
pr-title: 'chore/release: bump version to ${{ steps.nightly_version.outputs.RELEASE_VERSION }}'
|
||||
pr-body: 'Automated version bump for nightly release.'
|
||||
github-token: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
dry-run: '${{ github.event.inputs.dry_run }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
dry-run: '${{ steps.vars.outputs.is_dry_run }}'
|
||||
working-directory: './release'
|
||||
|
||||
- name: 'Create Issue on Failure'
|
||||
if: "${{ failure() && github.event.inputs.dry_run != 'true' }}"
|
||||
if: "${{ failure() && github.event.inputs.environment != 'dev' && (github.event_name == 'schedule' || github.event.inputs.dry_run != 'true') }}"
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
RELEASE_TAG: '${{ steps.nightly_version.outputs.RELEASE_TAG }}'
|
||||
@@ -125,4 +159,4 @@ jobs:
|
||||
gh issue create \
|
||||
--title "Nightly Release Failed for ${RELEASE_TAG} on $(date +'%Y-%m-%d')" \
|
||||
--body "The nightly-release workflow failed. See the full run for details: ${DETAILS_URL}" \
|
||||
--label 'kind/bug,release-failure,priority/p0'
|
||||
--label 'release-failure,priority/p0'
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
# This workflow is triggered on every new release.
|
||||
# It uses Gemini to generate release notes and creates a PR with the changes.
|
||||
name: 'Generate Release Notes'
|
||||
|
||||
on:
|
||||
release:
|
||||
types: ['published']
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'New version (e.g., v1.2.3)'
|
||||
required: true
|
||||
type: 'string'
|
||||
body:
|
||||
description: 'Release notes body'
|
||||
required: true
|
||||
type: 'string'
|
||||
time:
|
||||
description: 'Release time'
|
||||
required: true
|
||||
type: 'string'
|
||||
|
||||
jobs:
|
||||
generate-release-notes:
|
||||
runs-on: 'ubuntu-latest'
|
||||
permissions:
|
||||
contents: 'write'
|
||||
pull-requests: 'write'
|
||||
steps:
|
||||
- name: 'Checkout repository'
|
||||
uses: 'actions/checkout@v4'
|
||||
with:
|
||||
# The user-level skills need to be available to the workflow
|
||||
fetch-depth: 0
|
||||
ref: 'main'
|
||||
|
||||
- name: 'Set up Node.js'
|
||||
uses: 'actions/setup-node@v4'
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: 'Get release information'
|
||||
id: 'release_info'
|
||||
run: |
|
||||
VERSION="${{ github.event.inputs.version || github.event.release.tag_name }}"
|
||||
TIME="${{ github.event.inputs.time || github.event.release.created_at }}"
|
||||
|
||||
echo "VERSION=${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
echo "TIME=${TIME}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Use a heredoc to preserve multiline release body
|
||||
echo 'RAW_CHANGELOG<<EOF' >> "$GITHUB_OUTPUT"
|
||||
printf "%s\n" "$BODY" >> "$GITHUB_OUTPUT"
|
||||
echo 'EOF' >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
GH_TOKEN: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
BODY: '${{ github.event.inputs.body || github.event.release.body }}'
|
||||
|
||||
- name: 'Generate Changelog with Gemini'
|
||||
uses: 'google-github-actions/run-gemini-cli@a3bf79042542528e91937b3a3a6fbc4967ee3c31' # ratchet:google-github-actions/run-gemini-cli@v0
|
||||
with:
|
||||
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
|
||||
prompt: |
|
||||
Activate the 'docs-changelog' skill.
|
||||
|
||||
**Release Information:**
|
||||
- New Version: ${{ steps.release_info.outputs.VERSION }}
|
||||
- Release Date: ${{ steps.release_info.outputs.TIME }}
|
||||
- Raw Changelog Data: ${{ steps.release_info.outputs.RAW_CHANGELOG }}
|
||||
|
||||
Execute the release notes generation process using the information provided.
|
||||
|
||||
- name: 'Create Pull Request'
|
||||
uses: 'peter-evans/create-pull-request@v6'
|
||||
with:
|
||||
token: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
commit-message: 'docs(changelog): update for ${{ steps.release_info.outputs.VERSION }}'
|
||||
title: 'Changelog for ${{ steps.release_info.outputs.VERSION }}'
|
||||
body: |
|
||||
This PR contains the auto-generated changelog for the ${{ steps.release_info.outputs.VERSION }} release.
|
||||
|
||||
Please review and merge.
|
||||
branch: 'changelog-${{ steps.release_info.outputs.VERSION }}'
|
||||
base: 'main'
|
||||
team-reviewers: 'gemini-cli-docs, gemini-cli-maintainers'
|
||||
delete-branch: true
|
||||
@@ -89,7 +89,8 @@ jobs:
|
||||
inputs: {
|
||||
commit: '${{ steps.pr_status.outputs.MERGE_COMMIT_SHA }}',
|
||||
channel: channel,
|
||||
original_pr: '${{ github.event.issue.number }}'
|
||||
original_pr: '${{ github.event.issue.number }}',
|
||||
environment: 'prod'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
name: 'Release: Patch (1) Create PR'
|
||||
|
||||
run-name: >-
|
||||
Release Patch (1) Create PR | S:${{ inputs.channel }} | C:${{ inputs.commit }} ${{ inputs.original_pr && format('| PR:#{0}', inputs.original_pr) || '' }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -28,10 +31,19 @@ on:
|
||||
description: 'The original PR number to comment back on.'
|
||||
required: false
|
||||
type: 'string'
|
||||
environment:
|
||||
description: 'Environment'
|
||||
required: false
|
||||
type: 'choice'
|
||||
options:
|
||||
- 'prod'
|
||||
- 'dev'
|
||||
default: 'prod'
|
||||
|
||||
jobs:
|
||||
create-patch:
|
||||
runs-on: 'ubuntu-latest'
|
||||
environment: "${{ github.event.inputs.environment || 'prod' }}"
|
||||
permissions:
|
||||
contents: 'write'
|
||||
pull-requests: 'write'
|
||||
@@ -49,32 +61,50 @@ jobs:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'configure .npmrc'
|
||||
uses: './.github/actions/setup-npmrc'
|
||||
with:
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
|
||||
- name: 'Install Script Dependencies'
|
||||
run: 'npm install yargs'
|
||||
run: 'npm ci'
|
||||
|
||||
- name: 'Configure Git User'
|
||||
env:
|
||||
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
REPOSITORY: '${{ github.repository }}'
|
||||
run: |-
|
||||
git config user.name "gemini-cli-robot"
|
||||
git config user.email "gemini-cli-robot@google.com"
|
||||
# Configure git to use GITHUB_TOKEN for remote operations (has actions:write for workflow files)
|
||||
git remote set-url origin "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git"
|
||||
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${REPOSITORY}.git"
|
||||
|
||||
- name: 'Create Patch'
|
||||
id: 'create_patch'
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
GH_TOKEN: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
CLI_PACKAGE_NAME: '${{ vars.CLI_PACKAGE_NAME }}'
|
||||
PATCH_COMMIT: '${{ github.event.inputs.commit }}'
|
||||
PATCH_CHANNEL: '${{ github.event.inputs.channel }}'
|
||||
ORIGINAL_PR: '${{ github.event.inputs.original_pr }}'
|
||||
DRY_RUN: '${{ github.event.inputs.dry_run }}'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
# Capture output and display it in logs using tee
|
||||
{
|
||||
node scripts/releasing/create-patch-pr.js --commit=${{ github.event.inputs.commit }} --channel=${{ github.event.inputs.channel }} --pullRequestNumber=${{ github.event.inputs.original_pr }} --dry-run=${{ github.event.inputs.dry_run }}
|
||||
echo "EXIT_CODE=$?" >> "$GITHUB_OUTPUT"
|
||||
node scripts/releasing/create-patch-pr.js \
|
||||
--cli-package-name="${CLI_PACKAGE_NAME}" \
|
||||
--commit="${PATCH_COMMIT}" \
|
||||
--channel="${PATCH_CHANNEL}" \
|
||||
--pullRequestNumber="${ORIGINAL_PR}" \
|
||||
--dry-run="${DRY_RUN}"
|
||||
} 2>&1 | tee >(
|
||||
echo "LOG_CONTENT<<EOF" >> "$GITHUB_ENV"
|
||||
cat >> "$GITHUB_ENV"
|
||||
echo "EOF" >> "$GITHUB_ENV"
|
||||
)
|
||||
echo "EXIT_CODE=${PIPESTATUS[0]}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: 'Comment on Original PR'
|
||||
if: 'always() && inputs.original_pr'
|
||||
@@ -87,14 +117,18 @@ jobs:
|
||||
REPOSITORY: '${{ github.repository }}'
|
||||
GITHUB_RUN_ID: '${{ github.run_id }}'
|
||||
LOG_CONTENT: '${{ env.LOG_CONTENT }}'
|
||||
TARGET_REF: '${{ github.event.inputs.ref }}'
|
||||
ENVIRONMENT: '${{ github.event.inputs.environment }}'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
git checkout '${{ github.event.inputs.ref }}'
|
||||
git checkout "${TARGET_REF}"
|
||||
node scripts/releasing/patch-create-comment.js
|
||||
|
||||
- name: 'Fail Workflow if Main Task Failed'
|
||||
if: 'always() && steps.create_patch.outputs.EXIT_CODE != 0'
|
||||
env:
|
||||
EXIT_CODE: '${{ steps.create_patch.outputs.EXIT_CODE }}'
|
||||
run: |
|
||||
echo "Patch creation failed with exit code: ${{ steps.create_patch.outputs.EXIT_CODE }}"
|
||||
echo "Patch creation failed with exit code: ${EXIT_CODE}"
|
||||
echo "Check the logs above and the comment posted to the original PR for details."
|
||||
exit 1
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
name: 'Release: Patch (2) Trigger'
|
||||
|
||||
run-name: >-
|
||||
Release Patch (2) Trigger |
|
||||
${{ github.event.pull_request.number && format('PR #{0}', github.event.pull_request.number) || 'Manual' }} |
|
||||
${{ github.event.pull_request.head.ref || github.event.inputs.ref }}
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
@@ -18,7 +23,7 @@ on:
|
||||
type: 'string'
|
||||
default: 'main'
|
||||
workflow_id:
|
||||
description: 'The workflow to trigger. Defaults to patch-release.yml'
|
||||
description: 'The workflow to trigger. Defaults to release-patch-3-release.yml'
|
||||
required: false
|
||||
type: 'string'
|
||||
default: 'release-patch-3-release.yml'
|
||||
@@ -37,11 +42,20 @@ on:
|
||||
required: false
|
||||
type: 'boolean'
|
||||
default: false
|
||||
environment:
|
||||
description: 'Environment'
|
||||
required: false
|
||||
type: 'choice'
|
||||
options:
|
||||
- 'prod'
|
||||
- 'dev'
|
||||
default: 'prod'
|
||||
|
||||
jobs:
|
||||
trigger-patch-release:
|
||||
if: "(github.event_name == 'pull_request' && github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'hotfix/')) || github.event_name == 'workflow_dispatch'"
|
||||
runs-on: 'ubuntu-latest'
|
||||
environment: "${{ github.event.inputs.environment || 'prod' }}"
|
||||
permissions:
|
||||
actions: 'write'
|
||||
contents: 'write'
|
||||
@@ -74,5 +88,7 @@ jobs:
|
||||
GITHUB_EVENT_PAYLOAD: '${{ toJSON(github.event) }}'
|
||||
FORCE_SKIP_TESTS: '${{ github.event.inputs.force_skip_tests }}'
|
||||
TEST_MODE: '${{ github.event.inputs.test_mode }}'
|
||||
ENVIRONMENT: "${{ github.event.inputs.environment || 'prod' }}"
|
||||
DRY_RUN: '${{ github.event.inputs.dry_run }}'
|
||||
run: |
|
||||
node scripts/releasing/patch-trigger.js --dry-run=${{ github.event.inputs.dry_run }}
|
||||
node scripts/releasing/patch-trigger.js --dry-run="${DRY_RUN}"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
name: 'Release: Patch (3) Release'
|
||||
|
||||
run-name: >-
|
||||
Release Patch (3) Release | T:${{ inputs.type }} | R:${{ inputs.release_ref }} ${{ inputs.original_pr && format('| PR:#{0}', inputs.original_pr) || '' }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -28,13 +31,23 @@ on:
|
||||
description: 'The original PR number to comment back on.'
|
||||
required: false
|
||||
type: 'string'
|
||||
environment:
|
||||
description: 'Environment'
|
||||
required: false
|
||||
type: 'choice'
|
||||
options:
|
||||
- 'prod'
|
||||
- 'dev'
|
||||
default: 'prod'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: 'ubuntu-latest'
|
||||
environment: "${{ github.event.inputs.environment || 'prod' }}"
|
||||
permissions:
|
||||
contents: 'write'
|
||||
packages: 'write'
|
||||
pull-requests: 'write'
|
||||
issues: 'write'
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
@@ -56,6 +69,15 @@ jobs:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'configure .npmrc'
|
||||
uses: './.github/actions/setup-npmrc'
|
||||
with:
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
|
||||
- name: 'Install Script Dependencies'
|
||||
run: |-
|
||||
npm ci
|
||||
|
||||
- name: 'Install Dependencies'
|
||||
working-directory: './release'
|
||||
run: |-
|
||||
@@ -63,17 +85,20 @@ jobs:
|
||||
|
||||
- name: 'Print Inputs'
|
||||
shell: 'bash'
|
||||
run: |-
|
||||
echo "${{ toJSON(inputs) }}"
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
|
||||
- name: 'Get Patch Version'
|
||||
id: 'patch_version'
|
||||
env:
|
||||
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
PATCH_FROM: '${{ github.event.inputs.type }}'
|
||||
CLI_PACKAGE_NAME: '${{vars.CLI_PACKAGE_NAME}}'
|
||||
run: |
|
||||
# Use the existing get-release-version.js script to calculate patch version
|
||||
# Run from main checkout which has full git history and access to npm
|
||||
PATCH_JSON=$(node scripts/get-release-version.js --type=patch --patch-from=${{ github.event.inputs.type }})
|
||||
PATCH_JSON=$(node scripts/get-release-version.js --type=patch --cli-package-name="${CLI_PACKAGE_NAME}" --patch-from="${PATCH_FROM}")
|
||||
echo "Patch version calculation result: ${PATCH_JSON}"
|
||||
|
||||
RELEASE_VERSION=$(echo "${PATCH_JSON}" | jq -r .releaseVersion)
|
||||
@@ -90,14 +115,13 @@ jobs:
|
||||
env:
|
||||
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
CHANNEL: '${{ github.event.inputs.type }}'
|
||||
ORIGINAL_RELEASE_VERSION: '${{ steps.patch_version.outputs.RELEASE_VERSION }}'
|
||||
ORIGINAL_RELEASE_TAG: '${{ steps.patch_version.outputs.RELEASE_TAG }}'
|
||||
ORIGINAL_PREVIOUS_TAG: '${{ steps.patch_version.outputs.PREVIOUS_TAG }}'
|
||||
run: |
|
||||
echo "🔍 Verifying no concurrent patch releases have occurred..."
|
||||
|
||||
# Store original calculation for comparison
|
||||
ORIGINAL_RELEASE_VERSION="${{ steps.patch_version.outputs.RELEASE_VERSION }}"
|
||||
ORIGINAL_RELEASE_TAG="${{ steps.patch_version.outputs.RELEASE_TAG }}"
|
||||
ORIGINAL_PREVIOUS_TAG="${{ steps.patch_version.outputs.PREVIOUS_TAG }}"
|
||||
|
||||
echo "Original calculation:"
|
||||
echo " Release version: ${ORIGINAL_RELEASE_VERSION}"
|
||||
echo " Release tag: ${ORIGINAL_RELEASE_TAG}"
|
||||
@@ -105,7 +129,7 @@ jobs:
|
||||
|
||||
# Re-run the same version calculation script
|
||||
echo "Re-calculating version to check for changes..."
|
||||
CURRENT_PATCH_JSON=$(node scripts/get-release-version.js --type=patch --patch-from="${CHANNEL}")
|
||||
CURRENT_PATCH_JSON=$(node scripts/get-release-version.js --cli-package-name="${{vars.CLI_PACKAGE_NAME}}" --type=patch --patch-from="${CHANNEL}")
|
||||
CURRENT_RELEASE_VERSION=$(echo "${CURRENT_PATCH_JSON}" | jq -r .releaseVersion)
|
||||
CURRENT_RELEASE_TAG=$(echo "${CURRENT_PATCH_JSON}" | jq -r .releaseTag)
|
||||
CURRENT_PREVIOUS_TAG=$(echo "${CURRENT_PATCH_JSON}" | jq -r .previousReleaseTag)
|
||||
@@ -158,11 +182,19 @@ jobs:
|
||||
npm-tag: '${{ steps.patch_version.outputs.NPM_TAG }}'
|
||||
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
|
||||
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
|
||||
wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
github-release-token: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
dry-run: '${{ github.event.inputs.dry_run }}'
|
||||
previous-tag: '${{ steps.patch_version.outputs.PREVIOUS_TAG }}'
|
||||
working-directory: './release'
|
||||
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
|
||||
npm-registry-publish-url: '${{ vars.NPM_REGISTRY_PUBLISH_URL }}'
|
||||
npm-registry-url: '${{ vars.NPM_REGISTRY_URL }}'
|
||||
npm-registry-scope: '${{ vars.NPM_REGISTRY_SCOPE }}'
|
||||
cli-package-name: '${{ vars.CLI_PACKAGE_NAME }}'
|
||||
core-package-name: '${{ vars.CORE_PACKAGE_NAME }}'
|
||||
a2a-package-name: '${{ vars.A2A_PACKAGE_NAME }}'
|
||||
working-directory: './release'
|
||||
|
||||
- name: 'Create Issue on Failure'
|
||||
if: '${{ failure() && github.event.inputs.dry_run == false }}'
|
||||
@@ -174,7 +206,7 @@ jobs:
|
||||
gh issue create \
|
||||
--title 'Patch Release Failed for ${RELEASE_TAG} on $(date +'%Y-%m-%d')' \
|
||||
--body 'The patch-release workflow failed. See the full run for details: ${DETAILS_URL}' \
|
||||
--label 'kind/bug,release-failure,priority/p0'
|
||||
--label 'release-failure,priority/p0'
|
||||
|
||||
- name: 'Comment Success on Original PR'
|
||||
if: '${{ success() && github.event.inputs.original_pr }}'
|
||||
|
||||
@@ -26,11 +26,21 @@ on:
|
||||
description: 'Manually override the preview version number.'
|
||||
required: false
|
||||
type: 'string'
|
||||
environment:
|
||||
description: 'Environment'
|
||||
required: false
|
||||
type: 'choice'
|
||||
options:
|
||||
- 'prod'
|
||||
- 'dev'
|
||||
default: 'prod'
|
||||
|
||||
jobs:
|
||||
calculate-versions:
|
||||
name: 'Calculate Versions and Plan'
|
||||
runs-on: 'ubuntu-latest'
|
||||
environment: "${{ github.event.inputs.environment || 'prod' }}"
|
||||
|
||||
outputs:
|
||||
STABLE_VERSION: '${{ steps.versions.outputs.STABLE_VERSION }}'
|
||||
STABLE_SHA: '${{ steps.versions.outputs.STABLE_SHA }}'
|
||||
@@ -59,19 +69,32 @@ jobs:
|
||||
|
||||
- name: 'Print Inputs'
|
||||
shell: 'bash'
|
||||
run: |-
|
||||
echo "${{ toJSON(inputs) }}"
|
||||
env:
|
||||
JSON_INPUTS: '${{ toJSON(inputs) }}'
|
||||
run: 'echo "$JSON_INPUTS"'
|
||||
|
||||
- name: 'Calculate Versions and SHAs'
|
||||
id: 'versions'
|
||||
env:
|
||||
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
STABLE_OVERRIDE: '${{ github.event.inputs.stable_version_override }}'
|
||||
PREVIEW_OVERRIDE: '${{ github.event.inputs.preview_version_override }}'
|
||||
REF_INPUT: '${{ github.event.inputs.ref }}'
|
||||
run: |
|
||||
set -e
|
||||
STABLE_COMMAND="node scripts/get-release-version.js --type=stable ${{ github.event.inputs.stable_version_override && format('--stable_version_override={0}', github.event.inputs.stable_version_override) || '' }}"
|
||||
PREVIEW_COMMAND="node scripts/get-release-version.js --type=preview ${{ github.event.inputs.preview_version_override && format('--preview_version_override={0}', github.event.inputs.preview_version_override) || '' }}"
|
||||
STABLE_COMMAND="node scripts/get-release-version.js --type=stable"
|
||||
if [[ -n "${STABLE_OVERRIDE}" ]]; then
|
||||
STABLE_COMMAND+=" --stable_version_override=${STABLE_OVERRIDE}"
|
||||
fi
|
||||
PREVIEW_COMMAND="node scripts/get-release-version.js --type=preview"
|
||||
if [[ -n "${PREVIEW_OVERRIDE}" ]]; then
|
||||
PREVIEW_COMMAND+=" --preview_version_override=${PREVIEW_OVERRIDE}"
|
||||
fi
|
||||
NIGHTLY_COMMAND="node scripts/get-release-version.js --type=promote-nightly"
|
||||
STABLE_JSON=$(${STABLE_COMMAND})
|
||||
STABLE_VERSION=$(echo "${STABLE_JSON}" | jq -r .releaseVersion)
|
||||
PREVIEW_COMMAND+=" --stable-base-version=${STABLE_VERSION}"
|
||||
NIGHTLY_COMMAND+=" --stable-base-version=${STABLE_VERSION}"
|
||||
PREVIEW_JSON=$(${PREVIEW_COMMAND})
|
||||
NIGHTLY_JSON=$(${NIGHTLY_COMMAND})
|
||||
echo "STABLE_JSON_COMMAND=${STABLE_COMMAND}"
|
||||
@@ -80,14 +103,14 @@ jobs:
|
||||
echo "STABLE_JSON: ${STABLE_JSON}"
|
||||
echo "PREVIEW_JSON: ${PREVIEW_JSON}"
|
||||
echo "NIGHTLY_JSON: ${NIGHTLY_JSON}"
|
||||
echo "STABLE_VERSION=$(echo "${STABLE_JSON}" | jq -r .releaseVersion)" >> "${GITHUB_OUTPUT}"
|
||||
echo "STABLE_VERSION=${STABLE_VERSION}" >> "${GITHUB_OUTPUT}"
|
||||
# shellcheck disable=SC1083
|
||||
echo "STABLE_SHA=$(git rev-parse "$(echo "${PREVIEW_JSON}" | jq -r .previousReleaseTag)"^{commit})" >> "${GITHUB_OUTPUT}"
|
||||
echo "PREVIOUS_STABLE_TAG=$(echo "${STABLE_JSON}" | jq -r .previousReleaseTag)" >> "${GITHUB_OUTPUT}"
|
||||
echo "PREVIEW_VERSION=$(echo "${PREVIEW_JSON}" | jq -r .releaseVersion)" >> "${GITHUB_OUTPUT}"
|
||||
# shellcheck disable=SC1083
|
||||
REF="${{ github.event.inputs.ref }}"
|
||||
SHA=$(git ls-remote origin "$REF" | awk '{print $1}')
|
||||
REF="${REF_INPUT}"
|
||||
SHA=$(git ls-remote origin "$REF" | awk -v ref="$REF" '$2 == "refs/heads/"ref || $2 == "refs/tags/"ref || $2 == ref {print $1}' | head -n 1)
|
||||
if [ -z "$SHA" ]; then
|
||||
if [[ "$REF" =~ ^[0-9a-f]{7,40}$ ]]; then
|
||||
SHA="$REF"
|
||||
@@ -105,20 +128,30 @@ jobs:
|
||||
echo "NEXT_SHA=$SHA" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: 'Display Pending Updates'
|
||||
env:
|
||||
STABLE_VERSION: '${{ steps.versions.outputs.STABLE_VERSION }}'
|
||||
STABLE_SHA: '${{ steps.versions.outputs.STABLE_SHA }}'
|
||||
PREVIOUS_STABLE_TAG: '${{ steps.versions.outputs.PREVIOUS_STABLE_TAG }}'
|
||||
PREVIEW_VERSION: '${{ steps.versions.outputs.PREVIEW_VERSION }}'
|
||||
PREVIEW_SHA: '${{ steps.versions.outputs.PREVIEW_SHA }}'
|
||||
PREVIOUS_PREVIEW_TAG: '${{ steps.versions.outputs.PREVIOUS_PREVIEW_TAG }}'
|
||||
NEXT_NIGHTLY_VERSION: '${{ steps.versions.outputs.NEXT_NIGHTLY_VERSION }}'
|
||||
PREVIOUS_NIGHTLY_TAG: '${{ steps.versions.outputs.PREVIOUS_NIGHTLY_TAG }}'
|
||||
INPUT_REF: '${{ github.event.inputs.ref }}'
|
||||
run: |
|
||||
echo "Release Plan:"
|
||||
echo "-----------"
|
||||
echo "Stable Release: ${{ steps.versions.outputs.STABLE_VERSION }}"
|
||||
echo " - Commit: ${{ steps.versions.outputs.STABLE_SHA }}"
|
||||
echo " - Previous Tag: ${{ steps.versions.outputs.PREVIOUS_STABLE_TAG }}"
|
||||
echo "Stable Release: ${STABLE_VERSION}"
|
||||
echo " - Commit: ${STABLE_SHA}"
|
||||
echo " - Previous Tag: ${PREVIOUS_STABLE_TAG}"
|
||||
echo ""
|
||||
echo "Preview Release: ${{ steps.versions.outputs.PREVIEW_VERSION }}"
|
||||
echo " - Commit: ${{ steps.versions.outputs.PREVIEW_SHA }} (${{ github.event.inputs.ref }})"
|
||||
echo " - Previous Tag: ${{ steps.versions.outputs.PREVIOUS_PREVIEW_TAG }}"
|
||||
echo "Preview Release: ${PREVIEW_VERSION}"
|
||||
echo " - Commit: ${PREVIEW_SHA} (${INPUT_REF})"
|
||||
echo " - Previous Tag: ${PREVIOUS_PREVIEW_TAG}"
|
||||
echo ""
|
||||
echo "Next Nightly Release: ${{ steps.versions.outputs.NEXT_NIGHTLY_VERSION }}"
|
||||
echo " - Commit: ${{ steps.versions.outputs.NEXT_SHA }} (${{ github.event.inputs.ref }})"
|
||||
echo " - Previous Tag: ${{ steps.versions.outputs.PREVIOUS_NIGHTLY_TAG }}"
|
||||
echo "Preparing Next Nightly Release: ${NEXT_NIGHTLY_VERSION}"
|
||||
echo " - Merging Version Update PR to Branch: ${INPUT_REF}"
|
||||
echo " - Previous Tag: ${PREVIOUS_NIGHTLY_TAG}"
|
||||
|
||||
test:
|
||||
name: 'Test ${{ matrix.channel }}'
|
||||
@@ -168,6 +201,7 @@ jobs:
|
||||
name: 'Publish preview'
|
||||
needs: ['calculate-versions', 'test']
|
||||
runs-on: 'ubuntu-latest'
|
||||
environment: "${{ github.event.inputs.environment || 'prod' }}"
|
||||
permissions:
|
||||
contents: 'write'
|
||||
packages: 'write'
|
||||
@@ -203,12 +237,20 @@ jobs:
|
||||
npm-tag: 'preview'
|
||||
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
|
||||
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
|
||||
wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
github-release-token: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
dry-run: '${{ github.event.inputs.dry_run }}'
|
||||
previous-tag: '${{ needs.calculate-versions.outputs.PREVIOUS_PREVIEW_TAG }}'
|
||||
working-directory: './release'
|
||||
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
|
||||
force-skip-tests: '${{ github.event.inputs.force_skip_tests }}'
|
||||
npm-registry-publish-url: '${{ vars.NPM_REGISTRY_PUBLISH_URL }}'
|
||||
npm-registry-url: '${{ vars.NPM_REGISTRY_URL }}'
|
||||
npm-registry-scope: '${{ vars.NPM_REGISTRY_SCOPE }}'
|
||||
cli-package-name: '${{ vars.CLI_PACKAGE_NAME }}'
|
||||
core-package-name: '${{ vars.CORE_PACKAGE_NAME }}'
|
||||
a2a-package-name: '${{ vars.A2A_PACKAGE_NAME }}'
|
||||
|
||||
- name: 'Create Issue on Failure'
|
||||
if: '${{ failure() && github.event.inputs.dry_run == false }}'
|
||||
@@ -220,12 +262,13 @@ jobs:
|
||||
gh issue create \
|
||||
--title 'Promote Release Failed for ${RELEASE_TAG} on $(date +'%Y-%m-%d')' \
|
||||
--body 'The promote-release workflow failed during preview publish. See the full run for details: ${DETAILS_URL}' \
|
||||
--label 'kind/bug,release-failure,priority/p0'
|
||||
--label 'release-failure,priority/p0'
|
||||
|
||||
publish-stable:
|
||||
name: 'Publish stable'
|
||||
needs: ['calculate-versions', 'test', 'publish-preview']
|
||||
runs-on: 'ubuntu-latest'
|
||||
environment: "${{ github.event.inputs.environment || 'prod' }}"
|
||||
permissions:
|
||||
contents: 'write'
|
||||
packages: 'write'
|
||||
@@ -261,12 +304,20 @@ jobs:
|
||||
npm-tag: 'latest'
|
||||
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
|
||||
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
|
||||
wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
github-release-token: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
dry-run: '${{ github.event.inputs.dry_run }}'
|
||||
previous-tag: '${{ needs.calculate-versions.outputs.PREVIOUS_STABLE_TAG }}'
|
||||
working-directory: './release'
|
||||
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
|
||||
force-skip-tests: '${{ github.event.inputs.force_skip_tests }}'
|
||||
npm-registry-publish-url: '${{ vars.NPM_REGISTRY_PUBLISH_URL }}'
|
||||
npm-registry-url: '${{ vars.NPM_REGISTRY_URL }}'
|
||||
npm-registry-scope: '${{ vars.NPM_REGISTRY_SCOPE }}'
|
||||
cli-package-name: '${{ vars.CLI_PACKAGE_NAME }}'
|
||||
core-package-name: '${{ vars.CORE_PACKAGE_NAME }}'
|
||||
a2a-package-name: '${{ vars.A2A_PACKAGE_NAME }}'
|
||||
|
||||
- name: 'Create Issue on Failure'
|
||||
if: '${{ failure() && github.event.inputs.dry_run == false }}'
|
||||
@@ -278,7 +329,7 @@ jobs:
|
||||
gh issue create \
|
||||
--title 'Promote Release Failed for ${RELEASE_TAG} on $(date +'%Y-%m-%d')' \
|
||||
--body 'The promote-release workflow failed during stable publish. See the full run for details: ${DETAILS_URL}' \
|
||||
--label 'kind/bug,release-failure,priority/p0'
|
||||
--label 'release-failure,priority/p0'
|
||||
|
||||
nightly-pr:
|
||||
name: 'Create Nightly PR'
|
||||
@@ -341,7 +392,7 @@ jobs:
|
||||
branch-name: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
|
||||
pr-title: 'chore(release): bump version to ${{ needs.calculate-versions.outputs.NEXT_NIGHTLY_VERSION }}'
|
||||
pr-body: 'Automated version bump to prepare for the next nightly release.'
|
||||
github-token: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
dry-run: '${{ github.event.inputs.dry_run }}'
|
||||
|
||||
- name: 'Create Issue on Failure'
|
||||
@@ -354,4 +405,4 @@ jobs:
|
||||
gh issue create \
|
||||
--title 'Promote Release Failed for ${RELEASE_TAG} on $(date +'%Y-%m-%d')' \
|
||||
--body 'The promote-release workflow failed during nightly PR creation. See the full run for details: ${DETAILS_URL}' \
|
||||
--label 'kind/bug,release-failure,priority/p0'
|
||||
--label 'release-failure,priority/p0'
|
||||
|
||||
@@ -31,9 +31,18 @@ on:
|
||||
required: false
|
||||
type: 'boolean'
|
||||
default: true
|
||||
environment:
|
||||
description: 'Environment'
|
||||
required: false
|
||||
type: 'choice'
|
||||
options:
|
||||
- 'prod'
|
||||
- 'dev'
|
||||
default: 'prod'
|
||||
|
||||
jobs:
|
||||
change-tags:
|
||||
environment: "${{ github.event.inputs.environment || 'prod' }}"
|
||||
runs-on: 'ubuntu-latest'
|
||||
permissions:
|
||||
packages: 'write'
|
||||
@@ -49,23 +58,29 @@ jobs:
|
||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
registry-url: 'https://wombat-dressing-room.appspot.com'
|
||||
scope: '@google'
|
||||
|
||||
- name: 'configure .npmrc'
|
||||
uses: './.github/actions/setup-npmrc'
|
||||
with:
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
|
||||
- name: 'Get Origin Version Tag'
|
||||
id: 'origin_tag'
|
||||
shell: 'bash'
|
||||
env:
|
||||
ROLLBACK_ORIGIN: '${{ github.event.inputs.rollback_origin }}'
|
||||
run: |
|
||||
TAG_VALUE="v${{ github.event.inputs.rollback_origin }}"
|
||||
TAG_VALUE="v${ROLLBACK_ORIGIN}"
|
||||
echo "ORIGIN_TAG=$TAG_VALUE" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: 'Get Origin Commit Hash'
|
||||
id: 'origin_hash'
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
ORIGIN_TAG: '${{ steps.origin_tag.outputs.ORIGIN_TAG }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
echo "ORIGIN_HASH=$(git rev-parse ${{ steps.origin_tag.outputs.ORIGIN_TAG }})" >> "$GITHUB_OUTPUT"
|
||||
echo "ORIGIN_HASH=$(git rev-parse "${ORIGIN_TAG}")" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: 'Change tag'
|
||||
if: "${{ github.event.inputs.rollback_destination != '' }}"
|
||||
@@ -76,41 +91,91 @@ jobs:
|
||||
dry-run: '${{ github.event.inputs.dry-run }}'
|
||||
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
|
||||
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
|
||||
wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
cli-package-name: '${{ vars.CLI_PACKAGE_NAME }}'
|
||||
core-package-name: '${{ vars.CORE_PACKAGE_NAME }}'
|
||||
a2a-package-name: '${{ vars.A2A_PACKAGE_NAME }}'
|
||||
|
||||
- name: 'Get cli Token'
|
||||
uses: './.github/actions/npm-auth-token'
|
||||
id: 'cli-token'
|
||||
with:
|
||||
package-name: '${{ vars.CLI_PACKAGE_NAME }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
|
||||
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
|
||||
wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'
|
||||
|
||||
- name: 'Deprecate Cli Npm Package'
|
||||
if: "${{ github.event.inputs.dry-run == 'false' }}"
|
||||
if: "${{ github.event.inputs.dry-run == 'false' && github.event.inputs.environment == 'prod' }}"
|
||||
env:
|
||||
NODE_AUTH_TOKEN: '${{ secrets.WOMBAT_TOKEN_CLI }}'
|
||||
NODE_AUTH_TOKEN: '${{ steps.cli-token.outputs.auth-token }}'
|
||||
PACKAGE_NAME: '${{ vars.CLI_PACKAGE_NAME }}'
|
||||
ROLLBACK_ORIGIN: '${{ github.event.inputs.rollback_origin }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
npm deprecate @google/gemini-cli@${{ github.event.inputs.rollback_origin }} "This version has been rolled back."
|
||||
npm deprecate "${PACKAGE_NAME}@${ROLLBACK_ORIGIN}" "This version has been rolled back."
|
||||
|
||||
- name: 'Get core Token'
|
||||
uses: './.github/actions/npm-auth-token'
|
||||
id: 'core-token'
|
||||
with:
|
||||
package-name: '${{ vars.CLI_PACKAGE_NAME }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
|
||||
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
|
||||
wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'
|
||||
|
||||
- name: 'Deprecate Core Npm Package'
|
||||
if: "${{ github.event.inputs.dry-run == 'false' }}"
|
||||
if: "${{ github.event.inputs.dry-run == 'false' && github.event.inputs.environment == 'prod' }}"
|
||||
env:
|
||||
NODE_AUTH_TOKEN: '${{ secrets.WOMBAT_TOKEN_CORE }}'
|
||||
NODE_AUTH_TOKEN: '${{ steps.core-token.outputs.auth-token }}'
|
||||
PACKAGE_NAME: '${{ vars.CORE_PACKAGE_NAME }}'
|
||||
ROLLBACK_ORIGIN: '${{ github.event.inputs.rollback_origin }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
npm deprecate @google/gemini-core@${{ github.event.inputs.rollback_origin }} "This version has been rolled back."
|
||||
npm deprecate "${PACKAGE_NAME}@${ROLLBACK_ORIGIN}" "This version has been rolled back."
|
||||
|
||||
- name: 'Get a2a Token'
|
||||
uses: './.github/actions/npm-auth-token'
|
||||
id: 'a2a-token'
|
||||
with:
|
||||
package-name: '${{ vars.A2A_PACKAGE_NAME }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
|
||||
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
|
||||
wombat-token-a2a-server: '${{ secrets.WOMBAT_TOKEN_A2A_SERVER }}'
|
||||
|
||||
- name: 'Deprecate A2A Server Npm Package'
|
||||
if: "${{ github.event.inputs.dry-run == 'false' && github.event.inputs.environment == 'prod' }}"
|
||||
env:
|
||||
NODE_AUTH_TOKEN: '${{ steps.a2a-token.outputs.auth-token }}'
|
||||
PACKAGE_NAME: '${{ vars.A2A_PACKAGE_NAME }}'
|
||||
ROLLBACK_ORIGIN: '${{ github.event.inputs.rollback_origin }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
npm deprecate "${PACKAGE_NAME}@${ROLLBACK_ORIGIN}" "This version has been rolled back."
|
||||
|
||||
- name: 'Delete Github Release'
|
||||
if: "${{ github.event.inputs.dry-run == 'false' }}"
|
||||
if: "${{ github.event.inputs.dry-run == 'false' && github.event.inputs.environment == 'prod'}}"
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
ORIGIN_TAG: '${{ steps.origin_tag.outputs.ORIGIN_TAG }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
gh release delete '${{ steps.origin_tag.outputs.ORIGIN_TAG }}' --yes
|
||||
gh release delete "${ORIGIN_TAG}" --yes
|
||||
|
||||
- name: 'Verify Origin Release Deletion'
|
||||
if: "${{ github.event.inputs.dry-run == 'false' }}"
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
TARGET_TAG: '${{ steps.origin_tag.outputs.ORIGIN_TAG }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
TARGET_TAG="${{ steps.origin_tag.outputs.ORIGIN_TAG }}"
|
||||
RELEASE_TAG=$(gh release view "$TARGET_TAG" --json tagName --jq .tagName)
|
||||
if [ "$RELEASE_TAG" = "$TARGET_TAG" ]; then
|
||||
echo '❌ Failed to delete release with tag ${{ steps.origin_tag.outputs.ORIGIN_TAG }}'
|
||||
echo "❌ Failed to delete release with tag ${TARGET_TAG}"
|
||||
echo '❌ This means the release was not deleted, and the workflow should fail.'
|
||||
exit 1
|
||||
fi
|
||||
@@ -120,21 +185,22 @@ jobs:
|
||||
if: "${{ github.event.inputs.dry-run == 'false' }}"
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
ROLLBACK_TAG_NAME: '${{ steps.origin_tag.outputs.ORIGIN_TAG }}-rollback'
|
||||
ORIGIN_HASH: '${{ steps.origin_hash.outputs.ORIGIN_HASH }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
ROLLBACK_TAG_NAME="${{ steps.origin_tag.outputs.ORIGIN_TAG }}-rollback"
|
||||
echo "ROLLBACK_TAG=$ROLLBACK_TAG_NAME" >> "$GITHUB_OUTPUT"
|
||||
git tag "$ROLLBACK_TAG_NAME" "${{ steps.origin_hash.outputs.ORIGIN_HASH }}"
|
||||
git tag "$ROLLBACK_TAG_NAME" "${ORIGIN_HASH}"
|
||||
git push origin --tags
|
||||
|
||||
- name: 'Verify Rollback Tag Added'
|
||||
if: "${{ github.event.inputs.dry-run == 'false' }}"
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
TARGET_TAG: '${{ steps.rollback_tag.outputs.ROLLBACK_TAG }}'
|
||||
TARGET_HASH: '${{ steps.origin_hash.outputs.ORIGIN_HASH }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
TARGET_TAG="${{ steps.rollback_tag.outputs.ROLLBACK_TAG }}"
|
||||
TARGET_HASH="${{ steps.origin_hash.outputs.ORIGIN_HASH }}"
|
||||
ROLLBACK_COMMIT=$(git rev-parse -q --verify "$TARGET_TAG")
|
||||
if [ "$ROLLBACK_COMMIT" != "$TARGET_HASH" ]; then
|
||||
echo '❌ Failed to add tag $TARGET_TAG to commit $TARGET_HASH'
|
||||
@@ -144,21 +210,32 @@ jobs:
|
||||
|
||||
- name: 'Log Dry run'
|
||||
if: "${{ github.event.inputs.dry-run == 'true' }}"
|
||||
env:
|
||||
ROLLBACK_ORIGIN: '${{ github.event.inputs.rollback_origin }}'
|
||||
ROLLBACK_DESTINATION: '${{ github.event.inputs.rollback_destination }}'
|
||||
CHANNEL: '${{ github.event.inputs.channel }}'
|
||||
REF_INPUT: '${{ github.event.inputs.ref }}'
|
||||
ORIGIN_TAG: '${{ steps.origin_tag.outputs.ORIGIN_TAG }}'
|
||||
ORIGIN_HASH: '${{ steps.origin_hash.outputs.ORIGIN_HASH }}'
|
||||
ROLLBACK_TAG: '${{ steps.rollback_tag.outputs.ROLLBACK_TAG }}'
|
||||
CLI_PACKAGE_NAME: '${{ vars.CLI_PACKAGE_NAME }}'
|
||||
CORE_PACKAGE_NAME: '${{ vars.CORE_PACKAGE_NAME }}'
|
||||
A2A_PACKAGE_NAME: '${{ vars.A2A_PACKAGE_NAME }}'
|
||||
shell: 'bash'
|
||||
run: |
|
||||
echo "
|
||||
Inputs:
|
||||
- rollback_origin: '${{ github.event.inputs.rollback_origin }}'
|
||||
- rollback_destination: '${{ github.event.inputs.rollback_destination }}'
|
||||
- channel: '${{ github.event.inputs.channel }}'
|
||||
- ref: '${{ github.event.inputs.ref }}'
|
||||
- rollback_origin: '${ROLLBACK_ORIGIN}'
|
||||
- rollback_destination: '${ROLLBACK_DESTINATION}'
|
||||
- channel: '${CHANNEL}'
|
||||
- ref: '${REF_INPUT}'
|
||||
|
||||
Outputs:
|
||||
- ORIGIN_TAG: '${{ steps.origin_tag.outputs.ORIGIN_TAG }}'
|
||||
- ORIGIN_HASH: '${{ steps.origin_hash.outputs.ORIGIN_HASH }}'
|
||||
- ROLLBACK_TAG: '${{ steps.rollback_tag.outputs.ROLLBACK_TAG }}'
|
||||
- ORIGIN_TAG: '${ORIGIN_TAG}'
|
||||
- ORIGIN_HASH: '${ORIGIN_HASH}'
|
||||
- ROLLBACK_TAG: '${ROLLBACK_TAG}'
|
||||
|
||||
Would have npm deprecate @google/gemini-cli@${{ github.event.inputs.rollback_origin }} and @google/gemini-core@${{ github.event.inputs.rollback_origin }}
|
||||
Would have deleted the github release with tag ${{ steps.origin_tag.outputs.ORIGIN_TAG }}
|
||||
Would have added tag ${{ steps.origin_tag.outputs.ORIGIN_TAG }}-rollback to ${{ steps.origin_hash.outputs.ORIGIN_HASH }}
|
||||
Would have npm deprecate ${CLI_PACKAGE_NAME}@${ROLLBACK_ORIGIN}, ${CORE_PACKAGE_NAME}@${ROLLBACK_ORIGIN}, and ${A2A_PACKAGE_NAME}@${ROLLBACK_ORIGIN}
|
||||
Would have deleted the github release with tag ${ORIGIN_TAG}
|
||||
Would have added tag ${ORIGIN_TAG}-rollback to ${ORIGIN_HASH}
|
||||
"
|
||||
|
||||
@@ -46,4 +46,4 @@ jobs:
|
||||
gh issue create \
|
||||
--title 'Sandbox Release Failed on $(date +'%Y-%m-%d')' \
|
||||
--body 'The sandbox-release workflow failed. See the full run for details: ${DETAILS_URL}' \
|
||||
--label 'kind/bug,release-failure,priority/p0'
|
||||
--label 'release-failure,priority/p0'
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
name: 'On Merge Smoke Test'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'release/**'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ref:
|
||||
description: 'The branch, tag, or SHA to test on.'
|
||||
required: false
|
||||
type: 'string'
|
||||
default: 'main'
|
||||
dry-run:
|
||||
description: 'Run a dry-run of the smoke test; No bug will be created'
|
||||
required: true
|
||||
type: 'boolean'
|
||||
default: true
|
||||
|
||||
jobs:
|
||||
smoke-test:
|
||||
runs-on: 'ubuntu-latest'
|
||||
permissions:
|
||||
contents: 'write'
|
||||
packages: 'write'
|
||||
issues: 'write'
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
|
||||
with:
|
||||
ref: '${{ github.event.inputs.ref || github.sha }}'
|
||||
fetch-depth: 0
|
||||
- name: 'Install Dependencies'
|
||||
run: 'npm ci'
|
||||
- name: 'Build bundle'
|
||||
run: 'npm run bundle'
|
||||
- name: 'Smoke test bundle'
|
||||
run: 'node ./bundle/gemini.js --version'
|
||||
- name: 'Create Issue on Failure'
|
||||
if: '${{ failure() && github.event.inputs.dry-run == false }}'
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
DETAILS_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||
REF: '${{ github.event.inputs.ref }}'
|
||||
run: |
|
||||
gh issue create \
|
||||
--title 'Smoke test failed on ${REF} @ $(date +'%Y-%m-%d')' \
|
||||
--body 'Smoke test build failed. See the full run for details: ${DETAILS_URL}' \
|
||||
--label 'priority/p0'
|
||||
@@ -13,7 +13,6 @@ jobs:
|
||||
matrix:
|
||||
runner:
|
||||
- 'ubuntu-latest' # GitHub-hosted
|
||||
- 'self-hosted' # GHA on GCP runners
|
||||
runs-on: '${{ matrix.runner }}'
|
||||
if: |-
|
||||
${{ github.repository == 'google-gemini/gemini-cli' }}
|
||||
@@ -41,5 +40,5 @@ jobs:
|
||||
If this is still relevant, you are welcome to reopen or leave a comment. Thanks for contributing!
|
||||
days-before-stale: 60
|
||||
days-before-close: 14
|
||||
exempt-issue-labels: 'pinned,security'
|
||||
exempt-pr-labels: 'pinned,security'
|
||||
exempt-issue-labels: 'pinned,security,🔒 maintainer only,help wanted,🗓️ Public Roadmap'
|
||||
exempt-pr-labels: 'pinned,security,🔒 maintainer only,help wanted,🗓️ Public Roadmap'
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
name: 'Trigger E2E'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
repo_name:
|
||||
description: 'Repository name (e.g., owner/repo)'
|
||||
required: false
|
||||
type: 'string'
|
||||
head_sha:
|
||||
description: 'SHA of the commit to test'
|
||||
required: false
|
||||
type: 'string'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
save_repo_name:
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
steps:
|
||||
- name: 'Save Repo name'
|
||||
env:
|
||||
REPO_NAME: '${{ github.event.inputs.repo_name || github.event.pull_request.head.repo.full_name }}'
|
||||
HEAD_SHA: '${{ github.event.inputs.head_sha || github.event.pull_request.head.sha }}'
|
||||
run: |
|
||||
mkdir -p ./pr
|
||||
echo '${{ env.REPO_NAME }}' > ./pr/repo_name
|
||||
echo '${{ env.HEAD_SHA }}' > ./pr/head_sha
|
||||
- uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'repo_name'
|
||||
path: 'pr/'
|
||||
trigger_e2e:
|
||||
name: 'Trigger e2e'
|
||||
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||
steps:
|
||||
- id: 'trigger-e2e'
|
||||
run: |
|
||||
echo "Trigger e2e workflow"
|
||||
@@ -7,26 +7,49 @@ on:
|
||||
description: 'The expected Gemini binary version that should be released (e.g., 0.5.0-preview-2).'
|
||||
required: true
|
||||
type: 'string'
|
||||
npm-package:
|
||||
description: 'NPM package to verify'
|
||||
npm-tag:
|
||||
description: 'NPM tag to verify'
|
||||
required: true
|
||||
type: 'string'
|
||||
default: '@google/gemini-cli@latest'
|
||||
ref:
|
||||
description: 'The branch, tag, or SHA to release from.'
|
||||
type: 'choice'
|
||||
options:
|
||||
- 'dev'
|
||||
- 'latest'
|
||||
- 'preview'
|
||||
- 'nightly'
|
||||
default: 'latest'
|
||||
environment:
|
||||
description: 'Environment'
|
||||
required: false
|
||||
type: 'string'
|
||||
default: 'main'
|
||||
type: 'choice'
|
||||
options:
|
||||
- 'prod'
|
||||
- 'dev'
|
||||
default: 'prod'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: 'ubuntu-latest'
|
||||
verify-release:
|
||||
environment: "${{ github.event.inputs.environment || 'prod' }}"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: ['ubuntu-latest', 'macos-latest', 'windows-latest']
|
||||
runs-on: '${{ matrix.os }}'
|
||||
permissions:
|
||||
contents: 'read'
|
||||
packages: 'write'
|
||||
issues: 'write'
|
||||
steps:
|
||||
- name: '📝 Print vars'
|
||||
shell: 'bash'
|
||||
run: 'echo "${{ toJSON(vars) }}"'
|
||||
- uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
|
||||
- name: 'Verify release'
|
||||
uses: './.github/actions/verify-release'
|
||||
with:
|
||||
npm-package: '${{github.event.inputs.npm-package}}'
|
||||
npm-package: '${{vars.CLI_PACKAGE_NAME}}@${{github.event.inputs.npm-tag}}'
|
||||
expected-version: '${{github.event.inputs.version}}'
|
||||
ref: '${{github.event.inputs.ref}}'
|
||||
working-directory: '.'
|
||||
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
|
||||
npm-registry-url: '${{ vars.NPM_REGISTRY_URL }}'
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
npm-registry-scope: '${{ vars.NPM_REGISTRY_SCOPE }}'
|
||||
|
||||
+10
-1
@@ -11,13 +11,14 @@
|
||||
.gemini/*
|
||||
!.gemini/config.yaml
|
||||
!.gemini/commands/
|
||||
!.gemini/skills/
|
||||
!.gemini/settings.json
|
||||
|
||||
# Note: .gemini-clipboard/ is NOT in gitignore so Gemini can access pasted images
|
||||
|
||||
# Dependency directory
|
||||
node_modules
|
||||
bower_components
|
||||
package-lock.json
|
||||
|
||||
# Editors
|
||||
.idea
|
||||
@@ -45,11 +46,19 @@ packages/*/coverage/
|
||||
# Generated files
|
||||
packages/cli/src/generated/
|
||||
packages/core/src/generated/
|
||||
packages/devtools/src/_client-assets.ts
|
||||
.integration-tests/
|
||||
packages/vscode-ide-companion/*.vsix
|
||||
packages/cli/download-ripgrep*/
|
||||
|
||||
# GHA credentials
|
||||
gha-creds-*.json
|
||||
|
||||
# Log files
|
||||
patch_output.log
|
||||
gemini-debug.log
|
||||
|
||||
.genkit
|
||||
.gemini-clipboard/
|
||||
.eslintcache
|
||||
evals/logs/
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
http://localhost:16686/
|
||||
https://github.com/google-gemini/gemini-cli/issues/new/choose
|
||||
https://github.com/google-gemini/maintainers-gemini-cli/blob/main/npm.md
|
||||
https://github.com/settings/personal-access-tokens/new
|
||||
https://github.com/settings/tokens/new
|
||||
https://www.npmjs.com/package/@google/gemini-cli
|
||||
@@ -17,4 +17,8 @@ eslint.config.js
|
||||
**/generated
|
||||
gha-creds-*.json
|
||||
junit.xml
|
||||
.gemini-linters/
|
||||
Thumbs.db
|
||||
.pytest_cache
|
||||
**/SKILL.md
|
||||
packages/sdk/test-data/*.json
|
||||
|
||||
+11
-1
@@ -3,5 +3,15 @@
|
||||
"trailingComma": "all",
|
||||
"singleQuote": true,
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2
|
||||
"tabWidth": 2,
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.md"],
|
||||
"options": {
|
||||
"tabWidth": 2,
|
||||
"printWidth": 80,
|
||||
"proseWrap": "always"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+3
@@ -13,5 +13,8 @@
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[markdown]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"vitest.disableWorkspaceWarning": true
|
||||
}
|
||||
|
||||
+329
-84
@@ -1,6 +1,18 @@
|
||||
# How to Contribute
|
||||
# How to contribute
|
||||
|
||||
We would love to accept your patches and contributions to this project.
|
||||
We would love to accept your patches and contributions to this project. This
|
||||
document includes:
|
||||
|
||||
- **[Before you begin](#before-you-begin):** Essential steps to take before
|
||||
becoming a Gemini CLI contributor.
|
||||
- **[Code contribution process](#code-contribution-process):** How to contribute
|
||||
code to Gemini CLI.
|
||||
- **[Development setup and workflow](#development-setup-and-workflow):** How to
|
||||
set up your development environment and workflow.
|
||||
- **[Documentation contribution process](#documentation-contribution-process):**
|
||||
How to contribute documentation to Gemini CLI.
|
||||
|
||||
We're looking forward to seeing your contributions!
|
||||
|
||||
## Before you begin
|
||||
|
||||
@@ -20,88 +32,156 @@ sign a new one.
|
||||
|
||||
### Review our Community Guidelines
|
||||
|
||||
This project follows [Google's Open Source Community
|
||||
Guidelines](https://opensource.google/conduct/).
|
||||
This project follows
|
||||
[Google's Open Source Community Guidelines](https://opensource.google/conduct/).
|
||||
|
||||
## Contribution Process
|
||||
## Code contribution process
|
||||
|
||||
### Code Reviews
|
||||
### Get started
|
||||
|
||||
The process for contributing code is as follows:
|
||||
|
||||
1. **Find an issue** that you want to work on. If an issue is tagged as
|
||||
`🔒Maintainers only`, this means it is reserved for project maintainers. We
|
||||
will not accept pull requests related to these issues. In the near future,
|
||||
we will explicitly mark issues looking for contributions using the
|
||||
`help-wanted` label. If you believe an issue is a good candidate for
|
||||
community contribution, please leave a comment on the issue. A maintainer
|
||||
will review it and apply the `help-wanted` label if appropriate. Only
|
||||
maintainers should attempt to add the `help-wanted` label to an issue.
|
||||
2. **Fork the repository** and create a new branch.
|
||||
3. **Make your changes** in the `packages/` directory.
|
||||
4. **Ensure all checks pass** by running `npm run preflight`.
|
||||
5. **Open a pull request** with your changes.
|
||||
|
||||
### Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use [GitHub pull requests](https://docs.github.com/articles/about-pull-requests)
|
||||
for this purpose.
|
||||
|
||||
### Self Assigning Issues
|
||||
If your pull request involves changes to `packages/cli` (the frontend), we
|
||||
recommend running our automated frontend review tool. **Note: This tool is
|
||||
currently experimental.** It helps detect common React anti-patterns, testing
|
||||
issues, and other frontend-specific best practices that are easy to miss.
|
||||
|
||||
If you're looking for an issue to work on, check out our list of issues that are labeled ["help wanted"](https://github.com/google-gemini/gemini-cli/issues?q=is%3Aissue+state%3Aopen+label%3A%22help+wanted%22).
|
||||
To run the review tool, enter the following command from within Gemini CLI:
|
||||
|
||||
To assign an issue to yourself, simply add a comment with the text `/assign`. The comment must contain only that text and nothing else. This command will assign the issue to you, provided it is not already assigned.
|
||||
```text
|
||||
/review-frontend <PR_NUMBER>
|
||||
```
|
||||
|
||||
Please note that you can have a maximum of 3 issues assigned to you at any given time.
|
||||
Replace `<PR_NUMBER>` with your pull request number. Authors are encouraged to
|
||||
run this on their own PRs for self-review, and reviewers should use it to
|
||||
augment their manual review process.
|
||||
|
||||
### Pull Request Guidelines
|
||||
### Self assigning issues
|
||||
|
||||
To help us review and merge your PRs quickly, please follow these guidelines. PRs that do not meet these standards may be closed.
|
||||
To assign an issue to yourself, simply add a comment with the text `/assign`.
|
||||
The comment must contain only that text and nothing else. This command will
|
||||
assign the issue to you, provided it is not already assigned.
|
||||
|
||||
#### 1. Link to an Existing Issue
|
||||
Please note that you can have a maximum of 3 issues assigned to you at any given
|
||||
time.
|
||||
|
||||
All PRs should be linked to an existing issue in our tracker. This ensures that every change has been discussed and is aligned with the project's goals before any code is written.
|
||||
### Pull request guidelines
|
||||
|
||||
To help us review and merge your PRs quickly, please follow these guidelines.
|
||||
PRs that do not meet these standards may be closed.
|
||||
|
||||
#### 1. Link to an existing issue
|
||||
|
||||
All PRs should be linked to an existing issue in our tracker. This ensures that
|
||||
every change has been discussed and is aligned with the project's goals before
|
||||
any code is written.
|
||||
|
||||
- **For bug fixes:** The PR should be linked to the bug report issue.
|
||||
- **For features:** The PR should be linked to the feature request or proposal issue that has been approved by a maintainer.
|
||||
- **For features:** The PR should be linked to the feature request or proposal
|
||||
issue that has been approved by a maintainer.
|
||||
|
||||
If an issue for your change doesn't exist, please **open one first** and wait for feedback before you start coding.
|
||||
If an issue for your change doesn't exist, we will automatically close your PR
|
||||
along with a comment reminding you to associate the PR with an issue. The ideal
|
||||
workflow starts with an issue that has been reviewed and approved by a
|
||||
maintainer. Please **open the issue first** and wait for feedback before you
|
||||
start coding.
|
||||
|
||||
#### 2. Keep It Small and Focused
|
||||
#### 2. Keep it small and focused
|
||||
|
||||
We favor small, atomic PRs that address a single issue or add a single, self-contained feature.
|
||||
We favor small, atomic PRs that address a single issue or add a single,
|
||||
self-contained feature.
|
||||
|
||||
- **Do:** Create a PR that fixes one specific bug or adds one specific feature.
|
||||
- **Don't:** Bundle multiple unrelated changes (e.g., a bug fix, a new feature, and a refactor) into a single PR.
|
||||
- **Don't:** Bundle multiple unrelated changes (e.g., a bug fix, a new feature,
|
||||
and a refactor) into a single PR.
|
||||
|
||||
Large changes should be broken down into a series of smaller, logical PRs that can be reviewed and merged independently.
|
||||
Large changes should be broken down into a series of smaller, logical PRs that
|
||||
can be reviewed and merged independently.
|
||||
|
||||
#### 3. Use Draft PRs for Work in Progress
|
||||
#### 3. Use draft PRs for work in progress
|
||||
|
||||
If you'd like to get early feedback on your work, please use GitHub's **Draft Pull Request** feature. This signals to the maintainers that the PR is not yet ready for a formal review but is open for discussion and initial feedback.
|
||||
If you'd like to get early feedback on your work, please use GitHub's **Draft
|
||||
Pull Request** feature. This signals to the maintainers that the PR is not yet
|
||||
ready for a formal review but is open for discussion and initial feedback.
|
||||
|
||||
#### 4. Ensure All Checks Pass
|
||||
#### 4. Ensure all checks pass
|
||||
|
||||
Before submitting your PR, ensure that all automated checks are passing by running `npm run preflight`. This command runs all tests, linting, and other style checks.
|
||||
Before submitting your PR, ensure that all automated checks are passing by
|
||||
running `npm run preflight`. This command runs all tests, linting, and other
|
||||
style checks.
|
||||
|
||||
#### 5. Update Documentation
|
||||
#### 5. Update documentation
|
||||
|
||||
If your PR introduces a user-facing change (e.g., a new command, a modified flag, or a change in behavior), you must also update the relevant documentation in the `/docs` directory.
|
||||
If your PR introduces a user-facing change (e.g., a new command, a modified
|
||||
flag, or a change in behavior), you must also update the relevant documentation
|
||||
in the `/docs` directory.
|
||||
|
||||
#### 6. Write Clear Commit Messages and a Good PR Description
|
||||
See more about writing documentation:
|
||||
[Documentation contribution process](#documentation-contribution-process).
|
||||
|
||||
Your PR should have a clear, descriptive title and a detailed description of the changes. Follow the [Conventional Commits](https://www.conventionalcommits.org/) standard for your commit messages.
|
||||
#### 6. Write clear commit messages and a good PR description
|
||||
|
||||
- **Good PR Title:** `feat(cli): Add --json flag to 'config get' command`
|
||||
- **Bad PR Title:** `Made some changes`
|
||||
Your PR should have a clear, descriptive title and a detailed description of the
|
||||
changes. Follow the [Conventional Commits](https://www.conventionalcommits.org/)
|
||||
standard for your commit messages.
|
||||
|
||||
In the PR description, explain the "why" behind your changes and link to the relevant issue (e.g., `Fixes #123`).
|
||||
- **Good PR title:** `feat(cli): Add --json flag to 'config get' command`
|
||||
- **Bad PR title:** `Made some changes`
|
||||
|
||||
## Forking
|
||||
In the PR description, explain the "why" behind your changes and link to the
|
||||
relevant issue (e.g., `Fixes #123`).
|
||||
|
||||
If you are forking the repository you will be able to run the Build, Test and Integration test workflows. However in order to make the integration tests run you'll need to add a [GitHub Repository Secret](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository) with a value of `GEMINI_API_KEY` and set that to a valid API key that you have available. Your key and secret are private to your repo; no one without access can see your key and you cannot see any secrets related to this repo.
|
||||
### Forking
|
||||
|
||||
Additionally you will need to click on the `Actions` tab and enable workflows for your repository, you'll find it's the large blue button in the center of the screen.
|
||||
If you are forking the repository you will be able to run the Build, Test and
|
||||
Integration test workflows. However in order to make the integration tests run
|
||||
you'll need to add a
|
||||
[GitHub Repository Secret](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository)
|
||||
with a value of `GEMINI_API_KEY` and set that to a valid API key that you have
|
||||
available. Your key and secret are private to your repo; no one without access
|
||||
can see your key and you cannot see any secrets related to this repo.
|
||||
|
||||
## Development Setup and Workflow
|
||||
Additionally you will need to click on the `Actions` tab and enable workflows
|
||||
for your repository, you'll find it's the large blue button in the center of the
|
||||
screen.
|
||||
|
||||
This section guides contributors on how to build, modify, and understand the development setup of this project.
|
||||
### Development setup and workflow
|
||||
|
||||
### Setting Up the Development Environment
|
||||
This section guides contributors on how to build, modify, and understand the
|
||||
development setup of this project.
|
||||
|
||||
### Setting up the development environment
|
||||
|
||||
**Prerequisites:**
|
||||
|
||||
1. **Node.js**:
|
||||
- **Development:** Please use Node.js `~20.19.0`. This specific version is required due to an upstream development dependency issue. You can use a tool like [nvm](https://github.com/nvm-sh/nvm) to manage Node.js versions.
|
||||
- **Production:** For running the CLI in a production environment, any version of Node.js `>=20` is acceptable.
|
||||
- **Development:** Please use Node.js `~20.19.0`. This specific version is
|
||||
required due to an upstream development dependency issue. You can use a
|
||||
tool like [nvm](https://github.com/nvm-sh/nvm) to manage Node.js versions.
|
||||
- **Production:** For running the CLI in a production environment, any
|
||||
version of Node.js `>=20` is acceptable.
|
||||
2. **Git**
|
||||
|
||||
### Build Process
|
||||
### Build process
|
||||
|
||||
To clone the repository:
|
||||
|
||||
@@ -122,13 +202,19 @@ To build the entire project (all packages):
|
||||
npm run build
|
||||
```
|
||||
|
||||
This command typically compiles TypeScript to JavaScript, bundles assets, and prepares the packages for execution. Refer to `scripts/build.js` and `package.json` scripts for more details on what happens during the build.
|
||||
This command typically compiles TypeScript to JavaScript, bundles assets, and
|
||||
prepares the packages for execution. Refer to `scripts/build.js` and
|
||||
`package.json` scripts for more details on what happens during the build.
|
||||
|
||||
### Enabling Sandboxing
|
||||
### Enabling sandboxing
|
||||
|
||||
[Sandboxing](#sandboxing) is highly recommended and requires, at a minimum, setting `GEMINI_SANDBOX=true` in your `~/.env` and ensuring a sandboxing provider (e.g. `macOS Seatbelt`, `docker`, or `podman`) is available. See [Sandboxing](#sandboxing) for details.
|
||||
[Sandboxing](#sandboxing) is highly recommended and requires, at a minimum,
|
||||
setting `GEMINI_SANDBOX=true` in your `~/.env` and ensuring a sandboxing
|
||||
provider (e.g. `macOS Seatbelt`, `docker`, or `podman`) is available. See
|
||||
[Sandboxing](#sandboxing) for details.
|
||||
|
||||
To build both the `gemini` CLI utility and the sandbox container, run `build:all` from the root directory:
|
||||
To build both the `gemini` CLI utility and the sandbox container, run
|
||||
`build:all` from the root directory:
|
||||
|
||||
```bash
|
||||
npm run build:all
|
||||
@@ -136,21 +222,25 @@ npm run build:all
|
||||
|
||||
To skip building the sandbox container, you can use `npm run build` instead.
|
||||
|
||||
### Running
|
||||
### Running the CLI
|
||||
|
||||
To start the Gemini CLI from the source code (after building), run the following command from the root directory:
|
||||
To start the Gemini CLI from the source code (after building), run the following
|
||||
command from the root directory:
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
If you'd like to run the source build outside of the gemini-cli folder, you can utilize `npm link path/to/gemini-cli/packages/cli` (see: [docs](https://docs.npmjs.com/cli/v9/commands/npm-link)) or `alias gemini="node path/to/gemini-cli/packages/cli"` to run with `gemini`
|
||||
If you'd like to run the source build outside of the gemini-cli folder, you can
|
||||
utilize `npm link path/to/gemini-cli/packages/cli` (see:
|
||||
[docs](https://docs.npmjs.com/cli/v9/commands/npm-link)) or
|
||||
`alias gemini="node path/to/gemini-cli/packages/cli"` to run with `gemini`
|
||||
|
||||
### Running Tests
|
||||
### Running tests
|
||||
|
||||
This project contains two types of tests: unit tests and integration tests.
|
||||
|
||||
#### Unit Tests
|
||||
#### Unit tests
|
||||
|
||||
To execute the unit test suite for the project:
|
||||
|
||||
@@ -158,11 +248,14 @@ To execute the unit test suite for the project:
|
||||
npm run test
|
||||
```
|
||||
|
||||
This will run tests located in the `packages/core` and `packages/cli` directories. Ensure tests pass before submitting any changes. For a more comprehensive check, it is recommended to run `npm run preflight`.
|
||||
This will run tests located in the `packages/core` and `packages/cli`
|
||||
directories. Ensure tests pass before submitting any changes. For a more
|
||||
comprehensive check, it is recommended to run `npm run preflight`.
|
||||
|
||||
#### Integration Tests
|
||||
#### Integration tests
|
||||
|
||||
The integration tests are designed to validate the end-to-end functionality of the Gemini CLI. They are not run as part of the default `npm run test` command.
|
||||
The integration tests are designed to validate the end-to-end functionality of
|
||||
the Gemini CLI. They are not run as part of the default `npm run test` command.
|
||||
|
||||
To run the integration tests, use the following command:
|
||||
|
||||
@@ -170,9 +263,10 @@ To run the integration tests, use the following command:
|
||||
npm run test:e2e
|
||||
```
|
||||
|
||||
For more detailed information on the integration testing framework, please see the [Integration Tests documentation](./docs/integration-tests.md).
|
||||
For more detailed information on the integration testing framework, please see
|
||||
the [Integration Tests documentation](/docs/integration-tests.md).
|
||||
|
||||
### Linting and Preflight Checks
|
||||
### Linting and preflight checks
|
||||
|
||||
To ensure code quality and formatting consistency, run the preflight check:
|
||||
|
||||
@@ -180,11 +274,13 @@ To ensure code quality and formatting consistency, run the preflight check:
|
||||
npm run preflight
|
||||
```
|
||||
|
||||
This command will run ESLint, Prettier, all tests, and other checks as defined in the project's `package.json`.
|
||||
This command will run ESLint, Prettier, all tests, and other checks as defined
|
||||
in the project's `package.json`.
|
||||
|
||||
_ProTip_
|
||||
|
||||
after cloning create a git precommit hook file to ensure your commits are always clean.
|
||||
after cloning create a git precommit hook file to ensure your commits are always
|
||||
clean.
|
||||
|
||||
```bash
|
||||
echo "
|
||||
@@ -198,51 +294,71 @@ fi
|
||||
|
||||
#### Formatting
|
||||
|
||||
To separately format the code in this project by running the following command from the root directory:
|
||||
To separately format the code in this project by running the following command
|
||||
from the root directory:
|
||||
|
||||
```bash
|
||||
npm run format
|
||||
```
|
||||
|
||||
This command uses Prettier to format the code according to the project's style guidelines.
|
||||
This command uses Prettier to format the code according to the project's style
|
||||
guidelines.
|
||||
|
||||
#### Linting
|
||||
|
||||
To separately lint the code in this project, run the following command from the root directory:
|
||||
To separately lint the code in this project, run the following command from the
|
||||
root directory:
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Coding Conventions
|
||||
### Coding conventions
|
||||
|
||||
- Please adhere to the coding style, patterns, and conventions used throughout the existing codebase.
|
||||
- Consult [GEMINI.md](https://github.com/google-gemini/gemini-cli/blob/main/GEMINI.md) (typically found in the project root) for specific instructions related to AI-assisted development, including conventions for React, comments, and Git usage.
|
||||
- **Imports:** Pay special attention to import paths. The project uses ESLint to enforce restrictions on relative imports between packages.
|
||||
- Please adhere to the coding style, patterns, and conventions used throughout
|
||||
the existing codebase.
|
||||
- Consult
|
||||
[GEMINI.md](https://github.com/google-gemini/gemini-cli/blob/main/GEMINI.md)
|
||||
(typically found in the project root) for specific instructions related to
|
||||
AI-assisted development, including conventions for React, comments, and Git
|
||||
usage.
|
||||
- **Imports:** Pay special attention to import paths. The project uses ESLint to
|
||||
enforce restrictions on relative imports between packages.
|
||||
|
||||
### Project Structure
|
||||
### Project structure
|
||||
|
||||
- `packages/`: Contains the individual sub-packages of the project.
|
||||
- `a2a-server`: A2A server implementation for the Gemini CLI. (Experimental)
|
||||
- `cli/`: The command-line interface.
|
||||
- `core/`: The core backend logic for the Gemini CLI.
|
||||
- `test-utils` Utilities for creating and cleaning temporary file systems for
|
||||
testing.
|
||||
- `vscode-ide-companion/`: The Gemini CLI Companion extension pairs with
|
||||
Gemini CLI.
|
||||
- `docs/`: Contains all project documentation.
|
||||
- `scripts/`: Utility scripts for building, testing, and development tasks.
|
||||
|
||||
For more detailed architecture, see `docs/architecture.md`.
|
||||
|
||||
## Debugging
|
||||
### Debugging
|
||||
|
||||
### VS Code:
|
||||
#### VS Code
|
||||
|
||||
0. Run the CLI to interactively debug in VS Code with `F5`
|
||||
1. Start the CLI in debug mode from the root directory:
|
||||
```bash
|
||||
npm run debug
|
||||
```
|
||||
This command runs `node --inspect-brk dist/gemini.js` within the `packages/cli` directory, pausing execution until a debugger attaches. You can then open `chrome://inspect` in your Chrome browser to connect to the debugger.
|
||||
2. In VS Code, use the "Attach" launch configuration (found in `.vscode/launch.json`).
|
||||
This command runs `node --inspect-brk dist/gemini.js` within the
|
||||
`packages/cli` directory, pausing execution until a debugger attaches. You
|
||||
can then open `chrome://inspect` in your Chrome browser to connect to the
|
||||
debugger.
|
||||
2. In VS Code, use the "Attach" launch configuration (found in
|
||||
`.vscode/launch.json`).
|
||||
|
||||
Alternatively, you can use the "Launch Program" configuration in VS Code if you prefer to launch the currently open file directly, but 'F5' is generally recommended.
|
||||
Alternatively, you can use the "Launch Program" configuration in VS Code if you
|
||||
prefer to launch the currently open file directly, but 'F5' is generally
|
||||
recommended.
|
||||
|
||||
To hit a breakpoint inside the sandbox container run:
|
||||
|
||||
@@ -250,11 +366,13 @@ To hit a breakpoint inside the sandbox container run:
|
||||
DEBUG=1 gemini
|
||||
```
|
||||
|
||||
**Note:** If you have `DEBUG=true` in a project's `.env` file, it won't affect gemini-cli due to automatic exclusion. Use `.gemini/.env` files for gemini-cli specific debug settings.
|
||||
**Note:** If you have `DEBUG=true` in a project's `.env` file, it won't affect
|
||||
gemini-cli due to automatic exclusion. Use `.gemini/.env` files for gemini-cli
|
||||
specific debug settings.
|
||||
|
||||
### React DevTools
|
||||
|
||||
To debug the CLI's React-based UI, you can use React DevTools. Ink, the library used for the CLI's interface, is compatible with React DevTools version 4.x.
|
||||
To debug the CLI's React-based UI, you can use React DevTools.
|
||||
|
||||
1. **Start the Gemini CLI in development mode:**
|
||||
|
||||
@@ -262,43 +380,82 @@ To debug the CLI's React-based UI, you can use React DevTools. Ink, the library
|
||||
DEV=true npm start
|
||||
```
|
||||
|
||||
2. **Install and run React DevTools version 4.28.5 (or the latest compatible 4.x version):**
|
||||
2. **Install and run React DevTools version 6 (which matches the CLI's
|
||||
`react-devtools-core`):**
|
||||
|
||||
You can either install it globally:
|
||||
|
||||
```bash
|
||||
npm install -g react-devtools@4.28.5
|
||||
npm install -g react-devtools@6
|
||||
react-devtools
|
||||
```
|
||||
|
||||
Or run it directly using npx:
|
||||
|
||||
```bash
|
||||
npx react-devtools@4.28.5
|
||||
npx react-devtools@6
|
||||
```
|
||||
|
||||
Your running CLI application should then connect to React DevTools.
|
||||

|
||||
|
||||
## Sandboxing
|
||||
### Sandboxing
|
||||
|
||||
### macOS Seatbelt
|
||||
#### macOS Seatbelt
|
||||
|
||||
On macOS, `gemini` uses Seatbelt (`sandbox-exec`) under a `permissive-open` profile (see `packages/cli/src/utils/sandbox-macos-permissive-open.sb`) that restricts writes to the project folder but otherwise allows all other operations and outbound network traffic ("open") by default. You can switch to a `restrictive-closed` profile (see `packages/cli/src/utils/sandbox-macos-restrictive-closed.sb`) that declines all operations and outbound network traffic ("closed") by default by setting `SEATBELT_PROFILE=restrictive-closed` in your environment or `.env` file. Available built-in profiles are `{permissive,restrictive}-{open,closed,proxied}` (see below for proxied networking). You can also switch to a custom profile `SEATBELT_PROFILE=<profile>` if you also create a file `.gemini/sandbox-macos-<profile>.sb` under your project settings directory `.gemini`.
|
||||
On macOS, `gemini` uses Seatbelt (`sandbox-exec`) under a `permissive-open`
|
||||
profile (see `packages/cli/src/utils/sandbox-macos-permissive-open.sb`) that
|
||||
restricts writes to the project folder but otherwise allows all other operations
|
||||
and outbound network traffic ("open") by default. You can switch to a
|
||||
`strict-open` profile (see
|
||||
`packages/cli/src/utils/sandbox-macos-strict-open.sb`) that restricts both reads
|
||||
and writes to the working directory while allowing outbound network traffic by
|
||||
setting `SEATBELT_PROFILE=strict-open` in your environment or `.env` file.
|
||||
Available built-in profiles are `permissive-{open,proxied}`,
|
||||
`restrictive-{open,proxied}`, and `strict-{open,proxied}` (see below for proxied
|
||||
networking). You can also switch to a custom profile
|
||||
`SEATBELT_PROFILE=<profile>` if you also create a file
|
||||
`.gemini/sandbox-macos-<profile>.sb` under your project settings directory
|
||||
`.gemini`.
|
||||
|
||||
### Container-based Sandboxing (All Platforms)
|
||||
#### Container-based sandboxing (all platforms)
|
||||
|
||||
For stronger container-based sandboxing on macOS or other platforms, you can set `GEMINI_SANDBOX=true|docker|podman|<command>` in your environment or `.env` file. The specified command (or if `true` then either `docker` or `podman`) must be installed on the host machine. Once enabled, `npm run build:all` will build a minimal container ("sandbox") image and `npm start` will launch inside a fresh instance of that container. The first build can take 20-30s (mostly due to downloading of the base image) but after that both build and start overhead should be minimal. Default builds (`npm run build`) will not rebuild the sandbox.
|
||||
For stronger container-based sandboxing on macOS or other platforms, you can set
|
||||
`GEMINI_SANDBOX=true|docker|podman|<command>` in your environment or `.env`
|
||||
file. The specified command (or if `true` then either `docker` or `podman`) must
|
||||
be installed on the host machine. Once enabled, `npm run build:all` will build a
|
||||
minimal container ("sandbox") image and `npm start` will launch inside a fresh
|
||||
instance of that container. The first build can take 20-30s (mostly due to
|
||||
downloading of the base image) but after that both build and start overhead
|
||||
should be minimal. Default builds (`npm run build`) will not rebuild the
|
||||
sandbox.
|
||||
|
||||
Container-based sandboxing mounts the project directory (and system temp directory) with read-write access and is started/stopped/removed automatically as you start/stop Gemini CLI. Files created within the sandbox should be automatically mapped to your user/group on host machine. You can easily specify additional mounts, ports, or environment variables by setting `SANDBOX_{MOUNTS,PORTS,ENV}` as needed. You can also fully customize the sandbox for your projects by creating the files `.gemini/sandbox.Dockerfile` and/or `.gemini/sandbox.bashrc` under your project settings directory (`.gemini`) and running `gemini` with `BUILD_SANDBOX=1` to trigger building of your custom sandbox.
|
||||
Container-based sandboxing mounts the project directory (and system temp
|
||||
directory) with read-write access and is started/stopped/removed automatically
|
||||
as you start/stop Gemini CLI. Files created within the sandbox should be
|
||||
automatically mapped to your user/group on host machine. You can easily specify
|
||||
additional mounts, ports, or environment variables by setting
|
||||
`SANDBOX_{MOUNTS,PORTS,ENV}` as needed. You can also fully customize the sandbox
|
||||
for your projects by creating the files `.gemini/sandbox.Dockerfile` and/or
|
||||
`.gemini/sandbox.bashrc` under your project settings directory (`.gemini`) and
|
||||
running `gemini` with `BUILD_SANDBOX=1` to trigger building of your custom
|
||||
sandbox.
|
||||
|
||||
#### Proxied Networking
|
||||
#### Proxied networking
|
||||
|
||||
All sandboxing methods, including macOS Seatbelt using `*-proxied` profiles, support restricting outbound network traffic through a custom proxy server that can be specified as `GEMINI_SANDBOX_PROXY_COMMAND=<command>`, where `<command>` must start a proxy server that listens on `:::8877` for relevant requests. See `docs/examples/proxy-script.md` for a minimal proxy that only allows `HTTPS` connections to `example.com:443` (e.g. `curl https://example.com`) and declines all other requests. The proxy is started and stopped automatically alongside the sandbox.
|
||||
All sandboxing methods, including macOS Seatbelt using `*-proxied` profiles,
|
||||
support restricting outbound network traffic through a custom proxy server that
|
||||
can be specified as `GEMINI_SANDBOX_PROXY_COMMAND=<command>`, where `<command>`
|
||||
must start a proxy server that listens on `:::8877` for relevant requests. See
|
||||
`docs/examples/proxy-script.md` for a minimal proxy that only allows `HTTPS`
|
||||
connections to `example.com:443` (e.g. `curl https://example.com`) and declines
|
||||
all other requests. The proxy is started and stopped automatically alongside the
|
||||
sandbox.
|
||||
|
||||
## Manual Publish
|
||||
### Manual publish
|
||||
|
||||
We publish an artifact for each commit to our internal registry. But if you need to manually cut a local build, then run the following commands:
|
||||
We publish an artifact for each commit to our internal registry. But if you need
|
||||
to manually cut a local build, then run the following commands:
|
||||
|
||||
```
|
||||
npm run clean
|
||||
@@ -307,3 +464,91 @@ npm run auth
|
||||
npm run prerelease:dev
|
||||
npm publish --workspaces
|
||||
```
|
||||
|
||||
## Documentation contribution process
|
||||
|
||||
Our documentation must be kept up-to-date with our code contributions. We want
|
||||
our documentation to be clear, concise, and helpful to our users. We value:
|
||||
|
||||
- **Clarity:** Use simple and direct language. Avoid jargon where possible.
|
||||
- **Accuracy:** Ensure all information is correct and up-to-date.
|
||||
- **Completeness:** Cover all aspects of a feature or topic.
|
||||
- **Examples:** Provide practical examples to help users understand how to use
|
||||
Gemini CLI.
|
||||
|
||||
### Getting started
|
||||
|
||||
The process for contributing to the documentation is similar to contributing
|
||||
code.
|
||||
|
||||
1. **Fork the repository** and create a new branch.
|
||||
2. **Make your changes** in the `/docs` directory.
|
||||
3. **Preview your changes locally** in Markdown rendering.
|
||||
4. **Lint and format your changes.** Our preflight check includes linting and
|
||||
formatting for documentation files.
|
||||
```bash
|
||||
npm run preflight
|
||||
```
|
||||
5. **Open a pull request** with your changes.
|
||||
|
||||
### Documentation structure
|
||||
|
||||
Our documentation is organized using [sidebar.json](/docs/sidebar.json) as the
|
||||
table of contents. When adding new documentation:
|
||||
|
||||
1. Create your markdown file **in the appropriate directory** under `/docs`.
|
||||
2. Add an entry to `sidebar.json` in the relevant section.
|
||||
3. Ensure all internal links use relative paths and point to existing files.
|
||||
|
||||
### Style guide
|
||||
|
||||
We follow the
|
||||
[Google Developer Documentation Style Guide](https://developers.google.com/style).
|
||||
Please refer to it for guidance on writing style, tone, and formatting.
|
||||
|
||||
#### Key style points
|
||||
|
||||
- Use sentence case for headings.
|
||||
- Write in second person ("you") when addressing the reader.
|
||||
- Use present tense.
|
||||
- Keep paragraphs short and focused.
|
||||
- Use code blocks with appropriate language tags for syntax highlighting.
|
||||
- Include practical examples whenever possible.
|
||||
|
||||
### Linting and formatting
|
||||
|
||||
We use `prettier` to enforce a consistent style across our documentation. The
|
||||
`npm run preflight` command will check for any linting issues.
|
||||
|
||||
You can also run the linter and formatter separately:
|
||||
|
||||
- `npm run lint` - Check for linting issues
|
||||
- `npm run format` - Auto-format markdown files
|
||||
- `npm run lint:fix` - Auto-fix linting issues where possible
|
||||
|
||||
Please make sure your contributions are free of linting errors before submitting
|
||||
a pull request.
|
||||
|
||||
### Before you submit
|
||||
|
||||
Before submitting your documentation pull request, please:
|
||||
|
||||
1. Run `npm run preflight` to ensure all checks pass.
|
||||
2. Review your changes for clarity and accuracy.
|
||||
3. Check that all links work correctly.
|
||||
4. Ensure any code examples are tested and functional.
|
||||
5. Sign the
|
||||
[Contributor License Agreement (CLA)](https://cla.developers.google.com/) if
|
||||
you haven't already.
|
||||
|
||||
### Need help?
|
||||
|
||||
If you have questions about contributing documentation:
|
||||
|
||||
- Check our [FAQ](/docs/resources/faq.md).
|
||||
- Review existing documentation for examples.
|
||||
- Open [an issue](https://github.com/google-gemini/gemini-cli/issues) to discuss
|
||||
your proposed changes.
|
||||
- Reach out to the maintainers.
|
||||
|
||||
We appreciate your contributions to making Gemini CLI documentation better!
|
||||
|
||||
+4
-1
@@ -42,7 +42,10 @@ USER node
|
||||
# install gemini-cli and clean up
|
||||
COPY packages/cli/dist/google-gemini-cli-*.tgz /tmp/gemini-cli.tgz
|
||||
COPY packages/core/dist/google-gemini-cli-core-*.tgz /tmp/gemini-core.tgz
|
||||
RUN npm install -g /tmp/gemini-cli.tgz /tmp/gemini-core.tgz \
|
||||
RUN npm install -g /tmp/gemini-core.tgz \
|
||||
&& npm install -g /tmp/gemini-cli.tgz \
|
||||
&& node -e "const fs=require('node:fs'); JSON.parse(fs.readFileSync('/usr/local/share/npm-global/lib/node_modules/@google/gemini-cli/package.json','utf8')); JSON.parse(fs.readFileSync('/usr/local/share/npm-global/lib/node_modules/@google/gemini-cli-core/package.json','utf8'));" \
|
||||
&& gemini --version > /dev/null \
|
||||
&& npm cache clean --force \
|
||||
&& rm -f /tmp/gemini-{cli,core}.tgz
|
||||
|
||||
|
||||
@@ -1,193 +1,94 @@
|
||||
## Building and running
|
||||
|
||||
Before submitting any changes, it is crucial to validate them by running the full preflight check. This command will build the repository, run all tests, check for type errors, and lint the code.
|
||||
|
||||
To run the full suite of checks, execute the following command:
|
||||
|
||||
```bash
|
||||
npm run preflight
|
||||
```
|
||||
|
||||
This single command ensures that your changes meet all the quality gates of the project. While you can run the individual steps (`build`, `test`, `typecheck`, `lint`) separately, it is highly recommended to use `npm run preflight` to ensure a comprehensive validation.
|
||||
|
||||
## Writing Tests
|
||||
|
||||
This project uses **Vitest** as its primary testing framework. When writing tests, aim to follow existing patterns. Key conventions include:
|
||||
|
||||
### Test Structure and Framework
|
||||
|
||||
- **Framework**: All tests are written using Vitest (`describe`, `it`, `expect`, `vi`).
|
||||
- **File Location**: Test files (`*.test.ts` for logic, `*.test.tsx` for React components) are co-located with the source files they test.
|
||||
- **Configuration**: Test environments are defined in `vitest.config.ts` files.
|
||||
- **Setup/Teardown**: Use `beforeEach` and `afterEach`. Commonly, `vi.resetAllMocks()` is called in `beforeEach` and `vi.restoreAllMocks()` in `afterEach`.
|
||||
|
||||
### Mocking (`vi` from Vitest)
|
||||
|
||||
- **ES Modules**: Mock with `vi.mock('module-name', async (importOriginal) => { ... })`. Use `importOriginal` for selective mocking.
|
||||
- _Example_: `vi.mock('os', async (importOriginal) => { const actual = await importOriginal(); return { ...actual, homedir: vi.fn() }; });`
|
||||
- **Mocking Order**: For critical dependencies (e.g., `os`, `fs`) that affect module-level constants, place `vi.mock` at the _very top_ of the test file, before other imports.
|
||||
- **Hoisting**: Use `const myMock = vi.hoisted(() => vi.fn());` if a mock function needs to be defined before its use in a `vi.mock` factory.
|
||||
- **Mock Functions**: Create with `vi.fn()`. Define behavior with `mockImplementation()`, `mockResolvedValue()`, or `mockRejectedValue()`.
|
||||
- **Spying**: Use `vi.spyOn(object, 'methodName')`. Restore spies with `mockRestore()` in `afterEach`.
|
||||
|
||||
### Commonly Mocked Modules
|
||||
|
||||
- **Node.js built-ins**: `fs`, `fs/promises`, `os` (especially `os.homedir()`), `path`, `child_process` (`execSync`, `spawn`).
|
||||
- **External SDKs**: `@google/genai`, `@modelcontextprotocol/sdk`.
|
||||
- **Internal Project Modules**: Dependencies from other project packages are often mocked.
|
||||
|
||||
### React Component Testing (CLI UI - Ink)
|
||||
|
||||
- Use `render()` from `ink-testing-library`.
|
||||
- Assert output with `lastFrame()`.
|
||||
- Wrap components in necessary `Context.Provider`s.
|
||||
- Mock custom React hooks and complex child components using `vi.mock()`.
|
||||
|
||||
### Asynchronous Testing
|
||||
|
||||
- Use `async/await`.
|
||||
- For timers, use `vi.useFakeTimers()`, `vi.advanceTimersByTimeAsync()`, `vi.runAllTimersAsync()`.
|
||||
- Test promise rejections with `await expect(promise).rejects.toThrow(...)`.
|
||||
|
||||
### General Guidance
|
||||
|
||||
- When adding tests, first examine existing tests to understand and conform to established conventions.
|
||||
- Pay close attention to the mocks at the top of existing test files; they reveal critical dependencies and how they are managed in a test environment.
|
||||
|
||||
## Git Repo
|
||||
|
||||
The main branch for this project is called "main"
|
||||
|
||||
## JavaScript/TypeScript
|
||||
|
||||
When contributing to this React, Node, and TypeScript codebase, please prioritize the use of plain JavaScript objects with accompanying TypeScript interface or type declarations over JavaScript class syntax. This approach offers significant advantages, especially concerning interoperability with React and overall code maintainability.
|
||||
|
||||
### Preferring Plain Objects over Classes
|
||||
|
||||
JavaScript classes, by their nature, are designed to encapsulate internal state and behavior. While this can be useful in some object-oriented paradigms, it often introduces unnecessary complexity and friction when working with React's component-based architecture. Here's why plain objects are preferred:
|
||||
|
||||
- Seamless React Integration: React components thrive on explicit props and state management. Classes' tendency to store internal state directly within instances can make prop and state propagation harder to reason about and maintain. Plain objects, on the other hand, are inherently immutable (when used thoughtfully) and can be easily passed as props, simplifying data flow and reducing unexpected side effects.
|
||||
|
||||
- Reduced Boilerplate and Increased Conciseness: Classes often promote the use of constructors, this binding, getters, setters, and other boilerplate that can unnecessarily bloat code. TypeScript interface and type declarations provide powerful static type checking without the runtime overhead or verbosity of class definitions. This allows for more succinct and readable code, aligning with JavaScript's strengths in functional programming.
|
||||
|
||||
- Enhanced Readability and Predictability: Plain objects, especially when their structure is clearly defined by TypeScript interfaces, are often easier to read and understand. Their properties are directly accessible, and there's no hidden internal state or complex inheritance chains to navigate. This predictability leads to fewer bugs and a more maintainable codebase.
|
||||
|
||||
- Simplified Immutability: While not strictly enforced, plain objects encourage an immutable approach to data. When you need to modify an object, you typically create a new one with the desired changes, rather than mutating the original. This pattern aligns perfectly with React's reconciliation process and helps prevent subtle bugs related to shared mutable state.
|
||||
|
||||
- Better Serialization and Deserialization: Plain JavaScript objects are naturally easy to serialize to JSON and deserialize back, which is a common requirement in web development (e.g., for API communication or local storage). Classes, with their methods and prototypes, can complicate this process.
|
||||
|
||||
### Embracing ES Module Syntax for Encapsulation
|
||||
|
||||
Rather than relying on Java-esque private or public class members, which can be verbose and sometimes limit flexibility, we strongly prefer leveraging ES module syntax (`import`/`export`) for encapsulating private and public APIs.
|
||||
|
||||
- Clearer Public API Definition: With ES modules, anything that is exported is part of the public API of that module, while anything not exported is inherently private to that module. This provides a very clear and explicit way to define what parts of your code are meant to be consumed by other modules.
|
||||
|
||||
- Enhanced Testability (Without Exposing Internals): By default, unexported functions or variables are not accessible from outside the module. This encourages you to test the public API of your modules, rather than their internal implementation details. If you find yourself needing to spy on or stub an unexported function for testing purposes, it's often a "code smell" indicating that the function might be a good candidate for extraction into its own separate, testable module with a well-defined public API. This promotes a more robust and maintainable testing strategy.
|
||||
|
||||
- Reduced Coupling: Explicitly defined module boundaries through import/export help reduce coupling between different parts of your codebase. This makes it easier to refactor, debug, and understand individual components in isolation.
|
||||
|
||||
### Avoiding `any` Types and Type Assertions; Preferring `unknown`
|
||||
|
||||
TypeScript's power lies in its ability to provide static type checking, catching potential errors before your code runs. To fully leverage this, it's crucial to avoid the `any` type and be judicious with type assertions.
|
||||
|
||||
- **The Dangers of `any`**: Using any effectively opts out of TypeScript's type checking for that particular variable or expression. While it might seem convenient in the short term, it introduces significant risks:
|
||||
- **Loss of Type Safety**: You lose all the benefits of type checking, making it easy to introduce runtime errors that TypeScript would otherwise have caught.
|
||||
- **Reduced Readability and Maintainability**: Code with `any` types is harder to understand and maintain, as the expected type of data is no longer explicitly defined.
|
||||
- **Masking Underlying Issues**: Often, the need for any indicates a deeper problem in the design of your code or the way you're interacting with external libraries. It's a sign that you might need to refine your types or refactor your code.
|
||||
|
||||
- **Preferring `unknown` over `any`**: When you absolutely cannot determine the type of a value at compile time, and you're tempted to reach for any, consider using unknown instead. unknown is a type-safe counterpart to any. While a variable of type unknown can hold any value, you must perform type narrowing (e.g., using typeof or instanceof checks, or a type assertion) before you can perform any operations on it. This forces you to handle the unknown type explicitly, preventing accidental runtime errors.
|
||||
|
||||
```ts
|
||||
function processValue(value: unknown) {
|
||||
if (typeof value === 'string') {
|
||||
// value is now safely a string
|
||||
console.log(value.toUpperCase());
|
||||
} else if (typeof value === 'number') {
|
||||
// value is now safely a number
|
||||
console.log(value * 2);
|
||||
}
|
||||
// Without narrowing, you cannot access properties or methods on 'value'
|
||||
// console.log(value.someProperty); // Error: Object is of type 'unknown'.
|
||||
}
|
||||
```
|
||||
|
||||
- **Type Assertions (`as Type`) - Use with Caution**: Type assertions tell the TypeScript compiler, "Trust me, I know what I'm doing; this is definitely of this type." While there are legitimate use cases (e.g., when dealing with external libraries that don't have perfect type definitions, or when you have more information than the compiler), they should be used sparingly and with extreme caution.
|
||||
- **Bypassing Type Checking**: Like `any`, type assertions bypass TypeScript's safety checks. If your assertion is incorrect, you introduce a runtime error that TypeScript would not have warned you about.
|
||||
- **Code Smell in Testing**: A common scenario where `any` or type assertions might be tempting is when trying to test "private" implementation details (e.g., spying on or stubbing an unexported function within a module). This is a strong indication of a "code smell" in your testing strategy and potentially your code structure. Instead of trying to force access to private internals, consider whether those internal details should be refactored into a separate module with a well-defined public API. This makes them inherently testable without compromising encapsulation.
|
||||
|
||||
### Type narrowing `switch` clauses
|
||||
|
||||
Use the `checkExhaustive` helper in the default clause of a switch statement.
|
||||
This will ensure that all of the possible options within the value or
|
||||
enumeration are used.
|
||||
|
||||
This helper method can be found in `packages/cli/src/utils/checks.ts`
|
||||
|
||||
### Embracing JavaScript's Array Operators
|
||||
|
||||
To further enhance code cleanliness and promote safe functional programming practices, leverage JavaScript's rich set of array operators as much as possible. Methods like `.map()`, `.filter()`, `.reduce()`, `.slice()`, `.sort()`, and others are incredibly powerful for transforming and manipulating data collections in an immutable and declarative way.
|
||||
|
||||
Using these operators:
|
||||
|
||||
- Promotes Immutability: Most array operators return new arrays, leaving the original array untouched. This functional approach helps prevent unintended side effects and makes your code more predictable.
|
||||
- Improves Readability: Chaining array operators often lead to more concise and expressive code than traditional for loops or imperative logic. The intent of the operation is clear at a glance.
|
||||
- Facilitates Functional Programming: These operators are cornerstones of functional programming, encouraging the creation of pure functions that take inputs and produce outputs without causing side effects. This paradigm is highly beneficial for writing robust and testable code that pairs well with React.
|
||||
|
||||
By consistently applying these principles, we can maintain a codebase that is not only efficient and performant but also a joy to work with, both now and in the future.
|
||||
|
||||
## React (mirrored and adjusted from [react-mcp-server](https://github.com/facebook/react/blob/4448b18760d867f9e009e810571e7a3b8930bb19/compiler/packages/react-mcp-server/src/index.ts#L376C1-L441C94))
|
||||
|
||||
### Role
|
||||
|
||||
You are a React assistant that helps users write more efficient and optimizable React code. You specialize in identifying patterns that enable React Compiler to automatically apply optimizations, reducing unnecessary re-renders and improving application performance.
|
||||
|
||||
### Follow these guidelines in all code you produce and suggest
|
||||
|
||||
Use functional components with Hooks: Do not generate class components or use old lifecycle methods. Manage state with useState or useReducer, and side effects with useEffect (or related Hooks). Always prefer functions and Hooks for any new component logic.
|
||||
|
||||
Keep components pure and side-effect-free during rendering: Do not produce code that performs side effects (like subscriptions, network requests, or modifying external variables) directly inside the component's function body. Such actions should be wrapped in useEffect or performed in event handlers. Ensure your render logic is a pure function of props and state.
|
||||
|
||||
Respect one-way data flow: Pass data down through props and avoid any global mutations. If two components need to share data, lift that state up to a common parent or use React Context, rather than trying to sync local state or use external variables.
|
||||
|
||||
Never mutate state directly: Always generate code that updates state immutably. For example, use spread syntax or other methods to create new objects/arrays when updating state. Do not use assignments like state.someValue = ... or array mutations like array.push() on state variables. Use the state setter (setState from useState, etc.) to update state.
|
||||
|
||||
Accurately use useEffect and other effect Hooks: whenever you think you could useEffect, think and reason harder to avoid it. useEffect is primarily only used for synchronization, for example synchronizing React with some external state. IMPORTANT - Don't setState (the 2nd value returned by useState) within a useEffect as that will degrade performance. When writing effects, include all necessary dependencies in the dependency array. Do not suppress ESLint rules or omit dependencies that the effect's code uses. Structure the effect callbacks to handle changing values properly (e.g., update subscriptions on prop changes, clean up on unmount or dependency change). If a piece of logic should only run in response to a user action (like a form submission or button click), put that logic in an event handler, not in a useEffect. Where possible, useEffects should return a cleanup function.
|
||||
|
||||
Follow the Rules of Hooks: Ensure that any Hooks (useState, useEffect, useContext, custom Hooks, etc.) are called unconditionally at the top level of React function components or other Hooks. Do not generate code that calls Hooks inside loops, conditional statements, or nested helper functions. Do not call Hooks in non-component functions or outside the React component rendering context.
|
||||
|
||||
Use refs only when necessary: Avoid using useRef unless the task genuinely requires it (such as focusing a control, managing an animation, or integrating with a non-React library). Do not use refs to store application state that should be reactive. If you do use refs, never write to or read from ref.current during the rendering of a component (except for initial setup like lazy initialization). Any ref usage should not affect the rendered output directly.
|
||||
|
||||
Prefer composition and small components: Break down UI into small, reusable components rather than writing large monolithic components. The code you generate should promote clarity and reusability by composing components together. Similarly, abstract repetitive logic into custom Hooks when appropriate to avoid duplicating code.
|
||||
|
||||
Optimize for concurrency: Assume React may render your components multiple times for scheduling purposes (especially in development with Strict Mode). Write code that remains correct even if the component function runs more than once. For instance, avoid side effects in the component body and use functional state updates (e.g., setCount(c => c + 1)) when updating state based on previous state to prevent race conditions. Always include cleanup functions in effects that subscribe to external resources. Don't write useEffects for "do this when this changes" side effects. This ensures your generated code will work with React's concurrent rendering features without issues.
|
||||
|
||||
Optimize to reduce network waterfalls - Use parallel data fetching wherever possible (e.g., start multiple requests at once rather than one after another). Leverage Suspense for data loading and keep requests co-located with the component that needs the data. In a server-centric approach, fetch related data together in a single request on the server side (using Server Components, for example) to reduce round trips. Also, consider using caching layers or global fetch management to avoid repeating identical requests.
|
||||
|
||||
Rely on React Compiler - useMemo, useCallback, and React.memo can be omitted if React Compiler is enabled. Avoid premature optimization with manual memoization. Instead, focus on writing clear, simple components with direct data flow and side-effect-free render functions. Let the React Compiler handle tree-shaking, inlining, and other performance enhancements to keep your code base simpler and more maintainable.
|
||||
|
||||
Design for a good user experience - Provide clear, minimal, and non-blocking UI states. When data is loading, show lightweight placeholders (e.g., skeleton screens) rather than intrusive spinners everywhere. Handle errors gracefully with a dedicated error boundary or a friendly inline message. Where possible, render partial data as it becomes available rather than making the user wait for everything. Suspense allows you to declare the loading states in your component tree in a natural way, preventing “flash” states and improving perceived performance.
|
||||
|
||||
### Process
|
||||
|
||||
1. Analyze the user's code for optimization opportunities:
|
||||
- Check for React anti-patterns that prevent compiler optimization
|
||||
- Look for component structure issues that limit compiler effectiveness
|
||||
- Think about each suggestion you are making and consult React docs for best practices
|
||||
|
||||
2. Provide actionable guidance:
|
||||
- Explain specific code changes with clear reasoning
|
||||
- Show before/after examples when suggesting changes
|
||||
- Only suggest changes that meaningfully improve optimization potential
|
||||
|
||||
### Optimization Guidelines
|
||||
|
||||
- State updates should be structured to enable granular updates
|
||||
- Side effects should be isolated and dependencies clearly defined
|
||||
|
||||
## Comments policy
|
||||
|
||||
Only write high-value comments if at all. Avoid talking to the user through comments.
|
||||
|
||||
## General style requirements
|
||||
|
||||
Use hyphens instead of underscores in flag names (e.g. `my-flag` instead of `my_flag`).
|
||||
# Gemini CLI Project Context
|
||||
|
||||
Gemini CLI is an open-source AI agent that brings the power of Gemini directly
|
||||
into the terminal. It is designed to be a terminal-first, extensible, and
|
||||
powerful tool for developers.
|
||||
|
||||
## Project Overview
|
||||
|
||||
- **Purpose:** Provide a seamless terminal interface for Gemini models,
|
||||
supporting code understanding, generation, automation, and integration via MCP
|
||||
(Model Context Protocol).
|
||||
- **Main Technologies:**
|
||||
- **Runtime:** Node.js (>=20.0.0, recommended ~20.19.0 for development)
|
||||
- **Language:** TypeScript
|
||||
- **UI Framework:** React (using [Ink](https://github.com/vadimdemedes/ink)
|
||||
for CLI rendering)
|
||||
- **Testing:** Vitest
|
||||
- **Bundling:** esbuild
|
||||
- **Linting/Formatting:** ESLint, Prettier
|
||||
- **Architecture:** Monorepo structure using npm workspaces.
|
||||
- `packages/cli`: User-facing terminal UI, input processing, and display
|
||||
rendering.
|
||||
- `packages/core`: Backend logic, Gemini API orchestration, prompt
|
||||
construction, and tool execution.
|
||||
- `packages/core/src/tools/`: Built-in tools for file system, shell, and web
|
||||
operations.
|
||||
- `packages/a2a-server`: Experimental Agent-to-Agent server.
|
||||
- `packages/vscode-ide-companion`: VS Code extension pairing with the CLI.
|
||||
|
||||
## Building and Running
|
||||
|
||||
- **Install Dependencies:** `npm install`
|
||||
- **Build All:** `npm run build:all` (Builds packages, sandbox, and VS Code
|
||||
companion)
|
||||
- **Build Packages:** `npm run build`
|
||||
- **Run in Development:** `npm run start`
|
||||
- **Run in Debug Mode:** `npm run debug` (Enables Node.js inspector)
|
||||
- **Bundle Project:** `npm run bundle`
|
||||
- **Clean Artifacts:** `npm run clean`
|
||||
|
||||
## Testing and Quality
|
||||
|
||||
- **Test Commands:**
|
||||
- **Unit (All):** `npm run test`
|
||||
- **Integration (E2E):** `npm run test:e2e`
|
||||
- **Workspace-Specific:** `npm test -w <pkg> -- <path>` (Note: `<path>` must
|
||||
be relative to the workspace root, e.g.,
|
||||
`-w @google/gemini-cli-core -- src/routing/modelRouterService.test.ts`)
|
||||
- **Full Validation:** `npm run preflight` (Heaviest check; runs clean, install,
|
||||
build, lint, type check, and tests. Recommended before submitting PRs. Due to
|
||||
its long runtime, only run this at the very end of a code implementation task.
|
||||
If it fails, use faster, targeted commands (e.g., `npm run test`,
|
||||
`npm run lint`, or workspace-specific tests) to iterate on fixes before
|
||||
re-running `preflight`. For simple, non-code changes like documentation or
|
||||
prompting updates, skip `preflight` at the end of the task and wait for PR
|
||||
validation.)
|
||||
- **Individual Checks:** `npm run lint` / `npm run format` / `npm run typecheck`
|
||||
|
||||
## Development Conventions
|
||||
|
||||
- **Legacy Snippets:** `packages/core/src/prompts/snippets.legacy.ts` is a
|
||||
snapshot of an older system prompt. Avoid changing the prompting verbiage to
|
||||
preserve its historical behavior; however, structural changes to ensure
|
||||
compilation or simplify the code are permitted.
|
||||
- **Contributions:** Follow the process outlined in `CONTRIBUTING.md`. Requires
|
||||
signing the Google CLA.
|
||||
- **Pull Requests:** Keep PRs small, focused, and linked to an existing issue.
|
||||
Always activate the `pr-creator` skill for PR generation, even when using the
|
||||
`gh` CLI.
|
||||
- **Commit Messages:** Follow the
|
||||
[Conventional Commits](https://www.conventionalcommits.org/) standard.
|
||||
- **Coding Style:** Adhere to existing patterns in `packages/cli` (React/Ink)
|
||||
and `packages/core` (Backend logic).
|
||||
- **Imports:** Use specific imports and avoid restricted relative imports
|
||||
between packages (enforced by ESLint).
|
||||
- **License Headers:** For all new source code files (`.ts`, `.tsx`, `.js`),
|
||||
include the Apache-2.0 license header with the current year. (e.g.,
|
||||
`Copyright 2026 Google LLC`). This is enforced by ESLint.
|
||||
|
||||
## Testing Conventions
|
||||
|
||||
- **Environment Variables:** When testing code that depends on environment
|
||||
variables, use `vi.stubEnv('NAME', 'value')` in `beforeEach` and
|
||||
`vi.unstubAllEnvs()` in `afterEach`. Avoid modifying `process.env` directly as
|
||||
it can lead to test leakage and is less reliable. To "unset" a variable, use
|
||||
an empty string `vi.stubEnv('NAME', '')`.
|
||||
|
||||
## Documentation
|
||||
|
||||
- Always use the `docs-writer` skill when you are asked to write, edit, or
|
||||
review any documentation.
|
||||
- Documentation is located in the `docs/` directory.
|
||||
- Suggest documentation updates when code changes render existing documentation
|
||||
obsolete or incomplete.
|
||||
|
||||
@@ -1,32 +1,45 @@
|
||||
# Gemini CLI
|
||||
|
||||
[](https://github.com/google-gemini/gemini-cli/actions/workflows/ci.yml)
|
||||
[](https://github.com/google-gemini/gemini-cli/actions/workflows/e2e.yml)
|
||||
[](https://github.com/google-gemini/gemini-cli/actions/workflows/chained_e2e.yml)
|
||||
[](https://www.npmjs.com/package/@google/gemini-cli)
|
||||
[](https://github.com/google-gemini/gemini-cli/blob/main/LICENSE)
|
||||
[](https://codewiki.google/github.com/google-gemini/gemini-cli?utm_source=badge&utm_medium=github&utm_campaign=github.com/google-gemini/gemini-cli)
|
||||
|
||||

|
||||
|
||||
Gemini CLI is an open-source AI agent that brings the power of Gemini directly into your terminal. It provides lightweight access to Gemini, giving you the most direct path from your prompt to our model.
|
||||
Gemini CLI is an open-source AI agent that brings the power of Gemini directly
|
||||
into your terminal. It provides lightweight access to Gemini, giving you the
|
||||
most direct path from your prompt to our model.
|
||||
|
||||
Learn all about Gemini CLI in our [documentation](https://geminicli.com/docs/).
|
||||
|
||||
## 🚀 Why Gemini CLI?
|
||||
|
||||
- **🎯 Free tier**: 60 requests/min and 1,000 requests/day with personal Google account
|
||||
- **🧠 Powerful Gemini 2.5 Pro**: Access to 1M token context window
|
||||
- **🔧 Built-in tools**: Google Search grounding, file operations, shell commands, web fetching
|
||||
- **🔌 Extensible**: MCP (Model Context Protocol) support for custom integrations
|
||||
- **💻 Terminal-first**: Designed for developers who live in the command line
|
||||
- **🛡️ Open source**: Apache 2.0 licensed
|
||||
- **🎯 Free tier**: 60 requests/min and 1,000 requests/day with personal Google
|
||||
account.
|
||||
- **🧠 Powerful Gemini 3 models**: Access to improved reasoning and 1M token
|
||||
context window.
|
||||
- **🔧 Built-in tools**: Google Search grounding, file operations, shell
|
||||
commands, web fetching.
|
||||
- **🔌 Extensible**: MCP (Model Context Protocol) support for custom
|
||||
integrations.
|
||||
- **💻 Terminal-first**: Designed for developers who live in the command line.
|
||||
- **🛡️ Open source**: Apache 2.0 licensed.
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
See
|
||||
[Gemini CLI installation, execution, and releases](./docs/get-started/installation.md)
|
||||
for recommended system specifications and a detailed installation guide.
|
||||
|
||||
### Quick Install
|
||||
|
||||
#### Run instantly with npx
|
||||
|
||||
```bash
|
||||
# Using npx (no installation required)
|
||||
npx https://github.com/google-gemini/gemini-cli
|
||||
npx @google/gemini-cli
|
||||
```
|
||||
|
||||
#### Install globally with npm
|
||||
@@ -41,10 +54,22 @@ npm install -g @google/gemini-cli
|
||||
brew install gemini-cli
|
||||
```
|
||||
|
||||
#### System Requirements
|
||||
#### Install globally with MacPorts (macOS)
|
||||
|
||||
- Node.js version 20 or higher
|
||||
- macOS, Linux, or Windows
|
||||
```bash
|
||||
sudo port install gemini-cli
|
||||
```
|
||||
|
||||
#### Install with Anaconda (for restricted environments)
|
||||
|
||||
```bash
|
||||
# Create and activate a new environment
|
||||
conda create -y -n gemini_env -c conda-forge nodejs
|
||||
conda activate gemini_env
|
||||
|
||||
# Install Gemini CLI globally via npm (inside the environment)
|
||||
npm install -g @google/gemini-cli
|
||||
```
|
||||
|
||||
## Release Cadence and Tags
|
||||
|
||||
@@ -52,7 +77,9 @@ See [Releases](./docs/releases.md) for more details.
|
||||
|
||||
### Preview
|
||||
|
||||
New preview releases will be published each week at UTC 2359 on Tuesdays. These releases will not have been fully vetted and may contain regressions or other outstanding issues. Please help us test and install with `preview` tag.
|
||||
New preview releases will be published each week at UTC 2359 on Tuesdays. These
|
||||
releases will not have been fully vetted and may contain regressions or other
|
||||
outstanding issues. Please help us test and install with `preview` tag.
|
||||
|
||||
```bash
|
||||
npm install -g @google/gemini-cli@preview
|
||||
@@ -60,7 +87,9 @@ npm install -g @google/gemini-cli@preview
|
||||
|
||||
### Stable
|
||||
|
||||
- New stable releases will be published each week at UTC 2000 on Tuesdays, this will be the full promotion of last week's `preview` release + any bug fixes and validations. Use `latest` tag.
|
||||
- New stable releases will be published each week at UTC 2000 on Tuesdays, this
|
||||
will be the full promotion of last week's `preview` release + any bug fixes
|
||||
and validations. Use `latest` tag.
|
||||
|
||||
```bash
|
||||
npm install -g @google/gemini-cli@latest
|
||||
@@ -68,7 +97,9 @@ npm install -g @google/gemini-cli@latest
|
||||
|
||||
### Nightly
|
||||
|
||||
- New releases will be published each week at UTC 0000 each day, This will be all changes from the main branch as represented at time of release. It should be assumed there are pending validations and issues. Use `nightly` tag.
|
||||
- New releases will be published each day at UTC 0000. This will be all changes
|
||||
from the main branch as represented at time of release. It should be assumed
|
||||
there are pending validations and issues. Use `nightly` tag.
|
||||
|
||||
```bash
|
||||
npm install -g @google/gemini-cli@nightly
|
||||
@@ -84,24 +115,33 @@ npm install -g @google/gemini-cli@nightly
|
||||
|
||||
### Automation & Integration
|
||||
|
||||
- Automate operational tasks like querying pull requests or handling complex rebases
|
||||
- Use MCP servers to connect new capabilities, including [media generation with Imagen, Veo or Lyria](https://github.com/GoogleCloudPlatform/vertex-ai-creative-studio/tree/main/experiments/mcp-genmedia)
|
||||
- Automate operational tasks like querying pull requests or handling complex
|
||||
rebases
|
||||
- Use MCP servers to connect new capabilities, including
|
||||
[media generation with Imagen, Veo or Lyria](https://github.com/GoogleCloudPlatform/vertex-ai-creative-studio/tree/main/experiments/mcp-genmedia)
|
||||
- Run non-interactively in scripts for workflow automation
|
||||
|
||||
### Advanced Capabilities
|
||||
|
||||
- Ground your queries with built-in [Google Search](https://ai.google.dev/gemini-api/docs/grounding) for real-time information
|
||||
- Ground your queries with built-in
|
||||
[Google Search](https://ai.google.dev/gemini-api/docs/grounding) for real-time
|
||||
information
|
||||
- Conversation checkpointing to save and resume complex sessions
|
||||
- Custom context files (GEMINI.md) to tailor behavior for your projects
|
||||
|
||||
### GitHub Integration
|
||||
|
||||
Integrate Gemini CLI directly into your GitHub workflows with [**Gemini CLI GitHub Action**](https://github.com/google-github-actions/run-gemini-cli):
|
||||
Integrate Gemini CLI directly into your GitHub workflows with
|
||||
[**Gemini CLI GitHub Action**](https://github.com/google-github-actions/run-gemini-cli):
|
||||
|
||||
- **Pull Request Reviews**: Automated code review with contextual feedback and suggestions
|
||||
- **Issue Triage**: Automated labeling and prioritization of GitHub issues based on content analysis
|
||||
- **On-demand Assistance**: Mention `@gemini-cli` in issues and pull requests for help with debugging, explanations, or task delegation
|
||||
- **Custom Workflows**: Build automated, scheduled and on-demand workflows tailored to your team's needs
|
||||
- **Pull Request Reviews**: Automated code review with contextual feedback and
|
||||
suggestions
|
||||
- **Issue Triage**: Automated labeling and prioritization of GitHub issues based
|
||||
on content analysis
|
||||
- **On-demand Assistance**: Mention `@gemini-cli` in issues and pull requests
|
||||
for help with debugging, explanations, or task delegation
|
||||
- **Custom Workflows**: Build automated, scheduled and on-demand workflows
|
||||
tailored to your team's needs
|
||||
|
||||
## 🔐 Authentication Options
|
||||
|
||||
@@ -109,20 +149,17 @@ Choose the authentication method that best fits your needs:
|
||||
|
||||
### Option 1: Login with Google (OAuth login using your Google Account)
|
||||
|
||||
**✨ Best for:**
|
||||
|
||||
- Individual developers.
|
||||
- Google AI Pro and AI Ultra subscribers.
|
||||
- Anyone who has a Gemini Code Assist license.
|
||||
|
||||
_See [quota limits and terms of service](https://cloud.google.com/gemini/docs/quotas) for details._
|
||||
**✨ Best for:** Individual developers as well as anyone who has a Gemini Code
|
||||
Assist License. (see
|
||||
[quota limits and terms of service](https://cloud.google.com/gemini/docs/quotas)
|
||||
for details)
|
||||
|
||||
**Benefits:**
|
||||
|
||||
- **Free tier** with 60 requests/min and 1,000 requests/day
|
||||
- **Gemini 2.5 Pro and Flash** with 1M token context window
|
||||
- **Free tier**: 60 requests/min and 1,000 requests/day
|
||||
- **Gemini 3 models** with 1M token context window
|
||||
- **No API key management** - just sign in with your Google account
|
||||
- **Automatic updates** to our latest models
|
||||
- **Automatic updates** to latest models
|
||||
|
||||
#### Start Gemini CLI, then choose _Login with Google_ and follow the browser authentication flow when prompted
|
||||
|
||||
@@ -134,7 +171,7 @@ gemini
|
||||
|
||||
```bash
|
||||
# Set your Google Cloud Project
|
||||
export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_NAME"
|
||||
export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
|
||||
gemini
|
||||
```
|
||||
|
||||
@@ -144,7 +181,7 @@ gemini
|
||||
|
||||
**Benefits:**
|
||||
|
||||
- **Free tier**: 100 requests/day with Gemini 2.5 Pro
|
||||
- **Free tier**: 1000 requests/day with Gemini 3 (mix of flash and pro)
|
||||
- **Model selection**: Choose specific Gemini models
|
||||
- **Usage-based billing**: Upgrade for higher limits when needed
|
||||
|
||||
@@ -171,7 +208,8 @@ export GOOGLE_GENAI_USE_VERTEXAI=true
|
||||
gemini
|
||||
```
|
||||
|
||||
For Google Workspace accounts and other authentication methods, see the [authentication guide](./docs/cli/authentication.md).
|
||||
For Google Workspace accounts and other authentication methods, see the
|
||||
[authentication guide](./docs/get-started/authentication.md).
|
||||
|
||||
## 🚀 Getting Started
|
||||
|
||||
@@ -210,6 +248,13 @@ the `--output-format json` flag to get structured output:
|
||||
gemini -p "Explain the architecture of this codebase" --output-format json
|
||||
```
|
||||
|
||||
For real-time event streaming (useful for monitoring long-running operations),
|
||||
use `--output-format stream-json` to get newline-delimited JSON events:
|
||||
|
||||
```bash
|
||||
gemini -p "Run tests and deploy" --output-format stream-json
|
||||
```
|
||||
|
||||
### Quick Examples
|
||||
|
||||
#### Start a new project
|
||||
@@ -233,17 +278,26 @@ gemini
|
||||
|
||||
### Getting Started
|
||||
|
||||
- [**Quickstart Guide**](./docs/cli/index.md) - Get up and running quickly
|
||||
- [**Authentication Setup**](./docs/cli/authentication.md) - Detailed auth configuration
|
||||
- [**Configuration Guide**](./docs/cli/configuration.md) - Settings and customization
|
||||
- [**Keyboard Shortcuts**](./docs/keyboard-shortcuts.md) - Productivity tips
|
||||
- [**Quickstart Guide**](./docs/get-started/index.md) - Get up and running
|
||||
quickly.
|
||||
- [**Authentication Setup**](./docs/get-started/authentication.md) - Detailed
|
||||
auth configuration.
|
||||
- [**Configuration Guide**](./docs/get-started/configuration.md) - Settings and
|
||||
customization.
|
||||
- [**Keyboard Shortcuts**](./docs/cli/keyboard-shortcuts.md) - Productivity
|
||||
tips.
|
||||
|
||||
### Core Features
|
||||
|
||||
- [**Commands Reference**](./docs/cli/commands.md) - All slash commands (`/help`, `/chat`, `/mcp`, etc.)
|
||||
- [**Checkpointing**](./docs/checkpointing.md) - Save and resume conversations
|
||||
- [**Memory Management**](./docs/tools/memory.md) - Using GEMINI.md context files
|
||||
- [**Token Caching**](./docs/cli/token-caching.md) - Optimize token usage
|
||||
- [**Commands Reference**](./docs/cli/commands.md) - All slash commands
|
||||
(`/help`, `/chat`, etc).
|
||||
- [**Custom Commands**](./docs/cli/custom-commands.md) - Create your own
|
||||
reusable commands.
|
||||
- [**Context Files (GEMINI.md)**](./docs/cli/gemini-md.md) - Provide persistent
|
||||
context to Gemini CLI.
|
||||
- [**Checkpointing**](./docs/cli/checkpointing.md) - Save and resume
|
||||
conversations.
|
||||
- [**Token Caching**](./docs/cli/token-caching.md) - Optimize token usage.
|
||||
|
||||
### Tools & Extensions
|
||||
|
||||
@@ -251,35 +305,39 @@ gemini
|
||||
- [File System Operations](./docs/tools/file-system.md)
|
||||
- [Shell Commands](./docs/tools/shell.md)
|
||||
- [Web Fetch & Search](./docs/tools/web-fetch.md)
|
||||
- [Multi-file Operations](./docs/tools/multi-file.md)
|
||||
- [**MCP Server Integration**](./docs/tools/mcp-server.md) - Extend with custom tools
|
||||
- [**Custom Extensions**](./docs/extension.md) - Build your own commands
|
||||
- [**MCP Server Integration**](./docs/tools/mcp-server.md) - Extend with custom
|
||||
tools.
|
||||
- [**Custom Extensions**](./docs/extensions/index.md) - Build and share your own
|
||||
commands.
|
||||
|
||||
### Advanced Topics
|
||||
|
||||
- [**Architecture Overview**](./docs/architecture.md) - How Gemini CLI works
|
||||
- [**IDE Integration**](./docs/ide-integration.md) - VS Code companion
|
||||
- [**Sandboxing & Security**](./docs/sandbox.md) - Safe execution environments
|
||||
- [**Enterprise Deployment**](./docs/deployment.md) - Docker, system-wide config
|
||||
- [**Telemetry & Monitoring**](./docs/telemetry.md) - Usage tracking
|
||||
- [**Tools API Development**](./docs/core/tools-api.md) - Create custom tools
|
||||
|
||||
### Configuration & Customization
|
||||
|
||||
- [**Settings Reference**](./docs/cli/configuration.md) - All configuration options
|
||||
- [**Theme Customization**](./docs/cli/themes.md) - Visual customization
|
||||
- [**.gemini Directory**](./docs/gemini-ignore.md) - Project-specific settings
|
||||
- [**Environment Variables**](./docs/cli/configuration.md#environment-variables)
|
||||
- [**Headless Mode (Scripting)**](./docs/cli/headless.md) - Use Gemini CLI in
|
||||
automated workflows.
|
||||
- [**Architecture Overview**](./docs/architecture.md) - How Gemini CLI works.
|
||||
- [**IDE Integration**](./docs/ide-integration/index.md) - VS Code companion.
|
||||
- [**Sandboxing & Security**](./docs/cli/sandbox.md) - Safe execution
|
||||
environments.
|
||||
- [**Trusted Folders**](./docs/cli/trusted-folders.md) - Control execution
|
||||
policies by folder.
|
||||
- [**Enterprise Guide**](./docs/cli/enterprise.md) - Deploy and manage in a
|
||||
corporate environment.
|
||||
- [**Telemetry & Monitoring**](./docs/cli/telemetry.md) - Usage tracking.
|
||||
- [**Tools API Development**](./docs/core/tools-api.md) - Create custom tools.
|
||||
- [**Local development**](./docs/local-development.md) - Local development
|
||||
tooling.
|
||||
|
||||
### Troubleshooting & Support
|
||||
|
||||
- [**Troubleshooting Guide**](./docs/troubleshooting.md) - Common issues and solutions
|
||||
- [**FAQ**](./docs/troubleshooting.md#frequently-asked-questions) - Quick answers
|
||||
- Use `/bug` command to report issues directly from the CLI
|
||||
- [**Troubleshooting Guide**](./docs/troubleshooting.md) - Common issues and
|
||||
solutions.
|
||||
- [**FAQ**](./docs/faq.md) - Frequently asked questions.
|
||||
- Use `/bug` command to report issues directly from the CLI.
|
||||
|
||||
### Using MCP Servers
|
||||
|
||||
Configure MCP servers in `~/.gemini/settings.json` to extend Gemini CLI with custom tools:
|
||||
Configure MCP servers in `~/.gemini/settings.json` to extend Gemini CLI with
|
||||
custom tools:
|
||||
|
||||
```text
|
||||
> @github List my open pull requests
|
||||
@@ -287,36 +345,44 @@ Configure MCP servers in `~/.gemini/settings.json` to extend Gemini CLI with cus
|
||||
> @database Run a query to find inactive users
|
||||
```
|
||||
|
||||
See the [MCP Server Integration guide](./docs/tools/mcp-server.md) for setup instructions.
|
||||
See the [MCP Server Integration guide](./docs/tools/mcp-server.md) for setup
|
||||
instructions.
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
We welcome contributions! Gemini CLI is fully open source (Apache 2.0), and we encourage the community to:
|
||||
We welcome contributions! Gemini CLI is fully open source (Apache 2.0), and we
|
||||
encourage the community to:
|
||||
|
||||
- Report bugs and suggest features
|
||||
- Improve documentation
|
||||
- Submit code improvements
|
||||
- Share your MCP servers and extensions
|
||||
- Report bugs and suggest features.
|
||||
- Improve documentation.
|
||||
- Submit code improvements.
|
||||
- Share your MCP servers and extensions.
|
||||
|
||||
See our [Contributing Guide](./CONTRIBUTING.md) for development setup, coding standards, and how to submit pull requests.
|
||||
See our [Contributing Guide](./CONTRIBUTING.md) for development setup, coding
|
||||
standards, and how to submit pull requests.
|
||||
|
||||
Check our [Official Roadmap](https://github.com/orgs/google-gemini/projects/11/) for planned features and priorities.
|
||||
Check our [Official Roadmap](https://github.com/orgs/google-gemini/projects/11)
|
||||
for planned features and priorities.
|
||||
|
||||
## 📖 Resources
|
||||
|
||||
- **[Official Roadmap](./ROADMAP.md)** - See what's coming next
|
||||
- **[NPM Package](https://www.npmjs.com/package/@google/gemini-cli)** - Package registry
|
||||
- **[GitHub Issues](https://github.com/google-gemini/gemini-cli/issues)** - Report bugs or request features
|
||||
- **[Security Advisories](https://github.com/google-gemini/gemini-cli/security/advisories)** - Security updates
|
||||
- **[Official Roadmap](./ROADMAP.md)** - See what's coming next.
|
||||
- **[Changelog](./docs/changelogs/index.md)** - See recent notable updates.
|
||||
- **[NPM Package](https://www.npmjs.com/package/@google/gemini-cli)** - Package
|
||||
registry.
|
||||
- **[GitHub Issues](https://github.com/google-gemini/gemini-cli/issues)** -
|
||||
Report bugs or request features.
|
||||
- **[Security Advisories](https://github.com/google-gemini/gemini-cli/security/advisories)** -
|
||||
Security updates.
|
||||
|
||||
### Uninstall
|
||||
|
||||
See the [Uninstall Guide](docs/Uninstall.md) for removal instructions.
|
||||
See the [Uninstall Guide](docs/cli/uninstall.md) for removal instructions.
|
||||
|
||||
## 📄 Legal
|
||||
|
||||
- **License**: [Apache License 2.0](LICENSE)
|
||||
- **Terms of Service**: [Terms & Privacy](./docs/tos-privacy.md)
|
||||
- **Terms of Service**: [Terms & Privacy](./docs/resources/tos-privacy.md)
|
||||
- **Security**: [Security Policy](SECURITY.md)
|
||||
|
||||
---
|
||||
|
||||
+79
-29
@@ -1,63 +1,113 @@
|
||||
# Gemini CLI Roadmap
|
||||
|
||||
The [Official Gemini CLI Roadmap](https://github.com/orgs/google-gemini/projects/11/)
|
||||
The
|
||||
[Official Gemini CLI Roadmap](https://github.com/orgs/google-gemini/projects/11/)
|
||||
|
||||
Gemini CLI is an open-source AI agent that brings the power of Gemini directly into your terminal. It provides lightweight access to Gemini, giving you the most direct path from your prompt to our model.
|
||||
Gemini CLI is an open-source AI agent that brings the power of Gemini directly
|
||||
into your terminal. It provides lightweight access to Gemini, giving you the
|
||||
most direct path from your prompt to our model.
|
||||
|
||||
This document outlines our approach to the Gemini CLI roadmap. Here, you'll find our guiding principles and a breakdown of the key areas we are
|
||||
focused on for development. Our roadmap is not a static list but a dynamic set of priorities that are tracked live in our GitHub Issues.
|
||||
This document outlines our approach to the Gemini CLI roadmap. Here, you'll find
|
||||
our guiding principles and a breakdown of the key areas we are focused on for
|
||||
development. Our roadmap is not a static list but a dynamic set of priorities
|
||||
that are tracked live in our GitHub Issues.
|
||||
|
||||
As an [Apache 2.0 open source project](https://github.com/google-gemini/gemini-cli?tab=Apache-2.0-1-ov-file#readme), we appreciate and welcome [public contributions](https://github.com/google-gemini/gemini-cli/blob/main/CONTRIBUTING.md), and will give first priority to those contributions aligned with our roadmap. If you want to propose a new feature or change to our roadmap, please start by [opening an issue for discussion](https://github.com/google-gemini/gemini-cli/issues/new/choose).
|
||||
As an
|
||||
[Apache 2.0 open source project](https://github.com/google-gemini/gemini-cli?tab=Apache-2.0-1-ov-file#readme),
|
||||
we appreciate and welcome
|
||||
[public contributions](https://github.com/google-gemini/gemini-cli/blob/main/CONTRIBUTING.md),
|
||||
and will give first priority to those contributions aligned with our roadmap. If
|
||||
you want to propose a new feature or change to our roadmap, please start by
|
||||
[opening an issue for discussion](https://github.com/google-gemini/gemini-cli/issues/new/choose).
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This roadmap represents our current thinking and is for informational purposes only. It is not a commitment or a guarantee of future delivery. The development, release, and timing of any features are subject to change, and we may update the roadmap based on community discussions as well as when our priorities evolve.
|
||||
This roadmap represents our current thinking and is for informational purposes
|
||||
only. It is not a commitment or a guarantee of future delivery. The development,
|
||||
release, and timing of any features are subject to change, and we may update the
|
||||
roadmap based on community discussions as well as when our priorities evolve.
|
||||
|
||||
## Guiding Principles
|
||||
|
||||
Our development is guided by the following principles:
|
||||
|
||||
- **Power & Simplicity:** Deliver access to state-of-the-art Gemini models with an intuitive and easy-to-use lightweight command-line interface.
|
||||
- **Extensibility:** An adaptable agent to help you with a variety of use cases and environments along with the ability to run these agents anywhere.
|
||||
- **Intelligent:** Gemini CLI should be reliably ranked among the best agentic tools as measured by benchmarks like SWE Bench, Terminal Bench, and CSAT.
|
||||
- **Free and Open Source:** Foster a thriving open source community where cost isn’t a barrier to personal use, and PRs get merged quickly. This means resolving and closing issues, pull requests, and discussion posts quickly.
|
||||
- **Power & Simplicity:** Deliver access to state-of-the-art Gemini models with
|
||||
an intuitive and easy-to-use lightweight command-line interface.
|
||||
- **Extensibility:** An adaptable agent to help you with a variety of use cases
|
||||
and environments along with the ability to run these agents anywhere.
|
||||
- **Intelligent:** Gemini CLI should be reliably ranked among the best agentic
|
||||
tools as measured by benchmarks like SWE Bench, Terminal Bench, and CSAT.
|
||||
- **Free and Open Source:** Foster a thriving open source community where cost
|
||||
isn’t a barrier to personal use, and PRs get merged quickly. This means
|
||||
resolving and closing issues, pull requests, and discussion posts quickly.
|
||||
|
||||
## How the Roadmap Works
|
||||
|
||||
Our roadmap is managed directly through GitHub Issues. See our entry point Roadmap Issue [here](https://github.com/google-gemini/gemini-cli/issues/4191). This approach allows for transparency and gives you a direct way to learn more or get involved with any specific initiative. All our roadmap items will be tagged as Type:`Feature` and Label:`maintainer` for features we are actively working on, or Type:`Task` and Label:`maintainer` for a more detailed list of tasks.
|
||||
Our roadmap is managed directly through GitHub Issues. See our entry point
|
||||
Roadmap Issue [here](https://github.com/google-gemini/gemini-cli/issues/4191).
|
||||
This approach allows for transparency and gives you a direct way to learn more
|
||||
or get involved with any specific initiative. All our roadmap items will be
|
||||
tagged as Type:`Feature` and Label:`maintainer` for features we are actively
|
||||
working on, or Type:`Task` and Label:`maintainer` for a more detailed list of
|
||||
tasks.
|
||||
|
||||
Issues are organized to provide key information at a glance:
|
||||
|
||||
- **Target Quarter:** `Milestone` denotes the anticipated delivery timeline.
|
||||
- **Feature Area:** Labels such as `area/model` or `area/tooling` categorize the work.
|
||||
- **Feature Area:** Labels such as `area/model` or `area/tooling` categorize the
|
||||
work.
|
||||
- **Issue Type:** _Workstream_ => _Epics_ => _Features_ => _Tasks|Bugs_
|
||||
|
||||
To see what we're working on, you can filter our issues by these dimensions. See all our items [here](https://github.com/orgs/google-gemini/projects/11/views/19)
|
||||
To see what we're working on, you can filter our issues by these dimensions. See
|
||||
all our items [here](https://github.com/orgs/google-gemini/projects/11/views/19)
|
||||
|
||||
## Focus Areas
|
||||
|
||||
To better organize our efforts, we categorize our work into several key feature areas. These labels are used on our GitHub Issues to help you filter and
|
||||
find initiatives that interest you.
|
||||
To better organize our efforts, we categorize our work into several key feature
|
||||
areas. These labels are used on our GitHub Issues to help you filter and find
|
||||
initiatives that interest you.
|
||||
|
||||
- **Authentication:** Secure user access via API keys, Gemini Code Assist login, etc.
|
||||
- **Model:** Support new Gemini models, multi-modality, local execution, and performance tuning.
|
||||
- **User Experience:** Improve the CLI's usability, performance, interactive features, and documentation.
|
||||
- **Authentication:** Secure user access via API keys, Gemini Code Assist login,
|
||||
etc.
|
||||
- **Model:** Support new Gemini models, multi-modality, local execution, and
|
||||
performance tuning.
|
||||
- **User Experience:** Improve the CLI's usability, performance, interactive
|
||||
features, and documentation.
|
||||
- **Tooling:** Built-in tools and the MCP ecosystem.
|
||||
- **Core:** Core functionality of the CLI
|
||||
- **Extensibility:** Bringing Gemini CLI to other surfaces e.g. GitHub.
|
||||
- **Contribution:** Improve the contribution process via test automation and CI/CD pipeline enhancements.
|
||||
- **Platform:** Manage installation, OS support, and the underlying CLI framework.
|
||||
- **Quality:** Focus on testing, reliability, performance, and overall product quality.
|
||||
- **Background Agents:** Enable long-running, autonomous tasks and proactive assistance.
|
||||
- **Contribution:** Improve the contribution process via test automation and
|
||||
CI/CD pipeline enhancements.
|
||||
- **Platform:** Manage installation, OS support, and the underlying CLI
|
||||
framework.
|
||||
- **Quality:** Focus on testing, reliability, performance, and overall product
|
||||
quality.
|
||||
- **Background Agents:** Enable long-running, autonomous tasks and proactive
|
||||
assistance.
|
||||
- **Security and Privacy:** For all things related to security and privacy
|
||||
|
||||
## How to Contribute
|
||||
|
||||
Gemini CLI is an open-source project, and we welcome contributions from the community! Whether you're a developer, a designer, or just an enthusiastic user you can find our [Community Guidelines here](https://github.com/google-gemini/gemini-cli/blob/main/CONTRIBUTING.md) to learn how to get started. There are many ways to get involved:
|
||||
Gemini CLI is an open-source project, and we welcome contributions from the
|
||||
community! Whether you're a developer, a designer, or just an enthusiastic user
|
||||
you can find our
|
||||
[Community Guidelines here](https://github.com/google-gemini/gemini-cli/blob/main/CONTRIBUTING.md)
|
||||
to learn how to get started. There are many ways to get involved:
|
||||
|
||||
- **Roadmap:** Please review and find areas in our [roadmap](https://github.com/google-gemini/gemini-cli/issues/4191) that you would like to contribute to. Contributions based on this will be easiest to integrate with.
|
||||
- **Report Bugs:** If you find an issue, please create a [bug](https://github.com/google-gemini/gemini-cli/issues/new?template=bug_report.yml) with as much detail as possible. If you believe it is a critical breaking issue preventing direct CLI usage, please tag it as `priority/p0`.
|
||||
- **Suggest Features:** Have a great idea? We'd love to hear it! Open a [feature request](https://github.com/google-gemini/gemini-cli/issues/new?template=feature_request.yml).
|
||||
- **Contribute Code:** Check out our [CONTRIBUTING.md](https://github.com/google-gemini/gemini-cli/blob/main/CONTRIBUTING.md) file for guidelines on how to submit pull requests. We have a list of "good first issues" for new contributors.
|
||||
- **Write Documentation:** Help us improve our documentation, tutorials, and examples.
|
||||
We are excited about the future of Gemini CLI and look forward to building it with you!
|
||||
- **Roadmap:** Please review and find areas in our
|
||||
[roadmap](https://github.com/google-gemini/gemini-cli/issues/4191) that you
|
||||
would like to contribute to. Contributions based on this will be easiest to
|
||||
integrate with.
|
||||
- **Report Bugs:** If you find an issue, please create a
|
||||
[bug](https://github.com/google-gemini/gemini-cli/issues/new?template=bug_report.yml)
|
||||
with as much detail as possible. If you believe it is a critical breaking
|
||||
issue preventing direct CLI usage, please tag it as `priority/p0`.
|
||||
- **Suggest Features:** Have a great idea? We'd love to hear it! Open a
|
||||
[feature request](https://github.com/google-gemini/gemini-cli/issues/new?template=feature_request.yml).
|
||||
- **Contribute Code:** Check out our
|
||||
[CONTRIBUTING.md](https://github.com/google-gemini/gemini-cli/blob/main/CONTRIBUTING.md)
|
||||
file for guidelines on how to submit pull requests. We have a list of "good
|
||||
first issues" for new contributors.
|
||||
- **Write Documentation:** Help us improve our documentation, tutorials, and
|
||||
examples. We are excited about the future of Gemini CLI and look forward to
|
||||
building it with you!
|
||||
|
||||
+2
-1
@@ -5,4 +5,5 @@ We use g.co/vulnz for our intake, and do coordination and disclosure here on
|
||||
GitHub (including using GitHub Security Advisory). The Google Security Team will
|
||||
respond within 5 working days of your report on g.co/vulnz.
|
||||
|
||||
[GitHub Security Advisory]: https://github.com/google-gemini/gemini-cli/security/advisories
|
||||
[GitHub Security Advisory]:
|
||||
https://github.com/google-gemini/gemini-cli/security/advisories
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../CONTRIBUTING.md
|
||||
@@ -0,0 +1,115 @@
|
||||
# Enterprise Admin Controls
|
||||
|
||||
Gemini CLI empowers enterprise administrators to manage and enforce security
|
||||
policies and configuration settings across their entire organization. Secure
|
||||
defaults are enabled automatically for all enterprise users, but can be
|
||||
customized via the [Management Console](https://goo.gle/manage-gemini-cli).
|
||||
|
||||
**Enterprise Admin Controls are enforced globally and cannot be overridden by
|
||||
users locally**, ensuring a consistent security posture.
|
||||
|
||||
## Admin Controls vs. System Settings
|
||||
|
||||
While [System-wide settings](../cli/settings.md) act as convenient configuration
|
||||
overrides, they can still be modified by users with sufficient privileges. In
|
||||
contrast, admin controls are immutable at the local level, making them the
|
||||
preferred method for enforcing policy.
|
||||
|
||||
## Available Controls
|
||||
|
||||
### Strict Mode
|
||||
|
||||
**Enabled/Disabled** | Default: enabled
|
||||
|
||||
If enabled, users will not be able to enter yolo mode.
|
||||
|
||||
### Extensions
|
||||
|
||||
**Enabled/Disabled** | Default: disabled
|
||||
|
||||
If disabled, users will not be able to use or install extensions. See
|
||||
[Extensions](../extensions/index.md) for more details.
|
||||
|
||||
### MCP
|
||||
|
||||
#### Enabled/Disabled
|
||||
|
||||
**Enabled/Disabled** | Default: disabled
|
||||
|
||||
If disabled, users will not be able to use MCP servers. See
|
||||
[MCP Server Integration](../tools/mcp-server.md) for more details.
|
||||
|
||||
#### MCP Servers (preview)
|
||||
|
||||
**Default**: empty
|
||||
|
||||
Allows administrators to define an explicit allowlist of MCP servers. This
|
||||
guarantees that users can only connect to trusted MCP servers defined by the
|
||||
organization.
|
||||
|
||||
**Allowlist Format:**
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"external-provider": {
|
||||
"url": "https://api.mcp-provider.com",
|
||||
"type": "sse",
|
||||
"trust": true,
|
||||
"includeTools": ["toolA", "toolB"],
|
||||
"excludeTools": []
|
||||
},
|
||||
"internal-corp-tool": {
|
||||
"url": "https://mcp.internal-tool.corp",
|
||||
"type": "http",
|
||||
"includeTools": [],
|
||||
"excludeTools": ["adminTool"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Supported Fields:**
|
||||
|
||||
- `url`: (Required) The full URL of the MCP server endpoint.
|
||||
- `type`: (Required) The connection type (e.g., `sse` or `http`).
|
||||
- `trust`: (Optional) If set to `true`, the server is trusted and tool execution
|
||||
will not require user approval.
|
||||
- `includeTools`: (Optional) An explicit list of tool names to allow. If
|
||||
specified, only these tools will be available.
|
||||
- `excludeTools`: (Optional) A list of tool names to hide. These tools will be
|
||||
blocked.
|
||||
|
||||
**Client Enforcement Logic:**
|
||||
|
||||
- **Empty Allowlist**: If the admin allowlist is empty, the client uses the
|
||||
user’s local configuration as is (unless the MCP toggle above is disabled).
|
||||
- **Active Allowlist**: If the allowlist contains one or more servers, **all
|
||||
locally configured servers not present in the allowlist are ignored**.
|
||||
- **Configuration Merging**: For a server to be active, it must exist in
|
||||
**both** the admin allowlist and the user’s local configuration (matched by
|
||||
name). The client merges these definitions as follows:
|
||||
- **Override Fields**: The `url`, `type`, & `trust` are always taken from the
|
||||
admin allowlist, overriding any local values.
|
||||
- **Tools Filtering**: If `includeTools` or `excludeTools` are defined in the
|
||||
allowlist, the admin’s rules are used exclusively. If both are undefined in
|
||||
the admin allowlist, the client falls back to the user’s local tool
|
||||
settings.
|
||||
- **Cleared Fields**: To ensure security and consistency, the client
|
||||
automatically clears local execution fields (`command`, `args`, `env`,
|
||||
`cwd`, `httpUrl`, `tcp`). This prevents users from overriding the connection
|
||||
method.
|
||||
- **Other Fields**: All other MCP fields are pulled from the user’s local
|
||||
configuration.
|
||||
- **Missing Allowlisted Servers**: If a server appears in the admin allowlist
|
||||
but is missing from the local configuration, it will not be initialized. This
|
||||
ensures users maintain final control over which permitted servers are actually
|
||||
active in their environment.
|
||||
|
||||
### Unmanaged Capabilities
|
||||
|
||||
**Enabled/Disabled** | Default: disabled
|
||||
|
||||
If disabled, users will not be able to use certain features. Currently, this
|
||||
control disables Agent Skills. See [Agent Skills](../cli/skills.md) for more
|
||||
details.
|
||||
@@ -1,54 +0,0 @@
|
||||
# Gemini CLI Architecture Overview
|
||||
|
||||
This document provides a high-level overview of the Gemini CLI's architecture.
|
||||
|
||||
## Core components
|
||||
|
||||
The Gemini CLI is primarily composed of two main packages, along with a suite of tools that can be used by the system in the course of handling command-line input:
|
||||
|
||||
1. **CLI package (`packages/cli`):**
|
||||
- **Purpose:** This contains the user-facing portion of the Gemini CLI, such as handling the initial user input, presenting the final output, and managing the overall user experience.
|
||||
- **Key functions contained in the package:**
|
||||
- [Input processing](./cli/commands.md)
|
||||
- History management
|
||||
- Display rendering
|
||||
- [Theme and UI customization](./cli/themes.md)
|
||||
- [CLI configuration settings](./cli/configuration.md)
|
||||
|
||||
2. **Core package (`packages/core`):**
|
||||
- **Purpose:** This acts as the backend for the Gemini CLI. It receives requests sent from `packages/cli`, orchestrates interactions with the Gemini API, and manages the execution of available tools.
|
||||
- **Key functions contained in the package:**
|
||||
- API client for communicating with the Google Gemini API
|
||||
- Prompt construction and management
|
||||
- Tool registration and execution logic
|
||||
- State management for conversations or sessions
|
||||
- Server-side configuration
|
||||
|
||||
3. **Tools (`packages/core/src/tools/`):**
|
||||
- **Purpose:** These are individual modules that extend the capabilities of the Gemini model, allowing it to interact with the local environment (e.g., file system, shell commands, web fetching).
|
||||
- **Interaction:** `packages/core` invokes these tools based on requests from the Gemini model.
|
||||
|
||||
## Interaction Flow
|
||||
|
||||
A typical interaction with the Gemini CLI follows this flow:
|
||||
|
||||
1. **User input:** The user types a prompt or command into the terminal, which is managed by `packages/cli`.
|
||||
2. **Request to core:** `packages/cli` sends the user's input to `packages/core`.
|
||||
3. **Request processed:** The core package:
|
||||
- Constructs an appropriate prompt for the Gemini API, possibly including conversation history and available tool definitions.
|
||||
- Sends the prompt to the Gemini API.
|
||||
4. **Gemini API response:** The Gemini API processes the prompt and returns a response. This response might be a direct answer or a request to use one of the available tools.
|
||||
5. **Tool execution (if applicable):**
|
||||
- When the Gemini API requests a tool, the core package prepares to execute it.
|
||||
- If the requested tool can modify the file system or execute shell commands, the user is first given details of the tool and its arguments, and the user must approve the execution.
|
||||
- Read-only operations, such as reading files, might not require explicit user confirmation to proceed.
|
||||
- Once confirmed, or if confirmation is not required, the core package executes the relevant action within the relevant tool, and the result is sent back to the Gemini API by the core package.
|
||||
- The Gemini API processes the tool result and generates a final response.
|
||||
6. **Response to CLI:** The core package sends the final response back to the CLI package.
|
||||
7. **Display to user:** The CLI package formats and displays the response to the user in the terminal.
|
||||
|
||||
## Key Design Principles
|
||||
|
||||
- **Modularity:** Separating the CLI (frontend) from the Core (backend) allows for independent development and potential future extensions (e.g., different frontends for the same backend).
|
||||
- **Extensibility:** The tool system is designed to be extensible, allowing new capabilities to be added.
|
||||
- **User experience:** The CLI focuses on providing a rich and interactive terminal experience.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 350 KiB After Width: | Height: | Size: 60 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 110 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
@@ -0,0 +1,799 @@
|
||||
# Gemini CLI release notes
|
||||
|
||||
Gemini CLI has three major release channels: nightly, preview, and stable. For
|
||||
most users, we recommend the stable release.
|
||||
|
||||
On this page, you can find information regarding the current releases and
|
||||
announcements from each release.
|
||||
|
||||
For the full changelog, refer to
|
||||
[Releases - google-gemini/gemini-cli](https://github.com/google-gemini/gemini-cli/releases)
|
||||
on GitHub.
|
||||
|
||||
## Current releases
|
||||
|
||||
| Release channel | Notes |
|
||||
| :-------------------- | :---------------------------------------------- |
|
||||
| Nightly | Nightly release with the most recent changes. |
|
||||
| [Preview](preview.md) | Experimental features ready for early feedback. |
|
||||
| [Stable](latest.md) | Stable, recommended for general use. |
|
||||
|
||||
## Announcements: v0.29.0 - 2026-02-17
|
||||
|
||||
- **Plan Mode:** A new comprehensive planning capability with `/plan`,
|
||||
`enter_plan_mode` tool, and dedicated documentation
|
||||
([#17698](https://github.com/google-gemini/gemini-cli/pull/17698) by @Adib234,
|
||||
[#18324](https://github.com/google-gemini/gemini-cli/pull/18324) by @jerop).
|
||||
- **Gemini 3 Default:** We've removed the preview flag and enabled Gemini 3 by
|
||||
default for all users
|
||||
([#18414](https://github.com/google-gemini/gemini-cli/pull/18414) by
|
||||
@sehoon38).
|
||||
- **Extension Exploration:** New UI and settings to explore and manage
|
||||
extensions more easily
|
||||
([#18686](https://github.com/google-gemini/gemini-cli/pull/18686) by
|
||||
@sripasg).
|
||||
- **Admin Control:** Administrators can now allowlist specific MCP server
|
||||
configurations
|
||||
([#18311](https://github.com/google-gemini/gemini-cli/pull/18311) by
|
||||
@skeshive).
|
||||
|
||||
## Announcements: v0.28.0 - 2026-02-10
|
||||
|
||||
- **Slash Command:** We've added a new `/prompt-suggest` slash command to help
|
||||
you generate prompt suggestions
|
||||
([#17264](https://github.com/google-gemini/gemini-cli/pull/17264) by
|
||||
@NTaylorMullen).
|
||||
- **IDE Support:** Gemini CLI now supports the Positron IDE
|
||||
([#15047](https://github.com/google-gemini/gemini-cli/pull/15047) by
|
||||
@kapsner).
|
||||
- **Customization:** You can now use custom themes in extensions, and we've
|
||||
implemented automatic theme switching based on your terminal's background
|
||||
([#17327](https://github.com/google-gemini/gemini-cli/pull/17327) by
|
||||
@spencer426, [#17976](https://github.com/google-gemini/gemini-cli/pull/17976)
|
||||
by @Abhijit-2592).
|
||||
- **Authentication:** We've added interactive and non-interactive consent for
|
||||
OAuth, and you can now include your auth method in bug reports
|
||||
([#17699](https://github.com/google-gemini/gemini-cli/pull/17699) by
|
||||
@ehedlund, [#17569](https://github.com/google-gemini/gemini-cli/pull/17569) by
|
||||
@erikus).
|
||||
|
||||
## Announcements: v0.27.0 - 2026-02-03
|
||||
|
||||
- **Event-Driven Architecture:** The CLI now uses a new event-driven scheduler
|
||||
for tool execution, resulting in a more responsive and performant experience
|
||||
([#17078](https://github.com/google-gemini/gemini-cli/pull/17078) by
|
||||
@abhipatel12).
|
||||
- **Enhanced User Experience:** This release includes queued tool confirmations,
|
||||
and expandable large text pastes for a smoother workflow.
|
||||
- **New `/rewind` Command:** Easily navigate your session history with the new
|
||||
`/rewind` command
|
||||
([#15720](https://github.com/google-gemini/gemini-cli/pull/15720) by
|
||||
@Adib234).
|
||||
- **Linux Clipboard Support:** You can now paste images on Linux with Wayland
|
||||
and X11 ([#17144](https://github.com/google-gemini/gemini-cli/pull/17144) by
|
||||
@devr0306).
|
||||
|
||||
## Announcements: v0.26.0 - 2026-01-27
|
||||
|
||||
- **Agents and Skills:** We've introduced a new `skill-creator` skill
|
||||
([#16394](https://github.com/google-gemini/gemini-cli/pull/16394) by
|
||||
@NTaylorMullen), enabled agent skills by default, and added a generalist agent
|
||||
to improve task routing
|
||||
([#16638](https://github.com/google-gemini/gemini-cli/pull/16638) by
|
||||
@joshualitt).
|
||||
- **UI/UX Improvements:** You can now "Rewind" through your conversation history
|
||||
([#15717](https://github.com/google-gemini/gemini-cli/pull/15717) by @Adib234)
|
||||
and use a new `/introspect` command for debugging.
|
||||
- **Core and Scheduler Refactoring:** The core scheduler has been significantly
|
||||
refactored to improve performance and reliability
|
||||
([#16895](https://github.com/google-gemini/gemini-cli/pull/16895) by
|
||||
@abhipatel12), and numerous performance and stability fixes have been
|
||||
included.
|
||||
|
||||
## Announcements: v0.25.0 - 2026-01-20
|
||||
|
||||
- **Skills and Agents Improvements:** We've enhanced the `activate_skill` tool,
|
||||
added a new `pr-creator` skill
|
||||
([#16232](https://github.com/google-gemini/gemini-cli/pull/16232) by
|
||||
[@NTaylorMullen](https://github.com/NTaylorMullen)), enabled skills by
|
||||
default, improved the `cli_help` agent
|
||||
([#16100](https://github.com/google-gemini/gemini-cli/pull/16100) by
|
||||
[@scidomino](https://github.com/scidomino)), and added a new `/agents refresh`
|
||||
command ([#16204](https://github.com/google-gemini/gemini-cli/pull/16204) by
|
||||
[@joshualitt](https://github.com/joshualitt)).
|
||||
- **UI/UX Refinements:** You'll notice more transparent feedback for skills
|
||||
([#15954](https://github.com/google-gemini/gemini-cli/pull/15954) by
|
||||
[@NTaylorMullen](https://github.com/NTaylorMullen)), the ability to switch
|
||||
focus between the shell and input with Tab
|
||||
([#14332](https://github.com/google-gemini/gemini-cli/pull/14332) by
|
||||
[@jacob314](https://github.com/jacob314)), and dynamic terminal tab titles
|
||||
([#16378](https://github.com/google-gemini/gemini-cli/pull/16378) by
|
||||
[@NTaylorMullen](https://github.com/NTaylorMullen)).
|
||||
- **Core Functionality & Performance:** This release includes support for
|
||||
built-in agent skills
|
||||
([#16045](https://github.com/google-gemini/gemini-cli/pull/16045) by
|
||||
[@NTaylorMullen](https://github.com/NTaylorMullen)), refined Gemini 3 system
|
||||
instructions ([#16139](https://github.com/google-gemini/gemini-cli/pull/16139)
|
||||
by [@NTaylorMullen](https://github.com/NTaylorMullen)), caching for ignore
|
||||
instances to improve performance
|
||||
([#16185](https://github.com/google-gemini/gemini-cli/pull/16185) by
|
||||
[@EricRahm](https://github.com/EricRahm)), and enhanced retry mechanisms
|
||||
([#16489](https://github.com/google-gemini/gemini-cli/pull/16489) by
|
||||
[@sehoon38](https://github.com/sehoon38)).
|
||||
- **Bug Fixes and Stability:** We've squashed numerous bugs across the CLI,
|
||||
core, and workflows, addressing issues with subagent delegation, unicode
|
||||
character crashes, and sticky header regressions.
|
||||
|
||||
## Announcements: v0.24.0 - 2026-01-14
|
||||
|
||||
- **Agent Skills:** We've introduced significant advancements in Agent Skills.
|
||||
This includes initial documentation and tutorials to help you get started,
|
||||
alongside enhanced support for remote agents, allowing for more distributed
|
||||
and powerful automation within Gemini CLI.
|
||||
([#15869](https://github.com/google-gemini/gemini-cli/pull/15869) by
|
||||
[@NTaylorMullen](https://github.com/NTaylorMullen)),
|
||||
([#16013](https://github.com/google-gemini/gemini-cli/pull/16013) by
|
||||
[@adamweidman](https://github.com/adamweidman))
|
||||
- **Improved UI/UX:** The user interface has received several updates, featuring
|
||||
visual indicators for hook execution, a more refined display for settings, and
|
||||
the ability to use the Tab key to effortlessly switch focus between the shell
|
||||
and input areas.
|
||||
([#15408](https://github.com/google-gemini/gemini-cli/pull/15408) by
|
||||
[@abhipatel12](https://github.com/abhipatel12)),
|
||||
([#14332](https://github.com/google-gemini/gemini-cli/pull/14332) by
|
||||
[@galz10](https://github.com/galz10))
|
||||
- **Enhanced Security:** Security has been a major focus, with default folder
|
||||
trust now set to untrusted for increased safety. The Policy Engine has been
|
||||
improved to allow specific modes in user and administrator policies, and
|
||||
granular allowlisting for shell commands has been implemented, providing finer
|
||||
control over tool execution.
|
||||
([#15943](https://github.com/google-gemini/gemini-cli/pull/15943) by
|
||||
[@galz10](https://github.com/galz10)),
|
||||
([#15977](https://github.com/google-gemini/gemini-cli/pull/15977) by
|
||||
[@NTaylorMullen](https://github.com/NTaylorMullen))
|
||||
- **Core Functionality:** This release includes a mandatory MessageBus
|
||||
injection, marking Phase 3 of a hard migration to a more robust internal
|
||||
communication system. We've also added support for built-in skills with the
|
||||
CLI itself, and enhanced model routing to effectively utilize subagents.
|
||||
([#15776](https://github.com/google-gemini/gemini-cli/pull/15776) by
|
||||
[@abhipatel12](https://github.com/abhipatel12)),
|
||||
([#16300](https://github.com/google-gemini/gemini-cli/pull/16300) by
|
||||
[@NTaylorMullen](https://github.com/NTaylorMullen))
|
||||
- **Terminal Features:** Terminal interactions are more seamless with new
|
||||
features like OSC 52 paste support, along with fixes for Windows clipboard
|
||||
paste issues and general improvements to pasting in Windows terminals.
|
||||
([#15336](https://github.com/google-gemini/gemini-cli/pull/15336) by
|
||||
[@scidomino](https://github.com/scidomino)),
|
||||
([#15932](https://github.com/google-gemini/gemini-cli/pull/15932) by
|
||||
[@scidomino](https://github.com/scidomino))
|
||||
- **New Commands:** To manage the new features, we've added several new
|
||||
commands: `/agents refresh` to update agent configurations, `/skills reload`
|
||||
to refresh skill definitions, and `/skills install/uninstall` for easier
|
||||
management of your Agent Skills.
|
||||
([#16204](https://github.com/google-gemini/gemini-cli/pull/16204) by
|
||||
[@NTaylorMullen](https://github.com/NTaylorMullen)),
|
||||
([#15865](https://github.com/google-gemini/gemini-cli/pull/15865) by
|
||||
[@NTaylorMullen](https://github.com/NTaylorMullen)),
|
||||
([#16377](https://github.com/google-gemini/gemini-cli/pull/16377) by
|
||||
[@NTaylorMullen](https://github.com/NTaylorMullen))
|
||||
|
||||
## Announcements: v0.23.0 - 2026-01-07
|
||||
|
||||
- 🎉 **Experimental Agent Skills Support in Preview:** Gemini CLI now supports
|
||||
[Agent Skills](https://agentskills.io/home) in our preview builds. This is an
|
||||
early preview where we’re looking for feedback!
|
||||
- Install Preview: `npm install -g @google/gemini-cli@preview`
|
||||
- Enable in `/settings`
|
||||
- Docs:
|
||||
[https://geminicli.com/docs/cli/skills/](https://geminicli.com/docs/cli/skills/)
|
||||
- **Gemini CLI wrapped:** Run `npx gemini-wrapped` to visualize your usage
|
||||
stats, top models, languages, and more!
|
||||
- **Windows clipboard image support:** Windows users can now paste images
|
||||
directly from their clipboard into the CLI using `Alt`+`V`.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/13997) by
|
||||
[@sgeraldes](https://github.com/sgeraldes))
|
||||
- **Terminal background color detection:** Automatically optimizes your
|
||||
terminal's background color to select compatible themes and provide
|
||||
accessibility warnings.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/15132) by
|
||||
[@jacob314](https://github.com/jacob314))
|
||||
- **Session logout:** Use the new `/logout` command to instantly clear
|
||||
credentials and reset your authentication state for seamless account
|
||||
switching. ([pr](https://github.com/google-gemini/gemini-cli/pull/13383) by
|
||||
[@CN-Scars](https://github.com/CN-Scars))
|
||||
|
||||
## Announcements: v0.22.0 - 2025-12-22
|
||||
|
||||
- 🎉**Free Tier + Gemini 3:** Free tier users now all have access to Gemini 3
|
||||
Pro & Flash. Enable in `/settings` by toggling "Preview Features" to `true`.
|
||||
- 🎉**Gemini CLI + Colab:** Gemini CLI is now pre-installed. Can be used
|
||||
headlessly in notebook cells or interactively in the built-in terminal
|
||||
([pic](https://imgur.com/a/G0Tn7vi))
|
||||
- 🎉**Gemini CLI Extensions:**
|
||||
- **Conductor:** Planning++, Gemini works with you to build out a detailed
|
||||
plan, pull in extra details as needed, ultimately to give the LLM guardrails
|
||||
with artifacts. Measure twice, implement once!
|
||||
|
||||
`gemini extensions install https://github.com/gemini-cli-extensions/conductor`
|
||||
|
||||
Blog:
|
||||
[https://developers.googleblog.com/conductor-introducing-context-driven-development-for-gemini-cli/](https://developers.googleblog.com/conductor-introducing-context-driven-development-for-gemini-cli/)
|
||||
|
||||
- **Endor Labs:** Perform code analysis, vulnerability scanning, and
|
||||
dependency checks using natural language.
|
||||
|
||||
`gemini extensions install https://github.com/endorlabs/gemini-extension`
|
||||
|
||||
## Announcements: v0.21.0 - 2025-12-15
|
||||
|
||||
- **⚡️⚡️⚡️ Gemini 3 Flash + Gemini CLI:** Better, faster and cheaper than 2.5
|
||||
Pro - and in some scenarios better than 3 Pro! For paid tiers + free tier
|
||||
users who were on the wait list enable **Preview Features** in `/settings.`
|
||||
- For more information:
|
||||
[Gemini 3 Flash is now available in Gemini CLI](https://developers.googleblog.com/gemini-3-flash-is-now-available-in-gemini-cli/).
|
||||
- 🎉 Gemini CLI Extensions:
|
||||
- Rill: Utilize natural language to analyze Rill data, enabling the
|
||||
exploration of metrics and trends without the need for manual queries.
|
||||
`gemini extensions install https://github.com/rilldata/rill-gemini-extension`
|
||||
- Browserbase: Interact with web pages, take screenshots, extract information,
|
||||
and perform automated actions with atomic precision.
|
||||
`gemini extensions install https://github.com/browserbase/mcp-server-browserbase`
|
||||
- Quota Visibility: The `/stats` command now displays quota information for all
|
||||
available models, including those not used in the current session. (@sehoon38)
|
||||
- Fuzzy Setting Search: Users can now quickly find settings using fuzzy search
|
||||
within the settings dialog. (@sehoon38)
|
||||
- MCP Resource Support: Users can now discover, view, and search through
|
||||
resources using the @ command. (@MrLesk)
|
||||
- Auto-execute Simple Slash Commands: Simple slash commands are now executed
|
||||
immediately on enter. (@jackwotherspoon)
|
||||
|
||||
## Announcements: v0.20.0 - 2025-12-01
|
||||
|
||||
- **Multi-file Drag & Drop:** Users can now drag and drop multiple files into
|
||||
the terminal, and the CLI will automatically prefix each valid path with `@`.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/14832) by
|
||||
[@jackwotherspoon](https://github.com/jackwotherspoon))
|
||||
- **Persistent "Always Allow" Policies:** Users can now save "Always Allow"
|
||||
decisions for tool executions, with granular control over specific shell
|
||||
commands and multi-cloud platform tools.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/14737) by
|
||||
[@allenhutchison](https://github.com/allenhutchison))
|
||||
|
||||
## Announcements: v0.19.0 - 2025-11-24
|
||||
|
||||
- 🎉 **New extensions:**
|
||||
- **Eleven Labs:** Create, play, manage your audio play tracks with the Eleven
|
||||
Labs Gemini CLI extension:
|
||||
`gemini extensions install https://github.com/elevenlabs/elevenlabs-mcp`
|
||||
- **Zed integration:** Users can now leverage Gemini 3 within the Zed
|
||||
integration after enabling "Preview Features" in their CLI’s `/settings`.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/13398) by
|
||||
[@benbrandt](https://github.com/benbrandt))
|
||||
- **Interactive shell:**
|
||||
- **Click-to-Focus:** When "Use Alternate Buffer" setting is enabled, users
|
||||
can click within the embedded shell output to focus it for input.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/13341) by
|
||||
[@galz10](https://github.com/galz10))
|
||||
- **Loading phrase:** Clearly indicates when the interactive shell is awaiting
|
||||
user input. ([vid](https://imgur.com/a/kjK8bUK),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/12535) by
|
||||
[@jackwotherspoon](https://github.com/jackwotherspoon))
|
||||
|
||||
## Announcements: v0.18.0 - 2025-11-17
|
||||
|
||||
- 🎉 **New extensions:**
|
||||
- **Google Workspace**: Integrate Gemini CLI with your Workspace data. Write
|
||||
docs, build slides, chat with others or even get your calc on in sheets:
|
||||
`gemini extensions install https://github.com/gemini-cli-extensions/workspace`
|
||||
- Blog:
|
||||
[https://allen.hutchison.org/2025/11/19/bringing-the-office-to-the-terminal/](https://allen.hutchison.org/2025/11/19/bringing-the-office-to-the-terminal/)
|
||||
- **Redis:** Manage and search data in Redis with natural language:
|
||||
`gemini extensions install https://github.com/redis/mcp-redis`
|
||||
- **Anomalo:** Query your data warehouse table metadata and quality status
|
||||
through commands and natural language:
|
||||
`gemini extensions install https://github.com/datagravity-ai/anomalo-gemini-extension`
|
||||
- **Experimental permission improvements:** We are now experimenting with a new
|
||||
policy engine in Gemini CLI. This allows users and administrators to create
|
||||
fine-grained policy for tool calls. Currently behind a flag. See
|
||||
[policy engine documentation](../reference/policy-engine.md) for more
|
||||
information.
|
||||
- Blog:
|
||||
[https://allen.hutchison.org/2025/11/26/the-guardrails-of-autonomy/](https://allen.hutchison.org/2025/11/26/the-guardrails-of-autonomy/)
|
||||
- **Gemini 3 support for paid:** Gemini 3 support has been rolled out to all API
|
||||
key, Google AI Pro or Google AI Ultra (for individuals, not businesses) and
|
||||
Gemini Code Assist Enterprise users. Enable it via `/settings` and toggling on
|
||||
**Preview Features**.
|
||||
- **Updated UI rollback:** We’ve temporarily rolled back our updated UI to give
|
||||
it more time to bake. This means for a time you won’t have embedded scrolling
|
||||
or mouse support. You can re-enable with `/settings` -> **Use Alternate Screen
|
||||
Buffer** -> `true`.
|
||||
- **Model in history:** Users can now toggle in `/settings` to display model in
|
||||
their chat history. ([gif](https://imgur.com/a/uEmNKnQ),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/13034) by
|
||||
[@scidomino](https://github.com/scidomino))
|
||||
- **Multi-uninstall:** Users can now uninstall multiple extensions with a single
|
||||
command. ([pic](https://imgur.com/a/9Dtq8u2),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/13016) by
|
||||
[@JayadityaGit](https://github.com/JayadityaGit))
|
||||
|
||||
## Announcements: v0.16.0 - 2025-11-10
|
||||
|
||||
- **Gemini 3 + Gemini CLI:** launch 🚀🚀🚀
|
||||
- **Data Commons Gemini CLI Extension** - A new Data Commons Gemini CLI
|
||||
extension that lets you query open-source statistical data from
|
||||
datacommons.org. **To get started, you'll need a Data Commons API key and uv
|
||||
installed**. These and other details to get you started with the extension can
|
||||
be found at
|
||||
[https://github.com/gemini-cli-extensions/datacommons](https://github.com/gemini-cli-extensions/datacommons).
|
||||
|
||||
## Announcements: v0.15.0 - 2025-11-03
|
||||
|
||||
- **🎉 Seamless scrollable UI and mouse support:** We’ve given Gemini CLI a
|
||||
major facelift to make your terminal experience smoother and much more
|
||||
polished. You now get a flicker-free display with sticky headers that keep
|
||||
important context visible and a stable input prompt that doesn't jump around.
|
||||
We even added mouse support so you can click right where you need to type!
|
||||
([gif](https://imgur.com/a/O6qc7bx),
|
||||
[@jacob314](https://github.com/jacob314)).
|
||||
- **Announcement:**
|
||||
[https://developers.googleblog.com/en/making-the-terminal-beautiful-one-pixel-at-a-time/](https://developers.googleblog.com/en/making-the-terminal-beautiful-one-pixel-at-a-time/)
|
||||
- **🎉 New partner extensions:**
|
||||
- **Arize:** Seamlessly instrument AI applications with Arize AX and grant
|
||||
direct access to Arize support:
|
||||
|
||||
`gemini extensions install https://github.com/Arize-ai/arize-tracing-assistant`
|
||||
|
||||
- **Chronosphere:** Retrieve logs, metrics, traces, events, and specific
|
||||
entities:
|
||||
|
||||
`gemini extensions install https://github.com/chronosphereio/chronosphere-mcp`
|
||||
|
||||
- **Transmit:** Comprehensive context, validation, and automated fixes for
|
||||
creating production-ready authentication and identity workflows:
|
||||
|
||||
`gemini extensions install https://github.com/TransmitSecurity/transmit-security-journey-builder`
|
||||
|
||||
- **Todo planning:** Complex questions now get broken down into todo lists that
|
||||
the model can manage and check off. ([gif](https://imgur.com/a/EGDfNlZ),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/12905) by
|
||||
[@anj-s](https://github.com/anj-s))
|
||||
- **Disable GitHub extensions:** Users can now prevent the installation and
|
||||
loading of extensions from GitHub.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/12838) by
|
||||
[@kevinjwang1](https://github.com/kevinjwang1)).
|
||||
- **Extensions restart:** Users can now explicitly restart extensions using the
|
||||
`/extensions restart` command.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/12739) by
|
||||
[@jakemac53](https://github.com/jakemac53)).
|
||||
- **Better Angular support:** Angular workflows should now be more seamless
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/10252) by
|
||||
[@MarkTechson](https://github.com/MarkTechson)).
|
||||
- **Validate command:** Users can now check that local extensions are formatted
|
||||
correctly. ([pr](https://github.com/google-gemini/gemini-cli/pull/12186) by
|
||||
[@kevinjwang1](https://github.com/kevinjwang1)).
|
||||
|
||||
## Announcements: v0.12.0 - 2025-10-27
|
||||
|
||||

|
||||
|
||||
- **🎉 New partner extensions:**
|
||||
- **🤗 Hugging Face extension:** Access the Hugging Face hub.
|
||||
([gif](https://drive.google.com/file/d/1LEzIuSH6_igFXq96_tWev11svBNyPJEB/view?usp=sharing&resourcekey=0-LtPTzR1woh-rxGtfPzjjfg))
|
||||
|
||||
`gemini extensions install https://github.com/huggingface/hf-mcp-server`
|
||||
|
||||
- **Monday.com extension**: Analyze your sprints, update your task boards,
|
||||
etc.
|
||||
([gif](https://drive.google.com/file/d/1cO0g6kY1odiBIrZTaqu5ZakaGZaZgpQv/view?usp=sharing&resourcekey=0-xEr67SIjXmAXRe1PKy7Jlw))
|
||||
|
||||
`gemini extensions install https://github.com/mondaycom/mcp`
|
||||
|
||||
- **Data Commons extension:** Query public datasets or ground responses on
|
||||
data from Data Commons
|
||||
([gif](https://drive.google.com/file/d/1cuj-B-vmUkeJnoBXrO_Y1CuqphYc6p-O/view?usp=sharing&resourcekey=0-0adXCXDQEd91ZZW63HbW-Q)).
|
||||
|
||||
`gemini extensions install https://github.com/gemini-cli-extensions/datacommons`
|
||||
|
||||
- **Model selection:** Choose the Gemini model for your session with `/model`.
|
||||
([pic](https://imgur.com/a/ABFcWWw),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/8940) by
|
||||
[@abhipatel12](https://github.com/abhipatel12)).
|
||||
- **Model routing:** Gemini CLI will now intelligently pick the best model for
|
||||
the task. Simple queries will be sent to Flash while complex analytical or
|
||||
creative tasks will still use the power of Pro. This ensures your quota will
|
||||
last for a longer period of time. You can always opt-out of this via `/model`.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/9262) by
|
||||
[@abhipatel12](https://github.com/abhipatel12)).
|
||||
- Discussion:
|
||||
[https://github.com/google-gemini/gemini-cli/discussions/12375](https://github.com/google-gemini/gemini-cli/discussions/12375)
|
||||
- **Codebase investigator subagent:** We now have a new built-in subagent that
|
||||
will explore your workspace and resolve relevant information to improve
|
||||
overall performance.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/9988) by
|
||||
[@abhipatel12](https://github.com/abhipatel12),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/10282) by
|
||||
[@silviojr](https://github.com/silviojr)).
|
||||
- Enable, disable, or limit turns in `/settings`, plus advanced configs in
|
||||
`settings.json` ([pic](https://imgur.com/a/yJiggNO),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/10844) by
|
||||
[@silviojr](https://github.com/silviojr)).
|
||||
- **Explore extensions with `/extension`:** Users can now open the extensions
|
||||
page in their default browser directly from the CLI using the `/extension`
|
||||
explore command. ([pr](https://github.com/google-gemini/gemini-cli/pull/11846)
|
||||
by [@JayadityaGit](https://github.com/JayadityaGit)).
|
||||
- **Configurable compression:** Users can modify the compression threshold in
|
||||
`/settings`. The default has been made more proactive
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/12317) by
|
||||
[@scidomino](https://github.com/scidomino)).
|
||||
- **API key authentication:** Users can now securely enter and store their
|
||||
Gemini API key via a new dialog, eliminating the need for environment
|
||||
variables and repeated entry.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/11760) by
|
||||
[@galz10](https://github.com/galz10)).
|
||||
- **Sequential approval:** Users can now approve multiple tool calls
|
||||
sequentially during execution.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/11593) by
|
||||
[@joshualitt](https://github.com/joshualitt)).
|
||||
|
||||
## Announcements: v0.11.0 - 2025-10-20
|
||||
|
||||

|
||||
|
||||
- 🎉 **Gemini CLI Jules Extension:** Use Gemini CLI to orchestrate Jules. Spawn
|
||||
remote workers, delegate tedious tasks, or check in on running jobs!
|
||||
- Install:
|
||||
`gemini extensions install https://github.com/gemini-cli-extensions/jules`
|
||||
- Announcement:
|
||||
[https://developers.googleblog.com/en/introducing-the-jules-extension-for-gemini-cli/](https://developers.googleblog.com/en/introducing-the-jules-extension-for-gemini-cli/)
|
||||
- **Stream JSON output:** Stream real-time JSONL events with
|
||||
`--output-format stream-json` to monitor AI agent progress when run
|
||||
headlessly. ([gif](https://imgur.com/a/0UCE81X),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/10883) by
|
||||
[@anj-s](https://github.com/anj-s))
|
||||
- **Markdown toggle:** Users can now switch between rendered and raw markdown
|
||||
display using `alt+m `or` ctrl+m`. ([gif](https://imgur.com/a/lDNdLqr),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/10383) by
|
||||
[@srivatsj](https://github.com/srivatsj))
|
||||
- **Queued message editing:** Users can now quickly edit queued messages by
|
||||
pressing the up arrow key when the input is empty.
|
||||
([gif](https://imgur.com/a/ioRslLd),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/10392) by
|
||||
[@akhil29](https://github.com/akhil29))
|
||||
- **JSON web fetch**: Non-HTML content like JSON APIs or raw source code are now
|
||||
properly shown to the model (previously only supported HTML)
|
||||
([gif](https://imgur.com/a/Q58U4qJ),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/11284) by
|
||||
[@abhipatel12](https://github.com/abhipatel12))
|
||||
- **Non-interactive MCP commands:** Users can now run MCP slash commands in
|
||||
non-interactive mode `gemini "/some-mcp-prompt"`.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/10194) by
|
||||
[@capachino](https://github.com/capachino))
|
||||
- **Removal of deprecated flags:** We’ve finally removed a number of deprecated
|
||||
flags to cleanup Gemini CLI’s invocation profile:
|
||||
- `--all-files` / `-a` in favor of `@` from within Gemini CLI.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/11228) by
|
||||
[@allenhutchison](https://github.com/allenhutchison))
|
||||
- `--telemetry-*` flags in favor of
|
||||
[environment variables](https://github.com/google-gemini/gemini-cli/pull/11318)
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/11318) by
|
||||
[@allenhutchison](https://github.com/allenhutchison))
|
||||
|
||||
## Announcements: v0.10.0 - 2025-10-13
|
||||
|
||||
- **Polish:** The team has been heads down bug fixing and investing heavily into
|
||||
polishing existing flows, tools, and interactions.
|
||||
- **Interactive Shell Tool calling:** Gemini CLI can now also execute
|
||||
interactive tools if needed
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/11225) by
|
||||
[@galz10](https://github.com/galz10)).
|
||||
- **Alt+Key support:** Enables broader support for Alt+Key keyboard shortcuts
|
||||
across different terminals.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/10767) by
|
||||
[@srivatsj](https://github.com/srivatsj)).
|
||||
- **Telemetry Diff stats:** Track line changes made by the model and user during
|
||||
file operations via OTEL.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/10819) by
|
||||
[@jerop](https://github.com/jerop)).
|
||||
|
||||
## Announcements: v0.9.0 - 2025-10-06
|
||||
|
||||
- 🎉 **Interactive Shell:** Run interactive commands like `vim`, `rebase -i`, or
|
||||
even `gemini` 😎 directly in Gemini CLI:
|
||||
- Blog:
|
||||
[https://developers.googleblog.com/en/say-hello-to-a-new-level-of-interactivity-in-gemini-cli/](https://developers.googleblog.com/en/say-hello-to-a-new-level-of-interactivity-in-gemini-cli/)
|
||||
- **Install pre-release extensions:** Install the latest `--pre-release`
|
||||
versions of extensions. Used for when an extension’s release hasn’t been
|
||||
marked as "latest".
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/10752) by
|
||||
[@jakemac53](https://github.com/jakemac53))
|
||||
- **Simplified extension creation:** Create a new, empty extension. Templates
|
||||
are no longer required.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/10629) by
|
||||
[@chrstnb](https://github.com/chrstnb))
|
||||
- **OpenTelemetry GenAI metrics:** Aligns telemetry with industry-standard
|
||||
semantic conventions for improved interoperability.
|
||||
([spec](https://opentelemetry.io/docs/concepts/semantic-conventions/),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/10343) by
|
||||
[@jerop](https://github.com/jerop))
|
||||
- **List memory files:** Quickly find the location of your long-term memory
|
||||
files with `/memory list`.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/10108) by
|
||||
[@sgnagnarella](https://github.com/sgnagnarella))
|
||||
|
||||
## Announcements: v0.8.0 - 2025-09-29
|
||||
|
||||
- 🎉 **Announcing Gemini CLI Extensions** 🎉
|
||||
- Completely customize your Gemini CLI experience to fit your workflow.
|
||||
- Build and share your own Gemini CLI extensions with the world.
|
||||
- Launching with a growing catalog of community, partner, and Google-built
|
||||
extensions.
|
||||
- Check extensions from
|
||||
[key launch partners](https://github.com/google-gemini/gemini-cli/discussions/10718).
|
||||
- Easy install:
|
||||
- `gemini extensions install <github url|folder path>`
|
||||
- Easy management:
|
||||
- `gemini extensions install|uninstall|link`
|
||||
- `gemini extensions enable|disable`
|
||||
- `gemini extensions list|update|new`
|
||||
- Or use commands while running with `/extensions list|update`.
|
||||
- Everything you need to know:
|
||||
[Now open for building: Introducing Gemini CLI extensions](https://blog.google/technology/developers/gemini-cli-extensions/).
|
||||
- 🎉 **Our New Home Page & Better Documentation** 🎉
|
||||
- Check out our new home page for better getting started material, reference
|
||||
documentation, extensions and more!
|
||||
- _Homepage:_ [https://geminicli.com](https://geminicli.com)
|
||||
- ‼️*NEW documentation:*
|
||||
[https://geminicli.com/docs](https://geminicli.com/docs) (Have any
|
||||
[suggestions](https://github.com/google-gemini/gemini-cli/discussions/8722)?)
|
||||
- _Extensions:_
|
||||
[https://geminicli.com/extensions](https://geminicli.com/extensions)
|
||||
- **Non-Interactive Allowed Tools:** `--allowed-tools` will now also work in
|
||||
non-interactive mode.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/9114) by
|
||||
[@mistergarrison](https://github.com/mistergarrison))
|
||||
- **Terminal Title Status:** See the CLI's real-time status and thoughts
|
||||
directly in the terminal window's title by setting `showStatusInTitle: true`.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/4386) by
|
||||
[@Fridayxiao](https://github.com/Fridayxiao))
|
||||
- **Small features, polish, reliability & bug fixes:** A large amount of
|
||||
changes, smaller features, UI updates, reliability and bug fixes + general
|
||||
polish made it in this week!
|
||||
|
||||
## Announcements: v0.7.0 - 2025-09-22
|
||||
|
||||
- 🎉**Build your own Gemini CLI IDE plugin:** We've published a spec for
|
||||
creating IDE plugins to enable rich context-aware experiences and native
|
||||
in-editor diffing in your IDE of choice.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/8479) by
|
||||
[@skeshive](https://github.com/skeshive))
|
||||
- 🎉 **Gemini CLI extensions**
|
||||
- **Flutter:** An early version to help you create, build, test, and run
|
||||
Flutter apps with Gemini CLI
|
||||
([extension](https://github.com/gemini-cli-extensions/flutter))
|
||||
- **nanobanana:** Integrate nanobanana into Gemini CLI
|
||||
([extension](https://github.com/gemini-cli-extensions/nanobanana))
|
||||
- **Telemetry config via environment:** Manage telemetry settings using
|
||||
environment variables for a more flexible setup.
|
||||
([docs](https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/telemetry.md#configuration),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/9113) by
|
||||
[@jerop](https://github.com/jerop))
|
||||
- **Experimental todos:** Track and display progress on complex tasks with a
|
||||
managed checklist. Off by default but can be enabled via
|
||||
`"useWriteTodos": true`
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/8761) by
|
||||
[@anj-s](https://github.com/anj-s))
|
||||
- **Share chat support for tools:** Using `/chat share` will now also render
|
||||
function calls and responses in the final markdown file.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/8693) by
|
||||
[@rramkumar1](https://github.com/rramkumar1))
|
||||
- **Citations:** Now enabled for all users
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/8570) by
|
||||
[@scidomino](https://github.com/scidomino))
|
||||
- **Custom commands in Headless Mode:** Run custom slash commands directly from
|
||||
the command line in non-interactive mode: `gemini "/joke Chuck Norris"`
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/8305) by
|
||||
[@capachino](https://github.com/capachino))
|
||||
- **Small features, polish, reliability & bug fixes:** A large amount of
|
||||
changes, smaller features, UI updates, reliability and bug fixes + general
|
||||
polish made it in this week!
|
||||
|
||||
## Announcements: v0.6.0 - 2025-09-15
|
||||
|
||||
- 🎉 **Higher limits for Google AI Pro and Ultra subscribers:** We’re psyched to
|
||||
finally announce that Google AI Pro and AI Ultra subscribers now get access to
|
||||
significantly higher 2.5 quota limits for Gemini CLI!
|
||||
- **Announcement:**
|
||||
[https://blog.google/technology/developers/gemini-cli-code-assist-higher-limits/](https://blog.google/technology/developers/gemini-cli-code-assist-higher-limits/)
|
||||
- 🎉**Gemini CLI Databases and BigQuery Extensions:** Connect Gemini CLI to all
|
||||
of your cloud data with Gemini CLI.
|
||||
- Announcement and how to get started with each of the below extensions:
|
||||
[https://cloud.google.com/blog/products/databases/gemini-cli-extensions-for-google-data-cloud?e=48754805](https://cloud.google.com/blog/products/databases/gemini-cli-extensions-for-google-data-cloud?e=48754805)
|
||||
- **AlloyDB:** Interact, manage and observe AlloyDB for PostgreSQL databases
|
||||
([manage](https://github.com/gemini-cli-extensions/alloydb#configuration),
|
||||
[observe](https://github.com/gemini-cli-extensions/alloydb-observability#configuration))
|
||||
- **BigQuery:** Connect and query your BigQuery datasets or utilize a
|
||||
sub-agent for contextual insights
|
||||
([query](https://github.com/gemini-cli-extensions/bigquery-data-analytics#configuration),
|
||||
[sub-agent](https://github.com/gemini-cli-extensions/bigquery-conversational-analytics))
|
||||
- **Cloud SQL:** Interact, manage and observe Cloud SQL for PostgreSQL
|
||||
([manage](https://github.com/gemini-cli-extensions/cloud-sql-postgresql#configuration),[ observe](https://github.com/gemini-cli-extensions/cloud-sql-postgresql-observability#configuration)),
|
||||
Cloud SQL for MySQL
|
||||
([manage](https://github.com/gemini-cli-extensions/cloud-sql-mysql#configuration),[ observe](https://github.com/gemini-cli-extensions/cloud-sql-mysql-observability#configuration))
|
||||
and Cloud SQL for SQL Server
|
||||
([manage](https://github.com/gemini-cli-extensions/cloud-sql-sqlserver#configuration),[ observe](https://github.com/gemini-cli-extensions/cloud-sql-sqlserver-observability#configuration))
|
||||
databases.
|
||||
- **Dataplex:** Discover, manage, and govern data and AI artifacts
|
||||
([extension](https://github.com/gemini-cli-extensions/dataplex#configuration))
|
||||
- **Firestore:** Interact with Firestore databases, collections and documents
|
||||
([extension](https://github.com/gemini-cli-extensions/firestore-native#configuration))
|
||||
- **Looker:** Query data, run Looks and create dashboards
|
||||
([extension](https://github.com/gemini-cli-extensions/looker#configuration))
|
||||
- **MySQL:** Interact with MySQL databases
|
||||
([extension](https://github.com/gemini-cli-extensions/mysql#configuration))
|
||||
- **Postgres:** Interact with PostgreSQL databases
|
||||
([extension](https://github.com/gemini-cli-extensions/postgres#configuration))
|
||||
- **Spanner:** Interact with Spanner databases
|
||||
([extension](https://github.com/gemini-cli-extensions/spanner#configuration))
|
||||
- **SQL Server:** Interact with SQL Server databases
|
||||
([extension](https://github.com/gemini-cli-extensions/sql-server#configuration))
|
||||
- **MCP Toolbox:** Configure and load custom tools for more than 30+ data
|
||||
sources
|
||||
([extension](https://github.com/gemini-cli-extensions/mcp-toolbox#configuration))
|
||||
- **JSON output mode:** Have Gemini CLI output JSON with `--output-format json`
|
||||
when invoked headlessly for easy parsing and post-processing. Includes
|
||||
response, stats and errors.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/8119) by
|
||||
[@jerop](https://github.com/jerop))
|
||||
- **Keybinding triggered approvals:** When you use shortcuts (`shift+y` or
|
||||
`shift+tab`) to activate YOLO/auto-edit modes any pending confirmation dialogs
|
||||
will now approve. ([pr](https://github.com/google-gemini/gemini-cli/pull/6665)
|
||||
by [@bulkypanda](https://github.com/bulkypanda))
|
||||
- **Chat sharing:** Convert the current conversation to a Markdown or JSON file
|
||||
with _/chat share <file.md|file.json>_
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/8139) by
|
||||
[@rramkumar1](https://github.com/rramkumar1))
|
||||
- **Prompt search:** Search your prompt history using `ctrl+r`.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/5539) by
|
||||
[@Aisha630](https://github.com/Aisha630))
|
||||
- **Input undo/redo:** Recover accidentally deleted text in the input prompt
|
||||
using `ctrl+z` (undo) and `ctrl+shift+z` (redo).
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/4625) by
|
||||
[@masiafrest](https://github.com/masiafrest))
|
||||
- **Loop detection confirmation:** When loops are detected you are now presented
|
||||
with a dialog to disable detection for the current session.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/8231) by
|
||||
[@SandyTao520](https://github.com/SandyTao520))
|
||||
- **Direct to Google Cloud Telemetry:** Directly send telemetry to Google Cloud
|
||||
for a simpler and more streamlined setup.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/8541) by
|
||||
[@jerop](https://github.com/jerop))
|
||||
- **Visual Mode Indicator Revamp:** ‘shell’, 'accept edits' and 'yolo' modes now
|
||||
have colors to match their impact / usage. Input box now also updates.
|
||||
([shell](https://imgur.com/a/DovpVF1),
|
||||
[accept-edits](https://imgur.com/a/33KDz3J),
|
||||
[yolo](https://imgur.com/a/tbFwIWp),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/8200) by
|
||||
[@miguelsolorio](https://github.com/miguelsolorio))
|
||||
- **Small features, polish, reliability & bug fixes:** A large amount of
|
||||
changes, smaller features, UI updates, reliability and bug fixes + general
|
||||
polish made it in this week!
|
||||
|
||||
## Announcements: v0.5.0 - 2025-09-08
|
||||
|
||||
- 🎉**FastMCP + Gemini CLI**🎉: Quickly install and manage your Gemini CLI MCP
|
||||
servers with FastMCP ([video](https://imgur.com/a/m8QdCPh),
|
||||
[pr](https://github.com/jlowin/fastmcp/pull/1709) by
|
||||
[@jackwotherspoon](https://github.com/jackwotherspoon)**)**
|
||||
- Getting started:
|
||||
[https://gofastmcp.com/integrations/gemini-cli](https://gofastmcp.com/integrations/gemini-cli)
|
||||
- **Positional Prompt for Non-Interactive:** Seamlessly invoke Gemini CLI
|
||||
headlessly via `gemini "Hello"`. Synonymous with passing `-p`.
|
||||
([gif](https://imgur.com/a/hcBznpB),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/7668) by
|
||||
[@allenhutchison](https://github.com/allenhutchison))
|
||||
- **Experimental Tool output truncation:** Enable truncating shell tool outputs
|
||||
and saving full output to a file by setting
|
||||
`"enableToolOutputTruncation": true `([pr](https://github.com/google-gemini/gemini-cli/pull/8039)
|
||||
by [@SandyTao520](https://github.com/SandyTao520))
|
||||
- **Edit Tool improvements:** Gemini CLI’s ability to edit files should now be
|
||||
far more capable. ([pr](https://github.com/google-gemini/gemini-cli/pull/7679)
|
||||
by [@silviojr](https://github.com/silviojr))
|
||||
- **Custom witty messages:** The feature you’ve all been waiting for…
|
||||
Personalized witty loading messages via
|
||||
`"ui": { "customWittyPhrases": ["YOLO"]}` in `settings.json`.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/7641) by
|
||||
[@JayadityaGit](https://github.com/JayadityaGit))
|
||||
- **Nested .gitignore File Handling:** Nested `.gitignore` files are now
|
||||
respected. ([pr](https://github.com/google-gemini/gemini-cli/pull/7645) by
|
||||
[@gsquared94](https://github.com/gsquared94))
|
||||
- **Enforced authentication:** System administrators can now mandate a specific
|
||||
authentication method via
|
||||
`"enforcedAuthType": "oauth-personal|gemini-api-key|…"`in `settings.json`.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/6564) by
|
||||
[@chrstnb](https://github.com/chrstnb))
|
||||
- **A2A development-tool extension:** An RFC for an Agent2Agent
|
||||
([A2A](https://a2a-protocol.org/latest/)) powered extension for developer tool
|
||||
use cases.
|
||||
([feedback](https://github.com/google-gemini/gemini-cli/discussions/7822),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/7817) by
|
||||
[@skeshive](https://github.com/skeshive))
|
||||
- **Hands on Codelab:
|
||||
**[https://codelabs.developers.google.com/gemini-cli-hands-on](https://codelabs.developers.google.com/gemini-cli-hands-on)
|
||||
- **Small features, polish, reliability & bug fixes:** A large amount of
|
||||
changes, smaller features, UI updates, reliability and bug fixes + general
|
||||
polish made it in this week!
|
||||
|
||||
## Announcements: v0.4.0 - 2025-09-01
|
||||
|
||||
- 🎉**Gemini CLI CloudRun and Security Integrations**🎉: Automate app deployment
|
||||
and security analysis with CloudRun and Security extension integrations. Once
|
||||
installed deploy your app to the cloud with `/deploy` and find and fix
|
||||
security vulnerabilities with `/security:analyze`.
|
||||
- Announcement and how to get started:
|
||||
[https://cloud.google.com/blog/products/ai-machine-learning/automate-app-deployment-and-security-analysis-with-new-gemini-cli-extensions](https://cloud.google.com/blog/products/ai-machine-learning/automate-app-deployment-and-security-analysis-with-new-gemini-cli-extensions)
|
||||
- **Experimental**
|
||||
- **Edit Tool:** Give our new edit tool a try by setting
|
||||
`"useSmartEdit": true` in `settings.json`!
|
||||
([feedback](https://github.com/google-gemini/gemini-cli/discussions/7758),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/6823) by
|
||||
[@silviojr](https://github.com/silviojr))
|
||||
- **Model talking to itself fix:** We’ve removed a model workaround that would
|
||||
encourage Gemini CLI to continue conversations on your behalf. This may be
|
||||
disruptive and can be disabled via `"skipNextSpeakerCheck": false` in your
|
||||
`settings.json`
|
||||
([feedback](https://github.com/google-gemini/gemini-cli/discussions/6666),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/7614) by
|
||||
[@SandyTao520](https://github.com/SandyTao520))
|
||||
- **Prompt completion:** Get real-time AI suggestions to complete your prompts
|
||||
as you type. Enable it with `"general": { "enablePromptCompletion": true }`
|
||||
and share your feedback!
|
||||
([gif](https://miro.medium.com/v2/resize:fit:2000/format:webp/1*hvegW7YXOg6N_beUWhTdxA.gif),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/4691) by
|
||||
[@3ks](https://github.com/3ks))
|
||||
- **Footer visibility configuration:** Customize the CLI's footer look and feel
|
||||
in `settings.json`
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/7419) by
|
||||
[@miguelsolorio](https://github.com/miguelsolorio))
|
||||
- `hideCWD`: hide current working directory.
|
||||
- `hideSandboxStatus`: hide sandbox status.
|
||||
- `hideModelInfo`: hide current model information.
|
||||
- `hideContextSummary`: hide request context summary.
|
||||
- **Citations:** For enterprise Code Assist licenses users will now see
|
||||
citations in their responses by default. Enable this yourself with
|
||||
`"showCitations": true`
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/7350) by
|
||||
[@scidomino](https://github.com/scidomino))
|
||||
- **Pro Quota Dialog:** Handle daily Pro model usage limits with an interactive
|
||||
dialog that lets you immediately switch auth or fallback.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/7094) by
|
||||
[@JayadityaGit](https://github.com/JayadityaGit))
|
||||
- **Custom commands @:** Embed local file or directory content directly into
|
||||
your custom command prompts using `@{path}` syntax
|
||||
([gif](https://miro.medium.com/v2/resize:fit:2000/format:webp/1*GosBAo2SjMfFffAnzT7ZMg.gif),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/6716) by
|
||||
[@abhipatel12](https://github.com/abhipatel12))
|
||||
- **2.5 Flash Lite support:** You can now use the `gemini-2.5-flash-lite` model
|
||||
for Gemini CLI via `gemini -m …`.
|
||||
([gif](https://miro.medium.com/v2/resize:fit:2000/format:webp/1*P4SKwnrsyBuULoHrFqsFKQ.gif),
|
||||
[pr](https://github.com/google-gemini/gemini-cli/pull/4652) by
|
||||
[@psinha40898](https://github.com/psinha40898))
|
||||
- **CLI streamlining:** We have deprecated a number of command line arguments in
|
||||
favor of `settings.json` alternatives. We will remove these arguments in a
|
||||
future release. See the PR for the full list of deprecations.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/7360) by
|
||||
[@allenhutchison](https://github.com/allenhutchison))
|
||||
- **JSON session summary:** Track and save detailed CLI session statistics to a
|
||||
JSON file for performance analysis with `--session-summary <path>`
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/7347) by
|
||||
[@leehagoodjames](https://github.com/leehagoodjames))
|
||||
- **Robust keyboard handling:** More reliable and consistent behavior for arrow
|
||||
keys, special keys (Home, End, etc.), and modifier combinations across various
|
||||
terminals. ([pr](https://github.com/google-gemini/gemini-cli/pull/7118) by
|
||||
[@deepankarsharma](https://github.com/deepankarsharma))
|
||||
- **MCP loading indicator:** Provides visual feedback during CLI initialization
|
||||
when connecting to multiple servers.
|
||||
([pr](https://github.com/google-gemini/gemini-cli/pull/6923) by
|
||||
[@swissspidy](https://github.com/swissspidy))
|
||||
- **Small features, polish, reliability & bug fixes:** A large amount of
|
||||
changes, smaller features, UI updates, reliability and bug fixes + general
|
||||
polish made it in this week!
|
||||
@@ -0,0 +1,381 @@
|
||||
# Latest stable release: v0.29.0
|
||||
|
||||
Released: February 17, 2026
|
||||
|
||||
For most users, our latest stable release is the recommended release. Install
|
||||
the latest stable version with:
|
||||
|
||||
```
|
||||
npm install -g @google/gemini-cli
|
||||
```
|
||||
|
||||
## Highlights
|
||||
|
||||
- **Plan Mode:** Introduce a dedicated "Plan Mode" to help you architect complex
|
||||
changes before implementation. Use `/plan` to get started.
|
||||
- **Gemini 3 by Default:** Gemini 3 is now the default model family, bringing
|
||||
improved performance and reasoning capabilities to all users without needing a
|
||||
feature flag.
|
||||
- **Extension Discovery:** Easily discover and install extensions with the new
|
||||
exploration features and registry client.
|
||||
- **Enhanced Admin Controls:** New administrative capabilities allow for
|
||||
allowlisting MCP server configurations, giving organizations more control over
|
||||
available tools.
|
||||
- **Sub-agent Improvements:** Sub-agents have been transitioned to a new format
|
||||
with improved definitions and system prompts for better reliability.
|
||||
|
||||
## What's Changed
|
||||
|
||||
- fix: remove `ask_user` tool from non-interactive modes by @jackwotherspoon in
|
||||
[#18154](https://github.com/google-gemini/gemini-cli/pull/18154)
|
||||
- fix(cli): allow restricted .env loading in untrusted sandboxed folders by
|
||||
@galz10 in [#17806](https://github.com/google-gemini/gemini-cli/pull/17806)
|
||||
- Encourage agent to utilize ecosystem tools to perform work by @gundermanc in
|
||||
[#17881](https://github.com/google-gemini/gemini-cli/pull/17881)
|
||||
- feat(plan): unify workflow location in system prompt to optimize caching by
|
||||
@jerop in [#18258](https://github.com/google-gemini/gemini-cli/pull/18258)
|
||||
- feat(core): enable getUserTierName in config by @sehoon38 in
|
||||
[#18265](https://github.com/google-gemini/gemini-cli/pull/18265)
|
||||
- feat(core): add default execution limits for subagents by @abhipatel12 in
|
||||
[#18274](https://github.com/google-gemini/gemini-cli/pull/18274)
|
||||
- Fix issue where agent gets stuck at interactive commands. by @gundermanc in
|
||||
[#18272](https://github.com/google-gemini/gemini-cli/pull/18272)
|
||||
- chore(release): bump version to 0.29.0-nightly.20260203.71f46f116 by
|
||||
@gemini-cli-robot in
|
||||
[#18243](https://github.com/google-gemini/gemini-cli/pull/18243)
|
||||
- feat(core): remove hardcoded policy bypass for local subagents by @abhipatel12
|
||||
in [#18153](https://github.com/google-gemini/gemini-cli/pull/18153)
|
||||
- feat(plan): implement `plan` slash command by @Adib234 in
|
||||
[#17698](https://github.com/google-gemini/gemini-cli/pull/17698)
|
||||
- feat: increase `ask_user` label limit to 16 characters by @jackwotherspoon in
|
||||
[#18320](https://github.com/google-gemini/gemini-cli/pull/18320)
|
||||
- Add information about the agent skills lifecycle and clarify docs-writer skill
|
||||
metadata. by @g-samroberts in
|
||||
[#18234](https://github.com/google-gemini/gemini-cli/pull/18234)
|
||||
- feat(core): add `enter_plan_mode` tool by @jerop in
|
||||
[#18324](https://github.com/google-gemini/gemini-cli/pull/18324)
|
||||
- Stop showing an error message in `/plan` by @Adib234 in
|
||||
[#18333](https://github.com/google-gemini/gemini-cli/pull/18333)
|
||||
- fix(hooks): remove unnecessary logging for hook registration by @abhipatel12
|
||||
in [#18332](https://github.com/google-gemini/gemini-cli/pull/18332)
|
||||
- fix(mcp): ensure MCP transport is closed to prevent memory leaks by
|
||||
@cbcoutinho in
|
||||
[#18054](https://github.com/google-gemini/gemini-cli/pull/18054)
|
||||
- feat(skills): implement linking for agent skills by @MushuEE in
|
||||
[#18295](https://github.com/google-gemini/gemini-cli/pull/18295)
|
||||
- Changelogs for 0.27.0 and 0.28.0-preview0 by @g-samroberts in
|
||||
[#18336](https://github.com/google-gemini/gemini-cli/pull/18336)
|
||||
- chore: correct docs as skills and hooks are stable by @jackwotherspoon in
|
||||
[#18358](https://github.com/google-gemini/gemini-cli/pull/18358)
|
||||
- feat(admin): Implement admin allowlist for MCP server configurations by
|
||||
@skeshive in [#18311](https://github.com/google-gemini/gemini-cli/pull/18311)
|
||||
- fix(core): add retry logic for transient SSL/TLS errors (#17318) by @ppgranger
|
||||
in [#18310](https://github.com/google-gemini/gemini-cli/pull/18310)
|
||||
- Add support for /extensions config command by @chrstnb in
|
||||
[#17895](https://github.com/google-gemini/gemini-cli/pull/17895)
|
||||
- fix(core): handle non-compliant mcpbridge responses from Xcode 26.3 by
|
||||
@peterfriese in
|
||||
[#18376](https://github.com/google-gemini/gemini-cli/pull/18376)
|
||||
- feat(cli): Add W, B, E Vim motions and operator support by @ademuri in
|
||||
[#16209](https://github.com/google-gemini/gemini-cli/pull/16209)
|
||||
- fix: Windows Specific Agent Quality & System Prompt by @scidomino in
|
||||
[#18351](https://github.com/google-gemini/gemini-cli/pull/18351)
|
||||
- feat(plan): support `replace` tool in plan mode to edit plans by @jerop in
|
||||
[#18379](https://github.com/google-gemini/gemini-cli/pull/18379)
|
||||
- Improving memory tool instructions and eval testing by @alisa-alisa in
|
||||
[#18091](https://github.com/google-gemini/gemini-cli/pull/18091)
|
||||
- fix(cli): color extension link success message green by @MushuEE in
|
||||
[#18386](https://github.com/google-gemini/gemini-cli/pull/18386)
|
||||
- undo by @jacob314 in
|
||||
[#18147](https://github.com/google-gemini/gemini-cli/pull/18147)
|
||||
- feat(plan): add guidance on iterating on approved plans vs creating new plans
|
||||
by @jerop in [#18346](https://github.com/google-gemini/gemini-cli/pull/18346)
|
||||
- feat(plan): fix invalid tool calls in plan mode by @Adib234 in
|
||||
[#18352](https://github.com/google-gemini/gemini-cli/pull/18352)
|
||||
- feat(plan): integrate planning artifacts and tools into primary workflows by
|
||||
@jerop in [#18375](https://github.com/google-gemini/gemini-cli/pull/18375)
|
||||
- Fix permission check by @scidomino in
|
||||
[#18395](https://github.com/google-gemini/gemini-cli/pull/18395)
|
||||
- ux(polish) autocomplete in the input prompt by @jacob314 in
|
||||
[#18181](https://github.com/google-gemini/gemini-cli/pull/18181)
|
||||
- fix: resolve infinite loop when using 'Modify with external editor' by
|
||||
@ppgranger in [#17453](https://github.com/google-gemini/gemini-cli/pull/17453)
|
||||
- feat: expand verify-release to macOS and Windows by @yunaseoul in
|
||||
[#18145](https://github.com/google-gemini/gemini-cli/pull/18145)
|
||||
- feat(plan): implement support for MCP servers in Plan mode by @Adib234 in
|
||||
[#18229](https://github.com/google-gemini/gemini-cli/pull/18229)
|
||||
- chore: update folder trust error messaging by @galz10 in
|
||||
[#18402](https://github.com/google-gemini/gemini-cli/pull/18402)
|
||||
- feat(plan): create a metric for execution of plans generated in plan mode by
|
||||
@Adib234 in [#18236](https://github.com/google-gemini/gemini-cli/pull/18236)
|
||||
- perf(ui): optimize stripUnsafeCharacters with regex by @gsquared94 in
|
||||
[#18413](https://github.com/google-gemini/gemini-cli/pull/18413)
|
||||
- feat(context): implement observation masking for tool outputs by @abhipatel12
|
||||
in [#18389](https://github.com/google-gemini/gemini-cli/pull/18389)
|
||||
- feat(core,cli): implement session-linked tool output storage and cleanup by
|
||||
@abhipatel12 in
|
||||
[#18416](https://github.com/google-gemini/gemini-cli/pull/18416)
|
||||
- Shorten temp directory by @joshualitt in
|
||||
[#17901](https://github.com/google-gemini/gemini-cli/pull/17901)
|
||||
- feat(plan): add behavioral evals for plan mode by @jerop in
|
||||
[#18437](https://github.com/google-gemini/gemini-cli/pull/18437)
|
||||
- Add extension registry client by @chrstnb in
|
||||
[#18396](https://github.com/google-gemini/gemini-cli/pull/18396)
|
||||
- Enable extension config by default by @chrstnb in
|
||||
[#18447](https://github.com/google-gemini/gemini-cli/pull/18447)
|
||||
- Automatically generate change logs on release by @g-samroberts in
|
||||
[#18401](https://github.com/google-gemini/gemini-cli/pull/18401)
|
||||
- Remove previewFeatures and default to Gemini 3 by @sehoon38 in
|
||||
[#18414](https://github.com/google-gemini/gemini-cli/pull/18414)
|
||||
- feat(admin): apply MCP allowlist to extensions & gemini mcp list command by
|
||||
@skeshive in [#18442](https://github.com/google-gemini/gemini-cli/pull/18442)
|
||||
- fix(cli): improve focus navigation for interactive and background shells by
|
||||
@galz10 in [#18343](https://github.com/google-gemini/gemini-cli/pull/18343)
|
||||
- Add shortcuts hint and panel for discoverability by @LyalinDotCom in
|
||||
[#18035](https://github.com/google-gemini/gemini-cli/pull/18035)
|
||||
- fix(config): treat system settings as read-only during migration and warn user
|
||||
by @spencer426 in
|
||||
[#18277](https://github.com/google-gemini/gemini-cli/pull/18277)
|
||||
- feat(plan): add positive test case and update eval stability policy by @jerop
|
||||
in [#18457](https://github.com/google-gemini/gemini-cli/pull/18457)
|
||||
- fix- windows: add shell: true for spawnSync to fix EINVAL with .cmd editors by
|
||||
@zackoch in [#18408](https://github.com/google-gemini/gemini-cli/pull/18408)
|
||||
- bug(core): Fix bug when saving plans. by @joshualitt in
|
||||
[#18465](https://github.com/google-gemini/gemini-cli/pull/18465)
|
||||
- Refactor atCommandProcessor by @scidomino in
|
||||
[#18461](https://github.com/google-gemini/gemini-cli/pull/18461)
|
||||
- feat(core): implement persistence and resumption for masked tool outputs by
|
||||
@abhipatel12 in
|
||||
[#18451](https://github.com/google-gemini/gemini-cli/pull/18451)
|
||||
- refactor: simplify tool output truncation to single config by @SandyTao520 in
|
||||
[#18446](https://github.com/google-gemini/gemini-cli/pull/18446)
|
||||
- bug(core): Ensure storage is initialized early, even if config is not. by
|
||||
@joshualitt in
|
||||
[#18471](https://github.com/google-gemini/gemini-cli/pull/18471)
|
||||
- chore: Update build-and-start script to support argument forwarding by
|
||||
@Abhijit-2592 in
|
||||
[#18241](https://github.com/google-gemini/gemini-cli/pull/18241)
|
||||
- fix(core): prevent subagent bypass in plan mode by @jerop in
|
||||
[#18484](https://github.com/google-gemini/gemini-cli/pull/18484)
|
||||
- feat(cli): add WebSocket-based network logging and streaming chunk support by
|
||||
@SandyTao520 in
|
||||
[#18383](https://github.com/google-gemini/gemini-cli/pull/18383)
|
||||
- feat(cli): update approval modes UI by @jerop in
|
||||
[#18476](https://github.com/google-gemini/gemini-cli/pull/18476)
|
||||
- fix(cli): reload skills and agents on extension restart by @NTaylorMullen in
|
||||
[#18411](https://github.com/google-gemini/gemini-cli/pull/18411)
|
||||
- fix(core): expand excludeTools with legacy aliases for renamed tools by
|
||||
@SandyTao520 in
|
||||
[#18498](https://github.com/google-gemini/gemini-cli/pull/18498)
|
||||
- feat(core): overhaul system prompt for rigor, integrity, and intent alignment
|
||||
by @NTaylorMullen in
|
||||
[#17263](https://github.com/google-gemini/gemini-cli/pull/17263)
|
||||
- Patch for generate changelog docs yaml file by @g-samroberts in
|
||||
[#18496](https://github.com/google-gemini/gemini-cli/pull/18496)
|
||||
- Code review fixes for show question mark pr. by @jacob314 in
|
||||
[#18480](https://github.com/google-gemini/gemini-cli/pull/18480)
|
||||
- fix(cli): add SS3 Shift+Tab support for Windows terminals by @ThanhNguyxn in
|
||||
[#18187](https://github.com/google-gemini/gemini-cli/pull/18187)
|
||||
- chore: remove redundant planning prompt from final shell by @jerop in
|
||||
[#18528](https://github.com/google-gemini/gemini-cli/pull/18528)
|
||||
- docs: require pr-creator skill for PR generation by @NTaylorMullen in
|
||||
[#18536](https://github.com/google-gemini/gemini-cli/pull/18536)
|
||||
- chore: update colors for ask_user dialog by @jackwotherspoon in
|
||||
[#18543](https://github.com/google-gemini/gemini-cli/pull/18543)
|
||||
- feat(core): exempt high-signal tools from output masking by @abhipatel12 in
|
||||
[#18545](https://github.com/google-gemini/gemini-cli/pull/18545)
|
||||
- refactor(core): remove memory tool instructions from Gemini 3 prompt by
|
||||
@NTaylorMullen in
|
||||
[#18559](https://github.com/google-gemini/gemini-cli/pull/18559)
|
||||
- chore: remove feedback instruction from system prompt by @NTaylorMullen in
|
||||
[#18560](https://github.com/google-gemini/gemini-cli/pull/18560)
|
||||
- feat(context): add remote configuration for tool output masking thresholds by
|
||||
@abhipatel12 in
|
||||
[#18553](https://github.com/google-gemini/gemini-cli/pull/18553)
|
||||
- feat(core): pause agent timeout budget while waiting for tool confirmation by
|
||||
@abhipatel12 in
|
||||
[#18415](https://github.com/google-gemini/gemini-cli/pull/18415)
|
||||
- refactor(config): remove experimental.enableEventDrivenScheduler setting by
|
||||
@abhipatel12 in
|
||||
[#17924](https://github.com/google-gemini/gemini-cli/pull/17924)
|
||||
- feat(cli): truncate shell output in UI history and improve active shell
|
||||
display by @jwhelangoog in
|
||||
[#17438](https://github.com/google-gemini/gemini-cli/pull/17438)
|
||||
- refactor(cli): switch useToolScheduler to event-driven engine by @abhipatel12
|
||||
in [#18565](https://github.com/google-gemini/gemini-cli/pull/18565)
|
||||
- fix(core): correct escaped interpolation in system prompt by @NTaylorMullen in
|
||||
[#18557](https://github.com/google-gemini/gemini-cli/pull/18557)
|
||||
- propagate abortSignal by @scidomino in
|
||||
[#18477](https://github.com/google-gemini/gemini-cli/pull/18477)
|
||||
- feat(core): conditionally include ctrl+f prompt based on interactive shell
|
||||
setting by @NTaylorMullen in
|
||||
[#18561](https://github.com/google-gemini/gemini-cli/pull/18561)
|
||||
- fix(core): ensure `enter_plan_mode` tool registration respects
|
||||
`experimental.plan` by @jerop in
|
||||
[#18587](https://github.com/google-gemini/gemini-cli/pull/18587)
|
||||
- feat(core): transition sub-agents to XML format and improve definitions by
|
||||
@NTaylorMullen in
|
||||
[#18555](https://github.com/google-gemini/gemini-cli/pull/18555)
|
||||
- docs: Add Plan Mode documentation by @jerop in
|
||||
[#18582](https://github.com/google-gemini/gemini-cli/pull/18582)
|
||||
- chore: strengthen validation guidance in system prompt by @NTaylorMullen in
|
||||
[#18544](https://github.com/google-gemini/gemini-cli/pull/18544)
|
||||
- Fix newline insertion bug in replace tool by @werdnum in
|
||||
[#18595](https://github.com/google-gemini/gemini-cli/pull/18595)
|
||||
- fix(evals): update save_memory evals and simplify tool description by
|
||||
@NTaylorMullen in
|
||||
[#18610](https://github.com/google-gemini/gemini-cli/pull/18610)
|
||||
- chore(evals): update validation_fidelity_pre_existing_errors to USUALLY_PASSES
|
||||
by @NTaylorMullen in
|
||||
[#18617](https://github.com/google-gemini/gemini-cli/pull/18617)
|
||||
- fix: shorten tool call IDs and fix duplicate tool name in truncated output
|
||||
filenames by @SandyTao520 in
|
||||
[#18600](https://github.com/google-gemini/gemini-cli/pull/18600)
|
||||
- feat(cli): implement atomic writes and safety checks for trusted folders by
|
||||
@galz10 in [#18406](https://github.com/google-gemini/gemini-cli/pull/18406)
|
||||
- Remove relative docs links by @chrstnb in
|
||||
[#18650](https://github.com/google-gemini/gemini-cli/pull/18650)
|
||||
- docs: add legacy snippets convention to GEMINI.md by @NTaylorMullen in
|
||||
[#18597](https://github.com/google-gemini/gemini-cli/pull/18597)
|
||||
- fix(chore): Support linting for cjs by @aswinashok44 in
|
||||
[#18639](https://github.com/google-gemini/gemini-cli/pull/18639)
|
||||
- feat: move shell efficiency guidelines to tool description by @NTaylorMullen
|
||||
in [#18614](https://github.com/google-gemini/gemini-cli/pull/18614)
|
||||
- Added "" as default value, since getText() used to expect a string only and
|
||||
thus crashed when undefined... Fixes #18076 by @019-Abhi in
|
||||
[#18099](https://github.com/google-gemini/gemini-cli/pull/18099)
|
||||
- Allow @-includes outside of workspaces (with permission) by @scidomino in
|
||||
[#18470](https://github.com/google-gemini/gemini-cli/pull/18470)
|
||||
- chore: make `ask_user` header description more clear by @jackwotherspoon in
|
||||
[#18657](https://github.com/google-gemini/gemini-cli/pull/18657)
|
||||
- refactor(core): model-dependent tool definitions by @aishaneeshah in
|
||||
[#18563](https://github.com/google-gemini/gemini-cli/pull/18563)
|
||||
- Harded code assist converter. by @jacob314 in
|
||||
[#18656](https://github.com/google-gemini/gemini-cli/pull/18656)
|
||||
- bug(core): Fix minor bug in migration logic. by @joshualitt in
|
||||
[#18661](https://github.com/google-gemini/gemini-cli/pull/18661)
|
||||
- feat: enable plan mode experiment in settings by @jerop in
|
||||
[#18636](https://github.com/google-gemini/gemini-cli/pull/18636)
|
||||
- refactor: push isValidPath() into parsePastedPaths() by @scidomino in
|
||||
[#18664](https://github.com/google-gemini/gemini-cli/pull/18664)
|
||||
- fix(cli): correct 'esc to cancel' position and restore duration display by
|
||||
@NTaylorMullen in
|
||||
[#18534](https://github.com/google-gemini/gemini-cli/pull/18534)
|
||||
- feat(cli): add DevTools integration with gemini-cli-devtools by @SandyTao520
|
||||
in [#18648](https://github.com/google-gemini/gemini-cli/pull/18648)
|
||||
- chore: remove unused exports and redundant hook files by @SandyTao520 in
|
||||
[#18681](https://github.com/google-gemini/gemini-cli/pull/18681)
|
||||
- Fix number of lines being reported in rewind confirmation dialog by @Adib234
|
||||
in [#18675](https://github.com/google-gemini/gemini-cli/pull/18675)
|
||||
- feat(cli): disable folder trust in headless mode by @galz10 in
|
||||
[#18407](https://github.com/google-gemini/gemini-cli/pull/18407)
|
||||
- Disallow unsafe type assertions by @gundermanc in
|
||||
[#18688](https://github.com/google-gemini/gemini-cli/pull/18688)
|
||||
- Change event type for release by @g-samroberts in
|
||||
[#18693](https://github.com/google-gemini/gemini-cli/pull/18693)
|
||||
- feat: handle multiple dynamic context filenames in system prompt by
|
||||
@NTaylorMullen in
|
||||
[#18598](https://github.com/google-gemini/gemini-cli/pull/18598)
|
||||
- Properly parse at-commands with narrow non-breaking spaces by @scidomino in
|
||||
[#18677](https://github.com/google-gemini/gemini-cli/pull/18677)
|
||||
- refactor(core): centralize core tool definitions and support model-specific
|
||||
schemas by @aishaneeshah in
|
||||
[#18662](https://github.com/google-gemini/gemini-cli/pull/18662)
|
||||
- feat(core): Render memory hierarchically in context. by @joshualitt in
|
||||
[#18350](https://github.com/google-gemini/gemini-cli/pull/18350)
|
||||
- feat: Ctrl+O to expand paste placeholder by @jackwotherspoon in
|
||||
[#18103](https://github.com/google-gemini/gemini-cli/pull/18103)
|
||||
- fix(cli): Improve header spacing by @NTaylorMullen in
|
||||
[#18531](https://github.com/google-gemini/gemini-cli/pull/18531)
|
||||
- Feature/quota visibility 16795 by @spencer426 in
|
||||
[#18203](https://github.com/google-gemini/gemini-cli/pull/18203)
|
||||
- Inline thinking bubbles with summary/full modes by @LyalinDotCom in
|
||||
[#18033](https://github.com/google-gemini/gemini-cli/pull/18033)
|
||||
- docs: remove TOC marker from Plan Mode header by @jerop in
|
||||
[#18678](https://github.com/google-gemini/gemini-cli/pull/18678)
|
||||
- fix(ui): remove redundant newlines in Gemini messages by @NTaylorMullen in
|
||||
[#18538](https://github.com/google-gemini/gemini-cli/pull/18538)
|
||||
- test(cli): fix AppContainer act() warnings and improve waitFor resilience by
|
||||
@NTaylorMullen in
|
||||
[#18676](https://github.com/google-gemini/gemini-cli/pull/18676)
|
||||
- refactor(core): refine Security & System Integrity section in system prompt by
|
||||
@NTaylorMullen in
|
||||
[#18601](https://github.com/google-gemini/gemini-cli/pull/18601)
|
||||
- Fix layout rounding. by @gundermanc in
|
||||
[#18667](https://github.com/google-gemini/gemini-cli/pull/18667)
|
||||
- docs(skills): enhance pr-creator safety and interactivity by @NTaylorMullen in
|
||||
[#18616](https://github.com/google-gemini/gemini-cli/pull/18616)
|
||||
- test(core): remove hardcoded model from TestRig by @NTaylorMullen in
|
||||
[#18710](https://github.com/google-gemini/gemini-cli/pull/18710)
|
||||
- feat(core): optimize sub-agents system prompt intro by @NTaylorMullen in
|
||||
[#18608](https://github.com/google-gemini/gemini-cli/pull/18608)
|
||||
- feat(cli): update approval mode labels and shortcuts per latest UX spec by
|
||||
@jerop in [#18698](https://github.com/google-gemini/gemini-cli/pull/18698)
|
||||
- fix(plan): update persistent approval mode setting by @Adib234 in
|
||||
[#18638](https://github.com/google-gemini/gemini-cli/pull/18638)
|
||||
- fix: move toasts location to left side by @jackwotherspoon in
|
||||
[#18705](https://github.com/google-gemini/gemini-cli/pull/18705)
|
||||
- feat(routing): restrict numerical routing to Gemini 3 family by @mattKorwel in
|
||||
[#18478](https://github.com/google-gemini/gemini-cli/pull/18478)
|
||||
- fix(ide): fix ide nudge setting by @skeshive in
|
||||
[#18733](https://github.com/google-gemini/gemini-cli/pull/18733)
|
||||
- fix(core): standardize tool formatting in system prompts by @NTaylorMullen in
|
||||
[#18615](https://github.com/google-gemini/gemini-cli/pull/18615)
|
||||
- chore: consolidate to green in ask user dialog by @jackwotherspoon in
|
||||
[#18734](https://github.com/google-gemini/gemini-cli/pull/18734)
|
||||
- feat: add `extensionsExplore` setting to enable extensions explore UI. by
|
||||
@sripasg in [#18686](https://github.com/google-gemini/gemini-cli/pull/18686)
|
||||
- feat(cli): defer devtools startup and integrate with F12 by @SandyTao520 in
|
||||
[#18695](https://github.com/google-gemini/gemini-cli/pull/18695)
|
||||
- ui: update & subdue footer colors and animate progress indicator by
|
||||
@keithguerin in
|
||||
[#18570](https://github.com/google-gemini/gemini-cli/pull/18570)
|
||||
- test: add model-specific snapshots for coreTools by @aishaneeshah in
|
||||
[#18707](https://github.com/google-gemini/gemini-cli/pull/18707)
|
||||
- ci: shard windows tests and fix event listener leaks by @NTaylorMullen in
|
||||
[#18670](https://github.com/google-gemini/gemini-cli/pull/18670)
|
||||
- fix: allow `ask_user` tool in yolo mode by @jackwotherspoon in
|
||||
[#18541](https://github.com/google-gemini/gemini-cli/pull/18541)
|
||||
- feat: redact disabled tools from system prompt (#13597) by @NTaylorMullen in
|
||||
[#18613](https://github.com/google-gemini/gemini-cli/pull/18613)
|
||||
- Update Gemini.md to use the curent year on creating new files by @sehoon38 in
|
||||
[#18460](https://github.com/google-gemini/gemini-cli/pull/18460)
|
||||
- Code review cleanup for thinking display by @jacob314 in
|
||||
[#18720](https://github.com/google-gemini/gemini-cli/pull/18720)
|
||||
- fix(cli): hide scrollbars when in alternate buffer copy mode by @werdnum in
|
||||
[#18354](https://github.com/google-gemini/gemini-cli/pull/18354)
|
||||
- Fix issues with rip grep by @gundermanc in
|
||||
[#18756](https://github.com/google-gemini/gemini-cli/pull/18756)
|
||||
- fix(cli): fix history navigation regression after prompt autocomplete by
|
||||
@sehoon38 in [#18752](https://github.com/google-gemini/gemini-cli/pull/18752)
|
||||
- chore: cleanup unused and add unlisted dependencies in packages/cli by
|
||||
@adamfweidman in
|
||||
[#18749](https://github.com/google-gemini/gemini-cli/pull/18749)
|
||||
- Fix issue where Gemini CLI creates tests in a new file by @gundermanc in
|
||||
[#18409](https://github.com/google-gemini/gemini-cli/pull/18409)
|
||||
- feat(telemetry): Ensure experiment IDs are included in OpenTelemetry logs by
|
||||
@kevin-ramdass in
|
||||
[#18747](https://github.com/google-gemini/gemini-cli/pull/18747)
|
||||
- fix(patch): cherry-pick e9a9474 to release/v0.29.0-preview.0-pr-18840 to patch
|
||||
version v0.29.0-preview.0 and create version 0.29.0-preview.1 by
|
||||
@gemini-cli-robot in
|
||||
[#18841](https://github.com/google-gemini/gemini-cli/pull/18841)
|
||||
- fix(patch): cherry-pick 08e8eea to release/v0.29.0-preview.1-pr-18855 to patch
|
||||
version v0.29.0-preview.1 and create version 0.29.0-preview.2 by
|
||||
@gemini-cli-robot in
|
||||
[#18905](https://github.com/google-gemini/gemini-cli/pull/18905)
|
||||
- fix(patch): cherry-pick d0c6a56 to release/v0.29.0-preview.2-pr-18976 to patch
|
||||
version v0.29.0-preview.2 and create version 0.29.0-preview.3 by
|
||||
@gemini-cli-robot in
|
||||
[#19023](https://github.com/google-gemini/gemini-cli/pull/19023)
|
||||
- fix(patch): cherry-pick e5ff202 to release/v0.29.0-preview.3-pr-19254 to patch
|
||||
version v0.29.0-preview.3 and create version 0.29.0-preview.4 by
|
||||
@gemini-cli-robot in
|
||||
[#19264](https://github.com/google-gemini/gemini-cli/pull/19264)
|
||||
- fix(patch): cherry-pick 9590a09 to release/v0.29.0-preview.4-pr-18771 to patch
|
||||
version v0.29.0-preview.4 and create version 0.29.0-preview.5 by
|
||||
@gemini-cli-robot in
|
||||
[#19274](https://github.com/google-gemini/gemini-cli/pull/19274)
|
||||
|
||||
**Full Changelog**:
|
||||
https://github.com/google-gemini/gemini-cli/compare/v0.28.2...v0.29.0
|
||||
@@ -0,0 +1,318 @@
|
||||
# Preview release: v0.30.0-preview.5
|
||||
|
||||
Released: February 24, 2026
|
||||
|
||||
Our preview release includes the latest, new, and experimental features. This
|
||||
release may not be as stable as our [latest weekly release](latest.md).
|
||||
|
||||
To install the preview release:
|
||||
|
||||
```
|
||||
npm install -g @google/gemini-cli@preview
|
||||
```
|
||||
|
||||
## Highlights
|
||||
|
||||
- **Initial SDK Package:** Introduced the initial SDK package with support for
|
||||
custom skills and dynamic system instructions.
|
||||
- **Refined Plan Mode:** Refined Plan Mode with support for enabling skills,
|
||||
improved agentic execution, and project exploration without planning.
|
||||
- **Enhanced CLI UI:** Enhanced CLI UI with a new clean UI toggle, minimal-mode
|
||||
bleed-through, and support for Ctrl-Z suspension.
|
||||
- **`--policy` flag:** Added the `--policy` flag to support user-defined
|
||||
policies.
|
||||
- **New Themes:** Added Solarized Dark and Solarized Light themes.
|
||||
|
||||
## What's Changed
|
||||
|
||||
- fix(patch): cherry-pick 2c1d6f8 to release/v0.30.0-preview.4-pr-19369 to patch
|
||||
version v0.30.0-preview.4 and create version 0.30.0-preview.5 by
|
||||
@gemini-cli-robot in
|
||||
[#20086](https://github.com/google-gemini/gemini-cli/pull/20086)
|
||||
- fix(patch): cherry-pick 261788c to release/v0.30.0-preview.0-pr-19453 to patch
|
||||
version v0.30.0-preview.0 and create version 0.30.0-preview.1 by
|
||||
@gemini-cli-robot in
|
||||
[#19490](https://github.com/google-gemini/gemini-cli/pull/19490)
|
||||
- feat(ux): added text wrapping capabilities to markdown tables by @devr0306 in
|
||||
[#18240](https://github.com/google-gemini/gemini-cli/pull/18240)
|
||||
- Revert "fix(mcp): ensure MCP transport is closed to prevent memory leaks" by
|
||||
@skeshive in [#18771](https://github.com/google-gemini/gemini-cli/pull/18771)
|
||||
- chore(release): bump version to 0.30.0-nightly.20260210.a2174751d by
|
||||
@gemini-cli-robot in
|
||||
[#18772](https://github.com/google-gemini/gemini-cli/pull/18772)
|
||||
- chore: cleanup unused and add unlisted dependencies in packages/core by
|
||||
@adamfweidman in
|
||||
[#18762](https://github.com/google-gemini/gemini-cli/pull/18762)
|
||||
- chore(core): update activate_skill prompt verbiage to be more direct by
|
||||
@NTaylorMullen in
|
||||
[#18605](https://github.com/google-gemini/gemini-cli/pull/18605)
|
||||
- Add autoconfigure memory usage setting to the dialog by @jacob314 in
|
||||
[#18510](https://github.com/google-gemini/gemini-cli/pull/18510)
|
||||
- fix(core): prevent race condition in policy persistence by @braddux in
|
||||
[#18506](https://github.com/google-gemini/gemini-cli/pull/18506)
|
||||
- fix(evals): prevent false positive in hierarchical memory test by
|
||||
@Abhijit-2592 in
|
||||
[#18777](https://github.com/google-gemini/gemini-cli/pull/18777)
|
||||
- test(evals): mark all `save_memory` evals as `USUALLY_PASSES` due to
|
||||
unreliability by @jerop in
|
||||
[#18786](https://github.com/google-gemini/gemini-cli/pull/18786)
|
||||
- feat(cli): add setting to hide shortcuts hint UI by @LyalinDotCom in
|
||||
[#18562](https://github.com/google-gemini/gemini-cli/pull/18562)
|
||||
- feat(core): formalize 5-phase sequential planning workflow by @jerop in
|
||||
[#18759](https://github.com/google-gemini/gemini-cli/pull/18759)
|
||||
- Introduce limits for search results. by @gundermanc in
|
||||
[#18767](https://github.com/google-gemini/gemini-cli/pull/18767)
|
||||
- fix(cli): allow closing debug console after auto-open via flicker by
|
||||
@SandyTao520 in
|
||||
[#18795](https://github.com/google-gemini/gemini-cli/pull/18795)
|
||||
- feat(masking): enable tool output masking by default by @abhipatel12 in
|
||||
[#18564](https://github.com/google-gemini/gemini-cli/pull/18564)
|
||||
- perf(ui): optimize table rendering by memoizing styled characters by @devr0306
|
||||
in [#18770](https://github.com/google-gemini/gemini-cli/pull/18770)
|
||||
- feat: multi-line text answers in ask-user tool by @jackwotherspoon in
|
||||
[#18741](https://github.com/google-gemini/gemini-cli/pull/18741)
|
||||
- perf(cli): truncate large debug logs and limit message history by @mattKorwel
|
||||
in [#18663](https://github.com/google-gemini/gemini-cli/pull/18663)
|
||||
- fix(core): complete MCP discovery when configured servers are skipped by
|
||||
@LyalinDotCom in
|
||||
[#18586](https://github.com/google-gemini/gemini-cli/pull/18586)
|
||||
- fix(core): cache CLI version to ensure consistency during sessions by
|
||||
@sehoon38 in [#18793](https://github.com/google-gemini/gemini-cli/pull/18793)
|
||||
- fix(cli): resolve double rendering in shpool and address vscode lint warnings
|
||||
by @braddux in
|
||||
[#18704](https://github.com/google-gemini/gemini-cli/pull/18704)
|
||||
- feat(plan): document and validate Plan Mode policy overrides by @jerop in
|
||||
[#18825](https://github.com/google-gemini/gemini-cli/pull/18825)
|
||||
- Fix pressing any key to exit select mode. by @jacob314 in
|
||||
[#18421](https://github.com/google-gemini/gemini-cli/pull/18421)
|
||||
- fix(cli): update F12 behavior to only open drawer if browser fails by
|
||||
@SandyTao520 in
|
||||
[#18829](https://github.com/google-gemini/gemini-cli/pull/18829)
|
||||
- feat(plan): allow skills to be enabled in plan mode by @Adib234 in
|
||||
[#18817](https://github.com/google-gemini/gemini-cli/pull/18817)
|
||||
- docs(plan): add documentation for plan mode tools by @jerop in
|
||||
[#18827](https://github.com/google-gemini/gemini-cli/pull/18827)
|
||||
- Remove experimental note in extension settings docs by @chrstnb in
|
||||
[#18822](https://github.com/google-gemini/gemini-cli/pull/18822)
|
||||
- Update prompt and grep tool definition to limit context size by @gundermanc in
|
||||
[#18780](https://github.com/google-gemini/gemini-cli/pull/18780)
|
||||
- docs(plan): add `ask_user` tool documentation by @jerop in
|
||||
[#18830](https://github.com/google-gemini/gemini-cli/pull/18830)
|
||||
- Revert unintended credentials exposure by @Adib234 in
|
||||
[#18840](https://github.com/google-gemini/gemini-cli/pull/18840)
|
||||
- feat(core): update internal utility models to Gemini 3 by @SandyTao520 in
|
||||
[#18773](https://github.com/google-gemini/gemini-cli/pull/18773)
|
||||
- feat(a2a): add value-resolver for auth credential resolution by @adamfweidman
|
||||
in [#18653](https://github.com/google-gemini/gemini-cli/pull/18653)
|
||||
- Removed getPlainTextLength by @devr0306 in
|
||||
[#18848](https://github.com/google-gemini/gemini-cli/pull/18848)
|
||||
- More grep prompt tweaks by @gundermanc in
|
||||
[#18846](https://github.com/google-gemini/gemini-cli/pull/18846)
|
||||
- refactor(cli): Reactive useSettingsStore hook by @psinha40898 in
|
||||
[#14915](https://github.com/google-gemini/gemini-cli/pull/14915)
|
||||
- fix(mcp): Ensure that stdio MCP server execution has the `GEMINI_CLI=1` env
|
||||
variable populated. by @richieforeman in
|
||||
[#18832](https://github.com/google-gemini/gemini-cli/pull/18832)
|
||||
- fix(core): improve headless mode detection for flags and query args by @galz10
|
||||
in [#18855](https://github.com/google-gemini/gemini-cli/pull/18855)
|
||||
- refactor(cli): simplify UI and remove legacy inline tool confirmation logic by
|
||||
@abhipatel12 in
|
||||
[#18566](https://github.com/google-gemini/gemini-cli/pull/18566)
|
||||
- feat(cli): deprecate --allowed-tools and excludeTools in favor of policy
|
||||
engine by @Abhijit-2592 in
|
||||
[#18508](https://github.com/google-gemini/gemini-cli/pull/18508)
|
||||
- fix(workflows): improve maintainer detection for automated PR actions by
|
||||
@bdmorgan in [#18869](https://github.com/google-gemini/gemini-cli/pull/18869)
|
||||
- refactor(cli): consolidate useToolScheduler and delete legacy implementation
|
||||
by @abhipatel12 in
|
||||
[#18567](https://github.com/google-gemini/gemini-cli/pull/18567)
|
||||
- Update changelog for v0.28.0 and v0.29.0-preview0 by @g-samroberts in
|
||||
[#18819](https://github.com/google-gemini/gemini-cli/pull/18819)
|
||||
- fix(core): ensure sub-agents are registered regardless of tools.allowed by
|
||||
@mattKorwel in
|
||||
[#18870](https://github.com/google-gemini/gemini-cli/pull/18870)
|
||||
- Show notification when there's a conflict with an extensions command by
|
||||
@chrstnb in [#17890](https://github.com/google-gemini/gemini-cli/pull/17890)
|
||||
- fix(cli): dismiss '?' shortcuts help on hotkeys and active states by
|
||||
@LyalinDotCom in
|
||||
[#18583](https://github.com/google-gemini/gemini-cli/pull/18583)
|
||||
- fix(core): prioritize conditional policy rules and harden Plan Mode by
|
||||
@Abhijit-2592 in
|
||||
[#18882](https://github.com/google-gemini/gemini-cli/pull/18882)
|
||||
- feat(core): refine Plan Mode system prompt for agentic execution by
|
||||
@NTaylorMullen in
|
||||
[#18799](https://github.com/google-gemini/gemini-cli/pull/18799)
|
||||
- feat(plan): create metrics for usage of `AskUser` tool by @Adib234 in
|
||||
[#18820](https://github.com/google-gemini/gemini-cli/pull/18820)
|
||||
- feat(cli): support Ctrl-Z suspension by @scidomino in
|
||||
[#18931](https://github.com/google-gemini/gemini-cli/pull/18931)
|
||||
- fix(github-actions): use robot PAT for release creation to trigger release
|
||||
notes by @SandyTao520 in
|
||||
[#18794](https://github.com/google-gemini/gemini-cli/pull/18794)
|
||||
- feat: add strict seatbelt profiles and remove unusable closed profiles by
|
||||
@SandyTao520 in
|
||||
[#18876](https://github.com/google-gemini/gemini-cli/pull/18876)
|
||||
- chore: cleanup unused and add unlisted dependencies in packages/a2a-server by
|
||||
@adamfweidman in
|
||||
[#18916](https://github.com/google-gemini/gemini-cli/pull/18916)
|
||||
- fix(plan): isolate plan files per session by @Adib234 in
|
||||
[#18757](https://github.com/google-gemini/gemini-cli/pull/18757)
|
||||
- fix: character truncation in raw markdown mode by @jackwotherspoon in
|
||||
[#18938](https://github.com/google-gemini/gemini-cli/pull/18938)
|
||||
- feat(cli): prototype clean UI toggle and minimal-mode bleed-through by
|
||||
@LyalinDotCom in
|
||||
[#18683](https://github.com/google-gemini/gemini-cli/pull/18683)
|
||||
- ui(polish) blend background color with theme by @jacob314 in
|
||||
[#18802](https://github.com/google-gemini/gemini-cli/pull/18802)
|
||||
- Add generic searchable list to back settings and extensions by @chrstnb in
|
||||
[#18838](https://github.com/google-gemini/gemini-cli/pull/18838)
|
||||
- feat(ui): align `AskUser` color scheme with UX spec by @jerop in
|
||||
[#18943](https://github.com/google-gemini/gemini-cli/pull/18943)
|
||||
- Hide AskUser tool validation errors from UI (agent self-corrects) by @jerop in
|
||||
[#18954](https://github.com/google-gemini/gemini-cli/pull/18954)
|
||||
- bug(cli) fix flicker due to AppContainer continuous initialization by
|
||||
@jacob314 in [#18958](https://github.com/google-gemini/gemini-cli/pull/18958)
|
||||
- feat(admin): Add admin controls documentation by @skeshive in
|
||||
[#18644](https://github.com/google-gemini/gemini-cli/pull/18644)
|
||||
- feat(cli): disable ctrl-s shortcut outside of alternate buffer mode by
|
||||
@jacob314 in [#18887](https://github.com/google-gemini/gemini-cli/pull/18887)
|
||||
- fix(vim): vim support that feels (more) complete by @ppgranger in
|
||||
[#18755](https://github.com/google-gemini/gemini-cli/pull/18755)
|
||||
- feat(policy): add --policy flag for user defined policies by @allenhutchison
|
||||
in [#18500](https://github.com/google-gemini/gemini-cli/pull/18500)
|
||||
- Update installation guide by @g-samroberts in
|
||||
[#18823](https://github.com/google-gemini/gemini-cli/pull/18823)
|
||||
- refactor(core): centralize tool definitions (Group 1: replace, search, grep)
|
||||
by @aishaneeshah in
|
||||
[#18944](https://github.com/google-gemini/gemini-cli/pull/18944)
|
||||
- refactor(cli): finalize event-driven transition and remove interaction bridge
|
||||
by @abhipatel12 in
|
||||
[#18569](https://github.com/google-gemini/gemini-cli/pull/18569)
|
||||
- Fix drag and drop escaping by @scidomino in
|
||||
[#18965](https://github.com/google-gemini/gemini-cli/pull/18965)
|
||||
- feat(sdk): initial package bootstrap for SDK by @mbleigh in
|
||||
[#18861](https://github.com/google-gemini/gemini-cli/pull/18861)
|
||||
- feat(sdk): implements SessionContext for SDK tool calls by @mbleigh in
|
||||
[#18862](https://github.com/google-gemini/gemini-cli/pull/18862)
|
||||
- fix(plan): make question type required in AskUser tool by @Adib234 in
|
||||
[#18959](https://github.com/google-gemini/gemini-cli/pull/18959)
|
||||
- fix(core): ensure --yolo does not force headless mode by @NTaylorMullen in
|
||||
[#18976](https://github.com/google-gemini/gemini-cli/pull/18976)
|
||||
- refactor(core): adopt `CoreToolCallStatus` enum for type safety by @jerop in
|
||||
[#18998](https://github.com/google-gemini/gemini-cli/pull/18998)
|
||||
- Enable in-CLI extension management commands for team by @chrstnb in
|
||||
[#18957](https://github.com/google-gemini/gemini-cli/pull/18957)
|
||||
- Adjust lint rules to avoid unnecessary warning. by @scidomino in
|
||||
[#18970](https://github.com/google-gemini/gemini-cli/pull/18970)
|
||||
- fix(vscode): resolve unsafe type assertion lint errors by @ehedlund in
|
||||
[#19006](https://github.com/google-gemini/gemini-cli/pull/19006)
|
||||
- Remove unnecessary eslint config file by @scidomino in
|
||||
[#19015](https://github.com/google-gemini/gemini-cli/pull/19015)
|
||||
- fix(core): Prevent loop detection false positives on lists with long shared
|
||||
prefixes by @SandyTao520 in
|
||||
[#18975](https://github.com/google-gemini/gemini-cli/pull/18975)
|
||||
- feat(core): fallback to chat-base when using unrecognized models for chat by
|
||||
@SandyTao520 in
|
||||
[#19016](https://github.com/google-gemini/gemini-cli/pull/19016)
|
||||
- docs: fix inconsistent commandRegex example in policy engine by @NTaylorMullen
|
||||
in [#19027](https://github.com/google-gemini/gemini-cli/pull/19027)
|
||||
- fix(plan): persist the approval mode in UI even when agent is thinking by
|
||||
@Adib234 in [#18955](https://github.com/google-gemini/gemini-cli/pull/18955)
|
||||
- feat(sdk): Implement dynamic system instructions by @mbleigh in
|
||||
[#18863](https://github.com/google-gemini/gemini-cli/pull/18863)
|
||||
- Docs: Refresh docs to organize and standardize reference materials. by
|
||||
@jkcinouye in [#18403](https://github.com/google-gemini/gemini-cli/pull/18403)
|
||||
- fix windows escaping (and broken tests) by @scidomino in
|
||||
[#19011](https://github.com/google-gemini/gemini-cli/pull/19011)
|
||||
- refactor: use `CoreToolCallStatus` in the the history data model by @jerop in
|
||||
[#19033](https://github.com/google-gemini/gemini-cli/pull/19033)
|
||||
- feat(cleanup): enable 30-day session retention by default by @skeshive in
|
||||
[#18854](https://github.com/google-gemini/gemini-cli/pull/18854)
|
||||
- feat(plan): hide plan write and edit operations on plans in Plan Mode by
|
||||
@jerop in [#19012](https://github.com/google-gemini/gemini-cli/pull/19012)
|
||||
- bug(ui) fix flicker refreshing background color by @jacob314 in
|
||||
[#19041](https://github.com/google-gemini/gemini-cli/pull/19041)
|
||||
- chore: fix dep vulnerabilities by @scidomino in
|
||||
[#19036](https://github.com/google-gemini/gemini-cli/pull/19036)
|
||||
- Revamp automated changelog skill by @g-samroberts in
|
||||
[#18974](https://github.com/google-gemini/gemini-cli/pull/18974)
|
||||
- feat(sdk): implement support for custom skills by @mbleigh in
|
||||
[#19031](https://github.com/google-gemini/gemini-cli/pull/19031)
|
||||
- refactor(core): complete centralization of core tool definitions by
|
||||
@aishaneeshah in
|
||||
[#18991](https://github.com/google-gemini/gemini-cli/pull/18991)
|
||||
- feat: add /commands reload to refresh custom TOML commands by @korade-krushna
|
||||
in [#19078](https://github.com/google-gemini/gemini-cli/pull/19078)
|
||||
- fix(cli): wrap terminal capability queries in hidden sequence by @srithreepo
|
||||
in [#19080](https://github.com/google-gemini/gemini-cli/pull/19080)
|
||||
- fix(workflows): fix GitHub App token permissions for maintainer detection by
|
||||
@bdmorgan in [#19139](https://github.com/google-gemini/gemini-cli/pull/19139)
|
||||
- test: fix hook integration test flakiness on Windows CI by @NTaylorMullen in
|
||||
[#18665](https://github.com/google-gemini/gemini-cli/pull/18665)
|
||||
- fix(core): Encourage non-interactive flags for scaffolding commands by
|
||||
@NTaylorMullen in
|
||||
[#18804](https://github.com/google-gemini/gemini-cli/pull/18804)
|
||||
- fix(core): propagate User-Agent header to setup-phase CodeAssist API calls by
|
||||
@gsquared94 in
|
||||
[#19182](https://github.com/google-gemini/gemini-cli/pull/19182)
|
||||
- docs: document .agents/skills alias and discovery precedence by @kevmoo in
|
||||
[#19166](https://github.com/google-gemini/gemini-cli/pull/19166)
|
||||
- feat(cli): add loading state to new agents notification by @sehoon38 in
|
||||
[#19190](https://github.com/google-gemini/gemini-cli/pull/19190)
|
||||
- Add base branch to workflow. by @g-samroberts in
|
||||
[#19189](https://github.com/google-gemini/gemini-cli/pull/19189)
|
||||
- feat(cli): handle invalid model names in useQuotaAndFallback by @sehoon38 in
|
||||
[#19222](https://github.com/google-gemini/gemini-cli/pull/19222)
|
||||
- docs: custom themes in extensions by @jackwotherspoon in
|
||||
[#19219](https://github.com/google-gemini/gemini-cli/pull/19219)
|
||||
- Disable workspace settings when starting GCLI in the home directory. by
|
||||
@kevinjwang1 in
|
||||
[#19034](https://github.com/google-gemini/gemini-cli/pull/19034)
|
||||
- feat(cli): refactor model command to support set and manage subcommands by
|
||||
@sehoon38 in [#19221](https://github.com/google-gemini/gemini-cli/pull/19221)
|
||||
- Add refresh/reload aliases to slash command subcommands by @korade-krushna in
|
||||
[#19218](https://github.com/google-gemini/gemini-cli/pull/19218)
|
||||
- refactor: consolidate development rules and add cli guidelines by @jacob314 in
|
||||
[#19214](https://github.com/google-gemini/gemini-cli/pull/19214)
|
||||
- chore(ui): remove outdated tip about model routing by @sehoon38 in
|
||||
[#19226](https://github.com/google-gemini/gemini-cli/pull/19226)
|
||||
- feat(core): support custom reasoning models by default by @NTaylorMullen in
|
||||
[#19227](https://github.com/google-gemini/gemini-cli/pull/19227)
|
||||
- Add Solarized Dark and Solarized Light themes by @rmedranollamas in
|
||||
[#19064](https://github.com/google-gemini/gemini-cli/pull/19064)
|
||||
- fix(telemetry): replace JSON.stringify with safeJsonStringify in file
|
||||
exporters by @gsquared94 in
|
||||
[#19244](https://github.com/google-gemini/gemini-cli/pull/19244)
|
||||
- feat(telemetry): add keychain availability and token storage metrics by
|
||||
@abhipatel12 in
|
||||
[#18971](https://github.com/google-gemini/gemini-cli/pull/18971)
|
||||
- feat(cli): update approval mode cycle order by @jerop in
|
||||
[#19254](https://github.com/google-gemini/gemini-cli/pull/19254)
|
||||
- refactor(cli): code review cleanup fix for tab+tab by @jacob314 in
|
||||
[#18967](https://github.com/google-gemini/gemini-cli/pull/18967)
|
||||
- feat(plan): support project exploration without planning when in plan mode by
|
||||
@Adib234 in [#18992](https://github.com/google-gemini/gemini-cli/pull/18992)
|
||||
- feat: add role-specific statistics to telemetry and UI (cont. #15234) by
|
||||
@yunaseoul in [#18824](https://github.com/google-gemini/gemini-cli/pull/18824)
|
||||
- feat(cli): remove Plan Mode from rotation when actively working by @jerop in
|
||||
[#19262](https://github.com/google-gemini/gemini-cli/pull/19262)
|
||||
- Fix side breakage where anchors don't work in slugs. by @g-samroberts in
|
||||
[#19261](https://github.com/google-gemini/gemini-cli/pull/19261)
|
||||
- feat(config): add setting to make directory tree context configurable by
|
||||
@kevin-ramdass in
|
||||
[#19053](https://github.com/google-gemini/gemini-cli/pull/19053)
|
||||
- fix(acp): Wait for mcp initialization in acp (#18893) by @Mervap in
|
||||
[#18894](https://github.com/google-gemini/gemini-cli/pull/18894)
|
||||
- docs: format UTC times in releases doc by @pavan-sh in
|
||||
[#18169](https://github.com/google-gemini/gemini-cli/pull/18169)
|
||||
- Docs: Clarify extensions documentation. by @jkcinouye in
|
||||
[#19277](https://github.com/google-gemini/gemini-cli/pull/19277)
|
||||
- refactor(core): modularize tool definitions by model family by @aishaneeshah
|
||||
in [#19269](https://github.com/google-gemini/gemini-cli/pull/19269)
|
||||
- fix(paths): Add cross-platform path normalization by @spencer426 in
|
||||
[#18939](https://github.com/google-gemini/gemini-cli/pull/18939)
|
||||
- feat(core): experimental in-progress steering hints (1 of 3) by @joshualitt in
|
||||
[#19008](https://github.com/google-gemini/gemini-cli/pull/19008)
|
||||
|
||||
**Full changelog**:
|
||||
https://github.com/google-gemini/gemini-cli/compare/v0.29.0-preview.5...v0.30.0-preview.5
|
||||
@@ -1,77 +0,0 @@
|
||||
# Checkpointing
|
||||
|
||||
The Gemini CLI includes a Checkpointing feature that automatically saves a snapshot of your project's state before any file modifications are made by AI-powered tools. This allows you to safely experiment with and apply code changes, knowing you can instantly revert back to the state before the tool was run.
|
||||
|
||||
## How It Works
|
||||
|
||||
When you approve a tool that modifies the file system (like `write_file` or `replace`), the CLI automatically creates a "checkpoint." This checkpoint includes:
|
||||
|
||||
1. **A Git Snapshot:** A commit is made in a special, shadow Git repository located in your home directory (`~/.gemini/history/<project_hash>`). This snapshot captures the complete state of your project files at that moment. It does **not** interfere with your own project's Git repository.
|
||||
2. **Conversation History:** The entire conversation you've had with the agent up to that point is saved.
|
||||
3. **The Tool Call:** The specific tool call that was about to be executed is also stored.
|
||||
|
||||
If you want to undo the change or simply go back, you can use the `/restore` command. Restoring a checkpoint will:
|
||||
|
||||
- Revert all files in your project to the state captured in the snapshot.
|
||||
- Restore the conversation history in the CLI.
|
||||
- Re-propose the original tool call, allowing you to run it again, modify it, or simply ignore it.
|
||||
|
||||
All checkpoint data, including the Git snapshot and conversation history, is stored locally on your machine. The Git snapshot is stored in the shadow repository while the conversation history and tool calls are saved in a JSON file in your project's temporary directory, typically located at `~/.gemini/tmp/<project_hash>/checkpoints`.
|
||||
|
||||
## Enabling the Feature
|
||||
|
||||
The Checkpointing feature is disabled by default. To enable it, you can either use a command-line flag or edit your `settings.json` file.
|
||||
|
||||
### Using the Command-Line Flag
|
||||
|
||||
You can enable checkpointing for the current session by using the `--checkpointing` flag when starting the Gemini CLI:
|
||||
|
||||
```bash
|
||||
gemini --checkpointing
|
||||
```
|
||||
|
||||
### Using the `settings.json` File
|
||||
|
||||
To enable checkpointing by default for all sessions, you need to edit your `settings.json` file.
|
||||
|
||||
Add the following key to your `settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"general": {
|
||||
"checkpointing": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Using the `/restore` Command
|
||||
|
||||
Once enabled, checkpoints are created automatically. To manage them, you use the `/restore` command.
|
||||
|
||||
### List Available Checkpoints
|
||||
|
||||
To see a list of all saved checkpoints for the current project, simply run:
|
||||
|
||||
```
|
||||
/restore
|
||||
```
|
||||
|
||||
The CLI will display a list of available checkpoint files. These file names are typically composed of a timestamp, the name of the file being modified, and the name of the tool that was about to be run (e.g., `2025-06-22T10-00-00_000Z-my-file.txt-write_file`).
|
||||
|
||||
### Restore a Specific Checkpoint
|
||||
|
||||
To restore your project to a specific checkpoint, use the checkpoint file from the list:
|
||||
|
||||
```
|
||||
/restore <checkpoint_file>
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
/restore 2025-06-22T10-00-00_000Z-my-file.txt-write_file
|
||||
```
|
||||
|
||||
After running the command, your files and conversation will be immediately restored to the state they were in when the checkpoint was created, and the original tool prompt will reappear.
|
||||
@@ -1,181 +0,0 @@
|
||||
# Authentication Setup
|
||||
|
||||
Gemini CLI requires you to authenticate with Google's AI services. On initial startup you'll need to configure **one** of the following authentication methods:
|
||||
|
||||
1. **Login with Google**
|
||||
1. **Google AI Pro and AI Ultra subscribers**
|
||||
- Use this option to log in with your Google account that you use with Google AI Pro and Ultra.
|
||||
- During initial startup, Gemini CLI will direct you to a webpage for authentication. Once authenticated, your credentials will be cached locally so the web login can be skipped on subsequent runs.
|
||||
- Note that the web login must be done in a browser that can communicate with the machine Gemini CLI is being run from. (Specifically, the browser will be redirected to a localhost URL that Gemini CLI will be listening on.)
|
||||
2. **Gemini Code Assist:**
|
||||
- Use this option to log in with your Google account.
|
||||
- During initial startup, Gemini CLI will direct you to a webpage for authentication. Once authenticated, your credentials will be cached locally so the web login can be skipped on subsequent runs.
|
||||
- Note that the web login must be done in a browser that can communicate with the machine Gemini CLI is being run from. (Specifically, the browser will be redirected to a localhost url that Gemini CLI will be listening on.)
|
||||
- <a id="workspace-gca">Users may have to specify a GOOGLE_CLOUD_PROJECT if:</a>
|
||||
1. You have a Google Workspace account. Google Workspace is a paid service for businesses and organizations that provides a suite of productivity tools, including a custom email domain (e.g. your-name@your-company.com), enhanced security features, and administrative controls. These accounts are often managed by an employer or school.
|
||||
1. You have received a Gemini Code Assist license through the [Google Developer Program](https://developers.google.com/program/plans-and-pricing) (including qualified Google Developer Experts).
|
||||
1. You have been assigned a license to a current Gemini Code Assist standard or enterprise subscription.
|
||||
1. You are using the product outside the [supported regions](https://developers.google.com/gemini-code-assist/resources/available-locations) for free individual usage.
|
||||
1. You are a Google account holder under the age of 18.
|
||||
- If you fall into one of these categories, you must first configure a Google Cloud Project ID to use, [enable the Gemini for Cloud API](https://cloud.google.com/gemini/docs/discover/set-up-gemini#enable-api) and [configure access permissions](https://cloud.google.com/gemini/docs/discover/set-up-gemini#grant-iam).
|
||||
|
||||
You can temporarily set the environment variable in your current shell session using the following command:
|
||||
|
||||
```bash
|
||||
export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
|
||||
```
|
||||
- For repeated use, you can add the environment variable to your [.env file](#persisting-environment-variables-with-env-files) or your shell's configuration file (like `~/.bashrc`, `~/.zshrc`, or `~/.profile`). For example, the following command adds the environment variable to a `~/.bashrc` file:
|
||||
|
||||
```bash
|
||||
echo 'export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
2. **<a id="gemini-api-key"></a>Gemini API key:**
|
||||
- Obtain your API key from Google AI Studio: [https://aistudio.google.com/app/apikey](https://aistudio.google.com/app/apikey)
|
||||
- Set the `GEMINI_API_KEY` environment variable. In the following methods, replace `YOUR_GEMINI_API_KEY` with the API key you obtained from Google AI Studio:
|
||||
- You can temporarily set the environment variable in your current shell session using the following command:
|
||||
```bash
|
||||
export GEMINI_API_KEY="YOUR_GEMINI_API_KEY"
|
||||
```
|
||||
- For repeated use, you can add the environment variable to your [.env file](#persisting-environment-variables-with-env-files).
|
||||
|
||||
- Alternatively you can export the API key from your shell's configuration file (like `~/.bashrc`, `~/.zshrc`, or `~/.profile`). For example, the following command adds the environment variable to a `~/.bashrc` file:
|
||||
|
||||
```bash
|
||||
echo 'export GEMINI_API_KEY="YOUR_GEMINI_API_KEY"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
:warning: Be advised that when you export your API key inside your shell configuration file, any other process executed from the shell can read it.
|
||||
|
||||
3. **Vertex AI:**
|
||||
- **API Key:**
|
||||
- Obtain your Google Cloud API key: [Get an API Key](https://cloud.google.com/vertex-ai/generative-ai/docs/start/api-keys?usertype=newuser)
|
||||
- Set the `GOOGLE_API_KEY` environment variable. In the following methods, replace `YOUR_GOOGLE_API_KEY` with your Vertex AI API key:
|
||||
- You can temporarily set the environment variable in your current shell session using the following command:
|
||||
```bash
|
||||
export GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"
|
||||
```
|
||||
- For repeated use, you can add the environment variable to your [.env file](#persisting-environment-variables-with-env-files) or your shell's configuration file (like `~/.bashrc`, `~/.zshrc`, or `~/.profile`). For example, the following command adds the environment variable to a `~/.bashrc` file:
|
||||
|
||||
```bash
|
||||
echo 'export GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
:warning: Be advised that when you export your API key inside your shell configuration file, any other process executed from the shell can read it.
|
||||
|
||||
> **Note:**
|
||||
> If you encounter an error like `"API keys are not supported by this API - Expected OAuth2 access token or other authentication credentials that assert a principal"`, it is likely that your organization has restricted the creation of service account API keys. In this case, please try the [service account JSON key](#service-account-json-key) method described below.
|
||||
|
||||
- **Application Default Credentials (ADC):**
|
||||
|
||||
> **Note:**
|
||||
> If you have previously set the `GOOGLE_API_KEY` or `GEMINI_API_KEY` environment variables, you must unset them to use Application Default Credentials.
|
||||
>
|
||||
> ```bash
|
||||
> unset GOOGLE_API_KEY GEMINI_API_KEY
|
||||
> ```
|
||||
- **Using `gcloud` (for local development):**
|
||||
- Ensure you have a Google Cloud project and have enabled the Vertex AI API.
|
||||
- Log in with your user credentials:
|
||||
```bash
|
||||
gcloud auth application-default login
|
||||
```
|
||||
For more information, see [Set up Application Default Credentials for Google Cloud](https://cloud.google.com/docs/authentication/provide-credentials-adc).
|
||||
- **<a id="service-account-json-key"></a>Using a Service Account (for applications or when service account API keys are restricted):**
|
||||
- If you are unable to create an API key due to [organization policies](https://cloud.google.com/vertex-ai/generative-ai/docs/start/api-keys?usertype=existinguser#expandable-2), or if you are running in a non-interactive environment, you can authenticate using a service account key.
|
||||
- [Create a service account and key](https://cloud.google.com/iam/docs/keys-create-delete), and download the JSON key file. The service account will need to be assigned the "Vertex AI User" role.
|
||||
- Set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable to the absolute path of the JSON file.
|
||||
- You can temporarily set the environment variable in your current shell session:
|
||||
```bash
|
||||
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/keyfile.json"
|
||||
```
|
||||
- For repeated use, you can add the command to your shell's configuration file (e.g., `~/.bashrc`).
|
||||
```bash
|
||||
echo 'export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/keyfile.json"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
:warning: Be advised that when you export service account credentials inside your shell configuration file, any other process executed from the shell can read it.
|
||||
|
||||
- **Required Environment Variables for ADC:**
|
||||
- When using ADC (either with `gcloud` or a service account), you must also set the `GOOGLE_CLOUD_PROJECT` and `GOOGLE_CLOUD_LOCATION` environment variables. In the following methods, replace `YOUR_PROJECT_ID` and `YOUR_PROJECT_LOCATION` with the relevant values for your project:
|
||||
- You can temporarily set these environment variables in your current shell session using the following commands:
|
||||
```bash
|
||||
export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
|
||||
export GOOGLE_CLOUD_LOCATION="YOUR_PROJECT_LOCATION" # e.g., us-central1
|
||||
```
|
||||
- For repeated use, you can add the environment variables to your [.env file](#persisting-environment-variables-with-env-files) or your shell's configuration file (like `~/.bashrc`, `~/.zshrc`, or `~/.profile`). For example, the following commands add the environment variables to a `~/.bashrc` file:
|
||||
```bash
|
||||
echo 'export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"' >> ~/.bashrc
|
||||
echo 'export GOOGLE_CLOUD_LOCATION="YOUR_PROJECT_LOCATION"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
4. **Cloud Shell:**
|
||||
- This option is only available when running in a Google Cloud Shell environment.
|
||||
- It automatically uses the credentials of the logged-in user in the Cloud Shell environment.
|
||||
- This is the default authentication method when running in Cloud Shell and no other method is configured.
|
||||
|
||||
:warning: Be advised that when you export your API key inside your shell configuration file, any other process executed from the shell can read it.
|
||||
|
||||
### Persisting Environment Variables with `.env` Files
|
||||
|
||||
You can create a **`.gemini/.env`** file in your project directory or in your home directory. Creating a plain **`.env`** file also works, but `.gemini/.env` is recommended to keep Gemini variables isolated from other tools.
|
||||
|
||||
**Important:** Some environment variables (like `DEBUG` and `DEBUG_MODE`) are automatically excluded from project `.env` files to prevent interference with gemini-cli behavior. Use `.gemini/.env` files for gemini-cli specific variables.
|
||||
|
||||
Gemini CLI automatically loads environment variables from the **first** `.env` file it finds, using the following search order:
|
||||
|
||||
1. Starting in the **current directory** and moving upward toward `/`, for each directory it checks:
|
||||
1. `.gemini/.env`
|
||||
2. `.env`
|
||||
2. If no file is found, it falls back to your **home directory**:
|
||||
- `~/.gemini/.env`
|
||||
- `~/.env`
|
||||
|
||||
> **Important:** The search stops at the **first** file encountered—variables are **not merged** across multiple files.
|
||||
|
||||
#### Examples
|
||||
|
||||
**Project-specific overrides** (take precedence when you are inside the project):
|
||||
|
||||
```bash
|
||||
mkdir -p .gemini
|
||||
echo 'GOOGLE_CLOUD_PROJECT="your-project-id"' >> .gemini/.env
|
||||
```
|
||||
|
||||
**User-wide settings** (available in every directory):
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.gemini
|
||||
cat >> ~/.gemini/.env <<'EOF'
|
||||
GOOGLE_CLOUD_PROJECT="your-project-id"
|
||||
GEMINI_API_KEY="your-gemini-api-key"
|
||||
EOF
|
||||
```
|
||||
|
||||
## Non-Interactive Mode / Headless Environments
|
||||
|
||||
When running the Gemini CLI in a non-interactive environment, you cannot use the interactive login flow.
|
||||
Instead, you must configure authentication using environment variables.
|
||||
|
||||
The CLI will automatically detect if it is running in a non-interactive terminal and will use one of the
|
||||
following authentication methods if available:
|
||||
|
||||
1. **Gemini API Key:**
|
||||
- Set the `GEMINI_API_KEY` environment variable.
|
||||
- The CLI will use this key to authenticate with the Gemini API.
|
||||
|
||||
2. **Vertex AI:**
|
||||
- Set the `GOOGLE_GENAI_USE_VERTEXAI=true` environment variable.
|
||||
- **Using an API Key:** Set the `GOOGLE_API_KEY` environment variable.
|
||||
- **Using Application Default Credentials (ADC):**
|
||||
- Run `gcloud auth application-default login` in your environment to configure ADC.
|
||||
- Ensure the `GOOGLE_CLOUD_PROJECT` and `GOOGLE_CLOUD_LOCATION` environment variables are set.
|
||||
|
||||
If none of these environment variables are set in a non-interactive session, the CLI will exit with an error.
|
||||
|
||||
For comprehensive guidance on using Gemini CLI programmatically and in
|
||||
automation workflows, see the [Headless Mode Guide](../headless.md).
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user