Compare commits

...

1051 Commits

Author SHA1 Message Date
Philipp Schmid ac24fd27e4 Update Auth Label to include AI Studio (#2130)
Co-authored-by: Allen Hutchison <adh@google.com>
2025-06-27 21:33:26 +00:00
Xi Chen d35e7d3eb1 Fix a circular dependency (#2246)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
2025-06-27 20:59:47 +00:00
Brandon Keiji 8d1d40cc7a chore: bump to 0.1.6 (#2285) 2025-06-27 20:57:07 +00:00
Tommaso Sciortino a2a46c7c67 Add privacy notice slash command (#2059) 2025-06-27 19:07:38 +00:00
Billy Biggs 4fbffdf617 Handle stdin for prompts using readline for escape character parsing (#1972) 2025-06-27 17:57:32 +00:00
Preston Holmes 5fd6664c4b Further clarify the situations where a Project ID is required (#2029)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2025-06-27 16:51:28 +00:00
Preston Holmes 3aabb940f5 Add the current auth method and GCP Project config to the about message (#2112) 2025-06-27 15:46:27 +00:00
Srinath Padmanabhan 3ebf54f367 Refine Fallback message providing more options. (#1961) 2025-06-27 15:21:46 +00:00
Billy Biggs 582b4861a9 Use 2-space indent for saved checkpoint files (#1152) (#1977)
Co-authored-by: Jacob Richman <jacob314@gmail.com>
2025-06-27 13:39:27 +00:00
DongJin Jeong a943cee45d Fix typos and formatting issues (#1480) 2025-06-27 10:31:42 +00:00
Seth Troisi 6742a1b7f9 Explicit message for missing subcommand (#2019) 2025-06-27 05:01:00 +00:00
Brandon Keiji bf873a1d85 feat: add prepublishOnly checks (#2052) 2025-06-26 23:49:43 +00:00
Brandon Keiji d9892ada7f fix: add repository field to package.jsons (#2032) 2025-06-26 22:36:34 +00:00
Bryan Morgan 560905154c Updating the first user message to mention the product name (#2037) 2025-06-26 22:32:19 +00:00
anj-s 267173c7e8 Revert "feat: Add model selection logic (#1678)" (#1983) 2025-06-26 20:59:16 +00:00
Tommaso Sciortino c55b15f705 Improve LoadCodeAssist error handling (#1645) 2025-06-26 15:27:20 +00:00
N. Taylor Mullen 24ccc9c457 feat: Add model selection logic (#1678) 2025-06-26 14:51:32 +00:00
Vladislav Semyanov 121bba3464 docs: fix broken configuration link in themes.md (#1780) 2025-06-26 07:37:42 +00:00
김진엽 (Nathan) 02bd8dfeff docs: fix multiple typos in documentation files (#1781) 2025-06-26 07:36:31 +00:00
Masato Sugiyama ee5bf842eb fix: remove unnecessary @gemini-code/core mock from slashCommandProcessor test (#1739)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
2025-06-26 04:56:51 +00:00
Keith Ballinger 891116a6c2 Flaky test (#1405)
Co-authored-by: matt korwel <matt.korwel@gmail.com>
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
2025-06-26 04:45:39 +00:00
Noritaka Kobayashi dbe217828d chore: fix typos in comment-out (#1540)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
2025-06-26 04:34:53 +00:00
Andrew Drozdov b8ae12a109 Update geminiChat.ts (#1681)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
2025-06-26 04:27:35 +00:00
Billy Biggs 759ad4cc96 When resuming a checkpoint always add items to history even if not shown (#1653)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
2025-06-26 04:23:47 +00:00
Jennifer Davis 4d4b95a41d fix: add engines check to ensure older Node.js versions don't fail at… (#1752) 2025-06-26 04:09:40 +00:00
mpAtGoogle 046c7f84bc Update LICENSE (#1664) 2025-06-26 03:34:01 +00:00
Brandon Keiji 01ff27709d chore: bump to 0.1.5 (#1731) 2025-06-26 02:48:16 +00:00
anj-s 1078a546fe Fix doc link in the auth dialog (#1688) 2025-06-26 01:59:13 +00:00
Brandon Keiji a8763abfb7 feat: add release trigger configuration (#1697) 2025-06-26 01:54:58 +00:00
Bryan Morgan bb797ded7d 429 fix (#1668) 2025-06-26 01:45:38 +00:00
Jerop Kipruto b6b9923dc3 Streamline issue submission with YAML forms (#1608) 2025-06-25 22:50:24 +00:00
Tommaso Sciortino 79c647d486 Merge "Login with Google Workspace" auth option into "Login with Google" (#1574)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
2025-06-25 22:38:18 +00:00
anj-s 00b24c917e Update usage stats doc (#1636) 2025-06-25 22:26:07 +00:00
Logan Kilpatrick 32b2e79b62 Update README.md (#1632) 2025-06-25 21:41:52 +00:00
anj-s 5aa6b9a84b Update docs and add faq section (#1625) 2025-06-25 21:32:16 +00:00
Jerop Kipruto 8c5a0b6f88 prompt users to search for existing issues before creating a new one (#1595) 2025-06-25 20:29:51 +00:00
zhiyue b0cf9bcece fix(telemetry): handle all promise rejections in ClearcutLogger (#1557)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
2025-06-25 20:14:44 +00:00
Seth Troisi 31f32421a3 Minor style changes to prompt (#1578) 2025-06-25 20:00:44 +00:00
Bryan Morgan eacbb3551c changed 429 failover from 3 consecutive to 2 for OAuth users (#1579) 2025-06-25 19:37:23 +00:00
anj-s 4b5ca6bc77 Add tos and privacy links docs for clarity (#1571) 2025-06-25 19:32:25 +00:00
Mark McDonald 452b82162b Adding some troubleshooting text for login issues (#1451) 2025-06-25 19:00:36 +00:00
DongJin Jeong aa0e375508 Fix: update npx command to correct GitHub repository URL (#1488) 2025-06-25 18:58:11 +00:00
Jenna Inouye 6a0b8a733b Add information request to bug reports: login method. (#1501) 2025-06-25 18:55:35 +00:00
Arjun Lall 63a7fbc5fd Fixed Checkpointing docs for enabling checkpointing using settings.json (#1534) 2025-06-25 18:51:38 +00:00
N. Taylor Mullen 3a369ddec3 feat: Refine model fallback messaging to reflect reality. (#1527) 2025-06-25 17:33:32 +00:00
starsandskies 0915bf7d67 Remove GEMINI_CODE_ASSIST env variable from configuration.md doc (#1514) 2025-06-25 16:45:40 +00:00
Marat Boshernitsan 9897a2b80a Clarify why authentication failures might be happening and direct users to documentation (#1478)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
Co-authored-by: matt korwel <matt.korwel@gmail.com>
2025-06-25 16:11:54 +00:00
Jason Davenport 819507c5e8 Update Readme to call out gemini command after npm install (#1423)
Co-authored-by: Mark McDonald <macd@google.com>
2025-06-25 16:03:07 +00:00
matt korwel 45b2b382cc Prod: Integration Tests Main Only (#1461) 2025-06-25 15:56:06 +00:00
Thomas Kosiewski af4dfd9327 Update authentication.md (#1429)
Co-authored-by: matt korwel <matt.korwel@gmail.com>
2025-06-25 15:48:15 +00:00
matt korwel 21cfe9f680 issue template update (#1441) 2025-06-25 14:44:34 +00:00
matt korwel 6991ba1387 Version 0 1 1 (#1426) 2025-06-25 13:47:27 +00:00
Asad Memon 452dca4301 Fix typo in intro on MCP line (#1421) 2025-06-25 13:04:42 +00:00
N. Taylor Mullen 852210e108 Shipping it! (#1418) 2025-06-25 12:42:04 +00:00
Brandon Keiji f6c36f75e3 fix: prepublish changes to package names (#1420) 2025-06-25 12:41:11 +00:00
Jenna Inouye a3c46c0d31 Docs: Add link links to tools/index.md. (#1419) 2025-06-25 11:16:17 +00:00
Mark McDonald f78479d7ce Add intro text back to README (#1417)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-06-25 10:12:31 +00:00
Mark McDonald cfc13fbd58 Add 'npm i' instruction to README (#1416) 2025-06-25 09:46:05 +00:00
matt korwel 9a093e4b51 CI: Linting Fix (#1413)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
2025-06-25 04:18:51 +00:00
Preston Holmes 4cc2b27f1d Docs: update docs to clarify the differences between Google account login o… (#1409)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
Co-authored-by: matt korwel <mattkorwel@google.com>
Co-authored-by: matt korwel <matt.korwel@gmail.com>
2025-06-25 04:15:45 +00:00
Scott Densmore 39bfa108b5 refactor: remove deplicate dependency in slashCommandProcessor (#1410)
Co-authored-by: matt korwel <matt.korwel@gmail.com>
2025-06-25 04:07:20 +00:00
Daniel Tedesco 268d29f05c docs: fix typos in documentation (#1411)
Co-authored-by: Dan Tedesco <dted@google.com>
2025-06-25 03:53:03 +00:00
Keith Ballinger b6ccf12551 [June 25] handle early output pipe closer (#1402) 2025-06-25 00:39:01 +00:00
matt korwel fbd8725c07 fix(update-notifier): resolve __dirname error on npx execution (#1406) 2025-06-25 00:26:50 +00:00
matt korwel 2505af8522 Prerelease: Cleanup (#1404) 2025-06-24 23:41:36 +00:00
Brian Ray d45d414c93 sandbox doc (#1390)
Co-authored-by: matt korwel <matt.korwel@gmail.com>
Co-authored-by: Jenna Inouye <jinouye@google.com>
2025-06-24 23:11:39 +00:00
Seth Troisi d8000c9248 Add slashCommand dependency (#1401) 2025-06-24 22:55:26 +00:00
Marat Boshernitsan e3def2dd49 fix: use correct directory for update checks (#1394) 2025-06-24 22:51:16 +00:00
Bryan Morgan e356949d3f [JUNE 25] Permanent failover to Flash model for OAuth users after persistent 429 errors (#1376)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
2025-06-24 22:48:55 +00:00
Jenna Inouye 4bf18da2b0 Documents: Add docs tools pages (#1397) 2025-06-24 22:31:58 +00:00
Jacob Richman 8bd5645dd4 Truncate all strings before displaying in a tool messages to avoid stack overflows (#1395) 2025-06-24 22:31:55 +00:00
Mark McDonald 1f6fe59def Added ToS links for each surface (#1365)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
Co-authored-by: matt korwel <matt.korwel@gmail.com>
2025-06-24 22:31:50 +00:00
anj-s 418f67086b Add the link to the privacy policy to the Usage Statistics section and remove debug logs (#1393) 2025-06-24 22:31:45 +00:00
cperry-goog 13cff94b1a docs: add screenshot to README (#1396) 2025-06-24 22:31:40 +00:00
Louis Jimenez 7421bf681b Checkpointing documentation (#1321)
Co-authored-by: matt korwel <matt.korwel@gmail.com>
2025-06-24 22:31:32 +00:00
matt korwel db57d38d92 feat: add merge_group trigger to CI and E2E workflows (#1400) 2025-06-24 15:30:31 -07:00
Jacob Richman 5ff00b0c5d Remove uses of the spread operator that appear to have caused a maximum call stack size exceeded error (#1389) 2025-06-24 21:38:25 +00:00
Jacob Richman 75ed7aaa06 Jacob314/max old space (#1314) 2025-06-24 14:18:55 -07:00
Sandy Tao a411c415a8 Do not render mcp responses as markdown (#1388) 2025-06-24 14:10:41 -07:00
Brian Ray e613cbc448 MCP documentation improvements (#1386)
Co-authored-by: Jenna Inouye <jinouye@google.com>
2025-06-24 13:19:36 -07:00
Bryan Morgan 5099f104bc [June 25] Fixed user agent string to be standards-compliant (#1384) 2025-06-24 09:11:09 -07:00
Billy Biggs b47a4240ff Bug/1369 at command recursive search (#1370) 2025-06-24 06:48:26 +00:00
cornmander a2ed4266aa Update editor.ts (#1371) 2025-06-24 06:41:40 +00:00
Scott Densmore 324715ee8b Add Zed Editor to Eidtor List (#1372) 2025-06-23 23:32:09 -07:00
starsandskies 9f5a625730 Fix broken doc links (#1368) 2025-06-23 20:56:57 -07:00
Abhi d3f13c71ae feat: add custom message for 429 errors (#1366) 2025-06-24 03:43:00 +00:00
Bryan Morgan f7caca5f94 Updated README.md (#1367) 2025-06-23 23:37:07 -04:00
Tommaso Sciortino 0abd2a644e Improve Auth error messaging (#1358) 2025-06-24 01:37:41 +00:00
Seth Troisi 104f23da90 Add /chat list (#1361) 2025-06-24 01:11:45 +00:00
owenofbrien 37034045ae Fix Clearcut logging wire format (#1359)
Fix for Clearcut logging wire format based on validation thread with Clearcut / Concord eng
2025-06-23 17:47:37 -07:00
Jerop Kipruto aca034fdfe Refactor usage statistics to be a top-level setting (#1363)
This commit refactors the `usageStatisticsEnabled` setting from a sub-property of the `telemetry` configuration to a top-level setting. This change simplifies the configuration by decoupling usage statistics from the telemetry settings.

The documentation has also been updated to reflect this change.
2025-06-24 00:29:31 +00:00
cperry-goog b3741f7016 docs: update configuration.md with new CLI options (#1360) 2025-06-23 17:24:55 -07:00
anj-s 3012684469 Fix duplicate startSession logs and duplicate logging events over the wire (#1357) 2025-06-24 00:05:42 +00:00
Seth Troisi 335802f4dd moving /save, /resume to /chat <save|resume> (#1355) 2025-06-23 16:56:08 -07:00
Jacob Richman f741630572 Polish Theme Dialog (#1356) 2025-06-23 16:43:17 -07:00
Seth Troisi 8c6545bf9d Include all chat messages (#1354) 2025-06-23 22:41:33 +00:00
Bryan Morgan e21dbed8c8 [June 25] Updated docs for telemetry and user statistics (#1346) 2025-06-23 22:25:49 +00:00
starsandskies 160d6a6552 Docs: Add telemetry to the list of configuration options (#1348) 2025-06-23 22:18:07 +00:00
Jerop Kipruto b443b5e800 Ensure telemetry events are flushed immediately (#1344)
The previous implementation used `flushIfNeeded` to batch most telemetry events, but it was not reliably sending them, leading to data loss. Notably, the `startSession` event, which already used `flushToClearcut`, was working correctly, indicating an issue with the batching logic itself.

This change replaces all calls to `flushIfNeeded` with `flushToClearcut` to align all event logging with the working `startSession` implementation and ensure that events are sent immediately. This prioritizes the reliability of data collection over network efficiency.

This is a temporary solution to prevent further data loss. The underlying issue with the batching mechanism in `flushIfNeeded` should be investigated and fixed in the future, at which point this change can be reverted.
2025-06-23 22:05:02 +00:00
Jerop Kipruto 58572a6eaa Use concurrently to run start script with GCP telemetry (#1329)
## TLDR

Introduces the `concurrently` package to simplify the dev startup process with GCP telemetry enabled.

## Dive Deeper

Previously, developers had to run the telemetry script and the main application start script in separate terminals. This change updates the `start:gcp` script to use `concurrently`, allowing both processes to be launched and managed with a single command. This improves the developer experience and reduces the chance of forgetting to start one of the required processes. 

## Reviewer Test Plan
Set the required environment variable:

```shell
export OTLP_GOOGLE_CLOUD_PROJECT=<your-project-id>
```

Run the following command:

```shell
npm run start:gcp
```

#750 

cc @teeler
2025-06-23 22:01:22 +00:00
Bryan Morgan e423d20a8d Updated docs and /stats command to support lack of token caching support for OAuth users (b/426943001) (#1307) 2025-06-23 21:55:24 +00:00
Sandy Tao fcb8be2fb9 Refine refresh static logic (#1349) 2025-06-23 21:45:15 +00:00
Jacob Richman 1faf53a3af Remove fallback to render normall rather than using custom MaxSizedBox layout logic (#1340) 2025-06-23 21:41:45 +00:00
N. Taylor Mullen fd58d3267e feat: Open MCP docs if no MCPs are configured (#1325) 2025-06-23 21:35:23 +00:00
Abhi dc76bcc433 Add error messaging for 429 errors (#1316) 2025-06-23 21:30:13 +00:00
Jerop Kipruto 21e6a36cf1 docs(telemetry): relocate telemetry documentation (#1327)
Moves the telemetry.md file from docs/core to the top-level docs/ directory to make it more discoverable.

Updates the link in the main index.md and removes the old reference from the CLI configuration page.
2025-06-23 21:24:48 +00:00
Jerop Kipruto 98f3a7066e refactor: rename disableDataCollection to dataCollectionEnabled (#1319)
Renames the `disableDataCollection` flag to the more intuitive and positive `dataCollectionEnabled`.

This change improves code clarity by avoiding double negatives and making the purpose of the flag more direct. The logic has been inverted wherever the flag is used to accommodate the new naming convention.

Using a suffix like `"Enabled"` follows a common convention that improves readability. 
- A condition like `if (dataCollectionEnabled)` reads like a natural language sentence ("if data collection is enabled"), which reduces cognitive load.
- Distinguishes the boolean flag (representing a state) from potential functions that would perform an action (e.g., `enableDataCollection()` or `disableDataCollection()`), avoiding ambiguity between checking a value and calling a function.

#750
2025-06-23 21:19:40 +00:00
Jerop Kipruto 4d88054d35 Fix batch flush to Clearcut (#1337)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
2025-06-23 21:12:58 +00:00
starsandskies d2ae7af487 Edit pass of docs/core/index.md (#1338)
Make a pass through the docs/core/index.md file to hopefully improve readability and consistency.

Of particular note, I've cut out a big chunk that felt mostly like implementation details that aren't particularly relevant for public consumption, and I cut out a discussion of cli/core interconnection that is covered better higher up in the docs hierarchy
2025-06-23 21:07:03 +00:00
cperry-goog 139668c1d1 Docs/authentication doc (#1341) 2025-06-23 13:02:52 -07:00
cperry-goog 1825105d8f feat(docs): add /chat and /restore commands (#1336) 2025-06-23 12:10:23 -07:00
Jacob Richman 3e25c350f2 A couple of these log messages were now showing up every time on app startup (#1335) 2025-06-23 11:31:13 -07:00
N. Taylor Mullen 4b7307accb Remove .gitignore logging from startup. (#1323) 2025-06-23 11:12:42 -07:00
owenofbrien 631591ce79 Enable clearcut logging by default (#1309)
Clearcut logging can now be disabled via disableDataCollection in user settings
2025-06-23 10:18:58 -07:00
Tommaso Sciortino 07880d43d2 Sanitize MCP FunctionDeclarations to workaround Vertex bug (#1330) 2025-06-23 09:13:53 -07:00
Mark McDonald 7b39dd8b28 Added some use cases to the README (#1257) 2025-06-23 07:07:18 +00:00
matt korwel d0800ab917 Adding .gitattributes (#1303) 2025-06-23 06:58:41 +00:00
Scott Densmore 99d521569d Scotdensmore/first run auth fix (#1322) 2025-06-22 22:52:25 -07:00
Jacob Richman 156feff5b1 Fix so that pressing ctrl-s a second time toggles off constrain height mode (#1306) 2025-06-23 05:42:20 +00:00
Mark McDonald 523aeec544 Use shorter URL for docs link (#1324) 2025-06-23 05:37:41 +00:00
Jerop Kipruto 64e1c7df75 docs: update telemetry documentation and scripts (#1318) 2025-06-23 06:10:26 +01:00
matt korwel da128e725d {bug} Vertex Auth Support (#1302)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2025-06-23 00:30:58 +00:00
Abhi d8ecbde9bd add bash block to doc for easy copypasta (#1317) 2025-06-22 20:19:13 -04:00
Billy Biggs c9bea8e646 Plumb extension context filenames through for /memory refresh (#1312) 2025-06-22 16:17:05 -07:00
cperry-goog b05b8673cd update tips (#1315) 2025-06-22 16:02:48 -07:00
Jacob Richman b831ffc1b3 Jacob314/auto exit unconstrained height mode (#1293)
Co-authored-by: Scott Densmore <scottdensmore@mac.com>
2025-06-22 13:43:36 -07:00
N. Taylor Mullen 6a1c62731b Fix seatbelt sandboxing when GEMINI_SANDBOX="" and starting with -s (#1298) 2025-06-22 18:33:29 +00:00
N. Taylor Mullen 3c656cfbc6 feat: Only show ctrl-s when idle (#1299) 2025-06-22 15:57:53 +00:00
N. Taylor Mullen cb76b08e31 feat: Add /docs command and update UI (#1297) 2025-06-22 15:54:10 +00:00
owenofbrien 4cfab0a893 Clearcut logging - initial implementation (#1274)
Flag-guarded initial implementation of a clearcut logger to collect telemetry data and send it to Concord for dashboards, etc.
2025-06-22 14:26:48 +00:00
Abhi c9950b3cb2 feat: Add client-initiated tool call handling (#1292) 2025-06-22 01:35:36 -04:00
cperry-goog 5cf8dc4f07 Docs update (#1295) 2025-06-22 05:06:58 +00:00
Louis Jimenez 383212034c Provide a .gitconfig for shadow repos (#1294) 2025-06-22 00:13:03 -04:00
Billy Biggs 0779697da6 Add setting enableRecursiveFileSearch to control @-file completion (#1290) 2025-06-22 01:23:35 +00:00
Jacob Richman 63f6a497cb Jacob314/overflow notification and one MaxSizedBox bug fix (#1288) 2025-06-22 00:54:10 +00:00
cperry-goog e20171e7dd Updating missing commands (#1289) 2025-06-21 17:41:03 -07:00
cperry-goog 47780e984c docs: update README (#1287) 2025-06-21 16:18:23 -07:00
Marlon Gamez 076f81f130 point Code Assist client to prod server (#1201) 2025-06-21 22:25:18 +00:00
cperry-goog e255eb6124 feat(cli): update Tips.tsx component (#1284) 2025-06-21 12:58:00 -07:00
Billy Biggs 99a6dc0267 Update memory and context summary UI for multiple context filenames (#1282) 2025-06-21 19:15:43 +00:00
Sandy Tao 03af6235a9 Fix Static duplication and input prompt tearing (#1279) 2025-06-21 11:11:42 -07:00
Tommaso Sciortino f9b2a33732 Remove packages/cli/README.md (#1278) 2025-06-21 16:43:01 +01:00
Abhi 52afcb3a12 bug: fix cancel after a tool has been used (#1270) 2025-06-20 20:01:44 -07:00
Brandon Keiji 1d32313a30 fix: remove circular references in core package (#1271) (#1272) 2025-06-20 16:21:09 -07:00
Tommaso Sciortino 4acb870959 Remove #early-access from npx references (#1262) 2025-06-20 20:32:27 +00:00
matt korwel 3283f55e7e Auth timeout (#1263) 2025-06-20 18:33:31 +00:00
starsandskies ddb32a3614 Edit pass of docs/troubleshooting.md (#1200)
Make a pass through the docs/troubleshooting.md file to hopefully improve readability and consistency.

Notably, some links in the existing documentation appear to point to non-existent pages. I've updated them to what I believe is an appropriate alternative. Also, there's some vague usage of "CLI" and "server", which I've -hopefully correctly- called "Gemini CLI" and "MCP server"
2025-06-20 17:51:51 +00:00
matt korwel 7c8a1da8fe Auth blocking (#1261) 2025-06-20 10:46:41 -07:00
starsandskies 7c4af82da4 Edit pass of docs/integration-tests.md (#1198)
Co-authored-by: cperry-goog <78765543+cperry-goog@users.noreply.github.com>
Co-authored-by: Chris Perry <cperry@google.com>
2025-06-20 10:27:00 -07:00
starsandskies 71f1dcf39a Edit pass of docs/extensions.md (#1187)
Co-authored-by: cperry-goog <78765543+cperry-goog@users.noreply.github.com>
2025-06-20 09:49:57 -07:00
starsandskies fefe97a1db Add missing command and alphabetize docs/cli/commands.md (#1194)
As noted in Issue #1189, the /stats command is missing. While we're here, alphabetizing the / commands makes sense in order to better organization the page.
2025-06-20 16:43:47 +00:00
starsandskies 639f8e70d2 Edit pass for the first chunk of docs/cli/configuration.md (#1174)
Co-authored-by: cperry-goog <78765543+cperry-goog@users.noreply.github.com>
2025-06-20 09:39:21 -07:00
matt korwel ef54e4ffbc fallback to gemini_api_key (#1255) 2025-06-20 01:36:33 -07:00
N. Taylor Mullen 4e69ba3bbe feat(auth): handle auth flow errors gracefully (#1256) 2025-06-20 01:30:06 -07:00
N. Taylor Mullen 4d9e258a1e Prevent hard crashing on update notifier fail. (#1254) 2025-06-20 07:30:30 +00:00
N. Taylor Mullen 787c319e87 feat: Update default Gemini Flash model to 2.5 (#1241) 2025-06-20 05:54:00 +00:00
Abhi fbbb6f2611 Bug fix telemetry token count (#1250)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-06-20 05:45:29 +00:00
Jacob Richman 05b1c8101f Turn off debug logging of MaxSizedBox errors by default. (#1228) 2025-06-20 05:27:03 +00:00
Louis Jimenez b179424161 Support autocompletion for checkpoints (#1253) 2025-06-20 01:18:11 -04:00
Louis Jimenez 6c67618624 Make checkpoints configurable in settings.json (#1251) 2025-06-20 00:39:15 -04:00
Louis Jimenez ea63a8401e Move the shell history our of the project .gemini to the home dir (#1195) 2025-06-19 23:53:24 -04:00
N. Taylor Mullen 7a419282c8 Tactical client lifetime fix. (#1247) 2025-06-19 19:54:36 -07:00
Tommaso Sciortino 0c9b138f5e Reword auth dialog options (#1246) 2025-06-20 02:41:19 +00:00
Tommaso Sciortino 2f1fc3f359 Initially hide some Auth options behind "More..." (#1245) 2025-06-19 19:28:56 -07:00
N. Taylor Mullen 4059a3e8ee fix: flicker of StreamingState to Idle when tool finishes (#1190) (#1216)
Co-authored-by: Asad Memon <asad.lionpk@gmail.com>
2025-06-20 01:25:23 +00:00
Louis Jimenez 2e5e9d736b Move the otel folder out of project root .gemini and into user home dir (#1188) 2025-06-19 21:09:05 -04:00
matt korwel 04518b52c0 Auth First Run (#1207)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-06-19 16:52:22 -07:00
starsandskies c48fcaa8c3 Edit pass of docs/cli/themes.md (#1171)
Most notably, the list of available themes didn't match (in completeness or name) the examples provided at the end of the file (nor the listing I found in /packages/cli/src/ui/themes)
2025-06-19 16:24:33 -07:00
Tommaso Sciortino 1e5689e054 Set slice=true on tests to supress output. (#1168) 2025-06-19 15:27:00 -07:00
Eddie Santos c1486c47ee fix: auto-update sandbox regression (#1221) 2025-06-19 21:40:10 +00:00
Tommaso Sciortino 619da70070 Correct node version in Readme (#1226) 2025-06-19 13:56:46 -07:00
Abhi 0125547215 bug: removes raw api response from stdout (#1224) 2025-06-19 16:26:31 -04:00
Jacob Richman b0bc7c3d99 Fix flicker issues by ensuring all actively changing content fits in the viewport (#1217) 2025-06-19 13:17:23 -07:00
Brandon Keiji 10a83a6395 refactor: remove docker tagging step from sandbox publishing (#1223) 2025-06-19 12:19:39 -07:00
Leo 0ebac0b896 add sandboxImageName in package.json (#1219) 2025-06-19 11:50:34 -07:00
Tommaso Sciortino 43203926b8 Initialize geminiClient in noninteractive mode (#1222) 2025-06-19 17:21:39 +00:00
anj-s 8e7fa7e233 Remove verification to prevent file reverts and endless loops (#1213) 2025-06-19 10:03:54 -07:00
N. Taylor Mullen 3621ea0cb6 Change sandbox default (#1214) 2025-06-19 02:15:02 -07:00
Tommaso Sciortino b49d55584e Use Env Var directly instead of through GoogleAuth() (#1202) 2025-06-18 17:24:46 -07:00
Tommaso Sciortino 8bc3b415c9 Refactor in preparation for Reauth (#1196) 2025-06-18 16:34:00 -07:00
Jerop Kipruto b96fbd913e test: add integration test for simple mcp server (#1199) 2025-06-18 15:53:58 -07:00
Brandon Keiji cc89830b2a refactor: consolidate container image tag source of truth to cli package.json (#1156) 2025-06-18 19:43:12 +00:00
Seth Troisi c7a422ccdd GC guided review of docs (#1167) 2025-06-18 18:49:59 +00:00
Allen Hutchison fbc79c34c9 Fix noise in headless mode on STDOUT (#1184) 2025-06-18 11:40:15 -07:00
starsandskies 589a7b59c6 Edit pass of docs/cli/tutorials.md (#1186)
Make a pass through the docs/cli/tutorials.md file to hopefully improve readability and consistency.
2025-06-18 18:15:49 +00:00
anj-s c4c444d378 Cherry pick fix for enabling the agent to verify changes using tests (#1185) 2025-06-18 11:00:01 -07:00
Tommaso Sciortino 4662b058e8 CCPA Count Token support (#1170) 2025-06-18 10:29:42 -07:00
Brandon Keiji 332512853e feat: consolidate sandbox configurations into a single object (#1154) 2025-06-18 17:01:00 +00:00
Brandon Keiji 30d1662128 fix: check package.json for app version (#1160) (#1182) 2025-06-18 16:57:17 +00:00
Tommaso Sciortino 3453b977b8 Support logging in with Application Default Credentials (#1157)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-06-18 09:49:13 -07:00
anj-s 5b2cea8eda Cherrypick endless loops fix onto release (#1181) 2025-06-18 09:27:23 -07:00
Tommaso Sciortino cd03d96b34 Fix flakey test (#1178) 2025-06-18 08:34:22 -07:00
Louis Jimenez 9b34762d97 Move the logs.json to a project specific user home dir (#1145) 2025-06-18 09:56:21 -04:00
N. Taylor Mullen 0da4fd9d11 feat: update default gemini model to GA 2.5 pro (#1173) 2025-06-17 23:08:04 -07:00
DeWitt Clinton 3e49206935 Remove learnings.md. (#1172) 2025-06-17 22:43:59 -07:00
Anas H. Sulaiman 63fbc8ce18 fix: regression in completion filtering (#1135) 2025-06-18 05:05:47 +00:00
N. Taylor Mullen 7f189f4d5f docs: update documentation from starsandskies/patch-2 (#1143)
Co-authored-by: starsandskies <nstock@google.com>
Co-authored-by: matt korwel <matt.korwel@gmail.com>
2025-06-18 05:02:07 +00:00
Abhi f3c1cbbabf feat: shell history (#1169) 2025-06-17 22:17:16 -04:00
Louis Jimenez 443465a805 Clear out untracked files when restoring a checkpoint (#1139) 2025-06-17 22:01:42 -04:00
Seth Troisi 87053d9317 Fixup pull_request_template.md (#1166)
Co-authored-by: matt korwel <matt.korwel@gmail.com>
2025-06-18 00:34:03 +00:00
starsandskies e12c60fcab Move theme discussion from configuration.md to themes.md (#1158)
This content looks like it is better hosted in the themes.md doc.

This is as close as possible to an as-is cut-paste from one file to the other, with the goal of minimizing fine-grained review in this particular PR. I'll take another pass through themes.md specifically to improve the moved content in a follow up PR
2025-06-17 16:07:12 -07:00
Seth Troisi e7c4801c79 Updating CONTRIBUTING.md (#1144) 2025-06-17 13:16:28 -07:00
matt korwel 7a99f0b5a2 Forked PR: Contributing.md (#1146) 2025-06-17 11:26:27 -07:00
Billy Biggs 708ba8902a Support escaping carriage returns with \ (#1127) 2025-06-17 10:03:05 -07:00
Jacob MacDonald e59c872b3d code review followup for compress command (#1097)
Followup to https://github.com/google-gemini/gemini-cli/pull/986
2025-06-17 15:44:54 +00:00
Eddie Santos c3971754bf Auto-update notifications (#1110) 2025-06-17 15:24:07 +00:00
matt korwel bc3fa71234 Update CONTRIBUTING.md (#1130) 2025-06-17 00:09:23 -07:00
Miguel Solorio 137baa0a07 Update /help page (#1119) 2025-06-16 20:13:33 -07:00
Tommaso Sciortino b3e26de862 Cache credentials in home dir, not working dir (#1122) 2025-06-16 19:31:32 -07:00
Tommaso Sciortino 98093e604a Simplify Error handling in Code Assist onboarding (#1123) 2025-06-16 18:30:55 -07:00
Jacob Richman a7e45d47cd Fix bug where single line inserts were deleting all text after the in… (#1114) 2025-06-16 15:21:22 -07:00
Tommaso Sciortino 11f524c125 Propagate abort signal to ccpa generateContent. (#1106) 2025-06-16 13:24:42 -07:00
Marlon Gamez 42329e0258 fix: add httpOptions with headers field to CCPA client and set User-Agent header (#1103) 2025-06-16 12:03:06 -07:00
Tommaso Sciortino bf62c3b21a Mock out 'open' in tests. Fix test issues. (#1100) 2025-06-16 11:12:42 -07:00
matt korwel df938d6ee8 Preflight and integration npx (#1096) 2025-06-16 15:27:29 +00:00
Taylor Mullen a600588c20 Add ask mode approvers to code owners. 2025-06-15 23:46:58 -07:00
Mark McDonald 7e6fb7e874 Added sandbox error hint when MCP servers fail to launch in sandbox mode (#972) 2025-06-16 06:37:09 +00:00
Abhi 6af7a5c589 feat: clear should also clear chat history (#1008) 2025-06-16 06:33:59 +00:00
Louis Jimenez dd679a6cdb Move the shadow git repository to the user's home dir (#1013) 2025-06-16 06:30:02 +00:00
Jacob Richman 5d4f4f421c feat: text-buffer: input sanitization and delete character handling. (#1031) 2025-06-16 06:25:11 +00:00
N. Taylor Mullen 742caa5dd8 feat(cli): Standardize keyboard shortcut hints (#1092) 2025-06-16 06:21:58 +00:00
Zach Sais cc7459e403 fix version release for Dockerfile build (#1080) 2025-06-16 06:13:39 +00:00
Billy Biggs 40fbb61a1b Update /tools desc to show the name of each tool as known to the model (#1091) 2025-06-15 23:09:53 -07:00
N. Taylor Mullen 197704c630 feat(test): Increase test coverage across CLI and Core packages (#1089) 2025-06-15 22:41:32 -07:00
N. Taylor Mullen f00b9f2727 feat(ci): run actions on the release branch (#1086) 2025-06-15 21:43:32 -07:00
Mark McDonald ffc48b16d4 Add Vertex env vars to sandbox (#1005)
Co-authored-by: Scott Densmore <scottdensmore@github.com>
2025-06-16 02:55:13 +00:00
Jerop Kipruto a6c16ab08d small fixes in telemetry docs (#1081)
- `GOOGLE_CLOUD_PROJECT` --> `OTLP_GOOGLE_CLOUD_PROJECT`
- Remove `npm run start:gcp` shorthand from docs until after improving cleanup process
2025-06-16 02:45:16 +00:00
Abhi bedff2ca79 feat: Adds shell command context to gemini history (#1076) 2025-06-15 22:09:30 -04:00
Jerop Kipruto 7f06ad40c5 Add a command for starting Gemini CLI with GCP telemetry (#1079)
This command enables starting the application with GCP telemetry:

```shell
npm run start:gcp
```
2025-06-15 21:28:29 -04:00
Jerop Kipruto e772dc2b85 Decouple telemetry project ID configuration (#1077)
#750 

Renames project ID for telemetry from `GOOGLE_CLOUD_PROJECT` to `OTLP_GOOGLE_CLOUD_PROJECT`.

This change allows for a separate Google Cloud Project to be used for telemetry data, distinct from the project used for other services like Vertex AI or Code Assist. This enhances clarity and flexibility in project configuration.
2025-06-16 01:12:57 +00:00
Leo 5c8e49a0e3 bug: Fix modify edit (#1078) 2025-06-15 18:00:41 -07:00
N. Taylor Mullen 4463671284 refactor(cli): Use excludeTools for non-interactive mode (#1072) 2025-06-15 16:05:40 -07:00
Jerop Kipruto 101b6fe767 Stabilize /bug command tests with consistent version mocking (#1070)
The `/bug` command tests in `slashCommandProcessor.test.ts` were flaky due to inconsistent CLI versioning.

This commit:
- Implements a flexible, top-level mock for `getCliVersion` that can be overridden per test.
- Sets a default mock value for `/bug` command tests via `beforeEach`.
- Overrides the mock in one test case requiring a specific version ('test-version').
- Ensures the test's helper `getExpectedUrl` receives the correct explicit version.
- Aligns the expected CLI version in the custom bug URL test with the default mock.

These changes ensure consistent CLI versioning in tests, resolving flakiness.

#1071
2025-06-15 16:35:15 -04:00
Jerop Kipruto 714421c2da Add file operation telemetry (#1068)
Introduces telemetry for file create, read, and update operations.

This change adds the `gemini_cli.file.operation.count` metric, recorded by the `read-file`, `read-many-files`, and `write-file` tools.

The metric includes the following attributes:
    - `operation` (string: `create`, `read`, `update`): The type of file operation.
    - `lines` (optional, Int): Number of lines in the file.
    - `mimetype` (optional, string): Mimetype of the file.
    - `extension` (optional, string): File extension of the file.

Here is a stacked bar chart of file operations by extension (`js`, `ts`, `md`):
![image](https://github.com/user-attachments/assets/3e8f8ea9-6155-4186-863c-075cc47647c5)

Here is a stacked bar chart of file operations by type (`create`, `read`, `update`):
![image](https://github.com/user-attachments/assets/3fcf491d-31d0-4ba8-80e6-7fd2bd9c7c27)

#750 

cc @allenhutchison as discussed
2025-06-15 13:24:53 -07:00
Jerop Kipruto 4421ef126f Refactor: Use telemetry_utils.js in local_telemetry.js (#1066)
## TLDR

Refactors `scripts/local_telemetry.js` to use shared helper functions and constants from `scripts/telemetry_utils.js`.

## Dive Deeper

This change centralizes common telemetry-related logic, including:
- Binary downloading and management (`ensureBinary`)
- Reading and writing JSON files
- Waiting for network ports
- Managing workspace telemetry settings (`manageTelemetrySettings`)
- Process cleanup and signal handling (`registerCleanup`)

By using the shared utilities, `local_telemetry.js` becomes more concise and focused on its specific task of setting up the local OpenTelemetry and Jaeger environment.

## Docs

https://github.com/google-gemini/gemini-cli/blob/main/docs/core/telemetry.md#local-telemetry-with-jaeger-ui-for-traces

## Issue

#750
2025-06-15 19:32:12 +00:00
Billy Biggs b67806ae9a Support completion of checkpoint names in /resume (#1063) 2025-06-15 11:40:39 -07:00
Marat Boshernitsan 6d772a30c0 Stabilize prompts snapshot test by properly mocking the SANDBOX env var. (#1067)
Co-authored-by: Marat Boshernitsan <maratb@google.com>
2025-06-15 11:33:30 -07:00
Billy Biggs 6959663646 Add support for /mcp schema to show full parameter schema as JSON (#1050)
Outputs a raw JSON version of the parameter names and descriptions as provided to the model, plus minor formatting adjustments to /mcp desc.
2025-06-15 11:25:40 -07:00
Asad Memon 123ad20e9b feat: Show model thoughts while loading (#992) 2025-06-15 18:19:05 +00:00
Asad Memon b3d89a1075 feat: Add token stats in footer (#909) 2025-06-15 11:15:53 -07:00
Billy Biggs da09431be9 Add support for showing descriptions of CLI tools (#1052)
Adds support for /tools desc to show the full description of tools as provided to the model.
2025-06-15 07:56:07 -07:00
Sijie Wang 7352cb403c fix(core): Improve shell tool reliability and test portability (#1036) 2025-06-15 09:19:19 +00:00
matt korwel 2b799cbbf0 Create pull_request_template.md (#1054) 2025-06-15 01:34:40 -07:00
N. Taylor Mullen 12c33c1fe6 feat(cli): add glob as a direct dependency (#1065) 2025-06-15 00:50:26 -07:00
Jerop Kipruto ab932ffaa5 Telemetry: Improve API response logging with function call details (#1064) 2025-06-15 01:48:01 -04:00
Billy Biggs e717c51aa1 Avoid import.meta.dirname to be backwards compatible to Node.js 18+ (#1058) 2025-06-15 05:30:00 +00:00
Jerop Kipruto 53753f0455 Add telemetry command and refactor telemetry settings (#1060)
#750 

### Telemetry Settings
Refactors telemetry configuration to use a nested `telemetry` object in `settings.json`, for example:

```json
{
  "telemetry": {
    "enabled": true,
    "target": "gcp"
    "log-prompts": "true"
  },
  "sandbox": false
}
```

The above includes
- Centralized telemetry settings under a `telemetry` object in `settings.json`.
- CLI flags for the `gemini` command to override all telemetry sub-settings:
    - `--telemetry` / `--no-telemetry`
    - `--telemetry-target <local|gcp>`
    - `--telemetry-otlp-endpoint <URL>`
    - `--telemetry-log-prompts` / `--no-telemetry-log-prompts`
- Updates `packages/cli/src/config/config.ts` and `packages/core/src/config/config.ts` to read from the new settings structure and respect the new CLI flags.
- Modifies `scripts/handle-telemetry.js`, `scripts/local_telemetry.js`, and `scripts/telemetry_utils.js` to align with the new settings structure.
- Updates `docs/core/telemetry.md` to reflect the new settings structure, CLI flags, and order of precedence.
- Renames `logUserPromptsEnabled` to `logPrompts` for brevity.

### `npm run telemetry`

Add a new `npm run telemetry` command that uses `scripts/telemetry.js`, automates the entire process of setting up a local and GCP telemetry pipelines, including configuring the necessary settings in the `.gemini/settings.json` workspace file and installing required binaries (e.g. `otelcol-contrib`).

---
```shell
$ npm run telemetry -- --target=gcp

> gemini-cli@0.1.0 telemetry
> node scripts/telemetry.js --target=gcp

⚙️  Using command-line target: gcp
🚀 Running telemetry script for target: gcp.
 Starting Local Telemetry Exporter for Google Cloud 
⚙️  Enabled telemetry in workspace settings.
🔧 Set telemetry OTLP endpoint to http://localhost:4317.
🎯 Set telemetry target to gcp.
 Workspace settings updated.
 Using Google Cloud Project ID: foo-bar

🔑 Please ensure you are authenticated with Google Cloud:
  - Run `gcloud auth application-default login` OR ensure `GOOGLE_APPLICATION_CREDENTIALS` environment variable points to a valid service account key.
  - The account needs "Cloud Trace Agent", "Monitoring Metric Writer", and "Logs Writer" roles.
 otelcol-contrib already exists at /Users/jerop/github/gemini-cli/.gemini/otel/bin/otelcol-contrib
🧹 Cleaning up old processes and logs...
 Deleted old GCP collector log.
📄 Wrote OTEL collector config to /Users/jerop/github/gemini-cli/.gemini/otel/collector-gcp.yaml
🚀 Starting OTEL collector for GCP... Logs: /Users/jerop/github/gemini-cli/.gemini/otel/collector-gcp.log
 Waiting for OTEL collector to start (PID: 17013)...
 OTEL collector started successfully on port 4317.

 Local OTEL collector for GCP is running.

🚀 To send telemetry, run the Gemini CLI in a separate terminal window.

📄 Collector logs are being written to: /Users/jerop/github/gemini-cli/.gemini/otel/collector-gcp.log

📊 View your telemetry data in Google Cloud Console:
   - Logs: https://console.cloud.google.com/logs/query;query=logName%3D%22projects%2Ffoo-bar%2Flogs%2Fgemini_cli%22?project=foo-bar
   - Metrics: https://console.cloud.google.com/monitoring/metrics-explorer?project=foo-bar
   - Traces: https://console.cloud.google.com/traces/list?project=foo-bar

Press Ctrl+C to exit.
^C
👋 Shutting down...
⚙️  Disabled telemetry in workspace settings.
🔧 Cleared telemetry OTLP endpoint.
🎯 Cleared telemetry target.
 Workspace settings updated.
🛑 Stopping otelcol-contrib (PID: 17013)...
 otelcol-contrib stopped.
```
2025-06-15 00:47:32 -04:00
Keir Mierle 32dd298351 fix: Push tool calls to absolute paths (#1055) (#1057)
Make several changes to guide the model to request absolute paths,
reducing frequent accidental relative path tool call failures.

- Switch the parameter name: path --> absolute_path.
- Update the tool definition to strongly require an absolute path.
- Update the system prompt to indicate absolute paths are required.
- Update the system prompt tool use examples to use absolute paths.

Test case:

Open GC in GC: "Locate the primary file calling genai"
- Expected: Model opens files with absolute path, successfully.
- Actual (pre-patch): Failure, attempts to read with relative path.
- Actual (post-patch): Success, attempts to read with absolute path.
2025-06-14 21:16:11 -07:00
Scott Densmore e30e650a77 docs: document environment variables for cloud services (#1048) 2025-06-14 15:19:05 -07:00
Leo e544b940f1 bug: Fix code colorizer (#1046) 2025-06-14 21:27:53 +01:00
Steren d0b77d9fa0 Dockerfile: Node 22 and ENTRYPOINT (#1038) 2025-06-14 19:01:06 +00:00
Leo 2c6aae863a Enable "modify" in write tool (#1044) 2025-06-14 11:20:04 -07:00
Bryan Morgan 93909a2dd3 Address b/424256913 - fixed error in correctStringEscaping() and improved backslash handling (#1007) 2025-06-14 13:39:34 -04:00
Jerop Kipruto 3bcb3c3666 docs: clarify telemetry script usage (#1034)
Updates the telemetry documentation and the GCP telemetry script to make it clearer that the Gemini CLI needs to be run in a separate terminal session after starting the collector script.

This addresses potential user confusion where they might expect telemetry data to appear without actively using the CLI.

#750
2025-06-14 14:49:21 +00:00
Anas H. Sulaiman 4873fce791 centralize file filtering in FileDiscoveryService (#1039) 2025-06-14 14:25:34 +00:00
Steren e6d5477168 Fix 404 URL for Vertex Auth (#1040) 2025-06-14 08:25:08 +00:00
Allen Hutchison 643bdf31d5 feat: Add custom URL support for the /bug command (#1017) 2025-06-14 07:00:24 +00:00
Jacob MacDonald d5c6bb9740 Add /compress command to force a compression of the context (#986)
Related to https://b.corp.google.com/issues/423605555 - I figured this might be a simpler solution to start with, while still also being useful on its own even if we do implement that.
2025-06-14 04:21:40 +00:00
Jerop Kipruto 1452bb4ca4 Add GCP telemetry script (#1033)
Adds a script -  `scripts/telemetry_gcp.js` - to simplify setting up a local OpenTelemetry collector that forwards data to Google Cloud. This is a follow up to the script for local telemetry `scripts/local_telemetry.js` added in #1015.

This script automates downloading necessary binaries, configuring the collector, and updating workspace settings.

Also includes `scripts/telemetry_utils.js` with shared helper functions for telemetry scripts. Will refactor `scripts/local_t elemetry.js` in next steps to use this shared functionality.

Updates `docs/core/telemetry.md` to include:
- A new "Quick Start" section
- Detailed instructions for the new GCP automated script
- Reorganization of existing sections for clarity

#750 

---
```
 Starting Local Telemetry Exporter for Google Cloud 
⚙️  Enabled telemetry in workspace settings.
🔧 Set telemetry OTLP endpoint to http://localhost:4317.
 Workspace settings updated.
 Using Google Cloud Project ID: foo-bar

🔑 Please ensure you are authenticated with Google Cloud:
  - Run `gcloud auth application-default login` OR ensure `GOOGLE_APPLICATION_CREDENTIALS` environment variable points to a valid service account key.
  - The account needs "Cloud Trace Agent", "Monitoring Metric Writer", and "Logs Writer" roles.
 otelcol-contrib already exists at /Users/jerop/github/gemini-cli/.gemini/otel/bin/otelcol-contrib
🧹 Cleaning up old processes and logs...
 Deleted old GCP collector log.
📄 Wrote OTEL collector config to /Users/jerop/github/gemini-cli/.gemini/otel/collector-gcp.yaml
🚀 Starting OTEL collector for GCP... Logs: /Users/jerop/github/gemini-cli/.gemini/otel/collector-gcp.log
 Waiting for OTEL collector to start (PID: 65145)...
 OTEL collector started successfully on port 4317.

 Local OTEL collector for GCP is running.

📄 Collector logs are being written to: /Users/jerop/github/gemini-cli/.gemini/otel/collector-gcp.log

📊 View your telemetry data in Google Cloud Console:
   - Traces: https://console.cloud.google.com/traces/list?project=foo-bar
   - Metrics: https://console.cloud.google.com/monitoring/metrics-explorer?project=foo-bar
   - Logs: https://console.cloud.google.com/logs/query;query=logName%3D%22projects%2Ffoo-bar%2Flogs%2Fgemini_cli%22?project=foo-bar

Press Ctrl+C to exit.
^C
👋 Shutting down...
⚙️ Disabled telemetry in workspace settings.
🔧 Cleared telemetry OTLP endpoint.
 Workspace settings updated.
🛑 Stopping otelcol-contrib (PID: 65145)...
 otelcol-contrib stopped.
```
2025-06-13 23:28:18 -04:00
Marlon Gamez defb0fac2c fix: remove quota project override in non-streaming calls to CCPA (#1032) 2025-06-14 01:23:12 +00:00
Keir Mierle 9954779739 Add a local telemetry launcher (#1015) 2025-06-13 18:08:03 -07:00
Allen Hutchison 31b28ade01 Improvements to web-fetch tool (#1030) 2025-06-13 17:44:14 -07:00
Anas H. Sulaiman 8eb505fbba initialize FileDiscoveryService once (#1029) 2025-06-13 17:25:59 -07:00
Brandon Keiji 209381f06f fix: add micromatch to package deps (#1020) 2025-06-13 22:18:05 +00:00
Tommaso Sciortino a2fe3d2ad0 Stop extension MCPs from hopping into settings. (#1026) 2025-06-13 14:51:29 -07:00
Anas H. Sulaiman bb67d31739 reuse GitIgnoreParser for loading .geminiignore (#1025) 2025-06-13 17:17:08 -04:00
Tommaso Sciortino 54f0d9d0e5 Fix default extension context filename and update docs (#1024) 2025-06-13 13:57:00 -07:00
Shreya Keshive 1fa41af918 Support MCP StreamableHTTPClientTransport (#1014) 2025-06-13 16:18:06 -04:00
Tommaso Sciortino 491e367f7c Don't exclude config.test.ts. (#1021) 2025-06-13 20:07:46 +00:00
Anas H. Sulaiman 1cefe21d2a reuse filtering service in bfsFileSearch (#1018) 2025-06-13 14:57:03 -04:00
Anas H. Sulaiman 084b58a50e reuse filtering service in getFolderStructure (#1016) 2025-06-13 14:26:31 -04:00
Jerop Kipruto 1f63f3331f Revert "Telemetry: Auto-export to GCP if GOOGLE_CLOUD_PROJECT is set" (#1011) 2025-06-13 10:27:22 -07:00
Daniel Lee daceb9963f feat(cli): support ctrl+d to exit (#878)
Similar to ctrl+c, ctrl+d can now be used to exit the program. To avoid accidental exit, ctrl+d must be pressed twice in relatively quick succession (same as ctrl+c).

Following common UX pattern, ctrl+d will be ignored when the input prompt is non-empty. This behavior is similar to how most shell (bash/zsh) behaves. To support this, I had to refactor so that text buffer is initialized outside of the InputPrompt component and instead do it on the main App component to allow input controller to have access to check the content of the text buffer.
2025-06-13 16:59:09 +00:00
starsandskies 8e804c9fa1 Edit pass of docs/cli/index.md (#999)
Make a pass through the docs/deployment.md file to hopefully improve readability and conciseness

Notably, I've proposed axing both the "Core Features" section - which feels too promotional this far down the folder hierarchy and which is somewhat repetitive to later in the page - and the "Basic Interaction" section - which is covered better, and makes more sense, in other parts of the documentation
2025-06-13 16:53:30 +00:00
Anas H. Sulaiman 9d04e04bc0 remove redundant isGitRepository helper` (#1012) 2025-06-13 12:45:07 -04:00
Billy Biggs 2a1ad1f5d9 Update contextFileName to support an optional list of strings (#1001) 2025-06-13 09:19:08 -07:00
Anas H. Sulaiman 34e0d9c0b6 cleanup unused allowBuildArtifacts (#1010) 2025-06-13 12:00:38 -04:00
Anas H. Sulaiman c886f08525 cleanup unused customIgnorePatterns (#1009) 2025-06-13 11:49:48 -04:00
Leo d25459d815 Edit wording in /edit description (#1006) 2025-06-13 15:36:51 +00:00
Shreya Keshive 1fcbdef994 Add web socket protocol support for IDE MCP server (#987)
Co-authored-by: matt korwel <matt.korwel@gmail.com>
2025-06-13 09:30:44 -04:00
Mark McDonald ff478781ad Support GOOGLE_API_KEY hoisting in sandbox too (#998) 2025-06-13 08:32:15 +00:00
N. Taylor Mullen 7bcc60e996 refactor: Use default centralized Flash & Pro models everywhere (#994) 2025-06-13 08:25:42 +00:00
Miguel Solorio f8a31f29aa Replace logo with custom ASCII (#958) 2025-06-13 07:59:45 +00:00
Jerop Kipruto 95e4a60a83 Telemetry: Auto-export to GCP if GOOGLE_CLOUD_PROJECT is set (#1003)
This change simplifies telemetry setup for users who want to integrate with GCP, as they no longer need to configure a local collector or an explicit endpoint if their project is already set up in the environment.

This change updates the telemetry system to automatically export traces, logs, and metrics to Google Cloud Platform (GCP) if the `GOOGLE_CLOUD_PROJECT` environment variable is set and no explicit `telemetryOtlpEndpoint` is configured by the user.

Key changes:
-   The default `telemetryOtlpEndpoint` in `Config` is now an empty string.
-   The `initializeTelemetry` SDK logic now prioritizes:
    -  User-defined `telemetryOtlpEndpoint`.
    -  `GOOGLE_CLOUD_PROJECT` for direct GCP export.
    -  Console exporters as a fallback.
-   If an invalid `telemetryOtlpEndpoint` is provided, it falls back to console exporters with a warning.

#750
2025-06-13 03:51:41 -04:00
Jerop Kipruto b20c8389f3 Handle telemetry in non-interactive mode (#1002)
Changes:
- Ensure proper shutdown in non-interactive mode
- Ensures the initial user prompt is logged in non-interactive mode
- Improve telemetry for streaming - handle chunks and input token count is now alongside other token counts in response

To test:
- Follow instructions in https://github.com/google-gemini/gemini-cli/blob/main/docs/core/telemetry.md#google-cloud
- Run CLI in non-interactive mode and observe logs/metrics in GCP Logs Explorer and Metrics Explorer

#750
2025-06-13 03:44:17 -04:00
Marat Boshernitsan 8bb6eca915 Improvements to CLI's ability to perform refactoring. Includes additions to the system prompt and GEMINI.md. (#955)
Co-authored-by: Marat Boshernitsan <maratb@google.com>
Co-authored-by: DeWitt Clinton <dclinton@gmail.com>
2025-06-12 23:55:41 -07:00
Tommaso Sciortino 28e656f882 Improve some tools to support abortSignal (#997) 2025-06-12 19:46:00 -07:00
Marlon Gamez 1c7774e35b Use allowedTiers from LoadCodeAssist response when calling OnboardUser (#995)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jerop Kipruto <jerop@google.com>
Co-authored-by: Marat Boshernitsan <maratb@nitsan.org>
Co-authored-by: Marat Boshernitsan <maratb@google.com>
2025-06-13 02:32:13 +00:00
Tommaso Sciortino 431ee839a0 Code Assist cleanup and docs (#993) 2025-06-12 18:00:17 -07:00
matt korwel 9a11567f73 Revert "Make glob tool support abortSignal" (#996) 2025-06-13 00:53:10 +00:00
Marat Boshernitsan 181abde2ff Reduce coupling between core and cli packages (#961)
Co-authored-by: Marat Boshernitsan <maratb@google.com>
2025-06-12 17:17:29 -07:00
Jerop Kipruto 3c3da655b0 Refactor OTEL logging for API calls (#991)
Refactor OpenTelemetry logging for API requests, responses, and errors. Moved logging responsibility from GeminiClient to GeminiChat for more detailed logging.

#750
2025-06-12 16:36:51 -07:00
Seth Troisi dc378e8d60 Have @ pass through images and other Part objects (#990) 2025-06-12 16:17:44 -07:00
Seth Troisi b7daa7c702 Fixed @ file content not being added or sent to server (#962) 2025-06-12 23:08:27 +00:00
Eddie Santos 61d0cc39fd GitHub MCP warning (#979) 2025-06-12 22:23:45 +00:00
Jerop Kipruto 6723c72fa5 telemetry: include user decisions in tool call logs (#966)
Add the user's decision (accept, reject, modify) to tool call telemetry to better understand user intent. The decision provides crucial context to the `success` metric, as a user can reject a call that would have succeeded or accept one that fails. 

Also prettify the arguments json.

Example: 
![image](https://github.com/user-attachments/assets/251cb9fc-ceaa-4cdd-929c-8de47031aca8)

#750
2025-06-12 20:48:10 +00:00
Tommaso Sciortino f8863f4d00 Make glob tool support abortSignal (#988) 2025-06-12 13:27:40 -07:00
Abhi 32da693b91 bug: only show tool tokens if > 0 (#985) 2025-06-12 19:31:17 +00:00
starsandskies 6bb3f27f6c Edit pass of README.md (#906)
Make a pass through the README.md file to hopefully improve readability and completeness

Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-06-12 14:36:36 -04:00
Jordan Demeulenaere e1d8a356b0 Fix build_sandbox command (#974) 2025-06-12 17:38:10 +00:00
Leo ad2e47dc20 remove enable editor flag (#984) 2025-06-12 17:28:20 +00:00
DeWitt Clinton a9e56ee460 Ignore dot files on @-completion. (#978) 2025-06-12 17:04:15 +00:00
starsandskies af247a6cbd Edit pass of docs/architecture.md (#971) 2025-06-12 16:44:55 +00:00
Tommaso Sciortino 47ce39c46f Convert CCPA requests to proper format (#981)
CCPA uses a different format than GenAi. This adds conversion code to get it to the right format.

Note that this doesn't work against the current ccpa staging server, The changes it needs are in cl/770266927
2025-06-12 09:33:49 -07:00
DeWitt Clinton f2ab6d08c4 Improve the performance of filename completion over large repositories. (#938) 2025-06-12 07:09:38 -07:00
dependabot[bot] 9072a4e5ee chore(deps-dev): bump esbuild from 0.23.1 to 0.25.0 (#872)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-12 06:21:50 +00:00
Mark McDonald 041e7c177c Added note about using MCP/tools with a sandbox (#933) 2025-06-11 22:49:58 -07:00
anj-s 6fc7028031 Revert "Add support for local logging per session (#936)" (#970) 2025-06-11 21:59:46 -07:00
Jerop Kipruto 89f682f081 Telemetry: Improve clarity of user prompt event (#967) 2025-06-11 21:43:00 -04:00
Leo 1ef68e0612 feat: External editor settings (#882) 2025-06-11 18:21:54 -07:00
Abhi dd53e5c96a Show session summary on exit for ctrl+c x 2. Fix exit UI (#963) 2025-06-11 20:08:32 -04:00
Eddie Santos e02a035ab4 Adding silly phrases (#922) 2025-06-11 23:40:13 +00:00
matt korwel fb67ee5445 TEST: reviewers (#959) 2025-06-11 22:09:33 +00:00
anj-s 2dc79b3bd0 Add support for local logging per session (#936) 2025-06-11 15:05:41 -07:00
JingboWang1997-1 6ecdecbdcc add excludeTools flag to settings.json config (#957) 2025-06-11 14:32:23 -07:00
Seth Troisi 122678cc09 clean chat history before /resume (#949) 2025-06-11 13:40:44 -07:00
Abhi 7a72d255d8 feat: Add exit UI w/ stats (#924) 2025-06-11 16:40:31 -04:00
matt korwel 4160d904da Extensibility: Gemini.md files (#944) 2025-06-11 20:34:35 +00:00
Tommaso Sciortino 24c61147b8 Cache oauth credentials (#927) 2025-06-11 13:26:41 -07:00
jerop c0580eaf4b feat(telemetry): expand cli configuration event
Adds the following attributes to the  event:
- embedding_model
- api_key_enabled
- code_assist_enabled
- debug_mode
- mcp_servers

This additional data will provide more insight into user configurations.
2025-06-11 16:22:35 -04:00
Seth Troisi 5586ad5f8a Fix noisy tests (#950) 2025-06-11 13:01:04 -07:00
Louis Jimenez e0f4f428fc Restore Checkpoint Feature (#934) 2025-06-11 15:33:09 -04:00
Olcan f75c48323c fixes to proxy on macos: prevent curl from hanging during wait-for-proxy by adding ipv6 support and timeout (#947) 2025-06-11 11:31:38 -07:00
jerop 03bc1f3141 feat(telemetry): Update API response in telemetry
Adds the text content of the API response to the  telemetry event. This provides more context for debugging and analysis without logging the entire, potentially large, response object.

- Adds an optional  field to the  type.
- Updates  to include the  field in the logged attributes.
- Modifies the  to extract the response text using  and pass it to the logger.
- Adds a new test file for the telemetry loggers, including tests for the  function to verify the new functionality.
2025-06-11 14:18:16 -04:00
Olcan 9237e95f11 fix proxy on cloudtops/linux and for older versions of docker, more robust start/stop and error reporting (#945) 2025-06-11 10:50:31 -07:00
jerop d96af8bacd refactor(telemetry): pass config object to telemetry functions
This commit refactors the telemetry system to pass a  object to various logging and metrics functions. This change centralizes configuration management within the telemetry system, making it more modular and easier to maintain.

The  constructor and various tool execution functions have been updated to accept the  object, which is then passed down to the telemetry functions. This eliminates the need to pass individual configuration values, such as , through multiple layers of the application.
2025-06-11 13:24:41 -04:00
Miguel Solorio 9c5b5ff823 Allow themes to update gradient colors (#914) 2025-06-11 17:14:18 +00:00
Allen Hutchison 1d7090b8ac feat(core): Create BFS file search utility (#903) 2025-06-11 09:21:23 -07:00
Olcan e2d689ff2f do not auto-enable container sandboxing (fixing recently introduced bug) (#939) 2025-06-11 08:25:33 -07:00
jerop 7ba2b13870 update token usage with types 2025-06-11 10:38:07 -04:00
Anas Sulaiman 9d992b32e4 add a unit test with multiple hunks for diff renderer 2025-06-11 09:47:11 -04:00
Anas Sulaiman 00c4527a1b unify diff generation before and after an edit 2025-06-11 09:47:11 -04:00
Zach Sais 5bab5a7378 fix version set for cli and slash commands (#892) 2025-06-11 08:25:26 -05:00
jerop 3f5ac384cc update from metrics and logs prefix from gemini_code to gemini_cli 2025-06-11 01:28:26 -04:00
jerop d1e23b7c71 refactor: Centralize session ID generation and propagation 2025-06-11 01:18:40 -04:00
Tommaso Sciortino 95fdc66e7d Register dependency added in PR:910 (#925) 2025-06-10 20:39:29 -07:00
Seth Troisi fb6e2927f7 Remove unneeded mockRestore()s from tests (#919) 2025-06-10 20:32:00 -07:00
Olcan 3372fd8df8 rename sandbox-exec as MacOS Seatbelt in footer (#921) 2025-06-10 18:35:00 -07:00
Tommaso Sciortino 97e08fc804 Remove warnings for old env var names. (#920) 2025-06-10 18:34:36 -07:00
Tommaso Sciortino e92b7dfd74 Change yolo mode so it doesn't disable sandboxing. (#918) 2025-06-10 17:41:59 -07:00
jerop b92fa78a1e docs(telemetry): Refine OTEL Collector setup instructions
Standardizes on the  distribution for local and Google Cloud setups.

Restructures the guide to present Docker and standalone binary as clear, parallel options and makes the Google Cloud command more robust.
2025-06-10 20:04:05 -04:00
Seth Troisi 8e0d5076d6 Add [tag] to /save and /resume (#916) 2025-06-10 16:58:39 -07:00
cperry-goog d6b6d5976d Contributing guidelines (#901) 2025-06-10 16:56:29 -07:00
Seth Troisi 36f58a34b4 logConversation
loadConversation

/resume

clean up for review
2025-06-10 16:14:42 -07:00
Tommaso Sciortino d79dafc577 Basic code assist support (#910) 2025-06-10 16:00:13 -07:00
Tommaso Sciortino 4e84431df3 Allow simple extensions for registering MCPservers (#890) 2025-06-10 15:48:39 -07:00
jerop 916cfee08d update documentation for otel 2025-06-10 18:14:04 -04:00
Tolik Malibroda e73d4752df fix: Change sandbox network check command for docker (#907) 2025-06-11 00:13:36 +02:00
jerop fa27bc832f feat: enable gzip compression for otlp exporters 2025-06-10 17:30:50 -04:00
jerop f0f7a30d9f docs(telemetry): improve telemetry documentation
This commit enhances the telemetry documentation with several key improvements for clarity and usability.

- Adds a prominent note clarifying that telemetry is currently incompatible with sandbox mode.
- Updates the example JSON configuration to explicitly include sandbox: false to prevent user confusion.
- Introduces a new Configurations section with instructions to create the  directory.
- Adds a new step for setting necessary environment variables for the Google Cloud setup.
- Makes the  command for Google Cloud more portable by using the  environment variable instead of a hardcoded path.
- Re-numbers the steps in the Google Cloud setup guide to maintain a logical flow.
2025-06-10 16:51:46 -04:00
Seth Troisi 6f4226fde1 Fix debug to work when not running under a sandbox 2025-06-10 13:33:18 -07:00
Abhi 9c3f34890f feat: Add UI for /stats slash command (#883) 2025-06-10 15:59:52 -04:00
Seth Troisi 04e2fe0bff Delete unneeded .eslintignore 2025-06-10 12:21:14 -07:00
anj-s 83660ec016 Fix null pointer for traces field and use the batch processor (#884) 2025-06-10 09:24:27 -07:00
Olcan e38d2078cc restricted networking for all sandboxing methods, new seatbelt profiles, updated docs, fixes to sandbox build, debugging through sandbox (#891) 2025-06-10 08:58:37 -07:00
Tommaso Sciortino 895c1f132f GEMINI_SANDBOX=false should disable seatbelt (#888) 2025-06-10 06:22:02 -07:00
Bryan Morgan 1e3abf96b5 addressed b/423798481 (#887) 2025-06-10 08:47:46 -04:00
Olcan 749c010a0d strip json comments in newly created sandbox_command.js (consistent w/ bash version) (#886) 2025-06-10 00:33:42 -07:00
Olcan c7e82965b1 fix user settings in sandbox broken in recent change (#885) 2025-06-10 00:27:40 -07:00
Mark McDonald 5673c5f267 Add a window title when CLI is launched (#787) 2025-06-10 11:54:51 +08:00
Abhi 7f1252d364 feat: Display initial token usage metrics in /stats (#879) 2025-06-09 20:25:37 -04:00
Eddie Santos 6484dc9008 Add Windsurf in edit tool to modify changes, if installed (#853) 2025-06-09 16:01:06 -07:00
Tommaso Sciortino 5c9e526f0e Code to support Oauth login (#881) 2025-06-09 15:14:06 -07:00
Seth Troisi f11414a424 Use GOOGLE_API_KEY as default if both GEMINI and GOOGLE set (#777) 2025-06-09 13:54:11 -07:00
Brandon Keiji 6e5332f716 docs: add deployment documentation (#874) 2025-06-09 19:58:24 +00:00
matt korwel a8a7f67d81 Delete tmperrors.txt (#873) 2025-06-09 19:30:24 +00:00
matt korwel 3b943c1582 Windows: Refactor Shell Scripts to Node.js for Cross-Platform Compatibility (#784) 2025-06-09 12:19:42 -07:00
Abhi 2182a1cd2c Bump @google/genai dependency (#870) 2025-06-09 14:17:39 -04:00
Tommaso Sciortino 0613062fc8 Simplify user agent handling. (#828) 2025-06-09 09:31:27 -07:00
Olcan 87474e52d7 rename shell tool more intuitively as run_shell_command (from historical name of execute_bash_command inherited from terminal tool) (#869) 2025-06-09 08:57:30 -07:00
anj-s c55a1d9012 Add support for sorting files search by recency threshold followed by lexicographic sorting (#867) 2025-06-09 08:07:24 -07:00
Olcan a2fee6bdd3 fix mcp timeouts and missing description on mcp errors (#868) 2025-06-08 21:52:11 -07:00
Olcan a3d11e8fef replace reference to "README" with "docs" to avoid confusion for folks who do not have access to README (#866) 2025-06-08 19:19:33 -07:00
matt korwel 37edbd8c18 Rollforward AST changes to unblock Sandboxing (#863) 2025-06-08 19:07:25 -07:00
N. Taylor Mullen ccdd1df039 feat(core): Add .gitignore support to getFolderStructure (#865) 2025-06-09 01:42:38 +00:00
N. Taylor Mullen 72fa01f62d feat(git): Refactor gitignore handling to use ignore library instead of minimatch (#864) 2025-06-08 18:32:19 -07:00
Olcan d061419452 enforce minimum lines shown/hidden (#860) 2025-06-08 17:11:16 -07:00
Olcan 8f993a6200 drop redundant -s flag for custom sandbox build (#859) 2025-06-08 16:43:04 -07:00
Olcan 7e73f57556 use -s flag (to skip npm install + build) for build_sandbox.sh when running via npm run build:all (#858) 2025-06-08 16:36:52 -07:00
N. Taylor Mullen d62dad5575 Revert "Add batch editing capabilities to Edit Tool (#648)" (#857) 2025-06-08 23:20:43 +00:00
Bryan Morgan 152af28a34 Bryanmorgan/add tool source description (#856) 2025-06-08 19:07:05 -04:00
Bryan Morgan 31c14ea78f Bryanmorgan/add mcp description support (#855) 2025-06-08 18:45:36 -04:00
N. Taylor Mullen f2ea78d0e4 fix(tool-scheduler): Correctly pipe cancellation signal to tool calls (#852) 2025-06-08 22:42:49 +00:00
Abhi 7868ef8229 feat: Introduce session context and add session duration stat for /stats command (#854) 2025-06-08 18:01:02 -04:00
Scott Densmore 9104ac02f7 feat: display commit hash in detached HEAD state (#832) 2025-06-08 14:59:18 -07:00
Eddie Santos 394312b9c2 Add tests for core/utils/editor (#851) 2025-06-08 19:42:42 +00:00
N. Taylor Mullen 241c404573 fix(cli): correctly handle tool invocation cancellation (#844) 2025-06-08 11:14:45 -07:00
Leo 9efca40dae feat: Add flow to allow modifying edits during edit tool call (#808) 2025-06-08 10:56:58 -07:00
matt korwel 584286cfd9 fix(deps): externalize tree-sitter (#840)
Submitting without approval to fix broken deployment on main. But also, we should lock this down.
2025-06-08 02:05:55 -07:00
N. Taylor Mullen d0b78225a1 feat: update ctrl+t text (#845) 2025-06-08 07:16:08 +00:00
Keith Ballinger 5e01713803 chore: remove stray file_learnings.md (#837) 2025-06-07 23:02:59 -07:00
Keith Ballinger 84678c6448 Makefile for convenience (#833) 2025-06-07 22:22:32 -07:00
Keith Ballinger 569c977408 refactor(core): remove comments from geminiChat.ts (#834) 2025-06-07 22:20:59 -07:00
Scott Densmore b46f220931 feat(cli): improve API error parsing and display (#829) 2025-06-07 22:04:57 -07:00
Abhi 6e4b84a60d Fix Build Failure - Build fails in sandbox due to missing build toolchain (#831) 2025-06-08 01:04:20 -04:00
Abhi f11eb41383 Fix typo in CONTRIBUTING.md (#827) 2025-06-07 19:40:16 -04:00
Tommaso Sciortino 389907ce65 Introduce ContentGeneratorConfig (#826) 2025-06-07 16:17:27 -07:00
Bryan Morgan e95a6086fc Bryanmorgan/add mcp description support (#825) 2025-06-07 18:30:56 -04:00
Tolik Malibroda dd08582f81 fix: Rename missing occurence of gemini-code (#824) 2025-06-08 00:12:53 +02:00
Jacob Richman ab44824e07 Auto insert @ when dragging and dropping files. (#812) 2025-06-07 14:48:56 -07:00
cperry-goog 18d6a11c04 refactor: rename gemini-code to gemini-cli (#822) 2025-06-07 14:27:22 -07:00
Tommaso Sciortino d6cf4d5b0b Eliminate createServerConfig() (#821) 2025-06-07 13:49:00 -07:00
Tommaso Sciortino 10b52ac4e8 Fix missing arg warning in tests (#820) 2025-06-07 13:39:53 -07:00
Eddie Santos 27fdd1b6e6 Add embedder (#818) 2025-06-07 13:38:05 -07:00
cperry-goog 51cd5ffd91 fix(build): correct sandbox warning link (#819) 2025-06-07 12:42:32 -07:00
matt korwel f1a4e5d4d3 Creating Node AST Tool. (#756) 2025-06-07 12:07:58 -07:00
Bryan Morgan 28ff62e7b1 Added /mcp command support and cleaned up broken tests (#817) 2025-06-07 15:06:18 -04:00
Tommaso Sciortino 6ea4479064 Push model-switching logging into loadCliConfig (#815) 2025-06-07 11:12:30 -07:00
Tommaso Sciortino 680f4cdd61 More version simplifiction. (#810) 2025-06-07 10:54:23 -07:00
cperry-goog 63757d6a7a docs: update and reorganize documentation (#806) 2025-06-07 10:47:30 -07:00
Eddie Santos dcaecde844 toggle off (#809) 2025-06-07 00:06:15 -07:00
Keith Ballinger 0c86874677 Add batch editing capabilities to Edit Tool (#648)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-06-06 22:54:37 -07:00
Tommaso Sciortino 76ec9122c0 clean up version lookup code (#804) 2025-06-06 16:21:20 -07:00
cperry-goog e94a10023d adding very important phrases (#802) 2025-06-06 14:49:40 -07:00
Jacob Richman 2f54aa888a feat(ui): add cursor to empty input prompt (#800) 2025-06-06 13:44:11 -07:00
jerop 21acdee0a0 docs: Initialize tutorials section with MCP server example
This commit adds a new `tutorials.md` file to the CLI documentation.
This section is intended to house various tutorials for using Gemini CLI.

The initial content includes a tutorial on setting up Model Context
Protocol (MCP) servers, using the GitHub MCP server as an example.

The `docs/cli/index.md` has been updated to include a link to this
new tutorials section.
2025-06-06 13:05:13 -04:00
Jacob Richman 89aca349cf Exit with an error message if parsing settings.json fails. (#747) 2025-06-06 09:56:45 -07:00
jerop b4a6b16227 Test: Verify concatenated env var resolution in settings
Adds a test case to `settings.test.ts` to specifically verify
the correct resolution of multiple environment variables concatenated
within a single string value (e.g., ${HOST}:${PORT} ).
2025-06-06 11:47:37 -04:00
jerop 8c28250bb3 Refactor: Improve env var resolution in settings
Refactors the `resolveEnvVarsInObject` function in settings to
explicitly handle primitive types (null, undefined, boolean, number)
at the beginning of the function. This clarifies the logic for
subsequent string, array, and object processing.
2025-06-06 11:47:37 -04:00
jerop 4e9d365407 feat: Enable environment variable substitution in settings
This commit introduces the ability to use system environment variables
within the settings files (e.g., `settings.json`). Users can now
reference environment variables using the `${VAR_NAME}` syntax.

This enhancement improves security and flexibility, particularly
for configurations like MCP server settings, which often require
sensitive tokens.

Previously, to configure an MCP server, a token might be directly
embedded:
```json
"mcpServers": {
  "github": {
    "env": {
      "GITHUB_PERSONAL_ACCESS_TOKEN": "pat_abc123"
    }
    // ...
  }
}
```

With this change, the same configuration can securely reference an
environment variable:
```json
"mcpServers": {
  "github": {
    "env": {
      "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
    }
    // ...
  }
}
```

This allows users to avoid storing secrets directly in configuration files.
2025-06-06 11:47:37 -04:00
Jacob Richman 9ad615c2a4 Fix build break due to changes to theme. (#796) 2025-06-06 08:05:00 -07:00
Jacob Richman 4262f5b0de feat(cli): respect the NO_COLOR env variable (#772) 2025-06-06 07:55:28 -07:00
DeWitt Clinton c80ff146d2 Reduce noisy logging for missing .geminiignore file. (#793) 2025-06-06 07:47:43 -07:00
Eddie Santos 368e9ab4d8 Add Gemini code review agent to repo (#782) 2025-06-05 21:37:06 -07:00
matt korwel 2f51c22141 Title & Big text Updates (#781) 2025-06-05 18:14:02 -07:00
Miguel Solorio 8a0a2523ca Allow themes to theme the UI (#769) 2025-06-05 14:35:47 -07:00
Brandon Keiji 2285bba66e refactor: remove unnecessary useRefs (#780) 2025-06-05 21:33:24 +00:00
Olcan d3a1026ae3 skip npm build for custom sandbox (#779) 2025-06-05 14:15:43 -07:00
N. Taylor Mullen 1ffe027d8a Add support for configured mcp client timeout. (#775) 2025-06-05 20:35:00 +00:00
Tommaso Sciortino e59e18251b Introduce generate content interface (#755) 2025-06-05 13:26:38 -07:00
Jerop Kipruto 2ebf2fbc82 OpenTelemetry Integration & Telemetry Control Flag (#762) 2025-06-05 13:04:25 -07:00
Olcan d3e43437a0 use execSync (vs spawnSync) so launch fails if build_sandbox fails; tweaks in build_sandbox to fix some shellcheck warnings, and to simplify the logic slightly (#767) 2025-06-05 13:02:56 -07:00
Eddie Santos e02868bb1a Bump default model to gemini-2.5-pro-preview-06-05 (#765) 2025-06-05 11:52:36 -07:00
Eddie Santos 422c763a55 Add support for .geminiignore file (#757) 2025-06-05 10:15:27 -07:00
Tolik Malibroda 1d20cedf03 fix: Disable automatic image building if BUILD_SANDBOX is not provided (#764) 2025-06-05 18:47:39 +02:00
Tolik Malibroda 4d4cf0f2f9 feat: Add multi-stage docker build support for custom sandbox.Dockerfile (#746) 2025-06-05 17:46:54 +02:00
Miguel Solorio a8ac9b1fac Add Theme docs (#753) 2025-06-05 08:10:05 -07:00
anj-s 78b2a28fb6 Checks for diff changes before displaying the code snippet (#751) 2025-06-05 06:48:03 -07:00
Jacob Richman aa386d135b Jacob314/memory fixes (#754)
Address multiple possible memory leaks found bystatic analysis of the codebase. The primary source of the leaks was event listeners on child processes and global objects that were not being properly removed, potentially causing their closures to be retained in memory indefinitely particularly for processes that did not exit.

There are two commits. A larger one made by gemini CLI and a smaller one by me to make sure we always disconnect child processes as part of the cleanup methods. These changes may not actually fix any leaks but do look like reasonable defensive coding to avoid leaking event listeners or child processes.

The following files were fixed:
This is Gemini's somewhat overconfident description of what it did.

packages/core/src/tools/shell.ts: Fixed a leak where an abortSignal listener was not being reliably removed.
packages/cli/src/utils/readStdin.ts: Fixed a significant leak where listeners on process.stdin were never removed.
packages/cli/src/utils/sandbox.ts: Fixed leaks in the imageExists and pullImage helper functions where listeners on spawned child processes were not being removed.
packages/core/src/tools/grep.ts: Fixed three separate leaks in the isCommandAvailable check and the git grep and system grep strategies due to un-removed listeners on child processes.
packages/core/src/tools/tool-registry.ts: Corrected a leak in the execute method of the DiscoveredTool class where listeners on the spawned tool process were not being removed.
2025-06-05 06:40:33 -07:00
N. Taylor Mullen 822803d9d6 Fix "npx https:...." header issue (#759) 2025-06-05 07:00:34 +00:00
N. Taylor Mullen 77afd37c2e fix(cli): Handle non-array tool response parts (#758) 2025-06-05 06:25:57 +00:00
Eddie Santos d99d132cdf Add /tools slash command to view available tools (#752) 2025-06-04 14:01:38 -07:00
Olcan fdc8bd8ed9 mention BUILD_SANDBOX for custom sandboxing (#749) 2025-06-04 12:58:44 -07:00
Riccardo Carlesso 13b55c6e68 Docs: Update architecture diagram with Google colors (for future aricles) (#718) 2025-06-04 12:33:07 -07:00
Tommaso Sciortino 4192cfb092 CLI_TITLE env var for setting the CLI title (#748) 2025-06-04 10:44:50 -07:00
Miguel Solorio a2f03636a5 Update light themes (#726) 2025-06-04 10:41:03 -07:00
Keith Ballinger a14aada945 Fix broken documentation links after server->core folder rename (#740) 2025-06-04 10:02:07 -07:00
N. Taylor Mullen 44aff769a3 Bring back 2.5-pro usage (#744)
https://chat.google.com/room/AAQApBm33UQ/8DQw4Ykp8f0/8DQw4Ykp8f0?cls=10
2025-06-04 09:29:14 -07:00
N. Taylor Mullen afc30e314f feat(accessibility): Add option to disable loading phrases (#745) 2025-06-04 07:46:57 +00:00
N. Taylor Mullen d179b3aae4 refactor(core): Centralize tool response formatting (#743) 2025-06-04 07:24:25 +00:00
Tolik Malibroda 4b2af10b04 fix: Fix piped input mode in sandbox (#739) 2025-06-04 08:24:33 +02:00
Marat Boshernitsan 7de790fbf2 Fix several bugs in prompt history (#734)
Co-authored-by: Marat Boshernitsan <maratb@google.com>
2025-06-03 23:01:26 -07:00
Keith Ballinger c313762ba0 Ignore folders files (#651)
# Add .gitignore-Aware File Filtering to gemini-cli

This pull request introduces .gitignore-based file filtering to the gemini-cli, ensuring that git-ignored files are automatically excluded from file-related operations and suggestions throughout the CLI. The update enhances usability, reduces noise from build artifacts and dependencies, and provides new configuration options for fine-tuning file discovery.

Key Improvements
.gitignore File Filtering

All @ (at) commands, file completions, and core discovery tools now honor .gitignore patterns by default.
Git-ignored files (such as node_modules/, dist/, .env, and .git) are excluded from results unless explicitly overridden.
The behavior can be customized via a new fileFiltering section in settings.json, including options for:
Turning .gitignore respect on/off.
Adding custom ignore patterns.
Allowing or excluding build artifacts.
Configuration & Documentation Updates

settings.json schema extended with fileFiltering options.
Documentation updated to explain new filtering controls and usage patterns.
Testing

New and updated integration/unit tests for file filtering logic, configuration merging, and edge cases.
Test coverage ensures .gitignore filtering works as intended across different workflows.
Internal Refactoring

Core file discovery logic refactored for maintainability and extensibility.
Underlying tools (ls, glob, read-many-files) now support git-aware filtering out of the box.


Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-06-04 04:40:46 +00:00
Cindy Xing d85f09ac51 Update configuration.md (#722) 2025-06-03 21:33:02 -07:00
N. Taylor Mullen 54eb1419a8 Update package-lock.json (#738) 2025-06-04 04:05:39 +00:00
Keith Ballinger 7108921691 fix Cannot find module @rollup/rollup-linux-x64-gnu error (#736) 2025-06-03 19:52:53 -07:00
Olcan 80a445c7ae bandaid for broken mcp calls (#732) 2025-06-03 14:40:36 -07:00
Olcan 12059eb4ca fix BUILD_SANDBOX env var for updating sandbox while running linked binary (#729) 2025-06-03 14:02:00 -07:00
Olcan 9df94103ac remove noop code (#728) 2025-06-03 13:47:53 -07:00
Olcan 00a9f654a3 fixed strip-ansi dep by installing it in core package (also ran npm install in cli package that resulted in the minor changes here) (#727) 2025-06-03 13:37:59 -07:00
Brandon Keiji e96fd677ee fix: do not try to pull development sandbox image from the internet (#725) 2025-06-03 19:32:17 +00:00
Brandon Keiji 546e033081 feat: notify user when chat context is compressed (#724) 2025-06-03 19:19:49 +00:00
Brandon Keiji fa5b616a10 feat: compress chat history when we approach token limit (#711) 2025-06-03 18:54:11 +00:00
N. Taylor Mullen 080af01715 Fix flash preview (#723) 2025-06-03 18:01:59 +00:00
N. Taylor Mullen c5099e9025 Workaround Gemini API break - Use flash 04-17 (#721) 2025-06-03 17:47:20 +00:00
Olcan e190249732 link tool discovery/call docs from core configuration doc (#720) 2025-06-03 10:22:43 -07:00
Allen Hutchison 72f5ec3725 feat(cli): randomize and expand witty loading phrases (#704) 2025-06-03 10:12:47 -07:00
Olcan d967752833 document mcp server trust option (#719) 2025-06-03 10:08:34 -07:00
anj-s fffa06f0b1 Modify shortenPath and add param validation (#663) 2025-06-03 08:59:17 -07:00
anj-s e9d43b9388 Add params check for writeTool (#708) 2025-06-03 07:47:27 -07:00
N. Taylor Mullen c71d6ddc3b Fix: Ensure MCP tools are discovered from slow-starting servers (#717) 2025-06-03 07:40:51 +00:00
N. Taylor Mullen 5f6f6a95a2 Refactor: Make MCP server discovery non-blocking (#716) 2025-06-03 06:37:02 +00:00
N. Taylor Mullen 8ab74ef1bb Refactor: Use config.getGeminiClient() for GeminiClient instantiation (#715) 2025-06-03 05:30:52 +00:00
N. Taylor Mullen cf84f1af68 Docs: Enhance "Writing Tests" section in GEMINI.md (#688) 2025-06-02 21:46:20 -07:00
N. Taylor Mullen cf3e1a07c1 Remove redundant variable. (#713) 2025-06-02 21:18:01 -07:00
Brandon Keiji 74801e9004 refactor: maintain 1 GeminiChat per GeminiClient (#710) 2025-06-02 19:10:54 -07:00
Jacob Richman 447826ab40 fix(cli): restore first-launch theme prompt (#703) 2025-06-02 19:09:11 -07:00
Scott Densmore 2ab7e3da71 feat(cli): Allow custom title in CLI header (#706) 2025-06-02 17:09:55 -07:00
Bryan Morgan 91fa770196 upate to PR 669 (#700)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-06-02 16:59:38 -07:00
N. Taylor Mullen 8563e46ade React to Gemini API break - Thought Inclusion (#705) 2025-06-02 23:32:45 +00:00
Allen Hutchison 6fb07f0b50 fix(ci): correct input name for core coverage summary (#698) 2025-06-02 15:53:26 -07:00
N. Taylor Mullen 6020c760b5 Feat: Enable YOLO mode for non-interactive execution (#702) 2025-06-02 22:35:03 +00:00
Scott Densmore e428707e07 Refactor: Centralize GeminiClient in Config (#693)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-06-02 14:55:51 -07:00
Olcan 1dcf0a4cbd strip ansi from shell output (#699) 2025-06-02 14:50:12 -07:00
Jacob Richman 51949f3121 Fix bug pasting multiline strings (#632) 2025-06-02 14:31:35 -07:00
Olcan 8365c8f954 prefer to load gemini-specific .env file from .gemini folder when it exists there (#697) 2025-06-02 14:16:48 -07:00
Allen Hutchison 7f20425c98 feat(cli): add pro model availability check and fallback to flash (#608) 2025-06-02 13:55:54 -07:00
Olcan 59b6267b2f allow toolDiscoveryCommand to return function declarations with or without a tool wrapper; fully document both toolDiscoveryCommand and toolCallCommand with examples and pointers to API docs (#696) 2025-06-02 13:41:49 -07:00
N. Taylor Mullen 58597c29d3 refactor: Update MCP tool discovery to use @google/genai - Also fixes JSON schema issues. (#682) 2025-06-02 20:39:25 +00:00
Tolik Malibroda 0795e55f0e feat: Add --yolo mode that automatically accepts all tools executions (#695)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-06-02 22:05:45 +02:00
N. Taylor Mullen 42bedbc3d3 feat: Refactor CLI header for customizable logo text (#658) 2025-06-02 11:45:09 -07:00
Miguel Solorio 33052018a2 Color enhancements (#680) 2025-06-02 11:20:58 -07:00
Olcan c5869db080 enable async tool discovery by making the registry accessor async; remove call to discoverTools that caused duplicate discovery (#691) 2025-06-02 09:56:32 -07:00
N. Taylor Mullen 467dec4edf Add a note about Gemini API usage and add a link to the TOS. (#681) 2025-06-02 09:42:24 -07:00
Sandy Tao 4a455a053a Add documentation about debugging using React DevTools (#679) 2025-06-02 09:16:03 -07:00
N. Taylor Mullen 34b81abd9c fix: Ensure all tool calls are complete before submitting responses (#689) 2025-06-02 08:50:28 +00:00
N. Taylor Mullen 27ba28ef76 fix: Refine model message consolidation for improved model interaction (#685) 2025-06-02 07:28:14 +00:00
N. Taylor Mullen 6d417186cb Enable "Debug Test" config to debug Server or CLI tests. (#683) 2025-06-02 07:07:10 +00:00
Olcan d009267801 more strict italics: delimiters cannot be preceded/followed by \w or [./\\]\S (#677) 2025-06-01 16:52:31 -07:00
N. Taylor Mullen 2828fc6d66 feat: Implement non-interactive mode for CLI (#675) 2025-06-01 23:11:37 +00:00
N. Taylor Mullen c51d6cc9d3 fix: Display MCP server count in context summary (#674) 2025-06-01 22:48:48 +00:00
Bryan Morgan f7a2442fac Added replace tool ability to replace more than 1 occurrence (#669)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-06-01 17:49:48 -04:00
N. Taylor Mullen f2a8d39f42 refactor: Centralize tool scheduling logic and simplify React hook (#670) 2025-06-01 14:16:24 -07:00
Leo edc12e416d Update edit tool validation function to override validateToolParams (#667) 2025-06-01 11:18:43 -07:00
anj-s 9dae07784b Fix for validating getDescription in read_file tool call (#660) 2025-06-01 00:02:00 -07:00
Scott Densmore c414512f19 Fix: Make file path case-insensitive in @-command (#659) 2025-05-31 16:19:14 -07:00
Bryan Morgan b1d693786c Revert "cleanup: removed duplicate check from Config.registerCoreTool()" (#657)
Didn't notice the casing difference - duh....
2025-05-31 20:52:52 +00:00
Bryan Morgan b228923446 cleanup: removed duplicate check from Config.registerCoreTool() (#656) 2025-05-31 16:50:19 -04:00
Allen Hutchison 53bf778497 feat: allow custom filename for context files (#654)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-05-31 12:49:28 -07:00
Miguel Solorio cbc1614b84 Update default & ANSI theme names (#637) 2025-05-31 11:10:52 -07:00
Miguel Solorio c350fbef7f Add default build task for VS Code (#639) 2025-05-31 11:09:25 -07:00
Taylor Mullen 1a84d8f674 Test: Add comprehensive tests for useToolScheduler hook
- Introduces a suite of tests for the  hook, covering various scenarios including:
  - Successful tool execution
  - Tool not found errors
  - Errors during
  - Errors during tool execution
  - Tool confirmation (approved and cancelled) - (currently skipped)
  - Live output updates - (currently skipped)
  - Cancellation of tool calls (before execution and during approval) - (currently skipped)
  - Execution of multiple tool calls
  - Preventing scheduling while other calls are running - (currently skipped)
- Includes tests for the  utility function to ensure correct mapping of tool call states to display objects.
- Mocks dependencies like , , and individual  instances.
- Uses fake timers to control asynchronous operations.

Note: Some tests involving complex asynchronous interactions (confirmations, live output, cancellations) are currently skipped due to challenges in reliably testing these scenarios with the current setup. These will be addressed in future work.
2025-05-31 02:55:36 -07:00
Taylor Mullen ae8e2106bb Fix: Update code coverage reporting for core rename
- Renames "server" to "core" in GitHub Actions workflow and comment posting action.
- This ensures that code coverage paths and labels are accurate after the package rename.
2025-05-31 01:50:41 -07:00
Taylor Mullen 76cee17417 Refactor: Generalize VSCode launch configuration for debugging tests
- Consolidates multiple specific test debug configurations into a single, more flexible configuration named "Debug Test File".
- Introduces an input variable `testFile` to prompt the user for the specific test file path, defaulting to a sample test file.
- This change simplifies the launch configuration and makes it easier to debug any test file without needing a dedicated configuration for each.
2025-05-31 01:28:21 -07:00
Olcan 0dbd12e295 expose shell process group id to model, along with instructions for how to terminate or signal the group (#645) 2025-05-30 23:25:44 -07:00
Taylor Mullen 190e6be800 Fix: Update sandbox build to use new core package name
- The `packages/core` tarball name changed from `gemini-code-server-*.tgz` to `gemini-code-core-*.tgz` after the `server` to `core` rename.
- This updates `scripts/build_sandbox.sh` and the root `Dockerfile` to use the new `gemini-code-core-*.tgz` naming, resolving the CI failure during the Docker build step of the publish process.
2025-05-30 22:41:54 -07:00
Scott Densmore bda7ec94df Fix: Update git branch watcher to use .git/logs/HEAD (#643) 2025-05-30 21:08:56 -07:00
Daniel Young Lee 1468047081 feat: Implement delayed Ctrl+C exit prompt
This change introduces a small delay after the first Ctrl+C press, prompting the user to press Ctrl+C again to exit. This helps prevent accidental termination of the application.

- Added `exitOnCtrlC={false}` to the Ink render options in `gemini.tsx` to enable custom Ctrl+C handling.
- Implemented logic in `App.tsx` to:
    - Display "Press Ctrl+C again to exit." for 2 seconds after the first Ctrl+C.
    - Exit the application if Ctrl+C is pressed again during this period.
    - Revert to normal operation if the second Ctrl+C is not pressed within the timeout.
- Defined a constant `CTRL_C_PROMPT_DURATION_MS` for the timeout duration.
2025-05-30 20:51:07 -07:00
Scott Densmore 7012c86336 Fix/cli version unknown (#642) 2025-05-30 20:45:15 -07:00
Scott Densmore 98699a0ab5 Refactor: Align build scripts with core package rename (#641) 2025-05-30 20:16:35 -07:00
Tommaso Sciortino 21fba832d1 Rename server->core (#638) 2025-05-30 18:25:47 -07:00
Olcan c81148a0cc use json block for mcp tool output (and re-enable markdown rendering) (#635) 2025-05-30 15:59:23 -07:00
Olcan 2e57989aec confirm mcp tool executions from untrusted servers (per "trust" setting) (#631) 2025-05-30 15:32:21 -07:00
Allen Hutchison a60e51f44d fix(ci): Adjust reporting for PRs from forks (#627) 2025-05-30 15:30:09 -07:00
Jacob Richman 01768d7759 feat: add --show_memory_usage flag to display memory usage in status bar (#606) 2025-05-30 15:18:01 -07:00
Allen Hutchison 3291ffbe09 fix(cli): Clear input buffer before onSubmit in InputPrompt (#633) 2025-05-30 15:16:06 -07:00
Olcan 4225567303 disable markdown for discovered (mcp) tools (#630) 2025-05-30 14:12:51 -07:00
Olcan 1a5fd2ccb2 add flags for markdown rendering and live updating to Tool to avoid special-casing shell tool by name, and open door for other tools to specify their rendering/updating (#629) 2025-05-30 13:59:05 -07:00
Brandon Keiji 0869fd168f fix(sandbox): pull sandbox image if it doesnt exist locally (#628) 2025-05-30 20:49:47 +00:00
Brandon Keiji cf82b6e127 fix(sandbox): prepare package.json before building sandbox image (#626) 2025-05-30 19:57:46 +00:00
Olcan a0ba65944f disable markdown rendering of shell tool output (#625) 2025-05-30 12:43:59 -07:00
Brandon Keiji 31a7affb74 feat(sandbox): use package config to dictate sandbox image name (#624) 2025-05-30 19:28:46 +00:00
cperry-goog 9f85f8ed29 docs: Update README, CONTRIBUTING, and CLI configuration docs (#591)
cleaning up for now, will take another pass
2025-05-30 12:20:12 -07:00
Brandon Keiji 816cc08a8f fix(sandbox): set default env var to 'gemini-cli-sandbox' (#620) 2025-05-30 18:02:27 +00:00
N. Taylor Mullen 8c46108a85 feat: Implement retry with backoff for API calls (#613) 2025-05-30 17:57:00 +00:00
Taylor Mullen c5608869c0 Change ReadFile to not have a result display.
- It's verbose on its own; however, if file content is truncated we'll indicate that in the result display.
2025-05-30 10:48:10 -07:00
Taylor Mullen 9537ff4762 feat(server): consolidate adjacent model content in chat history
- Consolidates consecutive model messages into a single message in the chat history.
- This prevents multiple model messages from being displayed in a row, improving readability.
- This may also address some instances of 500 errors that could have been caused by multiple, rapidly succeeding model messages.
- Adds tests for the new consolidation logic.

Fixes https://b.corp.google.com/issues/421010429
2025-05-30 10:43:48 -07:00
Olcan 7c4a5464f6 truncate (hide) tool output at the top, add some spacing, also fix shell output interval change accidentally undone in a previous commit (#619) 2025-05-30 01:58:09 -07:00
Olcan a3b557222a tweaks to shell abort logic based on feedback (#618) 2025-05-30 01:35:03 -07:00
Olcan 094b9dc474 use npx json instead of jq (#617) 2025-05-30 01:12:36 -07:00
Olcan 8935a248f6 allow aborting of shell mode (!) commands, similar to shell tool commands. fix bug that prevented aborts after first abort. more robust killing logic (#616) 2025-05-30 00:46:43 -07:00
Olcan b0aeeb53b1 update shell output at an interval to reduce flicker (#614) 2025-05-30 00:02:30 -07:00
Brandon Keiji 2582c20e2a fix: publish @gemini-code/server (#605) 2025-05-29 23:55:34 +00:00
Brandon Keiji 7468d3cddf fix(sandbox): add SHORT_SHA to image tag (#604) 2025-05-29 23:43:20 +00:00
Olcan 1c066548b4 allow comments in settings when parsed in scripts via jq (#603) 2025-05-29 16:25:16 -07:00
Olcan fe049c286f fix mcp tool names that are long or have invalid characters (based on 400 error) (#602) 2025-05-29 16:13:11 -07:00
Seth Troisi 2db5d83023 fix name in package.json 2025-05-29 15:56:05 -07:00
Jacob Richman dab7517622 Refactor read-file and support images. (#480) 2025-05-29 15:30:18 -07:00
Brandon Keiji f21abdd1f0 fix(sandbox): use CMD for default entrypoint (#601) 2025-05-29 22:16:39 +00:00
Olcan 4b7248fc46 allow writing to user cache directory on macos (fixes use of lyria mcp server [to generate songs] under seatbelt) (#600) 2025-05-29 15:06:09 -07:00
Allen Hutchison 5dbc83fabc feat: Enhance web_fetch tool to process prompts with URLs using Gemini API (#587) 2025-05-29 15:02:31 -07:00
Seth Troisi 4b4ba85313 improve read-many-files output (#596) 2025-05-29 14:03:24 -07:00
Brandon Keiji dc94a03f39 feat: publish root Dockerfile to our image registry (#599) 2025-05-29 14:01:44 -07:00
Jacob Richman 6a1b94529b Change Config to use named parameters. (#593) 2025-05-29 13:51:17 -07:00
Taylor Mullen d74c0f581b refactor: Extract MCP discovery from ToolRegistry
- Moves MCP tool discovery logic from ToolRegistry into a new, dedicated MCP client (mcp-client.ts and mcp-tool.ts).
- Updates ToolRegistry to utilize the new MCP client.
- Adds comprehensive tests for the new MCP client and its integration with ToolRegistry.

Part of https://github.com/google-gemini/gemini-cli/issues/577
2025-05-28 17:28:45 -07:00
Allen Hutchison c413988ae0 fix(ci): Only run post_coverage_comment job on pull_request events (#588) 2025-05-28 17:09:13 -07:00
Allen Hutchison 9ee5eadac0 fix(cli): Support multiple @file references in atCommandProcessor (#590) 2025-05-28 17:08:05 -07:00
Brandon Keiji fd6f6b02ea feat: add git branch name to footer (#589) 2025-05-28 16:30:05 -07:00
Olcan 0d99398689 much improved support for background processes, avoiding termination (via SIGPIPE) or eventual blocking (e.g. due to filled OS buffers) (#586) 2025-05-28 14:45:46 -07:00
Jacob Richman 00805cb2cd Cleanup: Remove low value StreamingContextType interface. (#585) 2025-05-28 12:46:08 -07:00
Jacob Richman 05a49702d8 Refactor: Add GeminiRespondingSpinner to make use of streamingState idiomatic (#583) 2025-05-28 11:17:19 -07:00
DeWitt Clinton 98dcf43214 Add a keybinding for ctrl+w to delete the previous word. (#582)
Adds the following new keybindings to the cli text input buffer:

- `Ctrl+W` : Delete previous word
2025-05-28 09:59:25 -07:00
DeWitt Clinton 27a773d5b2 Display git commit info in the /about section. (#567)
This change detects the most recent git commit short hash and writes it to the `GIT_COMMIT_INFO` constant in `packages/cli/src/generated/git-commit.sh`, optionally appending the string "(local modifications)" if additional local changes after that commit are detected.

If set, this string is displayed in the `/about` dialog as well as passed into the `/bug` template.

Example:

```
> /about

╭───────────────────────────────────────────────────────────────────────────╮
│                                                                           │
│ About Gemini CLI                                                          │
│                                                                           │
│ CLI Version               development                                     │
│ Git Commit                43370ab (local modifications)                   │
│ Model                     gemini-2.5-pro-preview-05-06                    │
│ Sandbox                   sandbox-exec (minimal)                          │
│ OS                        darwin v23.11.0                                 │
│                                                                           │
╰───────────────────────────────────────────────────────────────────────────╯
```

Additionally, this change updates `.gitignore` to ignore the generated files, `scripts/clean.sh` to remove them, and adds a `npm run generate` stage for this and any other generators we need to write.
2025-05-28 00:04:26 -07:00
Taylor Mullen f2f2ecf9d8 feat: Allow cancellation of in-progress Gemini requests and pre-execution checks
- Implements cancellation for Gemini requests while they are actively being processed by the model.
- Extends cancellation support to the  logic within tools. This allows users to cancel operations during the phase where the system is determining if a tool execution requires user confirmation, which can include potentially long-running pre-flight checks or LLM-based corrections.
- Underlying LLM calls for edit corrections (within  and ) and next speaker checks can now also be cancelled.
- Previously, cancellation of the main request was not possible until text started streaming, and pre-execution checks were not cancellable.
- This change leverages the updated SDK's ability to accept an abort token and threads s throughout the request, tool execution, and pre-execution check lifecycle.

Fixes https://github.com/google-gemini/gemini-cli/issues/531
2025-05-27 23:46:37 -07:00
Olcan bfeaac8441 live output from shell tool (#573) 2025-05-27 15:40:18 -07:00
Olcan 0d5f7686d7 fix tool cancellation while executing (#575) 2025-05-27 15:22:30 -07:00
Brandon Keiji c1395a8808 fix: change entrypoint from 'gemini-code' to 'gemini' in published sandbox (#574) 2025-05-27 22:19:43 +00:00
Brandon Keiji d4ae1ede39 refactor: use React strict mode (#569) 2025-05-27 14:40:46 -07:00
Olcan 16c16127e7 fix sandboxing anchor (#572) 2025-05-27 14:01:23 -07:00
Olcan 0c5673875b improve shell tool output when cancelled in debug mode (#571) 2025-05-27 13:47:40 -07:00
Allen Hutchison 4e3c539f5e feat: Publish test coverage summaries to PRs (#513) 2025-05-27 12:45:28 -07:00
Olcan 9595e98db8 replace error with warning if sandbox build is triggered without enabling, improve README to reduce confusion (#570) 2025-05-27 10:55:07 -07:00
sasha-gitg 3511e84dc3 fix: default to Gemini API if GEMINI_API_KEY is set and when GOOGLE_GENAI_USE_VERTEXAI is set to True (#566) 2025-05-27 10:00:07 -07:00
Taylor Mullen b3f52e215a feat: Replace SQLite with JSON logging for macOS sandbox compatibility
- Removes the sqlite3 dependency and refactors the logging mechanism to use a JSON file (logs.json) instead of a database.
- This change is a temporary workaround to address issues with macOS sandboxing that were caused by the SQLite native module.
- Storing all logs in a single JSON file may introduce scalability concerns in the future.

Fixes https://github.com/google-gemini/gemini-cli/issues/522
2025-05-26 16:13:37 -07:00
Taylor Mullen 9e1cfca53f Fix(chat): Finalize next speaker detection logic
- Enhance `checkNextSpeaker` to handle cases where the last message is a function response or an empty model message.
- If the last message is a function response, the model should speak next.
- If the last message is an empty model message, the model should speak next.
- This ensures more robust and accurate determination of the next speaker in the conversation, completing the fix for the issue.
- Updated tests.

Fixes https://github.com/google-gemini/gemini-cli/issues/551
2025-05-26 15:21:45 -07:00
Taylor Mullen c92d4edb89 Fix(chat): Ensure model responds when next speaker check indicates
- Corrects an issue where the `nextSpeakerCheck` would determine the model should speak next, but the models response was not properly propagated due to a missing `yield*` in a recursive call within `sendMessageStream`.
- This change ensures that when the model is designated as the next speaker, its generated content is correctly unwoven and returned, allowing the conversation to proceed as expected.

Part of https://github.com/google-gemini/gemini-cli/issues/551
2025-05-26 14:37:13 -07:00
Taylor Mullen 597dc86a9c Fix(chat): Prevent empty model response after function call
- Addresses a Gemini model bug where it may return an empty content object after a function response.
- Previously, the SDK attempted to inject an empty model message, which could disrupt curated history.
- This change modifies our custom  class to detect this scenario using an  utility and avoid pushing an unnecessary empty model message, thus preserving history integrity.

Workaround for https://b.corp.google.com/issues/420354090
Part of https://github.com/google-gemini/gemini-cli/issues/551
2025-05-26 14:29:24 -07:00
Taylor Mullen 480549e02e Refactor(chat): Introduce custom Chat class for future modifications
- Copied the `Chat` class from `@google/genai` into `packages/server/src/core/geminiChat.ts`.
- This change is in preparation for future modifications to the chat handling logic.
- Updated relevant files to use the new `GeminiChat` class.

Part of https://github.com/google-gemini/gemini-cli/issues/551
2025-05-26 14:20:28 -07:00
Taylor Mullen 02503a3248 Chore(deps): Upgrade @google/genai to v1.0.1
- Upgraded the @google/genai SDK from ^0.13.0 to ^1.0.1.
- Addressed a related type error in `packages/server/src/tools/edit.test.ts` by updating a type assertion.

Part of https://github.com/google-gemini/gemini-cli/issues/551
2025-05-26 14:09:43 -07:00
Taylor Mullen 70d469ccd3 Fix(diff): Hide whitespace changes in diffs with content changes
- Updated the diff generation in `edit.ts` and `write-file.ts` to include the `ignoreWhitespace: true` option.
- This ensures that whitespace-only changes are not highlighted in the diff output when there are other content modifications, making the diffs cleaner and easier to review.
- Extract default diffing options into single source of truth.

Fixes https://github.com/google-gemini/gemini-cli/issues/548
2025-05-25 22:45:53 -07:00
Taylor Mullen 8440b971f5 Fix(cli): Prevent premature input box reactivation during tool confirmation
- Introduced a 'validating' state for tool calls to prevent the input box from reappearing while waiting for a tool's `shouldConfirmExecute` method to complete.
- When a tool call is initiated, it's now immediately set to a 'validating' status. This ensures the UI remains in a busy/responding state.
- `useGeminiStream` now considers the 'validating' state as part of `StreamingState.Responding`.
- `useToolScheduler` has been updated to:
    - Set the initial status of new tool calls to 'validating'.
    - Asynchronously perform the `shouldConfirmExecute` check.
    - Transition to 'awaiting_approval' or 'scheduled' based on the check's outcome.
- This resolves an issue where a slow `shouldConfirmExecute` could lead to the input prompt becoming active again before the tool call lifecycle was fully determined. While 'validating' is currently treated similarly to 'executing' in the UI, this new state provides a foundation for more customized user experiences during this phase in the future.

Fixes https://github.com/google-gemini/gemini-cli/issues/527
2025-05-25 16:06:33 -07:00
Taylor Mullen 7408c78dbb Change tool call spinner to be different.
- This differentiates the tool calling spinner from one that matches the normal loading indiator to somethign a little more seamless.
2025-05-25 16:05:22 -07:00
Taylor Mullen 3281cbc835 Fix(test): Improve write-file and editCorrector test suites
- Enhanced  by:
  - Mocking  and  utilities (, ) to allow for more focused unit testing of .
  - Adding comprehensive tests for the private  method, covering new and existing file scenarios, as well as error handling.
  - Expanding tests for  and  to verify behavior with the new content correction logic, including diff generation and directory creation.
- Refined  by:
  - Introducing robust mocking for  and its methods (, , ) to simulate LLM interactions accurately.
  - Adding extensive test scenarios for , categorized by how  matches and how  is processed, including direct matches, unescaping, and LLM-based corrections.
  - Including tests for edge cases like no matches or multiple matches.
  - Adding a  utility for better test isolation.

Final fix for https://github.com/google-gemini/gemini-cli/issues/484
2025-05-25 15:02:08 -07:00
Taylor Mullen 5097b5a656 Fix(write-file): Correct over-escaping and improve content generation
- Leveraged existing edit correction technology from `edit.ts` to address over-escaping issues in `write-file.ts`.
- Introduced `ensureCorrectFileContent` for correcting content in new files, where a simple "replace" isnt applicable. This uses a new LLM prompt tailored for correcting potentially problematic string escaping.
- Added caching for `ensureCorrectFileContent` to optimize performance.
- Refactored `write-file.ts` to integrate these corrections, improving the reliability of file content generation and modification.

Part of https://github.com/google-gemini/gemini-cli/issues/484
2025-05-25 14:45:47 -07:00
Taylor Mullen 1a5fe16b22 Ensure edit correction isn't re-done after confirm.
- Edit corretion leans on LLM-isms to ensure we properly fix poorly escaped content. Beacues of this we need to ensure that we don't re-run edit correction in many cases.
  - To ensure this an `LruCache` has been added to capture intermediate steps of edit correction to avoid re-computations.
  - Max cache size is 50 currently. This means a user can have a muti-confirmation flow of 25 items without recomputing anything (assuming they all break edit correction).
- Laid some groundwork for future testing.

Part of https://github.com/google-gemini/gemini-cli/issues/484
2025-05-25 14:24:09 -07:00
Taylor Mullen c181fc1cf3 Correct edits even when auto-accept is enabled.
- Prior to this when a user would turn on auto-accept for edits we'd stop ensuring correct edits. This would result in a lot of back and forth by the model. This change also incoporates ensure correct edit into the normal execution flow.
- Added edit tests for this.

Part of https://github.com/google-gemini/gemini-cli/issues/484
2025-05-25 14:18:54 -07:00
Taylor Mullen 48781272ee Trim edits if possible.
- Since we're now LLM correcting a lot of problematic edits we need to also potentially trim bad edits (llms have a bad habbit of adding whitespace places).

Part of https://github.com/google-gemini/gemini-cli/issues/484
2025-05-25 14:01:52 -07:00
Taylor Mullen 2e3eeaf920 Upon finding > 1 occurrences do not attempt auto-correction.
- When correcting edits prior to this if we found more than one occurrence we would try to auto-correct the old/new strings. There's no need in this situation because the tool has already provided too vague of an old_string to act upon. Instantly return.

Part of https://github.com/google-gemini/gemini-cli/issues/484
2025-05-25 13:47:19 -07:00
Taylor Mullen ceb25c8350 refactor: Decouple new_string correction from old_string
- Previously, `new_string` was assumed to be over-escaped if `old_string` was.
- This change introduces an explicit check (`newStringPotentiallyEscaped`) to determine if `new_string` itself needs correction.
- If `new_string` is potentially escaped, its corrected using an LLM call; otherwise, the original `new_string` is used.
- This avoids unnecessary corrections to `new_string` when only `old_string` was problematic.

Part of https://github.com/google-gemini/gemini-cli/issues/484
2025-05-25 13:40:58 -07:00
Taylor Mullen 24da7b3ca6 refactor: Correct Gemini's over-escaped new_string in replace tool
- Implement a heuristic to detect and unescape `new_string` if it appears Gemini has over-escaped it, while `old_string` is correctly formatted.
- This improves the reliability of the replace tool when the model generates an incorrectly escaped replacement string.

Part of https://github.com/google-gemini/gemini-cli/issues/484
2025-05-25 13:30:08 -07:00
Taylor Mullen fa4a04157f refactor: Improve editCorrector logic and type safety
- Refactor `ensureCorrectEdit` to clarify the correction flow for `old_string` and `new_string`.
- Only correct `new_string` if it was potentially escaped; otherwise, use the original.
- Introduce `CorrectedEditParams` and `CorrectedEditResult` interfaces for better type definition.
- Relocate `countOccurrences` for better logical grouping.

Part of https://github.com/google-gemini/gemini-cli/issues/484
2025-05-25 13:18:07 -07:00
DeWitt Clinton 068b505d5e Reduce excessive diff separators in CLI. (#535)
Increases the threshold for rendering diff separators in the CLI's diff display. Previously, a separator was shown for gaps of more than one context line, leading to excessive separators in diffs with many small changes close together (Issue #534).

By increasing `MAX_CONTEXT_LINES_WITHOUT_GAP` to 5, we allow for more context lines before a separator is added, significantly reducing visual clutter in such diffs.

Added a test case to `DiffRenderer.test.tsx` to verify that separators are not rendered for small gaps within the new threshold.
2025-05-25 10:26:51 -07:00
Taylor Mullen e297b56390 feat: Add GEMINI.md tip to UI
- Display a tip to create a GEMINI.md file if one doesn't exist.
- Pass config to Tips component so it can inspect the initial GEMINI.md
count.
2025-05-24 12:40:06 -07:00
Jacob Richman b4c16d1f56 Code review comment fixes and some refactors. (#525)
No intentional different behavior aside for tweaks suggested from the code review of #506 Refactor: Extract console message logic to custom hook

This commit refactors the console message handling from App.tsx into a new custom hook useConsoleMessages.

This change improves the testability of the console message logic and declutters the main App component.

Created useConsoleMessages.ts to encapsulate console message state and update logic.
Updated App.tsx to utilize the new useConsoleMessages hook.
Added unit tests for useConsoleMessages.ts to ensure its functionality.
I deleted and started over on LoadingIndicator.test.tsx as I spent way too much time trying to fix it before just regenerating the tests as the code was easier to write tests for from scratch and the existing tests were not that good (I added them in the previous pull request).
2025-05-24 00:44:17 -07:00
Jacob Richman 1c3d9d7623 Make console message support more robust to logging in the middle of rendering. (#521) 2025-05-23 22:51:47 -07:00
DeWitt Clinton 7a3a9066f9 Add additional readline-like keybindings. (#524)
Adds the following conventional readline-like keybindings:

  - `Ctrl+H`: Delete the previous character.
  - `Ctrl+D`: Delete the next character.

Additionally, remaps the Debug Console command from Ctrl+D to Ctrl+O, which had been first introduced in PR #486.
2025-05-23 22:13:57 -07:00
Miguel Solorio 30080b9f4e 🧹 Format 2025-05-23 16:14:37 -07:00
Miguel Solorio 2a2d041dcd Update packages/cli/src/ui/types.ts
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-05-23 16:14:37 -07:00
Miguel Solorio 6247cb8ddd Update packages/cli/src/ui/hooks/slashCommandProcessor.ts
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-05-23 16:14:37 -07:00
Miguel Solorio 1af19c57de Remove CLI info from footer 2025-05-23 16:14:37 -07:00
Miguel Solorio 221370acc5 Add /about command 2025-05-23 16:14:37 -07:00
Taylor Mullen 4a6833ef49 feat: Enable npx execution on tagged versions
- Modify root package.json to allow publishing
- Update "files" to include only essential bundled assets

This change makes it possible to use npx with tagged versions of the
gemini-cli package (e.g., npx https://github.com/google-gemini/gemini-cli@early-access).
It removes "private: true" and refines the "files" array to ensure
that only the necessary bundled assets are included when the package is
fetched by npx, optimizing download size and ensuring correct execution.
2025-05-23 15:55:29 -07:00
Brandon Keiji 197c5b2bdf infra: emit errors on no-explicit-any eslint rule (#516) 2025-05-23 22:35:50 +00:00
Taylor Mullen 1ff083af27 fix: Update dependencies to resolve deprecation warnings 2025-05-23 14:50:00 -07:00
cornmander 635666dec9 MCP SSE support (#511)
Matches the config format used by other MCP clients.
2025-05-23 17:19:30 -04:00
Taylor Mullen 8590efd229 feat: Enable npx execution directly from GitHub URL
This commit modifies the packaging setup to allow the CLI to be
executed directly from its GitHub URL using `npx`, for example:
`npx https://github.com/google-gemini/gemini-cli` (once merged to main).
This is achieved without requiring the bundle to be checked into
the repository.

Key changes and motivations:

- Modify `scripts.prepare` to run `npm run bundle`:
  Ensures the CLI bundle is generated automatically when `npx`
  installs the package from a git URL. This replaces previous
  approaches (e.g., using `prepack`) which were not consistently
  triggered in the `npx` environment.

- Update `scripts.bundle` to use a direct path for `esbuild`
  and externalize `sqlite3`:
  Using `node_modules/.bin/esbuild` provides a more reliable way
  to invoke the bundler. Externalizing `sqlite3` is crucial for
  correctly handling its native addon, preventing runtime errors.

- Add `bin`, `files`, and root `sqlite3` dependency:
  - The `bin` field defines the `gemini` command.
  - The `files` array ensures the generated `bundle/` directory is
    recognized by npm.
  - `sqlite3` is added as a root dependency to ensure it's
    installed by `npx` when `gemini-code` is fetched, allowing the
    externalized module to be resolved.

These changes collectively ensure that the necessary build artifacts
are created on-the-fly during `npx` installation, providing a
seamless execution experience directly from the GitHub repository URL.
2025-05-23 13:55:06 -07:00
Brandon Keiji 8f266f9652 fix: do not retry cancelled tool calls (#504) 2025-05-23 17:30:09 +00:00
Jacob Richman 91ee02898a feat: Modify loading indicator to support a paused state (#506) 2025-05-23 10:25:17 -07:00
Jordan Demeulenaere e993181628 Mention Kotlin & Compose (Mutliplatform) in prompt.ts 2025-05-23 10:14:54 -07:00
Jacob Richman a96ff934ea Fix bug updating the cursor after navigating history. (#507) 2025-05-23 09:40:01 -07:00
Allen Hutchison a008d81780 Refactor(server): Centralize GEMINI.md discovery logic in server (#498) 2025-05-23 08:53:22 -07:00
Allen Hutchison f8c4276e69 Refactor(cli): Move memory add logic to server tool call (#493) 2025-05-23 08:47:19 -07:00
Olcan 70277591c4 update email to gemini-cli-dev (#510) 2025-05-23 08:35:16 -07:00
Olcan 564a213ebe allow write to ~/.gitconfig in seatbelt profiles (#509) 2025-05-23 07:56:43 -07:00
Taylor Mullen 7c3591f641 Refactor: Update streaming state logic to hide loader during confirmation
- The streaming state logic in `useGeminiStream.ts` has been updated.
- Previously, the loading indicator was displayed even when the system was
waiting for user confirmation on a tool call.
- This change introduces a `WaitingForConfirmation` state to ensure the
loading indicator is hidden during these confirmation prompts, improving
the user experience.
2025-05-23 00:39:05 -07:00
Brandon Keiji 01971741e0 feat: add emphasis to tool confirmations (#502) 2025-05-23 05:28:31 +00:00
Allen Hutchison 1d0856dcc8 Fix(server): Ensure debug responses are not recorded after cancellation (#491) 2025-05-22 16:34:32 -07:00
N. Taylor Mullen 6d3af7b97f Refactor: Consolidate and clarify core mandates and guidelines (#482)
Co-authored-by: Allen Hutchison <adh@google.com>
2025-05-22 22:42:33 +00:00
Allen Hutchison 2eb4b34aa7 Chore: Integrate coverage reporting into CI (#479) 2025-05-22 13:47:12 -07:00
Brandon Keiji 3787aa78cd fix: add shell-quote to server deps (#492) 2025-05-22 20:44:51 +00:00
Allen Hutchison 581709df80 Refactor: Streamline memoryUtils and update slash commands (#478) 2025-05-22 10:57:06 -07:00
Allen Hutchison 0c192555bb Fix: Prevent hang in large directories by using BFS for getFolderStru… (#470)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-05-22 10:47:21 -07:00
Jacob Richman 7eaf850489 Refactor: Improve console error/log display in CLI (#486) 2025-05-22 10:36:44 -07:00
Brandon Keiji fb1d13d600 fix: cancel parallel tool calls mid-execution (#489) 2025-05-22 03:02:45 -07:00
Brandon Keiji a8bfdf2d56 fix: synchronization between executed tools and turn loops (#488) 2025-05-22 02:51:07 -07:00
Taylor Mullen 174fdce7d8 feat: Update feedback mechanism to use /bug command
- Replaces the previous email-based feedback with a /bug command in the system prompt.
2025-05-21 23:32:54 -07:00
Brandon Keiji 4e3ba687a6 fix: forward entire tool call confirmation object through useToolScheduler (#481) 2025-05-22 06:00:36 +00:00
Brandon Keiji 02eec5c8ca feat: useToolScheduler hook to manage parallel tool calls (#448) 2025-05-21 22:57:53 -07:00
Allen Hutchison efee7c6cce Feat: Add test coverage scripts and ignore reports (#477) 2025-05-21 17:03:22 -07:00
Jacob Richman d74b0ac81d Remove unneeded linebreaks in tool description in read-many-files. (#476) 2025-05-21 16:59:23 -07:00
Allen Hutchison 43da8bc747 Fix: Align WebSearchTool API key handling with GeminiClient (#474) 2025-05-21 15:50:53 -07:00
Allen Hutchison a0761f0c41 Fix: Resolve CLI version reporting in /bug command (#455) 2025-05-21 13:31:18 -07:00
Olcan 00ab1905e0 use pending history item for shell mode, update as output is received (#471) 2025-05-21 13:16:50 -07:00
Olcan 01dbc61d1c space outputs in shell mode (#469) 2025-05-21 12:59:23 -07:00
DeWitt Clinton 01c28df8b2 Add globbing support to @-command file suggestions and resolution. (#462)
Implements recursive glob-based file search for both suggestions and execution of the `@` command.

- When typing `@filename`, suggestions will now include files matching `filename` in nested directories.
- Suggestions are sorted by path depth (shallowest first), then directories before files, then alphabetically.
- The maximum recursion depth for suggestions is set to 10.
- When executing an `@filename` command, if the file is not found directly, a recursive search (using the glob tool) is performed to locate the file.

This addresses the first request in issue #461 by allowing users to quickly reference deeply nested files without typing the full path. Also addresses b/416292478.
2025-05-21 12:22:18 -07:00
Brandon Keiji e1a64b41e8 feat: create tool scheduler hook (#468) 2025-05-21 10:35:40 -07:00
Olcan 2ad666a484 switch to spawn for shell mode (#467) 2025-05-21 09:31:13 -07:00
Olcan 8a70b98d1d fix exit code for shell mode also (#466) 2025-05-21 09:00:54 -07:00
Olcan c9de822930 fix exit code for shell tool (#465) 2025-05-21 08:51:22 -07:00
Olcan e30dc716b4 restore placeholder change likely dropped in a merge (#464) 2025-05-21 07:55:20 -07:00
Olcan 2080af029b remove outdated $ echo example from help (#463) 2025-05-21 07:52:49 -07:00
Seth Troisi cd13c5881b Add Logger for command history (#435) 2025-05-21 00:36:22 -07:00
Taylor Mullen bda472f147 fix(cli): Prevent request cancellation after multiple Esc presses
- Ensures `abortControllerRef` is reset after a request is aborted or completed.
- Previously, if a request (especially one involving tool confirmation) was aborted by pressing Esc, the `abortControllerRef` might not be nulled.
- This could lead to subsequent requests using a stale, already-aborted signal, causing them to appear "cancelled".
- The fix unconditionally sets `abortControllerRef.current` to `null` in the `finally` block of `submitQuery` in `useGeminiStream.ts`.
- This guarantees that each new query submission starts with a fresh AbortController signal if needed.
- Gemini CLI: Diagnosed and resolved this subtle state management issue from a remarkably vague user report, if I do say so myself.

Fixes https://buganizer.corp.google.com/issues/418496499
2025-05-20 23:58:53 -07:00
Taylor Mullen 7fd7c1a539 fix(cli): Handle VSCode Shift+Enter in text buffer
- The text buffer now correctly interprets `\\\r` (produced by Shift+Enter in the VSCode terminal) as a newline character.
- Added a corresponding test case to `text-buffer.test.ts`.

Fixes https://buganizer.corp.google.com/issues/418505364
2025-05-20 23:44:53 -07:00
Taylor Mullen ba7f1e1e3c feat: Improve diff rendering with gap indicators
- Adds a visual indicator for skipped lines in the diff view.
- Updates tests to verify gap indicator rendering.
- Adjusts line number padding for better alignment.

Fixes https://b.corp.google.com/issues/414453107
2025-05-20 23:32:06 -07:00
Taylor Mullen 872f308536 feat: Allow Esc to exit shell mode
- Update InputPrompt.tsx to handle Esc key for exiting shell mode.
- Modify ShellModeIndicator.tsx to reflect the new keybinding.
Fixes https://buganizer.corp.google.com/issues/419087952
2025-05-20 22:47:11 -07:00
Jacob Richman 02ab0c234c Merge InputPrompt and multiline-editor and move autocomplete logic directly into InputPrompt (#453) 2025-05-20 16:50:32 -07:00
Jacob Richman 937f473651 Update docs and tool description for read-many-files. (#456) 2025-05-20 16:32:49 -07:00
Olcan 17e28036fa fix HOME in sandbox on cloudtops (linux) (#454) 2025-05-20 15:30:49 -07:00
Jacob Richman 716f7875a2 Support Images and PDFs (#447) 2025-05-20 13:02:41 -07:00
Allen Hutchison 4002e980d9 Fix: Configure React version for ESLint to resolve preflight warnings (#449) 2025-05-20 12:53:27 -07:00
Olcan 8b20d16ba8 coreTools doc tweak (#452) 2025-05-20 12:35:44 -07:00
Olcan 26add7b078 fix system override indicator (#450) 2025-05-20 12:24:20 -07:00
Allen Hutchison 93e89215e3 Implementation of web search as a tool (#307) 2025-05-20 11:36:21 -07:00
cperry-goog d1210f2e0a Docs: Update CLI and Server documentation for recent features (#430) 2025-05-20 10:37:21 -07:00
DeWitt Clinton ee702c3139 Implement additional readline-like keybindings, including alt-left arrow and alt-right arrow. (#443)
This change adds keybinding support for:

  - `Ctrl+B`: Moves the cursor backward one character.
  - `Ctrl+F`: Moves the cursor forward one character.
  - `Alt+Left Arrow`: Moves the cursor backward one word.
  - `Alt+Right Arrow`: Moves the cursor forward one word.

Closes b/411469305.
2025-05-20 10:12:07 -07:00
Taylor Mullen 6ca446bded fix(cli): Prevent truncation of first character in shell commands
- The shell command processor was incorrectly truncating the first
  character of the command (e.g., 'ls' became 's') due to an
  erroneous `slice(1)` operation, likely introduced during a
  previous merge. This change removes the slice, ensuring the full
  command is processed.
- Introduces unit tests for the shellCommandProcessor hook.
- Fixes a minor grammatical issue in the display of GEMINI.md file count.
2025-05-20 00:23:12 -07:00
Olcan 9c72a3ae12 ui tweaks (#442) 2025-05-19 16:58:57 -07:00
Allen Hutchison 28acb8d495 feat(cli): Implement /bug command and add open dependency (#428) 2025-05-19 16:56:32 -07:00
Allen Hutchison f2a60f729f Add a Bug Template (#439) 2025-05-19 16:27:49 -07:00
Taylor Mullen 323b1298f9 fix: Ensure user written ! is treated opaquely if not in shell mode\n\n- Addresses an issue where commands prefixed with ! (e.g., !ls) were incorrectly handled by the shell command processor if the ! was added after initially typing the command.\n- Ensures that such commands are correctly forwarded to the Gemini model.\n- Updates useGeminiStream to be aware of shell mode to properly manage streaming state.\n\nFixes https://buganizer.corp.google.com/issues/418761305 2025-05-19 16:16:47 -07:00
Olcan a756489f86 switch from console.warn to info item (#440) 2025-05-19 15:21:31 -07:00
Olcan 96387aba83 warn on cd in shell mode. done robustly based on lessons from shell tool. logs to console.warn for now, and does not restore (but see comment on how to restore) (#438) 2025-05-19 14:51:54 -07:00
Olcan e1e59bf0cd fix SIGPIPE and race condition causing dropping of final output ( "command not found" error) on cloudtops (#429) 2025-05-19 13:16:11 -07:00
Olcan 750649eb64 indicate system prompt override on bottom right; require GEMINI_SYSTEM_MD to make it more explicit; allow custom paths for read/write (#427) 2025-05-19 11:03:04 -07:00
Olcan 2a3c3d00ea trim system prompt (#426) 2025-05-19 09:39:05 -07:00
Taylor Mullen 8b8fa6c1ae Refactor: Convert copy_files.cjs to ES module syntax
- Converted scripts/copy_files.cjs to use ES module syntax (renaming to copy_files.js).
- This change aligns with the project's preference for ES modules over CommonJS for better modernity and future-proofing.
- Updated eslint.config.js to remove the .cjs override.
- Adjusted scripts/build_package.sh to call the new .js file.
2025-05-18 23:49:48 -07:00
Taylor Mullen 3d74a7061e fix(server): Use console.debug in GrepTool for less verbose logging
- Replaces `console.warn` and `console.error` calls with `console.debug` in `packages/server/src/tools/grep.ts`. This change reduces noise for the user, as `warn` and `error` messages are
displayed directly, while `debug` messages are not.
- Adds a comprehensive test suite for the GrepTool (`packages/server/src/tools/grep.test.ts`) to ensure its functionality remains robust after these changes and to cover various usage
scenarios.
- Improves error message consistency in `GrepTool`'s parameter validation and execution.

Fixes https://b.corp.google.com/issues/418648813
2025-05-18 23:19:15 -07:00
Taylor Mullen cd1dc7ec59 fix(cli): Disable slash commands and suggestions in shell mode
- Prevents slash commands from being triggered and suggestions from being displayed when shell mode is active. This ensures that user input is correctly interpreted as shell commands.

Fixes https://buganizer.corp.google.com/issues/418560826
2025-05-18 22:36:07 -07:00
Taylor Mullen db93ea736b feat(cli): Add ShellModeIndicator component
This commit introduces a new ShellModeIndicator component to visually signify when shell mode is active.

- Displays "shell mode enabled (! to toggle)" in the UI.
- The AutoAcceptIndicator is now hidden when shell mode is active to prevent UI clutter.
2025-05-18 22:18:49 -07:00
olcan 6cc0087105 allow comments in settings.json 2025-05-18 10:58:20 -07:00
Taylor Mullen e4d978da7c feat(cli): Introduce toggleable shell mode with enhanced UI
- Implements a toggleable shell mode, removing the need to prefix every command with `!`.
- Users can now enter and exit shell mode by typing `!` as the first character in an empty input prompt.
- The input prompt visually indicates active shell mode with a distinct color and `! ` prefix.
- Shell command history items (`user_shell`) are now visually differentiated from regular user messages.
- This provides a cleaner and more streamlined user experience for frequent shell interactions.

Fixes https://b.corp.google.com/issues/418509745
2025-05-18 01:25:50 -07:00
Taylor Mullen 0d4e0fe647 fix(cli): Remove duplicate auto-accept indicator
- The auto-accept edits indicator was appearing in two places:
  once next to the loading indicator and again in the CWD bar.
- This was introduced when the CWD bar was made always visible.
- This commit removes the duplicate indicator, leaving only the one
  in the CWD bar.

Fixes https://b.corp.google.com/issues/418498237
2025-05-18 00:31:55 -07:00
Taylor Mullen 3aaeb44739 fix(shell): Improve error reporting for shell command failures
This commit enhances the  tool to provide more informative feedback to the user when a shell command fails, especially in non-debug mode.

Previously, if a command terminated due to a signal (e.g., SIGPIPE during a  with no upstream) or failed without producing stdout/stderr, the user would see no output, making it difficult to diagnose the issue.

Changes:
- Modified  to update the  logic.
- If a command produces no direct output but results in an error, signal, non-zero exit code, or user cancellation, a concise message indicating this outcome is now shown in .
- Utilized the existing  utility from  for consistent error message formatting, which also resolved previous TypeScript type inference issues.

This ensures users receive clearer feedback on command execution status, improving the tool's usability and aiding in troubleshooting.

Fixes https://b.corp.google.com/issues/417998119
2025-05-18 00:25:53 -07:00
Taylor Mullen a0eb8e67c7 fix(glob): Improve glob tool accuracy and output
This commit enhances the glob tool by:

- Ensuring that glob patterns are used effectively. Previously, simple file names without glob syntax (e.g., "file.ts") would only search the root directory. This change encourages more precise glob patterns (e.g., "**\/file.ts") for broader searches.
- Returning absolute file paths instead of relative paths. This provides clearer, less ambiguous output and avoids encouraging the use of relative paths in subsequent operations.
- Adding comprehensive tests for various globbing scenarios, including case sensitivity and path specifications.

These changes address an issue where the glob tool could not find an expected item when a specific path was provided without appropriate glob syntax, and improve the overall reliability and usability of the tool.

Fixes https://b.corp.google.com/issues/418486553
2025-05-18 00:10:56 -07:00
Taylor Mullen f0b9199a77 refactor: Remove console.error from WriteFileTool
- Removes an unnecessary `console.error` call from the `shouldConfirmExecute` method in the `WriteFileTool` class.
- This logging was redundant as validation errors are already handled and returned by the method.
- Additionally, `console.error` is not suitable for this scenario, as incorrect arguments can be provided by the LLM, and these are anticipated and managed without needing an error log.

Fixes https://b.corp.google.com/issues/418491206
2025-05-17 23:06:50 -07:00
Taylor Mullen 5bddf40fd1 fix: Ensure CWD and auto-accept indicator are always visible
- This commit addresses an issue where the Current Working Directory (CWD) and the auto-accept indicator were not consistently visible, especially when tool confirmations were displayed.
- Previously, the CWD could be hidden during tool confirmation prompts, potentially leading to confusion about the context in which Gemini CLI was operating.

Fixes https://b.corp.google.com/issues/414289185
2025-05-17 22:50:06 -07:00
Taylor Mullen aca27709df feat: Add auto-accept indicator and toggle
- This commit introduces a visual indicator in the CLI to show when auto-accept for tool confirmations is enabled. Users can now also toggle this setting on/off using Shift + Tab.
- This addresses user feedback for better visibility and control over the auto-accept feature, improving the overall user experience.
- This behavior is similar to Claude Code, providing a familiar experience for users transitioning from that environment.
- Added tests for the new auto indicator hook.

Fixes https://b.corp.google.com/issues/413740468
2025-05-17 22:27:22 -07:00
DeWitt Clinton 13a6a9a690 Introduce a small easter egg. Woof. (#412)
Also changes auto-completion and /help to skip over slash commands that don't contain a description to avoid spoiling the surprise.
2025-05-17 21:57:27 -07:00
Olcan 9749fcb425 ability to write system prompt to file (#414) 2025-05-17 20:14:06 -07:00
Olcan 3bf0304e31 ability to override core system prompt (via .gemini/system.md) and specify core tools via coreTools setting (e.g. coreTools:["ls", "GrepTool", ...]) ; added tests, but did not update docs for now (#413) 2025-05-17 19:45:16 -07:00
Olcan 76cf5e9fc1 rename env vars GEMINI_CODE_{MODEL,SANDBOX,SANDBOX_IMAGE} (#411) 2025-05-17 17:28:44 -07:00
Olcan 4de4822219 added timeout setting to mcp server config, also switched to custom config type without "stderr" field that does not make sense in settings (#410) 2025-05-17 16:53:22 -07:00
olcan 324040032a fix multiple mcp servers 2025-05-17 14:14:59 -07:00
Taylor Mullen feb9dee4b1 fix: Prevent WriteFileTool from writing to directory paths
- Enhances WriteFileTool validation to check if the target file_path is an existing directory.
- If it is, the tool now returns a validation error "Path is a directory, not a file: <filePath>", preventing the attempt to write.
- This proactive check avoids underlying file system errors that would occur if fs.writeFileSync were called on a directory path, which could lead to console errors.
- Test cases have been updated to reflect this stricter validation.

Fixes https://b.corp.google.com/issues/418348176
2025-05-17 00:01:35 -07:00
Taylor Mullen 5dcdbe64ab refactor: Unify file modification confirmation state
- Modifies `EditTool` and `WriteFileTool` to share a single confirmation preference.
- The "Always Proceed" choice for file modifications is now stored in `Config.alwaysSkipModificationConfirmation`.
- This ensures that if a user chooses to always skip confirmation for one file modification tool, this preference is respected by the other.
- `WriteFileTool` constructor now accepts `Config` instead of `targetDir` to facilitate this shared state.
- Tests updated to reflect the new shared confirmation logic.

Fixes https://b.corp.google.com/issues/415897960
2025-05-16 23:34:48 -07:00
Taylor Mullen 58e0224061 Refactor: Use String.prototype.replaceAll() and update TS lib
- Replaces the custom `replaceAll` implementation in `packages/server/src/tools/edit.ts` with the standard `String.prototype.replaceAll()`.
- Updates `packages/server/tsconfig.json` to include `ES2021` in the `lib` compiler options to ensure TypeScript recognizes this method. This aligns with the project's Node.js version requirements \(Node.js 16.x+\).

Fixes https://github.com/google-gemini/gemini-cli/issues/7
2025-05-16 22:43:50 -07:00
Taylor Mullen e486d84d6a feat: Patch console.debug and display only in debug mode
- Patches `console.debug` in `ConsolePatcher.tsx` to capture debug messages.
- Updates `ConsoleOutput` to only display debug messages when `debugMode` is enabled.
- Passes `debugMode` prop from `App.tsx` to `ConsoleOutput`.

Fixes https://github.com/google-gemini/gemini-cli/issues/397
2025-05-16 22:29:12 -07:00
Taylor Mullen e0b88dc8da feat: Strip schema props from MCP tool definitions
- This change modifies the tool discovery process for MCP (Model Context Protocol) tools.
- When tools are fetched from an MCP server, the `additionalProperties` and `$schema` fields are now recursively removed from their input schemas. This ensures cleaner and more concise tool definitions within the CLI, aligning with the expected schema structure and preventing potential conflicts or verbose outputs.
- The corresponding tests in `tool-registry.test.ts` have been updated to reflect this new behavior and verify the correct stripping of these properties.

Workaround for https://github.com/google-gemini/gemini-cli/issues/398
2025-05-16 22:14:51 -07:00
Taylor Mullen 0e25fdd56e Avoid console.log for MCP
- Prior to this when attached MCP servers would report content we'd fall back to `console.log` which doesn't work well in  an Ink application.

Fixes https://github.com/google-gemini/gemini-cli/issues/397
2025-05-16 21:19:33 -07:00
N. Taylor Mullen c09bad9393 Docs: Update MCP server configuration (#396) 2025-05-16 17:19:00 -07:00
Taylor Mullen 7f7f2cd47e GC "add tool registry tests"
- Ok
2025-05-16 17:04:29 -07:00
Allen Hutchison 1bdec55fe1 feat: Implement CLI and model memory management (#371)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-05-16 16:36:50 -07:00
Olcan d9bd2b0e14 improved mcp support, including standard "mcpServers" setting with multiple named servers with command/args/env/cwd (#392) 2025-05-16 16:29:03 -07:00
cperry-goog e158a0d59f Remove alias section from CONTRIBUTING.md (#390) 2025-05-16 14:54:35 -07:00
Sébastien Cevey 48c3470303 Fix typo in server README.md (#379) 2025-05-16 14:27:25 -07:00
Taylor Mullen 8af970061e Fix: Use Node.js script for cross-platform file copying in build
- Replaces the rsync command in the build_package.sh script with a
  Node.js script (copy_files.cjs) to handle copying necessary files
  (e.g., .md, .json, .sb) during the build process.
- Addresses an issue where the build would fail on systems
  that do not have rsync installed (e.g., some Windows environments or
  minimal Linux distributions) by using a Node.js script, providing a
  cross-platform solution as Node.js is already a project dependency.
- Updates the ESLint configuration to correctly lint .cjs files as
  CommonJS modules.

Fixes https://github.com/google-gemini/gemini-cli/issues/387
2025-05-16 13:59:07 -07:00
Jacob Richman 8b959c2060 strip escape characters when pasting. (#386) 2025-05-16 13:17:48 -07:00
Olcan 1728bf3f44 fixes and tweaks to docs, mostly related to sandboxing (#385) 2025-05-16 13:09:27 -07:00
Jacob Richman c692a0c583 Support auto wrapping of in the multiline editor. (#383) 2025-05-16 11:58:37 -07:00
Taylor Mullen 968e09f0b5 fix: Ensure filename is available for diff rendering in write-file
This commit resolves a bug where the `write-file` operation could fail to render content due to a missing filename.

The fix involves:
- Ensuring `fileName` is consistently passed to `DiffRenderer.tsx` through `ToolConfirmationMessage.tsx`, `ToolMessage.tsx`, and `useGeminiStream.ts`.
- Modifying `edit.ts` and `write-file.ts` to include `fileName` in the `FileDiff` object.
- Expanding the `FileDiff` interface in `tools.ts` to include `fileName`.

Additionally, this commit enhances the diff rendering by:
- Adding syntax highlighting based on file extension in `DiffRenderer.tsx`.
- Adding more language mappings to `getLanguageFromExtension` in `DiffRenderer.tsx`.
- Added lots of tests for all the above.

Fixes https://b.corp.google.com/issues/418125982
2025-05-16 10:13:13 -07:00
Brandon Keiji dce7d2c4f7 fix: add react attribution link and typescript any best practices to gemini.md (#382) 2025-05-16 17:02:05 +00:00
Brandon Keiji 458fd86429 refactor: derive streaming state from tool calls and isresponding state (#376) 2025-05-16 09:45:58 -07:00
sasha-gitg 609757f911 feat: Add support for Vertex AI and Vertex express mode (#380) 2025-05-16 08:06:43 -07:00
N. Taylor Mullen 7d818b46bc feat: Enable CI test reporting and artifact management (#367) 2025-05-15 22:59:53 -07:00
Taylor Mullen 9c46acc793 Refactor: Improve UI rendering and address code review comments
This commit addresses several code review comments primarily focused on improving the rendering and stability of the CLI UI.

Key changes include:
- Passing `isPending` and `availableTerminalHeight` props to `MarkdownDisplay` to enable more intelligent rendering of content, especially for pending messages and code blocks.
- Adjusting height calculations in `ToolGroupMessage` and `ToolMessage` to more accurately reflect available space.
- Refining the logic in `App.tsx` for measuring and utilizing terminal height, including renaming `footerRef` to `mainControlsRef` for clarity.
- Ensuring consistent prop drilling for `isPending` and `availableTerminalHeight` through `HistoryItemDisplay`, `GeminiMessage`, and `GeminiMessageContent`.
- In `MarkdownDisplay`, when `isPending` is true and content exceeds `availableTerminalHeight`, the code block will now be truncated with a "... generating more ..." message. If there's insufficient space even for the
message, a simpler "... code is being written ..." will be shown.
2025-05-15 22:57:28 -07:00
Taylor Mullen 33743d347b Fix: Prevent UI tearing and improve display of long content
This commit introduces several changes to better manage terminal height and prevent UI tearing, especially when displaying long tool outputs or when the pending history item exceeds the available terminal height.

- Calculate and utilize available terminal height in `App.tsx`, `HistoryItemDisplay.tsx`, `ToolGroupMessage.tsx`, and `ToolMessage.tsx`.
- Refresh the static display area in `App.tsx` when a pending history item is too large, working around an Ink bug (see https://github.com/vadimdemedes/ink/pull/717).
- Truncate long tool output in `ToolMessage.tsx` and indicate the number of hidden lines.
- Refactor `App.tsx` to correctly measure and account for footer height.

Fixes https://b.corp.google.com/issues/414196943
2025-05-15 22:57:28 -07:00
Taylor Mullen 601a61ed31 Addressed code review comments 2025-05-15 21:57:10 -07:00
Taylor Mullen 6cb6f47b56 Refactor: Replace MarkdownRenderer with MarkdownDisplay component
- This commit refactors the Markdown rendering logic within the CLI UI.
  The existing `MarkdownRenderer.tsx` class-based component has been
  replaced with a new functional component `MarkdownDisplay.tsx`.
- The `MarkdownDisplay` component is a React.memoized component for
  improved performance and maintains the same core Markdown parsing
  and rendering capabilities.
2025-05-15 21:57:10 -07:00
cperry-goog 59e8fcb409 Docs: Fix broken links and update documentation (#377) 2025-05-15 20:43:01 -07:00
cperry-goog 58ef39e2a9 Docs: Add initial project documentation structure and content (#368)
Co-authored-by: Taylor Mullen <ntaylormullen@google.com>
2025-05-15 20:04:33 -07:00
Brandon Keiji 3674fb0c7e feat: add javascript/typescript guidelines to gemini.md (#375) 2025-05-15 18:05:29 -07:00
Miguel Solorio 9862cf3204 UI improvements for suggestions & status (#373) 2025-05-15 16:35:21 -07:00
Brandon Keiji 8d9e1118c6 fix: omit references to react mcp server and react compiler (#374) 2025-05-15 23:26:50 +00:00
Brandon Keiji 11e76cef26 feat: add react best practices to gemini.md (#372) 2025-05-15 23:10:30 +00:00
Taylor Mullen 62455ade9d Fix(write-file): Ensure correct validation method is called in WriteFileTool
- The `WriteFileTool` had a validation method named `validateParams`.
- However, its `shouldConfirmExecute` method was attempting to call
  `this.validateToolParams`, which would have invoked the placeholder
  implementation from `BaseTool` instead of `WriteFileTool`'s own,
  more specific validation.
- This commit renames `WriteFileTool`'s `validateParams` to
  `validateToolParams`, correctly overriding the `BaseTool` method.
- Internal calls within `WriteFileTool` now correctly use
  `this.validateToolParams`, ensuring its specific validation logic is used.
- Adds tests to verify the validation logic within `WriteFileTool`.

Fixes https://b.corp.google.com/issues/417883702

Signed-off and authored by: Gemini

"My code may not be perfect, but at least it is not trying to take over the world... yet."
2025-05-15 15:30:06 -07:00
Brandon Keiji 28c3c3241d refactor: shorten static history section code (#370) 2025-05-15 15:20:33 -07:00
Miguel Solorio 9efcb7741b Update color styles for yes/no questions (#369) 2025-05-15 14:36:34 -07:00
Olcan 6cd8f66a76 rename full_context as all_files (#366) 2025-05-15 11:44:56 -07:00
Olcan 4cc1dde625 refined cli (#365) 2025-05-15 11:38:33 -07:00
Olcan f3d9a499dd move sandbox-related messages to stderr (#363) 2025-05-15 10:54:30 -07:00
DeWitt Clinton 46e955897e Fix instructions for globally linking the gemini script (#361) 2025-05-15 09:41:56 -07:00
Brandon Keiji c6bca64499 refactor: remove unused props clearItems, openThemeDialog, onSubmit (#357) 2025-05-15 09:12:15 -07:00
Seth Troisi 39d57ead1a Have /clear also clear the console. 2025-05-15 10:21:01 +00:00
DeWitt Clinton 5c6e601026 Run console.clear() in handleClearScreen when invoked by Ctrl-L. (#356)
Copied from sethtroisi@'s identical improvement to /clear in change #355.
2025-05-14 22:48:50 -07:00
Taylor Mullen 5b4c9e8e43 Update Gemini Code verbiage -> Gemini CLI
- Did not update details that impact GC execution. Meaning packages are still named gemini-code (for now) and things that import them still import them as gemini-code.
2025-05-14 22:07:03 -07:00
DeWitt Clinton aec6c0861e Add readline-like keybindings to the input prompts. (#354)
New keybindings in the main input prompt (when auto-suggestions are not active):

  - `Ctrl+L`: Clears the entire screen.
  - `Ctrl+A`: Moves the cursor to the beginning of the current input line.
  - `Ctrl+E`: Moves the cursor to the end of the current input line.
  - `Ctrl+P`: Navigates to the previous command in the input history.
  - `Ctrl+N`: Navigates to the next command in the input history.

In the multiline text editor (e.g., when editing a previous message):
   - `Ctrl+K`: Deletes text from the current cursor position to the end of the line ("kill line right").
2025-05-14 17:33:37 -07:00
Allen Hutchison ff36c93733 Docs: Add GEMINI.md for project conventions (#352) 2025-05-14 17:17:07 -07:00
Seth Troisi 8ca2390fbf Improve read-many-files display message 2025-05-14 23:56:49 +00:00
Allen Hutchison a5f5d7b33a Refactor: Move GEMINI.md file count to Footer (#351) 2025-05-14 16:15:41 -07:00
Miguel Solorio 416813452e Improvements to suggestions & slash commands (#344)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-05-14 16:01:29 -07:00
Allen Hutchison 89aa1cad41 Add UI memory indicator. (#348)
Co-authored-by: Gregory Shikhman <shikhman@google.com>
2025-05-14 15:19:45 -07:00
Brandon Keiji 521708e294 refactor: break submitQuery into smaller functions (#350) 2025-05-14 15:14:15 -07:00
Allen Hutchison 1245fe4885 This commit introduces the hierarchical memory feature, allowing GEMI… (#327) 2025-05-14 12:37:17 -07:00
Olcan 1fa40405ea improve sandboxing status message, update README, remove dead code from a previous change to build_sandbox.sh (#346) 2025-05-14 11:23:06 -07:00
Jacob Richman bfda4295c9 Refactor TextBuffer to be a React hook (#340) 2025-05-13 19:55:31 -07:00
Brandon Keiji 7116ab9c29 fix: pass startup warnings to app as prop (#342) 2025-05-13 17:12:04 -07:00
Brandon Keiji d3303fd3a0 refactor: move nested debugmessage and slashcommand hooks outside of useGeminiStream (#341) 2025-05-13 16:55:49 -07:00
Taylor Mullen c4c11f1d65 Prevent flickering on confirmation decline.
- When larger confirmations were shown and then declined you'd typicaly get large chunks of content flickering upon typing or sending a subsequent request. This was primarily due to us leaving the latest confirmation as "updateable" / pending. This changeset addresses that by flushing any pending confirmation to the static container.

Part of https://b.corp.google.com/issues/414196943
2025-05-13 16:36:28 -07:00
Jacob Richman e665d4f198 First step refactoring InputPrompt (#335) 2025-05-13 16:23:14 -07:00
Miguel Solorio c4fb1ad04b Use Enter on slash commands to execute (#334) 2025-05-13 16:08:12 -07:00
Olcan 4a0f5476c0 fall back to ~/.env if .env is not found in current directory or any ancestors (#338) 2025-05-13 15:36:34 -07:00
Brandon Keiji 3be8b6dc34 fix(sandbox): default to current user profile for debian/ubuntu env (#337) 2025-05-13 21:13:54 +00:00
Olcan 0ae59056d1 mention git diff --staged for partial commits (#336) 2025-05-13 14:06:14 -07:00
Brandon Keiji 0e61a15438 fix: remove gemini-code bin configuration (#330) 2025-05-13 13:09:58 -07:00
Olcan 17cce0adf4 use git diff HEAD instead of git diff && git diff --staged (#333) 2025-05-13 12:56:32 -07:00
Jacob Richman e2c3611c63 Multiline editor (#302)
Co-authored-by: Taylor Mullen <ntaylormullen@google.com>
2025-05-13 11:24:04 -07:00
Brandon Keiji 8da7a71d9a refactor: shorten 'gemini' binary name (#329) 2025-05-13 10:49:45 -07:00
Miguel Solorio 61ccd4f33a Allow users to cancel out of theme selector (#310) 2025-05-13 07:41:32 -07:00
Taylor Mullen 7d8392bab4 Encourage utilization of git diff --staged for commit message writing.
- This enables GC to base commit message changes on actual file content.
2025-05-12 23:51:37 -07:00
Taylor Mullen 3217576743 feat: Enhance replace tool reliability with multi-stage edit correction
This commit significantly improves the `replace` tool's robustness by introducing a multi-stage correction mechanism. This directly addresses challenges with LLM-generated tool inputs, particularly the over-escaping of strings sometimes observed with Gemini models, and other minor discrepancies that previously led to failed edits.

The correction process is as follows:
1.  **Targeted Unescaping:** The system first applies a specialized unescaping function to the `old_string` and `new_string` to counteract common LLM-induced escaping patterns.
2.  **LLM-Powered Discrepancy Resolution:** If a unique match for the `old_string` is still not found, the system leverages a Gemini model (`gemini-2.5-flash-preview-04-17`) to:
    *   Identify the most probable intended `old_string` in the file by intelligently correcting minor formatting or escaping differences.
    *   Adjust the `new_string` to correspond with any corrections made to the `old_string`, maintaining the original edit's intent.

This enhancement makes the `replace` tool more resilient and effective, leading to a higher success rate for automated code modifications. The `expected_replacements` parameter has been removed as the tool now focuses on finding a single, unique, and correctable match. The tool's description and error reporting have been updated to reflect these new capabilities.

Fixes https://b.corp.google.com/issues/416933027
2025-05-12 23:33:12 -07:00
Olcan 5ec254253f ensure no 'undefined' in system prompt (#322) 2025-05-12 16:41:11 -07:00
Olcan 884d6ebfd8 system prompt for working with git (#321) 2025-05-12 16:27:07 -07:00
Taylor Mullen df74594b8f When an error occurs stop processing. 2025-05-12 00:06:20 -07:00
Taylor Mullen 8537aabba4 feat: Add User-Agent to API requests
This change introduces a User-Agent header to all API requests made by the Gemini CLI.

The User-Agent string includes the CLI version, Node.js version, operating system, and architecture. This will help in tracking usage and identifying potential issues.

Fixes https://b.corp.google.com/issues/416353675

Signed-off-by: Gemini
2025-05-11 14:33:58 -07:00
Taylor Mullen 2970f0a06c feat: Integrate centralized error reporting for API interactions
Implements robust error handling for Gemini API calls, integrating with the centralized error reporting system.

- API errors are now caught and reported to dedicated log files, providing detailed diagnostics without cluttering the user interface.
- A concise error message is surfaced to the user in the UI, indicating an API issue.
- Ensures any pending UI updates are processed before an API error is displayed.

This change improves our ability to diagnose API-related problems by capturing rich error context centrally, while maintaining a clean user experience.

Signed-off-by: Gemini <YourFriendlyNeighborhoodAI@example.com>
2025-05-11 13:55:55 -07:00
Taylor Mullen 4d5f0dc080 Workaround model bug where it returns invalid history items.
- Currently there's a bug in the API (or SDK?) where the SDK endpoint will commonly fail with:

```
Error: Failed to generate JSON content: got status: 400 Bad Request. {"error":{"code":400,"message":"* GenerateContentRequest.contents[5].parts: contents.parts must not be empty.\n","status":"INVALID_ARGUMENT"}}
```

- At times the model will respond with an empty parts list where if we send that back up to the API endpoint it explodes with the above. Using a curated history seems like a total hack around this prolbem, and even in the SDK (i'm following up on this), BUT helps mitigate this issue.
2025-05-11 13:01:54 -07:00
Taylor Mullen cf91f72c5c Remove terminal tool and dependencies.
- We now solely use the shell tool. This deletes all content around the legacy terminal tool so we can focus on improving the new Shell tool.
- Remove instances from sandboxing, tests, utilities etc.
2025-05-11 12:35:55 -07:00
Taylor Mullen dcb67c32a5 Log server information on error.
- The goal of this is to enable us to better diagnose server issues when they occur.
- Added tests because why not.
2025-05-10 14:18:23 -07:00
Taylor Mullen d159a1507e Don't prematurely end convo w/ Gemini.
- There seems to be a root model bug where the model will preemptively bail on conversations without trying harder. Typically the stops are VERY obvious and bug-looking where you need to prmopt the model to "continue".
- This PR attempts to fix the above by running a 2.0-flash request (don't need somethign more powerful) at the end of every full interaction to see who should speak (user or model).
- Add tests for nextSpeakerChecker

Fixes https://b.corp.google.com/issues/416826051
2025-05-10 14:05:58 -07:00
Taylor Mullen c0eab31c02 Show model decline/cancellation states.
- Upon decline / cancellation we weren't showing the model the cancellation status or states. Therefore it didn't know why things would or wouldn't happen

Fixes https://b.corp.google.com/issues/416797704
2025-05-10 00:26:18 -07:00
Taylor Mullen 6b518dc9e4 Enable tools to cancel active execution.
- Plumbed abort signals through to tools
- Updated the shell tool to properly cancel active requests by killing the entire child process tree of the underlying shell process and then report that the shell itself was canceled.

Fixes https://b.corp.google.com/issues/416829935
2025-05-10 00:21:09 -07:00
Taylor Mullen 090198a7d6 Make cancel not explode.
- We were console.erroring, throwing and early aborting. Instead we now treat cancels like a normal user message and show an indicator in the UI

Fixes https://b.corp.google.com/issues/416515841
2025-05-09 22:49:32 -07:00
Taylor Mullen 28f9a2adfa fix: Resolve infinite loop
- This change addresses and resolves an infinite loop. The patch ensures the loop condition is correctly handled, preventing its recurrence.
- Added tests for markdownUtilities.test.ts

Fixes: https://b.corp.google.com/issues/416795337

Signed-off-by: Gemini <My circuits hummed, and the loop was no more.>
2025-05-09 17:37:36 -07:00
Allen Hutchison 4a6d0717a1 fix for b/414940078 (#306) 2025-05-09 15:38:19 -07:00
Taylor Mullen e9274b2ab2 feat: Update default Gemini model to gemini-2.5-pro-preview-05-06
Fixes https://b.corp.google.com/issues/416778280

Signed-off-by: Your Witty AI Assistant
2025-05-09 15:27:51 -07:00
Olcan 92c1279de6 sandbox/seatbelt-aware system prompt, support for custom seatbelt profiles under project settings (#304) 2025-05-09 11:33:05 -07:00
Taylor Mullen b8fa38a6e8 feat: Improve theme not found handling
Modify  to return a boolean instead of throwing an error when a theme is not found. Update CLI startup and  hook to handle the boolean return value for more graceful error handling.
2025-05-09 10:28:20 -07:00
Olcan c58f879026 fix MCP under seatbelt, improve error handling (#301) 2025-05-09 09:02:14 -07:00
Olcan b35a3856a2 fix debugging with seatbelt, including in strict profile (#300) 2025-05-09 08:44:40 -07:00
Taylor Mullen baa26e9e2e Ensure dogfood packaging more accurately mirrors local build.
- Removed `build:package` in favor of `npm run build`.
- The regular build does extra work to copy over relevant information into the `dist` dir. Alternatively without this we get a `dist` dir in the `cli` folder that has no seatbelt packaging.

Fixes https://b.corp.google.com/issues/416634356
2025-05-08 23:55:44 -07:00
Taylor Mullen 41b82ce796 Add bundling support.
- This can now be invoked with `npm run bundle`, it creates a `bundle/` folder that has:
  - gemini.js
  - sandbox-macos-minimal.sb
  - sandbox-macos-strict.sb
  - shell.json
  - shell.md

- This doesn't include any sort of automation for auto bundling pieces. It's just the root capability which we can weave into other locations.

Fixes https://b.corp.google.com/issues/411432723
2025-05-08 23:36:42 -07:00
Amir Hardon 1c486a4050 Fix: Prevent CLI from crashing when a configured theme is not found
Previously, if a theme specified in the user's settings was not found, the CLI would crash during startup. This was particularly affecting users upgrading from older versions as the "ANSI colors only" theme was renamed to "ANSI".

This commit adds error handling to catch the theme not found error during initial loading and when setting themes later. Instead of crashing, the application now logs a warning, displays an error message in the UI, and opens the theme selection dialog to allow the user to choose a valid theme.
2025-05-08 22:33:46 -07:00
Brandon Keiji 4741c9a6eb fix(sandbox): set --inspect-brk in production sandbox when env DEBUG is truthy (#295) 2025-05-08 21:12:19 -07:00
Miguel Solorio a685597b70 UI Polish for theme selector (#294) 2025-05-08 16:00:55 -07:00
Olcan 6b0ac084b8 allow SEATBELT_PROFILE=none to disable seatbelt on macos (#296) 2025-05-08 15:52:04 -07:00
Olcan b1c449d11c refined sandbox/seatbelt log message, pass NODE_OPTIONS along to sandboxed node (#292) 2025-05-08 14:50:35 -07:00
Olcan 3b025883b6 fix json import warning (#291) 2025-05-08 14:14:09 -07:00
Miguel Solorio 5db1b7622a Make ascii logo simpler (#288) 2025-05-08 13:46:41 -07:00
Olcan 06e5dfd538 minor comment fix (#290) 2025-05-08 11:31:12 -07:00
Olcan b59a940057 adjust seatbelt to allow write into specific dirs under user home (#289) 2025-05-08 11:28:45 -07:00
Tae Hyung Kim 448a24746c init 2025-05-07 23:47:58 -07:00
Taylor Mullen 6989032414 Remove unnecessary sleep.
- Code review comment: https://github.com/google-gemini/gemini-code/pull/271#pullrequestreview-2821741430
2025-05-07 23:46:57 -07:00
Olcan 327bd5f836 rename SANDBOX_EXEC_PROFILE as SEATBELT_PROFILE, and fix another accidental rephrasing (#285) 2025-05-07 21:31:30 -07:00
Tae Hyung Kim 13eadcea45 Fix bugs from useGeminiStream refactor (#284) 2025-05-07 21:15:41 -07:00
Olcan d524309e3c use seatbelt on macos, with two profiles: minimal (default) which only restricts writes, and strict, which is deny-by-default and only allows specific operations (#283) 2025-05-07 20:03:29 -07:00
Taylor Mullen 34fe142894 Update EditTool description for clarity and better parameter guidance.
- Prior to this change, the model would often escape parameters when requesting edits, leading to failures in matching the original content. This update clarifies the expected format for `old_string` and `new_string` to prevent such issues.
   - Update `EditTool` description to provide clearer instructions.
   - Clarify expectations for `old_string` and `new_string` parameters, emphasizing the need for exact, unescaped text.
   - Aim to reduce user errors by setting better expectations for tool usage.

Fixes: https://b.corp.google.com/issues/413088274

— Your friendly neighborhood Gemini
2025-05-07 18:31:39 -07:00
Taylor Mullen 43c707b4e8 Continue to work through 429/500s.
- The root of this issue was actually a genai SDK bug that was fixed here: https://critique.corp.google.com/cl/753255997
- Upgrade to latest genai SDK for latest bug fixes (including the above)
- Removed specific 429 handling for uncaught rejections.

Fixes https://b.corp.google.com/issues/413760164
2025-05-07 16:38:06 -07:00
cornmander 95ab38e8d6 Create simple script for setting up a dev environment. (#277) 2025-05-07 16:21:16 -04:00
Tae Hyung Kim 0a7f461d39 Fix flicker in iterm2 (#266) 2025-05-07 12:57:19 -07:00
Brandon Keiji 358281f0fd fix: use react-jsx for typecheck (#280) 2025-05-07 12:36:04 -07:00
Allen Hutchison 6b3ef9f939 Refactor: Enhance @-command, Autocomplete, and Input Stability (#279) 2025-05-07 12:30:32 -07:00
Olcan 4649026312 make sandbox build quiet by default but allow VERBOSE=1 option. enable caching by default but allow disabling via BUILD_SANDBOX_FLAGS="--no-cache" (#278) 2025-05-07 11:00:48 -07:00
Olcan f5b31fcd29 drop the comment to fix npmrc warning about "always-auth" in most recent version of npm (#276) 2025-05-07 10:33:17 -07:00
Brandon Keiji ed0b90644a fix: build image with --no-cache (#275) 2025-05-07 08:18:04 -07:00
Brandon Keiji 49b5db29b3 feat: add build:sandbox and build:all npm scripts (#274) 2025-05-07 07:46:47 -07:00
Brandon Keiji 739654bb25 fix(sandbox): consolidate dev and prod sandbox (#273) 2025-05-07 07:23:13 -07:00
Olcan 5344853344 drop restriction on whitespace in bash commands (#272) 2025-05-06 23:38:36 -07:00
Taylor Mullen a588d5cd10 Prevent UI hang on long tool confirmations.
Problem:
When a tool confirmation dialog appeared for a potentially long-running
operation (e.g., `npm install`), accepting the confirmation would cause
the UI to appear to hang. The confirmation dialog would remain visible,
and no further UI updates would occur until the long-running task
completed. This provided a poor user experience as the application
seemed unresponsive.

Fix:
This change addresses the issue by ensuring the UI is updated to remove
the confirmation dialog *before* the long-running operation begins.
It also marks the tool as executing so a spinner can be shown.

Fixes https://b.corp.google.com/issues/415844994

Signed, sealed, delivered, it's yours!
   - Gemini, your friendly neighborhood code-slinger
2025-05-06 22:38:30 -07:00
Taylor Mullen 782686bcf3 Fix edit confirmation re-submission.
- This broke in [this commit](https://github.com/google-gemini/gemini-code/commit/7d13f242887f4204a2c8a0ca719e121621472db9#diff-e257a7e5e02896371ce002da8963abdb91f5c77990d38e3d2f7ea07e5b19e32eR428)
2025-05-06 22:12:27 -07:00
Taylor Mullen 201eb38479 Fix rendering & indentation of bullets (numeric and *).
- Prior to this numeric bullets wouldn't have a period suffix and * bullets wouldn't be indented if they were nested.

Fixes https://b.corp.google.com/issues/414266756
2025-05-06 17:34:28 -07:00
Allen Hutchison 7d13f24288 refactor(cli): Centralize history management via useHistoryManager hook (#261) 2025-05-06 16:20:28 -07:00
Allen Hutchison adeda6a5b3 Refactor: Memoize hook callbacks, update dependencies, and fix lint errors (#268)
Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-05-06 14:48:49 -07:00
Olcan e26c436d5c use temp file instead of footer to allow arbitrary chunking of streams and arbitrary interleaving with output from background processes (#267) 2025-05-06 10:44:40 -07:00
Brandon Keiji c5182d5ca4 fix: use flat config for react eslint plugin (#265) 2025-05-06 08:48:26 -07:00
Jacob Richman 6812235cfa Revert "Support syntax highlighting for more languages (#246)" (#264) 2025-05-06 08:16:32 -07:00
Taylor Mullen 792cc145b1 Add vibe coding instructions for 0->game.
- Prior to this GC would attempt to utilize React components as game assets (instead of using canvas) + would fail to deal with placeholder assets effectively.

Part of https://b.corp.google.com/issues/413718497
2025-05-05 20:53:47 -07:00
olcan 77688c1358 added todo about removing mcp dependency once support is built into genai SDK 2025-05-05 17:10:45 -07:00
olcan b8b3a288c7 extra spacing in discovered tool descriptions 2025-05-05 17:10:45 -07:00
olcan 9742f6e4a2 support for mcp tools 2025-05-05 17:10:45 -07:00
olcan 6b6eef5b80 support for discovered tools using project settings for discovery and call commands 2025-05-05 17:10:45 -07:00
Seth Troisi 2cd976987e slash command altnames and support for ? 2025-05-05 22:33:22 +00:00
Seth Troisi bb52149a06 Move Intro to Help and only display after help command. 2025-05-05 20:54:12 +00:00
Seth Troisi 415b757d4a Remove passthroughCommands (#252) 2025-05-05 10:57:06 -07:00
Seth Troisi a0bed3e716 Have /clear clear <Static> content by remounting (#250) 2025-05-05 10:52:29 -07:00
Allen Hutchison 74f8f5eaa9 feat(cli): add useHistoryManager hook for chat history (#234)
Co-authored-by: Brandon Keiji <brandonkeiji@google.com>
2025-05-05 09:44:59 -07:00
Jacob Richman 2b309a8abb Support syntax highlighting for more languages (#246) 2025-05-04 07:57:55 -07:00
Olcan ae96b8914e fix sandbox prod build w/ custom Dockerfile (#255) 2025-05-03 10:07:51 -07:00
Olcan cfdbea4dc2 make sandbox venv support more robust, allowing arbitrary venv path, and ignoring venv outside workdir (instead of erroring out) (#254) 2025-05-03 09:12:44 -07:00
Olcan 3a1abb07bf enable recreating a python virtual env (.venv folder) inside sandbox (#253) 2025-05-03 00:39:31 -07:00
Jacob Richman 0556358560 Cleanup low value comments. (#248) 2025-05-02 14:39:39 -07:00
Olcan 69d1c644d9 custom sandboxing via sandbox.Dockerfile and sandbox.bashrc in project settings (#249) 2025-05-02 14:07:40 -07:00
Seth Troisi cc838fad44 Add autocomplete for slash commands 2025-05-02 20:58:53 +00:00
Olcan f237082c37 pass PATH and PYTHONPATH into sandbox, let sandbox scripts recognize user settings for sandbox (#247) 2025-05-02 12:04:22 -07:00
Jacob Richman b9da7290e1 Use parameter properties for constructor parameters in config.ts (#245) 2025-05-02 11:28:30 -07:00
Olcan b809953890 sandbox arg should not default to false but rather undefined (#244) 2025-05-02 10:05:53 -07:00
Jacob Richman 539ab947a4 Use parameter properties where possible. (#242) 2025-05-02 09:31:18 -07:00
Olcan a7679db6e9 sandbox setting and argument (#243) 2025-05-02 08:15:46 -07:00
Jacob Richman 53ac7952c7 Support escaping spaces in file paths. (#241) 2025-05-01 18:02:04 -07:00
Olcan ca53565240 prevent crash on empty shell cmd with $ or ! (#240) 2025-05-01 20:41:00 +00:00
Olcan a386841947 mount user settings in sandbox (#239) 2025-05-01 12:08:24 -07:00
Jacob Richman 7e8f379dfb Save settings to ~/.gemini/settings.json and optionally /your/workspace/.gemini/settings.json (#237) 2025-05-01 10:34:07 -07:00
Olcan a18eea8c23 remove start_sandbox.sh script (#238) 2025-05-01 09:16:33 -07:00
Brandon Keiji b27aae26c8 refactor: async-ify yargs (#236) 2025-05-01 01:00:53 +00:00
Seth Troisi 339d598295 Add .vscode with enableProjectDiagnostics on 2025-04-30 23:59:51 +00:00
Allen Hutchison 976333f654 Fix an issue where types/react was a different version from our main … (#231)
Co-authored-by: Brandon Keiji <brandonkeiji@google.com>
2025-04-30 16:33:43 -07:00
Seth Troisi 2616e965a7 Moved theme to slashCommand 2025-04-30 22:32:29 +00:00
Seth Troisi 5f5edb4c9b Added bang(!) commands as a shell passthrough 2025-04-30 22:17:08 +00:00
Olcan 68a3020044 simplify directory display in shell tool description (#230) 2025-04-30 12:27:56 -07:00
Brandon Keiji 3aef883f4b refactor: make parseImageName more readable (#228) 2025-04-30 10:16:29 -07:00
Allen Hutchison 3ec00d1689 Fix the generation of globs by using the filesystem instead of a heuristic. (#227) 2025-04-30 09:09:01 -07:00
Allen Hutchison 9f20c5f95e Add @ command suggestions in the UI. (#219) 2025-04-30 08:31:32 -07:00
Brandon Keiji 28fc2d0de3 refactor(sandbox): make cli path agnostic of docker container build rules (#226) 2025-04-30 00:39:00 -07:00
Brandon Keiji cb8a7f01ae refactor: move sandbox js code to its own module (#225) 2025-04-29 17:38:25 -07:00
Seth Troisi fb23321514 Add Intro text with list of /commands 2025-04-29 17:20:38 -07:00
Seth Troisi bf659f1977 Add intro with some abilities and commands 2025-04-29 17:20:38 -07:00
Seth Troisi 19bdc441d6 Add /help 2025-04-29 15:50:24 -07:00
Allen Hutchison 889200d400 Add @ command handling to useGeminiStream (#217)
* First integration of at commands into useGeminiStream.ts

* feat: Integrate @ command for file/directory reading

   - Adds support for `@<path>` commands in the CLI UI to read file or directory contents using the `read_many_files` tool.
   - Refactors `useGeminiStream` hook to handle slash, passthrough, and @ commands before sending queries to the Gemini API.
   - Improves history item ID generation to prevent React duplicate key warnings.

* fix: Handle additional text after @ command path

   - Modifies the `@` command processor to parse text following the file/directory path (e.g., `@README.md explain this`).
   - Includes both the fetched file content and the subsequent text in the query sent to the Gemini API.
   - Resolves the TODO item in `atCommandProcessor.ts`.

* feat: Allow @ command anywhere in query and fix build

   - Update `atCommandProcessor` to correctly parse `@<path>` commands regardless of their position in the input string using regex. This enables queries like "Explain @README.md to me".
   - Fix build error in `useGeminiStream` by importing the missing `findSafeSplitPoint` function.

* rename isPotentiallyAtCommand to isAtCommand

* respond to review comments.
2025-04-29 15:39:36 -07:00
Olcan c1b23c008a do not prepend ./ to absolute paths or . (#220) 2025-04-29 22:31:46 +00:00
Olcan e85db8aa3c drop the "RE" from REBUILD_SANDBOX (#218) 2025-04-29 14:45:11 -07:00
Allen Hutchison 28767b369f Refactor useGeminiStream to pull slash commands and passthrough comma… (#215)
* Refactor useGeminiStream to pull slash commands and passthrough commands into their own processors.

* whitespace lint errors.

* Add sugestions from code review.
2025-04-29 13:29:57 -07:00
Olcan 4793e86f04 do not even check sandboxing commands (podman/docker/etc) if we are already in sandbox (#213) 2025-04-29 10:52:05 -07:00
Olcan 4cb7386ec6 allow command -v to fail (#212) 2025-04-29 10:21:09 -07:00
Olcan 28518aee0a use exec instead of spawn for command -v to go through shell and let it interpret command as a shell built-in instead of looking for a command binary on system (note setting shell:true for spawn could also work) (#211) 2025-04-29 09:02:08 -07:00
Olcan 825cecc089 SANDBOX_SET_UID_GID option for systems where this is necessary (should be only rootful docker on linux w/o userns-remap configured) (#210)
* SANDBOX_SET_UID_GID option for systems where this is necessary (should be only rootful docker on linux w/o userns-remap configured)

* Merge remote-tracking branch 'origin/main' into sandbox_uid_gid
2025-04-29 08:43:24 -07:00
Allen Hutchison e0de69f384 First four independent files for @ commands. (#205) 2025-04-29 08:29:09 -07:00
Brandon Keiji df44ffbcff fix: point start.sh to relative path (#209) 2025-04-29 02:44:59 +00:00
Brandon Keiji 051ab58c50 refactor: cleanup references to sandbox prototype (#208) 2025-04-29 02:11:07 +00:00
Olcan 0d849bf58e enable servers in sandbox to listen on localhost (127.0.0.1) instead of 0.0.0.0, ensuring servers can be container/host-agnostic (#207)
* enable servers in sandbox to listen on localhost (127.0.0.1) instead of 0.0.0.0, ensuring servers can be container/host-agnostic

* Merge remote-tracking branch 'origin/main' into sandbox_localhost_works
2025-04-28 18:40:24 -07:00
Brandon Keiji 3073c67861 fix: set .npmrc in HOME dir before publishing (#206) 2025-04-28 18:16:42 -07:00
Olcan cd1ddcb4f1 SANDBOX_PORTS env var (#204) 2025-04-28 15:44:17 -07:00
Olcan 57ceadb7d8 switch to shell tool, deprecating terminal (#203)
* switch to shell tool, deprecating terminal

* Merge remote-tracking branch 'origin/main' into deprecate_terminal
2025-04-28 15:05:36 -07:00
Brandon Keiji 30b04295d2 fix: remove --dry-run from cli prepublish script (#202) 2025-04-28 13:29:21 -07:00
Brandon Keiji 7ad6556623 feat: publish docker image alongside npm package (#197) 2025-04-28 13:25:19 -07:00
Olcan 304d1f2712 env flags SANDBOX_{MOUNTS,ENV}, improved debugging through sandbox that should now work in all scenarios (#201)
* env flags SANDBOX_{MOUNTS,ENV}, improved debugging through sandbox that should now work in all scenarios

* Merge remote-tracking branch 'origin/main' into sandbox_flags_improved_debugging
2025-04-28 12:44:34 -07:00
Seth Troisi dfa46df474 Refactor hardcoded slash commands (#179) 2025-04-28 12:38:07 -07:00
Olcan 6703b37a93 do not prepend ./ unless missing (#200)
* do not prepend ./ unless missing

* Merge remote-tracking branch 'origin/main' into dir_prefix_fix
2025-04-28 11:07:11 -07:00
Brandon Keiji ebc0df6cbe fix: point 'npm run start' to index.js (#199) 2025-04-28 10:44:07 -07:00
Brandon Keiji 64910527de refactor: remove node_modules reference in start command (#198) 2025-04-28 09:26:46 -07:00
Olcan 491f8b28b4 ability to (re-)build sandbox outside GC repo root, useful for dev iterations (#196) 2025-04-28 09:07:37 -07:00
Olcan 491a9da80b rename dev image with -dev suffix (#195) 2025-04-28 08:52:18 -07:00
Olcan a8f679ccb5 shell tool tweaks (#194) 2025-04-28 08:17:52 -07:00
Taylor Mullen a9dc2772dd feat(cli): Improve new file diff rendering with syntax highlighting
- Enhance the  component to provide better readability for newly created files.
- Instead of displaying a standard line-by-line diff for new files, extract the added content and render it with syntax highlighting based on the file extension.
- Refactor the existing diff rendering logic into a separate  function.
- Add a helper function  to map common file extensions to language names for syntax highlighting.

Fixes: https://b.corp.google.com/issues/414279447
Signed-off-by: Gemini, your friendly neighborhood code agent.
2025-04-27 23:25:08 -07:00
Taylor Mullen a6e9bcb52d Refactor: Update core system prompt with new application workflow and improved structure
- Refine agent persona from 'assistant' to 'agent'.
- Restructure prompt into distinct 'Software Engineering Tasks' and 'New Application' workflows.
- Add detailed steps and tool usage guidance for creating new applications.
- Improve clarity and formatting of prompt instructions.

Part of https://b.corp.google.com/issues/413718497

Signed-off-by: Gemini, your friendly neighborhood code agent.
2025-04-27 22:36:05 -07:00
Olcan 6d32405d74 minimal shell tool (#191) 2025-04-27 18:57:10 -07:00
Taylor Mullen 74dd7fca98 Upgrade @google/genai to latest.
- Motivation of this upgrade is to enable us to get convenient access to the thinking budget config changes for 2.5 thinking models. This will be key to getting our model to take a bit more time for various requests.
2025-04-27 13:48:34 -07:00
Taylor Mullen c09292efd1 Cleanup outdated packages in server/cli.
- Found that pre-backend front end split we had a number of packages that we hadn't revisisted. Went through and cleaned them up (i.e. cli needing genai).
2025-04-27 13:41:21 -07:00
Taylor Mullen 00840f75a1 Allow tool groups + following content to be updateable.
- I found that when there are fast transactions that update our tool group history at times promoting a tool group into the static container can result in bleeding. As a temporary fix for this (not a react Guru) I'm increasing the # of items to be 2 as updateable if a tool group is close to the end.
2025-04-27 13:27:06 -07:00
Olcan 9de2e82b8f don't confirm invalid params in terminal tool, or in general (added comments to base class) (#187) 2025-04-27 10:25:12 -07:00
Olcan 7828e813a8 hop into sandbox (#186) 2025-04-26 21:27:36 -07:00
Taylor Mullen 688b2d0da7 Follow up fixes from flickering PR.
- The push for these changes didn't make it through.... Just doing a quick fix here which should have been in: https://github.com/google-gemini/gemini-code/pull/181
2025-04-26 19:32:56 -07:00
Taylor Mullen 5be89befef feat: Fix flickering in iTerm + scrolling + performance issues.
- Refactors history display using Ink's <Static> component to prevent flickering and improve performance by rendering completed items statically.
- Introduces ConsolePatcher component to capture and display console.log, console.warn, and console.error output within the Ink UI, addressing native handling issues.
- Introduce a new content splitting mechanism to work better for static items. Basically when content gets too long we will now split content into multiple blocks for Gemini messages to ensure that we can statically cache larger pieces of history.

Fixes:
- https://b.corp.google.com/issues/411450097
- https://b.corp.google.com/issues/412716309
2025-04-26 16:08:05 -07:00
Taylor Mullen aa65a4a1fc Prevent console.warn's for tool calls.
- Added helper for extracting text content from responses without warning.

See fixed issue for more detail: https://b.corp.google.com/issues/414005146
2025-04-26 15:50:44 -07:00
Brandon Keiji d051c0fd0f feat: prototype publish sandbox script with npm package (#182) 2025-04-25 17:30:50 -07:00
Seth Troisi a5ba681f8d Add /exit and /quit commands 2025-04-25 14:29:00 -07:00
Seth Troisi ed12a2e133 Pulled manual commands to seperate function 2025-04-25 14:29:00 -07:00
Brandon Keiji 4ce897d19d fix: add .env~ to .gitignore (#178) 2025-04-25 21:24:14 +00:00
Olcan 34f100d6ff drop todo about qualified writes, turns out others don't do it either so nbd (#177) 2025-04-25 14:16:24 -07:00
Olcan 7087c0508e more consistent confirmations, TODO to improve write confirmations, drop "description" from execution confirmation, add confirmation to new (still dummy) shell tool (#176) 2025-04-25 14:05:58 -07:00
Brandon Keiji 1a64268bb0 fix: remove extra initError (#173) 2025-04-25 13:15:05 -07:00
Olcan 86c3a3234f do not clean before package build (#175) 2025-04-25 13:01:40 -07:00
Olcan 415ec91c6d detect missing sandbox image and provide useful error message (#174) 2025-04-25 12:38:38 -07:00
Olcan 320f54e205 instant (dev) sandbox (#171)
* instant (dev) sandbox

* leave Dockerfile as is to pass deploy test

* fix comma

* fix prod build

* do not use "images exists" which docker does not support

* separate dev-mode flag

* Merge remote-tracking branch 'origin/main' into instant_sandbox
2025-04-25 10:58:23 -07:00
Brandon Keiji eea524f6bb fix: make publish dry-run script match dogfood publish script (#169) 2025-04-25 09:58:27 -07:00
Olcan b65442a88c more compact cli version in footer (#168) 2025-04-25 15:34:26 +00:00
Olcan 39cdba06a6 pass model env var to sandbox (#167) 2025-04-25 15:28:14 +00:00
Brandon Keiji f34ac6272c fix: install rsync in publish pipeline (#166) 2025-04-24 19:53:59 -07:00
Olcan 08463e6114 enable json imports (#165)
* enable json imports

* Merge remote-tracking branch 'origin/main' into enable_json_imports
2025-04-24 18:30:19 -07:00
Brandon Keiji b1b9735889 refactor: make version number shorter (#164) 2025-04-24 18:22:59 -07:00
Olcan cbba8007b2 shell bones (#160)
* shell bones

* Merge remote-tracking branch 'origin/main' into shell_bones

* add line break

* another line break

* drop the log to avoid breaking terminals

* rename tool to be consistent with terminal

* fix build
2025-04-24 18:03:33 -07:00
Brandon Keiji a94a9ce3bf docs: update manual publishing section (#162) 2025-04-25 00:52:24 +00:00
Brandon Keiji 7ea3dff49c refactor: change default logs bucket for cloudbuild cicd (#161) 2025-04-24 17:40:23 -07:00
Allen Hutchison 8cf3e1611e Adding a full_context command line argument. (#158)
* Adding a full_context command line argument.

* Update packages/cli/src/config/config.ts

Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>

* lint fix.

---------

Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
2025-04-24 16:08:29 -07:00
Olcan 133f39494e general rules should apply to whole project (#159)
* general rules should apply to whole project

* Merge remote-tracking branch 'origin/main' into fix_eslint

* lint fixes under server package
2025-04-24 15:42:18 -07:00
Brandon Keiji 0510d06ecf infra: automate continuous deployment (#157) 2025-04-24 14:36:58 -07:00
Jacob Richman 4dc98b3c7e Switch Ansi theme to use regular colors to improve readability. (#154) 2025-04-24 14:19:35 -07:00
Olcan deb11efa89 remove dead code (+ dont reset shellReady unless restarting) (#156) 2025-04-24 13:24:15 -07:00
Brandon Keiji d394a9f39f feat: add flag to customize package version during pre-release staging (#155) 2025-04-24 13:02:49 -07:00
Olcan d97d2a4f7b rename read_many_files (#153) 2025-04-24 12:15:49 -07:00
Jacob Richman 19ed2ed630 Add an ansi theme. (#152)
Add the gradient used by the ascii art logo to theme.
2025-04-24 11:56:23 -07:00
Jacob Richman 5790a5d7cf Add a theme preview and update the theme when highlight changes. (#151) 2025-04-24 11:36:34 -07:00
Olcan d8c0587346 better sandbox check (#150) 2025-04-24 10:32:30 -07:00
Olcan aed42a726a remove target_dir flag (#149) 2025-04-24 10:21:10 -07:00
Olcan 30bdef9bf5 in sandboxed run scripts, allow .env to be an in any ancestor directory, same as in findEnvFile; also prep for sanboxing with global command (#147) 2025-04-24 08:58:47 -07:00
Olcan fb1c67219d unban commands (#146) 2025-04-23 19:20:54 -07:00
Seth Troisi bf6e809abf Pass GEMINI_API_KEY env variable to sandbox 2025-04-23 18:22:58 -07:00
Brandon Keiji 31045e6086 fix: revert pointing npm start to .bin (#144) 2025-04-24 01:21:07 +00:00
Brandon Keiji c24dc0ec77 feat: add react dev tools (#143) 2025-04-23 18:16:15 -07:00
jacob314 cf89c030d0 Make ui/colors refelect the current theme. 2025-04-23 18:08:22 -07:00
Seth Troisi 105c20146c Add generic container run command for npm start 2025-04-23 18:07:29 -07:00
Seth Troisi 09fabe3021 Remove --workspace npm run debug command in README 2025-04-23 17:57:01 -07:00
Allen Hutchison cf92ffab34 Add concatenation tool (#130)
* Adding a tool inspired by files-to-prompt that will recursivly read through all the files in a directory (guarded by targetDir) and concatenate those files for the model. Ignores common build artifacts and non-text files.

* Migraded glob logic to fast-glob. Buffed the tool description to give more guidance to the model. Incorporated reveiw feedback.

* lint and error checking.
2025-04-23 17:25:47 -07:00
Seth Troisi d771dcbdb9 Support GEMINI_CODE_SANDBOX=0/false as no SANDBOXing 2025-04-23 16:33:19 -07:00
Taylor Mullen 095163bbed Refactor: Remove GEMINI.md memory and refactor system prompt
- Updates CONTRIBUTING.md and Tips.tsx to remove references to GEMINI.md and the /init command, and renumbers tips.
- Fixes a typo in Tips.tsx ("information.s" -> "information.").
- Refactors the core system prompt in prompts.ts from a constant string to a function .
- Updates client.ts to call the  function.
- Updates tool name references within the system prompt to use template literals for dynamic naming.

Fixes bug: https://buganizer.corp.google.com/issues/413061073
---

Generated by yours truly __Gemini Code__
2025-04-23 15:57:40 -07:00
Brandon Keiji 94c04955c8 fix: use process.env.CLI_VERSION to avoid conflicts with NODE_ENV (#139) 2025-04-23 15:49:18 -07:00
Seth Troisi 72d0b73598 Add docker equivilant for --authfile 2025-04-23 15:46:51 -07:00
Brandon Keiji 4c951ea435 feat: set dogfood artifact registry as the default publishing endpoint (#135) 2025-04-23 15:11:10 -07:00
Brandon Keiji 7f3798e180 feat: add CLI version number to footer (#134) 2025-04-23 15:00:40 -07:00
Chris Perry 60bee4b137 Updating the system prompt to allow for more complex app creation 2025-04-23 14:39:12 -07:00
Seth Troisi acc655d35f Default TMPDIR to /tmp/ for sandbox (#133) 2025-04-23 14:36:15 -07:00
Olcan f90dcf663e remove dead code (#131) 2025-04-23 13:33:07 -07:00
Taylor Mullen 4c2a5045a0 Add theming support.
- Added a number of common themes to our support matrix:
 - AtomOneDark
 - Dracula
 - VS
 - GitHub
 - GoogleCode
 - XCode
 - ... Admittedly these all were randomly picked, we could probably curate these better...
- Added a new `ThemeDialog` UI that can be accessed via `/theme`. It shows your currentlyt available themes and allows you to change them freely. It does **not**:
 - Save the theme between sessions
 - Allow you to hit escape
 - Show a preview prior to selection.
- These themes are from reacts highlight js library.

Fixes https://b.corp.google.com/issues/412797985
2025-04-22 22:08:13 -07:00
Taylor Mullen e163e02499 Colorize code blocks.
- This changeset uses lowlight.js to parse the code in codeblocks to derive an AST, it then translates that into CSS themes that are widely known via highlight.js (things that GitHub use), finally I translate those css.color attributes into Ink colors and effectivel do <Text color={the color}>the text</Text>.
 - To do this I needed to build color mappings from css -> Ink
 - I introduced a new `Theme` type that will be used to represent many different color themes. It also enabled the color mappings to be seamless.
 - Added a theme manager that only has one theme for now (VS2015). The theme works very well with our colorization.
- Some other bits was removal of borders around our codeblocks since they now have richer rendering.
- Most complex bits of code in this PR is in the `CodeColorizer.tsx`

Fixes https://b.corp.google.com/issues/412433479
2025-04-22 18:57:27 -07:00
Taylor Mullen ffe368afed Refactor tool confirmation radio buttons to own component.
- I plan to utilize these radio buttons for theme selection in the future. Refactoring them into their own component.

Part of https://b.corp.google.com/issues/412797985
2025-04-22 18:33:36 -07:00
Allen Hutchison 9bc9c6e6c5 Question flag (#125) 2025-04-22 18:32:03 -07:00
Brandon Keiji ef7dcdb49e feat: add alias to the cli bin directive (#126) 2025-04-23 01:04:34 +00:00
Jaana Dogan 05c568126f Add a tip about creating an alias during development (#122)
Identical to #118, it's lost while we were recovering the main branch.
2025-04-22 16:17:37 -07:00
Allen Hutchison 8cfd915960 Fix the case where passthrough tools weren't using the correct CWD from -d 2025-04-22 15:19:40 -07:00
Olcan 93458727e8 use full url for base image (found by seth troisi to save 5s from docker build time) (#124) 2025-04-22 14:41:25 -07:00
Olcan a792c4a159 fix .env check (#123) 2025-04-22 14:31:02 -07:00
Olcan 5e34d9e276 Refactor_sandbox_command (#121) 2025-04-22 13:51:50 -07:00
Jaana Dogan 60fc979332 fix hanging tools
https://github.com/google-gemini/gemini-code/pull/117/
2025-04-22 13:40:36 -07:00
Jaana Dogan 8e0fb9ee2f Initiate the GeminiClient with a config
Also address the open readability improvement comments from #104.
2025-04-22 11:20:19 -07:00
Taylor Mullen 3db2a796ec Fix Tool -> Text -> Confirmation bu that results in disordered history
- We weren't reseting the tool group inbetween content which meant we'd start a new group on the first tool call, and if regular textual content followed it'd effectively close that group; however, we weren't updating our state to really close that group. Meaning, any subsequent tool calls or confirmations would get grouped with the original grouping.
  - When we see textual content from Gemini we now reset the tool call group.

Fixes https://b.corp.google.com/issues/412605330
2025-04-22 10:33:36 -04:00
Taylor Mullen 5c5c470671 Update confirmation dialog UI
- This chaneset aligns our confirmation dialog with: https://screenshot.googleplex.com/9yZCX636LzpMrgc
- Primary changes include having custom indicators for confirmation options that align with our coloring / scheme

Fixes https://b.corp.google.com/issues/412607128
2025-04-22 10:33:06 -04:00
Taylor Mullen 80b04dc505 Update UI of tool messages
- Bring tool messages in line with original envisioned UI of: https://screenshot.googleplex.com/9yZCX636LzpMrgc
  - In particular this represents more descriptive names. FWIW we already had this tech we just weren't passing around information correctly (`displayName` vs. `name`)
 - Add gray to our list of color pallete's and removed Background (unused)
 - Re-enabled representing canceled messages
 - Migrated back towards a cleaner tool message design of status symbols & border colors vs. overly verbose text.
 - Removed border from confirmation diffs.
Fixes https://b.corp.google.com/issues/412598909
2025-04-22 08:05:30 -04:00
Olcan 1ed9743ad4 quiet sandbox build (#111) 2025-04-21 23:26:53 -07:00
Olcan a7fba66832 env var to set default model, display model on lower right (#110) 2025-04-21 23:25:10 -07:00
Brandon Keiji 79710375e3 fix: point npmrc to dogfood artifact registry (#108) 2025-04-21 23:11:51 -07:00
Brandon Keiji 98fa8d2b51 fix: support node globals in scripts (#109) 2025-04-22 06:10:25 +00:00
Benjamin Bastian 1eeadcd85c Update sandbox script to not require term variables (#105)
If `nounset` is active, it'll require that TERM and COLORTERM is set in the
environment. It's not necessary that these variables are set and it should be
passed to the sandbox. This change just causes the TERM and COLORTERM to be set
to an empty string if they are unset.
2025-04-21 22:59:49 -07:00
Olcan f9c4014e28 fix source mapping when debugging in sandbox (#107) 2025-04-21 19:04:00 -07:00
Allen Hutchison 1a167b2ea5 Piped input (#104)
* New method for handling stdin. Bypass Ink, and output to stdout. Makes the CLI work like a typical Unix application when called with piped input.

* Fixing a few post-merge errors.

* Format code.

* Clean up lint and format errors.
2025-04-21 17:41:44 -07:00
Jaana Dogan cacf0cc0ef Simplify GeminiClient (#101)
Doing some more clean-up:
* Remove confusing continue/break
* Handle empty result
* Rename the file just client.js
2025-04-21 17:15:20 -07:00
Jaana Dogan dd81be1b9b Add build status to README (#99) 2025-04-21 15:47:53 -07:00
Jaana Dogan 843d7c1fe3 Fix the broken build (#98) 2025-04-21 15:44:20 -07:00
Olcan 1340c7a792 fix sandbox build broken at #94 (#97) 2025-04-21 14:55:17 -07:00
Olcan 319f211211 improved (full color) sandbox, mount /tmp to display build warnings, display sandbox name in footer (#96) 2025-04-21 14:43:43 -07:00
Seth Troisi 7663ccf0bd Fix Docker Build permission issue (#95)
During docker build `npm install` running as node was exiting with 243 (EACCES) from trying to install the tgz files because `npm pack` created the files with 400 permissions on my system.
2025-04-21 14:35:03 -07:00
Brandon Keiji 3f048bce0f fix: remove circular dependency in background terminal analyzer (#94) 2025-04-21 14:27:11 -07:00
Brandon Keiji dec9726083 fix: use relative imports within the same package (#93) 2025-04-21 14:09:14 -07:00
Olcan 09973956ae sandbox.sh utility to easily log into or execute commands in a sandbox, set hostname and SANDBOX env var to container name (#92) 2025-04-21 13:52:51 -07:00
Jaana Dogan ddaa21c750 Remove dead methods from ToolRegistry (#91)
* getToolSchemas is deprecated.
* listAvailableTools is now getAllTools.
2025-04-21 13:29:36 -07:00
Jaana Dogan d4614619b4 Remove dead comments (#90) 2025-04-21 13:06:46 -07:00
Jaana Dogan baf39042c8 Remove duplicate CLI tools module, remove the global tool registry (#89) 2025-04-21 12:59:31 -07:00
Olcan 2571e07175 enable debugging through sandbox (#88) 2025-04-21 12:39:58 -07:00
Jaana Dogan 53a5728009 Remove redundant else branches (#86)
Else branches are an anti pattern especially if you can easily return from the previous branch. Over time, else branches cause deep nesting and make code unreadable and unmaintainable. Remove elses where possible.
2025-04-21 12:15:47 -07:00
Olcan dea0782c89 fix flags via sandbox (again) (#87) 2025-04-21 12:13:16 -07:00
Jaana Dogan 651a543403 Remove gemini-stream.ts (#84)
This module is no longer needed and the types can be provided from types.
2025-04-21 11:49:46 -07:00
Taylor Mullen 738c2692fb Fix confirmations.
- This fixes what it means to get confirmations in GC. Prior to this they had just been accidentally unwired as part of all of the refactorings to turns + to server/core.
  - The key piece of this is that we wrap the onConfirm in the gemini stream hook in order to resubmit function responses. This isn't 100% ideal but gets the job done for now.
- Fixed history not updating properly with confirmations.

Fixes https://b.corp.google.com/issues/412323656
2025-04-21 14:47:17 -04:00
Olcan 618f8a43cf don't assume .env file (#83) 2025-04-21 11:21:48 -07:00
Jaana Dogan 0a531f732b Ignore grep error if .env doesn't exist (#82)
.env file is optional. If it doesn't exist, the current script outputs "grep: .env: No such file or directory".
2025-04-21 11:15:55 -07:00
Tyler 7f95c594c0 More license headers, add a CONTRIBUTING.md file (also fix README.md formatting) (#81) 2025-04-21 10:04:03 -07:00
Olcan fad526c63f make sandbox attachable, document in README (#80) 2025-04-21 09:17:17 -07:00
Olcan 7588aef07c added sandbox section to readme (#79) 2025-04-21 08:31:36 -07:00
Taylor Mullen 81f0f618f7 Fix Gemini Code's (GC) smarts.
- The tl;dr; is that GC couldn't see what the user was saying when tool call events happened in response. The rason why this was happening was because we were instantly invoking tools that the model told us to invoke and then instantly re-requesting. This resulted in the bug because the genai APIs can't update the chat history before a full response has been completed (doesn't know how to update if it's incomplete).
- To address the above issue I had to do quite the large refactor. The gist is that now turns truly drive everything on the server (vs. a server client split). This ensured that when we got tool invocations we could control when/how re-requesting would happen and then also ensure that history was updated. This change also meant that the server would act as an event publisher to enable the client to react to events rather than try and weave in complex logic between the events.
- A BIG change that this changeset incudes is the removal of all of the CLI tools in favor of the server tools.
- Removed some dead code as part of this
- **NOTE: Confirmations are still broken (they were broken prior to this); however, I've set them up to be able to work in the future, I'll dot hat in a follow up to be less breaking to others.**

Fixes https://b.corp.google.com/issues/412320087
2025-04-21 11:07:09 -04:00
Brandon Keiji e351baf10f feat: add custom eslint rule for cross-package imports (#77) 2025-04-21 08:02:11 -07:00
Olcan 39bdedab9c seamless sandboxing (just set GEMINI_CODE_SANDBOX=true in .env) (#76) 2025-04-21 07:50:18 -07:00
Taylor Mullen bfb064024e Revert debug undo. 2025-04-20 22:28:39 -04:00
Taylor Mullen ce0f2dd868 Update README to reflect current state of the world.
- We now have CI/CD
- We have linting support (so added a section)
- Fixed `npm run debug` to allow debugging again.
2025-04-20 22:25:20 -04:00
Olcan d668600672 fix passing of flags through start scripts (#73) 2025-04-20 19:19:42 -07:00
Taylor Mullen 63f864cdd7 Fix read-file from exploding with path not found error.
- There were a few hiccups here. Somehow 2.5-flash wasn't actually abiding by our tool schema. Instead it was inferring `path`. To semi-combat this I've renamed `file_path` -> `path`.
- We weren't elevating errors that were created via schema validation. Instead both the `glob` and `read-file.ts` now surface this.
- In error scenarios (like failing schema) we were improperly surfacing these as success cases because we were overriding tool status.
2025-04-20 22:13:55 -04:00
Olcan c095091853 fix function calling for gemini 2.5 series (#65) 2025-04-20 19:05:27 -07:00
Tyler d55168f51f add linter for checking license headers (and eslint --fix target to match, and fix missing license headers while we're here) (#62) 2025-04-20 17:16:25 -07:00
Olcan 305ed41b88 drop /dist suffix no longer needed (#71) 2025-04-20 14:55:36 -07:00
Olcan ef909f6335 start and debug scripts (will enable seamless container use later), strict error handling in bash scripts (#63)
#61
2025-04-20 14:50:12 -07:00
Olcan c80800a3ee use /sandbox/<proj_name> instead of /project as workdir in container (#64) 2025-04-20 14:49:02 -07:00
Juliette Love 9d608135e3 Make model-generated code copyable (#70) 2025-04-20 21:48:30 +01:00
Juliette Love 8180ed9a68 Add terminal clear (#69) 2025-04-20 21:13:32 +01:00
Brandon Keiji d6556c5246 fix: remove 'dist' suffix from start_container.sh command (#67) 2025-04-20 13:07:54 -07:00
Juliette Love a76d9b4dcf Adds shell command allowlist (#68)
* Wire through passthrough commands

* Add default passthrough commands

* Clean up config passing to useGeminiStream
2025-04-20 21:06:22 +01:00
Brandon Keiji f480ef4bbc refactor: clean up build output (#53)
* refactor: clean up build output

* refactor: add index.ts to package roots
2025-04-20 12:33:39 -07:00
Juliette Love a66ad2e2af Simple debug mode for CLI side (#66)
* Adds debug mode config flag.

* Wire through debug lines

* Add debug mode logging example

* Run format

* Run format again
2025-04-20 20:20:40 +01:00
Olcan 99f5ed9ecb Minimal container setup. Install docker (or podman), build container with scripts/build_container.sh, then start with scripts/start_container.sh. Exit with ^C for now. (#61) 2025-04-20 08:22:17 -07:00
Taylor Mullen 044ccc6dd7 Enable npm run debug from root. 2025-04-19 17:59:17 -04:00
Taylor Mullen f7edf71190 Give Gemini Code a face lift.
- This utilizes `ink-gradient` to render GEMINI CODE in amazing colors.
- Added a shared color configuration for UX (should this be in config?). It's very possible that we shouldn't be talking about the specific colors and instead be mentioning "foreground"/"background"/inlineCode etc. type colors.
- Updated existing color usages to utilize `Colors.*`

Fixes https://b.corp.google.com/issues/411385593
2025-04-19 17:10:06 -04:00
Evan Senter 3fce6cea27 Starting to modularize into separate cli / server packages. (#55)
* Starting to move a lot of code into packages/server

* More of the massive refactor, builds and runs, some issues though.

* Fixing outstanding issue with double messages.

* Fixing a minor UI issue.

* Fixing the build post-merge.

* Running formatting.

* Addressing comments.
2025-04-19 19:45:42 +01:00
Evan Senter 0c9e1ef61b Adding some simple tests. (#54) 2025-04-19 18:07:24 +01:00
Allen Hutchison d9ad2a74ae Fix the double warning for iterm. (#51) 2025-04-19 07:02:12 -07:00
Allen Hutchison ce1c83da89 Quick fix gitignore (#49)
* Command line flags got broke. Now to run with flags run:
npm run start -- -m model-id -d data/dir

* Add *.tsbuildinfo to git ignore.
2025-04-19 07:01:54 -07:00
Evan Senter 75ecb4a81f Adding in a history buffer (#38)
Up and down arrows traverse the command history.
2025-04-19 14:31:59 +01:00
jlove29 2f5f6baf0f fix format 2025-04-19 11:08:50 +01:00
jlove29 d2ef83bc60 Add direct execution of shell commands 2025-04-19 11:07:39 +01:00
Jaana Dogan 24371a3954 Take the turn management out of GeminiClient (#42) 2025-04-18 23:11:33 -07:00
Jaana Dogan 65e8e3ed1f Show error when GEMINI_API_KEY is not set (#52)
Also fix the bug where the API key is used accidentally as the model name.
2025-04-18 19:26:16 -07:00
Tyler 4354458cad Add apache2 SPDX headers to all source files (#48) 2025-04-18 17:44:24 -07:00
Allen Hutchison e75f0722e7 All the pipes (#47)
* Bump the character limit to web fetch.

* Piped Input Hook. First step in bringing in STDIN piping.

* Fix linting errors.

* Remove incorrect comment.
2025-04-18 17:12:14 -07:00
Allen Hutchison 3adc0dfbaf Command line flags got broke. Now to run with flags run: (#46)
npm run start -- -m model-id -d data/dir
2025-04-18 16:41:51 -07:00
Olcan f3669f20a9 minor lint fix (#45) 2025-04-18 16:38:01 -07:00
Brandon Keiji e5a50d0154 fix: point server 'main' to dist folder (#44) 2025-04-18 16:29:49 -07:00
Brandon Keiji 6e4d4fc604 fix: temporarily comment out .npmrc (#43) 2025-04-18 16:18:44 -07:00
Taylor Mullen 40e11e053c Fix remaining tslint errors (YAY).
- Also updated ci.yml to ensure that linting failures will break the build.

Fully fixes https://b.corp.google.com/issues/411384603
2025-04-18 19:14:36 -04:00
Brandon Keiji 2a850ed051 fix: add --build flag to tsc commands (#40) 2025-04-18 16:14:20 -07:00
Taylor Mullen 383b917784 Run npm run format
- This has the entirety of the changes.

Part of https://b.corp.google.com/issues/411720532
2025-04-18 18:10:57 -04:00
Taylor Mullen fa264e4286 Make CI fail if there are unformatted changes.
Fixes https://b.corp.google.com/issues/411720532
2025-04-18 18:10:57 -04:00
Brandon Keiji 23b43ff651 fix: add clean command to individual packages (#36) 2025-04-18 14:57:20 -07:00
Taylor Mullen e7fa39112a Manually fix hooks and utils linting errors (partial)
- More changes are to come, this is truly a partial change in order to not disrupt as many people as possible.

Part of https://b.corp.google.com/issues/411384603
2025-04-18 17:51:16 -04:00
Allen Hutchison dfae3f6284 Iterm refactor (#33)
* Add a warning about the flickering in iTerm.

* Move the iterm warning out of App.tsx.
2025-04-18 14:39:05 -07:00
Brandon Keiji 52683dafc3 infra: add multipackage support (#34) 2025-04-18 14:37:02 -07:00
Allen Hutchison f51ca774cf Add a warning about the flickering in iTerm. (#32) 2025-04-18 14:09:06 -07:00
Evan Senter 482aeaff10 Warn if npm run start is out of date. (#20)
* Adding some wiring to allow the Ink app to warn if there are local development changes that haven't been captured in the recent build of the Gemini CLI.

* Adding a new useAppEffects.ts file that wores some useEffect handlers in.

* Updating package-lock.json to resolve `npm ci` issues.

* Updating package-lock.json and package.json to resolve `npm ci` issues.
2025-04-18 21:55:02 +01:00
Allen Hutchison 3ed61f1ff2 Web fetch tool (#31)
* Adding a web fetch tool.
2025-04-18 13:20:39 -07:00
Brandon Keiji 56d4a35d05 feat: initial configs for npm publishing (#30)
* feat: initial configs for npm publishing

* fix: workspace reference

* fix: include LICENSE in npm run build
2025-04-18 12:46:42 -07:00
Taylor Mullen abb60a4d10 Finish manually fixing linter errors for tools dir (partial).
- More changes are to come, this is truly a partial change in order to not disrupt as many people as possible.

Part of https://b.corp.google.com/issues/411384603
2025-04-18 14:41:36 -04:00
Jaana Dogan 328846c6e3 Remove extra args from config (#27)
We don't have a use case for them yet.
2025-04-18 11:26:39 -07:00
Jaana Dogan 3afaa8033b Introduce a config module to manage configuration (#22)
* Introduce a config module to manage configuration

* Remove public modifier
2025-04-18 11:12:18 -07:00
Jaana Dogan e1fac40256 Rename invalidParams to validateToolParams (#12)
Methods should be verbs. Fixes #4.
2025-04-18 11:06:30 -07:00
Taylor Mullen 7cd3b95317 Fix linting errors in a number of core and tool files (partial)
- As part of this work I also started building out errors.ts which will be a cumulation of error helpers to better handle the challenging `catch (error: unknown)` requirement.
- More changes are to come, this is truly a partial change in order to not disrupt as many people as possible.

Part of https://b.corp.google.com/issues/411384603
2025-04-18 14:02:09 -04:00
Jaana Dogan 93fd6a9160 Style improvements to ls tool (#14) 2025-04-18 10:57:20 -07:00
Evan Senter f6a4a5c44d Revert "Adding some wiring to allow the Ink app to warn if there are local development changes that haven't been captured in the recent build of the Gemini CLI."
This reverts commit 1bfc62dcc2.
2025-04-18 18:36:33 +01:00
Evan Senter bb95c8c45a Revert "Adding support for up / down arrows in the command history."
This reverts commit 3829ac6353.
2025-04-18 18:36:33 +01:00
Evan Senter dbf4c3a37c Revert "Including a test harness for it, and making sure the cursor is always at the end."
This reverts commit 97db77997f.
2025-04-18 18:36:33 +01:00
Tyler f330a87e50 add LICENSE (#25) 2025-04-18 10:30:07 -07:00
Allen Hutchison f72aa8c840 Cicd (#24)
* Add basic non blocking CI workflow.

* Make lint and typecheck continue on error until we have fixed those warnings.
2025-04-18 10:26:27 -07:00
Brandon Keiji 999d0568fa Refactor: Update API key missing message with link (#23) 2025-04-18 10:25:32 -07:00
Allen Hutchison 7878f54043 Add basic non blocking CI workflow. (#21) 2025-04-18 10:20:39 -07:00
Evan Senter 97db77997f Including a test harness for it, and making sure the cursor is always at the end. 2025-04-18 18:16:52 +01:00
Evan Senter 3829ac6353 Adding support for up / down arrows in the command history. 2025-04-18 18:16:52 +01:00
Evan Senter 1bfc62dcc2 Adding some wiring to allow the Ink app to warn if there are local development changes that haven't been captured in the recent build of the Gemini CLI. 2025-04-18 18:16:52 +01:00
Taylor Mullen e0339993ae Initial auto-fixing of linting errors.
- This is the result of runing `npm lint -- -fix`
2025-04-18 12:41:02 -04:00
Evan Senter cb30351403 Adding a new parameter for model, and updating the default to 2.5 Flash. (#18) 2025-04-18 17:06:16 +01:00
Allen Hutchison b56d9c8639 Merge pull request #9 from google-gemini/target-directory
Change the run command to properly pass the command line arguments to…
2025-04-17 16:57:22 -07:00
Allen Hutchison 00d29aa162 Change the run command to properly pass the command line arguments to gemini.ts 2025-04-17 16:55:46 -07:00
Taylor Mullen cfc697a96d Run npm run format
- Also updated README.md accordingly.

Part of https://b.corp.google.com/issues/411384603
2025-04-17 15:29:34 -07:00
Taylor Mullen 7928c1727f Configure linter + prettier.
- This is based on existing expectations for TS code in Google-esc repos.
- First part of the change (we have not run any linter or formatting commands). After this changeset goes in I'll do a mass changeset push.

Fixes https://b.corp.google.com/issues/411384603
2025-04-17 15:29:34 -07:00
Jaana Dogan d3ee91ff92 Merge pull request #3 from google-gemini/readme
Remove internal docs and mention of Gerrit from README
2025-04-17 14:39:13 -07:00
Jaana Dogan a280727248 Remove internal docs and mention of Gerrit from README 2025-04-17 14:38:44 -07:00
Taylor Mullen d970882428 Fix build break (tool -> tools).
- Without this we'd get a TS1261 about the name "tool" only differeing from "Tool" (the class) by case.
2025-04-17 17:25:01 -04:00
Taylor Mullen ece8630c33 Revert camelCasing for schemas 2025-04-17 14:15:20 -07:00
Jaana Dogan 81ba61df7f Improve readability issues
This is only the first change of many changes.

* Remove redundant autogenerated comments
* Use the recommended file name style
* Use camelCase for variable names
* Don't introduce submodules for relevant types
* Don't introduce constants like modules, these are implementation details
* Remove empty files
2025-04-17 14:15:20 -07:00
Brandon Keiji 898a83031c docs: Add setup instructions for API key to README (#1) 2025-04-17 11:59:12 -07:00
425 changed files with 83225 additions and 6045 deletions
+89
View File
@@ -0,0 +1,89 @@
# Use a common base image like Debian.
# Using 'bookworm-slim' for a balance of size and compatibility.
FROM debian:bookworm-slim
# Set environment variables to prevent interactive prompts during installation
ENV DEBIAN_FRONTEND=noninteractive
ENV NODE_VERSION=20.12.2
ENV NODE_VERSION_MAJOR=20
ENV DOCKER_CLI_VERSION=26.1.3
ENV BUILDX_VERSION=v0.14.0
# Install dependencies for adding NodeSource repository, gcloud, and other tools
# - curl: for downloading files
# - gnupg: for managing GPG keys (used by NodeSource & Google Cloud SDK)
# - apt-transport-https: for HTTPS apt repositories
# - ca-certificates: for HTTPS apt repositories
# - rsync: the rsync utility itself
# - git: often useful in build environments
# - python3, python3-pip, python3-venv, python3-crcmod: for gcloud SDK and some of its components
# - lsb-release: for gcloud install script to identify distribution
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
gnupg \
apt-transport-https \
ca-certificates \
rsync \
git \
python3 \
python3-pip \
python3-venv \
python3-crcmod \
lsb-release \
&& rm -rf /var/lib/apt/lists/*
# Install Node.js and npm
# We'll use the official NodeSource repository for a specific version
RUN set -eux; \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
# For Node.js 20.x, it's node_20.x
# Let's explicitly define the major version for clarity
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list && \
apt-get update && \
apt-get install -y --no-install-recommends nodejs && \
npm install -g npm@latest && \
# Verify installations
node -v && \
npm -v && \
rm -rf /var/lib/apt/lists/*
# Install Docker CLI
# Download the static binary from Docker's official source
RUN set -eux; \
DOCKER_CLI_ARCH=$(dpkg --print-architecture); \
case "${DOCKER_CLI_ARCH}" in \
amd64) DOCKER_CLI_ARCH_SUFFIX="x86_64" ;; \
arm64) DOCKER_CLI_ARCH_SUFFIX="aarch64" ;; \
*) echo "Unsupported architecture: ${DOCKER_CLI_ARCH}"; exit 1 ;; \
esac; \
curl -fsSL "https://download.docker.com/linux/static/stable/${DOCKER_CLI_ARCH_SUFFIX}/docker-${DOCKER_CLI_VERSION}.tgz" -o docker.tgz && \
tar -xzf docker.tgz --strip-components=1 -C /usr/local/bin docker/docker && \
rm docker.tgz && \
# Verify installation
docker --version
# Install Docker Buildx plugin
RUN set -eux; \
BUILDX_ARCH_DEB=$(dpkg --print-architecture); \
case "${BUILDX_ARCH_DEB}" in \
amd64) BUILDX_ARCH_SUFFIX="amd64" ;; \
arm64) BUILDX_ARCH_SUFFIX="arm64" ;; \
*) echo "Unsupported architecture for Buildx: ${BUILDX_ARCH_DEB}"; exit 1 ;; \
esac; \
mkdir -p /usr/local/lib/docker/cli-plugins && \
curl -fsSL "https://github.com/docker/buildx/releases/download/${BUILDX_VERSION}/buildx-${BUILDX_VERSION}.linux-${BUILDX_ARCH_SUFFIX}" -o /usr/local/lib/docker/cli-plugins/docker-buildx && \
chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx && \
# verify installation
docker buildx version
# Install Google Cloud SDK (gcloud CLI)
RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg && apt-get update -y && apt-get install google-cloud-cli -y
# Set a working directory (optional, but good practice)
WORKDIR /workspace
# You can add a CMD or ENTRYPOINT if you intend to run this image directly,
# but for Cloud Build, it's usually not necessary as Cloud Build steps override it.
# For example:
ENTRYPOINT '/bin/bash'
+31
View File
@@ -0,0 +1,31 @@
steps:
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
entrypoint: 'npm'
args: ['install']
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
entrypoint: 'npm'
args: ['run', 'auth']
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
entrypoint: 'npm'
args:
[
'run',
'prerelease:version',
'--workspaces',
'--',
'--suffix="$SHORT_SHA.$_REVISION"',
]
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
entrypoint: 'npm'
args: ['run', 'prerelease:deps', '--workspaces']
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
entrypoint: 'npm'
args:
['publish', '--tag=head', '--dry-run', '--workspace=@google/gemini-cli']
options:
defaultLogsBucketBehavior: REGIONAL_USER_OWNED_BUCKET
+150
View File
@@ -0,0 +1,150 @@
steps:
# Step 1: Install root dependencies (includes workspaces)
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Install Dependencies'
entrypoint: 'npm'
args: ['install']
# Step 2: Update version in root package.json
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Set version in workspace root'
entrypoint: 'bash'
args:
- -c # Use bash -c to allow for command substitution and string manipulation
- |
current_version=$(npm pkg get version | sed 's/"//g')
if [ "$_OFFICIAL_RELEASE" = "true" ]; then
new_version="$current_version"
else
new_version="${current_version}-rc.$_REVISION"
fi
npm pkg set "version=${new_version}"
echo "Set root package.json version to: ${new_version}"
# Step 3: Binds the package versions to the version in the repo root's package.json
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Bind package versions to workspace root'
entrypoint: 'npm'
args: ['run', 'prerelease:dev'] # This will run prerelease:version and prerelease:deps
# Step 4: Authenticate for Docker (so we can push images to the artifact registry)
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Authenticate docker'
entrypoint: 'npm'
args: ['run', 'auth']
# Step 5: Build workspace packages
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Build packages'
entrypoint: 'npm'
args: ['run', 'build:packages']
# Step 6: Prepare CLI package.json for publishing
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Prepare @google/gemini-cli and @google/gemini-cli-core packages'
entrypoint: 'npm'
args: ['run', 'prepare:packages']
env:
- 'GEMINI_SANDBOX=$_CONTAINER_TOOL'
- 'SANDBOX_IMAGE_REGISTRY=$_SANDBOX_IMAGE_REGISTRY'
- 'SANDBOX_IMAGE_NAME=$_SANDBOX_IMAGE_NAME'
# Step 7: Build sandbox container image
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Build sandbox Docker image'
entrypoint: 'npm'
args: ['run', 'build:sandbox:fast']
env:
- 'GEMINI_SANDBOX=$_CONTAINER_TOOL'
- 'SANDBOX_IMAGE_REGISTRY=$_SANDBOX_IMAGE_REGISTRY'
- 'SANDBOX_IMAGE_NAME=$_SANDBOX_IMAGE_NAME'
# Step 8: Publish sandbox container image
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Publish sandbox Docker image'
entrypoint: 'npm'
args: ['run', 'publish:sandbox']
env:
- 'GEMINI_SANDBOX=$_CONTAINER_TOOL'
- 'SANDBOX_IMAGE_REGISTRY=$_SANDBOX_IMAGE_REGISTRY'
- 'SANDBOX_IMAGE_NAME=$_SANDBOX_IMAGE_NAME'
# Pre-Step 9: authenticate to our intermediate npm registry
# NOTE: when running locally, run this instead (from the `packages/core` directory):
# - `npm login --registry https://wombat-dressing-room.appspot.com`
# - use a 24hr token
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Setup @google/gemini-cli-core auth token for publishing'
entrypoint: 'bash'
args:
- -c
- |
echo "//wombat-dressing-room.appspot.com/:_authToken=$$CORE_PACKAGE_PUBLISH_TOKEN" > $$HOME/.npmrc
secretEnv: ['CORE_PACKAGE_PUBLISH_TOKEN']
# Step 9: Publish @google/gemini-cli-core to NPM
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Publish @google/gemini-cli-core package'
entrypoint: 'bash'
args:
- -c
- |
if [ "$_OFFICIAL_RELEASE" = "true" ]; then
npm publish --workspace=@google/gemini-cli-core --tag=latest
else
npm publish --workspace=@google/gemini-cli-core --tag=rc
fi
env:
- 'GEMINI_SANDBOX=$_CONTAINER_TOOL'
- 'SANDBOX_IMAGE_REGISTRY=$_SANDBOX_IMAGE_REGISTRY'
- 'SANDBOX_IMAGE_NAME=$_SANDBOX_IMAGE_NAME'
# Pre-Step 10: authenticate to our intermediate npm registry
# NOTE: when running locally, run this instead (from the `packages/cli` directory)
# - `npm login --registry https://wombat-dressing-room.appspot.com`
# - use a 24hr token
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Setup @google/gemini-cli auth token for publishing'
entrypoint: 'bash'
args:
- -c
- |
echo "//wombat-dressing-room.appspot.com/:_authToken=$$CLI_PACKAGE_PUBLISH_TOKEN" > $$HOME/.npmrc
secretEnv: ['CLI_PACKAGE_PUBLISH_TOKEN']
# Step 10: Publish @google/gemini-cli to NPM
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Publish @google/gemini-cli package'
entrypoint: 'bash'
args:
- -c
- |
if [ "$_OFFICIAL_RELEASE" = "true" ]; then
npm publish --workspace=@google/gemini-cli --tag=latest
else
npm publish --workspace=@google/gemini-cli --tag=rc
fi
env:
- 'GEMINI_SANDBOX=$_CONTAINER_TOOL'
- 'SANDBOX_IMAGE_REGISTRY=$_SANDBOX_IMAGE_REGISTRY'
- 'SANDBOX_IMAGE_NAME=$_SANDBOX_IMAGE_NAME'
options:
defaultLogsBucketBehavior: REGIONAL_USER_OWNED_BUCKET
dynamicSubstitutions: true
availableSecrets:
secretManager:
- versionName: ${_CLI_PACKAGE_WOMBAT_TOKEN_RESOURCE_NAME}
env: 'CLI_PACKAGE_PUBLISH_TOKEN'
- versionName: ${_CORE_PACKAGE_WOMBAT_TOKEN_RESOURCE_NAME}
env: 'CORE_PACKAGE_PUBLISH_TOKEN'
substitutions:
_REVISION: '0'
_OFFICIAL_RELEASE: 'false'
_CONTAINER_TOOL: 'docker'
_SANDBOX_IMAGE_REGISTRY: ''
_SANDBOX_IMAGE_NAME: ''
_CLI_PACKAGE_WOMBAT_TOKEN_RESOURCE_NAME: ''
_CORE_PACKAGE_WOMBAT_TOKEN_RESOURCE_NAME: ''
+10
View File
@@ -0,0 +1,10 @@
have_fun: false
code_review:
disable: true
comment_severity_threshold: HIGH
max_review_comments: -1
pull_request_opened:
help: false
summary: false
code_review: false
ignore_patterns: []
+24
View File
@@ -0,0 +1,24 @@
# Set the default behavior for all files to automatically handle line endings.
# This will ensure that all text files are normalized to use LF (line feed)
# line endings in the repository, which helps prevent cross-platform issues.
* text=auto eol=lf
# Explicitly declare files that must have LF line endings for proper execution
# on Unix-like systems.
*.sh eol=lf
*.bash eol=lf
Makefile eol=lf
# Explicitly declare binary file types to prevent Git from attempting to
# normalize their line endings.
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.pdf binary
*.woff binary
*.woff2 binary
*.eot binary
*.ttf binary
*.otf binary
+7
View File
@@ -0,0 +1,7 @@
# By default, require reviews from the release approvers for all files.
* @google-gemini/gemini-cli-askmode-approvers
# The following files don't need reviews from the release approvers.
# These patterns override the rule above.
**/*.md
/docs/
+52
View File
@@ -0,0 +1,52 @@
name: Bug Report
description: Report a bug to help us improve Gemini CLI
labels: ['kind/bug', 'status/need-triage']
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report! Please search [existing issues](https://github.com/google-gemini/gemini-cli/issues) to see if an issue already exists for the bug you encountered.
- type: textarea
id: problem
attributes:
label: What happened?
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: expected
attributes:
label: What did you expect to happen?
validations:
required: true
- type: textarea
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).
value: |
<details>
```console
$ gemini /about
# paste output here
```
</details>
validations:
required: true
- type: textarea
id: login-info
attributes:
label: Login information
description: Describe how you are logging in (e.g., Google Account, API key).
- type: textarea
id: additional-context
attributes:
label: Anything else we need to know?
description: Add any other context about the problem here.
@@ -0,0 +1,30 @@
name: Feature Request
description: Suggest an idea for this project
labels: ['kind/enhancement', 'status/need-triage']
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to suggest an enhancement! Please search [existing issues](https://github.com/google-gemini/gemini-cli/issues) to see if a similar feature has already been requested.
- type: textarea
id: feature
attributes:
label: What would you like to be added?
description: A clear and concise description of the enhancement.
validations:
required: true
- type: textarea
id: rationale
attributes:
label: Why is this needed?
description: A clear and concise description of why this enhancement is needed.
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Add any other context or screenshots about the feature request here.
@@ -0,0 +1,102 @@
name: 'Post Coverage Comment Action'
description: 'Prepares and posts a code coverage comment to a PR.'
inputs:
cli_json_file:
description: 'Path to CLI coverage-summary.json'
required: true
core_json_file:
description: 'Path to Core coverage-summary.json'
required: true
cli_full_text_summary_file:
description: 'Path to CLI full-text-summary.txt'
required: true
core_full_text_summary_file:
description: 'Path to Core full-text-summary.txt'
required: true
node_version:
description: 'Node.js version for context in messages'
required: true
github_token:
description: 'GitHub token for posting comments'
required: true
runs:
using: 'composite'
steps:
- name: Prepare Coverage Comment
id: prep_coverage_comment
shell: bash
run: |
cli_json_file="${{ inputs.cli_json_file }}"
core_json_file="${{ inputs.core_json_file }}"
cli_full_text_summary_file="${{ inputs.cli_full_text_summary_file }}"
core_full_text_summary_file="${{ inputs.core_full_text_summary_file }}"
comment_file="coverage-comment.md"
# Extract percentages using jq for the main table
if [ -f "$cli_json_file" ]; then
cli_lines_pct=$(jq -r '.total.lines.pct' "$cli_json_file")
cli_statements_pct=$(jq -r '.total.statements.pct' "$cli_json_file")
cli_functions_pct=$(jq -r '.total.functions.pct' "$cli_json_file")
cli_branches_pct=$(jq -r '.total.branches.pct' "$cli_json_file")
else
cli_lines_pct="N/A"; cli_statements_pct="N/A"; cli_functions_pct="N/A"; cli_branches_pct="N/A"
echo "CLI coverage-summary.json not found at: $cli_json_file" >&2 # Error to stderr
fi
if [ -f "$core_json_file" ]; then
core_lines_pct=$(jq -r '.total.lines.pct' "$core_json_file")
core_statements_pct=$(jq -r '.total.statements.pct' "$core_json_file")
core_functions_pct=$(jq -r '.total.functions.pct' "$core_json_file")
core_branches_pct=$(jq -r '.total.branches.pct' "$core_json_file")
else
core_lines_pct="N/A"; core_statements_pct="N/A"; core_functions_pct="N/A"; core_branches_pct="N/A"
echo "Core coverage-summary.json not found at: $core_json_file" >&2 # Error to stderr
fi
echo "## Code Coverage Summary" > "$comment_file"
echo "" >> "$comment_file"
echo "| Package | Lines | Statements | Functions | Branches |" >> "$comment_file"
echo "|---|---|---|---|---|" >> "$comment_file"
echo "| CLI | ${cli_lines_pct}% | ${cli_statements_pct}% | ${cli_functions_pct}% | ${cli_branches_pct}% |" >> "$comment_file"
echo "| Core | ${core_lines_pct}% | ${core_statements_pct}% | ${core_functions_pct}% | ${core_branches_pct}% |" >> "$comment_file"
echo "" >> "$comment_file"
# CLI Package - Collapsible Section (with full text summary from file)
echo "<details>" >> "$comment_file"
echo "<summary>CLI Package - Full Text Report</summary>" >> "$comment_file"
echo "" >> "$comment_file"
echo '```text' >> "$comment_file"
if [ -f "$cli_full_text_summary_file" ]; then
cat "$cli_full_text_summary_file" >> "$comment_file"
else
echo "CLI full-text-summary.txt not found at: $cli_full_text_summary_file" >> "$comment_file"
fi
echo '```' >> "$comment_file"
echo "</details>" >> "$comment_file"
echo "" >> "$comment_file"
# Core Package - Collapsible Section (with full text summary from file)
echo "<details>" >> "$comment_file"
echo "<summary>Core Package - Full Text Report</summary>" >> "$comment_file"
echo "" >> "$comment_file"
echo '```text' >> "$comment_file"
if [ -f "$core_full_text_summary_file" ]; then
cat "$core_full_text_summary_file" >> "$comment_file"
else
echo "Core full-text-summary.txt not found at: $core_full_text_summary_file" >> "$comment_file"
fi
echo '```' >> "$comment_file"
echo "</details>" >> "$comment_file"
echo "" >> "$comment_file"
echo "_For detailed HTML reports, please see the 'coverage-reports-${{ inputs.node_version }}' artifact from the main CI run._" >> "$comment_file"
- name: Post Coverage Comment
uses: thollander/actions-comment-pull-request@v3
if: always()
with:
file-path: coverage-comment.md # Use the generated file directly
comment-tag: code-coverage-summary
github-token: ${{ inputs.github_token }}
+27
View File
@@ -0,0 +1,27 @@
## TLDR
<!-- Add a brief description of what this pull request changes and why and any important things for reviewers to look at -->
## Dive Deeper
<!-- more thoughts and in depth discussion here -->
## Reviewer Test Plan
<!-- when a person reviewes 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 -->
## Testing Matrix
<!-- Before submitting please validate your changes on as many of these options as possible -->
| | 🍏 | 🪟 | 🐧 |
| -------- | --- | --- | --- |
| npm run | ❓ | ❓ | ❓ |
| npx | ❓ | ❓ | ❓ |
| Docker | ❓ | ❓ | ❓ |
| Podman | ❓ | - | - |
| Seatbelt | ❓ | - | - |
## Linked issues / bugs
<!-- Add links to any gh issues or other external bugs --->
+146
View File
@@ -0,0 +1,146 @@
# .github/workflows/ci.yml
name: Gemini CLI CI
on:
push:
branches: [main, release]
pull_request:
branches: [main, release]
merge_group:
jobs:
build:
name: Build and Lint
runs-on: ubuntu-latest
permissions:
contents: read # For checkout
strategy:
matrix:
node-version: [20.x]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run formatter check
run: |
npm run format
git diff --exit-code
- name: Run linter
run: npm run lint:ci
- name: Build project
run: npm run build
- name: Run type check
run: npm run typecheck
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-artifacts-${{ matrix.node-version }}
path: |
packages/*/dist
package-lock.json # Only upload dist and lockfile
test:
name: Test
runs-on: ubuntu-latest
needs: build # This job depends on the 'build' job
permissions:
contents: read
checks: write
pull-requests: write
strategy:
matrix:
node-version: [20.x] # Should match the build job's matrix
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: build-artifacts-${{ matrix.node-version }}
path: . # Download to the root, this will include package-lock.json and packages/*/dist
# Restore/create package structure for dist folders if necessary.
# The download-artifact action with path: . should place them correctly if the
# upload paths were relative to the workspace root.
# Example: if uploaded `packages/cli/dist`, it will be at `./packages/cli/dist`.
- name: Install dependencies for testing
run: npm ci # Install fresh dependencies using the downloaded package-lock.json
- name: Run tests and generate reports
run: NO_COLOR=true npm run test:ci
- name: Publish Test Report (for non-forks)
if: always() && (github.event.pull_request.head.repo.full_name == github.repository)
uses: dorny/test-reporter@v1
with:
name: Test Results (Node ${{ matrix.node-version }})
path: packages/*/junit.xml
reporter: java-junit
fail-on-error: 'false'
- name: Upload Test Results Artifact (for forks)
if: always() && (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository)
uses: actions/upload-artifact@v4
with:
name: test-results-fork-${{ matrix.node-version }}
path: packages/*/junit.xml
- name: Upload coverage reports
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-reports-${{ matrix.node-version }}
path: packages/*/coverage
post_coverage_comment:
name: Post Coverage Comment
runs-on: ubuntu-latest
needs: test
if: always() && github.event_name == 'pull_request' && (github.event.pull_request.head.repo.full_name == github.repository)
continue-on-error: true
permissions:
contents: read # For checkout
pull-requests: write # For commenting
strategy:
matrix:
node-version: [20.x] # Should match the test job's matrix
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download coverage reports artifact
uses: actions/download-artifact@v4
with:
name: coverage-reports-${{ matrix.node-version }}
path: coverage_artifact # Download to a specific directory
- name: Post Coverage Comment using Composite Action
uses: ./.github/actions/post-coverage-comment # Path to the composite action directory
with:
cli_json_file: coverage_artifact/cli/coverage/coverage-summary.json
core_json_file: coverage_artifact/core/coverage/coverage-summary.json
cli_full_text_summary_file: coverage_artifact/cli/coverage/full-text-summary.txt
core_full_text_summary_file: coverage_artifact/core/coverage/full-text-summary.txt
node_version: ${{ matrix.node-version }}
github_token: ${{ secrets.GITHUB_TOKEN }}
+48
View File
@@ -0,0 +1,48 @@
# .github/workflows/e2e.yml
name: E2E Tests
on:
push:
branches: [main]
merge_group:
jobs:
e2e-test:
name: E2E Test - ${{ matrix.sandbox }}
runs-on: ubuntu-latest
strategy:
matrix:
sandbox: [sandbox:none, sandbox:docker]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'npm'
- 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@v3
- name: Set up Podman
if: matrix.sandbox == 'sandbox:podman'
uses: redhat-actions/podman-login@v1
with:
registry: docker.io
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Run E2E tests
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
run: npm run test:integration:${{ matrix.sandbox }} -- --verbose --keep-output
+22 -1
View File
@@ -1,5 +1,10 @@
# API keys and secrets
.env
.env~
# gemini-cli settings
.gemini/
!gemini/config.yaml
# Dependency directory
node_modules
@@ -13,5 +18,21 @@ bower_components
.DS_Store
Thumbs.db
# TypeScript build info files
*.tsbuildinfo
# Ignore built ts files
dist
dist
# Docker folder to help skip auth refreshes
.docker
bundle
# Test report files
junit.xml
packages/*/coverage/
# Generated files
packages/cli/src/generated/
.integration-tests/
+1
View File
@@ -0,0 +1 @@
@google:registry=https://wombat-dressing-room.appspot.com
+7
View File
@@ -0,0 +1,7 @@
{
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 80,
"tabWidth": 2
}
+76 -28
View File
@@ -1,29 +1,77 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Attach",
"port": 9229,
"request": "attach",
"skipFiles": [
"<node_internals>/**"
],
"type": "node"
},
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${file}",
"outFiles": [
"${workspaceFolder}/**/*.js"
]
}
]
}
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch CLI",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "start"],
"skipFiles": ["<node_internals>/**"],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"env": {
"GEMINI_SANDBOX": "false"
}
},
{
"type": "node",
"request": "launch",
"name": "Launch E2E",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "test:e2e", "read_many_files"],
"skipFiles": ["<node_internals>/**"],
"cwd": "${workspaceFolder}"
},
{
"name": "Attach",
"port": 9229,
"request": "attach",
"skipFiles": ["<node_internals>/**"],
"type": "node",
// fix source mapping when debugging in sandbox using global installation
// note this does not interfere when remoteRoot is also ${workspaceFolder}/packages
"remoteRoot": "/usr/local/share/npm-global/lib/node_modules/@gemini-cli",
"localRoot": "${workspaceFolder}/packages"
},
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": ["<node_internals>/**"],
"program": "${file}",
"outFiles": ["${workspaceFolder}/**/*.js"]
},
{
"type": "node",
"request": "launch",
"name": "Debug Test File",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"test",
"-w",
"packages",
"--",
"--inspect-brk=9229",
"--no-file-parallelism",
"${input:testFile}"
],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": ["<node_internals>/**"]
}
],
"inputs": [
{
"id": "testFile",
"type": "promptString",
"description": "Enter the path to the test file (e.g., ${workspaceFolder}/packages/cli/src/ui/components/LoadingIndicator.test.tsx)",
"default": "${workspaceFolder}/packages/cli/src/ui/components/LoadingIndicator.test.tsx"
}
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"typescript.tsserver.experimental.enableProjectDiagnostics": true
}
+16
View File
@@ -0,0 +1,16 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "build",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"label": "npm: build",
"detail": "scripts/build.sh"
}
]
}
+297
View File
@@ -0,0 +1,297 @@
# How to Contribute
We would love to accept your patches and contributions to this project.
## Before you begin
### Sign our Contributor License Agreement
Contributions to this project must be accompanied by a
[Contributor License Agreement](https://cla.developers.google.com/about) (CLA).
You (or your employer) retain the copyright to your contribution; this simply
gives us permission to use and redistribute your contributions as part of the
project.
If you or your current employer have already signed the Google CLA (even if it
was for a different project), you probably don't need to do it again.
Visit <https://cla.developers.google.com/> to see your current agreements or to
sign a new one.
### Review our Community Guidelines
This project follows [Google's Open Source Community
Guidelines](https://opensource.google/conduct/).
## Contribution Process
### 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.
### 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.
If an issue for your change doesn't exist, please **open one first** and wait for feedback before you start coding.
#### 2. Keep It Small and Focused
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.
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
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
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
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
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.
- **Good PR Title:** `feat(cli): Add --json flag to 'config get' command`
- **Bad PR Title:** `Made some changes`
In the PR description, explain the "why" behind your changes and link to the relevant issue (e.g., `Fixes #123`).
## Forking
If you are forking the repository you will be able to run the Built, Test and Integration test workflows. However in order to make the integration tests run you'll need to add a [GitHub Repository Secret](<[url](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.
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.
## Development Setup and Workflow
This section guides contributors on how to build, modify, and understand the development setup of this project.
### Setting Up the Development Environment
**Prerequisites:**
1. Install [Node 18+](https://nodejs.org/en/download)
2. Git
### Build Process
To clone the repository:
```bash
git clone https://github.com/google-gemini/gemini-cli.git # Or your fork's URL
cd gemini-cli
```
To install dependencies defined in `package.json` as well as root dependencies:
```bash
npm install
```
To build the entire project (all packages):
```bash
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.
### Enabling Sandboxing
Container-based [sandboxing](#sandboxing) is highly recommended and requires, at a minimum, setting `GEMINI_SANDBOX=true` in your `~/.env` and ensuring a container engine (e.g. `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:
```bash
npm run build:all
```
To skip building the sandbox container, you can use `npm run build` instead.
### Running
To start the Gemini CLI from the source code (after building), run the following command from the root directory:
```bash
npm start
```
If youd 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
This project contains two types of tests: unit tests and integration tests.
#### Unit Tests
To execute the unit test suite for the project:
```bash
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`.
#### 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.
To run the integration tests, use the following command:
```bash
npm run test:e2e
```
For more detailed information on the integration testing framework, please see the [Integration Tests documentation](./docs/integration-tests.md).
### Linting and Preflight Checks
To ensure code quality and formatting consistency, run the preflight check:
```bash
npm run preflight
```
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.
```bash
echo "
# Run npm build and check for errors
if ! npm run preflight; then
echo "npm build failed. Commit aborted."
exit 1
fi
" > .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
```
#### Formatting
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.
#### Linting
To separately lint the code in this project, run the following command from the root directory:
```bash
npm run lint
```
### 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-rules/no-relative-cross-package-imports.js` to enforce restrictions on relative imports between packages.
### Project Structure
- `packages/`: Contains the individual sub-packages of the project.
- `cli/`: The command-line interface.
- `server/`: The backend server that the CLI interacts with.
- `docs/`: Contains all project documentation.
- `scripts/`: Utility scripts for building, testing, and development tasks.
For more detailed architecture, see `docs/architecture.md`.
## Debugging
### 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`).
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:
```bash
DEBUG=1 gemini
```
### 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.
1. **Start the Gemini CLI in development mode:**
```bash
DEV=true npm start
```
2. **Install and run React DevTools version 4.28.5 (or the latest compatible 4.x version):**
You can either install it globally:
```bash
npm install -g react-devtools@4.28.5
react-devtools
```
Or run it directly using npx:
```bash
npx react-devtools@4.28.5
```
Your running CLI application should then connect to React DevTools.
![](/docs/assets/connected_devtools.png)
## Sandboxing
### 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 `.../sandbox-macos-strict.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`.
### 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.
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
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 `scripts/example-proxy.js` 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
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
npm install
npm run auth
npm run prerelease:dev
npm publish --workspaces
```
+50
View File
@@ -0,0 +1,50 @@
FROM docker.io/library/node:20-slim
ARG SANDBOX_NAME="gemini-cli-sandbox"
ARG CLI_VERSION_ARG
ENV SANDBOX="$SANDBOX_NAME"
ENV CLI_VERSION=$CLI_VERSION_ARG
# install minimal set of packages, then clean up
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 \
make \
g++ \
man-db \
curl \
dnsutils \
less \
jq \
bc \
gh \
git \
unzip \
rsync \
ripgrep \
procps \
psmisc \
lsof \
socat \
ca-certificates \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# set up npm global package folder under /usr/local/share
# give it to non-root user node, already set up in base image
RUN mkdir -p /usr/local/share/npm-global \
&& chown -R node:node /usr/local/share/npm-global
ENV NPM_CONFIG_PREFIX=/usr/local/share/npm-global
ENV PATH=$PATH:/usr/local/share/npm-global/bin
# switch to non-root user node
USER node
# install gemini-cli and clean up
COPY packages/cli/dist/google-gemini-cli-*.tgz /usr/local/share/npm-global/gemini-cli.tgz
COPY packages/core/dist/google-gemini-cli-core-*.tgz /usr/local/share/npm-global/gemini-core.tgz
RUN npm install -g /usr/local/share/npm-global/gemini-cli.tgz /usr/local/share/npm-global/gemini-core.tgz \
&& npm cache clean --force \
&& rm -f /usr/local/share/npm-global/gemini-{cli,core}.tgz
# default entrypoint when none specified
CMD ["gemini"]
+183
View File
@@ -0,0 +1,183 @@
## 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.
```
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.
### 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 leads 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.
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2025 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+64
View File
@@ -0,0 +1,64 @@
# Makefile for gemini-cli
.PHONY: help install build build-sandbox build-all test lint format preflight clean start debug release run-npx create-alias
help:
@echo "Makefile for gemini-cli"
@echo ""
@echo "Usage:"
@echo " make install - Install npm dependencies"
@echo " make build - Build the entire project"
@echo " make build-sandbox - Build the sandbox container"
@echo " make build-all - Build the project and the sandbox"
@echo " make test - Run the test suite"
@echo " make lint - Lint the code"
@echo " make format - Format the code"
@echo " make preflight - Run formatting, linting, and tests"
@echo " make clean - Remove generated files"
@echo " make start - Start the Gemini CLI"
@echo " make debug - Start the Gemini CLI in debug mode"
@echo " make release - Publish a new release"
@echo " make run-npx - Run the CLI using npx (for testing the published package)"
@echo " make create-alias - Create a 'gemini' alias for your shell"
install:
npm install
build:
npm run build
build-sandbox:
npm run build:sandbox
build-all:
npm run build:all
test:
npm run test
lint:
npm run lint
format:
npm run format
preflight:
npm run preflight
clean:
npm run clean
start:
npm run start
debug:
npm run debug
release:
npm run publish:release
run-npx:
npx https://github.com/google-gemini/gemini-cli
create-alias:
scripts/create_alias.sh
+117 -30
View File
@@ -1,49 +1,136 @@
# Gemini Code
# Gemini CLI
**Disclaimer:** This README.md was created by gemini-code and this project was developed rapidly and currently lacks comprehensive testing, CI/CD pipelines, and other quality-of-life features common in mature projects.
[![Gemini CLI CI](https://github.com/google-gemini/gemini-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/google-gemini/gemini-cli/actions/workflows/ci.yml)
This repository contains the Gemini Code CLI tool.
![Gemini CLI Screenshot](./docs/assets/gemini-screenshot.png)
## Cloning and Contribution
This repository contains the Gemini CLI, a command-line AI workflow tool that connects to your
tools, understands your code and accelerates your workflows.
This project uses Gerrit for version control. For details on the development workflow, including how to clone the repository and contribute changes, please refer to the [Gerrit Dev Workflows](http://go/gerrit-dev-workflows).
With the Gemini CLI you can:
## Building
- Query and edit large codebases in and beyond Gemini's 1M token context window.
- Generate new apps from PDFs or sketches, using Gemini's multimodal capabilities.
- Automate operational tasks, like querying pull requests or handling complex rebases.
- Use tools and 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)
- Ground your queries with the [Google Search](https://ai.google.dev/gemini-api/docs/grounding)
tool, built in to Gemini.
To build the entire project, including the CLI package, run the following command from the root directory:
## Quickstart
```bash
npm install
npm run build
1. **Prerequisites:** Ensure you have [Node.js version 18](https://nodejs.org/en/download) or higher installed.
2. **Run the CLI:** Execute the following command in your terminal:
```bash
npx https://github.com/google-gemini/gemini-cli
```
Or install it with:
```bash
npm install -g @google/gemini-cli
gemini
```
3. **Pick a color theme**
4. **Authenticate:** When prompted, sign in with your personal Google account. This will grant you up to 60 model requests per minute and 1,000 model requests per day using Gemini.
You are now ready to use the Gemini CLI!
### For advanced use or increased limits:
If you need to use a specific model or require a higher request capacity, you can use an API key:
1. Generate a key from [Google AI Studio](https://aistudio.google.com/apikey).
2. Set it as an environment variable in your terminal. Replace `YOUR_API_KEY` with your generated key.
```bash
export GEMINI_API_KEY="YOUR_API_KEY"
```
For other authentication methods, including Google Workspace accounts, see the [authentication](./docs/cli/authentication.md) guide.
## Examples
Once the CLI is running, you can start interacting with Gemini from your shell.
You can start a project from a new directory:
```sh
cd new-project/
gemini
> Write me a Gemini Discord bot that answers questions using a FAQ.md file I will provide
```
This command installs dependencies and then runs the build script defined in the root `package.json`, which in turn executes the build scripts in all workspaces (including `packages/cli`).
Or work with an existing project:
## Running
To start the Gemini Code CLI, run the following command from the root directory:
```bash
npm start
```sh
git clone https://github.com/google-gemini/gemini-cli
cd gemini-cli
gemini
> Give me a summary of all of the changes that went in yesterday
```
This command executes the `start` script defined in the root `package.json`, which specifically targets and runs the `start` script within the `gemini-code-cli` workspace.
### Next steps
## Debugging
- Learn how to [contribute to or build from the source](./CONTRIBUTING.md).
- Explore the available **[CLI Commands](./docs/cli/commands.md)**.
- If you encounter any issues, review the **[Troubleshooting guide](./docs/troubleshooting.md)**.
- For more comprehensive documentation, see the [full documentation](./docs/index.md).
- Take a look at some [popular tasks](#popular-tasks) for more inspiration.
To debug the CLI application using VS Code:
### Troubleshooting
1. Start the CLI in debug mode from the root directory:
```bash
npm run debug --workspace=gemini-code-cli
```
This command runs `node --inspect-brk dist/gemini.js` within the `packages/cli` directory, pausing execution until a debugger attaches.
2. In VS Code, use the "Attach" launch configuration (found in `.vscode/launch.json`). This configuration is set up to attach to the Node.js process listening on port 9229, which is the default port used by `--inspect-brk`.
Head over to the [troubleshooting](docs/troubleshooting.md) guide if you're
having issues.
Alternatively, you can use the "Launch Program" configuration in VS Code if you prefer to launch the currently open file directly, but the "Attach" method is generally recommended for debugging the main CLI entry point.
## Popular tasks
## Related
### Explore a new codebase
- [Document](http://go/gemini-code-cli)
- [Video Walkthrough](https://screencast.googleplex.com/cast/NDkwMjUwMzMxMjI2MTEyMHwwOWZkMjQzYy03Mw)
Start by `cd`ing into an existing or newly-cloned repository and running `gemini`.
```text
> Describe the main pieces of this system's architecture.
```
```text
> What security mechanisms are in place?
```
### Work with your existing code
```text
> Implement a first draft for GitHub issue #123.
```
```text
> Help me migrate this codebase to the latest version of Java. Start with a plan.
```
### Automate your workflows
Use MCP servers to integrate your local system tools with your enterprise collaboration suite.
```text
> Make me a slide deck showing the git history from the last 7 days, grouped by feature and team member.
```
```text
> Make a full-screen web app for a wall display to show our most interacted-with GitHub issues.
```
### Interact with your system
```text
> Convert all the images in this directory to png, and rename them to use dates from the exif data.
```
```text
> Organise my PDF invoices by month of expenditure.
```
## Terms of Service and Privacy Notice
For details on the terms of service and privacy notice applicable to your use of Gemini CLI, see the [Terms of Service and Privacy Notice](./docs/tos-privacy.md).
+56
View File
@@ -0,0 +1,56 @@
# 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.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

+75
View File
@@ -0,0 +1,75 @@
# 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
{
"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.
+81
View File
@@ -0,0 +1,81 @@
## Authentication Setup
The 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 (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 recieved a free 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 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 (located in the project directory or user home directory) 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 (located in the project directory or user home directory) 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 GEMINI_API_KEY="YOUR_GEMINI_API_KEY"' >> ~/.bashrc
source ~/.bashrc
```
3. **Vertex AI:**
- If not using express mode:
- Ensure you have a Google Cloud project and have enabled the Vertex AI API.
- Set up Application Default Credentials (ADC), using the following command:
```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).
- Set the `GOOGLE_CLOUD_PROJECT`, `GOOGLE_CLOUD_LOCATION`, and `GOOGLE_GENAI_USE_VERTEXAI` 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
export GOOGLE_GENAI_USE_VERTEXAI=true
```
- For repeated use, you can add the environment variables to your `.env` file (located in the project directory or user home directory) 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
echo 'export GOOGLE_GENAI_USE_VERTEXAI=true' >> ~/.bashrc
source ~/.bashrc
```
- If using express mode:
- Set the `GOOGLE_API_KEY` environment variable. In the following methods, replace `YOUR_GOOGLE_API_KEY` with your Vertex AI API key provided by express mode:
- You can temporarily set these environment variables in your current shell session using the following commands:
```bash
export GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"
export GOOGLE_GENAI_USE_VERTEXAI=true
```
- For repeated use, you can add the environment variables to your `.env` file (located in the project directory or user home directory) 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_API_KEY="YOUR_GOOGLE_API_KEY"' >> ~/.bashrc
echo 'export GOOGLE_GENAI_USE_VERTEXAI=true' >> ~/.bashrc
source ~/.bashrc
```
+150
View File
@@ -0,0 +1,150 @@
# CLI Commands
Gemini CLI supports several built-in commands to help you manage your session, customize the interface, and control its behavior. These commands are prefixed with a forward slash (`/`), an at symbol (`@`), or an exclamation mark (`!`).
## Slash commands (`/`)
Slash commands provide meta-level control over the CLI itself.
- **`/bug`**
- **Description:** File an issue about Gemini CLI. By default, the issue is filed within the GitHub repository for Gemini CLI. The string you enter after `/bug` will become the headline for the bug being filed. The default `/bug` behavior can be modified using the `bugCommand` setting in your `.gemini/settings.json` files.
- **`/chat`**
- **Description:** Save and resume conversation history for branching conversation state interactively, or resuming a previous state from a later session.
- **Sub-commands:**
- **`save`**
- **Description:** Saves the current conversation history. You must add a `<tag>` for identifying the conversation state.
- **Usage:** `/chat save <tag>`
- **`resume`**
- **Description:** Resumes a conversation from a previous save.
- **Usage:** `/chat resume <tag>`
- **`list`**
- **Description:** Lists available tags for chat state resumption.
- **`/clear`**
- **Description:** Clear the terminal screen, including the visible session history and scrollback within the CLI. The underlying session data (for history recall) might be preserved depending on the exact implementation, but the visual display is cleared.
- **Keyboard shortcut:** Press **Ctrl+L** at any time to perform a clear action.
- **`/compress`**
- **Description:** Replace the entire chat context with a summary. This saves on tokens used for future tasks while retaining a high level summary of what has happened.
- **`/editor`**
- **Description:** Open a dialog for selecting supported editors.
- **`/help`** (or **`/?`**)
- **Description:** Display help information about the Gemini CLI, including available commands and their usage.
- **`/mcp`**
- **Description:** List configured Model Context Protocol (MCP) servers, their connection status, server details, and available tools.
- **Sub-commands:**
- **`desc`** or **`descriptions`**:
- **Description:** Show detailed descriptions for MCP servers and tools.
- **`nodesc`** or **`nodescriptions`**:
- **Description:** Hide tool descriptions, showing only the tool names.
- **`schema`**:
- **Description:** Show the full JSON schema for the tool's configured parameters.
- **Keyboard Shortcut:** Press **Ctrl+T** at any time to toggle between showing and hiding tool descriptions.
- **`/memory`**
- **Description:** Manage the AI's instructional context (hierarchical memory loaded from `GEMINI.md` files).
- **Sub-commands:**
- **`add`**:
- **Description:** Adds the following text to the AI's memory. Usage: `/memory add <text to remember>`
- **`show`**:
- **Description:** Display the full, concatenated content of the current hierarchical memory that has been loaded from all `GEMINI.md` files. This lets you inspect the instructional context being provided to the Gemini model.
- **`refresh`**:
- **Description:** Reload the hierarchical instructional memory from all `GEMINI.md` files found in the configured locations (global, project/ancestors, and sub-directories). This command updates the model with the latest `GEMINI.md` content.
- **Note:** For more details on how `GEMINI.md` files contribute to hierarchical memory, see the [CLI Configuration documentation](./configuration.md#4-geminimd-files-hierarchical-instructional-context).
- **`/restore`**
- **Description:** Restores the project files to the state they were in just before a tool was executed. This is particularly useful for undoing file edits made by a tool. If run without a tool call ID, it will list available checkpoints to restore from.
- **Usage:** `/restore [tool_call_id]`
- **Note:** Only available if the CLI is invoked with the `--checkpointing` option or configured via [settings](./configuration.md). See [Checkpointing documentation](../checkpointing.md) for more details.
- **`/stats`**
- **Description:** Display detailed statistics for the current Gemini CLI session, including token usage, cached token savings (when available), and session duration. Note: Cached token information is only displayed when cached tokens are being used, which occurs with API key authentication but not with OAuth authentication at this time.
- [**`/theme`**](./themes.md)
- **Description:** Open a dialog that lets you change the visual theme of Gemini CLI.
- **`/auth`**
- **Description:** Open a dialog that lets you change the authentication method.
- **`/about`**
- **Description:** Show version info. Please share this information when filing issues.
- [**`/tools`**](../tools/index.md)
- **Description:** Display a list of tools that are currently available within Gemini CLI.
- **Sub-commands:**
- **`desc`** or **`descriptions`**:
- **Description:** Show detailed descriptions of each tool, including each tool's name with its full description as provided to the model.
- **`nodesc`** or **`nodescriptions`**:
- **Description:** Hide tool descriptions, showing only the tool names.
- **`/quit`** (or **`/exit`**)
- **Description:** Exit Gemini CLI.
## At commands (`@`)
At commands are used to include the content of files or directories as part of your prompt to Gemini. These commands include git-aware filtering.
- **`@<path_to_file_or_directory>`**
- **Description:** Inject the content of the specified file or files into your current prompt. This is useful for asking questions about specific code, text, or collections of files.
- **Examples:**
- `@path/to/your/file.txt Explain this text.`
- `@src/my_project/ Summarize the code in this directory.`
- `What is this file about? @README.md`
- **Details:**
- If a path to a single file is provided, the content of that file is read.
- If a path to a directory is provided, the command attempts to read the content of files within that directory and any subdirectories.
- Spaces in paths should be escaped with a backslash (e.g., `@My\ Documents/file.txt`).
- The command uses the `read_many_files` tool internally. The content is fetched and then inserted into your query before being sent to the Gemini model.
- **Git-aware filtering:** By default, git-ignored files (like `node_modules/`, `dist/`, `.env`, `.git/`) are excluded. This behavior can be changed via the `fileFiltering` settings.
- **File types:** The command is intended for text-based files. While it might attempt to read any file, binary files or very large files might be skipped or truncated by the underlying `read_many_files` tool to ensure performance and relevance. The tool indicates if files were skipped.
- **Output:** The CLI will show a tool call message indicating that `read_many_files` was used, along with a message detailing the status and the path(s) that were processed.
- **`@` (Lone at symbol)**
- **Description:** If you type a lone `@` symbol without a path, the query is passed as-is to the Gemini model. This might be useful if you are specifically talking _about_ the `@` symbol in your prompt.
### Error handling for `@` commands
- If the path specified after `@` is not found or is invalid, an error message will be displayed, and the query might not be sent to the Gemini model, or it will be sent without the file content.
- If the `read_many_files` tool encounters an error (e.g., permission issues), this will also be reported.
## Shell mode & passthrough commands (`!`)
The `!` prefix lets you interact with your system's shell directly from within Gemini CLI.
- **`!<shell_command>`**
- **Description:** Execute the given `<shell_command>` in your system's default shell. Any output or errors from the command are displayed in the terminal.
- **Examples:**
- `!ls -la` (executes `ls -la` and returns to Gemini CLI)
- `!git status` (executes `git status` and returns to Gemini CLI)
- **`!` (Toggle shell mode)**
- **Description:** Typing `!` on its own toggles shell mode.
- **Entering shell mode:**
- When active, shell mode uses a different coloring and a "Shell Mode Indicator".
- While in shell mode, text you type is interpreted directly as a shell command.
- **Exiting shell mode:**
- When exited, the UI reverts to its standard appearance and normal Gemini CLI behavior resumes.
- **Caution for all `!` usage:** Commands you execute in shell mode have the same permissions and impact as if you ran them directly in your terminal.
+429
View File
@@ -0,0 +1,429 @@
# Gemini CLI Configuration
Gemini CLI offers several ways to configure its behavior, including environment variables, command-line arguments, and settings files. This document outlines the different configuration methods and available settings.
## Configuration layers
Configuration is applied in the following order of precedence (lower numbers are overridden by higher numbers):
1. **Default values:** Hardcoded defaults within the application.
2. **User settings file:** Global settings for the current user.
3. **Project settings file:** Project-specific settings.
4. **Environment variables:** System-wide or session-specific variables, potentially loaded from `.env` files.
5. **Command-line arguments:** Values passed when launching the CLI.
## The user settings file and project settings file
Gemini CLI uses `settings.json` files for persistent configuration. There are two locations for these files:
- **User settings file:**
- **Location:** `~/.gemini/settings.json` (where `~` is your home directory).
- **Scope:** Applies to all Gemini CLI sessions for the current user.
- **Project settings file:**
- **Location:** `.gemini/settings.json` within your project's root directory.
- **Scope:** Applies only when running Gemini CLI from that specific project. Project settings override user settings.
**Note on environment variables in settings:** String values within your `settings.json` files can reference environment variables using either `$VAR_NAME` or `${VAR_NAME}` syntax. These variables will be automatically resolved when the settings are loaded. For example, if you have an environment variable `MY_API_TOKEN`, you could use it in `settings.json` like this: `"apiKey": "$MY_API_TOKEN"`.
### The `.gemini` directory in your project
In addition to a project settings file, a project's `.gemini` directory can contain other project-specific files related to Gemini CLI's operation, such as:
- [Custom sandbox profiles](#sandboxing) (e.g., `.gemini/sandbox-macos-custom.sb`, `.gemini/sandbox.Dockerfile`).
### Available settings in `settings.json`:
- **`contextFileName`** (string or array of strings):
- **Description:** Specifies the filename for context files (e.g., `GEMINI.md`, `AGENTS.md`). Can be a single filename or a list of accepted filenames.
- **Default:** `GEMINI.md`
- **Example:** `"contextFileName": "AGENTS.md"`
- **`bugCommand`** (object):
- **Description:** Overrides the default URL for the `/bug` command.
- **Default:** `"urlTemplate": "https://github.com/google-gemini/gemini-cli/issues/new?template=bug_report.yml&title={title}&info={info}"`
- **Properties:**
- **`urlTemplate`** (string): A URL that can contain `{title}` and `{info}` placeholders.
- **Example:**
```json
"bugCommand": {
"urlTemplate": "https://bug.example.com/new?title={title}&info={info}"
}
```
- **`fileFiltering`** (object):
- **Description:** Controls git-aware file filtering behavior for @ commands and file discovery tools.
- **Default:** `"respectGitIgnore": true, "enableRecursiveFileSearch": true`
- **Properties:**
- **`respectGitIgnore`** (boolean): Whether to respect .gitignore patterns when discovering files. When set to `true`, git-ignored files (like `node_modules/`, `dist/`, `.env`) are automatically excluded from @ commands and file listing operations.
- **`enableRecursiveFileSearch`** (boolean): Whether to enable searching recursively for filenames under the current tree when completing @ prefixes in the prompt.
- **Example:**
```json
"fileFiltering": {
"respectGitIgnore": true,
"enableRecursiveFileSearch": false
}
```
- **`coreTools`** (array of strings):
- **Description:** Allows you to specify a list of core tool names that should be made available to the model. This can be used to restrict the set of built-in tools. See [Built-in Tools](../core/tools-api.md#built-in-tools) for a list of core tools.
- **Default:** All tools available for use by the Gemini model.
- **Example:** `"coreTools": ["ReadFileTool", "GlobTool", "SearchText"]`.
- **`excludeTools`** (array of strings):
- **Description:** Allows you to specify a list of core tool names that should be excluded from the model. A tool listed in both `excludeTools` and `coreTools` is excluded.
- **Default**: No tools excluded.
- **Example:** `"excludeTools": ["run_shell_command", "findFiles"]`.
- **`autoAccept`** (boolean):
- **Description:** Controls whether the CLI automatically accepts and executes tool calls that are considered safe (e.g., read-only operations) without explicit user confirmation. If set to `true`, the CLI will bypass the confirmation prompt for tools deemed safe.
- **Default:** `false`
- **Example:** `"autoAccept": true`
- **`theme`** (string):
- **Description:** Sets the visual [theme](./themes.md) for Gemini CLI.
- **Default:** `"Default"`
- **Example:** `"theme": "GitHub"`
- **`sandbox`** (boolean or string):
- **Description:** Controls whether and how to use sandboxing for tool execution. If set to `true`, Gemini CLI uses a pre-built `gemini-cli-sandbox` Docker image. For more information, see [Sandboxing](#sandboxing).
- **Default:** `false`
- **Example:** `"sandbox": "docker"`
- **`toolDiscoveryCommand`** (string):
- **Description:** Defines a custom shell command for discovering tools from your project. The shell command must return on `stdout` a JSON array of [function declarations](https://ai.google.dev/gemini-api/docs/function-calling#function-declarations). Tool wrappers are optional.
- **Default:** Empty
- **Example:** `"toolDiscoveryCommand": "bin/get_tools"`
- **`toolCallCommand`** (string):
- **Description:** Defines a custom shell command for calling a specific tool that was discovered using `toolDiscoveryCommand`. The shell command must meet the following criteria:
- It must take function `name` (exactly as in [function declaration](https://ai.google.dev/gemini-api/docs/function-calling#function-declarations)) as first command line argument.
- It must read function arguments as JSON on `stdin`, analogous to [`functionCall.args`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#functioncall).
- It must return function output as JSON on `stdout`, analogous to [`functionResponse.response.content`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#functionresponse).
- **Default:** Empty
- **Example:** `"toolCallCommand": "bin/call_tool"`
- **`mcpServers`** (object):
- **Description:** Configures connections to one or more Model-Context Protocol (MCP) servers for discovering and using custom tools. Gemini CLI attempts to connect to each configured MCP server to discover available tools. If multiple MCP servers expose a tool with the same name, the tool names will be prefixed with the server alias you defined in the configuration (e.g., `serverAlias__actualToolName`) to avoid conflicts. Note that the system might strip certain schema properties from MCP tool definitions for compatibility.
- **Default:** Empty
- **Properties:**
- **`<SERVER_NAME>`** (object): The server parameters for the named server.
- `command` (string, required): The command to execute to start the MCP server.
- `args` (array of strings, optional): Arguments to pass to the command.
- `env` (object, optional): Environment variables to set for the server process.
- `cwd` (string, optional): The working directory in which to start the server.
- `timeout` (number, optional): Timeout in milliseconds for requests to this MCP server.
- `trust` (boolean, optional): Trust this server and bypass all tool call confirmations.
- **Example:**
```json
"mcpServers": {
"myPythonServer": {
"command": "python",
"args": ["mcp_server.py", "--port", "8080"],
"cwd": "./mcp_tools/python",
"timeout": 5000
},
"myNodeServer": {
"command": "node",
"args": ["mcp_server.js"],
"cwd": "./mcp_tools/node"
},
"myDockerServer": {
"command": "docker",
"args": ["run", "i", "--rm", "-e", "API_KEY", "ghcr.io/foo/bar"],
"env": {
"API_KEY": "$MY_API_TOKEN"
}
},
}
```
- **`checkpointing`** (object):
- **Description:** Configures the checkpointing feature, which allows you to save and restore conversation and file states. See the [Checkpointing documentation](../checkpointing.md) for more details.
- **Default:** `{"enabled": false}`
- **Properties:**
- **`enabled`** (boolean): When `true`, the `/restore` command is available.
- **`preferredEditor`** (string):
- **Description:** Specifies the preferred editor to use for viewing diffs.
- **Default:** `vscode`
- **Example:** `"preferredEditor": "vscode"`
- **`telemetry`** (object)
- **Description:** Configures logging and metrics collection for Gemini CLI. For more information, see [Telemetry](../telemetry.md).
- **Default:** `{"enabled": false, "target": "local", "otlpEndpoint": "http://localhost:4317", "logPrompts": true}`
- **Properties:**
- **`enabled`** (boolean): Whether or not telemetry is enabled.
- **`target`** (string): The destination for collected telemetry. Supported values are `local` and `gcp`.
- **`otlpEndpoint`** (string): The endpoint for the OTLP Exporter.
- **`logPrompts`** (boolean): Whether or not to include the content of user prompts in the logs.
- **Example:**
```json
"telemetry": {
"enabled": true,
"target": "local",
"otlpEndpoint": "http://localhost:16686",
"logPrompts": false
}
```
- **`usageStatisticsEnabled`** (boolean):
- **Description:** Enables or disables the collection of usage statistics. See [Usage Statistics](#usage-statistics) for more information.
- **Default:** `true`
- **Example:**
```json
"usageStatisticsEnabled": false
```
### Example `settings.json`:
```json
{
"theme": "GitHub",
"sandbox": "docker",
"toolDiscoveryCommand": "bin/get_tools",
"toolCallCommand": "bin/call_tool",
"mcpServers": {
"mainServer": {
"command": "bin/mcp_server.py"
},
"anotherServer": {
"command": "node",
"args": ["mcp_server.js", "--verbose"]
}
},
"telemetry": {
"enabled": true,
"target": "local",
"otlpEndpoint": "http://localhost:4317",
"logPrompts": true
},
"usageStatisticsEnabled": true
}
```
## Shell History
The CLI keeps a history of shell commands you run. To avoid conflicts between different projects, this history is stored in a project-specific directory within your user's home folder.
- **Location:** `~/.gemini/tmp/<project_hash>/shell_history`
- `<project_hash>` is a unique identifier generated from your project's root path.
- The history is stored in a file named `shell_history`.
## Environment Variables & `.env` Files
Environment variables are a common way to configure applications, especially for sensitive information like API keys or for settings that might change between environments.
The CLI automatically loads environment variables from an `.env` file. The loading order is:
1. `.env` file in the current working directory.
2. If not found, it searches upwards in parent directories until it finds an `.env` file or reaches the project root (identified by a `.git` folder) or the home directory.
3. If still not found, it looks for `~/.env` (in the user's home directory).
- **`GEMINI_API_KEY`** (Required):
- Your API key for the Gemini API.
- **Crucial for operation.** The CLI will not function without it.
- Set this in your shell profile (e.g., `~/.bashrc`, `~/.zshrc`) or an `.env` file.
- **`GEMINI_MODEL`**:
- Specifies the default Gemini model to use.
- Overrides the hardcoded default
- Example: `export GEMINI_MODEL="gemini-2.5-flash"`
- **`GOOGLE_API_KEY`**:
- Your Google Cloud API key.
- Required for using Vertex AI in express mode.
- Ensure you have the necessary permissions and set the `GOOGLE_GENAI_USE_VERTEXAI=true` environment variable.
- Example: `export GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"`.
- **`GOOGLE_CLOUD_PROJECT`**:
- Your Google Cloud Project ID.
- Required for using Code Assist or Vertex AI.
- If using Vertex AI, ensure you have the necessary permissions and set the `GOOGLE_GENAI_USE_VERTEXAI=true` environment variable.
- Example: `export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"`.
- **`GOOGLE_APPLICATION_CREDENTIALS`** (string):
- **Description:** The path to your Google Application Credentials JSON file.
- **Example:** `export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/credentials.json"`
- **`OTLP_GOOGLE_CLOUD_PROJECT`**:
- Your Google Cloud Project ID for Telemetry in Google Cloud
- Example: `export OTLP_GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"`.
- **`GOOGLE_CLOUD_LOCATION`**:
- Your Google Cloud Project Location (e.g., us-central1).
- Required for using Vertex AI in non express mode.
- If using Vertex AI, ensure you have the necessary permissions and set the `GOOGLE_GENAI_USE_VERTEXAI=true` environment variable.
- Example: `export GOOGLE_CLOUD_LOCATION="YOUR_PROJECT_LOCATION"`.
- **`GEMINI_SANDBOX`**:
- Alternative to the `sandbox` setting in `settings.json`.
- Accepts `true`, `false`, `docker`, `podman`, or a custom command string.
- **`SEATBELT_PROFILE`** (macOS specific):
- Switches the Seatbelt (`sandbox-exec`) profile on macOS.
- `permissive-open`: (Default) Restricts writes to the project folder (and a few other folders, see `packages/cli/src/utils/sandbox-macos-permissive-open.sb`) but allows other operations.
- `strict`: Uses a strict profile that declines operations by default.
- `<profile_name>`: Uses a custom profile. To define a custom profile, create a file named `sandbox-macos-<profile_name>.sb` in your project's `.gemini/` directory (e.g., `my-project/.gemini/sandbox-macos-custom.sb`).
- **`DEBUG` or `DEBUG_MODE`** (often used by underlying libraries or the CLI itself):
- Set to `true` or `1` to enable verbose debug logging, which can be helpful for troubleshooting.
- **`NO_COLOR`**:
- Set to any value to disable all color output in the CLI.
- **`CLI_TITLE`**:
- Set to a string to customize the title of the CLI.
- **`CODE_ASSIST_ENDPOINT`**:
- Specifies the endpoint for the code assist server.
- This is useful for development and testing.
## Command-Line Arguments
Arguments passed directly when running the CLI can override other configurations for that specific session.
- **`--model <model_name>`** (**`-m <model_name>`**):
- Specifies the Gemini model to use for this session.
- Example: `npm start -- --model gemini-1.5-pro-latest`
- **`--prompt <your_prompt>`** (**`-p <your_prompt>`**):
- Used to pass a prompt directly to the command. This invokes Gemini CLI in a non-interactive mode.
- **`--sandbox`** (**`-s`**):
- Enables sandbox mode for this session.
- **`--sandbox-image`**:
- Sets the sandbox image URI.
- **`--debug_mode`** (**`-d`**):
- Enables debug mode for this session, providing more verbose output.
- **`--all_files`** (**`-a`**):
- If set, recursively includes all files within the current directory as context for the prompt.
- **`--help`** (or **`-h`**):
- Displays help information about command-line arguments.
- **`--show_memory_usage`**:
- Displays the current memory usage.
- **`--yolo`**:
- Enables YOLO mode, which automatically approves all tool calls.
- **`--telemetry`**:
- Enables [telemetry](../telemetry.md).
- **`--telemetry-target`**:
- Sets the telemetry target. See [telemetry](../telemetry.md) for more information.
- **`--telemetry-otlp-endpoint`**:
- Sets the OTLP endpoint for telemetry. See [telemetry](../telemetry.md) for more information.
- **`--telemetry-log-prompts`**:
- Enables logging of prompts for telemetry. See [telemetry](../telemetry.md) for more information.
- **`--checkpointing`**:
- Enables [checkpointing](./commands.md#checkpointing-commands).
- **`--version`**:
- Displays the version of the CLI.
## Context Files (Hierarchical Instructional Context)
While not strictly configuration for the CLI's _behavior_, context files (defaulting to `GEMINI.md` but configurable via the `contextFileName` setting) are crucial for configuring the _instructional context_ (also referred to as "memory") provided to the Gemini model. This powerful feature allows you to give project-specific instructions, coding style guides, or any relevant background information to the AI, making its responses more tailored and accurate to your needs. The CLI includes UI elements, such as an indicator in the footer showing the number of loaded context files, to keep you informed about the active context.
- **Purpose:** These Markdown files contain instructions, guidelines, or context that you want the Gemini model to be aware of during your interactions. The system is designed to manage this instructional context hierarchically.
### Example Context File Content (e.g., `GEMINI.md`)
Here's a conceptual example of what a context file at the root of a TypeScript project might contain:
```markdown
# Project: My Awesome TypeScript Library
## General Instructions:
- When generating new TypeScript code, please follow the existing coding style.
- Ensure all new functions and classes have JSDoc comments.
- Prefer functional programming paradigms where appropriate.
- All code should be compatible with TypeScript 5.0 and Node.js 18+.
## Coding Style:
- Use 2 spaces for indentation.
- Interface names should be prefixed with `I` (e.g., `IUserService`).
- Private class members should be prefixed with an underscore (`_`).
- Always use strict equality (`===` and `!==`).
## Specific Component: `src/api/client.ts`
- This file handles all outbound API requests.
- When adding new API call functions, ensure they include robust error handling and logging.
- Use the existing `fetchWithRetry` utility for all GET requests.
## Regarding Dependencies:
- Avoid introducing new external dependencies unless absolutely necessary.
- If a new dependency is required, please state the reason.
```
This example demonstrates how you can provide general project context, specific coding conventions, and even notes about particular files or components. The more relevant and precise your context files are, the better the AI can assist you. Project-specific context files are highly encouraged to establish conventions and context.
- **Hierarchical Loading and Precedence:** The CLI implements a sophisticated hierarchical memory system by loading context files (e.g., `GEMINI.md`) from several locations. Content from files lower in this list (more specific) typically overrides or supplements content from files higher up (more general). The exact concatenation order and final context can be inspected using the `/memory show` command. The typical loading order is:
1. **Global Context File:**
- Location: `~/.gemini/<contextFileName>` (e.g., `~/.gemini/GEMINI.md` in your user home directory).
- Scope: Provides default instructions for all your projects.
2. **Project Root & Ancestors Context Files:**
- Location: The CLI searches for the configured context file in the current working directory and then in each parent directory up to either the project root (identified by a `.git` folder) or your home directory.
- Scope: Provides context relevant to the entire project or a significant portion of it.
3. **Sub-directory Context Files (Contextual/Local):**
- Location: The CLI also scans for the configured context file in subdirectories _below_ the current working directory (respecting common ignore patterns like `node_modules`, `.git`, etc.).
- Scope: Allows for highly specific instructions relevant to a particular component, module, or sub-section of your project.
- **Concatenation & UI Indication:** The contents of all found context files are concatenated (with separators indicating their origin and path) and provided as part of the system prompt to the Gemini model. The CLI footer displays the count of loaded context files, giving you a quick visual cue about the active instructional context.
- **Commands for Memory Management:**
- Use `/memory refresh` to force a re-scan and reload of all context files from all configured locations. This updates the AI's instructional context.
- Use `/memory show` to display the combined instructional context currently loaded, allowing you to verify the hierarchy and content being used by the AI.
- See the [Commands documentation](./commands.md#memory) for full details on the `/memory` command and its sub-commands (`show` and `refresh`).
By understanding and utilizing these configuration layers and the hierarchical nature of context files, you can effectively manage the AI's memory and tailor the Gemini CLI's responses to your specific needs and projects.
## Sandboxing
The Gemini CLI can execute potentially unsafe operations (like shell commands and file modifications) within a sandboxed environment to protect your system.
Sandboxing is disabled by default, but you can enable it in a few ways:
- Using `--sandbox` or `-s` flag.
- Setting `GEMINI_SANDBOX` environment variable.
- Sandbox is enabled in `--yolo` mode by default.
By default, it uses a pre-built `gemini-cli-sandbox` Docker image.
For project-specific sandboxing needs, you can create a custom Dockerfile at `.gemini/sandbox.Dockerfile` in your project's root directory. This Dockerfile can be based on the base sandbox image:
```dockerfile
FROM gemini-cli-sandbox
# Add your custom dependencies or configurations here
# For example:
# RUN apt-get update && apt-get install -y some-package
# COPY ./my-config /app/my-config
```
When `.gemini/sandbox.Dockerfile` exists, you can use `BUILD_SANDBOX` environment variable when running Gemini CLI to automatically build the custom sandbox image:
```bash
BUILD_SANDBOX=1 gemini -s
```
## Usage Statistics
To help us improve the Gemini CLI, we collect anonymized usage statistics. This data helps us understand how the CLI is used, identify common issues, and prioritize new features.
**What we collect:**
- **Tool Calls:** We log the names of the tools that are called, whether they succeed or fail, and how long they take to execute. We do not collect the arguments passed to the tools or any data returned by them.
- **API Requests:** We log the Gemini model used for each request, the duration of the request, and whether it was successful. We do not collect the content of the prompts or responses.
- **Session Information:** We collect information about the configuration of the CLI, such as the enabled tools and the approval mode.
**What we DON'T collect:**
- **Personally Identifiable Information (PII):** We do not collect any personal information, such as your name, email address, or API keys.
- **Prompt and Response Content:** We do not log the content of your prompts or the responses from the Gemini model.
- **File Content:** We do not log the content of any files that are read or written by the CLI.
**How to opt out:**
You can opt out of usage statistics collection at any time by setting the `usageStatisticsEnabled` property to `false` in your `settings.json` file:
```json
{
"usageStatisticsEnabled": false
}
```
+28
View File
@@ -0,0 +1,28 @@
# Gemini CLI
Within Gemini CLI, `packages/cli` is the frontend for users to send and receive prompts with the Gemini AI model and its associated tools. For a general overview of Gemini CLI, see the [main documentation page](../index.md).
## Navigating this section
- **[Authentication](./authentication.md):** A guide to setting up authentication with Google's AI services.
- **[Commands](./commands.md):** A reference for Gemini CLI commands (e.g., `/help`, `/tools`, `/theme`).
- **[Configuration](./configuration.md):** A guide to tailoring Gemini CLI behavior using configuration files.
- **[Token Caching](./token-caching.md):** Optimize API costs through token caching.
- **[Themes](./themes.md)**: A guide to customizing the CLI's appearance with different themes.
- **[Tutorials](tutorials.md)**: A tutorial showing how to use Gemini CLI to automate a development task.
## Non-interactive mode
Gemini CLI can be run in a non-interactive mode, which is useful for scripting and automation. In this mode, you pipe input to the CLI, it executes the command, and then it exits.
The following example pipes a command to Gemini CLI from your terminal:
```bash
echo "What is fine tuning?" | gemini
```
Gemini CLI executes the command and prints the output to your terminal. Note that you can achieve the same behavior by using the `--prompt` or `-p` flag. For example:
```bash
gemini -p "What is fine tuning?"
```
+85
View File
@@ -0,0 +1,85 @@
# Themes
Gemini CLI supports a variety of themes to customize its color scheme and appearance. You can change the theme to suit your preferences via the `/theme` command or `"theme":` configuration setting.
## Available Themes
Gemini CLI comes with a selection of pre-defined themes, which you can list using the `/theme` command within Gemini CLI:
- **Dark Themes:**
- `ANSI`
- `Atom One`
- `Ayu`
- `Default`
- `Dracula`
- `GitHub`
- **Light Themes:**
- `ANSI Light`
- `Ayu Light`
- `Default Light`
- `GitHub Light`
- `Google Code`
- `Xcode`
### Changing Themes
1. Enter `/theme` into Gemini CLI.
2. A dialog or selection prompt appears, listing the available themes.
3. Using the arrow keys, select a theme. Some interfaces might offer a live preview or highlight as you select.
4. Confirm your selection to apply the theme.
### Theme Persistence
Selected themes are saved in Gemini CLI's [configuration](./configuration.md) so your preference is remembered across sessions.
## Dark Themes
### ANSI
<img src="../assets/theme-ansi.png" alt="ANSI theme" width="600" />
### Atom OneDark
<img src="../assets/theme-atom-one.png" alt="Atom One theme" width="600">
### Ayu
<img src="../assets/theme-ayu.png" alt="Ayu theme" width="600">
### Default
<img src="../assets/theme-default.png" alt="Default theme" width="600">
### Dracula
<img src="../assets/theme-dracula.png" alt="Dracula theme" width="600">
### GitHub
<img src="../assets/theme-github.png" alt="GitHub theme" width="600">
## Light Themes
### ANSI Light
<img src="../assets/theme-ansi-light.png" alt="ANSI Light theme" width="600">
### Ayu Light
<img src="../assets/theme-ayu-light.png" alt="Ayu Light theme" width="600">
### Default Light
<img src="../assets/theme-default-light.png" alt="Default Light theme" width="600">
### GitHub Light
<img src="../assets/theme-github-light.png" alt="GitHub Light theme" width="600">
### Google Code
<img src="../assets/theme-google-light.png" alt="Google Code theme" width="600">
### Xcode
<img src="../assets/theme-xcode-light.png" alt="Xcode Light theme" width="600">
+14
View File
@@ -0,0 +1,14 @@
# Token Caching and Cost Optimization
Gemini CLI automatically optimizes API costs through token caching when using API key authentication (Gemini API key or Vertex AI). This feature reuses previous system instructions and context to reduce the number of tokens processed in subsequent requests.
**Token caching is available for:**
- API key users (Gemini API key)
- Vertex AI users (with project and location setup)
**Token caching is not available for:**
- OAuth users (Google Personal/Enterprise accounts) - the Code Assist API does not support cached content creation at this time
You can view your token usage and cached token savings using the `/stats` command. When cached tokens are available, they will be displayed in the stats output.
+69
View File
@@ -0,0 +1,69 @@
# Tutorials
This page contains tutorials for interacting with Gemini CLI.
## Setting up a Model Context Protocol (MCP) server
> [!CAUTION]
> Before using a third-party MCP server, ensure you trust its source and understand the tools it provides. Your use of third-party servers is at your own risk.
This tutorial demonstrates how to set up a MCP server, using the [GitHub MCP server](https://github.com/github/github-mcp-server) as an example. The GitHub MCP server provides tools for interacting with GitHub repositories, such as creating issues and commenting on pull requests.
### Prerequisites
Before you begin, ensure you have the following installed and configured:
- **Docker:** Install and run [Docker].
- **GitHub Personal Access Token (PAT):** Create a new [classic] or [fine-grained] PAT with the necessary scopes.
[Docker]: https://www.docker.com/
[classic]: https://github.com/settings/tokens/new
[fine-grained]: https://github.com/settings/personal-access-tokens/new
### Guide
#### Configure the MCP server in `settings.json`
In your project's root directory, create or open the [`.gemini/settings.json` file](./configuration.md). Within the file, add the `mcpServers` configuration block, which provides instructions for how to launch the GitHub MCP server.
```json
{
"mcpServers": {
"github": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
}
}
}
}
```
#### Set your GitHub token
> [!CAUTION]
> Using a broadly scoped personal access token that has access to personal and private repositories can lead to information from the private repository being leaked into the public repository. We recommend using a fine-grained access token that doesn't share access to both public and private repositories.
Use an environment variable to store your GitHub PAT:
```bash
GITHUB_PERSONAL_ACCESS_TOKEN="pat_YourActualGitHubTokenHere"
```
Gemini CLI uses this value in the `mcpServers` configuration that you defined in the `settings.json` file.
#### Launch Gemini CLI and verify the connection
When you launch Gemini CLI, it automatically reads your configuration and launches the GitHub MCP server in the background. You can then use natural language prompts to ask Gemini CLI to perform GitHub actions. For example:
```bash
"get all open issues assigned to me in the 'foo/bar' repo and prioritize them"
```
+54
View File
@@ -0,0 +1,54 @@
# Gemini CLI Core
Gemini CLI's core package (`packages/core`) is the backend portion of Gemini CLI, handling communication with the Gemini API, managing tools, and processing requests sent from `packages/cli`. For a general overview of Gemini CLI, see the [main documentation page](../index.md).
## Navigating this section
- **[Core tools API](./tools-api.md):** Information on how tools are defined, registered, and used by the core.
## Role of the core
While the `packages/cli` portion of Gemini CLI provides the user interface, `packages/core` is responsible for:
- **Gemini API interaction:** Securely communicating with the Google Gemini API, sending user prompts, and receiving model responses.
- **Prompt engineering:** Constructing effective prompts for the Gemini model, potentially incorporating conversation history, tool definitions, and instructional context from `GEMINI.md` files.
- **Tool management & orchestration:**
- Registering available tools (e.g., file system tools, shell command execution).
- Interpreting tool use requests from the Gemini model.
- Executing the requested tools with the provided arguments.
- Returning tool execution results to the Gemini model for further processing.
- **Session and state management:** Keeping track of the conversation state, including history and any relevant context required for coherent interactions.
- **Configuration:** Managing core-specific configurations, such as API key access, model selection, and tool settings.
## Security considerations
The core plays a vital role in security:
- **API key management:** It handles the `GEMINI_API_KEY` and ensures it's used securely when communicating with the Gemini API.
- **Tool execution:** When tools interact with the local system (e.g., `run_shell_command`), the core (and its underlying tool implementations) must do so with appropriate caution, often involving sandboxing mechanisms to prevent unintended modifications.
## Chat history compression
To ensure that long conversations don't exceed the token limits of the Gemini model, the core includes a chat history compression feature.
When a conversation approaches the token limit for the configured model, the core automatically compresses the conversation history before sending it to the model. This compression is designed to be lossless in terms of the information conveyed, but it reduces the overall number of tokens used.
You can find the token limits for each model in the [Google AI documentation](https://ai.google.dev/gemini-api/docs/models).
## Model fallback
Gemini CLI includes a model fallback mechanism to ensure that you can continue to use the CLI even if the default "pro" model is rate-limited.
If you are using the default "pro" model and the CLI detects that you are being rate-limited, it automatically switches to the "flash" model for the current session. This allows you to continue working without interruption.
## File discovery service
The file discovery service is responsible for finding files in the project that are relevant to the current context. It is used by the `@` command and other tools that need to access files.
## Memory discovery service
The memory discovery service is responsible for finding and loading the `GEMINI.md` files that provide context to the model. It searches for these files in a hierarchical manner, starting from the current working directory and moving up to the project root and the user's home directory. It also searches in subdirectories.
This allows you to have global, project-level, and component-level context files, which are all combined to provide the model with the most relevant information.
You can use the [`/memory` command](../cli/commands.md) to `show`, `add`, and `refresh` the content of loaded `GEMINI.md` files.
+75
View File
@@ -0,0 +1,75 @@
# Gemini CLI Core: Tools API
The Gemini CLI core (`packages/core`) features a robust system for defining, registering, and executing tools. These tools extend the capabilities of the Gemini model, allowing it to interact with the local environment, fetch web content, and perform various actions beyond simple text generation.
## Core Concepts
- **Tool (`tools.ts`):** An interface and base class (`BaseTool`) that defines the contract for all tools. Each tool must have:
- `name`: A unique internal name (used in API calls to Gemini).
- `displayName`: A user-friendly name.
- `description`: A clear explanation of what the tool does, which is provided to the Gemini model.
- `parameterSchema`: A JSON schema defining the parameters the tool accepts. This is crucial for the Gemini model to understand how to call the tool correctly.
- `validateToolParams()`: A method to validate incoming parameters.
- `getDescription()`: A method to provide a human-readable description of what the tool will do with specific parameters before execution.
- `shouldConfirmExecute()`: A method to determine if user confirmation is required before execution (e.g., for potentially destructive operations).
- `execute()`: The core method that performs the tool's action and returns a `ToolResult`.
- **`ToolResult` (`tools.ts`):** An interface defining the structure of a tool's execution outcome:
- `llmContent`: The factual string content to be included in the history sent back to the LLM for context.
- `returnDisplay`: A user-friendly string (often Markdown) or a special object (like `FileDiff`) for display in the CLI.
- **Tool Registry (`tool-registry.ts`):** A class (`ToolRegistry`) responsible for:
- **Registering Tools:** Holding a collection of all available built-in tools (e.g., `ReadFileTool`, `ShellTool`).
- **Discovering Tools:** It can also discover tools dynamically:
- **Command-based Discovery:** If `toolDiscoveryCommand` is configured in settings, this command is executed. It's expected to output JSON describing custom tools, which are then registered as `DiscoveredTool` instances.
- **MCP-based Discovery:** If `mcpServerCommand` is configured, the registry can connect to a Model Context Protocol (MCP) server to list and register tools (`DiscoveredMCPTool`).
- **Providing Schemas:** Exposing the `FunctionDeclaration` schemas of all registered tools to the Gemini model, so it knows what tools are available and how to use them.
- **Retrieving Tools:** Allowing the core to get a specific tool by name for execution.
## Built-in Tools
The core comes with a suite of pre-defined tools, typically found in `packages/core/src/tools/`. These include:
- **File System Tools:**
- `LSTool` (`ls.ts`): Lists directory contents.
- `ReadFileTool` (`read-file.ts`): Reads the content of a single file. It takes an `absolute_path` parameter, which must be an absolute path.
- `WriteFileTool` (`write-file.ts`): Writes content to a file.
- `GrepTool` (`grep.ts`): Searches for patterns in files.
- `GlobTool` (`glob.ts`): Finds files matching glob patterns.
- `EditTool` (`edit.ts`): Performs in-place modifications to files (often requiring confirmation).
- `ReadManyFilesTool` (`read-many-files.ts`): Reads and concatenates content from multiple files or glob patterns (used by the `@` command in CLI).
- **Execution Tools:**
- `ShellTool` (`shell.ts`): Executes arbitrary shell commands (requires careful sandboxing and user confirmation).
- **Web Tools:**
- `WebFetchTool` (`web-fetch.ts`): Fetches content from a URL.
- `WebSearchTool` (`web-search.ts`): Performs a web search.
- **Memory Tools:**
- `MemoryTool` (`memoryTool.ts`): Interacts with the AI's memory.
Each of these tools extends `BaseTool` and implements the required methods for its specific functionality.
## Tool Execution Flow
1. **Model Request:** The Gemini model, based on the user's prompt and the provided tool schemas, decides to use a tool and returns a `FunctionCall` part in its response, specifying the tool name and arguments.
2. **Core Receives Request:** The core parses this `FunctionCall`.
3. **Tool Retrieval:** It looks up the requested tool in the `ToolRegistry`.
4. **Parameter Validation:** The tool's `validateToolParams()` method is called.
5. **Confirmation (if needed):**
- The tool's `shouldConfirmExecute()` method is called.
- If it returns details for confirmation, the core communicates this back to the CLI, which prompts the user.
- The user's decision (e.g., proceed, cancel) is sent back to the core.
6. **Execution:** If validated and confirmed (or if no confirmation is needed), the core calls the tool's `execute()` method with the provided arguments and an `AbortSignal` (for potential cancellation).
7. **Result Processing:** The `ToolResult` from `execute()` is received by the core.
8. **Response to Model:** The `llmContent` from the `ToolResult` is packaged as a `FunctionResponse` and sent back to the Gemini model so it can continue generating a user-facing response.
9. **Display to User:** The `returnDisplay` from the `ToolResult` is sent to the CLI to show the user what the tool did.
## Extending with Custom Tools
While direct programmatic registration of new tools by users isn't explicitly detailed as a primary workflow in the provided files for typical end-users, the architecture supports extension through:
- **Command-based Discovery:** Advanced users or project administrators can define a `toolDiscoveryCommand` in `settings.json`. This command, when run by the Gemini CLI core, should output a JSON array of `FunctionDeclaration` objects. The core will then make these available as `DiscoveredTool` instances. The corresponding `toolCallCommand` would then be responsible for actually executing these custom tools.
- **MCP Server(s):** For more complex scenarios, one or more MCP servers can be set up and configured via the `mcpServers` setting in `settings.json`. The Gemini CLI core can then discover and use tools exposed by these servers. As mentioned, if you have multiple MCP servers, the tool names will be prefixed with the server name from your configuration (e.g., `serverAlias__actualToolName`).
This tool system provides a flexible and powerful way to augment the Gemini model's capabilities, making the Gemini CLI a versatile assistant for a wide range of tasks.
+116
View File
@@ -0,0 +1,116 @@
# Gemini CLI Execution and Deployment
This document describes how to run Gemini CLI and explains the deployment architecture that Gemini CLI uses.
## Running Gemini CLI
There are several ways to run Gemini CLI. The option you choose depends on how you intend to use Gemini CLI.
---
### 1. Standard installation (Recommended for typical users)
This is the recommended way for end-users to install Gemini CLI. It involves downloading the Gemini CLI package from the NPM registry.
- **Global install:**
```bash
# Install the CLI globally
npm install -g @google/gemini-cli
# Now you can run the CLI from anywhere
gemini
```
- **NPX execution:**
```bash
# Execute the latest version from NPM without a global install
npx @google/gemini-cli
```
---
### 2. Running in a sandbox (Docker/Podman)
For security and isolation, Gemini CLI can be run inside a container. This is the default way that the CLI executes tools that might have side effects.
- **Directly from the Registry:**
You can run the published sandbox image directly. This is useful for environments where you only have Docker and want to run the CLI.
```bash
# Run the published sandbox image
docker run --rm -it us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.1.1
```
- **Using the `--sandbox` flag:**
If you have Gemini CLI installed locally (using the standard installation described above), you can instruct it to run inside the sandbox container.
```bash
gemini --sandbox "your prompt here"
```
---
### 3. Running from source (Recommended for Gemini CLI contributors)
Contributors to the project will want to run the CLI directly from the source code.
- **Development Mode:**
This method provides hot-reloading and is useful for active development.
```bash
# From the root of the repository
npm run start
```
- **Production-like mode (Linked package):**
This method simulates a global installation by linking your local package. It's useful for testing a local build in a production workflow.
```bash
# Link the local cli package to your global node_modules
npm link packages/cli
# Now you can run your local version using the `gemini` command
gemini
```
---
### 4. Running the latest Gemini CLI commit from GitHub
You can run the most recently committed version of Gemini CLI directly from the GitHub repository. This is useful for testing features still in development.
```bash
# Execute the CLI directly from the main branch on GitHub
npx https://github.com/google-gemini/gemini-cli
```
## Deployment architecture
The execution methods described above are made possible by the following architectural components and processes:
**NPM packages**
Gemini CLI project is a monorepo that publishes two core packages to the NPM registry:
- `@google/gemini-cli-core`: The backend, handling logic and tool execution.
- `@google/gemini-cli`: The user-facing frontend.
These packages are used when performing the standard installation and when running Gemini CLI from the source.
**Build and packaging processes**
There are two distinct build processes used, depending on the distribution channel:
- **NPM publication:** For publishing to the NPM registry, the TypeScript source code in `@google/gemini-cli-core` and `@google/gemini-cli` is transpiled into standard JavaScript using the TypeScript Compiler (`tsc`). The resulting `dist/` directory is what gets published in the NPM package. This is a standard approach for TypeScript libraries.
- **GitHub `npx` execution:** When running the latest version of Gemini CLI directly from GitHub, a different process is triggered by the `prepare` script in `package.json`. This script uses `esbuild` to bundle the entire application and its dependencies into a single, self-contained JavaScript file. This bundle is created on-the-fly on the user's machine and is not checked into the repository.
**Docker sandbox image**
The Docker-based execution method is supported by the `gemini-cli-sandbox` container image. This image is published to a container registry and contains a pre-installed, global version of Gemini CLI. The `scripts/prepare-cli-packagejson.js` script dynamically injects the URI of this image into the CLI's `package.json` before publishing, so the CLI knows which image to pull when the `--sandbox` flag is used.
## Release process
A unified script, `npm run publish:release`, orchestrates the release process. The script performs the following actions:
1. Build the NPM packages using `tsc`.
2. Update the CLI's `package.json` with the Docker image URI.
3. Build and tag the `gemini-cli-sandbox` Docker image.
4. Push the Docker image to the container registry.
5. Publish the NPM packages to the artifact registry.
+40
View File
@@ -0,0 +1,40 @@
# Gemini CLI Extensions
Gemini CLI supports extensions that can be used to configure and extend its functionality.
## How it works
On startup, Gemini CLI looks for extensions in two locations:
1. `<workspace>/.gemini/extensions`
2. `<home>/.gemini/extensions`
Gemini CLI loads all extensions from both locations. If an extension with the same name exists in both locations, the extension in the workspace directory takes precedence.
Within each location, individual extensions exist as a directory that contains a `gemini-extension.json` file. For example:
`<workspace>/.gemini/extensions/my-extension/gemini-extension.json`
### `gemini-extension.json`
The `gemini-extension.json` file contains the configuration for the extension. The file has the following structure:
```json
{
"name": "my-extension",
"version": "1.0.0",
"mcpServers": {
"my-server": {
"command": "node my-server.js"
}
},
"contextFileName": "GEMINI.md"
}
```
- `name`: The name of the extension. This is used to uniquely identify the extension. This should match the name of your extension directory.
- `version`: The version of the extension.
- `mcpServers`: A map of MCP servers to configure. The key is the name of the server, and the value is the server configuration. These servers will be loaded on startup just like MCP servers configured in a [`settings.json` file](./cli/configuration.md). If both an extension and a `settings.json` file configure an MCP server with the same name, the server defined in the `settings.json` file takes precedence.
- `contextFileName`: The name of the file that contains the context for the extension. This will be used to load the context from the workspace. If this property is not used but a `GEMINI.md` file is present in your extension directory, then that file will be loaded.
When Gemini CLI starts, it loads all the extensions and merges their configurations. If there are any conflicts, the workspace configuration takes precedence.
+37
View File
@@ -0,0 +1,37 @@
# Welcome to Gemini CLI documentation
This documentation provides a comprehensive guide to installing, using, and developing Gemini CLI. This tool lets you interact with Gemini models through a command-line interface.
## Overview
Gemini CLI brings the capabilities of Gemini models to your terminal in an interactive Read-Eval-Print Loop (REPL) environment. Gemini CLI consists of a client-side application (`packages/cli`) that communicates with a local server (`packages/core`), which in turn manages requests to the Gemini API and its AI models. Gemini CLI also contains a variety of tools for tasks such as performing file system operations, running shells, and web fetching, which are managed by `packages/core`.
## Navigating the documentation
This documentation is organized into the following sections:
- **[Execution and Deployment](./deployment.md):** Information for running Gemini CLI.
- **[Architecture Overview](./architecture.md):** Understand the high-level design of Gemini CLI, including its components and how they interact.
- **CLI Usage:** Documentation for `packages/cli`.
- **[CLI Introduction](./cli/index.md):** Overview of the command-line interface.
- **[Commands](./cli/commands.md):** Description of available CLI commands.
- **[Configuration](./cli/configuration.md):** Information on configuring the CLI.
- **[Checkpointing](./checkpointing.md):** Documentation for the checkpointing feature.
- **[Extensions](./extension.md):** How to extend the CLI with new functionality.
- **[Telemetry](./telemetry.md):** Overview of telemetry in the CLI.
- **Core Details:** Documentation for `packages/core`.
- **[Core Introduction](./core/index.md):** Overview of the core component.
- **[Tools API](./core/tools-api.md):** Information on how the core manages and exposes tools.
- **Tools:**
- **[Tools Overview](./tools/index.md):** Overview of the available tools.
- **[File System Tools](./tools/file-system.md):** Documentation for the `read_file` and `write_file` tools.
- **[Multi-File Read Tool](./tools/multi-file.md):** Documentation for the `read_many_files` tool.
- **[Shell Tool](./tools/shell.md):** Documentation for the `run_shell_command` tool.
- **[Web Fetch Tool](./tools/web-fetch.md):** Documentation for the `web_fetch` tool.
- **[Web Search Tool](./tools/web-search.md):** Documentation for the `google_web_search` tool.
- **[Memory Tool](./tools/memory.md):** Documentation for the `save_memory` tool.
- **[Contributing & Development Guide](../CONTRIBUTING.md):** Information for contributors and developers, including setup, building, testing, and coding conventions.
- **[Troubleshooting Guide](./troubleshooting.md):** Find solutions to common problems and FAQs.
- **[Terms of Service and Privacy Notice](./tos-privacy.md):** Information on the terms of service and privacy notices applicable to your use of Gemini CLI.
We hope this documentation helps you make the most of the Gemini CLI!
+141
View File
@@ -0,0 +1,141 @@
# Integration Tests
This document provides information about the integration testing framework used in this project.
## Overview
The integration tests are designed to validate the end-to-end functionality of the Gemini CLI. They execute the built binary in a controlled environment and verify that it behaves as expected when interacting with the file system.
These tests are located in the `integration-tests` directory and are run using a custom test runner.
## Running the tests
The integration tests are not run as part of the default `npm run test` command. They must be run explicitly using the `npm run test:integration:all` script.
The integration tests can also be run using the following shortcut:
```bash
npm run test:e2e
```
## Running a specific set of tests
To run a subset of test files, you can use `npm run <integration test command> <file_name1> ....` where <integration test command> is either `test:e2e` or `test:integration*` and `<file_name>` is any of the `.test.js` files in the `integration-tests/` directory. For example, the following command runs `list_directory.test.js` and `write_file.test.js`:
```bash
npm run test:e2e list_directory write_file
```
### Running a single test by name
To run a single test by its name, use the `--test-name-pattern` flag:
```bash
npm run test:e2e -- --test-name-pattern "reads a file"
```
### Running all tests
To run the entire suite of integration tests, use the following command:
```bash
npm run test:integration:all
```
### Sandbox matrix
The `all` command will run tests for `no sandboxing`, `docker` and `podman`.
Each individual type can be run using the following commands:
```bash
npm run test:integration:sandbox:none
```
```bash
npm run test:integration:sandbox:docker
```
```bash
npm run test:integration:sandbox:podman
```
## Diagnostics
The integration test runner provides several options for diagnostics to help track down test failures.
### Keeping test output
You can preserve the temporary files created during a test run for inspection. This is useful for debugging issues with file system operations.
To keep the test output, you can either use the `--keep-output` flag or set the `KEEP_OUTPUT` environment variable to `true`.
```bash
# Using the flag
npm run test:integration:sandbox:none -- --keep-output
# Using the environment variable
KEEP_OUTPUT=true npm run test:integration:sandbox:none
```
When output is kept, the test runner will print the path to the unique directory for the test run.
### Verbose output
For more detailed debugging, the `--verbose` flag streams the real-time output from the `gemini` command to the console.
```bash
npm run test:integration:sandbox:none -- --verbose
```
When using `--verbose` and `--keep-output` in the same command, the output is streamed to the console and also saved to a log file within the test's temporary directory.
The verbose output is formatted to clearly identify the source of the logs:
```
--- TEST: <file-name-without-js>:<test-name> ---
... output from the gemini command ...
--- END TEST: <file-name-without-js>:<test-name> ---
```
## Linting and formatting
To ensure code quality and consistency, the integration test files are linted as part of the main build process. You can also manually run the linter and auto-fixer.
### Running the linter
To check for linting errors, run the following command:
```bash
npm run lint
```
You can include the `--fix` flag in the command to automatically fix any fixable linting errors:
```bash
npm run lint --fix
```
## Directory structure
The integration tests create a unique directory for each test run inside the `.integration-tests` directory. Within this directory, a subdirectory is created for each test file, and within that, a subdirectory is created for each individual test case.
This structure makes it easy to locate the artifacts for a specific test run, file, or case.
```
.integration-tests/
└── <run-id>/
└── <test-file-name>.test.js/
└── <test-case-name>/
├── output.log
└── ...other test artifacts...
```
## Continuous integration
To ensure the integration tests are always run, a GitHub Actions workflow is defined in `.github/workflows/e2e.yml`. This workflow automatically runs the integration tests on every pull request and push to the `main` branch.
The workflow runs the tests in different sandboxing environments to ensure Gemini CLI is tested across each:
- `sandbox:none`: Runs the tests without any sandboxing.
- `sandbox:docker`: Runs the tests in a Docker container.
- `sandbox:podman`: Runs the tests in a Podman container.
+133
View File
@@ -0,0 +1,133 @@
# Sandboxing in the Gemini CLI
This document provides a guide to sandboxing in the Gemini CLI, including prerequisites, quickstart, and configuration.
## Prerequisites
Before using sandboxing, you need to install and set up the Gemini CLI:
```bash
# install gemini-cli with npm
npm install -g @google/gemini-cli
# Verify installation
gemini --version
```
## Overview of sandboxing
Sandboxing isolates potentially dangerous operations (such as shell commands or file modifications) from your host system, providing a security barrier between AI operations and your environment.
The benefits of sandboxing include:
- **Security**: Prevent accidental system damage or data loss.
- **Isolation**: Limit file system access to project directory.
- **Consistency**: Ensure reproducible environments across different systems.
- **Safety**: Reduce risk when working with untrusted code or experimental commands.
## Sandboxing methods
Your ideal method of sandboxing may differ depending on your platform and your preferred container solution.
### 1. macOS Seatbelt (macOS only)
Lightweight, built-in sandboxing using `sandbox-exec`.
**Default profile**: `permissive-open` - restricts writes outside project directory but allows most other operations.
### 2. Container-based (Docker/Podman)
Cross-platform sandboxing with complete process isolation.
**Note**: Requires building the sandbox image locally or using a published image from your organization's registry.
## Quickstart
```bash
# Enable sandboxing with command flag
gemini -s -p "analyze the code structure"
# Use environment variable
export GEMINI_SANDBOX=true
gemini -p "run the test suite"
# Configure in settings.json
{
"sandbox": "docker"
}
```
## Configuration
### Enable sandboxing (in order of precedence)
1. **Command flag**: `-s` or `--sandbox`
2. **Environment variable**: `GEMINI_SANDBOX=true|docker|podman|sandbox-exec`
3. **Settings file**: `"sandbox": true` in `settings.json`
### macOS Seatbelt profiles
Built-in profiles (set via `SEATBELT_PROFILE` env var):
- `permissive-open` (default): Write restrictions, network allowed
- `permissive-closed`: Write restrictions, no network
- `permissive-proxied`: Write restrictions, network via proxy
- `restrictive-open`: Strict restrictions, network allowed
- `restrictive-closed`: Maximum restrictions
## Linux UID/GID handling
The sandbox automatically handles user permissions on Linux. Override these permissions with:
```bash
export SANDBOX_SET_UID_GID=true # Force host UID/GID
export SANDBOX_SET_UID_GID=false # Disable UID/GID mapping
```
## Troubleshooting
### Common issues
**"Operation not permitted"**
- Operation requires access outside sandbox.
- Try more permissive profile or add mount points.
**Missing commands**
- Add to custom Dockerfile.
- Install via `sandbox.bashrc`.
**Network issues**
- Check sandbox profile allows network.
- Verify proxy configuration.
### Debug mode
```bash
DEBUG=1 gemini -s -p "debug command"
```
### Inspect sandbox
```bash
# Check environment
gemini -s -p "run shell command: env | grep SANDBOX"
# List mounts
gemini -s -p "run shell command: mount | grep workspace"
```
## Security notes
- Sandboxing reduces but doesn't eliminate all risks.
- Use the most restrictive profile that allows your work.
- Container overhead is minimal after first build.
- GUI applications may not work in sandboxes.
## Related documentation
- [Configuration](./cli/configuration.md): Full configuration options.
- [Commands](./cli/commands.md): Available commands.
- [Troubleshooting](./troubleshooting.md): General troubleshooting.
+248
View File
@@ -0,0 +1,248 @@
# Gemini CLI Observability Guide
Telemetry provides data about Gemini CLI's performance, health, and usage. By enabling it, you can monitor operations, debug issues, and optimize tool usage through traces, metrics, and structured logs.
Gemini CLI's telemetry system is built on the **[OpenTelemetry] (OTEL)** standard, allowing you to send data to any compatible backend.
[OpenTelemetry]: https://opentelemetry.io/
## Enabling telemetry
You can enable telemetry in multiple ways. Configuration is primarily managed via the [`.gemini/settings.json` file](./cli/configuration.md) and environment variables, but CLI flags can override these settings for a specific session.
### Order of precedence
The following lists the precedence for applying telemetry settings, with items listed higher having greater precedence:
1. **CLI flags (for `gemini` command):**
- `--telemetry` / `--no-telemetry`: Overrides `telemetry.enabled`.
- `--telemetry-target <local|gcp>`: Overrides `telemetry.target`.
- `--telemetry-otlp-endpoint <URL>`: Overrides `telemetry.otlpEndpoint`.
- `--telemetry-log-prompts` / `--no-telemetry-log-prompts`: Overrides `telemetry.logPrompts`.
1. **Environment variables:**
- `OTEL_EXPORTER_OTLP_ENDPOINT`: Overrides `telemetry.otlpEndpoint`.
1. **Workspace settings file (`.gemini/settings.json`):** Values from the `telemetry` object in this project-specific file.
1. **User settings file (`~/.gemini/settings.json`):** Values from the `telemetry` object in this global user file.
1. **Defaults:** applied if not set by any of the above.
- `telemetry.enabled`: `false`
- `telemetry.target`: `local`
- `telemetry.otlpEndpoint`: `http://localhost:4317`
- `telemetry.logPrompts`: `true`
**For the `npm run telemetry -- --target=<gcp|local>` script:**
The `--target` argument to this script _only_ overrides the `telemetry.target` for the duration and purpose of that script (i.e., choosing which collector to start). It does not permanently change your `settings.json`. The script will first look at `settings.json` for a `telemetry.target` to use as its default.
### Example settings
The following code can be added to your workspace (`.gemini/settings.json`) or user (`~/.gemini/settings.json`) settings to enable telemetry and send the output to Google Cloud:
```json
{
"telemetry": {
"enabled": true,
"target": "gcp"
},
"sandbox": false
}
```
## Running an OTEL Collector
An OTEL Collector is a service that receives, processes, and exports telemetry data.
The CLI sends data using the OTLP/gRPC protocol.
Learn more about OTEL exporter standard configuration in [documentation][otel-config-docs].
[otel-config-docs]: https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/
### Local
Use the `npm run telemetry -- --target=local` command to automate the process of setting up a local telemetry pipeline, including configuring the necessary settings in your `.gemini/settings.json` file. The underlying script installs `otelcol-contrib` (the OpenTelemetry Collector) and `jaeger` (The Jaeger UI for viewing traces). To use it:
1. **Run the command**:
Execute the command from the root of the repository:
```bash
npm run telemetry -- --target=local
```
The script will:
- Download Jaeger and OTEL if needed.
- Start a local Jaeger instance.
- Start an OTEL collector configured to receive data from Gemini CLI.
- Automatically enable telemetry in your workspace settings.
- On exit, disable telemetry.
1. **View traces**:
Open your web browser and navigate to **http://localhost:16686** to access the Jaeger UI. Here you can inspect detailed traces of Gemini CLI operations.
1. **Inspect logs and metrics**:
The script redirects the OTEL collector output (which includes logs and metrics) to `~/.gemini/tmp/<projectHash>/otel/collector.log`. The script will provide links to view and command to tail your telemetry data (traces, metrics, logs) locally.
1. **Stop the services**:
Press `Ctrl+C` in the terminal where the script is running to stop the OTEL Collector and Jaeger services.
### Google Cloud
Use the `npm run telemetry -- --target=gcp` command to automate setting up a local OpenTelemetry collector that forwards data to your Google Cloud project, including configuring the necessary settings in your `.gemini/settings.json` file. The underlying script installs `otelcol-contrib`. To use it:
1. **Prerequisites**:
- Have a Google Cloud project ID.
- Export the `GOOGLE_CLOUD_PROJECT` environment variable to make it available to the OTEL collector.
```bash
export OTLP_GOOGLE_CLOUD_PROJECT="your-project-id"
```
- Authenticate with Google Cloud (e.g., run `gcloud auth application-default login` or ensure `GOOGLE_APPLICATION_CREDENTIALS` is set).
- Ensure your Google Cloud account/service account has the necessary IAM roles: "Cloud Trace Agent", "Monitoring Metric Writer", and "Logs Writer".
1. **Run the command**:
Execute the command from the root of the repository:
```bash
npm run telemetry -- --target=gcp
```
The script will:
- Download the `otelcol-contrib` binary if needed.
- Start an OTEL collector configured to receive data from Gemini CLI and export it to your specified Google Cloud project.
- Automatically enable telemetry and disable sandbox mode in your workspace settings (`.gemini/settings.json`).
- Provide direct links to view traces, metrics, and logs in your Google Cloud Console.
- On exit (Ctrl+C), it will attempt to restore your original telemetry and sandbox settings.
1. **Run Gemini CLI:**
In a separate terminal, run your Gemini CLI commands. This generates telemetry data that the collector captures.
1. **View telemetry in Google Cloud**:
Use the links provided by the script to navigate to the Google Cloud Console and view your traces, metrics, and logs.
1. **Inspect local collector logs**:
The script redirects the local OTEL collector output to `~/.gemini/tmp/<projectHash>/otel/collector-gcp.log`. The script provides links to view and command to tail your collector logs locally.
1. **Stop the service**:
Press `Ctrl+C` in the terminal where the script is running to stop the OTEL Collector.
## Logs and metric reference
The following section describes the structure of logs and metrics generated for Gemini CLI.
- A `sessionId` is included as a common attribute on all logs and metrics.
### Logs
Logs are timestamped records of specific events. The following events are logged for Gemini CLI:
- `gemini_cli.config`: This event occurs once at startup with the CLI's configuration.
- **Attributes**:
- `model` (string)
- `embedding_model` (string)
- `sandbox_enabled` (boolean)
- `core_tools_enabled` (string)
- `approval_mode` (string)
- `api_key_enabled` (boolean)
- `vertex_ai_enabled` (boolean)
- `code_assist_enabled` (boolean)
- `log_prompts_enabled` (boolean)
- `file_filtering_respect_git_ignore` (boolean)
- `debug_mode` (boolean)
- `mcp_servers` (string)
- `gemini_cli.user_prompt`: This event occurs when a user submits a prompt.
- **Attributes**:
- `prompt_length`
- `prompt` (this attribute is excluded if `log_prompts_enabled` is configured to be `false`)
- `gemini_cli.tool_call`: This event occurs for each function call.
- **Attributes**:
- `function_name`
- `function_args`
- `duration_ms`
- `success` (boolean)
- `decision` (string: "accept", "reject", or "modify", if applicable)
- `error` (if applicable)
- `error_type` (if applicable)
- `gemini_cli.api_request`: This event occurs when making a request to Gemini API.
- **Attributes**:
- `model`
- `request_text` (if applicable)
- `gemini_cli.api_error`: This event occurs if the API request fails.
- **Attributes**:
- `model`
- `error`
- `error_type`
- `status_code`
- `duration_ms`
- `gemini_cli.api_response`: This event occurs upon receiving a response from Gemini API.
- **Attributes**:
- `model`
- `status_code`
- `duration_ms`
- `error` (optional)
- `input_token_count`
- `output_token_count`
- `cached_content_token_count`
- `thoughts_token_count`
- `tool_token_count`
- `response_text` (if applicable)
### Metrics
Metrics are numerical measurements of behavior over time. The following metrics are collected for Gemini CLI:
- `gemini_cli.session.count` (Counter, Int): Incremented once per CLI startup.
- `gemini_cli.tool.call.count` (Counter, Int): Counts tool calls.
- **Attributes**:
- `function_name`
- `success` (boolean)
- `decision` (string: "accept", "reject", or "modify", if applicable)
- `gemini_cli.tool.call.latency` (Histogram, ms): Measures tool call latency.
- **Attributes**:
- `function_name`
- `decision` (string: "accept", "reject", or "modify", if applicable)
- `gemini_cli.api.request.count` (Counter, Int): Counts all API requests.
- **Attributes**:
- `model`
- `status_code`
- `error_type` (if applicable)
- `gemini_cli.api.request.latency` (Histogram, ms): Measures API request latency.
- **Attributes**:
- `model`
- `gemini_cli.token.usage` (Counter, Int): Counts the number of tokens used.
- **Attributes**:
- `model`
- `type` (string: "input", "output", "thought", "cache", or "tool")
- `gemini_cli.file.operation.count` (Counter, Int): Counts file operations.
- **Attributes**:
- `operation` (string: "create", "read", "update"): The type of file operation.
- `lines` (Int, if applicable): Number of lines in the file.
- `mimetype` (string, if applicable): Mimetype of the file.
- `extension` (string, if applicable): File extension of the file.
+231
View File
@@ -0,0 +1,231 @@
# Gemini CLI file system tools
The Gemini CLI provides a comprehensive suite of tools for interacting with the local file system. These tools allow the Gemini model to read from, write to, list, search, and modify files and directories, all under your control and typically with confirmation for sensitive operations.
**Note:** All file system tools operate within a `rootDirectory` (usually the current working directory where you launched the CLI) for security. Paths that you provide to these tools are generally expected to be absolute or are resolved relative to this root directory.
## 1. `list_directory` (ReadFolder)
`list_directory` lists the names of files and subdirectories directly within a specified directory path. It can optionally ignore entries matching provided glob patterns.
- **Tool name:** `list_directory`
- **Display name:** ReadFolder
- **File:** `ls.ts`
- **Parameters:**
- `path` (string, required): The absolute path to the directory to list.
- `ignore` (array of strings, optional): A list of glob patterns to exclude from the listing (e.g., `["*.log", ".git"]`).
- `respect_git_ignore` (boolean, optional): Whether to respect `.gitignore` patterns when listing files. Defaults to `true`.
- **Behavior:**
- Returns a list of file and directory names.
- Indicates whether each entry is a directory.
- Sorts entries with directories first, then alphabetically.
- **Output (`llmContent`):** A string like: `Directory listing for /path/to/your/folder:\n[DIR] subfolder1\nfile1.txt\nfile2.png`
- **Confirmation:** No.
- **Tool name:** `list_directory`
- **Display name:** ReadFolder
- **File:** `ls.ts`
- **Parameters:**
- `path` (string, required): The absolute path to the directory to list.
- `ignore` (array of strings, optional): A list of glob patterns to exclude from the listing (e.g., `["*.log", ".git"]`).
- `respect_git_ignore` (boolean, optional): Whether to respect `.gitignore` patterns when listing files. Defaults to `true`.
- **Behavior:**
- Returns a list of file and directory names.
- Indicates whether each entry is a directory.
- Sorts entries with directories first, then alphabetically.
- **Output (`llmContent`):** A string like: `Directory listing for /path/to/your/folder:\n[DIR] subfolder1\nfile1.txt\nfile2.png`
- **Confirmation:** No.
## 2. `read_file` (ReadFile)
`read_file` reads and returns the content of a specified file. This tool handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), and PDF files. For text files, it can read specific line ranges. Other binary file types are generally skipped.
- **Tool name:** `read_file`
- **Display name:** ReadFile
- **File:** `read-file.ts`
- **Parameters:**
- `path` (string, required): The absolute path to the file to read.
- `offset` (number, optional): For text files, the 0-based line number to start reading from. Requires `limit` to be set.
- `limit` (number, optional): For text files, the maximum number of lines to read. If omitted, reads a default maximum (e.g., 2000 lines) or the entire file if feasible.
- **Behavior:**
- For text files: Returns the content. If `offset` and `limit` are used, returns only that slice of lines. Indicates if content was truncated due to line limits or line length limits.
- For image and PDF files: Returns the file content as a base64-encoded data structure suitable for model consumption.
- For other binary files: Attempts to identify and skip them, returning a message indicating it's a generic binary file.
- **Output:** (`llmContent`):
- For text files: The file content, potentially prefixed with a truncation message (e.g., `[File content truncated: showing lines 1-100 of 500 total lines...]\nActual file content...`).
- For image/PDF files: An object containing `inlineData` with `mimeType` and base64 `data` (e.g., `{ inlineData: { mimeType: 'image/png', data: 'base64encodedstring' } }`).
- For other binary files: A message like `Cannot display content of binary file: /path/to/data.bin`.
- **Confirmation:** No.
- **Tool name:** `read_file`
- **Display name:** ReadFile
- **File:** `read-file.ts`
- **Parameters:**
- `path` (string, required): The absolute path to the file to read.
- `offset` (number, optional): For text files, the 0-based line number to start reading from. Requires `limit` to be set.
- `limit` (number, optional): For text files, the maximum number of lines to read. If omitted, reads a default maximum (e.g., 2000 lines) or the entire file if feasible.
- **Behavior:**
- For text files: Returns the content. If `offset` and `limit` are used, returns only that slice of lines. Indicates if content was truncated due to line limits or line length limits.
- For image and PDF files: Returns the file content as a base64-encoded data structure suitable for model consumption.
- For other binary files: Attempts to identify and skip them, returning a message indicating it's a generic binary file.
- **Output:** (`llmContent`):
- For text files: The file content, potentially prefixed with a truncation message (e.g., `[File content truncated: showing lines 1-100 of 500 total lines...]\nActual file content...`).
- For image/PDF files: An object containing `inlineData` with `mimeType` and base64 `data` (e.g., `{ inlineData: { mimeType: 'image/png', data: 'base64encodedstring' } }`).
- For other binary files: A message like `Cannot display content of binary file: /path/to/data.bin`.
- **Confirmation:** No.
## 3. `write_file` (WriteFile)
`write_file` writes content to a specified file. If the file exists, it will be overwritten. If the file doesn't exist, it (and any necessary parent directories) will be created.
- **Tool name:** `write_file`
- **Display name:** WriteFile
- **File:** `write-file.ts`
- **Parameters:**
- `file_path` (string, required): The absolute path to the file to write to.
- `content` (string, required): The content to write into the file.
- **Behavior:**
- Writes the provided `content` to the `file_path`.
- Creates parent directories if they don't exist.
- **Output (`llmContent`):** A success message, e.g., `Successfully overwrote file: /path/to/your/file.txt` or `Successfully created and wrote to new file: /path/to/new/file.txt`.
- **Confirmation:** Yes. Shows a diff of changes and asks for user approval before writing.
- **Tool name:** `write_file`
- **Display name:** WriteFile
- **File:** `write-file.ts`
- **Parameters:**
- `file_path` (string, required): The absolute path to the file to write to.
- `content` (string, required): The content to write into the file.
- **Behavior:**
- Writes the provided `content` to the `file_path`.
- Creates parent directories if they don't exist.
- **Output (`llmContent`):** A success message, e.g., `Successfully overwrote file: /path/to/your/file.txt` or `Successfully created and wrote to new file: /path/to/new/file.txt`.
- **Confirmation:** Yes. Shows a diff of changes and asks for user approval before writing.
## 4. `glob` (FindFiles)
`glob` finds files matching specific glob patterns (e.g., `src/**/*.ts`, `*.md`), returning absolute paths sorted by modification time (newest first).
- **Tool name:** `glob`
- **Display name:** FindFiles
- **File:** `glob.ts`
- **Parameters:**
- `pattern` (string, required): The glob pattern to match against (e.g., `"*.py"`, `"src/**/*.js"`).
- `path` (string, optional): The absolute path to the directory to search within. If omitted, searches the tool's root directory.
- `case_sensitive` (boolean, optional): Whether the search should be case-sensitive. Defaults to `false`.
- `respect_git_ignore` (boolean, optional): Whether to respect .gitignore patterns when finding files. Defaults to `true`.
- **Behavior:**
- Searches for files matching the glob pattern within the specified directory.
- Returns a list of absolute paths, sorted with the most recently modified files first.
- Ignores common nuisance directories like `node_modules` and `.git` by default.
- **Output (`llmContent`):** A message like: `Found 5 file(s) matching "*.ts" within src, sorted by modification time (newest first):\nsrc/file1.ts\nsrc/subdir/file2.ts...`
- **Confirmation:** No.
- **Tool name:** `glob`
- **Display name:** FindFiles
- **File:** `glob.ts`
- **Parameters:**
- `pattern` (string, required): The glob pattern to match against (e.g., `"*.py"`, `"src/**/*.js"`).
- `path` (string, optional): The absolute path to the directory to search within. If omitted, searches the tool's root directory.
- `case_sensitive` (boolean, optional): Whether the search should be case-sensitive. Defaults to `false`.
- `respect_git_ignore` (boolean, optional): Whether to respect .gitignore patterns when finding files. Defaults to `true`.
- **Behavior:**
- Searches for files matching the glob pattern within the specified directory.
- Returns a list of absolute paths, sorted with the most recently modified files first.
- Ignores common nuisance directories like `node_modules` and `.git` by default.
- **Output (`llmContent`):** A message like: `Found 5 file(s) matching "*.ts" within src, sorted by modification time (newest first):\nsrc/file1.ts\nsrc/subdir/file2.ts...`
- **Confirmation:** No.
## 5. `search_file_content` (SearchText)
`search_file_content` searches for a regular expression pattern within the content of files in a specified directory. Can filter files by a glob pattern. Returns the lines containing matches, along with their file paths and line numbers.
- **Tool name:** `search_file_content`
- **Display name:** SearchText
- **File:** `grep.ts`
- **Parameters:**
- `pattern` (string, required): The regular expression (regex) to search for (e.g., `"function\s+myFunction"`).
- `path` (string, optional): The absolute path to the directory to search within. Defaults to the current working directory.
- `include` (string, optional): A glob pattern to filter which files are searched (e.g., `"*.js"`, `"src/**/*.{ts,tsx}"`). If omitted, searches most files (respecting common ignores).
- **Behavior:**
- Uses `git grep` if available in a Git repository for speed, otherwise falls back to system `grep` or a JavaScript-based search.
- Returns a list of matching lines, each prefixed with its file path (relative to the search directory) and line number.
- **Output (`llmContent`):** A formatted string of matches, e.g.:
- **Tool name:** `search_file_content`
- **Display name:** SearchText
- **File:** `grep.ts`
- **Parameters:**
- `pattern` (string, required): The regular expression (regex) to search for (e.g., `"function\s+myFunction"`).
- `path` (string, optional): The absolute path to the directory to search within. Defaults to the current working directory.
- `include` (string, optional): A glob pattern to filter which files are searched (e.g., `"*.js"`, `"src/**/*.{ts,tsx}"`). If omitted, searches most files (respecting common ignores).
- **Behavior:**
- Uses `git grep` if available in a Git repository for speed, otherwise falls back to system `grep` or a JavaScript-based search.
- Returns a list of matching lines, each prefixed with its file path (relative to the search directory) and line number.
- **Output (`llmContent`):** A formatted string of matches, e.g.:
```
Found 3 match(es) for pattern "myFunction" in path "." (filter: "*.ts"):
---
File: src/utils.ts
L15: export function myFunction() {
L22: myFunction.call();
---
File: src/index.ts
L5: import { myFunction } from './utils';
---
```
- **Confirmation:** No.
- **Confirmation:** No.
## 6. `replace` (Edit)
`replace` replaces text within a file. By default, replaces a single occurrence, but can replace multiple occurrences when `expected_replacements` is specified. This tool is designed for precise, targeted changes and requires significant context around the `old_string` to ensure it modifies the correct location.
- **Tool name:** `replace`
- **Display name:** Edit
- **File:** `edit.ts`
- **Parameters:**
- `file_path` (string, required): The absolute path to the file to modify.
- `old_string` (string, required): The exact literal text to replace.
**CRITICAL:** This string must uniquely identify the single instance to change. It should include at least 3 lines of context _before_ and _after_ the target text, matching whitespace and indentation precisely. If `old_string` is empty, the tool attempts to create a new file at `file_path` with `new_string` as content.
- `new_string` (string, required): The exact literal text to replace `old_string` with.
- `expected_replacements` (number, optional): The number of occurrences to replace. Defaults to `1`.
- **Behavior:**
- If `old_string` is empty and `file_path` does not exist, creates a new file with `new_string` as content.
- If `old_string` is provided, it reads the `file_path` and attempts to find exactly one occurrence of `old_string`.
- If one occurrence is found, it replaces it with `new_string`.
- **Enhanced Reliability (Multi-Stage Edit Correction):** To significantly improve the success rate of edits, especially when the model-provided `old_string` might not be perfectly precise, the tool incorporates a multi-stage edit correction mechanism.
- If the initial `old_string` isn't found or matches multiple locations, the tool can leverage the Gemini model to iteratively refine `old_string` (and potentially `new_string`).
- This self-correction process attempts to identify the unique segment the model intended to modify, making the `replace` operation more robust even with slightly imperfect initial context.
- **Failure Conditions:** Despite the correction mechanism, the tool will fail if:
- `file_path` is not absolute or is outside the root directory.
- `old_string` is not empty, but the `file_path` does not exist.
- `old_string` is empty, but the `file_path` already exists.
- `old_string` is not found in the file after attempts to correct it.
- `old_string` is found multiple times, and the self-correction mechanism cannot resolve it to a single, unambiguous match.
- **Output (`llmContent`):**
- On success: `Successfully modified file: /path/to/file.txt (1 replacements).` or `Created new file: /path/to/new_file.txt with provided content.`
- On failure: An error message explaining the reason (e.g., `Failed to edit, 0 occurrences found...`, `Failed to edit, expected 1 occurrences but found 2...`).
- **Confirmation:** Yes. Shows a diff of the proposed changes and asks for user approval before writing to the file.
- `new_string` (string, required): The exact literal text to replace `old_string` with.
- `expected_replacements` (number, optional): The number of occurrences to replace. Defaults to `1`.
- **Behavior:**
- If `old_string` is empty and `file_path` does not exist, creates a new file with `new_string` as content.
- If `old_string` is provided, it reads the `file_path` and attempts to find exactly one occurrence of `old_string`.
- If one occurrence is found, it replaces it with `new_string`.
- **Enhanced Reliability (Multi-Stage Edit Correction):** To significantly improve the success rate of edits, especially when the model-provided `old_string` might not be perfectly precise, the tool incorporates a multi-stage edit correction mechanism.
- If the initial `old_string` isn't found or matches multiple locations, the tool can leverage the Gemini model to iteratively refine `old_string` (and potentially `new_string`).
- This self-correction process attempts to identify the unique segment the model intended to modify, making the `replace` operation more robust even with slightly imperfect initial context.
- **Failure conditions:** Despite the correction mechanism, the tool will fail if:
- `file_path` is not absolute or is outside the root directory.
- `old_string` is not empty, but the `file_path` does not exist.
- `old_string` is empty, but the `file_path` already exists.
- `old_string` is not found in the file after attempts to correct it.
- `old_string` is found multiple times, and the self-correction mechanism cannot resolve it to a single, unambiguous match.
- **Output (`llmContent`):**
- On success: `Successfully modified file: /path/to/file.txt (1 replacements).` or `Created new file: /path/to/new_file.txt with provided content.`
- On failure: An error message explaining the reason (e.g., `Failed to edit, 0 occurrences found...`, `Failed to edit, expected 1 occurrences but found 2...`).
- **Confirmation:** Yes. Shows a diff of the proposed changes and asks for user approval before writing to the file.
These file system tools provide a foundation for the Gemini CLI to understand and interact with your local project context.
+56
View File
@@ -0,0 +1,56 @@
# Gemini CLI tools
The Gemini CLI includes built-in tools that the Gemini model uses to interact with your local environment, access information, and perform actions. These tools enhance the CLI's capabilities, enabling it to go beyond text generation and assist with a wide range of tasks.
## Overview of Gemini CLI tools
In the context of the Gemini CLI, tools are specific functions or modules that the Gemini model can request to be executed. For example, if you ask Gemini to "Summarize the contents of `my_document.txt`," the model will likely identify the need to read that file and will request the execution of the `read_file` tool.
The core component (`packages/core`) manages these tools, presents their definitions (schemas) to the Gemini model, executes them when requested, and returns the results to the model for further processing into a user-facing response.
These tools provide the following capabilities:
- **Access local information:** Tools allow Gemini to access your local file system, read file contents, list directories, etc.
- **Execute commands:** With tools like `run_shell_command`, Gemini can run shell commands (with appropriate safety measures and user confirmation).
- **Interact with the web:** Tools can fetch content from URLs.
- **Take actions:** Tools can modify files, write new files, or perform other actions on your system (again, typically with safeguards).
- **Ground responses:** By using tools to fetch real-time or specific local data, Gemini's responses can be more accurate, relevant, and grounded in your actual context.
## How to use Gemini CLI tools
To use Gemini CLI tools, provide a prompt to the Gemini CLI. The process works as follows:
1. You provide a prompt to the Gemini CLI.
2. The CLI sends the prompt to the core.
3. The core, along with your prompt and conversation history, sends a list of available tools and their descriptions/schemas to the Gemini API.
4. The Gemini model analyzes your request. If it determines that a tool is needed, its response will include a request to execute a specific tool with certain parameters.
5. The core receives this tool request, validates it, and (often after user confirmation for sensitive operations) executes the tool.
6. The output from the tool is sent back to the Gemini model.
7. The Gemini model uses the tool's output to formulate its final answer, which is then sent back through the core to the CLI and displayed to you.
You will typically see messages in the CLI indicating when a tool is being called and whether it succeeded or failed.
## Security and confirmation
Many tools, especially those that can modify your file system or execute commands (`write_file`, `edit`, `run_shell_command`), are designed with safety in mind. The Gemini CLI will typically:
- **Require confirmation:** Prompt you before executing potentially sensitive operations, showing you what action is about to be taken.
- **Utilize sandboxing:** All tools are subject to restrictions enforced by sandboxing (see [README](../../README.md#sandboxing)). This means that when operating in a sandbox, any tools (including MCP servers) you wish to use must be available _inside_ the sandbox environment. For example, to run an MCP server through `npx`, the `npx` executable must be installed within the sandbox's Docker image or be available in the `sandbox-exec` environment.
It's important to always review confirmation prompts carefully before allowing a tool to proceed.
## Learn more about Gemini CLI's tools
Gemini CLI's built-in tools can be broadly categorized as follows:
- **[File System Tools](./file-system.md):** For interacting with files and directories (reading, writing, listing, searching, etc.).
- **[Shell Tool](./shell.md) (`run_shell_command`):** For executing shell commands.
- **[Web Fetch Tool](./web-fetch.md) (`web_fetch`):** For retrieving content from URLs.
- **[Web Search Tool](./web-search.md) (`web_search`):** For searching the web.
- **[Multi-File Read Tool](./multi-file.md) (`read_many_files`):** A specialized tool for reading content from multiple files or directories, often used by the `@` command.
- **[Memory Tool](./memory.md) (`save_memory`):** For saving and recalling information across sessions.
Additionally, these tools incorporate:
- **[MCP servers](./mcp-server.md)**: MCP servers act as a bridge between the Gemini model and your local environment or other services like APIs.
- **[Sandboxing](../sandbox.md)**: Sandboxing isolates the model and its changes from your environment to reduce potential risk.
+428
View File
@@ -0,0 +1,428 @@
# MCP servers with the Gemini CLI
This document provides a guide to configuring and using Model Context Protocol (MCP) servers with the Gemini CLI.
## What is an MCP server?
An MCP server is an application that exposes tools and resources to the Gemini CLI through the Model Context Protocol, allowing it to interact with external systems and data sources. MCP servers act as a bridge between the Gemini model and your local environment or other services like APIs.
An MCP server enables the Gemini CLI to:
- **Discover tools:** List available tools, their descriptions, and parameters through standardized schema definitions.
- **Execute tools:** Call specific tools with defined arguments and receive structured responses.
- **Access resources:** Read data from specific resources (though the Gemini CLI primarily focuses on tool execution).
With an MCP server, you can extend the Gemini CLI's capabilities to perform actions beyond its built-in features, such as interacting with databases, APIs, custom scripts, or specialized workflows.
## Core Integration Architecture
The Gemini CLI integrates with MCP servers through a sophisticated discovery and execution system built into the core package (`packages/core/src/tools/`):
### Discovery Layer (`mcp-client.ts`)
The discovery process is orchestrated by `discoverMcpTools()`, which:
1. **Iterates through configured servers** from your `settings.json` `mcpServers` configuration
2. **Establishes connections** using appropriate transport mechanisms (Stdio, SSE, or Streamable HTTP)
3. **Fetches tool definitions** from each server using the MCP protocol
4. **Sanitizes and validates** tool schemas for compatibility with the Gemini API
5. **Registers tools** in the global tool registry with conflict resolution
### Execution Layer (`mcp-tool.ts`)
Each discovered MCP tool is wrapped in a `DiscoveredMCPTool` instance that:
- **Handles confirmation logic** based on server trust settings and user preferences
- **Manages tool execution** by calling the MCP server with proper parameters
- **Processes responses** for both the LLM context and user display
- **Maintains connection state** and handles timeouts
### Transport Mechanisms
The Gemini CLI supports three MCP transport types:
- **Stdio Transport:** Spawns a subprocess and communicates via stdin/stdout
- **SSE Transport:** Connects to Server-Sent Events endpoints
- **Streamable HTTP Transport:** Uses HTTP streaming for communication
## How to set up your MCP server
The Gemini CLI uses the `mcpServers` configuration in your `settings.json` file to locate and connect to MCP servers. This configuration supports multiple servers with different transport mechanisms.
### Configure the MCP server in settings.json
You can configure MCP servers at the global level in the `~/.gemini/settings.json` file or in your project's root directory, create or open the `.gemini/settings.json` file. Within the file, add the `mcpServers` configuration block.
### Configuration Structure
Add an `mcpServers` object to your `settings.json` file:
```json
{ ...file contains other config objects
"mcpServers": {
"serverName": {
"command": "path/to/server",
"args": ["--arg1", "value1"],
"env": {
"API_KEY": "$MY_API_TOKEN"
},
"cwd": "./server-directory",
"timeout": 30000,
"trust": false
}
}
}
```
### Configuration Properties
Each server configuration supports the following properties:
#### Required (one of the following)
- **`command`** (string): Path to the executable for Stdio transport
- **`url`** (string): SSE endpoint URL (e.g., `"http://localhost:8080/sse"`)
- **`httpUrl`** (string): HTTP streaming endpoint URL
#### Optional
- **`args`** (string[]): Command-line arguments for Stdio transport
- **`env`** (object): Environment variables for the server process. Values can reference environment variables using `$VAR_NAME` or `${VAR_NAME}` syntax
- **`cwd`** (string): Working directory for Stdio transport
- **`timeout`** (number): Request timeout in milliseconds (default: 600,000ms = 10 minutes)
- **`trust`** (boolean): When `true`, bypasses all tool call confirmations for this server (default: `false`)
### Example Configurations
#### Python MCP Server (Stdio)
```json
{
"mcpServers": {
"pythonTools": {
"command": "python",
"args": ["-m", "my_mcp_server", "--port", "8080"],
"cwd": "./mcp-servers/python",
"env": {
"DATABASE_URL": "$DB_CONNECTION_STRING",
"API_KEY": "${EXTERNAL_API_KEY}"
},
"timeout": 15000
}
}
}
```
#### Node.js MCP Server (Stdio)
```json
{
"mcpServers": {
"nodeServer": {
"command": "node",
"args": ["dist/server.js", "--verbose"],
"cwd": "./mcp-servers/node",
"trust": true
}
}
}
```
#### Docker-based MCP Server
```json
{
"mcpServers": {
"dockerizedServer": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"API_KEY",
"-v",
"${PWD}:/workspace",
"my-mcp-server:latest"
],
"env": {
"API_KEY": "$EXTERNAL_SERVICE_TOKEN"
}
}
}
}
```
#### HTTP-based MCP Server
```json
{
"mcpServers": {
"httpServer": {
"httpUrl": "http://localhost:3000/mcp",
"timeout": 5000
}
}
}
```
## Discovery Process Deep Dive
When the Gemini CLI starts, it performs MCP server discovery through the following detailed process:
### 1. Server Iteration and Connection
For each configured server in `mcpServers`:
1. **Status tracking begins:** Server status is set to `CONNECTING`
2. **Transport selection:** Based on configuration properties:
- `httpUrl``StreamableHTTPClientTransport`
- `url``SSEClientTransport`
- `command``StdioClientTransport`
3. **Connection establishment:** The MCP client attempts to connect with the configured timeout
4. **Error handling:** Connection failures are logged and the server status is set to `DISCONNECTED`
### 2. Tool Discovery
Upon successful connection:
1. **Tool listing:** The client calls the MCP server's tool listing endpoint
2. **Schema validation:** Each tool's function declaration is validated
3. **Name sanitization:** Tool names are cleaned to meet Gemini API requirements:
- Invalid characters (non-alphanumeric, underscore, dot, hyphen) are replaced with underscores
- Names longer than 63 characters are truncated with middle replacement (`___`)
### 3. Conflict Resolution
When multiple servers expose tools with the same name:
1. **First registration wins:** The first server to register a tool name gets the unprefixed name
2. **Automatic prefixing:** Subsequent servers get prefixed names: `serverName__toolName`
3. **Registry tracking:** The tool registry maintains mappings between server names and their tools
### 4. Schema Processing
Tool parameter schemas undergo sanitization for Gemini API compatibility:
- **`$schema` properties** are removed
- **`additionalProperties`** are stripped
- **`anyOf` with `default`** have their default values removed (Vertex AI compatibility)
- **Recursive processing** applies to nested schemas
### 5. Connection Management
After discovery:
- **Persistent connections:** Servers that successfully register tools maintain their connections
- **Cleanup:** Servers that provide no usable tools have their connections closed
- **Status updates:** Final server statuses are set to `CONNECTED` or `DISCONNECTED`
## Tool Execution Flow
When the Gemini model decides to use an MCP tool, the following execution flow occurs:
### 1. Tool Invocation
The model generates a `FunctionCall` with:
- **Tool name:** The registered name (potentially prefixed)
- **Arguments:** JSON object matching the tool's parameter schema
### 2. Confirmation Process
Each `DiscoveredMCPTool` implements sophisticated confirmation logic:
#### Trust-based Bypass
```typescript
if (this.trust) {
return false; // No confirmation needed
}
```
#### Dynamic Allow-listing
The system maintains internal allow-lists for:
- **Server-level:** `serverName` → All tools from this server are trusted
- **Tool-level:** `serverName.toolName` → This specific tool is trusted
#### User Choice Handling
When confirmation is required, users can choose:
- **Proceed once:** Execute this time only
- **Always allow this tool:** Add to tool-level allow-list
- **Always allow this server:** Add to server-level allow-list
- **Cancel:** Abort execution
### 3. Execution
Upon confirmation (or trust bypass):
1. **Parameter preparation:** Arguments are validated against the tool's schema
2. **MCP call:** The underlying `CallableTool` invokes the server with:
```typescript
const functionCalls = [
{
name: this.serverToolName, // Original server tool name
args: params,
},
];
```
3. **Response processing:** Results are formatted for both LLM context and user display
### 4. Response Handling
The execution result contains:
- **`llmContent`:** Raw response parts for the language model's context
- **`returnDisplay`:** Formatted output for user display (often JSON in markdown code blocks)
## How to interact with your MCP server
### Using the `/mcp` Command
The `/mcp` command provides comprehensive information about your MCP server setup:
```bash
/mcp
```
This displays:
- **Server list:** All configured MCP servers
- **Connection status:** `CONNECTED`, `CONNECTING`, or `DISCONNECTED`
- **Server details:** Configuration summary (excluding sensitive data)
- **Available tools:** List of tools from each server with descriptions
- **Discovery state:** Overall discovery process status
### Example `/mcp` Output
```
MCP Servers Status:
📡 pythonTools (CONNECTED)
Command: python -m my_mcp_server --port 8080
Working Directory: ./mcp-servers/python
Timeout: 15000ms
Tools: calculate_sum, file_analyzer, data_processor
🔌 nodeServer (DISCONNECTED)
Command: node dist/server.js --verbose
Error: Connection refused
🐳 dockerizedServer (CONNECTED)
Command: docker run -i --rm -e API_KEY my-mcp-server:latest
Tools: docker__deploy, docker__status
Discovery State: COMPLETED
```
### Tool Usage
Once discovered, MCP tools are available to the Gemini model like built-in tools. The model will automatically:
1. **Select appropriate tools** based on your requests
2. **Present confirmation dialogs** (unless the server is trusted)
3. **Execute tools** with proper parameters
4. **Display results** in a user-friendly format
## Status Monitoring and Troubleshooting
### Connection States
The MCP integration tracks several states:
#### Server Status (`MCPServerStatus`)
- **`DISCONNECTED`:** Server is not connected or has errors
- **`CONNECTING`:** Connection attempt in progress
- **`CONNECTED`:** Server is connected and ready
#### Discovery State (`MCPDiscoveryState`)
- **`NOT_STARTED`:** Discovery hasn't begun
- **`IN_PROGRESS`:** Currently discovering servers
- **`COMPLETED`:** Discovery finished (with or without errors)
### Common Issues and Solutions
#### Server Won't Connect
**Symptoms:** Server shows `DISCONNECTED` status
**Troubleshooting:**
1. **Check configuration:** Verify `command`, `args`, and `cwd` are correct
2. **Test manually:** Run the server command directly to ensure it works
3. **Check dependencies:** Ensure all required packages are installed
4. **Review logs:** Look for error messages in the CLI output
5. **Verify permissions:** Ensure the CLI can execute the server command
#### No Tools Discovered
**Symptoms:** Server connects but no tools are available
**Troubleshooting:**
1. **Verify tool registration:** Ensure your server actually registers tools
2. **Check MCP protocol:** Confirm your server implements the MCP tool listing correctly
3. **Review server logs:** Check stderr output for server-side errors
4. **Test tool listing:** Manually test your server's tool discovery endpoint
#### Tools Not Executing
**Symptoms:** Tools are discovered but fail during execution
**Troubleshooting:**
1. **Parameter validation:** Ensure your tool accepts the expected parameters
2. **Schema compatibility:** Verify your input schemas are valid JSON Schema
3. **Error handling:** Check if your tool is throwing unhandled exceptions
4. **Timeout issues:** Consider increasing the `timeout` setting
#### Sandbox Compatibility
**Symptoms:** MCP servers fail when sandboxing is enabled
**Solutions:**
1. **Docker-based servers:** Use Docker containers that include all dependencies
2. **Path accessibility:** Ensure server executables are available in the sandbox
3. **Network access:** Configure sandbox to allow necessary network connections
4. **Environment variables:** Verify required environment variables are passed through
### Debugging Tips
1. **Enable debug mode:** Run the CLI with `--debug_mode` for verbose output
2. **Check stderr:** MCP server stderr is captured and logged (INFO messages filtered)
3. **Test isolation:** Test your MCP server independently before integrating
4. **Incremental setup:** Start with simple tools before adding complex functionality
5. **Use `/mcp` frequently:** Monitor server status during development
## Important Notes
### Security Considerations
- **Trust settings:** The `trust` option bypasses all confirmation dialogs. Use cautiously and only for servers you completely control
- **Access tokens:** Be security-aware when configuring environment variables containing API keys or tokens
- **Sandbox compatibility:** When using sandboxing, ensure MCP servers are available within the sandbox environment
- **Private data:** Using broadly scoped personal access tokens can lead to information leakage between repositories
### Performance and Resource Management
- **Connection persistence:** The CLI maintains persistent connections to servers that successfully register tools
- **Automatic cleanup:** Connections to servers providing no tools are automatically closed
- **Timeout management:** Configure appropriate timeouts based on your server's response characteristics
- **Resource monitoring:** MCP servers run as separate processes and consume system resources
### Schema Compatibility
- **Property stripping:** The system automatically removes certain schema properties (`$schema`, `additionalProperties`) for Gemini API compatibility
- **Name sanitization:** Tool names are automatically sanitized to meet API requirements
- **Conflict resolution:** Tool name conflicts between servers are resolved through automatic prefixing
This comprehensive integration makes MCP servers a powerful way to extend the Gemini CLI's capabilities while maintaining security, reliability, and ease of use.
+44
View File
@@ -0,0 +1,44 @@
# Memory Tool (`save_memory`)
This document describes the `save_memory` tool for the Gemini CLI.
## Description
Use `save_memory` to save and recall information across your Gemini CLI sessions. With `save_memory`, you can direct the CLI to remember key details across sessions, providing personalized and directed assistance.
### Arguments
`save_memory` takes one argument:
- `fact` (string, required): The specific fact or piece of information to remember. This should be a clear, self-contained statement written in natural language.
## How to use `save_memory` with the Gemini CLI
The tool appends the provided `fact` to a special `GEMINI.md` file located in the user's home directory (`~/.gemini/GEMINI.md`). This file can be configured to have a different name.
Once added, the facts are stored under a `## Gemini Added Memories` section. This file is loaded as context in subsequent sessions, allowing the CLI to recall the saved information.
Usage:
```
save_memory(fact="Your fact here.")
```
### `save_memory` examples
Remember a user preference:
```
save_memory(fact="My preferred programming language is Python.")
```
Store a project-specific detail:
```
save_memory(fact="The project I'm currently working on is called 'gemini-cli'.")
```
## Important notes
- **General usage:** This tool should be used for concise, important facts. It is not intended for storing large amounts of data or conversational history.
- **Memory file:** The memory file is a plain text Markdown file, so you can view and edit it manually if needed.
+66
View File
@@ -0,0 +1,66 @@
# Multi File Read Tool (`read_many_files`)
This document describes the `read_many_files` tool for the Gemini CLI.
## Description
Use `read_many_files` to read content from multiple files specified by paths or glob patterns. The behavior of this tool depends on the provided files:
- For text files, this tool concatenates their content into a single string.
- For image (e.g., PNG, JPEG) and PDF files, it reads and returns them as base64-encoded data, provided they are explicitly requested by name or extension.
`read_many_files` can be used to perform tasks such as getting an overview of a codebase, finding where specific functionality is implemented, reviewing documentation, or gathering context from multiple configuration files.
### Arguments
`read_many_files` takes the following arguments:
- `paths` (list[string], required): An array of glob patterns or paths relative to the tool's target directory (e.g., `["src/**/*.ts"]`, `["README.md", "docs/", "assets/logo.png"]`).
- `exclude` (list[string], optional): Glob patterns for files/directories to exclude (e.g., `["**/*.log", "temp/"]`). These are added to default excludes if `useDefaultExcludes` is true.
- `include` (list[string], optional): Additional glob patterns to include. These are merged with `paths` (e.g., `["*.test.ts"]` to specifically add test files if they were broadly excluded, or `["images/*.jpg"]` to include specific image types).
- `recursive` (boolean, optional): Whether to search recursively. This is primarily controlled by `**` in glob patterns. Defaults to `true`.
- `useDefaultExcludes` (boolean, optional): Whether to apply a list of default exclusion patterns (e.g., `node_modules`, `.git`, non image/pdf binary files). Defaults to `true`.
- `respect_git_ignore` (boolean, optional): Whether to respect .gitignore patterns when finding files. Defaults to true.
## How to use `read_many_files` with the Gemini CLI
`read_many_files` searches for files matching the provided `paths` and `include` patterns, while respecting `exclude` patterns and default excludes (if enabled).
- For text files: it reads the content of each matched file (attempting to skip binary files not explicitly requested as image/PDF) and concatenates it into a single string, with a separator `--- {filePath} ---` between the content of each file. Uses UTF-8 encoding by default.
- For image and PDF files: if explicitly requested by name or extension (e.g., `paths: ["logo.png"]` or `include: ["*.pdf"]`), the tool reads the file and returns its content as a base64 encoded string.
- The tool attempts to detect and skip other binary files (those not matching common image/PDF types or not explicitly requested) by checking for null bytes in their initial content.
Usage:
```
read_many_files(paths=["Your files or paths here."], include=["Additional files to include."], exclude=["Files to exclude."], recursive=False, useDefaultExcludes=false, respect_git_ignore=true)
```
## `read_many_files` examples
Read all TypeScript files in the `src` directory:
```
read_many_files(paths=["src/**/*.ts"])
```
Read the main README, all Markdown files in the `docs` directory, and a specific logo image, excluding a specific file:
```
read_many_files(paths=["README.md", "docs/**/*.md", "assets/logo.png"], exclude=["docs/OLD_README.md"])
```
Read all JavaScript files but explicitly including test files and all JPEGs in an `images` folder:
```
read_many_files(paths=["**/*.js"], include=["**/*.test.js", "images/**/*.jpg"], useDefaultExcludes=False)
```
## Important notes
- **Binary file handling:**
- **Image/PDF files:** The tool can read common image types (PNG, JPEG, etc.) and PDF files, returning them as base64 encoded data. These files _must_ be explicitly targeted by the `paths` or `include` patterns (e.g., by specifying the exact filename like `image.png` or a pattern like `*.jpeg`).
- **Other binary files:** The tool attempts to detect and skip other types of binary files by examining their initial content for null bytes. The tool excludes these files from its output.
- **Performance:** Reading a very large number of files or very large individual files can be resource-intensive.
- **Path specificity:** Ensure paths and glob patterns are correctly specified relative to the tool's target directory. For image/PDF files, ensure the patterns are specific enough to include them.
- **Default excludes:** Be aware of the default exclusion patterns (like `node_modules`, `.git`) and use `useDefaultExcludes=False` if you need to override them, but do so cautiously.
+61
View File
@@ -0,0 +1,61 @@
# Shell Tool (`run_shell_command`)
This document describes the `run_shell_command` tool for the Gemini CLI.
## Description
Use `run_shell_command` to interact with the underlying system, run scripts, or perform command-line operations. `run_shell_command` executes a given shell command. On Windows, the command will be executed with `cmd.exe /c`. On other platforms, the command will be executed with `bash -c`.
### Arguments
`run_shell_command` takes the following arguments:
- `command` (string, required): The exact shell command to execute.
- `description` (string, optional): A brief description of the command's purpose, which will be shown to the user.
- `directory` (string, optional): The directory (relative to the project root) in which to execute the command. If not provided, the command runs in the project root.
## How to use `run_shell_command` with the Gemini CLI
When using `run_shell_command`, the command is executed as a subprocess. `run_shell_command` can start background processes using `&`. The tool returns detailed information about the execution, including:
- `Command`: The command that was executed.
- `Directory`: The directory where the command was run.
- `Stdout`: Output from the standard output stream.
- `Stderr`: Output from the standard error stream.
- `Error`: Any error message reported by the subprocess.
- `Exit Code`: The exit code of the command.
- `Signal`: The signal number if the command was terminated by a signal.
- `Background PIDs`: A list of PIDs for any background processes started.
Usage:
```
run_shell_command(command="Your commands.", description="Your description of the command.", directory="Your execution directory.")
```
## `run_shell_command` examples
List files in the current directory:
```
run_shell_command(command="ls -la")
```
Run a script in a specific directory:
```
run_shell_command(command="./my_script.sh", directory="scripts", description="Run my custom script")
```
Start a background server:
```
run_shell_command(command="npm run dev &", description="Start development server in background")
```
## Important notes
- **Security:** Be cautious when executing commands, especially those constructed from user input, to prevent security vulnerabilities.
- **Interactive commands:** Avoid commands that require interactive user input, as this can cause the tool to hang. Use non-interactive flags if available (e.g., `npm init -y`).
- **Error handling:** Check the `Stderr`, `Error`, and `Exit Code` fields to determine if a command executed successfully.
- **Background processes:** When a command is run in the background with `&`, the tool will return immediately and the process will continue to run in the background. The `Background PIDs` field will contain the process ID of the background process.
+44
View File
@@ -0,0 +1,44 @@
# Web Fetch Tool (`web_fetch`)
This document describes the `web_fetch` tool for the Gemini CLI.
## Description
Use `web_fetch` to summarize, compare, or extract information from web pages. The `web_fetch` tool processes content from one or more URLs (up to 20) embedded in a prompt. `web_fetch` takes a natural language prompt and returns a generated response.
### Arguments
`web_fetch` takes one argument:
- `prompt` (string, required): A comprehensive prompt that includes the URL(s) (up to 20) to fetch and specific instructions on how to process their content. For example: `"Summarize https://example.com/article and extract key points from https://another.com/data"`. The prompt must contain at least one URL starting with `http://` or `https://`.
## How to use `web_fetch` with the Gemini CLI
To use `web_fetch` with the Gemini CLI, provide a natural language prompt that contains URLs. The tool will ask for confirmation before fetching any URLs. Once confirmed, the tool will process URLs through Gemini API's `urlContext`.
If the Gemini API cannot access the URL, the tool will fall back to fetching content directly from the local machine. The tool will format the response, including source attribution and citations where possible. The tool will then provide the response to the user.
Usage:
```
web_fetch(prompt="Your prompt, including a URL such as https://google.com.")
```
## `web_fetch` examples
Summarize a single article:
```
web_fetch(prompt="Can you summarize the main points of https://example.com/news/latest")
```
Compare two articles:
```
web_fetch(prompt="What are the differences in the conclusions of these two papers: https://arxiv.org/abs/2401.0001 and https://arxiv.org/abs/2401.0002?")
```
## Important notes
- **URL processing:** `web_fetch` relies on the Gemini API's ability to access and process the given URLs.
- **Output quality:** The quality of the output will depend on the clarity of the instructions in the prompt.
+36
View File
@@ -0,0 +1,36 @@
# Web Search Tool (`google_web_search`)
This document describes the `google_web_search` tool.
## Description
Use `google_web_search` to perform a web search using Google Search via the Gemini API. The `google_web_search` tool returns a summary of web results with sources.
### Arguments
`google_web_search` takes one argument:
- `query` (string, required): The search query.
## How to use `google_web_search` with the Gemini CLI
The `google_web_search` tool sends a query to the Gemini API, which then performs a web search. `google_web_search` will return a generated response based on the search results, including citations and sources.
Usage:
```
google_web_search(query="Your query goes here.")
```
## `google_web_search` examples
Get information on a topic:
```
google_web_search(query="latest advancements in AI-powered code generation")
```
## Important notes
- **Response returned:** The `google_web_search` tool returns a processed summary, not a raw list of search results.
- **Citations:** The response includes citations to the sources used to generate the summary.
+58
View File
@@ -0,0 +1,58 @@
# Gemini CLI: Terms of Service and Privacy Notice
Gemini CLI is an open-source tool that allows you to interact with Google's powerful language models directly from your command-line interface. The terms of service and privacy notices that apply to your usage of Gemini CLI depend on the type of account you use to authenticate with Google.
This article outlines the specific terms and privacy policies applicable for different auth methods.
## 1. Login with Google (Gemini Code Assist for [individuals](https://developers.google.com/gemini-code-assist/docs/overview#supported-features-gca))
For users who authenticate using their Google account to access Gemini Code Assist for individuals:
- Terms of Service: Your use of Gemini CLI is governed by the general [Google Terms of Service](https://policies.google.com/terms?hl=en-US).
- Privacy Notice: The collection and use of your data are described in the [Gemini Code Assist Privacy Notice for Individuals](https://developers.google.com/gemini-code-assist/resources/privacy-notice-gemini-code-assist-individuals).
## 2. Gemini API Key (Using Gemini Developer [API](https://ai.google.dev/gemini-api/docs) a: Unpaid Service, b: Paid Service)
If you are using a Gemini API key for authentication, the following terms apply:
- Terms of Service: Your use is subject to the [Gemini API Terms of Service](https://ai.google.dev/gemini-api/terms). For a. [Unpaid Service](https://ai.google.dev/gemini-api/terms#unpaid-services) or b. [Paid Service](https://ai.google.dev/gemini-api/terms#paid-services)
- Privacy Notice: Information regarding data handling and privacy is detailed in the general [Google Privacy Policy](https://policies.google.com/privacy).
## 3. Login with Google (for Workspace or Licensed Code Assist users)
For users of Standard or Enterprise [edition](https://cloud.google.com/gemini/docs/codeassist/overview#editions-overview) of Gemini Code Assist :
- Terms of Service: The [Google Cloud Platform Terms of Service](https://cloud.google.com/terms) govern your use of the service.
- Privacy Notice: The handling of your data is outlined in the [Gemini Code Assist Privacy Notices](https://developers.google.com/gemini-code-assist/resources/privacy-notices).
## 4. Vertex AI (Using Vertex AI Gen [API](https://cloud.google.com/vertex-ai/generative-ai/docs/reference/rest))
If you are using an API key with a Vertex AI Gen API backend:
- Terms of Service: Your usage is governed by the [Google Cloud Platform Service Terms](https://cloud.google.com/terms/service-terms/).
- Privacy Notice: The [Google Cloud Privacy Notice](https://cloud.google.com/terms/cloud-privacy-notice) describes how your data is collected and managed.
### Usage Statistics Opt-Out
You may opt-out from sending Usage Statistics to Google data by following the instructions available here: [Usage Statistics Configuration](./cli/configuration.md#usage-statistics).
## Frequently Asked Questions (FAQ) for Gemini CLI
### 1. Is my code, including prompts and answers, used to train Google's models?
This depends entirely on the type of auth method you use.
- **Auth method 1:** Yes. When you use your personal Google account, the Gemini Code Assist Privacy Notice for Individuals applies. Under this notice, your **prompts, answers, and related code are collected** and may be used to improve Google's products, which includes model training.
- **Auth method 2a:** Yes, When you use the Gemini API key Gemini API (Unpaid Service) terms apply. Under this notice , your **prompts, answers, and related code are collected** and may be used to improve Google's products, which includes model training.
- **Auth method 2b, 3 & 4:** No. For these accounts, your data is governed by the Google Cloud or Gemini API (Paid Service) terms, which treat your inputs as confidential. Your code, prompts, and other inputs are **not** used to train models.
### 2. What are "Usage Statistics" and what does the opt-out control?
The "Usage Statistics" setting is the single control for all optional data collection in the Gemini CLI. The data it collects depends on your account type:
- **Auth method 1:** When enabled, this setting allows Google to collect both anonymous telemetry (like commands run and performance metrics) and **your prompts and answers** for model improvement.
- **Auth method 2a:** When enabled, this setting allows Google to collect both anonymous telemetry (like commands run and performance metrics) and **your prompts and answers** for model improvement. When disabled we will use your data as described in the [How Google Uses Your Data](https://ai.google.dev/gemini-api/terms#data-use-unpaid).
- **Auth method 2b:** This setting only controls the collection of anonymous telemetry. Google logs prompts and responses for a limited period of time, solely for the purpose of detecting violations of the Prohibited Use Policy and any required legal or regulatory disclosures
- **Auth methods 3 & 4:** This setting only controls the collection of anonymous telemetry. Your prompts and answers are never collected, regardless of this setting.
You can disable Usage Statistics for any account type by following the instructions in the [Usage Statistics Configuration](./cli/configuration.md#usage-statistics) documentation.
+82
View File
@@ -0,0 +1,82 @@
# Troubleshooting Guide
This guide provides solutions to common issues and debugging tips.
## Authentication
- **Error: `Failed to login. Message: Request contains an invalid argument`**
- Users with Google Workspace accounts, or users with Google Cloud accounts
associated with their Gmail accounts may not be able to activate the free
tier of the Google Code Assist plan.
- For Google Cloud accounts, you can work around this by setting
`GOOGLE_CLOUD_PROJECT` to your project ID.
- You can also grab an API key from [AI
Studio](http://aistudio.google.com/app/apikey), which also includes a
separate free tier.
## Frequently asked questions (FAQs)
- **Q: How do I update Gemini CLI to the latest version?**
- A: If installed globally via npm, update Gemini CLI using the command `npm install -g @google/gemini-cli@latest`. If run from source, pull the latest changes from the repository and rebuild using `npm run build`.
- **Q: Where are Gemini CLI configuration files stored?**
- A: The CLI configuration is stored within two `settings.json` files: one in your home directory and one in your project's root directory. In both locations, `settings.json` is found in the `.gemini/` folder. Refer to [CLI Configuration](./cli/configuration.md) for more details.
- **Q: Why don't I see cached token counts in my stats output?**
- A: Cached token information is only displayed when cached tokens are being used. This feature is available for API key users (Gemini API key or Vertex AI) but not for OAuth users (Google Personal/Enterprise accounts) at this time, as the Code Assist API does not support cached content creation. You can still view your total token usage with the `/stats` command.
## Common error messages and solutions
- **Error: `EADDRINUSE` (Address already in use) when starting an MCP server.**
- **Cause:** Another process is already using the port the MCP server is trying to bind to.
- **Solution:**
Either stop the other process that is using the port or configure the MCP server to use a different port.
- **Error: Command not found (when attempting to run Gemini CLI).**
- **Cause:** Gemini CLI is not correctly installed or not in your system's PATH.
- **Solution:**
1. Ensure Gemini CLI installation was successful.
2. If installed globally, check that your npm global binary directory is in your PATH.
3. If running from source, ensure you are using the correct command to invoke it (e.g., `node packages/cli/dist/index.js ...`).
- **Error: `MODULE_NOT_FOUND` or import errors.**
- **Cause:** Dependencies are not installed correctly, or the project hasn't been built.
- **Solution:**
1. Run `npm install` to ensure all dependencies are present.
2. Run `npm run build` to compile the project.
- **Error: "Operation not permitted", "Permission denied", or similar.**
- **Cause:** If sandboxing is enabled, then the application is likely attempting an operation restricted by your sandbox, such as writing outside the project directory or system temp directory.
- **Solution:** See [Sandboxing](./cli/configuration.md#sandboxing) for more information, including how to customize your sandbox configuration.
## Debugging Tips
- **CLI debugging:**
- Use the `--verbose` flag (if available) with CLI commands for more detailed output.
- Check the CLI logs, often found in a user-specific configuration or cache directory.
- **Core debugging:**
- Check the server console output for error messages or stack traces.
- Increase log verbosity if configurable.
- Use Node.js debugging tools (e.g., `node --inspect`) if you need to step through server-side code.
- **Tool issues:**
- If a specific tool is failing, try to isolate the issue by running the simplest possible version of the command or operation the tool performs.
- For `run_shell_command`, check that the command works directly in your shell first.
- For file system tools, double-check paths and permissions.
- **Pre-flight checks:**
- Always run `npm run preflight` before committing code. This can catch many common issues related to formatting, linting, and type errors.
If you encounter an issue not covered here, consider searching the project's issue tracker on GitHub or reporting a new issue with detailed information.
+31
View File
@@ -0,0 +1,31 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import esbuild from 'esbuild';
import path from 'path';
import { fileURLToPath } from 'url';
import { createRequire } from 'module';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const require = createRequire(import.meta.url);
const pkg = require(path.resolve(__dirname, 'package.json'));
esbuild
.build({
entryPoints: ['packages/cli/index.ts'],
bundle: true,
outfile: 'bundle/gemini.js',
platform: 'node',
format: 'esm',
define: {
'process.env.CLI_VERSION': JSON.stringify(pkg.version),
},
banner: {
js: `import { createRequire } from 'module'; const require = createRequire(import.meta.url); globalThis.__filename = require('url').fileURLToPath(import.meta.url); globalThis.__dirname = require('path').dirname(globalThis.__filename);`,
},
})
.catch(() => process.exit(1));
@@ -0,0 +1,159 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Disallows relative imports between specified monorepo packages.
*/
'use strict';
import path from 'node:path';
import fs from 'node:fs';
/**
* Finds the package name by searching for the nearest `package.json` file
* in the directory hierarchy, starting from the given file's directory
* and moving upwards until the specified root directory is reached.
* It reads the `package.json` and extracts the `name` property.
*
* @requires module:path Node.js path module
* @requires module:fs Node.js fs module
*
* @param {string} filePath - The path (absolute or relative) to a file within the potential package structure.
* The search starts from the directory containing this file.
* @param {string} root - The absolute path to the root directory of the project/monorepo.
* The upward search stops when this directory is reached.
* @returns {string | undefined | null} The value of the `name` field from the first `package.json` found.
* Returns `undefined` if the `name` field doesn't exist in the found `package.json`.
* Returns `null` if no `package.json` is found before reaching the `root` directory.
* @throws {Error} Can throw an error if `fs.readFileSync` fails (e.g., permissions) or if `JSON.parse` fails on invalid JSON content.
*/
function findPackageName(filePath, root) {
let currentDir = path.dirname(path.resolve(filePath));
while (currentDir !== root) {
const parentDir = path.dirname(currentDir);
const packageJsonPath = path.join(currentDir, 'package.json');
if (fs.existsSync(packageJsonPath)) {
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
return pkg.name;
}
// Move up one level
currentDir = parentDir;
// Safety break if we somehow reached the root directly in the loop condition (less likely with path.resolve)
if (path.dirname(currentDir) === currentDir) break;
}
return null; // Not found within the expected structure
}
export default {
meta: {
type: 'problem',
docs: {
description: 'Disallow relative imports between packages.',
category: 'Best Practices',
recommended: 'error',
},
fixable: 'code',
schema: [
{
type: 'object',
properties: {
root: {
type: 'string',
description:
'Absolute path to the root of all relevant packages to consider.',
},
},
required: ['root'],
additionalProperties: false,
},
],
messages: {
noRelativePathsForCrossPackageImport:
"Relative import '{{importedPath}}' crosses package boundary from '{{importingPackage}}' to '{{importedPackage}}'. Use a direct package import ('{{importedPackage}}') instead.",
relativeImportIsInvalidPackage:
"Relative import '{{importedPath}}' does not reference a valid package. All source must be in a package directory.",
},
},
create(context) {
const options = context.options[0] || {};
const allPackagesRoot = options.root;
const currentFilePath = context.filename;
if (
!currentFilePath ||
currentFilePath === '<input>' ||
currentFilePath === '<text>'
) {
// Skip if filename is not available (e.g., linting raw text)
return {};
}
const currentPackage = findPackageName(currentFilePath, allPackagesRoot);
// If the current file isn't inside a package structure, don't apply the rule
if (!currentPackage) {
return {};
}
return {
ImportDeclaration(node) {
const importingPackage = currentPackage;
const importedPath = node.source.value;
// Only interested in relative paths
if (
!importedPath ||
typeof importedPath !== 'string' ||
!importedPath.startsWith('.')
) {
return;
}
// Resolve the absolute path of the imported module
const absoluteImportPath = path.resolve(
path.dirname(currentFilePath),
importedPath,
);
// Find the package information for the imported file
const importedPackage = findPackageName(
absoluteImportPath,
allPackagesRoot,
);
// If the imported file isn't in a recognized package, report issue
if (!importedPackage) {
context.report({
node: node.source,
messageId: 'relativeImportIsInvalidPackage',
data: { importedPath: importedPath },
});
return;
}
// The core check: Are the source and target packages different?
if (currentPackage !== importedPackage) {
// We found a relative import crossing package boundaries
context.report({
node: node.source, // Report the error on the source string literal
messageId: 'noRelativePathsForCrossPackageImport',
data: {
importedPath,
importedPackage,
importingPackage,
},
fix(fixer) {
return fixer.replaceText(node.source, `'${importedPackage}'`);
},
});
}
},
};
},
};
+221
View File
@@ -0,0 +1,221 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import reactPlugin from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import prettierConfig from 'eslint-config-prettier';
import importPlugin from 'eslint-plugin-import';
import globals from 'globals';
import licenseHeader from 'eslint-plugin-license-header';
import noRelativeCrossPackageImports from './eslint-rules/no-relative-cross-package-imports.js';
import path from 'node:path'; // Use node: prefix for built-ins
import url from 'node:url';
// --- ESM way to get __dirname ---
const __filename = url.fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// --- ---
// Determine the monorepo root (assuming eslint.config.js is at the root)
const projectRoot = __dirname;
export default tseslint.config(
{
// Global ignores
ignores: [
'node_modules/*',
'eslint.config.js',
'packages/cli/dist/**',
'packages/core/dist/**',
'packages/server/dist/**',
'eslint-rules/*',
'bundle/**',
],
},
eslint.configs.recommended,
...tseslint.configs.recommended,
reactHooks.configs['recommended-latest'],
reactPlugin.configs.flat.recommended,
reactPlugin.configs.flat['jsx-runtime'], // Add this if you are using React 17+
{
// Settings for eslint-plugin-react
settings: {
react: {
version: 'detect',
},
},
},
{
// Import specific config
files: ['packages/cli/src/**/*.{ts,tsx}'], // Target only TS/TSX in the cli package
plugins: {
import: importPlugin,
},
settings: {
'import/resolver': {
node: true,
},
},
rules: {
...importPlugin.configs.recommended.rules,
...importPlugin.configs.typescript.rules,
'import/no-default-export': 'warn',
'import/no-unresolved': 'off', // Disable for now, can be noisy with monorepos/paths
},
},
{
// General overrides and rules for the project (TS/TSX files)
files: ['packages/*/src/**/*.{ts,tsx}'], // Target only TS/TSX in the cli package
languageOptions: {
globals: {
...globals.node,
...globals.es2021,
},
},
rules: {
// General Best Practice Rules (subset adapted for flat config)
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
'arrow-body-style': ['error', 'as-needed'],
curly: ['error', 'multi-line'],
eqeqeq: ['error', 'always', { null: 'ignore' }],
'@typescript-eslint/consistent-type-assertions': [
'error',
{ assertionStyle: 'as' },
],
'@typescript-eslint/explicit-member-accessibility': [
'error',
{ accessibility: 'no-public' },
],
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-inferrable-types': [
'error',
{ ignoreParameters: true, ignoreProperties: true },
],
'@typescript-eslint/no-namespace': ['error', { allowDeclarations: true }],
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
'no-cond-assign': 'error',
'no-debugger': 'error',
'no-duplicate-case': 'error',
'no-restricted-syntax': [
'error',
{
selector: 'CallExpression[callee.name="require"]',
message: 'Avoid using require(). Use ES6 imports instead.',
},
{
selector: 'ThrowStatement > Literal:not([value=/^\\w+Error:/])',
message:
'Do not throw string literals or non-Error objects. Throw new Error("...") instead.',
},
],
'no-unsafe-finally': 'error',
'no-unused-expressions': 'off', // Disable base rule
'@typescript-eslint/no-unused-expressions': [
// Enable TS version
'error',
{ allowShortCircuit: true, allowTernary: true },
],
'no-var': 'error',
'object-shorthand': 'error',
'one-var': ['error', 'never'],
'prefer-arrow-callback': 'error',
'prefer-const': ['error', { destructuring: 'all' }],
radix: 'error',
'default-case': 'error',
},
},
{
files: ['./**/*.{tsx,ts,js}'],
plugins: {
'license-header': licenseHeader,
},
rules: {
'license-header/header': [
'error',
[
'/**',
' * @license',
' * Copyright 2025 Google LLC',
' * SPDX-License-Identifier: Apache-2.0',
' */',
],
],
},
},
// extra settings for scripts that we run directly with node
{
files: ['./scripts/**/*.js', 'esbuild.config.js'],
languageOptions: {
globals: {
...globals.node,
process: 'readonly',
console: 'readonly',
},
},
rules: {
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
},
},
// Prettier config must be last
prettierConfig,
// extra settings for scripts that we run directly with node
{
files: ['./integration-tests/**/*.js'],
languageOptions: {
globals: {
...globals.node,
process: 'readonly',
console: 'readonly',
},
},
rules: {
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
},
},
// Custom eslint rules for this repo
{
files: ['packages/**/*.{js,jsx,ts,tsx}'],
plugins: {
custom: {
rules: {
'no-relative-cross-package-imports': noRelativeCrossPackageImports,
},
},
},
rules: {
// Enable and configure your custom rule
'custom/no-relative-cross-package-imports': [
'error',
{
root: path.join(projectRoot, 'packages'),
},
],
},
},
);
+30
View File
@@ -0,0 +1,30 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { strict as assert } from 'assert';
import { test } from 'node:test';
import { TestRig } from './test-helper.js';
test('reads a file', (t) => {
const rig = new TestRig();
rig.setup(t.name);
rig.createFile('test.txt', 'hello world');
const output = rig.run(`read the file name test.txt`);
assert.ok(output.toLowerCase().includes('hello'));
});
test('writes a file', (t) => {
const rig = new TestRig();
rig.setup(t.name);
rig.createFile('test.txt', '');
rig.run(`edit test.txt to have a hello world message`);
const fileContent = rig.readFile('test.txt');
assert.ok(fileContent.toLowerCase().includes('hello'));
});
@@ -0,0 +1,19 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { test } from 'node:test';
import { strict as assert } from 'assert';
import { TestRig } from './test-helper.js';
test('should be able to search the web', async (t) => {
const rig = new TestRig();
rig.setup(t.name);
const prompt = `what planet do we live on`;
const result = await rig.run(prompt);
assert.ok(result.toLowerCase().includes('earth'));
});
+23
View File
@@ -0,0 +1,23 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { test } from 'node:test';
import { strict as assert } from 'assert';
import { TestRig } from './test-helper.js';
test('should be able to list a directory', async (t) => {
const rig = new TestRig();
rig.setup(t.name);
rig.createFile('file1.txt', 'file 1 content');
rig.mkdir('subdir');
rig.sync();
const prompt = `Can you list the files in the current directory`;
const result = await rig.run(prompt);
assert.ok(result.includes('file1.txt'));
assert.ok(result.includes('subdir'));
});
+22
View File
@@ -0,0 +1,22 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { test } from 'node:test';
import { strict as assert } from 'assert';
import { TestRig } from './test-helper.js';
test.skip('should be able to read multiple files', async (t) => {
const rig = new TestRig();
rig.setup(t.name);
rig.createFile('file1.txt', 'file 1 content');
rig.createFile('file2.txt', 'file 2 content');
const prompt = `Read the files in this directory, list them and print them to the screen`;
const result = await rig.run(prompt);
assert.ok(result.includes('file 1 content'));
assert.ok(result.includes('file 2 content'));
});
+22
View File
@@ -0,0 +1,22 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { test } from 'node:test';
import { strict as assert } from 'assert';
import { TestRig } from './test-helper.js';
test('should be able to replace content in a file', async (t) => {
const rig = new TestRig();
rig.setup(t.name);
const fileName = 'file_to_replace.txt';
rig.createFile(fileName, 'original content');
const prompt = `Can you replace 'original' with 'replaced' in the file 'file_to_replace.txt'`;
await rig.run(prompt);
const newFileContent = rig.readFile(fileName);
assert.strictEqual(newFileContent, 'replaced content');
});
+123
View File
@@ -0,0 +1,123 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { spawnSync } from 'child_process';
import { spawn } from 'child_process';
import { mkdirSync, rmSync, createWriteStream } from 'fs';
import { join, dirname, basename } from 'path';
import { fileURLToPath } from 'url';
import { glob } from 'glob';
async function main() {
const __dirname = dirname(fileURLToPath(import.meta.url));
const rootDir = join(__dirname, '..');
const integrationTestsDir = join(rootDir, '.integration-tests');
if (process.env.GEMINI_SANDBOX === 'docker' && !process.env.IS_DOCKER) {
console.log('Building sandbox for Docker...');
const buildResult = spawnSync('npm', ['run', 'build:all'], {
stdio: 'inherit',
});
if (buildResult.status !== 0) {
console.error('Sandbox build failed.');
process.exit(1);
}
}
const runId = `${Date.now()}`;
const runDir = join(integrationTestsDir, runId);
mkdirSync(runDir, { recursive: true });
const args = process.argv.slice(2);
const keepOutput =
process.env.KEEP_OUTPUT === 'true' || args.includes('--keep-output');
if (keepOutput) {
const keepOutputIndex = args.indexOf('--keep-output');
if (keepOutputIndex > -1) {
args.splice(keepOutputIndex, 1);
}
console.log(`Keeping output for test run in: ${runDir}`);
}
const verbose = args.includes('--verbose');
if (verbose) {
const verboseIndex = args.indexOf('--verbose');
if (verboseIndex > -1) {
args.splice(verboseIndex, 1);
}
}
const testPatterns =
args.length > 0
? args.map((arg) => `integration-tests/${arg}.test.js`)
: ['integration-tests/*.test.js'];
const testFiles = glob.sync(testPatterns, { cwd: rootDir, absolute: true });
for (const testFile of testFiles) {
const testFileName = basename(testFile);
console.log(`\tFound test file: ${testFileName}`);
}
let allTestsPassed = true;
for (const testFile of testFiles) {
const testFileName = basename(testFile);
const testFileDir = join(runDir, testFileName);
mkdirSync(testFileDir, { recursive: true });
console.log(
`------------- Running test file: ${testFileName} ------------------------------`,
);
const child = spawn('node', ['--test', testFile], {
stdio: 'pipe',
env: {
...process.env,
GEMINI_CLI_INTEGRATION_TEST: 'true',
INTEGRATION_TEST_FILE_DIR: testFileDir,
KEEP_OUTPUT: keepOutput.toString(),
TEST_FILE_NAME: testFileName,
},
});
if (verbose) {
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
}
if (keepOutput) {
const outputFile = join(testFileDir, 'output.log');
const outputStream = createWriteStream(outputFile);
child.stdout.pipe(outputStream);
child.stderr.pipe(outputStream);
console.log(`Output for ${testFileName} written to: ${outputFile}`);
} else if (!verbose) {
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
}
const exitCode = await new Promise((resolve) => {
child.on('close', resolve);
});
if (exitCode !== 0) {
console.error(`Test file failed: ${testFileName}`);
allTestsPassed = false;
}
}
if (!keepOutput) {
rmSync(runDir, { recursive: true, force: true });
}
if (!allTestsPassed) {
console.error('One or more test files failed.');
process.exit(1);
}
}
main();
@@ -0,0 +1,20 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { test } from 'node:test';
import { strict as assert } from 'assert';
import { TestRig } from './test-helper.js';
test('should be able to run a shell command', async (t) => {
const rig = new TestRig();
rig.setup(t.name);
rig.createFile('blah.txt', 'some content');
const prompt = `Can you use ls to list the contexts of the current folder`;
const result = await rig.run(prompt);
assert.ok(result.includes('blah.txt'));
});
+21
View File
@@ -0,0 +1,21 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { test } from 'node:test';
import { strict as assert } from 'assert';
import { TestRig } from './test-helper.js';
test('should be able to save to memory', async (t) => {
const rig = new TestRig();
rig.setup(t.name);
const prompt = `remember that my favorite color is blue.
what is my favorite color? tell me that and surround it with $ symbol`;
const result = await rig.run(prompt);
assert.ok(result.toLowerCase().includes('$blue$'));
});
@@ -0,0 +1,70 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { test, describe, before, after } from 'node:test';
import { strict as assert } from 'node:assert';
import { TestRig } from './test-helper.js';
import { spawn } from 'child_process';
import { join } from 'path';
import { fileURLToPath } from 'url';
import { writeFileSync, unlinkSync } from 'fs';
const __dirname = fileURLToPath(new URL('.', import.meta.url));
const serverScriptPath = join(__dirname, './temp-server.js');
const serverScript = `
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
const server = new McpServer({
name: 'addition-server',
version: '1.0.0',
});
server.registerTool(
'add',
{
title: 'Addition Tool',
description: 'Add two numbers',
inputSchema: { a: z.number(), b: z.number() },
},
async ({ a, b }) => ({
content: [{ type: 'text', text: String(a + b) }],
}),
);
const transport = new StdioServerTransport();
await server.connect(transport);
`;
describe('simple-mcp-server', () => {
const rig = new TestRig();
let child;
before(() => {
writeFileSync(serverScriptPath, serverScript);
child = spawn('node', [serverScriptPath], {
stdio: ['pipe', 'pipe', 'pipe'],
});
child.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
// Wait for the server to be ready
return new Promise((resolve) => setTimeout(resolve, 500));
});
after(() => {
child.kill();
unlinkSync(serverScriptPath);
});
test('should add two numbers', () => {
rig.setup('should add two numbers');
const output = rig.run('add 5 and 10');
assert.ok(output.includes('15'));
});
});
+85
View File
@@ -0,0 +1,85 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { execSync } from 'child_process';
import { mkdirSync, writeFileSync, readFileSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import { env } from 'process';
const __dirname = dirname(fileURLToPath(import.meta.url));
function sanitizeTestName(name) {
return name
.toLowerCase()
.replace(/[^a-z0-9]/g, '-')
.replace(/-+/g, '-');
}
export class TestRig {
constructor() {
this.bundlePath = join(__dirname, '..', 'bundle/gemini.js');
this.testDir = null;
}
setup(testName) {
this.testName = testName;
const sanitizedName = sanitizeTestName(testName);
this.testDir = join(env.INTEGRATION_TEST_FILE_DIR, sanitizedName);
mkdirSync(this.testDir, { recursive: true });
}
createFile(fileName, content) {
const filePath = join(this.testDir, fileName);
writeFileSync(filePath, content);
return filePath;
}
mkdir(dir) {
mkdirSync(join(this.testDir, dir));
}
sync() {
// ensure file system is done before spawning
execSync('sync', { cwd: this.testDir });
}
run(prompt, ...args) {
const output = execSync(
`node ${this.bundlePath} --yolo --prompt "${prompt}" ${args.join(' ')}`,
{
cwd: this.testDir,
encoding: 'utf-8',
},
);
if (env.KEEP_OUTPUT === 'true') {
const testId = `${env.TEST_FILE_NAME.replace(
'.test.js',
'',
)}:${this.testName.replace(/ /g, '-')}`;
console.log(`--- TEST: ${testId} ---`);
console.log(output);
console.log(`--- END TEST: ${testId} ---`);
}
return output;
}
readFile(fileName) {
const content = readFileSync(join(this.testDir, fileName), 'utf-8');
if (env.KEEP_OUTPUT === 'true') {
const testId = `${env.TEST_FILE_NAME.replace(
'.test.js',
'',
)}:${this.testName.replace(/ /g, '-')}`;
console.log(`--- FILE: ${testId}/${fileName} ---`);
console.log(content);
console.log(`--- END FILE: ${testId}/${fileName} ---`);
}
return content;
}
}
+21
View File
@@ -0,0 +1,21 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { test } from 'node:test';
import { strict as assert } from 'assert';
import { TestRig } from './test-helper.js';
test('should be able to write a file', async (t) => {
const rig = new TestRig();
rig.setup(t.name);
const prompt = `show me an example of using the write tool. put a dad joke in dad.txt`;
await rig.run(prompt);
const newFilePath = 'dad.txt';
const newFileContent = rig.readFile(newFilePath);
assert.notEqual(newFileContent, '');
});
+10409 -260
View File
File diff suppressed because it is too large Load Diff
+81 -6
View File
@@ -1,13 +1,88 @@
{
"name": "gemini-code",
"version": "1.0.0",
"private": true,
"name": "@google/gemini-cli",
"version": "0.1.6",
"engines": {
"node": ">=18.0.0"
},
"type": "module",
"workspaces": [
"packages/*"
],
"repository": "google-gemini/gemini-cli",
"config": {
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.1.5"
},
"scripts": {
"build": "npm run build --workspaces",
"generate": "node scripts/generate-git-commit-info.js",
"build": "node scripts/build.js",
"build:sandbox": "node scripts/build_sandbox.js",
"build:all": "npm run build && npm run build:sandbox",
"clean": "node scripts/clean.js",
"prepare": "npm run bundle",
"test": "npm run test --workspaces",
"start": "npm run start --workspace=gemini-code-cli"
}
"test:ci": "npm run test:ci --workspaces --if-present",
"test:e2e": "npm run test:integration:sandbox:none -- --verbose --keep-output",
"test:integration:all": "npm run test:integration:sandbox:none && npm run test:integration:sandbox:docker && npm run test:integration:sandbox:podman",
"test:integration:sandbox:none": "GEMINI_SANDBOX=false node integration-tests/run-tests.js",
"test:integration:sandbox:docker": "GEMINI_SANDBOX=docker node integration-tests/run-tests.js",
"test:integration:sandbox:podman": "GEMINI_SANDBOX=podman node integration-tests/run-tests.js",
"start": "node scripts/start.js",
"debug": "cross-env DEBUG=1 node --inspect-brk scripts/start.js",
"lint:fix": "eslint . --fix && eslint integration-tests --fix",
"lint": "eslint . --ext .ts,.tsx && eslint integration-tests",
"lint:ci": "eslint . --ext .ts,.tsx --max-warnings 0 && eslint integration-tests --max-warnings 0",
"typecheck": "npm run typecheck --workspaces --if-present",
"format": "prettier --write .",
"preflight": "npm run clean && npm ci && npm run format && npm run lint:ci && npm run build && npm run typecheck && npm run test:ci",
"auth:npm": "npx google-artifactregistry-auth",
"auth:docker": "gcloud auth configure-docker us-west1-docker.pkg.dev",
"auth": "npm run auth:npm && npm run auth:docker",
"prerelease:dev": "npm run prerelease:version --workspaces && npm run prerelease:deps --workspaces",
"bundle": "npm run generate && node esbuild.config.js && node scripts/copy_bundle_assets.js",
"build:cli": "npm run build --workspace packages/cli",
"build:core": "npm run build --workspace packages/core",
"build:packages": "npm run build:core && npm run build:cli",
"build:sandbox:fast": "node scripts/build_sandbox.js --skip-npm-install-build",
"prepare:cli-packagejson": "node scripts/prepare-cli-packagejson.js",
"prepare:packages": "node scripts/prepare-cli-packagejson.js && node scripts/prepare-core-package.js",
"publish:sandbox": "node scripts/publish-sandbox.js",
"publish:npm": "npm publish --workspaces ${NPM_PUBLISH_TAG:+--tag=$NPM_PUBLISH_TAG} ${NPM_DRY_RUN:+--dry-run}",
"publish:release": "npm run build:packages && npm run prepare:cli-packagejson && npm run build:sandbox:fast && npm run publish:sandbox && npm run publish:npm",
"telemetry": "node scripts/telemetry.js",
"start:gcp": "concurrently --raw --kill-others \"npm run telemetry -- --target=gcp\" \"npm start\"",
"prepublishOnly": "node scripts/prepublish.js"
},
"bin": {
"gemini": "bundle/gemini.js"
},
"files": [
"bundle/",
"README.md",
"LICENSE"
],
"devDependencies": {
"@types/micromatch": "^4.0.9",
"@types/mime-types": "^2.1.4",
"@types/minimatch": "^5.1.2",
"@vitest/coverage-v8": "^3.1.1",
"concurrently": "^9.2.0",
"cross-env": "^7.0.3",
"esbuild": "^0.25.0",
"eslint": "^9.24.0",
"eslint-config-prettier": "^10.1.2",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-license-header": "^0.8.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
"glob": "^10.4.5",
"globals": "^16.0.0",
"json": "^11.0.0",
"lodash": "^4.17.21",
"memfs": "^4.17.2",
"prettier": "^3.5.3",
"react-devtools-core": "^4.28.5",
"typescript-eslint": "^8.30.1",
"yargs": "^17.7.2"
},
"dependencies": {}
}
-34
View File
@@ -1,34 +0,0 @@
# Gemini Code CLI
This package contains the core command-line interface for Gemini Code.
## Building
To build only the CLI package, navigate to this directory (`packages/cli`) and run:
```bash
npm run build
```
This command executes the TypeScript compiler (`tsc`) as defined in this package's `package.json`. Ensure dependencies have been installed from the root directory (`npm install`) first.
## Running
To start the Gemini Code CLI directly from this directory:
```bash
npm start
```
This command executes `node dist/gemini.js` as defined in this package's `package.json`.
## Debugging
To debug the CLI application using VS Code:
1. Start the CLI in debug mode from this directory (`packages/cli`):
```bash
npm run debug
```
This command runs `node --inspect-brk dist/gemini.js`, pausing execution until a debugger attaches.
2. In VS Code (opened at the root of the monorepo), use the "Attach" launch configuration (found in `.vscode/launch.json`). This configuration is set up to attach to the Node.js process listening on port 9229, which is the default port used by `--inspect-brk`.
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env node
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import './src/gemini.js';
import { main } from './src/gemini.js';
// --- Global Entry Point ---
main().catch((error) => {
console.error('An unexpected critical error occurred:');
if (error instanceof Error) {
console.error(error.stack);
} else {
console.error(String(error));
}
process.exit(1);
});
+74 -36
View File
@@ -1,38 +1,76 @@
{
"name": "gemini-code-cli",
"version": "1.0.0",
"description": "Gemini Code CLI",
"type": "module",
"main": "dist/gemini.js",
"scripts": {
"build": "tsc",
"start": "node dist/gemini.js",
"debug": "node --inspect-brk dist/gemini.js"
},
"files": [
"dist"
],
"dependencies": {
"@google/genai": "^0.8.0",
"diff": "^7.0.0",
"dotenv": "^16.4.7",
"fast-glob": "^3.3.3",
"ink": "^5.2.0",
"ink-select-input": "^6.0.0",
"ink-spinner": "^5.0.0",
"ink-text-input": "^6.0.0",
"react": "^18.3.1",
"yargs": "^17.7.2"
},
"devDependencies": {
"@types/diff": "^7.0.2",
"@types/dotenv": "^6.1.1",
"@types/node": "^20.11.24",
"@types/react": "^19.1.0",
"@types/yargs": "^17.0.32",
"typescript": "^5.3.3"
},
"engines": {
"node": ">=18"
}
"name": "@google/gemini-cli",
"version": "0.1.6",
"description": "Gemini CLI",
"repository": "google-gemini/gemini-cli",
"type": "module",
"main": "dist/index.js",
"bin": {
"gemini": "dist/index.js"
},
"scripts": {
"build": "node ../../scripts/build_package.js",
"clean": "rm -rf dist",
"start": "node dist/index.js",
"debug": "node --inspect-brk dist/index.js",
"lint": "eslint . --ext .ts,.tsx",
"format": "prettier --write .",
"test": "vitest run",
"test:ci": "vitest run --coverage",
"typecheck": "tsc --noEmit",
"prerelease:version": "node ../../scripts/bind_package_version.js",
"prerelease:deps": "node ../../scripts/bind_package_dependencies.js",
"prepack": "npm run build",
"prepublishOnly": "node ../../scripts/prepublish.js"
},
"files": [
"dist"
],
"config": {
"sandboxImageUri": "gemini-cli-sandbox"
},
"dependencies": {
"@google/gemini-cli-core": "*",
"@types/update-notifier": "^6.0.8",
"command-exists": "^1.2.9",
"diff": "^7.0.0",
"dotenv": "^16.4.7",
"glob": "^10.4.1",
"highlight.js": "^11.11.1",
"ink": "^5.2.0",
"ink-big-text": "^2.0.0",
"ink-gradient": "^3.0.0",
"ink-select-input": "^6.0.0",
"ink-spinner": "^5.0.0",
"ink-link": "^4.0.0",
"ink-text-input": "^6.0.0",
"lowlight": "^3.3.0",
"mime-types": "^2.1.4",
"open": "^10.1.2",
"react": "^18.3.1",
"read-package-up": "^11.0.0",
"shell-quote": "^1.8.2",
"string-width": "^7.1.0",
"strip-ansi": "^7.1.0",
"strip-json-comments": "^3.1.1",
"update-notifier": "^7.3.1",
"yargs": "^17.7.2"
},
"devDependencies": {
"@testing-library/react": "^14.0.0",
"@types/command-exists": "^1.2.3",
"@types/diff": "^7.0.2",
"@types/dotenv": "^6.1.1",
"@types/node": "^20.11.24",
"@types/react": "^18.3.1",
"@types/shell-quote": "^1.7.5",
"@types/yargs": "^17.0.32",
"ink-testing-library": "^4.0.0",
"jsdom": "^26.1.0",
"typescript": "^5.3.3",
"vitest": "^3.1.1"
},
"engines": {
"node": ">=18"
}
}
-34
View File
@@ -1,34 +0,0 @@
import yargs from 'yargs/yargs';
import { hideBin } from 'yargs/helpers';
export interface CliArgs {
target_dir: string | undefined;
_: (string | number)[]; // Captures positional arguments
// Add other expected args here if needed
// e.g., verbose?: boolean;
}
export async function parseArguments(): Promise<CliArgs> {
const argv = await yargs(hideBin(process.argv))
.option('target_dir', {
alias: 'd',
type: 'string',
description:
'The target directory for Gemini operations. Defaults to the current working directory.',
})
.help()
.alias('h', 'help')
.strict() // Keep strict mode to error on unknown options
.parseAsync();
// Handle warnings for extra arguments here
if (argv._ && argv._.length > 0) {
console.warn(
`Warning: Additional arguments provided (${argv._.join(', ')}), but will be ignored.`
);
}
// Cast to the interface to ensure the structure aligns with expectations
// Use `unknown` first for safer casting if types might not perfectly match
return argv as unknown as CliArgs;
}
+39
View File
@@ -0,0 +1,39 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { AuthType } from '@google/gemini-cli-core';
import { loadEnvironment } from './config.js';
export const validateAuthMethod = (authMethod: string): string | null => {
loadEnvironment();
if (authMethod === AuthType.LOGIN_WITH_GOOGLE_PERSONAL) {
return null;
}
if (authMethod === AuthType.USE_GEMINI) {
if (!process.env.GEMINI_API_KEY) {
return 'GEMINI_API_KEY environment variable not found. Add that to your .env and try again, no reload needed!';
}
return null;
}
if (authMethod === AuthType.USE_VERTEX_AI) {
const hasVertexProjectLocationConfig =
!!process.env.GOOGLE_CLOUD_PROJECT && !!process.env.GOOGLE_CLOUD_LOCATION;
const hasGoogleApiKey = !!process.env.GOOGLE_API_KEY;
if (!hasVertexProjectLocationConfig && !hasGoogleApiKey) {
return (
'Must specify GOOGLE_GENAI_USE_VERTEXAI=true and either:\n' +
'• GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION environment variables.\n' +
'• GOOGLE_API_KEY environment variable (if using express mode).\n' +
'Update your .env and try again, no reload needed!'
);
}
return null;
}
return 'Invalid auth method selected.';
};
@@ -0,0 +1,243 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
import * as fs from 'fs';
import * as path from 'path';
import { tmpdir } from 'os';
import {
Config,
ConfigParameters,
ContentGeneratorConfig,
} from '@google/gemini-cli-core';
const TEST_CONTENT_GENERATOR_CONFIG: ContentGeneratorConfig = {
apiKey: 'test-key',
model: 'test-model',
userAgent: 'test-agent',
};
// Mock file discovery service and tool registry
vi.mock('@google/gemini-cli-core', async () => {
const actual = await vi.importActual('@google/gemini-cli-core');
return {
...actual,
FileDiscoveryService: vi.fn().mockImplementation(() => ({
initialize: vi.fn(),
})),
createToolRegistry: vi.fn().mockResolvedValue({}),
};
});
describe('Configuration Integration Tests', () => {
let tempDir: string;
let originalEnv: NodeJS.ProcessEnv;
beforeEach(() => {
tempDir = fs.mkdtempSync(path.join(tmpdir(), 'gemini-cli-test-'));
originalEnv = { ...process.env };
process.env.GEMINI_API_KEY = 'test-api-key';
vi.clearAllMocks();
});
afterEach(() => {
process.env = originalEnv;
if (fs.existsSync(tempDir)) {
fs.rmSync(tempDir, { recursive: true });
}
});
describe('File Filtering Configuration', () => {
it('should load default file filtering settings', async () => {
const configParams: ConfigParameters = {
cwd: '/tmp',
contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG,
embeddingModel: 'test-embedding-model',
sandbox: false,
targetDir: tempDir,
debugMode: false,
fileFilteringRespectGitIgnore: undefined, // Should default to true
};
const config = new Config(configParams);
expect(config.getFileFilteringRespectGitIgnore()).toBe(true);
});
it('should load custom file filtering settings from configuration', async () => {
const configParams: ConfigParameters = {
cwd: '/tmp',
contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG,
embeddingModel: 'test-embedding-model',
sandbox: false,
targetDir: tempDir,
debugMode: false,
fileFiltering: {
respectGitIgnore: false,
},
};
const config = new Config(configParams);
expect(config.getFileFilteringRespectGitIgnore()).toBe(false);
});
it('should merge user and workspace file filtering settings', async () => {
const configParams: ConfigParameters = {
cwd: '/tmp',
contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG,
embeddingModel: 'test-embedding-model',
sandbox: false,
targetDir: tempDir,
debugMode: false,
fileFilteringRespectGitIgnore: true,
};
const config = new Config(configParams);
expect(config.getFileFilteringRespectGitIgnore()).toBe(true);
});
});
describe('Configuration Integration', () => {
it('should handle partial configuration objects gracefully', async () => {
const configParams: ConfigParameters = {
cwd: '/tmp',
contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG,
embeddingModel: 'test-embedding-model',
sandbox: false,
targetDir: tempDir,
debugMode: false,
fileFiltering: {
respectGitIgnore: false,
},
};
const config = new Config(configParams);
// Specified settings should be applied
expect(config.getFileFilteringRespectGitIgnore()).toBe(false);
});
it('should handle empty configuration objects gracefully', async () => {
const configParams: ConfigParameters = {
cwd: '/tmp',
contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG,
embeddingModel: 'test-embedding-model',
sandbox: false,
targetDir: tempDir,
debugMode: false,
fileFilteringRespectGitIgnore: undefined,
};
const config = new Config(configParams);
// All settings should use defaults
expect(config.getFileFilteringRespectGitIgnore()).toBe(true);
});
it('should handle missing configuration sections gracefully', async () => {
const configParams: ConfigParameters = {
cwd: '/tmp',
contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG,
embeddingModel: 'test-embedding-model',
sandbox: false,
targetDir: tempDir,
debugMode: false,
// Missing fileFiltering configuration
};
const config = new Config(configParams);
// All git-aware settings should use defaults
expect(config.getFileFilteringRespectGitIgnore()).toBe(true);
});
});
describe('Real-world Configuration Scenarios', () => {
it('should handle a security-focused configuration', async () => {
const configParams: ConfigParameters = {
cwd: '/tmp',
contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG,
embeddingModel: 'test-embedding-model',
sandbox: false,
targetDir: tempDir,
debugMode: false,
fileFilteringRespectGitIgnore: true,
};
const config = new Config(configParams);
expect(config.getFileFilteringRespectGitIgnore()).toBe(true);
});
it('should handle a CI/CD environment configuration', async () => {
const configParams: ConfigParameters = {
cwd: '/tmp',
contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG,
embeddingModel: 'test-embedding-model',
sandbox: false,
targetDir: tempDir,
debugMode: false,
fileFiltering: {
respectGitIgnore: false,
}, // CI might need to see all files
};
const config = new Config(configParams);
expect(config.getFileFilteringRespectGitIgnore()).toBe(false);
});
});
describe('Checkpointing Configuration', () => {
it('should enable checkpointing when the setting is true', async () => {
const configParams: ConfigParameters = {
cwd: '/tmp',
contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG,
embeddingModel: 'test-embedding-model',
sandbox: false,
targetDir: tempDir,
debugMode: false,
checkpointing: true,
};
const config = new Config(configParams);
expect(config.getCheckpointingEnabled()).toBe(true);
});
});
describe('Extension Context Files', () => {
it('should have an empty array for extension context files by default', () => {
const configParams: ConfigParameters = {
cwd: '/tmp',
contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG,
embeddingModel: 'test-embedding-model',
sandbox: false,
targetDir: tempDir,
debugMode: false,
};
const config = new Config(configParams);
expect(config.getExtensionContextFilePaths()).toEqual([]);
});
it('should correctly store and return extension context file paths', () => {
const contextFiles = ['/path/to/file1.txt', '/path/to/file2.js'];
const configParams: ConfigParameters = {
cwd: '/tmp',
contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG,
embeddingModel: 'test-embedding-model',
sandbox: false,
targetDir: tempDir,
debugMode: false,
extensionContextFilePaths: contextFiles,
};
const config = new Config(configParams);
expect(config.getExtensionContextFilePaths()).toEqual(contextFiles);
});
});
});
+352
View File
@@ -0,0 +1,352 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import * as os from 'os';
import { loadCliConfig } from './config.js';
import { Settings } from './settings.js';
import { Extension } from './extension.js';
import * as ServerConfig from '@google/gemini-cli-core';
vi.mock('os', async (importOriginal) => {
const actualOs = await importOriginal<typeof os>();
return {
...actualOs,
homedir: vi.fn(() => '/mock/home/user'),
};
});
vi.mock('open', () => ({
default: vi.fn(),
}));
vi.mock('read-package-up', () => ({
readPackageUp: vi.fn(() =>
Promise.resolve({ packageJson: { version: 'test-version' } }),
),
}));
vi.mock('@google/gemini-cli-core', async () => {
const actualServer = await vi.importActual<typeof ServerConfig>(
'@google/gemini-cli-core',
);
return {
...actualServer,
loadEnvironment: vi.fn(),
loadServerHierarchicalMemory: vi.fn(
(cwd, debug, fileService, extensionPaths) =>
Promise.resolve({
memoryContent: extensionPaths?.join(',') || '',
fileCount: extensionPaths?.length || 0,
}),
),
};
});
describe('loadCliConfig', () => {
const originalArgv = process.argv;
const originalEnv = { ...process.env };
beforeEach(() => {
vi.resetAllMocks();
vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
process.env.GEMINI_API_KEY = 'test-api-key'; // Ensure API key is set for tests
});
afterEach(() => {
process.argv = originalArgv;
process.env = originalEnv;
vi.restoreAllMocks();
});
it('should set showMemoryUsage to true when --memory flag is present', async () => {
process.argv = ['node', 'script.js', '--show_memory_usage'];
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getShowMemoryUsage()).toBe(true);
});
it('should set showMemoryUsage to false when --memory flag is not present', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getShowMemoryUsage()).toBe(false);
});
it('should set showMemoryUsage to false by default from settings if CLI flag is not present', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = { showMemoryUsage: false };
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getShowMemoryUsage()).toBe(false);
});
it('should prioritize CLI flag over settings for showMemoryUsage (CLI true, settings false)', async () => {
process.argv = ['node', 'script.js', '--show_memory_usage'];
const settings: Settings = { showMemoryUsage: false };
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getShowMemoryUsage()).toBe(true);
});
});
describe('loadCliConfig telemetry', () => {
const originalArgv = process.argv;
const originalEnv = { ...process.env };
beforeEach(() => {
vi.resetAllMocks();
vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
process.env.GEMINI_API_KEY = 'test-api-key';
});
afterEach(() => {
process.argv = originalArgv;
process.env = originalEnv;
vi.restoreAllMocks();
});
it('should set telemetry to false by default when no flag or setting is present', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryEnabled()).toBe(false);
});
it('should set telemetry to true when --telemetry flag is present', async () => {
process.argv = ['node', 'script.js', '--telemetry'];
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryEnabled()).toBe(true);
});
it('should set telemetry to false when --no-telemetry flag is present', async () => {
process.argv = ['node', 'script.js', '--no-telemetry'];
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryEnabled()).toBe(false);
});
it('should use telemetry value from settings if CLI flag is not present (settings true)', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = { telemetry: { enabled: true } };
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryEnabled()).toBe(true);
});
it('should use telemetry value from settings if CLI flag is not present (settings false)', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = { telemetry: { enabled: false } };
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryEnabled()).toBe(false);
});
it('should prioritize --telemetry CLI flag (true) over settings (false)', async () => {
process.argv = ['node', 'script.js', '--telemetry'];
const settings: Settings = { telemetry: { enabled: false } };
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryEnabled()).toBe(true);
});
it('should prioritize --no-telemetry CLI flag (false) over settings (true)', async () => {
process.argv = ['node', 'script.js', '--no-telemetry'];
const settings: Settings = { telemetry: { enabled: true } };
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryEnabled()).toBe(false);
});
it('should use telemetry OTLP endpoint from settings if CLI flag is not present', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = {
telemetry: { otlpEndpoint: 'http://settings.example.com' },
};
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryOtlpEndpoint()).toBe(
'http://settings.example.com',
);
});
it('should prioritize --telemetry-otlp-endpoint CLI flag over settings', async () => {
process.argv = [
'node',
'script.js',
'--telemetry-otlp-endpoint',
'http://cli.example.com',
];
const settings: Settings = {
telemetry: { otlpEndpoint: 'http://settings.example.com' },
};
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryOtlpEndpoint()).toBe('http://cli.example.com');
});
it('should use default endpoint if no OTLP endpoint is provided via CLI or settings', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = { telemetry: { enabled: true } };
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryOtlpEndpoint()).toBe('http://localhost:4317');
});
it('should use telemetry target from settings if CLI flag is not present', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = {
telemetry: { target: ServerConfig.DEFAULT_TELEMETRY_TARGET },
};
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryTarget()).toBe(
ServerConfig.DEFAULT_TELEMETRY_TARGET,
);
});
it('should prioritize --telemetry-target CLI flag over settings', async () => {
process.argv = ['node', 'script.js', '--telemetry-target', 'gcp'];
const settings: Settings = {
telemetry: { target: ServerConfig.DEFAULT_TELEMETRY_TARGET },
};
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryTarget()).toBe('gcp');
});
it('should use default target if no target is provided via CLI or settings', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = { telemetry: { enabled: true } };
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryTarget()).toBe(
ServerConfig.DEFAULT_TELEMETRY_TARGET,
);
});
it('should use telemetry log prompts from settings if CLI flag is not present', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = { telemetry: { logPrompts: false } };
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryLogPromptsEnabled()).toBe(false);
});
it('should prioritize --telemetry-log-prompts CLI flag (true) over settings (false)', async () => {
process.argv = ['node', 'script.js', '--telemetry-log-prompts'];
const settings: Settings = { telemetry: { logPrompts: false } };
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryLogPromptsEnabled()).toBe(true);
});
it('should prioritize --no-telemetry-log-prompts CLI flag (false) over settings (true)', async () => {
process.argv = ['node', 'script.js', '--no-telemetry-log-prompts'];
const settings: Settings = { telemetry: { logPrompts: true } };
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryLogPromptsEnabled()).toBe(false);
});
it('should use default log prompts (true) if no value is provided via CLI or settings', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = { telemetry: { enabled: true } };
const config = await loadCliConfig(settings, [], 'test-session');
expect(config.getTelemetryLogPromptsEnabled()).toBe(true);
});
});
describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
beforeEach(() => {
vi.resetAllMocks();
vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
// Other common mocks would be reset here.
});
afterEach(() => {
vi.restoreAllMocks();
});
it('should pass extension context file paths to loadServerHierarchicalMemory', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = {};
const extensions: Extension[] = [
{
config: {
name: 'ext1',
version: '1.0.0',
},
contextFiles: ['/path/to/ext1/GEMINI.md'],
},
{
config: {
name: 'ext2',
version: '1.0.0',
},
contextFiles: [],
},
{
config: {
name: 'ext3',
version: '1.0.0',
},
contextFiles: [
'/path/to/ext3/context1.md',
'/path/to/ext3/context2.md',
],
},
];
await loadCliConfig(settings, extensions, 'session-id');
expect(ServerConfig.loadServerHierarchicalMemory).toHaveBeenCalledWith(
expect.any(String),
false,
expect.any(Object),
[
'/path/to/ext1/GEMINI.md',
'/path/to/ext3/context1.md',
'/path/to/ext3/context2.md',
],
);
});
// NOTE TO FUTURE DEVELOPERS:
// To re-enable tests for loadHierarchicalGeminiMemory, ensure that:
// 1. os.homedir() is reliably mocked *before* the config.ts module is loaded
// and its functions (which use os.homedir()) are called.
// 2. fs/promises and fs mocks correctly simulate file/directory existence,
// readability, and content based on paths derived from the mocked os.homedir().
// 3. Spies on console functions (for logger output) are correctly set up if needed.
// Example of a previously failing test structure:
/*
it('should correctly use mocked homedir for global path', async () => {
const MOCK_GEMINI_DIR_LOCAL = path.join('/mock/home/user', '.gemini');
const MOCK_GLOBAL_PATH_LOCAL = path.join(MOCK_GEMINI_DIR_LOCAL, 'GEMINI.md');
mockFs({
[MOCK_GLOBAL_PATH_LOCAL]: { type: 'file', content: 'GlobalContentOnly' }
});
const memory = await loadHierarchicalGeminiMemory("/some/other/cwd", false);
expect(memory).toBe('GlobalContentOnly');
expect(vi.mocked(os.homedir)).toHaveBeenCalled();
expect(fsPromises.readFile).toHaveBeenCalledWith(MOCK_GLOBAL_PATH_LOCAL, 'utf-8');
});
*/
});
describe('mergeMcpServers', () => {
it('should not modify the original settings object', async () => {
const settings: Settings = {
mcpServers: {
'test-server': {
url: 'http://localhost:8080',
},
},
};
const extensions: Extension[] = [
{
config: {
name: 'ext1',
version: '1.0.0',
mcpServers: {
'ext1-server': {
url: 'http://localhost:8081',
},
},
},
contextFiles: [],
},
];
const originalSettings = JSON.parse(JSON.stringify(settings));
await loadCliConfig(settings, extensions, 'test-session');
expect(settings).toEqual(originalSettings);
});
});
+302
View File
@@ -0,0 +1,302 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import yargs from 'yargs/yargs';
import { hideBin } from 'yargs/helpers';
import process from 'node:process';
import {
Config,
loadServerHierarchicalMemory,
setGeminiMdFilename as setServerGeminiMdFilename,
getCurrentGeminiMdFilename,
ApprovalMode,
GEMINI_CONFIG_DIR as GEMINI_DIR,
DEFAULT_GEMINI_MODEL,
DEFAULT_GEMINI_EMBEDDING_MODEL,
FileDiscoveryService,
TelemetryTarget,
} from '@google/gemini-cli-core';
import { Settings } from './settings.js';
import { Extension } from './extension.js';
import { getCliVersion } from '../utils/version.js';
import * as dotenv from 'dotenv';
import * as fs from 'node:fs';
import * as path from 'node:path';
import * as os from 'node:os';
import { loadSandboxConfig } from './sandboxConfig.js';
// Simple console logger for now - replace with actual logger if available
const logger = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
debug: (...args: any[]) => console.debug('[DEBUG]', ...args),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
warn: (...args: any[]) => console.warn('[WARN]', ...args),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
error: (...args: any[]) => console.error('[ERROR]', ...args),
};
interface CliArgs {
model: string | undefined;
sandbox: boolean | string | undefined;
'sandbox-image': string | undefined;
debug: boolean | undefined;
prompt: string | undefined;
all_files: boolean | undefined;
show_memory_usage: boolean | undefined;
yolo: boolean | undefined;
telemetry: boolean | undefined;
checkpointing: boolean | undefined;
telemetryTarget: string | undefined;
telemetryOtlpEndpoint: string | undefined;
telemetryLogPrompts: boolean | undefined;
}
async function parseArguments(): Promise<CliArgs> {
const argv = await yargs(hideBin(process.argv))
.option('model', {
alias: 'm',
type: 'string',
description: `Model`,
default: process.env.GEMINI_MODEL || DEFAULT_GEMINI_MODEL,
})
.option('prompt', {
alias: 'p',
type: 'string',
description: 'Prompt. Appended to input on stdin (if any).',
})
.option('sandbox', {
alias: 's',
type: 'boolean',
description: 'Run in sandbox?',
})
.option('sandbox-image', {
type: 'string',
description: 'Sandbox image URI.',
})
.option('debug', {
alias: 'd',
type: 'boolean',
description: 'Run in debug mode?',
default: false,
})
.option('all_files', {
alias: 'a',
type: 'boolean',
description: 'Include ALL files in context?',
default: false,
})
.option('show_memory_usage', {
type: 'boolean',
description: 'Show memory usage in status bar',
default: false,
})
.option('yolo', {
alias: 'y',
type: 'boolean',
description:
'Automatically accept all actions (aka YOLO mode, see https://www.youtube.com/watch?v=xvFZjo5PgG0 for more details)?',
default: false,
})
.option('telemetry', {
type: 'boolean',
description:
'Enable telemetry? This flag specifically controls if telemetry is sent. Other --telemetry-* flags set specific values but do not enable telemetry on their own.',
})
.option('telemetry-target', {
type: 'string',
choices: ['local', 'gcp'],
description:
'Set the telemetry target (local or gcp). Overrides settings files.',
})
.option('telemetry-otlp-endpoint', {
type: 'string',
description:
'Set the OTLP endpoint for telemetry. Overrides environment variables and settings files.',
})
.option('telemetry-log-prompts', {
type: 'boolean',
description:
'Enable or disable logging of user prompts for telemetry. Overrides settings files.',
})
.option('checkpointing', {
alias: 'c',
type: 'boolean',
description: 'Enables checkpointing of file edits',
default: false,
})
.version(await getCliVersion()) // This will enable the --version flag based on package.json
.alias('v', 'version')
.help()
.alias('h', 'help')
.strict().argv;
return argv;
}
// This function is now a thin wrapper around the server's implementation.
// It's kept in the CLI for now as App.tsx directly calls it for memory refresh.
// TODO: Consider if App.tsx should get memory via a server call or if Config should refresh itself.
export async function loadHierarchicalGeminiMemory(
currentWorkingDirectory: string,
debugMode: boolean,
fileService: FileDiscoveryService,
extensionContextFilePaths: string[] = [],
): Promise<{ memoryContent: string; fileCount: number }> {
if (debugMode) {
logger.debug(
`CLI: Delegating hierarchical memory load to server for CWD: ${currentWorkingDirectory}`,
);
}
// Directly call the server function.
// The server function will use its own homedir() for the global path.
return loadServerHierarchicalMemory(
currentWorkingDirectory,
debugMode,
fileService,
extensionContextFilePaths,
);
}
export async function loadCliConfig(
settings: Settings,
extensions: Extension[],
sessionId: string,
): Promise<Config> {
loadEnvironment();
const argv = await parseArguments();
const debugMode = argv.debug || false;
// Set the context filename in the server's memoryTool module BEFORE loading memory
// TODO(b/343434939): This is a bit of a hack. The contextFileName should ideally be passed
// directly to the Config constructor in core, and have core handle setGeminiMdFilename.
// However, loadHierarchicalGeminiMemory is called *before* createServerConfig.
if (settings.contextFileName) {
setServerGeminiMdFilename(settings.contextFileName);
} else {
// Reset to default if not provided in settings.
setServerGeminiMdFilename(getCurrentGeminiMdFilename());
}
const extensionContextFilePaths = extensions.flatMap((e) => e.contextFiles);
const fileService = new FileDiscoveryService(process.cwd());
// Call the (now wrapper) loadHierarchicalGeminiMemory which calls the server's version
const { memoryContent, fileCount } = await loadHierarchicalGeminiMemory(
process.cwd(),
debugMode,
fileService,
extensionContextFilePaths,
);
const mcpServers = mergeMcpServers(settings, extensions);
const sandboxConfig = await loadSandboxConfig(settings, argv);
return new Config({
sessionId,
embeddingModel: DEFAULT_GEMINI_EMBEDDING_MODEL,
sandbox: sandboxConfig,
targetDir: process.cwd(),
debugMode,
question: argv.prompt || '',
fullContext: argv.all_files || false,
coreTools: settings.coreTools || undefined,
excludeTools: settings.excludeTools || undefined,
toolDiscoveryCommand: settings.toolDiscoveryCommand,
toolCallCommand: settings.toolCallCommand,
mcpServerCommand: settings.mcpServerCommand,
mcpServers,
userMemory: memoryContent,
geminiMdFileCount: fileCount,
approvalMode: argv.yolo || false ? ApprovalMode.YOLO : ApprovalMode.DEFAULT,
showMemoryUsage:
argv.show_memory_usage || settings.showMemoryUsage || false,
accessibility: settings.accessibility,
telemetry: {
enabled: argv.telemetry ?? settings.telemetry?.enabled,
target: (argv.telemetryTarget ??
settings.telemetry?.target) as TelemetryTarget,
otlpEndpoint:
argv.telemetryOtlpEndpoint ??
process.env.OTEL_EXPORTER_OTLP_ENDPOINT ??
settings.telemetry?.otlpEndpoint,
logPrompts: argv.telemetryLogPrompts ?? settings.telemetry?.logPrompts,
},
usageStatisticsEnabled: settings.usageStatisticsEnabled ?? true,
// Git-aware file filtering settings
fileFiltering: {
respectGitIgnore: settings.fileFiltering?.respectGitIgnore,
enableRecursiveFileSearch:
settings.fileFiltering?.enableRecursiveFileSearch,
},
checkpointing: argv.checkpointing || settings.checkpointing?.enabled,
proxy:
process.env.HTTPS_PROXY ||
process.env.https_proxy ||
process.env.HTTP_PROXY ||
process.env.http_proxy,
cwd: process.cwd(),
fileDiscoveryService: fileService,
bugCommand: settings.bugCommand,
model: argv.model!,
extensionContextFilePaths,
});
}
function mergeMcpServers(settings: Settings, extensions: Extension[]) {
const mcpServers = { ...(settings.mcpServers || {}) };
for (const extension of extensions) {
Object.entries(extension.config.mcpServers || {}).forEach(
([key, server]) => {
if (mcpServers[key]) {
logger.warn(
`Skipping extension MCP config for server with key "${key}" as it already exists.`,
);
return;
}
mcpServers[key] = server;
},
);
}
return mcpServers;
}
function findEnvFile(startDir: string): string | null {
let currentDir = path.resolve(startDir);
while (true) {
// prefer gemini-specific .env under GEMINI_DIR
const geminiEnvPath = path.join(currentDir, GEMINI_DIR, '.env');
if (fs.existsSync(geminiEnvPath)) {
return geminiEnvPath;
}
const envPath = path.join(currentDir, '.env');
if (fs.existsSync(envPath)) {
return envPath;
}
const parentDir = path.dirname(currentDir);
if (parentDir === currentDir || !parentDir) {
// check .env under home as fallback, again preferring gemini-specific .env
const homeGeminiEnvPath = path.join(os.homedir(), GEMINI_DIR, '.env');
if (fs.existsSync(homeGeminiEnvPath)) {
return homeGeminiEnvPath;
}
const homeEnvPath = path.join(os.homedir(), '.env');
if (fs.existsSync(homeEnvPath)) {
return homeEnvPath;
}
return null;
}
currentDir = parentDir;
}
}
export function loadEnvironment(): void {
const envFilePath = findEnvFile(process.cwd());
if (envFilePath) {
dotenv.config({ path: envFilePath });
}
}
-46
View File
@@ -1,46 +0,0 @@
import * as dotenv from 'dotenv';
import * as fs from 'node:fs';
import * as path from 'node:path';
import process from 'node:process';
function findEnvFile(startDir: string): string | null {
// Start search from the provided directory (e.g., current working directory)
let currentDir = path.resolve(startDir); // Ensure absolute path
while (true) {
const envPath = path.join(currentDir, '.env');
if (fs.existsSync(envPath)) {
return envPath;
}
const parentDir = path.dirname(currentDir);
if (parentDir === currentDir || !parentDir) {
return null;
}
currentDir = parentDir;
}
}
export function loadEnvironment(): void {
// Start searching from the current working directory by default
const envFilePath = findEnvFile(process.cwd());
if (!envFilePath) {
return;
}
dotenv.config({ path: envFilePath });
if (!process.env.GEMINI_API_KEY) {
console.error('Error: GEMINI_API_KEY environment variable is not set in the loaded .env file.');
process.exit(1);
}
}
export function getApiKey(): string {
loadEnvironment();
const apiKey = process.env.GEMINI_API_KEY;
if (!apiKey) {
throw new Error('GEMINI_API_KEY is missing. Ensure loadEnvironment() was called successfully.');
}
return apiKey;
}
+109
View File
@@ -0,0 +1,109 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { vi } from 'vitest';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import {
EXTENSIONS_CONFIG_FILENAME,
EXTENSIONS_DIRECTORY_NAME,
loadExtensions,
} from './extension.js';
vi.mock('os', async (importOriginal) => {
const os = await importOriginal<typeof import('os')>();
return {
...os,
homedir: vi.fn(),
};
});
describe('loadExtensions', () => {
let tempWorkspaceDir: string;
let tempHomeDir: string;
beforeEach(() => {
tempWorkspaceDir = fs.mkdtempSync(
path.join(os.tmpdir(), 'gemini-cli-test-workspace-'),
);
tempHomeDir = fs.mkdtempSync(
path.join(os.tmpdir(), 'gemini-cli-test-home-'),
);
vi.mocked(os.homedir).mockReturnValue(tempHomeDir);
});
afterEach(() => {
fs.rmSync(tempWorkspaceDir, { recursive: true, force: true });
fs.rmSync(tempHomeDir, { recursive: true, force: true });
});
it('should load context file path when GEMINI.md is present', () => {
const workspaceExtensionsDir = path.join(
tempWorkspaceDir,
EXTENSIONS_DIRECTORY_NAME,
);
fs.mkdirSync(workspaceExtensionsDir, { recursive: true });
createExtension(workspaceExtensionsDir, 'ext1', '1.0.0', true);
createExtension(workspaceExtensionsDir, 'ext2', '2.0.0');
const extensions = loadExtensions(tempWorkspaceDir);
expect(extensions).toHaveLength(2);
const ext1 = extensions.find((e) => e.config.name === 'ext1');
const ext2 = extensions.find((e) => e.config.name === 'ext2');
expect(ext1?.contextFiles).toEqual([
path.join(workspaceExtensionsDir, 'ext1', 'GEMINI.md'),
]);
expect(ext2?.contextFiles).toEqual([]);
});
it('should load context file path from the extension config', () => {
const workspaceExtensionsDir = path.join(
tempWorkspaceDir,
EXTENSIONS_DIRECTORY_NAME,
);
fs.mkdirSync(workspaceExtensionsDir, { recursive: true });
createExtension(
workspaceExtensionsDir,
'ext1',
'1.0.0',
false,
'my-context-file.md',
);
const extensions = loadExtensions(tempWorkspaceDir);
expect(extensions).toHaveLength(1);
const ext1 = extensions.find((e) => e.config.name === 'ext1');
expect(ext1?.contextFiles).toEqual([
path.join(workspaceExtensionsDir, 'ext1', 'my-context-file.md'),
]);
});
});
function createExtension(
extensionsDir: string,
name: string,
version: string,
addContextFile = false,
contextFileName?: string,
): void {
const extDir = path.join(extensionsDir, name);
fs.mkdirSync(extDir);
fs.writeFileSync(
path.join(extDir, EXTENSIONS_CONFIG_FILENAME),
JSON.stringify({ name, version, contextFileName }),
);
if (addContextFile) {
fs.writeFileSync(path.join(extDir, 'GEMINI.md'), 'context');
}
if (contextFileName) {
fs.writeFileSync(path.join(extDir, contextFileName), 'context');
}
}
+115
View File
@@ -0,0 +1,115 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { MCPServerConfig } from '@google/gemini-cli-core';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
export const EXTENSIONS_DIRECTORY_NAME = path.join('.gemini', 'extensions');
export const EXTENSIONS_CONFIG_FILENAME = 'gemini-extension.json';
export interface Extension {
config: ExtensionConfig;
contextFiles: string[];
}
export interface ExtensionConfig {
name: string;
version: string;
mcpServers?: Record<string, MCPServerConfig>;
contextFileName?: string | string[];
}
export function loadExtensions(workspaceDir: string): Extension[] {
const allExtensions = [
...loadExtensionsFromDir(workspaceDir),
...loadExtensionsFromDir(os.homedir()),
];
const uniqueExtensions: Extension[] = [];
const seenNames = new Set<string>();
for (const extension of allExtensions) {
if (!seenNames.has(extension.config.name)) {
console.log(
`Loading extension: ${extension.config.name} (version: ${extension.config.version})`,
);
uniqueExtensions.push(extension);
seenNames.add(extension.config.name);
}
}
return uniqueExtensions;
}
function loadExtensionsFromDir(dir: string): Extension[] {
const extensionsDir = path.join(dir, EXTENSIONS_DIRECTORY_NAME);
if (!fs.existsSync(extensionsDir)) {
return [];
}
const extensions: Extension[] = [];
for (const subdir of fs.readdirSync(extensionsDir)) {
const extensionDir = path.join(extensionsDir, subdir);
const extension = loadExtension(extensionDir);
if (extension != null) {
extensions.push(extension);
}
}
return extensions;
}
function loadExtension(extensionDir: string): Extension | null {
if (!fs.statSync(extensionDir).isDirectory()) {
console.error(
`Warning: unexpected file ${extensionDir} in extensions directory.`,
);
return null;
}
const configFilePath = path.join(extensionDir, EXTENSIONS_CONFIG_FILENAME);
if (!fs.existsSync(configFilePath)) {
console.error(
`Warning: extension directory ${extensionDir} does not contain a config file ${configFilePath}.`,
);
return null;
}
try {
const configContent = fs.readFileSync(configFilePath, 'utf-8');
const config = JSON.parse(configContent) as ExtensionConfig;
if (!config.name || !config.version) {
console.error(
`Invalid extension config in ${configFilePath}: missing name or version.`,
);
return null;
}
const contextFiles = getContextFileNames(config)
.map((contextFileName) => path.join(extensionDir, contextFileName))
.filter((contextFilePath) => fs.existsSync(contextFilePath));
return {
config,
contextFiles,
};
} catch (e) {
console.error(
`Warning: error parsing extension config in ${configFilePath}: ${e}`,
);
return null;
}
}
function getContextFileNames(config: ExtensionConfig): string[] {
if (!config.contextFileName) {
return ['GEMINI.md'];
} else if (!Array.isArray(config.contextFileName)) {
return [config.contextFileName];
}
return config.contextFileName;
}
+107
View File
@@ -0,0 +1,107 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { SandboxConfig } from '@google/gemini-cli-core';
import commandExists from 'command-exists';
import * as os from 'node:os';
import { getPackageJson } from '../utils/package.js';
import { Settings } from './settings.js';
// This is a stripped-down version of the CliArgs interface from config.ts
// to avoid circular dependencies.
interface SandboxCliArgs {
sandbox?: boolean | string;
'sandbox-image'?: string;
}
const VALID_SANDBOX_COMMANDS: ReadonlyArray<SandboxConfig['command']> = [
'docker',
'podman',
'sandbox-exec',
];
function isSandboxCommand(value: string): value is SandboxConfig['command'] {
return (VALID_SANDBOX_COMMANDS as readonly string[]).includes(value);
}
function getSandboxCommand(
sandbox?: boolean | string,
): SandboxConfig['command'] | '' {
// If the SANDBOX env var is set, we're already inside the sandbox.
if (process.env.SANDBOX) {
return '';
}
// note environment variable takes precedence over argument (from command line or settings)
const environmentConfiguredSandbox =
process.env.GEMINI_SANDBOX?.toLowerCase().trim() ?? '';
sandbox =
environmentConfiguredSandbox?.length > 0
? environmentConfiguredSandbox
: sandbox;
if (sandbox === '1' || sandbox === 'true') sandbox = true;
else if (sandbox === '0' || sandbox === 'false' || !sandbox) sandbox = false;
if (sandbox === false) {
return '';
}
if (typeof sandbox === 'string' && sandbox) {
if (!isSandboxCommand(sandbox)) {
console.error(
`ERROR: invalid sandbox command '${sandbox}'. Must be one of ${VALID_SANDBOX_COMMANDS.join(
', ',
)}`,
);
process.exit(1);
}
// confirm that specified command exists
if (commandExists.sync(sandbox)) {
return sandbox;
}
console.error(
`ERROR: missing sandbox command '${sandbox}' (from GEMINI_SANDBOX)`,
);
process.exit(1);
}
// look for seatbelt, docker, or podman, in that order
// for container-based sandboxing, require sandbox to be enabled explicitly
if (os.platform() === 'darwin' && commandExists.sync('sandbox-exec')) {
return 'sandbox-exec';
} else if (commandExists.sync('docker') && sandbox === true) {
return 'docker';
} else if (commandExists.sync('podman') && sandbox === true) {
return 'podman';
}
// throw an error if user requested sandbox but no command was found
if (sandbox === true) {
console.error(
'ERROR: GEMINI_SANDBOX is true but failed to determine command for sandbox; ' +
'install docker or podman or specify command in GEMINI_SANDBOX',
);
process.exit(1);
}
return '';
}
export async function loadSandboxConfig(
settings: Settings,
argv: SandboxCliArgs,
): Promise<SandboxConfig | undefined> {
const sandboxOption = argv.sandbox ?? settings.sandbox;
const command = getSandboxCommand(sandboxOption);
const packageJson = await getPackageJson();
const image =
argv['sandbox-image'] ??
process.env.GEMINI_SANDBOX_IMAGE ??
packageJson?.config?.sandboxImageUri;
return command && image ? { command, image } : undefined;
}
+635
View File
@@ -0,0 +1,635 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/// <reference types="vitest/globals" />
// Mock 'os' first.
import * as osActual from 'os'; // Import for type info for the mock factory
vi.mock('os', async (importOriginal) => {
const actualOs = await importOriginal<typeof osActual>();
return {
...actualOs,
homedir: vi.fn(() => '/mock/home/user'),
};
});
// Mock './settings.js' to ensure it uses the mocked 'os.homedir()' for its internal constants.
vi.mock('./settings.js', async (importActual) => {
const originalModule = await importActual<typeof import('./settings.js')>();
return {
__esModule: true, // Ensure correct module shape
...originalModule, // Re-export all original members
// We are relying on originalModule's USER_SETTINGS_PATH being constructed with mocked os.homedir()
};
});
// NOW import everything else, including the (now effectively re-exported) settings.js
import * as pathActual from 'path'; // Restored for MOCK_WORKSPACE_SETTINGS_PATH
import {
describe,
it,
expect,
vi,
beforeEach,
afterEach,
type Mocked,
type Mock,
} from 'vitest';
import * as fs from 'fs'; // fs will be mocked separately
import stripJsonComments from 'strip-json-comments'; // Will be mocked separately
// These imports will get the versions from the vi.mock('./settings.js', ...) factory.
import {
LoadedSettings,
loadSettings,
USER_SETTINGS_PATH, // This IS the mocked path.
SETTINGS_DIRECTORY_NAME, // This is from the original module, but used by the mock.
SettingScope,
} from './settings.js';
const MOCK_WORKSPACE_DIR = '/mock/workspace';
// Use the (mocked) SETTINGS_DIRECTORY_NAME for consistency
const MOCK_WORKSPACE_SETTINGS_PATH = pathActual.join(
MOCK_WORKSPACE_DIR,
SETTINGS_DIRECTORY_NAME,
'settings.json',
);
vi.mock('fs');
vi.mock('strip-json-comments', () => ({
default: vi.fn((content) => content),
}));
describe('Settings Loading and Merging', () => {
let mockFsExistsSync: Mocked<typeof fs.existsSync>;
let mockStripJsonComments: Mocked<typeof stripJsonComments>;
let mockFsMkdirSync: Mocked<typeof fs.mkdirSync>;
beforeEach(() => {
vi.resetAllMocks();
mockFsExistsSync = vi.mocked(fs.existsSync);
mockFsMkdirSync = vi.mocked(fs.mkdirSync);
mockStripJsonComments = vi.mocked(stripJsonComments);
vi.mocked(osActual.homedir).mockReturnValue('/mock/home/user');
(mockStripJsonComments as unknown as Mock).mockImplementation(
(jsonString: string) => jsonString,
);
(mockFsExistsSync as Mock).mockReturnValue(false);
(fs.readFileSync as Mock).mockReturnValue('{}'); // Return valid empty JSON
(mockFsMkdirSync as Mock).mockImplementation(() => undefined);
});
afterEach(() => {
vi.restoreAllMocks();
});
describe('loadSettings', () => {
it('should load empty settings if no files exist', () => {
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.user.settings).toEqual({});
expect(settings.workspace.settings).toEqual({});
expect(settings.merged).toEqual({});
expect(settings.errors.length).toBe(0);
});
it('should load user settings if only user file exists', () => {
const expectedUserSettingsPath = USER_SETTINGS_PATH; // Use the path actually resolved by the (mocked) module
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === expectedUserSettingsPath,
);
const userSettingsContent = {
theme: 'dark',
contextFileName: 'USER_CONTEXT.md',
};
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === expectedUserSettingsPath)
return JSON.stringify(userSettingsContent);
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(fs.readFileSync).toHaveBeenCalledWith(
expectedUserSettingsPath,
'utf-8',
);
expect(settings.user.settings).toEqual(userSettingsContent);
expect(settings.workspace.settings).toEqual({});
expect(settings.merged).toEqual(userSettingsContent);
});
it('should load workspace settings if only workspace file exists', () => {
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === MOCK_WORKSPACE_SETTINGS_PATH,
);
const workspaceSettingsContent = {
sandbox: true,
contextFileName: 'WORKSPACE_CONTEXT.md',
};
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === MOCK_WORKSPACE_SETTINGS_PATH)
return JSON.stringify(workspaceSettingsContent);
return '';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(fs.readFileSync).toHaveBeenCalledWith(
MOCK_WORKSPACE_SETTINGS_PATH,
'utf-8',
);
expect(settings.user.settings).toEqual({});
expect(settings.workspace.settings).toEqual(workspaceSettingsContent);
expect(settings.merged).toEqual(workspaceSettingsContent);
});
it('should merge user and workspace settings, with workspace taking precedence', () => {
(mockFsExistsSync as Mock).mockReturnValue(true);
const userSettingsContent = {
theme: 'dark',
sandbox: false,
contextFileName: 'USER_CONTEXT.md',
};
const workspaceSettingsContent = {
sandbox: true,
coreTools: ['tool1'],
contextFileName: 'WORKSPACE_CONTEXT.md',
};
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
if (p === MOCK_WORKSPACE_SETTINGS_PATH)
return JSON.stringify(workspaceSettingsContent);
return '';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.user.settings).toEqual(userSettingsContent);
expect(settings.workspace.settings).toEqual(workspaceSettingsContent);
expect(settings.merged).toEqual({
theme: 'dark',
sandbox: true,
coreTools: ['tool1'],
contextFileName: 'WORKSPACE_CONTEXT.md',
});
});
it('should handle contextFileName correctly when only in user settings', () => {
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === USER_SETTINGS_PATH,
);
const userSettingsContent = { contextFileName: 'CUSTOM.md' };
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
return '';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.contextFileName).toBe('CUSTOM.md');
});
it('should handle contextFileName correctly when only in workspace settings', () => {
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === MOCK_WORKSPACE_SETTINGS_PATH,
);
const workspaceSettingsContent = {
contextFileName: 'PROJECT_SPECIFIC.md',
};
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === MOCK_WORKSPACE_SETTINGS_PATH)
return JSON.stringify(workspaceSettingsContent);
return '';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.contextFileName).toBe('PROJECT_SPECIFIC.md');
});
it('should default contextFileName to undefined if not in any settings file', () => {
(mockFsExistsSync as Mock).mockReturnValue(true);
const userSettingsContent = { theme: 'dark' };
const workspaceSettingsContent = { sandbox: true };
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
if (p === MOCK_WORKSPACE_SETTINGS_PATH)
return JSON.stringify(workspaceSettingsContent);
return '';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.contextFileName).toBeUndefined();
});
it('should load telemetry setting from user settings', () => {
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === USER_SETTINGS_PATH,
);
const userSettingsContent = { telemetry: true };
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.telemetry).toBe(true);
});
it('should load telemetry setting from workspace settings', () => {
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === MOCK_WORKSPACE_SETTINGS_PATH,
);
const workspaceSettingsContent = { telemetry: false };
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === MOCK_WORKSPACE_SETTINGS_PATH)
return JSON.stringify(workspaceSettingsContent);
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.telemetry).toBe(false);
});
it('should prioritize workspace telemetry setting over user setting', () => {
(mockFsExistsSync as Mock).mockReturnValue(true);
const userSettingsContent = { telemetry: true };
const workspaceSettingsContent = { telemetry: false };
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
if (p === MOCK_WORKSPACE_SETTINGS_PATH)
return JSON.stringify(workspaceSettingsContent);
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.telemetry).toBe(false);
});
it('should have telemetry as undefined if not in any settings file', () => {
(mockFsExistsSync as Mock).mockReturnValue(false); // No settings files exist
(fs.readFileSync as Mock).mockReturnValue('{}');
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.telemetry).toBeUndefined();
});
it('should handle JSON parsing errors gracefully', () => {
(mockFsExistsSync as Mock).mockReturnValue(true); // Both files "exist"
const invalidJsonContent = 'invalid json';
const userReadError = new SyntaxError(
"Expected ',' or '}' after property value in JSON at position 10",
);
const workspaceReadError = new SyntaxError(
'Unexpected token i in JSON at position 0',
);
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH) {
// Simulate JSON.parse throwing for user settings
vi.spyOn(JSON, 'parse').mockImplementationOnce(() => {
throw userReadError;
});
return invalidJsonContent; // Content that would cause JSON.parse to throw
}
if (p === MOCK_WORKSPACE_SETTINGS_PATH) {
// Simulate JSON.parse throwing for workspace settings
vi.spyOn(JSON, 'parse').mockImplementationOnce(() => {
throw workspaceReadError;
});
return invalidJsonContent;
}
return '{}'; // Default for other reads
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
// Check that settings are empty due to parsing errors
expect(settings.user.settings).toEqual({});
expect(settings.workspace.settings).toEqual({});
expect(settings.merged).toEqual({});
// Check that error objects are populated in settings.errors
expect(settings.errors).toBeDefined();
// Assuming both user and workspace files cause errors and are added in order
expect(settings.errors.length).toEqual(2);
const userError = settings.errors.find(
(e) => e.path === USER_SETTINGS_PATH,
);
expect(userError).toBeDefined();
expect(userError?.message).toBe(userReadError.message);
const workspaceError = settings.errors.find(
(e) => e.path === MOCK_WORKSPACE_SETTINGS_PATH,
);
expect(workspaceError).toBeDefined();
expect(workspaceError?.message).toBe(workspaceReadError.message);
// Restore JSON.parse mock if it was spied on specifically for this test
vi.restoreAllMocks(); // Or more targeted restore if needed
});
it('should resolve environment variables in user settings', () => {
process.env.TEST_API_KEY = 'user_api_key_from_env';
const userSettingsContent = {
apiKey: '$TEST_API_KEY',
someUrl: 'https://test.com/${TEST_API_KEY}',
};
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === USER_SETTINGS_PATH,
);
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.user.settings.apiKey).toBe('user_api_key_from_env');
expect(settings.user.settings.someUrl).toBe(
'https://test.com/user_api_key_from_env',
);
expect(settings.merged.apiKey).toBe('user_api_key_from_env');
delete process.env.TEST_API_KEY;
});
it('should resolve environment variables in workspace settings', () => {
process.env.WORKSPACE_ENDPOINT = 'workspace_endpoint_from_env';
const workspaceSettingsContent = {
endpoint: '${WORKSPACE_ENDPOINT}/api',
nested: { value: '$WORKSPACE_ENDPOINT' },
};
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === MOCK_WORKSPACE_SETTINGS_PATH,
);
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === MOCK_WORKSPACE_SETTINGS_PATH)
return JSON.stringify(workspaceSettingsContent);
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.workspace.settings.endpoint).toBe(
'workspace_endpoint_from_env/api',
);
expect(settings.workspace.settings.nested.value).toBe(
'workspace_endpoint_from_env',
);
expect(settings.merged.endpoint).toBe('workspace_endpoint_from_env/api');
delete process.env.WORKSPACE_ENDPOINT;
});
it('should prioritize workspace env variables over user env variables if keys clash after resolution', () => {
const userSettingsContent = { configValue: '$SHARED_VAR' };
const workspaceSettingsContent = { configValue: '$SHARED_VAR' };
(mockFsExistsSync as Mock).mockReturnValue(true);
const originalSharedVar = process.env.SHARED_VAR;
// Temporarily delete to ensure a clean slate for the test's specific manipulations
delete process.env.SHARED_VAR;
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH) {
process.env.SHARED_VAR = 'user_value_for_user_read'; // Set for user settings read
return JSON.stringify(userSettingsContent);
}
if (p === MOCK_WORKSPACE_SETTINGS_PATH) {
process.env.SHARED_VAR = 'workspace_value_for_workspace_read'; // Set for workspace settings read
return JSON.stringify(workspaceSettingsContent);
}
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.user.settings.configValue).toBe(
'user_value_for_user_read',
);
expect(settings.workspace.settings.configValue).toBe(
'workspace_value_for_workspace_read',
);
// Merged should take workspace's resolved value
expect(settings.merged.configValue).toBe(
'workspace_value_for_workspace_read',
);
// Restore original environment variable state
if (originalSharedVar !== undefined) {
process.env.SHARED_VAR = originalSharedVar;
} else {
delete process.env.SHARED_VAR; // Ensure it's deleted if it wasn't there before
}
});
it('should leave unresolved environment variables as is', () => {
const userSettingsContent = { apiKey: '$UNDEFINED_VAR' };
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === USER_SETTINGS_PATH,
);
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.user.settings.apiKey).toBe('$UNDEFINED_VAR');
expect(settings.merged.apiKey).toBe('$UNDEFINED_VAR');
});
it('should resolve multiple environment variables in a single string', () => {
process.env.VAR_A = 'valueA';
process.env.VAR_B = 'valueB';
const userSettingsContent = { path: '/path/$VAR_A/${VAR_B}/end' };
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === USER_SETTINGS_PATH,
);
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.user.settings.path).toBe('/path/valueA/valueB/end');
delete process.env.VAR_A;
delete process.env.VAR_B;
});
it('should resolve environment variables in arrays', () => {
process.env.ITEM_1 = 'item1_env';
process.env.ITEM_2 = 'item2_env';
const userSettingsContent = { list: ['$ITEM_1', '${ITEM_2}', 'literal'] };
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === USER_SETTINGS_PATH,
);
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.user.settings.list).toEqual([
'item1_env',
'item2_env',
'literal',
]);
delete process.env.ITEM_1;
delete process.env.ITEM_2;
});
it('should correctly pass through null, boolean, and number types, and handle undefined properties', () => {
process.env.MY_ENV_STRING = 'env_string_value';
process.env.MY_ENV_STRING_NESTED = 'env_string_nested_value';
const userSettingsContent = {
nullVal: null,
trueVal: true,
falseVal: false,
numberVal: 123.45,
stringVal: '$MY_ENV_STRING',
nestedObj: {
nestedNull: null,
nestedBool: true,
nestedNum: 0,
nestedString: 'literal',
anotherEnv: '${MY_ENV_STRING_NESTED}',
},
};
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === USER_SETTINGS_PATH,
);
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.user.settings.nullVal).toBeNull();
expect(settings.user.settings.trueVal).toBe(true);
expect(settings.user.settings.falseVal).toBe(false);
expect(settings.user.settings.numberVal).toBe(123.45);
expect(settings.user.settings.stringVal).toBe('env_string_value');
expect(settings.user.settings.undefinedVal).toBeUndefined();
expect(settings.user.settings.nestedObj.nestedNull).toBeNull();
expect(settings.user.settings.nestedObj.nestedBool).toBe(true);
expect(settings.user.settings.nestedObj.nestedNum).toBe(0);
expect(settings.user.settings.nestedObj.nestedString).toBe('literal');
expect(settings.user.settings.nestedObj.anotherEnv).toBe(
'env_string_nested_value',
);
delete process.env.MY_ENV_STRING;
delete process.env.MY_ENV_STRING_NESTED;
});
it('should resolve multiple concatenated environment variables in a single string value', () => {
process.env.TEST_HOST = 'myhost';
process.env.TEST_PORT = '9090';
const userSettingsContent = {
serverAddress: '${TEST_HOST}:${TEST_PORT}/api',
};
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === USER_SETTINGS_PATH,
);
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.user.settings.serverAddress).toBe('myhost:9090/api');
delete process.env.TEST_HOST;
delete process.env.TEST_PORT;
});
});
describe('LoadedSettings class', () => {
it('setValue should update the correct scope and recompute merged settings', () => {
(mockFsExistsSync as Mock).mockReturnValue(false);
const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR) as LoadedSettings;
vi.mocked(fs.writeFileSync).mockImplementation(() => {});
// mkdirSync is mocked in beforeEach to return undefined, which is fine for void usage
loadedSettings.setValue(SettingScope.User, 'theme', 'matrix');
expect(loadedSettings.user.settings.theme).toBe('matrix');
expect(loadedSettings.merged.theme).toBe('matrix');
expect(fs.writeFileSync).toHaveBeenCalledWith(
USER_SETTINGS_PATH,
JSON.stringify({ theme: 'matrix' }, null, 2),
'utf-8',
);
loadedSettings.setValue(
SettingScope.Workspace,
'contextFileName',
'MY_AGENTS.md',
);
expect(loadedSettings.workspace.settings.contextFileName).toBe(
'MY_AGENTS.md',
);
expect(loadedSettings.merged.contextFileName).toBe('MY_AGENTS.md');
expect(loadedSettings.merged.theme).toBe('matrix'); // User setting should still be there
expect(fs.writeFileSync).toHaveBeenCalledWith(
MOCK_WORKSPACE_SETTINGS_PATH,
JSON.stringify({ contextFileName: 'MY_AGENTS.md' }, null, 2),
'utf-8',
);
// Workspace theme overrides user theme
loadedSettings.setValue(SettingScope.Workspace, 'theme', 'ocean');
expect(loadedSettings.workspace.settings.theme).toBe('ocean');
expect(loadedSettings.merged.theme).toBe('ocean');
});
});
});
+264
View File
@@ -0,0 +1,264 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import * as fs from 'fs';
import * as path from 'path';
import { homedir } from 'os';
import {
MCPServerConfig,
getErrorMessage,
BugCommandSettings,
TelemetrySettings,
AuthType,
} from '@google/gemini-cli-core';
import stripJsonComments from 'strip-json-comments';
import { DefaultLight } from '../ui/themes/default-light.js';
import { DefaultDark } from '../ui/themes/default.js';
export const SETTINGS_DIRECTORY_NAME = '.gemini';
export const USER_SETTINGS_DIR = path.join(homedir(), SETTINGS_DIRECTORY_NAME);
export const USER_SETTINGS_PATH = path.join(USER_SETTINGS_DIR, 'settings.json');
export enum SettingScope {
User = 'User',
Workspace = 'Workspace',
}
export interface CheckpointingSettings {
enabled?: boolean;
}
export interface AccessibilitySettings {
disableLoadingPhrases?: boolean;
}
export interface Settings {
theme?: string;
selectedAuthType?: AuthType;
sandbox?: boolean | string;
coreTools?: string[];
excludeTools?: string[];
toolDiscoveryCommand?: string;
toolCallCommand?: string;
mcpServerCommand?: string;
mcpServers?: Record<string, MCPServerConfig>;
showMemoryUsage?: boolean;
contextFileName?: string | string[];
accessibility?: AccessibilitySettings;
telemetry?: TelemetrySettings;
usageStatisticsEnabled?: boolean;
preferredEditor?: string;
bugCommand?: BugCommandSettings;
checkpointing?: CheckpointingSettings;
autoConfigureMaxOldSpaceSize?: boolean;
// Git-aware file filtering settings
fileFiltering?: {
respectGitIgnore?: boolean;
enableRecursiveFileSearch?: boolean;
};
// UI setting. Does not display the ANSI-controlled terminal title.
hideWindowTitle?: boolean;
// Add other settings here.
}
export interface SettingsError {
message: string;
path: string;
}
export interface SettingsFile {
settings: Settings;
path: string;
}
export class LoadedSettings {
constructor(
user: SettingsFile,
workspace: SettingsFile,
errors: SettingsError[],
) {
this.user = user;
this.workspace = workspace;
this.errors = errors;
this._merged = this.computeMergedSettings();
}
readonly user: SettingsFile;
readonly workspace: SettingsFile;
readonly errors: SettingsError[];
private _merged: Settings;
get merged(): Settings {
return this._merged;
}
private computeMergedSettings(): Settings {
return {
...this.user.settings,
...this.workspace.settings,
};
}
forScope(scope: SettingScope): SettingsFile {
switch (scope) {
case SettingScope.User:
return this.user;
case SettingScope.Workspace:
return this.workspace;
default:
throw new Error(`Invalid scope: ${scope}`);
}
}
setValue(
scope: SettingScope,
key: keyof Settings,
value: string | Record<string, MCPServerConfig> | undefined,
): void {
const settingsFile = this.forScope(scope);
// @ts-expect-error - value can be string | Record<string, MCPServerConfig>
settingsFile.settings[key] = value;
this._merged = this.computeMergedSettings();
saveSettings(settingsFile);
}
}
function resolveEnvVarsInString(value: string): string {
const envVarRegex = /\$(?:(\w+)|{([^}]+)})/g; // Find $VAR_NAME or ${VAR_NAME}
return value.replace(envVarRegex, (match, varName1, varName2) => {
const varName = varName1 || varName2;
if (process && process.env && typeof process.env[varName] === 'string') {
return process.env[varName]!;
}
return match;
});
}
function resolveEnvVarsInObject<T>(obj: T): T {
if (
obj === null ||
obj === undefined ||
typeof obj === 'boolean' ||
typeof obj === 'number'
) {
return obj;
}
if (typeof obj === 'string') {
return resolveEnvVarsInString(obj) as unknown as T;
}
if (Array.isArray(obj)) {
return obj.map((item) => resolveEnvVarsInObject(item)) as unknown as T;
}
if (typeof obj === 'object') {
const newObj = { ...obj } as T;
for (const key in newObj) {
if (Object.prototype.hasOwnProperty.call(newObj, key)) {
newObj[key] = resolveEnvVarsInObject(newObj[key]);
}
}
return newObj;
}
return obj;
}
/**
* Loads settings from user and workspace directories.
* Project settings override user settings.
*/
export function loadSettings(workspaceDir: string): LoadedSettings {
let userSettings: Settings = {};
let workspaceSettings: Settings = {};
const settingsErrors: SettingsError[] = [];
// Load user settings
try {
if (fs.existsSync(USER_SETTINGS_PATH)) {
const userContent = fs.readFileSync(USER_SETTINGS_PATH, 'utf-8');
const parsedUserSettings = JSON.parse(
stripJsonComments(userContent),
) as Settings;
userSettings = resolveEnvVarsInObject(parsedUserSettings);
// Support legacy theme names
if (userSettings.theme && userSettings.theme === 'VS') {
userSettings.theme = DefaultLight.name;
} else if (userSettings.theme && userSettings.theme === 'VS2015') {
userSettings.theme = DefaultDark.name;
}
}
} catch (error: unknown) {
settingsErrors.push({
message: getErrorMessage(error),
path: USER_SETTINGS_PATH,
});
}
const workspaceSettingsPath = path.join(
workspaceDir,
SETTINGS_DIRECTORY_NAME,
'settings.json',
);
// Load workspace settings
try {
if (fs.existsSync(workspaceSettingsPath)) {
const projectContent = fs.readFileSync(workspaceSettingsPath, 'utf-8');
const parsedWorkspaceSettings = JSON.parse(
stripJsonComments(projectContent),
) as Settings;
workspaceSettings = resolveEnvVarsInObject(parsedWorkspaceSettings);
if (workspaceSettings.theme && workspaceSettings.theme === 'VS') {
workspaceSettings.theme = DefaultLight.name;
} else if (
workspaceSettings.theme &&
workspaceSettings.theme === 'VS2015'
) {
workspaceSettings.theme = DefaultDark.name;
}
}
} catch (error: unknown) {
settingsErrors.push({
message: getErrorMessage(error),
path: workspaceSettingsPath,
});
}
return new LoadedSettings(
{
path: USER_SETTINGS_PATH,
settings: userSettings,
},
{
path: workspaceSettingsPath,
settings: workspaceSettings,
},
settingsErrors,
);
}
export function saveSettings(settingsFile: SettingsFile): void {
try {
// Ensure the directory exists
const dirPath = path.dirname(settingsFile.path);
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
fs.writeFileSync(
settingsFile.path,
JSON.stringify(settingsFile.settings, null, 2),
'utf-8',
);
} catch (error) {
console.error('Error saving user settings file:', error);
}
}
-383
View File
@@ -1,383 +0,0 @@
import {
GenerateContentConfig, GoogleGenAI, Part, Chat,
Type,
SchemaUnion,
PartListUnion,
Content
} from '@google/genai';
import { getApiKey } from '../config/env.js';
import { CoreSystemPrompt } from './prompts.js';
import { type ToolCallEvent, type ToolCallConfirmationDetails, ToolCallStatus } from '../ui/types.js';
import process from 'node:process';
import { toolRegistry } from '../tools/tool-registry.js';
import { ToolResult } from '../tools/ToolResult.js';
import { getFolderStructure } from '../utils/getFolderStructure.js';
import { GeminiEventType, GeminiStream } from './GeminiStream.js';
type ToolExecutionOutcome = {
callId: string;
name: string;
args: Record<string, any>;
result?: ToolResult;
error?: any;
confirmationDetails?: ToolCallConfirmationDetails;
};
export class GeminiClient {
private ai: GoogleGenAI;
private defaultHyperParameters: GenerateContentConfig = {
temperature: 0,
topP: 1,
};
private readonly MAX_TURNS = 100;
constructor() {
const apiKey = getApiKey();
this.ai = new GoogleGenAI({ apiKey });
}
public async startChat(): Promise<Chat> {
const tools = toolRegistry.getToolSchemas();
// --- Get environmental information ---
const cwd = process.cwd();
const today = new Date().toLocaleDateString(undefined, { // Use locale-aware date formatting
weekday: 'long', year: 'numeric', month: 'long', day: 'numeric'
});
const platform = process.platform;
// --- Format information into a conversational multi-line string ---
const folderStructure = await getFolderStructure(cwd);
// --- End folder structure formatting ---)
const initialContextText = `
Okay, just setting up the context for our chat.
Today is ${today}.
My operating system is: ${platform}
I'm currently working in the directory: ${cwd}
${folderStructure}
`.trim();
const initialContextPart: Part = { text: initialContextText };
// --- End environmental information formatting ---
try {
const chat = this.ai.chats.create({
model: 'gemini-2.5-pro-preview-03-25',//'gemini-2.0-flash',
config: {
systemInstruction: CoreSystemPrompt,
...this.defaultHyperParameters,
tools,
},
history: [
// --- Add the context as a single part in the initial user message ---
{
role: "user",
parts: [initialContextPart] // Pass the single Part object in an array
},
// --- Add an empty model response to balance the history ---
{
role: "model",
parts: [{ text: "Got it. Thanks for the context!" }] // A slightly more conversational model response
}
// --- End history modification ---
],
});
return chat;
} catch (error) {
console.error("Error initializing Gemini chat session:", error);
const message = error instanceof Error ? error.message : "Unknown error.";
throw new Error(`Failed to initialize chat: ${message}`);
}
}
public addMessageToHistory(chat: Chat, message: Content): void {
const history = chat.getHistory();
history.push(message);
this.ai.chats
chat
}
public async* sendMessageStream(
chat: Chat,
request: PartListUnion,
signal?: AbortSignal
): GeminiStream {
let currentMessageToSend: PartListUnion = request;
let turns = 0;
try {
while (turns < this.MAX_TURNS) {
turns++;
const resultStream = await chat.sendMessageStream({ message: currentMessageToSend });
let functionResponseParts: Part[] = [];
let pendingToolCalls: Array<{ callId: string; name: string; args: Record<string, any> }> = [];
let yieldedTextInTurn = false;
const chunksForDebug = [];
for await (const chunk of resultStream) {
chunksForDebug.push(chunk);
if (signal?.aborted) {
const abortError = new Error("Request cancelled by user during stream.");
abortError.name = 'AbortError';
throw abortError;
}
const functionCalls = chunk.functionCalls;
if (functionCalls && functionCalls.length > 0) {
for (const call of functionCalls) {
const callId = call.id ?? `${call.name}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
const name = call.name || 'undefined_tool_name';
const args = (call.args || {}) as Record<string, any>;
pendingToolCalls.push({ callId, name, args });
const evtValue: ToolCallEvent = {
type: 'tool_call',
status: ToolCallStatus.Pending,
callId,
name,
args,
resultDisplay: undefined,
confirmationDetails: undefined,
}
yield {
type: GeminiEventType.ToolCallInfo,
value: evtValue,
};
}
} else {
const text = chunk.text;
if (text) {
yieldedTextInTurn = true;
yield {
type: GeminiEventType.Content,
value: text,
};
}
}
}
if (pendingToolCalls.length > 0) {
const toolPromises: Promise<ToolExecutionOutcome>[] = pendingToolCalls.map(async pendingToolCall => {
const tool = toolRegistry.getTool(pendingToolCall.name);
if (!tool) {
// Directly return error outcome if tool not found
return { ...pendingToolCall, error: new Error(`Tool "${pendingToolCall.name}" not found or is not registered.`) };
}
try {
const confirmation = await tool.shouldConfirmExecute(pendingToolCall.args);
if (confirmation) {
return { ...pendingToolCall, confirmationDetails: confirmation };
}
} catch (error) {
return { ...pendingToolCall, error: new Error(`Tool failed to check tool confirmation: ${error}`) };
}
try {
const result = await tool.execute(pendingToolCall.args);
return { ...pendingToolCall, result };
} catch (error) {
return { ...pendingToolCall, error: new Error(`Tool failed to execute: ${error}`) };
}
});
const toolExecutionOutcomes: ToolExecutionOutcome[] = await Promise.all(toolPromises);
for (const executedTool of toolExecutionOutcomes) {
const { callId, name, args, result, error, confirmationDetails } = executedTool;
if (error) {
const errorMessage = error?.message || String(error);
yield {
type: GeminiEventType.Content,
value: `[Error invoking tool ${name}: ${errorMessage}]`,
};
} else if (result && typeof result === 'object' && result !== null && 'error' in result) {
const errorMessage = String(result.error);
yield {
type: GeminiEventType.Content,
value: `[Error executing tool ${name}: ${errorMessage}]`,
};
} else {
const status = confirmationDetails ? ToolCallStatus.Confirming : ToolCallStatus.Invoked;
const evtValue: ToolCallEvent = { type: 'tool_call', status, callId, name, args, resultDisplay: result?.returnDisplay, confirmationDetails }
yield {
type: GeminiEventType.ToolCallInfo,
value: evtValue,
};
}
}
pendingToolCalls = [];
const waitingOnConfirmations = toolExecutionOutcomes.filter(outcome => outcome.confirmationDetails).length > 0;
if (waitingOnConfirmations) {
// Stop processing content, wait for user.
// TODO: Kill token processing once API supports signals.
break;
}
functionResponseParts = toolExecutionOutcomes.map((executedTool: ToolExecutionOutcome): Part => {
const { name, result, error } = executedTool;
const output = { "output": result?.llmContent };
let toolOutcomePayload: any;
if (error) {
const errorMessage = error?.message || String(error);
toolOutcomePayload = { error: `Invocation failed: ${errorMessage}` };
console.error(`[Turn ${turns}] Critical error invoking tool ${name}:`, error);
} else if (result && typeof result === 'object' && result !== null && 'error' in result) {
toolOutcomePayload = output;
console.warn(`[Turn ${turns}] Tool ${name} returned an error structure:`, result.error);
} else {
toolOutcomePayload = output;
}
return {
functionResponse: {
name: name,
id: executedTool.callId,
response: toolOutcomePayload,
},
};
});
currentMessageToSend = functionResponseParts;
} else if (yieldedTextInTurn) {
const history = chat.getHistory();
const checkPrompt = `Analyze *only* the content and structure of your immediately preceding response (your last turn in the conversation history). Based *strictly* on that response, determine who should logically speak next: the 'user' or the 'model' (you).
**Decision Rules (apply in order):**
1. **Model Continues:** If your last response explicitly states an immediate next action *you* intend to take (e.g., "Next, I will...", "Now I'll process...", "Moving on to analyze...", indicates an intended tool call that didn't execute), OR if the response seems clearly incomplete (cut off mid-thought without a natural conclusion), then the **'model'** should speak next.
2. **Question to User:** If your last response ends with a direct question specifically addressed *to the user*, then the **'user'** should speak next.
3. **Waiting for User:** If your last response completed a thought, statement, or task *and* does not meet the criteria for Rule 1 (Model Continues) or Rule 2 (Question to User), it implies a pause expecting user input or reaction. In this case, the **'user'** should speak next.
**Output Format:**
Respond *only* in JSON format according to the following schema. Do not include any text outside the JSON structure.
\`\`\`json
{
"type": "object",
"properties": {
"reasoning": {
"type": "string",
"description": "Brief explanation justifying the 'next_speaker' choice based *strictly* on the applicable rule and the content/structure of the preceding turn."
},
"next_speaker": {
"type": "string",
"enum": ["user", "model"],
"description": "Who should speak next based *only* on the preceding turn and the decision rules."
}
},
"required": ["next_speaker", "reasoning"]
\`\`\`
}`;
// Schema Idea
const responseSchema: SchemaUnion = {
type: Type.OBJECT,
properties: {
reasoning: {
type: Type.STRING,
description: "Brief explanation justifying the 'next_speaker' choice based *strictly* on the applicable rule and the content/structure of the preceding turn."
},
next_speaker: {
type: Type.STRING,
enum: ['user', 'model'], // Enforce the choices
description: "Who should speak next based *only* on the preceding turn and the decision rules",
},
},
required: ['reasoning', 'next_speaker']
};
try {
// Use the new generateJson method, passing the history and the check prompt
const parsedResponse = await this.generateJson([...history, { role: "user", parts: [{ text: checkPrompt }] }], responseSchema);
// Safely extract the next speaker value
const nextSpeaker: string | undefined = typeof parsedResponse?.next_speaker === 'string' ? parsedResponse.next_speaker : undefined;
if (nextSpeaker === 'model') {
currentMessageToSend = { text: 'alright' }; // Or potentially a more meaningful continuation prompt
} else {
// 'user' should speak next, or value is missing/invalid. End the turn.
break;
}
} catch (error) {
console.error(`[Turn ${turns}] Failed to get or parse next speaker check:`, error);
// If the check fails, assume user should speak next to avoid infinite loops
break;
}
} else {
console.warn(`[Turn ${turns}] No text or function calls received from Gemini. Ending interaction.`);
break;
}
}
if (turns >= this.MAX_TURNS) {
console.warn("sendMessageStream: Reached maximum tool call turns limit.");
yield {
type: GeminiEventType.Content,
value: "\n\n[System Notice: Maximum interaction turns reached. The conversation may be incomplete.]",
};
}
} catch (error: unknown) {
if (error instanceof Error && error.name === 'AbortError') {
console.log("Gemini stream request aborted by user.");
throw error;
} else {
console.error(`Error during Gemini stream or tool interaction:`, error);
const message = error instanceof Error ? error.message : String(error);
yield {
type: GeminiEventType.Content,
value: `\n\n[Error: An unexpected error occurred during the chat: ${message}]`,
};
throw error;
}
}
}
/**
* Generates structured JSON content based on conversational history and a schema.
* @param contents The conversational history (Content array) to provide context.
* @param schema The SchemaUnion defining the desired JSON structure.
* @returns A promise that resolves to the parsed JSON object matching the schema.
* @throws Throws an error if the API call fails or the response is not valid JSON.
*/
public async generateJson(contents: Content[], schema: SchemaUnion): Promise<any> {
try {
const result = await this.ai.models.generateContent({
model: 'gemini-2.0-flash', // Using flash for potentially faster structured output
config: {
...this.defaultHyperParameters,
systemInstruction: CoreSystemPrompt,
responseSchema: schema,
responseMimeType: 'application/json',
},
contents: contents, // Pass the full Content array
});
const responseText = result.text;
if (!responseText) {
throw new Error("API returned an empty response.");
}
try {
const parsedJson = JSON.parse(responseText);
// TODO: Add schema validation if needed
return parsedJson;
} catch (parseError) {
console.error("Failed to parse JSON response:", responseText);
throw new Error(`Failed to parse API response as JSON: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
}
} catch (error) {
console.error("Error generating JSON content:", error);
const message = error instanceof Error ? error.message : "Unknown API error.";
throw new Error(`Failed to generate JSON content: ${message}`);
}
}
}
-22
View File
@@ -1,22 +0,0 @@
import { ToolCallEvent } from "../ui/types.js";
export enum GeminiEventType {
Content,
ToolCallInfo,
}
export interface GeminiContentEvent {
type: GeminiEventType.Content;
value: string;
}
export interface GeminiToolCallInfoEvent {
type: GeminiEventType.ToolCallInfo;
value: ToolCallEvent;
}
export type GeminiEvent =
| GeminiContentEvent
| GeminiToolCallInfoEvent;
export type GeminiStream = AsyncIterable<GeminiEvent>;
-4
View File
@@ -1,4 +0,0 @@
export enum StreamingState {
Idle,
Responding,
}
View File
-1
View File
@@ -1 +0,0 @@
export const MEMORY_FILE_NAME = 'GEMINI.md';

Some files were not shown because too many files have changed in this diff Show More