Copy disabled (too large)
Download .txt
Showing preview only (16,205K chars total). Download the full file to get everything.
Repository: google-gemini/gemini-cli
Branch: main
Commit: 8615315711a8
Files: 2279
Total size: 18.6 MB
Directory structure:
gitextract_3lf9y2ue/
├── .allstar/
│ └── branch_protection.yaml
├── .editorconfig
├── .gcp/
│ ├── Dockerfile.gemini-code-builder
│ └── release-docker.yml
├── .gemini/
│ ├── config.yaml
│ └── settings.json
├── .geminiignore
├── .gitattributes
├── .github/
│ ├── CODEOWNERS
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── feature_request.yml
│ │ └── website_issue.yml
│ ├── actions/
│ │ ├── calculate-vars/
│ │ │ └── action.yml
│ │ ├── create-pull-request/
│ │ │ └── action.yml
│ │ ├── npm-auth-token/
│ │ │ └── action.yml
│ │ ├── post-coverage-comment/
│ │ │ └── action.yml
│ │ ├── publish-release/
│ │ │ └── action.yml
│ │ ├── push-docker/
│ │ │ └── action.yml
│ │ ├── push-sandbox/
│ │ │ └── action.yml
│ │ ├── run-tests/
│ │ │ └── action.yml
│ │ ├── setup-npmrc/
│ │ │ └── action.yml
│ │ ├── tag-npm-release/
│ │ │ └── action.yml
│ │ └── verify-release/
│ │ └── action.yml
│ ├── dependabot.yml
│ ├── pull_request_template.md
│ ├── scripts/
│ │ ├── backfill-need-triage.cjs
│ │ ├── backfill-pr-notification.cjs
│ │ ├── pr-triage.sh
│ │ └── sync-maintainer-labels.cjs
│ └── workflows/
│ ├── chained_e2e.yml
│ ├── ci.yml
│ ├── community-report.yml
│ ├── deflake.yml
│ ├── docs-page-action.yml
│ ├── docs-rebuild.yml
│ ├── eval.yml
│ ├── evals-nightly.yml
│ ├── gemini-automated-issue-dedup.yml
│ ├── gemini-automated-issue-triage.yml
│ ├── gemini-scheduled-issue-dedup.yml
│ ├── gemini-scheduled-issue-triage.yml
│ ├── gemini-scheduled-pr-triage.yml
│ ├── gemini-scheduled-stale-issue-closer.yml
│ ├── gemini-scheduled-stale-pr-closer.yml
│ ├── gemini-self-assign-issue.yml
│ ├── issue-opened-labeler.yml
│ ├── label-backlog-child-issues.yml
│ ├── label-workstream-rollup.yml
│ ├── links.yml
│ ├── no-response.yml
│ ├── pr-contribution-guidelines-notifier.yml
│ ├── pr-rate-limiter.yaml
│ ├── release-change-tags.yml
│ ├── release-manual.yml
│ ├── release-nightly.yml
│ ├── release-notes.yml
│ ├── release-patch-0-from-comment.yml
│ ├── release-patch-1-create-pr.yml
│ ├── release-patch-2-trigger.yml
│ ├── release-patch-3-release.yml
│ ├── release-promote.yml
│ ├── release-rollback.yml
│ ├── release-sandbox.yml
│ ├── smoke-test.yml
│ ├── stale.yml
│ ├── test-build-binary.yml
│ ├── trigger_e2e.yml
│ ├── unassign-inactive-assignees.yml
│ └── verify-release.yml
├── .gitignore
├── .husky/
│ └── pre-commit
├── .lycheeignore
├── .npmrc
├── .nvmrc
├── .prettierignore
├── .prettierrc.json
├── .vscode/
│ ├── extensions.json
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── .yamllint.yml
├── CONTRIBUTING.md
├── Dockerfile
├── GEMINI.md
├── LICENSE
├── Makefile
├── README.md
├── ROADMAP.md
├── SECURITY.md
├── docs/
│ ├── admin/
│ │ └── enterprise-controls.md
│ ├── changelogs/
│ │ ├── index.md
│ │ ├── latest.md
│ │ └── preview.md
│ ├── cli/
│ │ ├── checkpointing.md
│ │ ├── cli-reference.md
│ │ ├── creating-skills.md
│ │ ├── custom-commands.md
│ │ ├── enterprise.md
│ │ ├── gemini-ignore.md
│ │ ├── gemini-md.md
│ │ ├── generation-settings.md
│ │ ├── headless.md
│ │ ├── model-routing.md
│ │ ├── model-steering.md
│ │ ├── model.md
│ │ ├── notifications.md
│ │ ├── plan-mode.md
│ │ ├── rewind.md
│ │ ├── sandbox.md
│ │ ├── session-management.md
│ │ ├── settings.md
│ │ ├── skills.md
│ │ ├── system-prompt.md
│ │ ├── telemetry.md
│ │ ├── themes.md
│ │ ├── token-caching.md
│ │ ├── trusted-folders.md
│ │ └── tutorials/
│ │ ├── automation.md
│ │ ├── file-management.md
│ │ ├── mcp-setup.md
│ │ ├── memory-management.md
│ │ ├── plan-mode-steering.md
│ │ ├── session-management.md
│ │ ├── shell-commands.md
│ │ ├── skills-getting-started.md
│ │ ├── task-planning.md
│ │ └── web-tools.md
│ ├── core/
│ │ ├── index.md
│ │ ├── local-model-routing.md
│ │ ├── remote-agents.md
│ │ └── subagents.md
│ ├── examples/
│ │ └── proxy-script.md
│ ├── extensions/
│ │ ├── best-practices.md
│ │ ├── index.md
│ │ ├── reference.md
│ │ ├── releasing.md
│ │ └── writing-extensions.md
│ ├── get-started/
│ │ ├── authentication.md
│ │ ├── examples.md
│ │ ├── gemini-3.md
│ │ ├── index.md
│ │ └── installation.md
│ ├── hooks/
│ │ ├── best-practices.md
│ │ ├── index.md
│ │ ├── reference.md
│ │ └── writing-hooks.md
│ ├── ide-integration/
│ │ ├── ide-companion-spec.md
│ │ └── index.md
│ ├── index.md
│ ├── integration-tests.md
│ ├── issue-and-pr-automation.md
│ ├── local-development.md
│ ├── mermaid/
│ │ ├── context.mmd
│ │ └── render-path.mmd
│ ├── npm.md
│ ├── redirects.json
│ ├── reference/
│ │ ├── commands.md
│ │ ├── configuration.md
│ │ ├── keyboard-shortcuts.md
│ │ ├── memport.md
│ │ ├── policy-engine.md
│ │ └── tools.md
│ ├── release-confidence.md
│ ├── releases.md
│ ├── resources/
│ │ ├── faq.md
│ │ ├── quota-and-pricing.md
│ │ ├── tos-privacy.md
│ │ ├── troubleshooting.md
│ │ └── uninstall.md
│ ├── sidebar.json
│ └── tools/
│ ├── activate-skill.md
│ ├── ask-user.md
│ ├── file-system.md
│ ├── internal-docs.md
│ ├── mcp-server.md
│ ├── memory.md
│ ├── planning.md
│ ├── shell.md
│ ├── todos.md
│ ├── web-fetch.md
│ └── web-search.md
├── esbuild.config.js
├── eslint.config.js
├── evals/
│ ├── README.md
│ ├── answer-vs-act.eval.ts
│ ├── app-test-helper.ts
│ ├── ask_user.eval.ts
│ ├── automated-tool-use.eval.ts
│ ├── concurrency-safety.eval.ts
│ ├── edit-locations-eval.eval.ts
│ ├── frugalReads.eval.ts
│ ├── frugalSearch.eval.ts
│ ├── generalist_agent.eval.ts
│ ├── generalist_delegation.eval.ts
│ ├── gitRepo.eval.ts
│ ├── grep_search_functionality.eval.ts
│ ├── hierarchical_memory.eval.ts
│ ├── interactive-hang.eval.ts
│ ├── model_steering.eval.ts
│ ├── plan_mode.eval.ts
│ ├── save_memory.eval.ts
│ ├── shell-efficiency.eval.ts
│ ├── subagents.eval.ts
│ ├── test-helper.ts
│ ├── tool_output_masking.eval.ts
│ ├── tracker.eval.ts
│ ├── validation_fidelity.eval.ts
│ ├── validation_fidelity_pre_existing_errors.eval.ts
│ └── vitest.config.ts
├── integration-tests/
│ ├── acp-env-auth.test.ts
│ ├── acp-telemetry.test.ts
│ ├── api-resilience.responses
│ ├── api-resilience.test.ts
│ ├── browser-agent.cleanup.responses
│ ├── browser-agent.confirmation.responses
│ ├── browser-agent.interaction.responses
│ ├── browser-agent.navigate-snapshot.responses
│ ├── browser-agent.screenshot.responses
│ ├── browser-agent.sequential.responses
│ ├── browser-agent.test.ts
│ ├── browser-policy.responses
│ ├── browser-policy.test.ts
│ ├── checkpointing.test.ts
│ ├── clipboard-linux.test.ts
│ ├── concurrency-limit.responses
│ ├── concurrency-limit.test.ts
│ ├── context-compress-interactive.compress-empty.responses
│ ├── context-compress-interactive.compress-failure.responses
│ ├── context-compress-interactive.compress.responses
│ ├── context-compress-interactive.test.ts
│ ├── ctrl-c-exit.test.ts
│ ├── deprecation-warnings.test.ts
│ ├── extensions-install.test.ts
│ ├── extensions-reload.test.ts
│ ├── file-system-interactive.test.ts
│ ├── file-system.test.ts
│ ├── flicker-detector.max-height.responses
│ ├── flicker.test.ts
│ ├── globalSetup.ts
│ ├── google_web_search.test.ts
│ ├── hooks-agent-flow-multistep.responses
│ ├── hooks-agent-flow.responses
│ ├── hooks-agent-flow.test.ts
│ ├── hooks-system.after-agent.responses
│ ├── hooks-system.after-model.responses
│ ├── hooks-system.after-tool-context.responses
│ ├── hooks-system.allow-tool.responses
│ ├── hooks-system.before-agent.responses
│ ├── hooks-system.before-model.responses
│ ├── hooks-system.before-tool-selection.responses
│ ├── hooks-system.before-tool-stop.responses
│ ├── hooks-system.block-tool.responses
│ ├── hooks-system.compress-auto.responses
│ ├── hooks-system.disabled-via-command.responses
│ ├── hooks-system.disabled-via-settings.responses
│ ├── hooks-system.error-handling.responses
│ ├── hooks-system.input-modification.responses
│ ├── hooks-system.input-validation.responses
│ ├── hooks-system.multiple-events.responses
│ ├── hooks-system.notification.responses
│ ├── hooks-system.sequential-execution.responses
│ ├── hooks-system.session-clear.responses
│ ├── hooks-system.session-startup.responses
│ ├── hooks-system.tail-tool-call.responses
│ ├── hooks-system.telemetry.responses
│ ├── hooks-system.test.ts
│ ├── json-output.error.responses
│ ├── json-output.france.responses
│ ├── json-output.session-id.responses
│ ├── json-output.test.ts
│ ├── list_directory.test.ts
│ ├── mcp_server_cyclic_schema.test.ts
│ ├── mixed-input-crash.test.ts
│ ├── parallel-tools.responses
│ ├── parallel-tools.test.ts
│ ├── plan-mode.test.ts
│ ├── policy-headless-readonly.responses
│ ├── policy-headless-shell-allowed.responses
│ ├── policy-headless-shell-denied.responses
│ ├── policy-headless.test.ts
│ ├── read_many_files.test.ts
│ ├── replace.test.ts
│ ├── resume_repro.responses
│ ├── resume_repro.test.ts
│ ├── ripgrep-real.test.ts
│ ├── run_shell_command.test.ts
│ ├── simple-mcp-server.test.ts
│ ├── skill-creator-scripts.test.ts
│ ├── skill-creator-vulnerabilities.test.ts
│ ├── stdin-context.test.ts
│ ├── stdout-stderr-output-error.responses
│ ├── stdout-stderr-output.responses
│ ├── stdout-stderr-output.test.ts
│ ├── symlink-install.test.ts
│ ├── telemetry.test.ts
│ ├── test-helper.ts
│ ├── test-mcp-server.ts
│ ├── tsconfig.json
│ ├── user-policy.responses
│ ├── user-policy.test.ts
│ ├── utf-bom-encoding.test.ts
│ ├── vitest.config.ts
│ └── write_file.test.ts
├── package.json
├── packages/
│ ├── a2a-server/
│ │ ├── GEMINI.md
│ │ ├── README.md
│ │ ├── development-extension-rfc.md
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── agent/
│ │ │ │ ├── executor.test.ts
│ │ │ │ ├── executor.ts
│ │ │ │ ├── task-event-driven.test.ts
│ │ │ │ ├── task.test.ts
│ │ │ │ └── task.ts
│ │ │ ├── commands/
│ │ │ │ ├── command-registry.test.ts
│ │ │ │ ├── command-registry.ts
│ │ │ │ ├── extensions.test.ts
│ │ │ │ ├── extensions.ts
│ │ │ │ ├── init.test.ts
│ │ │ │ ├── init.ts
│ │ │ │ ├── memory.test.ts
│ │ │ │ ├── memory.ts
│ │ │ │ ├── restore.test.ts
│ │ │ │ ├── restore.ts
│ │ │ │ └── types.ts
│ │ │ ├── config/
│ │ │ │ ├── config.test.ts
│ │ │ │ ├── config.ts
│ │ │ │ ├── extension.ts
│ │ │ │ ├── settings.test.ts
│ │ │ │ └── settings.ts
│ │ │ ├── http/
│ │ │ │ ├── app.test.ts
│ │ │ │ ├── app.ts
│ │ │ │ ├── endpoints.test.ts
│ │ │ │ ├── requestStorage.ts
│ │ │ │ └── server.ts
│ │ │ ├── index.ts
│ │ │ ├── persistence/
│ │ │ │ ├── gcs.test.ts
│ │ │ │ └── gcs.ts
│ │ │ ├── types.ts
│ │ │ └── utils/
│ │ │ ├── executor_utils.ts
│ │ │ ├── logger.ts
│ │ │ └── testing_utils.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ ├── cli/
│ │ ├── GEMINI.md
│ │ ├── examples/
│ │ │ ├── ask-user-dialog-demo.tsx
│ │ │ └── scrollable-list-demo.tsx
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── __snapshots__/
│ │ │ │ └── nonInteractiveCli.test.ts.snap
│ │ │ ├── acp/
│ │ │ │ ├── acpClient.test.ts
│ │ │ │ ├── acpClient.ts
│ │ │ │ ├── acpErrors.test.ts
│ │ │ │ ├── acpErrors.ts
│ │ │ │ ├── acpResume.test.ts
│ │ │ │ ├── commandHandler.test.ts
│ │ │ │ ├── commandHandler.ts
│ │ │ │ ├── commands/
│ │ │ │ │ ├── commandRegistry.ts
│ │ │ │ │ ├── extensions.ts
│ │ │ │ │ ├── init.ts
│ │ │ │ │ ├── memory.ts
│ │ │ │ │ ├── restore.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── fileSystemService.test.ts
│ │ │ │ └── fileSystemService.ts
│ │ │ ├── commands/
│ │ │ │ ├── extensions/
│ │ │ │ │ ├── configure.test.ts
│ │ │ │ │ ├── configure.ts
│ │ │ │ │ ├── disable.test.ts
│ │ │ │ │ ├── disable.ts
│ │ │ │ │ ├── enable.test.ts
│ │ │ │ │ ├── enable.ts
│ │ │ │ │ ├── examples/
│ │ │ │ │ │ ├── custom-commands/
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── commands/
│ │ │ │ │ │ │ │ └── fs/
│ │ │ │ │ │ │ │ └── grep-code.toml
│ │ │ │ │ │ │ └── gemini-extension.json
│ │ │ │ │ │ ├── exclude-tools/
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ └── gemini-extension.json
│ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── gemini-extension.json
│ │ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ │ └── hooks.json
│ │ │ │ │ │ │ └── scripts/
│ │ │ │ │ │ │ └── on-start.js
│ │ │ │ │ │ ├── mcp-server/
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── example.js
│ │ │ │ │ │ │ ├── gemini-extension.json
│ │ │ │ │ │ │ └── package.json
│ │ │ │ │ │ ├── policies/
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── gemini-extension.json
│ │ │ │ │ │ │ └── policies/
│ │ │ │ │ │ │ └── policies.toml
│ │ │ │ │ │ ├── skills/
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── gemini-extension.json
│ │ │ │ │ │ │ └── skills/
│ │ │ │ │ │ │ └── greeter/
│ │ │ │ │ │ │ └── SKILL.md
│ │ │ │ │ │ └── themes-example/
│ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ └── gemini-extension.json
│ │ │ │ │ ├── install.test.ts
│ │ │ │ │ ├── install.ts
│ │ │ │ │ ├── link.test.ts
│ │ │ │ │ ├── link.ts
│ │ │ │ │ ├── list.test.ts
│ │ │ │ │ ├── list.ts
│ │ │ │ │ ├── new.test.ts
│ │ │ │ │ ├── new.ts
│ │ │ │ │ ├── uninstall.test.ts
│ │ │ │ │ ├── uninstall.ts
│ │ │ │ │ ├── update.test.ts
│ │ │ │ │ ├── update.ts
│ │ │ │ │ ├── utils.ts
│ │ │ │ │ ├── validate.test.ts
│ │ │ │ │ └── validate.ts
│ │ │ │ ├── extensions.test.tsx
│ │ │ │ ├── extensions.tsx
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── migrate.test.ts
│ │ │ │ │ └── migrate.ts
│ │ │ │ ├── hooks.tsx
│ │ │ │ ├── mcp/
│ │ │ │ │ ├── add.test.ts
│ │ │ │ │ ├── add.ts
│ │ │ │ │ ├── enableDisable.ts
│ │ │ │ │ ├── list.test.ts
│ │ │ │ │ ├── list.ts
│ │ │ │ │ ├── remove.test.ts
│ │ │ │ │ └── remove.ts
│ │ │ │ ├── mcp.test.ts
│ │ │ │ ├── mcp.ts
│ │ │ │ ├── skills/
│ │ │ │ │ ├── disable.test.ts
│ │ │ │ │ ├── disable.ts
│ │ │ │ │ ├── enable.test.ts
│ │ │ │ │ ├── enable.ts
│ │ │ │ │ ├── install.test.ts
│ │ │ │ │ ├── install.ts
│ │ │ │ │ ├── link.test.ts
│ │ │ │ │ ├── link.ts
│ │ │ │ │ ├── list.test.ts
│ │ │ │ │ ├── list.ts
│ │ │ │ │ ├── uninstall.test.ts
│ │ │ │ │ └── uninstall.ts
│ │ │ │ ├── skills.test.tsx
│ │ │ │ ├── skills.tsx
│ │ │ │ ├── utils.test.ts
│ │ │ │ └── utils.ts
│ │ │ ├── config/
│ │ │ │ ├── auth.test.ts
│ │ │ │ ├── auth.ts
│ │ │ │ ├── config.integration.test.ts
│ │ │ │ ├── config.test.ts
│ │ │ │ ├── config.ts
│ │ │ │ ├── extension-manager-agents.test.ts
│ │ │ │ ├── extension-manager-hydration.test.ts
│ │ │ │ ├── extension-manager-permissions.test.ts
│ │ │ │ ├── extension-manager-scope.test.ts
│ │ │ │ ├── extension-manager-skills.test.ts
│ │ │ │ ├── extension-manager-themes.spec.ts
│ │ │ │ ├── extension-manager.test.ts
│ │ │ │ ├── extension-manager.ts
│ │ │ │ ├── extension.test.ts
│ │ │ │ ├── extension.ts
│ │ │ │ ├── extensionRegistryClient.test.ts
│ │ │ │ ├── extensionRegistryClient.ts
│ │ │ │ ├── extensions/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── consent.test.ts.snap
│ │ │ │ │ ├── consent.test.ts
│ │ │ │ │ ├── consent.ts
│ │ │ │ │ ├── extensionEnablement.test.ts
│ │ │ │ │ ├── extensionEnablement.ts
│ │ │ │ │ ├── extensionSettings.test.ts
│ │ │ │ │ ├── extensionSettings.ts
│ │ │ │ │ ├── extensionUpdates.test.ts
│ │ │ │ │ ├── github.test.ts
│ │ │ │ │ ├── github.ts
│ │ │ │ │ ├── github_fetch.test.ts
│ │ │ │ │ ├── github_fetch.ts
│ │ │ │ │ ├── storage.test.ts
│ │ │ │ │ ├── storage.ts
│ │ │ │ │ ├── update.test.ts
│ │ │ │ │ ├── update.ts
│ │ │ │ │ ├── variableSchema.ts
│ │ │ │ │ ├── variables.test.ts
│ │ │ │ │ └── variables.ts
│ │ │ │ ├── footerItems.test.ts
│ │ │ │ ├── footerItems.ts
│ │ │ │ ├── mcp/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── mcpServerEnablement.test.ts
│ │ │ │ │ └── mcpServerEnablement.ts
│ │ │ │ ├── policy-engine.integration.test.ts
│ │ │ │ ├── policy.test.ts
│ │ │ │ ├── policy.ts
│ │ │ │ ├── sandboxConfig.test.ts
│ │ │ │ ├── sandboxConfig.ts
│ │ │ │ ├── settingPaths.test.ts
│ │ │ │ ├── settingPaths.ts
│ │ │ │ ├── settings-validation.test.ts
│ │ │ │ ├── settings-validation.ts
│ │ │ │ ├── settings.test.ts
│ │ │ │ ├── settings.ts
│ │ │ │ ├── settingsSchema.test.ts
│ │ │ │ ├── settingsSchema.ts
│ │ │ │ ├── settings_repro.test.ts
│ │ │ │ ├── settings_validation_warning.test.ts
│ │ │ │ ├── trustedFolders.test.ts
│ │ │ │ ├── trustedFolders.ts
│ │ │ │ └── workspace-policy-cli.test.ts
│ │ │ ├── core/
│ │ │ │ ├── auth.test.ts
│ │ │ │ ├── auth.ts
│ │ │ │ ├── initializer.test.ts
│ │ │ │ ├── initializer.ts
│ │ │ │ ├── theme.test.ts
│ │ │ │ └── theme.ts
│ │ │ ├── deferred.test.ts
│ │ │ ├── deferred.ts
│ │ │ ├── gemini.test.tsx
│ │ │ ├── gemini.tsx
│ │ │ ├── gemini_cleanup.test.tsx
│ │ │ ├── integration-tests/
│ │ │ │ └── modelSteering.test.tsx
│ │ │ ├── interactiveCli.tsx
│ │ │ ├── nonInteractiveCli.test.ts
│ │ │ ├── nonInteractiveCli.ts
│ │ │ ├── nonInteractiveCliCommands.ts
│ │ │ ├── patches/
│ │ │ │ └── is-in-ci.ts
│ │ │ ├── services/
│ │ │ │ ├── BuiltinCommandLoader.test.ts
│ │ │ │ ├── BuiltinCommandLoader.ts
│ │ │ │ ├── CommandService.test.ts
│ │ │ │ ├── CommandService.ts
│ │ │ │ ├── FileCommandLoader.test.ts
│ │ │ │ ├── FileCommandLoader.ts
│ │ │ │ ├── McpPromptLoader.test.ts
│ │ │ │ ├── McpPromptLoader.ts
│ │ │ │ ├── SkillCommandLoader.test.ts
│ │ │ │ ├── SkillCommandLoader.ts
│ │ │ │ ├── SlashCommandConflictHandler.test.ts
│ │ │ │ ├── SlashCommandConflictHandler.ts
│ │ │ │ ├── SlashCommandResolver.test.ts
│ │ │ │ ├── SlashCommandResolver.ts
│ │ │ │ ├── prompt-processors/
│ │ │ │ │ ├── argumentProcessor.test.ts
│ │ │ │ │ ├── argumentProcessor.ts
│ │ │ │ │ ├── atFileProcessor.test.ts
│ │ │ │ │ ├── atFileProcessor.ts
│ │ │ │ │ ├── injectionParser.test.ts
│ │ │ │ │ ├── injectionParser.ts
│ │ │ │ │ ├── shellProcessor.test.ts
│ │ │ │ │ ├── shellProcessor.ts
│ │ │ │ │ └── types.ts
│ │ │ │ └── types.ts
│ │ │ ├── test-utils/
│ │ │ │ ├── AppRig.test.tsx
│ │ │ │ ├── AppRig.tsx
│ │ │ │ ├── MockShellExecutionService.ts
│ │ │ │ ├── async.ts
│ │ │ │ ├── createExtension.ts
│ │ │ │ ├── customMatchers.ts
│ │ │ │ ├── fixtures/
│ │ │ │ │ ├── simple.responses
│ │ │ │ │ └── steering.responses
│ │ │ │ ├── mockCommandContext.test.ts
│ │ │ │ ├── mockCommandContext.ts
│ │ │ │ ├── mockConfig.ts
│ │ │ │ ├── mockDebugLogger.ts
│ │ │ │ ├── persistentStateFake.ts
│ │ │ │ ├── render.test.tsx
│ │ │ │ ├── render.tsx
│ │ │ │ ├── settings.ts
│ │ │ │ └── svg.ts
│ │ │ ├── ui/
│ │ │ │ ├── App.test.tsx
│ │ │ │ ├── App.tsx
│ │ │ │ ├── AppContainer.test.tsx
│ │ │ │ ├── AppContainer.tsx
│ │ │ │ ├── IdeIntegrationNudge.test.tsx
│ │ │ │ ├── IdeIntegrationNudge.tsx
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── App.test.tsx.snap
│ │ │ │ ├── auth/
│ │ │ │ │ ├── ApiAuthDialog.test.tsx
│ │ │ │ │ ├── ApiAuthDialog.tsx
│ │ │ │ │ ├── AuthDialog.test.tsx
│ │ │ │ │ ├── AuthDialog.tsx
│ │ │ │ │ ├── AuthInProgress.test.tsx
│ │ │ │ │ ├── AuthInProgress.tsx
│ │ │ │ │ ├── BannedAccountDialog.test.tsx
│ │ │ │ │ ├── BannedAccountDialog.tsx
│ │ │ │ │ ├── LoginWithGoogleRestartDialog.test.tsx
│ │ │ │ │ ├── LoginWithGoogleRestartDialog.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ ├── ApiAuthDialog.test.tsx.snap
│ │ │ │ │ │ ├── AuthDialog.test.tsx.snap
│ │ │ │ │ │ ├── BannedAccountDialog.test.tsx.snap
│ │ │ │ │ │ └── LoginWithGoogleRestartDialog.test.tsx.snap
│ │ │ │ │ ├── useAuth.test.tsx
│ │ │ │ │ └── useAuth.ts
│ │ │ │ ├── colors.ts
│ │ │ │ ├── commands/
│ │ │ │ │ ├── aboutCommand.test.ts
│ │ │ │ │ ├── aboutCommand.ts
│ │ │ │ │ ├── agentsCommand.test.ts
│ │ │ │ │ ├── agentsCommand.ts
│ │ │ │ │ ├── authCommand.test.ts
│ │ │ │ │ ├── authCommand.ts
│ │ │ │ │ ├── bugCommand.test.ts
│ │ │ │ │ ├── bugCommand.ts
│ │ │ │ │ ├── chatCommand.test.ts
│ │ │ │ │ ├── chatCommand.ts
│ │ │ │ │ ├── clearCommand.test.ts
│ │ │ │ │ ├── clearCommand.ts
│ │ │ │ │ ├── commandsCommand.test.ts
│ │ │ │ │ ├── commandsCommand.ts
│ │ │ │ │ ├── compressCommand.test.ts
│ │ │ │ │ ├── compressCommand.ts
│ │ │ │ │ ├── copyCommand.test.ts
│ │ │ │ │ ├── copyCommand.ts
│ │ │ │ │ ├── corgiCommand.test.ts
│ │ │ │ │ ├── corgiCommand.ts
│ │ │ │ │ ├── directoryCommand.test.tsx
│ │ │ │ │ ├── directoryCommand.tsx
│ │ │ │ │ ├── docsCommand.test.ts
│ │ │ │ │ ├── docsCommand.ts
│ │ │ │ │ ├── editorCommand.test.ts
│ │ │ │ │ ├── editorCommand.ts
│ │ │ │ │ ├── extensionsCommand.test.ts
│ │ │ │ │ ├── extensionsCommand.ts
│ │ │ │ │ ├── footerCommand.tsx
│ │ │ │ │ ├── helpCommand.test.ts
│ │ │ │ │ ├── helpCommand.ts
│ │ │ │ │ ├── hooksCommand.test.ts
│ │ │ │ │ ├── hooksCommand.ts
│ │ │ │ │ ├── ideCommand.test.ts
│ │ │ │ │ ├── ideCommand.ts
│ │ │ │ │ ├── initCommand.test.ts
│ │ │ │ │ ├── initCommand.ts
│ │ │ │ │ ├── mcpCommand.test.ts
│ │ │ │ │ ├── mcpCommand.ts
│ │ │ │ │ ├── memoryCommand.test.ts
│ │ │ │ │ ├── memoryCommand.ts
│ │ │ │ │ ├── modelCommand.test.ts
│ │ │ │ │ ├── modelCommand.ts
│ │ │ │ │ ├── oncallCommand.tsx
│ │ │ │ │ ├── permissionsCommand.test.ts
│ │ │ │ │ ├── permissionsCommand.ts
│ │ │ │ │ ├── planCommand.test.ts
│ │ │ │ │ ├── planCommand.ts
│ │ │ │ │ ├── policiesCommand.test.ts
│ │ │ │ │ ├── policiesCommand.ts
│ │ │ │ │ ├── privacyCommand.test.ts
│ │ │ │ │ ├── privacyCommand.ts
│ │ │ │ │ ├── profileCommand.ts
│ │ │ │ │ ├── quitCommand.test.ts
│ │ │ │ │ ├── quitCommand.ts
│ │ │ │ │ ├── restoreCommand.test.ts
│ │ │ │ │ ├── restoreCommand.ts
│ │ │ │ │ ├── resumeCommand.test.ts
│ │ │ │ │ ├── resumeCommand.ts
│ │ │ │ │ ├── rewindCommand.test.tsx
│ │ │ │ │ ├── rewindCommand.tsx
│ │ │ │ │ ├── settingsCommand.test.ts
│ │ │ │ │ ├── settingsCommand.ts
│ │ │ │ │ ├── setupGithubCommand.test.ts
│ │ │ │ │ ├── setupGithubCommand.ts
│ │ │ │ │ ├── shellsCommand.test.ts
│ │ │ │ │ ├── shellsCommand.ts
│ │ │ │ │ ├── shortcutsCommand.ts
│ │ │ │ │ ├── skillsCommand.test.ts
│ │ │ │ │ ├── skillsCommand.ts
│ │ │ │ │ ├── statsCommand.test.ts
│ │ │ │ │ ├── statsCommand.ts
│ │ │ │ │ ├── terminalSetupCommand.test.ts
│ │ │ │ │ ├── terminalSetupCommand.ts
│ │ │ │ │ ├── themeCommand.test.ts
│ │ │ │ │ ├── themeCommand.ts
│ │ │ │ │ ├── toolsCommand.test.ts
│ │ │ │ │ ├── toolsCommand.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ ├── upgradeCommand.test.ts
│ │ │ │ │ ├── upgradeCommand.ts
│ │ │ │ │ └── vimCommand.ts
│ │ │ │ ├── components/
│ │ │ │ │ ├── AboutBox.test.tsx
│ │ │ │ │ ├── AboutBox.tsx
│ │ │ │ │ ├── AdminSettingsChangedDialog.test.tsx
│ │ │ │ │ ├── AdminSettingsChangedDialog.tsx
│ │ │ │ │ ├── AgentConfigDialog.test.tsx
│ │ │ │ │ ├── AgentConfigDialog.tsx
│ │ │ │ │ ├── AlternateBufferQuittingDisplay.test.tsx
│ │ │ │ │ ├── AlternateBufferQuittingDisplay.tsx
│ │ │ │ │ ├── AnsiOutput.test.tsx
│ │ │ │ │ ├── AnsiOutput.tsx
│ │ │ │ │ ├── AppHeader.test.tsx
│ │ │ │ │ ├── AppHeader.tsx
│ │ │ │ │ ├── AppHeaderIcon.test.tsx
│ │ │ │ │ ├── ApprovalModeIndicator.test.tsx
│ │ │ │ │ ├── ApprovalModeIndicator.tsx
│ │ │ │ │ ├── AsciiArt.ts
│ │ │ │ │ ├── AskUserDialog.test.tsx
│ │ │ │ │ ├── AskUserDialog.tsx
│ │ │ │ │ ├── BackgroundShellDisplay.test.tsx
│ │ │ │ │ ├── BackgroundShellDisplay.tsx
│ │ │ │ │ ├── Banner.test.tsx
│ │ │ │ │ ├── Banner.tsx
│ │ │ │ │ ├── BubblingRegression.test.tsx
│ │ │ │ │ ├── Checklist.test.tsx
│ │ │ │ │ ├── Checklist.tsx
│ │ │ │ │ ├── ChecklistItem.test.tsx
│ │ │ │ │ ├── ChecklistItem.tsx
│ │ │ │ │ ├── CliSpinner.test.tsx
│ │ │ │ │ ├── CliSpinner.tsx
│ │ │ │ │ ├── ColorsDisplay.test.tsx
│ │ │ │ │ ├── ColorsDisplay.tsx
│ │ │ │ │ ├── Composer.test.tsx
│ │ │ │ │ ├── Composer.tsx
│ │ │ │ │ ├── ConfigExtensionDialog.tsx
│ │ │ │ │ ├── ConfigInitDisplay.test.tsx
│ │ │ │ │ ├── ConfigInitDisplay.tsx
│ │ │ │ │ ├── ConsentPrompt.test.tsx
│ │ │ │ │ ├── ConsentPrompt.tsx
│ │ │ │ │ ├── ConsoleSummaryDisplay.test.tsx
│ │ │ │ │ ├── ConsoleSummaryDisplay.tsx
│ │ │ │ │ ├── ContextSummaryDisplay.test.tsx
│ │ │ │ │ ├── ContextSummaryDisplay.tsx
│ │ │ │ │ ├── ContextUsageDisplay.test.tsx
│ │ │ │ │ ├── ContextUsageDisplay.tsx
│ │ │ │ │ ├── CopyModeWarning.test.tsx
│ │ │ │ │ ├── CopyModeWarning.tsx
│ │ │ │ │ ├── DebugProfiler.test.tsx
│ │ │ │ │ ├── DebugProfiler.tsx
│ │ │ │ │ ├── DetailedMessagesDisplay.test.tsx
│ │ │ │ │ ├── DetailedMessagesDisplay.tsx
│ │ │ │ │ ├── DialogManager.test.tsx
│ │ │ │ │ ├── DialogManager.tsx
│ │ │ │ │ ├── EditorSettingsDialog.test.tsx
│ │ │ │ │ ├── EditorSettingsDialog.tsx
│ │ │ │ │ ├── EmptyWalletDialog.test.tsx
│ │ │ │ │ ├── EmptyWalletDialog.tsx
│ │ │ │ │ ├── ExitPlanModeDialog.test.tsx
│ │ │ │ │ ├── ExitPlanModeDialog.tsx
│ │ │ │ │ ├── ExitWarning.test.tsx
│ │ │ │ │ ├── ExitWarning.tsx
│ │ │ │ │ ├── FolderTrustDialog.test.tsx
│ │ │ │ │ ├── FolderTrustDialog.tsx
│ │ │ │ │ ├── Footer.test.tsx
│ │ │ │ │ ├── Footer.tsx
│ │ │ │ │ ├── FooterConfigDialog.test.tsx
│ │ │ │ │ ├── FooterConfigDialog.tsx
│ │ │ │ │ ├── GeminiRespondingSpinner.test.tsx
│ │ │ │ │ ├── GeminiRespondingSpinner.tsx
│ │ │ │ │ ├── GeminiSpinner.tsx
│ │ │ │ │ ├── GradientRegression.test.tsx
│ │ │ │ │ ├── Header.test.tsx
│ │ │ │ │ ├── Header.tsx
│ │ │ │ │ ├── Help.test.tsx
│ │ │ │ │ ├── Help.tsx
│ │ │ │ │ ├── HistoryItemDisplay.test.tsx
│ │ │ │ │ ├── HistoryItemDisplay.tsx
│ │ │ │ │ ├── HookStatusDisplay.test.tsx
│ │ │ │ │ ├── HookStatusDisplay.tsx
│ │ │ │ │ ├── HooksDialog.test.tsx
│ │ │ │ │ ├── HooksDialog.tsx
│ │ │ │ │ ├── IdeTrustChangeDialog.test.tsx
│ │ │ │ │ ├── IdeTrustChangeDialog.tsx
│ │ │ │ │ ├── InputPrompt.test.tsx
│ │ │ │ │ ├── InputPrompt.tsx
│ │ │ │ │ ├── LoadingIndicator.test.tsx
│ │ │ │ │ ├── LoadingIndicator.tsx
│ │ │ │ │ ├── LogoutConfirmationDialog.test.tsx
│ │ │ │ │ ├── LogoutConfirmationDialog.tsx
│ │ │ │ │ ├── LoopDetectionConfirmation.test.tsx
│ │ │ │ │ ├── LoopDetectionConfirmation.tsx
│ │ │ │ │ ├── MainContent.test.tsx
│ │ │ │ │ ├── MainContent.tsx
│ │ │ │ │ ├── MemoryUsageDisplay.test.tsx
│ │ │ │ │ ├── MemoryUsageDisplay.tsx
│ │ │ │ │ ├── ModelDialog.test.tsx
│ │ │ │ │ ├── ModelDialog.tsx
│ │ │ │ │ ├── ModelStatsDisplay.test.tsx
│ │ │ │ │ ├── ModelStatsDisplay.tsx
│ │ │ │ │ ├── MultiFolderTrustDialog.test.tsx
│ │ │ │ │ ├── MultiFolderTrustDialog.tsx
│ │ │ │ │ ├── NewAgentsNotification.test.tsx
│ │ │ │ │ ├── NewAgentsNotification.tsx
│ │ │ │ │ ├── Notifications.test.tsx
│ │ │ │ │ ├── Notifications.tsx
│ │ │ │ │ ├── OverageMenuDialog.test.tsx
│ │ │ │ │ ├── OverageMenuDialog.tsx
│ │ │ │ │ ├── PermissionsModifyTrustDialog.test.tsx
│ │ │ │ │ ├── PermissionsModifyTrustDialog.tsx
│ │ │ │ │ ├── PolicyUpdateDialog.test.tsx
│ │ │ │ │ ├── PolicyUpdateDialog.tsx
│ │ │ │ │ ├── ProQuotaDialog.test.tsx
│ │ │ │ │ ├── ProQuotaDialog.tsx
│ │ │ │ │ ├── QueuedMessageDisplay.test.tsx
│ │ │ │ │ ├── QueuedMessageDisplay.tsx
│ │ │ │ │ ├── QuittingDisplay.test.tsx
│ │ │ │ │ ├── QuittingDisplay.tsx
│ │ │ │ │ ├── QuotaDisplay.test.tsx
│ │ │ │ │ ├── QuotaDisplay.tsx
│ │ │ │ │ ├── QuotaStatsInfo.tsx
│ │ │ │ │ ├── RawMarkdownIndicator.test.tsx
│ │ │ │ │ ├── RawMarkdownIndicator.tsx
│ │ │ │ │ ├── RewindConfirmation.test.tsx
│ │ │ │ │ ├── RewindConfirmation.tsx
│ │ │ │ │ ├── RewindViewer.test.tsx
│ │ │ │ │ ├── RewindViewer.tsx
│ │ │ │ │ ├── SessionBrowser/
│ │ │ │ │ │ ├── SessionBrowserEmpty.tsx
│ │ │ │ │ │ ├── SessionBrowserError.tsx
│ │ │ │ │ │ ├── SessionBrowserLoading.tsx
│ │ │ │ │ │ ├── SessionBrowserNav.tsx
│ │ │ │ │ │ ├── SessionBrowserSearchNav.test.tsx
│ │ │ │ │ │ ├── SessionBrowserStates.test.tsx
│ │ │ │ │ │ ├── SessionListHeader.tsx
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ ├── SessionBrowserSearchNav.test.tsx.snap
│ │ │ │ │ │ │ └── SessionBrowserStates.test.tsx.snap
│ │ │ │ │ │ ├── utils.test.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ ├── SessionBrowser.test.tsx
│ │ │ │ │ ├── SessionBrowser.tsx
│ │ │ │ │ ├── SessionSummaryDisplay.test.tsx
│ │ │ │ │ ├── SessionSummaryDisplay.tsx
│ │ │ │ │ ├── SettingsDialog.test.tsx
│ │ │ │ │ ├── SettingsDialog.tsx
│ │ │ │ │ ├── ShellInputPrompt.test.tsx
│ │ │ │ │ ├── ShellInputPrompt.tsx
│ │ │ │ │ ├── ShellModeIndicator.test.tsx
│ │ │ │ │ ├── ShellModeIndicator.tsx
│ │ │ │ │ ├── ShortcutsHelp.test.tsx
│ │ │ │ │ ├── ShortcutsHelp.tsx
│ │ │ │ │ ├── ShortcutsHint.tsx
│ │ │ │ │ ├── ShowMoreLines.test.tsx
│ │ │ │ │ ├── ShowMoreLines.tsx
│ │ │ │ │ ├── ShowMoreLinesLayout.test.tsx
│ │ │ │ │ ├── StatsDisplay.test.tsx
│ │ │ │ │ ├── StatsDisplay.tsx
│ │ │ │ │ ├── StatusDisplay.test.tsx
│ │ │ │ │ ├── StatusDisplay.tsx
│ │ │ │ │ ├── StickyHeader.test.tsx
│ │ │ │ │ ├── StickyHeader.tsx
│ │ │ │ │ ├── SuggestionsDisplay.test.tsx
│ │ │ │ │ ├── SuggestionsDisplay.tsx
│ │ │ │ │ ├── Table.test.tsx
│ │ │ │ │ ├── Table.tsx
│ │ │ │ │ ├── ThemeDialog.test.tsx
│ │ │ │ │ ├── ThemeDialog.tsx
│ │ │ │ │ ├── ThemedGradient.test.tsx
│ │ │ │ │ ├── ThemedGradient.tsx
│ │ │ │ │ ├── Tips.test.tsx
│ │ │ │ │ ├── Tips.tsx
│ │ │ │ │ ├── ToastDisplay.test.tsx
│ │ │ │ │ ├── ToastDisplay.tsx
│ │ │ │ │ ├── ToolConfirmationQueue.test.tsx
│ │ │ │ │ ├── ToolConfirmationQueue.tsx
│ │ │ │ │ ├── ToolStatsDisplay.test.tsx
│ │ │ │ │ ├── ToolStatsDisplay.tsx
│ │ │ │ │ ├── UpdateNotification.test.tsx
│ │ │ │ │ ├── UpdateNotification.tsx
│ │ │ │ │ ├── UserIdentity.test.tsx
│ │ │ │ │ ├── UserIdentity.tsx
│ │ │ │ │ ├── ValidationDialog.test.tsx
│ │ │ │ │ ├── ValidationDialog.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ ├── AdminSettingsChangedDialog.test.tsx.snap
│ │ │ │ │ │ ├── AlternateBufferQuittingDisplay.test.tsx.snap
│ │ │ │ │ │ ├── AppHeader.test.tsx.snap
│ │ │ │ │ │ ├── AppHeaderIcon.test.tsx.snap
│ │ │ │ │ │ ├── ApprovalModeIndicator.test.tsx.snap
│ │ │ │ │ │ ├── AskUserDialog.test.tsx.snap
│ │ │ │ │ │ ├── BackgroundShellDisplay.test.tsx.snap
│ │ │ │ │ │ ├── Banner.test.tsx.snap
│ │ │ │ │ │ ├── Checklist.test.tsx.snap
│ │ │ │ │ │ ├── ChecklistItem.test.tsx.snap
│ │ │ │ │ │ ├── Composer.test.tsx.snap
│ │ │ │ │ │ ├── ConfigInitDisplay.test.tsx.snap
│ │ │ │ │ │ ├── ContextSummaryDisplay.test.tsx.snap
│ │ │ │ │ │ ├── DetailedMessagesDisplay.test.tsx.snap
│ │ │ │ │ │ ├── EditorSettingsDialog.test.tsx.snap
│ │ │ │ │ │ ├── EmptyWalletDialog.test.tsx.snap
│ │ │ │ │ │ ├── ExitPlanModeDialog.test.tsx.snap
│ │ │ │ │ │ ├── Footer.test.tsx.snap
│ │ │ │ │ │ ├── FooterConfigDialog.test.tsx.snap
│ │ │ │ │ │ ├── HistoryItemDisplay.test.tsx.snap
│ │ │ │ │ │ ├── HookStatusDisplay.test.tsx.snap
│ │ │ │ │ │ ├── HooksDialog.test.tsx.snap
│ │ │ │ │ │ ├── IDEContextDetailDisplay.test.tsx.snap
│ │ │ │ │ │ ├── InputPrompt.test.tsx.snap
│ │ │ │ │ │ ├── LoadingIndicator.test.tsx.snap
│ │ │ │ │ │ ├── LoopDetectionConfirmation.test.tsx.snap
│ │ │ │ │ │ ├── MainContent.test.tsx.snap
│ │ │ │ │ │ ├── ModelStatsDisplay.test.tsx.snap
│ │ │ │ │ │ ├── NewAgentsNotification.test.tsx.snap
│ │ │ │ │ │ ├── Notifications.test.tsx.snap
│ │ │ │ │ │ ├── OverageMenuDialog.test.tsx.snap
│ │ │ │ │ │ ├── PolicyUpdateDialog.test.tsx.snap
│ │ │ │ │ │ ├── PrepareLabel.test.tsx.snap
│ │ │ │ │ │ ├── QuotaDisplay.test.tsx.snap
│ │ │ │ │ │ ├── RewindConfirmation.test.tsx.snap
│ │ │ │ │ │ ├── RewindViewer.test.tsx.snap
│ │ │ │ │ │ ├── SessionBrowser.test.tsx.snap
│ │ │ │ │ │ ├── SessionSummaryDisplay.test.tsx.snap
│ │ │ │ │ │ ├── SettingsDialog.test.tsx.snap
│ │ │ │ │ │ ├── ShortcutsHelp.test.tsx.snap
│ │ │ │ │ │ ├── StatsDisplay.test.tsx.snap
│ │ │ │ │ │ ├── StatusDisplay.test.tsx.snap
│ │ │ │ │ │ ├── SuggestionsDisplay.test.tsx.snap
│ │ │ │ │ │ ├── Table.test.tsx.snap
│ │ │ │ │ │ ├── ThemeDialog.test.tsx.snap
│ │ │ │ │ │ ├── Tips.test.tsx.snap
│ │ │ │ │ │ ├── ToastDisplay.test.tsx.snap
│ │ │ │ │ │ ├── ToolConfirmationQueue.test.tsx.snap
│ │ │ │ │ │ └── ToolStatsDisplay.test.tsx.snap
│ │ │ │ │ ├── messages/
│ │ │ │ │ │ ├── CompressionMessage.test.tsx
│ │ │ │ │ │ ├── CompressionMessage.tsx
│ │ │ │ │ │ ├── DiffRenderer.test.tsx
│ │ │ │ │ │ ├── DiffRenderer.tsx
│ │ │ │ │ │ ├── ErrorMessage.test.tsx
│ │ │ │ │ │ ├── ErrorMessage.tsx
│ │ │ │ │ │ ├── GeminiMessage.test.tsx
│ │ │ │ │ │ ├── GeminiMessage.tsx
│ │ │ │ │ │ ├── GeminiMessageContent.tsx
│ │ │ │ │ │ ├── HintMessage.tsx
│ │ │ │ │ │ ├── InfoMessage.test.tsx
│ │ │ │ │ │ ├── InfoMessage.tsx
│ │ │ │ │ │ ├── ModelMessage.tsx
│ │ │ │ │ │ ├── RedirectionConfirmation.test.tsx
│ │ │ │ │ │ ├── ShellToolMessage.test.tsx
│ │ │ │ │ │ ├── ShellToolMessage.tsx
│ │ │ │ │ │ ├── SubagentGroupDisplay.test.tsx
│ │ │ │ │ │ ├── SubagentGroupDisplay.tsx
│ │ │ │ │ │ ├── SubagentProgressDisplay.test.tsx
│ │ │ │ │ │ ├── SubagentProgressDisplay.tsx
│ │ │ │ │ │ ├── ThinkingMessage.test.tsx
│ │ │ │ │ │ ├── ThinkingMessage.tsx
│ │ │ │ │ │ ├── Todo.test.tsx
│ │ │ │ │ │ ├── Todo.tsx
│ │ │ │ │ │ ├── ToolConfirmationMessage.test.tsx
│ │ │ │ │ │ ├── ToolConfirmationMessage.tsx
│ │ │ │ │ │ ├── ToolGroupMessage.test.tsx
│ │ │ │ │ │ ├── ToolGroupMessage.tsx
│ │ │ │ │ │ ├── ToolMessage.test.tsx
│ │ │ │ │ │ ├── ToolMessage.tsx
│ │ │ │ │ │ ├── ToolMessageFocusHint.test.tsx
│ │ │ │ │ │ ├── ToolMessageRawMarkdown.test.tsx
│ │ │ │ │ │ ├── ToolOverflowConsistencyChecks.test.tsx
│ │ │ │ │ │ ├── ToolResultDisplay.test.tsx
│ │ │ │ │ │ ├── ToolResultDisplay.tsx
│ │ │ │ │ │ ├── ToolResultDisplayOverflow.test.tsx
│ │ │ │ │ │ ├── ToolShared.test.tsx
│ │ │ │ │ │ ├── ToolShared.tsx
│ │ │ │ │ │ ├── ToolStickyHeaderRegression.test.tsx
│ │ │ │ │ │ ├── UserMessage.test.tsx
│ │ │ │ │ │ ├── UserMessage.tsx
│ │ │ │ │ │ ├── UserShellMessage.tsx
│ │ │ │ │ │ ├── WarningMessage.test.tsx
│ │ │ │ │ │ ├── WarningMessage.tsx
│ │ │ │ │ │ └── __snapshots__/
│ │ │ │ │ │ ├── DiffRenderer.test.tsx.snap
│ │ │ │ │ │ ├── ErrorMessage.test.tsx.snap
│ │ │ │ │ │ ├── GeminiMessage.test.tsx.snap
│ │ │ │ │ │ ├── InfoMessage.test.tsx.snap
│ │ │ │ │ │ ├── RedirectionConfirmation.test.tsx.snap
│ │ │ │ │ │ ├── ShellToolMessage.test.tsx.snap
│ │ │ │ │ │ ├── SubagentGroupDisplay.test.tsx.snap
│ │ │ │ │ │ ├── SubagentProgressDisplay.test.tsx.snap
│ │ │ │ │ │ ├── ThinkingMessage.test.tsx.snap
│ │ │ │ │ │ ├── Todo.test.tsx.snap
│ │ │ │ │ │ ├── ToolConfirmationMessage.test.tsx.snap
│ │ │ │ │ │ ├── ToolConfirmationMessageOverflow.test.tsx.snap
│ │ │ │ │ │ ├── ToolGroupMessage.test.tsx.snap
│ │ │ │ │ │ ├── ToolMessage.test.tsx.snap
│ │ │ │ │ │ ├── ToolMessageFocusHint.test.tsx.snap
│ │ │ │ │ │ ├── ToolMessageRawMarkdown.test.tsx.snap
│ │ │ │ │ │ ├── ToolResultDisplay.test.tsx.snap
│ │ │ │ │ │ ├── ToolShared.test.tsx.snap
│ │ │ │ │ │ ├── ToolStickyHeaderRegression.test.tsx.snap
│ │ │ │ │ │ ├── UserMessage.test.tsx.snap
│ │ │ │ │ │ └── WarningMessage.test.tsx.snap
│ │ │ │ │ ├── shared/
│ │ │ │ │ │ ├── BaseSelectionList.test.tsx
│ │ │ │ │ │ ├── BaseSelectionList.tsx
│ │ │ │ │ │ ├── BaseSettingsDialog.test.tsx
│ │ │ │ │ │ ├── BaseSettingsDialog.tsx
│ │ │ │ │ │ ├── DescriptiveRadioButtonSelect.test.tsx
│ │ │ │ │ │ ├── DescriptiveRadioButtonSelect.tsx
│ │ │ │ │ │ ├── DialogFooter.tsx
│ │ │ │ │ │ ├── EnumSelector.test.tsx
│ │ │ │ │ │ ├── EnumSelector.tsx
│ │ │ │ │ │ ├── ExpandableText.test.tsx
│ │ │ │ │ │ ├── ExpandableText.tsx
│ │ │ │ │ │ ├── HalfLinePaddedBox.test.tsx
│ │ │ │ │ │ ├── HalfLinePaddedBox.tsx
│ │ │ │ │ │ ├── HorizontalLine.tsx
│ │ │ │ │ │ ├── MaxSizedBox.test.tsx
│ │ │ │ │ │ ├── MaxSizedBox.tsx
│ │ │ │ │ │ ├── RadioButtonSelect.test.tsx
│ │ │ │ │ │ ├── RadioButtonSelect.tsx
│ │ │ │ │ │ ├── ScopeSelector.tsx
│ │ │ │ │ │ ├── Scrollable.test.tsx
│ │ │ │ │ │ ├── Scrollable.tsx
│ │ │ │ │ │ ├── ScrollableList.test.tsx
│ │ │ │ │ │ ├── ScrollableList.tsx
│ │ │ │ │ │ ├── SearchableList.test.tsx
│ │ │ │ │ │ ├── SearchableList.tsx
│ │ │ │ │ │ ├── SectionHeader.test.tsx
│ │ │ │ │ │ ├── SectionHeader.tsx
│ │ │ │ │ │ ├── SlicingMaxSizedBox.test.tsx
│ │ │ │ │ │ ├── SlicingMaxSizedBox.tsx
│ │ │ │ │ │ ├── TabHeader.test.tsx
│ │ │ │ │ │ ├── TabHeader.tsx
│ │ │ │ │ │ ├── TextInput.test.tsx
│ │ │ │ │ │ ├── TextInput.tsx
│ │ │ │ │ │ ├── VirtualizedList.test.tsx
│ │ │ │ │ │ ├── VirtualizedList.tsx
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ ├── BaseSelectionList.test.tsx.snap
│ │ │ │ │ │ │ ├── DescriptiveRadioButtonSelect.test.tsx.snap
│ │ │ │ │ │ │ ├── EnumSelector.test.tsx.snap
│ │ │ │ │ │ │ ├── ExpandablePrompt.test.tsx.snap
│ │ │ │ │ │ │ ├── ExpandableText.test.tsx.snap
│ │ │ │ │ │ │ ├── HalfLinePaddedBox.test.tsx.snap
│ │ │ │ │ │ │ ├── MaxSizedBox.test.tsx.snap
│ │ │ │ │ │ │ ├── Scrollable.test.tsx.snap
│ │ │ │ │ │ │ ├── SearchableList.test.tsx.snap
│ │ │ │ │ │ │ ├── SectionHeader.test.tsx.snap
│ │ │ │ │ │ │ ├── TabHeader.test.tsx.snap
│ │ │ │ │ │ │ └── VirtualizedList.test.tsx.snap
│ │ │ │ │ │ ├── performance.test.ts
│ │ │ │ │ │ ├── text-buffer.test.ts
│ │ │ │ │ │ ├── text-buffer.ts
│ │ │ │ │ │ ├── vim-buffer-actions.test.ts
│ │ │ │ │ │ └── vim-buffer-actions.ts
│ │ │ │ │ ├── triage/
│ │ │ │ │ │ ├── TriageDuplicates.tsx
│ │ │ │ │ │ └── TriageIssues.tsx
│ │ │ │ │ └── views/
│ │ │ │ │ ├── AgentsStatus.tsx
│ │ │ │ │ ├── ChatList.test.tsx
│ │ │ │ │ ├── ChatList.tsx
│ │ │ │ │ ├── ExtensionDetails.test.tsx
│ │ │ │ │ ├── ExtensionDetails.tsx
│ │ │ │ │ ├── ExtensionRegistryView.test.tsx
│ │ │ │ │ ├── ExtensionRegistryView.tsx
│ │ │ │ │ ├── ExtensionsList.test.tsx
│ │ │ │ │ ├── ExtensionsList.tsx
│ │ │ │ │ ├── McpStatus.test.tsx
│ │ │ │ │ ├── McpStatus.tsx
│ │ │ │ │ ├── SkillsList.test.tsx
│ │ │ │ │ ├── SkillsList.tsx
│ │ │ │ │ ├── ToolsList.test.tsx
│ │ │ │ │ ├── ToolsList.tsx
│ │ │ │ │ └── __snapshots__/
│ │ │ │ │ ├── ChatList.test.tsx.snap
│ │ │ │ │ ├── McpStatus.test.tsx.snap
│ │ │ │ │ └── ToolsList.test.tsx.snap
│ │ │ │ ├── constants/
│ │ │ │ │ ├── tips.ts
│ │ │ │ │ └── wittyPhrases.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── contexts/
│ │ │ │ │ ├── AppContext.tsx
│ │ │ │ │ ├── AskUserActionsContext.tsx
│ │ │ │ │ ├── ConfigContext.tsx
│ │ │ │ │ ├── KeypressContext.test.tsx
│ │ │ │ │ ├── KeypressContext.tsx
│ │ │ │ │ ├── MouseContext.test.tsx
│ │ │ │ │ ├── MouseContext.tsx
│ │ │ │ │ ├── OverflowContext.tsx
│ │ │ │ │ ├── ScrollProvider.drag.test.tsx
│ │ │ │ │ ├── ScrollProvider.test.tsx
│ │ │ │ │ ├── ScrollProvider.tsx
│ │ │ │ │ ├── SessionContext.test.tsx
│ │ │ │ │ ├── SessionContext.tsx
│ │ │ │ │ ├── SettingsContext.test.tsx
│ │ │ │ │ ├── SettingsContext.tsx
│ │ │ │ │ ├── ShellFocusContext.tsx
│ │ │ │ │ ├── StreamingContext.tsx
│ │ │ │ │ ├── TerminalContext.test.tsx
│ │ │ │ │ ├── TerminalContext.tsx
│ │ │ │ │ ├── ToolActionsContext.test.tsx
│ │ │ │ │ ├── ToolActionsContext.tsx
│ │ │ │ │ ├── UIActionsContext.tsx
│ │ │ │ │ ├── UIStateContext.tsx
│ │ │ │ │ └── VimModeContext.tsx
│ │ │ │ ├── debug.ts
│ │ │ │ ├── editors/
│ │ │ │ │ └── editorSettingsManager.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── usePhraseCycler.test.tsx.snap
│ │ │ │ │ ├── atCommandProcessor.test.ts
│ │ │ │ │ ├── atCommandProcessor.ts
│ │ │ │ │ ├── atCommandProcessor_agents.test.ts
│ │ │ │ │ ├── creditsFlowHandler.test.ts
│ │ │ │ │ ├── creditsFlowHandler.ts
│ │ │ │ │ ├── shell-completions/
│ │ │ │ │ │ ├── gitProvider.test.ts
│ │ │ │ │ │ ├── gitProvider.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── npmProvider.test.ts
│ │ │ │ │ │ ├── npmProvider.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── shellCommandProcessor.test.tsx
│ │ │ │ │ ├── shellCommandProcessor.ts
│ │ │ │ │ ├── shellReducer.test.ts
│ │ │ │ │ ├── shellReducer.ts
│ │ │ │ │ ├── slashCommandProcessor.test.tsx
│ │ │ │ │ ├── slashCommandProcessor.ts
│ │ │ │ │ ├── toolMapping.test.ts
│ │ │ │ │ ├── toolMapping.ts
│ │ │ │ │ ├── useAlternateBuffer.test.ts
│ │ │ │ │ ├── useAlternateBuffer.ts
│ │ │ │ │ ├── useAnimatedScrollbar.test.tsx
│ │ │ │ │ ├── useAnimatedScrollbar.ts
│ │ │ │ │ ├── useApprovalModeIndicator.test.ts
│ │ │ │ │ ├── useApprovalModeIndicator.ts
│ │ │ │ │ ├── useAtCompletion.test.ts
│ │ │ │ │ ├── useAtCompletion.ts
│ │ │ │ │ ├── useAtCompletion_agents.test.ts
│ │ │ │ │ ├── useBackgroundShellManager.test.tsx
│ │ │ │ │ ├── useBackgroundShellManager.ts
│ │ │ │ │ ├── useBanner.test.ts
│ │ │ │ │ ├── useBanner.ts
│ │ │ │ │ ├── useBatchedScroll.test.ts
│ │ │ │ │ ├── useBatchedScroll.ts
│ │ │ │ │ ├── useCommandCompletion.test.tsx
│ │ │ │ │ ├── useCommandCompletion.tsx
│ │ │ │ │ ├── useCompletion.ts
│ │ │ │ │ ├── useConfirmingTool.ts
│ │ │ │ │ ├── useConsoleMessages.test.tsx
│ │ │ │ │ ├── useConsoleMessages.ts
│ │ │ │ │ ├── useEditorSettings.test.tsx
│ │ │ │ │ ├── useEditorSettings.ts
│ │ │ │ │ ├── useExtensionRegistry.ts
│ │ │ │ │ ├── useExtensionUpdates.test.tsx
│ │ │ │ │ ├── useExtensionUpdates.ts
│ │ │ │ │ ├── useFlickerDetector.test.ts
│ │ │ │ │ ├── useFlickerDetector.ts
│ │ │ │ │ ├── useFocus.test.tsx
│ │ │ │ │ ├── useFocus.ts
│ │ │ │ │ ├── useFolderTrust.test.ts
│ │ │ │ │ ├── useFolderTrust.ts
│ │ │ │ │ ├── useGeminiStream.test.tsx
│ │ │ │ │ ├── useGeminiStream.ts
│ │ │ │ │ ├── useGitBranchName.test.tsx
│ │ │ │ │ ├── useGitBranchName.ts
│ │ │ │ │ ├── useHistoryManager.test.ts
│ │ │ │ │ ├── useHistoryManager.ts
│ │ │ │ │ ├── useHookDisplayState.test.ts
│ │ │ │ │ ├── useHookDisplayState.ts
│ │ │ │ │ ├── useIdeTrustListener.test.tsx
│ │ │ │ │ ├── useIdeTrustListener.ts
│ │ │ │ │ ├── useInactivityTimer.ts
│ │ │ │ │ ├── useIncludeDirsTrust.test.tsx
│ │ │ │ │ ├── useIncludeDirsTrust.tsx
│ │ │ │ │ ├── useInlineEditBuffer.test.ts
│ │ │ │ │ ├── useInlineEditBuffer.ts
│ │ │ │ │ ├── useInputHistory.test.ts
│ │ │ │ │ ├── useInputHistory.ts
│ │ │ │ │ ├── useInputHistoryStore.test.ts
│ │ │ │ │ ├── useInputHistoryStore.ts
│ │ │ │ │ ├── useKeyMatchers.tsx
│ │ │ │ │ ├── useKeypress.test.tsx
│ │ │ │ │ ├── useKeypress.ts
│ │ │ │ │ ├── useKittyKeyboardProtocol.ts
│ │ │ │ │ ├── useLoadingIndicator.test.tsx
│ │ │ │ │ ├── useLoadingIndicator.ts
│ │ │ │ │ ├── useLogger.test.tsx
│ │ │ │ │ ├── useLogger.ts
│ │ │ │ │ ├── useMcpStatus.test.tsx
│ │ │ │ │ ├── useMcpStatus.ts
│ │ │ │ │ ├── useMemoryMonitor.test.tsx
│ │ │ │ │ ├── useMemoryMonitor.ts
│ │ │ │ │ ├── useMessageQueue.test.tsx
│ │ │ │ │ ├── useMessageQueue.ts
│ │ │ │ │ ├── useModelCommand.test.tsx
│ │ │ │ │ ├── useModelCommand.ts
│ │ │ │ │ ├── useMouse.test.ts
│ │ │ │ │ ├── useMouse.ts
│ │ │ │ │ ├── useMouseClick.test.ts
│ │ │ │ │ ├── useMouseClick.ts
│ │ │ │ │ ├── usePermissionsModifyTrust.test.ts
│ │ │ │ │ ├── usePermissionsModifyTrust.ts
│ │ │ │ │ ├── usePhraseCycler.test.tsx
│ │ │ │ │ ├── usePhraseCycler.ts
│ │ │ │ │ ├── usePrivacySettings.test.tsx
│ │ │ │ │ ├── usePrivacySettings.ts
│ │ │ │ │ ├── usePromptCompletion.ts
│ │ │ │ │ ├── useQuotaAndFallback.test.ts
│ │ │ │ │ ├── useQuotaAndFallback.ts
│ │ │ │ │ ├── useRegistrySearch.ts
│ │ │ │ │ ├── useRepeatedKeyPress.ts
│ │ │ │ │ ├── useReverseSearchCompletion.test.tsx
│ │ │ │ │ ├── useReverseSearchCompletion.tsx
│ │ │ │ │ ├── useRewind.test.ts
│ │ │ │ │ ├── useRewind.ts
│ │ │ │ │ ├── useRunEventNotifications.ts
│ │ │ │ │ ├── useSearchBuffer.ts
│ │ │ │ │ ├── useSelectionList.test.tsx
│ │ │ │ │ ├── useSelectionList.ts
│ │ │ │ │ ├── useSessionBrowser.test.ts
│ │ │ │ │ ├── useSessionBrowser.ts
│ │ │ │ │ ├── useSessionResume.test.ts
│ │ │ │ │ ├── useSessionResume.ts
│ │ │ │ │ ├── useSettingsCommand.ts
│ │ │ │ │ ├── useSettingsNavigation.test.ts
│ │ │ │ │ ├── useSettingsNavigation.ts
│ │ │ │ │ ├── useShellCompletion.test.ts
│ │ │ │ │ ├── useShellCompletion.ts
│ │ │ │ │ ├── useShellHistory.test.ts
│ │ │ │ │ ├── useShellHistory.ts
│ │ │ │ │ ├── useShellInactivityStatus.test.ts
│ │ │ │ │ ├── useShellInactivityStatus.ts
│ │ │ │ │ ├── useSlashCompletion.test.ts
│ │ │ │ │ ├── useSlashCompletion.ts
│ │ │ │ │ ├── useSnowfall.test.tsx
│ │ │ │ │ ├── useSnowfall.ts
│ │ │ │ │ ├── useStateAndRef.ts
│ │ │ │ │ ├── useSuspend.test.ts
│ │ │ │ │ ├── useSuspend.ts
│ │ │ │ │ ├── useTabbedNavigation.test.ts
│ │ │ │ │ ├── useTabbedNavigation.ts
│ │ │ │ │ ├── useTerminalSize.ts
│ │ │ │ │ ├── useTerminalTheme.test.tsx
│ │ │ │ │ ├── useTerminalTheme.ts
│ │ │ │ │ ├── useThemeCommand.ts
│ │ │ │ │ ├── useTimedMessage.ts
│ │ │ │ │ ├── useTimer.test.tsx
│ │ │ │ │ ├── useTimer.ts
│ │ │ │ │ ├── useTips.test.ts
│ │ │ │ │ ├── useTips.ts
│ │ │ │ │ ├── useToolScheduler.test.ts
│ │ │ │ │ ├── useToolScheduler.ts
│ │ │ │ │ ├── useTurnActivityMonitor.test.ts
│ │ │ │ │ ├── useTurnActivityMonitor.ts
│ │ │ │ │ ├── useVisibilityToggle.ts
│ │ │ │ │ ├── vim-passthrough.test.tsx
│ │ │ │ │ ├── vim.test.tsx
│ │ │ │ │ └── vim.ts
│ │ │ │ ├── key/
│ │ │ │ │ ├── keyBindings.test.ts
│ │ │ │ │ ├── keyBindings.ts
│ │ │ │ │ ├── keyMatchers.test.ts
│ │ │ │ │ ├── keyMatchers.ts
│ │ │ │ │ ├── keyToAnsi.ts
│ │ │ │ │ ├── keybindingUtils.test.ts
│ │ │ │ │ └── keybindingUtils.ts
│ │ │ │ ├── layouts/
│ │ │ │ │ ├── DefaultAppLayout.test.tsx
│ │ │ │ │ ├── DefaultAppLayout.tsx
│ │ │ │ │ ├── ScreenReaderAppLayout.tsx
│ │ │ │ │ └── __snapshots__/
│ │ │ │ │ └── DefaultAppLayout.test.tsx.snap
│ │ │ │ ├── noninteractive/
│ │ │ │ │ └── nonInteractiveUi.ts
│ │ │ │ ├── privacy/
│ │ │ │ │ ├── CloudFreePrivacyNotice.test.tsx
│ │ │ │ │ ├── CloudFreePrivacyNotice.tsx
│ │ │ │ │ ├── CloudPaidPrivacyNotice.test.tsx
│ │ │ │ │ ├── CloudPaidPrivacyNotice.tsx
│ │ │ │ │ ├── GeminiPrivacyNotice.test.tsx
│ │ │ │ │ ├── GeminiPrivacyNotice.tsx
│ │ │ │ │ ├── PrivacyNotice.test.tsx
│ │ │ │ │ └── PrivacyNotice.tsx
│ │ │ │ ├── semantic-colors.ts
│ │ │ │ ├── state/
│ │ │ │ │ ├── extensions.test.ts
│ │ │ │ │ └── extensions.ts
│ │ │ │ ├── textConstants.ts
│ │ │ │ ├── themes/
│ │ │ │ │ ├── builtin/
│ │ │ │ │ │ ├── dark/
│ │ │ │ │ │ │ ├── ansi-dark.ts
│ │ │ │ │ │ │ ├── atom-one-dark.ts
│ │ │ │ │ │ │ ├── ayu-dark.ts
│ │ │ │ │ │ │ ├── default-dark.ts
│ │ │ │ │ │ │ ├── dracula-dark.ts
│ │ │ │ │ │ │ ├── github-dark.ts
│ │ │ │ │ │ │ ├── holiday-dark.ts
│ │ │ │ │ │ │ ├── shades-of-purple-dark.ts
│ │ │ │ │ │ │ └── solarized-dark.ts
│ │ │ │ │ │ ├── light/
│ │ │ │ │ │ │ ├── ansi-light.ts
│ │ │ │ │ │ │ ├── ayu-light.ts
│ │ │ │ │ │ │ ├── default-light.ts
│ │ │ │ │ │ │ ├── github-light.ts
│ │ │ │ │ │ │ ├── googlecode-light.ts
│ │ │ │ │ │ │ ├── solarized-light.ts
│ │ │ │ │ │ │ └── xcode-light.ts
│ │ │ │ │ │ └── no-color.ts
│ │ │ │ │ ├── color-utils.test.ts
│ │ │ │ │ ├── color-utils.ts
│ │ │ │ │ ├── semantic-tokens.ts
│ │ │ │ │ ├── theme-manager.test.ts
│ │ │ │ │ ├── theme-manager.ts
│ │ │ │ │ ├── theme.test.ts
│ │ │ │ │ └── theme.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── utils/
│ │ │ │ ├── CodeColorizer.test.tsx
│ │ │ │ ├── CodeColorizer.tsx
│ │ │ │ ├── ConsolePatcher.ts
│ │ │ │ ├── InlineMarkdownRenderer.tsx
│ │ │ │ ├── MarkdownDisplay.test.tsx
│ │ │ │ ├── MarkdownDisplay.tsx
│ │ │ │ ├── TableRenderer.test.tsx
│ │ │ │ ├── TableRenderer.tsx
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── CodeColorizer.test.tsx.snap
│ │ │ │ │ ├── MarkdownDisplay.test.tsx.snap
│ │ │ │ │ ├── TableRenderer.test.tsx.snap
│ │ │ │ │ ├── borderStyles.test.tsx.snap
│ │ │ │ │ ├── terminalSetup.test.ts.snap
│ │ │ │ │ └── textOutput.test.ts.snap
│ │ │ │ ├── borderStyles.test.tsx
│ │ │ │ ├── borderStyles.ts
│ │ │ │ ├── clipboardUtils.test.ts
│ │ │ │ ├── clipboardUtils.ts
│ │ │ │ ├── clipboardUtils.windows.test.ts
│ │ │ │ ├── commandUtils.test.ts
│ │ │ │ ├── commandUtils.ts
│ │ │ │ ├── computeStats.test.ts
│ │ │ │ ├── computeStats.ts
│ │ │ │ ├── confirmingTool.ts
│ │ │ │ ├── contextUsage.ts
│ │ │ │ ├── directoryUtils.test.ts
│ │ │ │ ├── directoryUtils.ts
│ │ │ │ ├── displayUtils.test.ts
│ │ │ │ ├── displayUtils.ts
│ │ │ │ ├── editorUtils.ts
│ │ │ │ ├── formatters.test.ts
│ │ │ │ ├── formatters.ts
│ │ │ │ ├── highlight.test.ts
│ │ │ │ ├── highlight.ts
│ │ │ │ ├── historyExportUtils.ts
│ │ │ │ ├── inlineThinkingMode.ts
│ │ │ │ ├── input.test.ts
│ │ │ │ ├── input.ts
│ │ │ │ ├── isNarrowWidth.ts
│ │ │ │ ├── markdownParsingUtils.test.ts
│ │ │ │ ├── markdownParsingUtils.ts
│ │ │ │ ├── markdownUtilities.test.ts
│ │ │ │ ├── markdownUtilities.ts
│ │ │ │ ├── mouse.test.ts
│ │ │ │ ├── mouse.ts
│ │ │ │ ├── pendingAttentionNotification.test.ts
│ │ │ │ ├── pendingAttentionNotification.ts
│ │ │ │ ├── rewindFileOps.test.ts
│ │ │ │ ├── rewindFileOps.ts
│ │ │ │ ├── shortcutsHelp.ts
│ │ │ │ ├── terminalCapabilityManager.test.ts
│ │ │ │ ├── terminalCapabilityManager.ts
│ │ │ │ ├── terminalSetup.test.ts
│ │ │ │ ├── terminalSetup.ts
│ │ │ │ ├── terminalUtils.ts
│ │ │ │ ├── textOutput.test.ts
│ │ │ │ ├── textOutput.ts
│ │ │ │ ├── textUtils.test.ts
│ │ │ │ ├── textUtils.ts
│ │ │ │ ├── toolLayoutUtils.test.ts
│ │ │ │ ├── toolLayoutUtils.ts
│ │ │ │ ├── ui-sizing.test.ts
│ │ │ │ ├── ui-sizing.ts
│ │ │ │ ├── updateCheck.test.ts
│ │ │ │ ├── updateCheck.ts
│ │ │ │ ├── urlSecurityUtils.test.ts
│ │ │ │ └── urlSecurityUtils.ts
│ │ │ ├── utils/
│ │ │ │ ├── activityLogger.test.ts
│ │ │ │ ├── activityLogger.ts
│ │ │ │ ├── agentSettings.test.ts
│ │ │ │ ├── agentSettings.ts
│ │ │ │ ├── agentUtils.test.ts
│ │ │ │ ├── agentUtils.ts
│ │ │ │ ├── cleanup.test.ts
│ │ │ │ ├── cleanup.ts
│ │ │ │ ├── commands.test.ts
│ │ │ │ ├── commands.ts
│ │ │ │ ├── commentJson.test.ts
│ │ │ │ ├── commentJson.ts
│ │ │ │ ├── deepMerge.test.ts
│ │ │ │ ├── deepMerge.ts
│ │ │ │ ├── devtoolsService.test.ts
│ │ │ │ ├── devtoolsService.ts
│ │ │ │ ├── dialogScopeUtils.test.ts
│ │ │ │ ├── dialogScopeUtils.ts
│ │ │ │ ├── envVarResolver.test.ts
│ │ │ │ ├── envVarResolver.ts
│ │ │ │ ├── errors.test.ts
│ │ │ │ ├── errors.ts
│ │ │ │ ├── events.test.ts
│ │ │ │ ├── events.ts
│ │ │ │ ├── featureToggleUtils.test.ts
│ │ │ │ ├── featureToggleUtils.ts
│ │ │ │ ├── gitUtils.test.ts
│ │ │ │ ├── gitUtils.ts
│ │ │ │ ├── handleAutoUpdate.test.ts
│ │ │ │ ├── handleAutoUpdate.ts
│ │ │ │ ├── hookSettings.test.ts
│ │ │ │ ├── hookSettings.ts
│ │ │ │ ├── hookUtils.test.ts
│ │ │ │ ├── hookUtils.ts
│ │ │ │ ├── installationInfo.test.ts
│ │ │ │ ├── installationInfo.ts
│ │ │ │ ├── jsonoutput.test.ts
│ │ │ │ ├── jsonoutput.ts
│ │ │ │ ├── logCleanup.test.ts
│ │ │ │ ├── logCleanup.ts
│ │ │ │ ├── math.test.ts
│ │ │ │ ├── math.ts
│ │ │ │ ├── persistentState.test.ts
│ │ │ │ ├── persistentState.ts
│ │ │ │ ├── processUtils.test.ts
│ │ │ │ ├── processUtils.ts
│ │ │ │ ├── readStdin.test.ts
│ │ │ │ ├── readStdin.ts
│ │ │ │ ├── readStdin_safety.test.ts
│ │ │ │ ├── relaunch.test.ts
│ │ │ │ ├── relaunch.ts
│ │ │ │ ├── resolvePath.test.ts
│ │ │ │ ├── resolvePath.ts
│ │ │ │ ├── sandbox-macos-permissive-open.sb
│ │ │ │ ├── sandbox-macos-permissive-proxied.sb
│ │ │ │ ├── sandbox-macos-restrictive-open.sb
│ │ │ │ ├── sandbox-macos-restrictive-proxied.sb
│ │ │ │ ├── sandbox-macos-strict-open.sb
│ │ │ │ ├── sandbox-macos-strict-proxied.sb
│ │ │ │ ├── sandbox.test.ts
│ │ │ │ ├── sandbox.ts
│ │ │ │ ├── sandboxUtils.test.ts
│ │ │ │ ├── sandboxUtils.ts
│ │ │ │ ├── sessionCleanup.integration.test.ts
│ │ │ │ ├── sessionCleanup.test.ts
│ │ │ │ ├── sessionCleanup.ts
│ │ │ │ ├── sessionUtils.test.ts
│ │ │ │ ├── sessionUtils.ts
│ │ │ │ ├── sessions.test.ts
│ │ │ │ ├── sessions.ts
│ │ │ │ ├── settingsUtils.test.ts
│ │ │ │ ├── settingsUtils.ts
│ │ │ │ ├── skillSettings.test.ts
│ │ │ │ ├── skillSettings.ts
│ │ │ │ ├── skillUtils.test.ts
│ │ │ │ ├── skillUtils.ts
│ │ │ │ ├── spawnWrapper.ts
│ │ │ │ ├── startupWarnings.test.ts
│ │ │ │ ├── startupWarnings.ts
│ │ │ │ ├── terminalNotifications.test.ts
│ │ │ │ ├── terminalNotifications.ts
│ │ │ │ ├── terminalTheme.ts
│ │ │ │ ├── tierUtils.test.ts
│ │ │ │ ├── tierUtils.ts
│ │ │ │ ├── toolOutputCleanup.test.ts
│ │ │ │ ├── updateEventEmitter.test.ts
│ │ │ │ ├── updateEventEmitter.ts
│ │ │ │ ├── userStartupWarnings.test.ts
│ │ │ │ ├── userStartupWarnings.ts
│ │ │ │ ├── windowTitle.test.ts
│ │ │ │ └── windowTitle.ts
│ │ │ ├── validateNonInterActiveAuth.test.ts
│ │ │ └── validateNonInterActiveAuth.ts
│ │ ├── test-setup.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ ├── core/
│ │ ├── GEMINI.md
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── scripts/
│ │ │ ├── bundle-browser-mcp.mjs
│ │ │ └── compile-windows-sandbox.js
│ │ ├── src/
│ │ │ ├── __mocks__/
│ │ │ │ └── fs/
│ │ │ │ └── promises.ts
│ │ │ ├── agent/
│ │ │ │ ├── content-utils.test.ts
│ │ │ │ ├── content-utils.ts
│ │ │ │ ├── mock.test.ts
│ │ │ │ ├── mock.ts
│ │ │ │ └── types.ts
│ │ │ ├── agents/
│ │ │ │ ├── a2a-client-manager.test.ts
│ │ │ │ ├── a2a-client-manager.ts
│ │ │ │ ├── a2a-errors.test.ts
│ │ │ │ ├── a2a-errors.ts
│ │ │ │ ├── a2aUtils.test.ts
│ │ │ │ ├── a2aUtils.ts
│ │ │ │ ├── acknowledgedAgents.test.ts
│ │ │ │ ├── acknowledgedAgents.ts
│ │ │ │ ├── agent-scheduler.test.ts
│ │ │ │ ├── agent-scheduler.ts
│ │ │ │ ├── agentLoader.test.ts
│ │ │ │ ├── agentLoader.ts
│ │ │ │ ├── auth-provider/
│ │ │ │ │ ├── api-key-provider.test.ts
│ │ │ │ │ ├── api-key-provider.ts
│ │ │ │ │ ├── base-provider.test.ts
│ │ │ │ │ ├── base-provider.ts
│ │ │ │ │ ├── factory.test.ts
│ │ │ │ │ ├── factory.ts
│ │ │ │ │ ├── google-credentials-provider.test.ts
│ │ │ │ │ ├── google-credentials-provider.ts
│ │ │ │ │ ├── http-provider.test.ts
│ │ │ │ │ ├── http-provider.ts
│ │ │ │ │ ├── oauth2-provider.test.ts
│ │ │ │ │ ├── oauth2-provider.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ ├── value-resolver.test.ts
│ │ │ │ │ └── value-resolver.ts
│ │ │ │ ├── browser/
│ │ │ │ │ ├── analyzeScreenshot.test.ts
│ │ │ │ │ ├── analyzeScreenshot.ts
│ │ │ │ │ ├── automationOverlay.ts
│ │ │ │ │ ├── browser-tools-manifest.json
│ │ │ │ │ ├── browserAgentDefinition.ts
│ │ │ │ │ ├── browserAgentFactory.test.ts
│ │ │ │ │ ├── browserAgentFactory.ts
│ │ │ │ │ ├── browserAgentInvocation.test.ts
│ │ │ │ │ ├── browserAgentInvocation.ts
│ │ │ │ │ ├── browserManager.test.ts
│ │ │ │ │ ├── browserManager.ts
│ │ │ │ │ ├── inputBlocker.test.ts
│ │ │ │ │ ├── inputBlocker.ts
│ │ │ │ │ ├── mcpToolWrapper.test.ts
│ │ │ │ │ ├── mcpToolWrapper.ts
│ │ │ │ │ ├── mcpToolWrapperConfirmation.test.ts
│ │ │ │ │ └── modelAvailability.ts
│ │ │ │ ├── cli-help-agent.test.ts
│ │ │ │ ├── cli-help-agent.ts
│ │ │ │ ├── codebase-investigator.test.ts
│ │ │ │ ├── codebase-investigator.ts
│ │ │ │ ├── generalist-agent.test.ts
│ │ │ │ ├── generalist-agent.ts
│ │ │ │ ├── local-executor.test.ts
│ │ │ │ ├── local-executor.ts
│ │ │ │ ├── local-invocation.test.ts
│ │ │ │ ├── local-invocation.ts
│ │ │ │ ├── memory-manager-agent.test.ts
│ │ │ │ ├── memory-manager-agent.ts
│ │ │ │ ├── registry.test.ts
│ │ │ │ ├── registry.ts
│ │ │ │ ├── registry_acknowledgement.test.ts
│ │ │ │ ├── remote-invocation.test.ts
│ │ │ │ ├── remote-invocation.ts
│ │ │ │ ├── subagent-tool-wrapper.test.ts
│ │ │ │ ├── subagent-tool-wrapper.ts
│ │ │ │ ├── subagent-tool.test.ts
│ │ │ │ ├── subagent-tool.ts
│ │ │ │ ├── types.ts
│ │ │ │ ├── utils.test.ts
│ │ │ │ └── utils.ts
│ │ │ ├── availability/
│ │ │ │ ├── errorClassification.ts
│ │ │ │ ├── fallbackIntegration.test.ts
│ │ │ │ ├── modelAvailabilityService.test.ts
│ │ │ │ ├── modelAvailabilityService.ts
│ │ │ │ ├── modelPolicy.ts
│ │ │ │ ├── policyCatalog.test.ts
│ │ │ │ ├── policyCatalog.ts
│ │ │ │ ├── policyHelpers.test.ts
│ │ │ │ ├── policyHelpers.ts
│ │ │ │ └── testUtils.ts
│ │ │ ├── billing/
│ │ │ │ ├── billing.test.ts
│ │ │ │ ├── billing.ts
│ │ │ │ └── index.ts
│ │ │ ├── code_assist/
│ │ │ │ ├── admin/
│ │ │ │ │ ├── admin_controls.test.ts
│ │ │ │ │ ├── admin_controls.ts
│ │ │ │ │ ├── mcpUtils.test.ts
│ │ │ │ │ └── mcpUtils.ts
│ │ │ │ ├── codeAssist.test.ts
│ │ │ │ ├── codeAssist.ts
│ │ │ │ ├── converter.test.ts
│ │ │ │ ├── converter.ts
│ │ │ │ ├── experiments/
│ │ │ │ │ ├── client_metadata.test.ts
│ │ │ │ │ ├── client_metadata.ts
│ │ │ │ │ ├── experiments.test.ts
│ │ │ │ │ ├── experiments.ts
│ │ │ │ │ ├── experiments_local.test.ts
│ │ │ │ │ ├── flagNames.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── oauth-credential-storage.test.ts
│ │ │ │ ├── oauth-credential-storage.ts
│ │ │ │ ├── oauth2.test.ts
│ │ │ │ ├── oauth2.ts
│ │ │ │ ├── server.test.ts
│ │ │ │ ├── server.ts
│ │ │ │ ├── setup.test.ts
│ │ │ │ ├── setup.ts
│ │ │ │ ├── telemetry.test.ts
│ │ │ │ ├── telemetry.ts
│ │ │ │ └── types.ts
│ │ │ ├── commands/
│ │ │ │ ├── extensions.test.ts
│ │ │ │ ├── extensions.ts
│ │ │ │ ├── init.test.ts
│ │ │ │ ├── init.ts
│ │ │ │ ├── memory.test.ts
│ │ │ │ ├── memory.ts
│ │ │ │ ├── restore.test.ts
│ │ │ │ ├── restore.ts
│ │ │ │ └── types.ts
│ │ │ ├── config/
│ │ │ │ ├── agent-loop-context.ts
│ │ │ │ ├── config.test.ts
│ │ │ │ ├── config.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── defaultModelConfigs.ts
│ │ │ │ ├── extensions/
│ │ │ │ │ ├── integrity.test.ts
│ │ │ │ │ ├── integrity.ts
│ │ │ │ │ └── integrityTypes.ts
│ │ │ │ ├── flashFallback.test.ts
│ │ │ │ ├── injectionService.test.ts
│ │ │ │ ├── injectionService.ts
│ │ │ │ ├── memory.test.ts
│ │ │ │ ├── memory.ts
│ │ │ │ ├── models.test.ts
│ │ │ │ ├── models.ts
│ │ │ │ ├── path-validation.test.ts
│ │ │ │ ├── projectRegistry.test.ts
│ │ │ │ ├── projectRegistry.ts
│ │ │ │ ├── sandbox-integration.test.ts
│ │ │ │ ├── storage.test.ts
│ │ │ │ ├── storage.ts
│ │ │ │ ├── storageMigration.test.ts
│ │ │ │ ├── storageMigration.ts
│ │ │ │ └── trackerFeatureFlag.test.ts
│ │ │ ├── confirmation-bus/
│ │ │ │ ├── index.ts
│ │ │ │ ├── message-bus.test.ts
│ │ │ │ ├── message-bus.ts
│ │ │ │ └── types.ts
│ │ │ ├── core/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── prompts.test.ts.snap
│ │ │ │ ├── apiKeyCredentialStorage.test.ts
│ │ │ │ ├── apiKeyCredentialStorage.ts
│ │ │ │ ├── baseLlmClient.test.ts
│ │ │ │ ├── baseLlmClient.ts
│ │ │ │ ├── client.test.ts
│ │ │ │ ├── client.ts
│ │ │ │ ├── contentGenerator.test.ts
│ │ │ │ ├── contentGenerator.ts
│ │ │ │ ├── coreToolHookTriggers.test.ts
│ │ │ │ ├── coreToolHookTriggers.ts
│ │ │ │ ├── coreToolScheduler.test.ts
│ │ │ │ ├── coreToolScheduler.ts
│ │ │ │ ├── fakeContentGenerator.test.ts
│ │ │ │ ├── fakeContentGenerator.ts
│ │ │ │ ├── geminiChat.test.ts
│ │ │ │ ├── geminiChat.ts
│ │ │ │ ├── geminiChat_network_retry.test.ts
│ │ │ │ ├── geminiRequest.ts
│ │ │ │ ├── localLiteRtLmClient.test.ts
│ │ │ │ ├── localLiteRtLmClient.ts
│ │ │ │ ├── logger.test.ts
│ │ │ │ ├── logger.ts
│ │ │ │ ├── loggingContentGenerator.test.ts
│ │ │ │ ├── loggingContentGenerator.ts
│ │ │ │ ├── prompts-substitution.test.ts
│ │ │ │ ├── prompts.test.ts
│ │ │ │ ├── prompts.ts
│ │ │ │ ├── recordingContentGenerator.test.ts
│ │ │ │ ├── recordingContentGenerator.ts
│ │ │ │ ├── tokenLimits.test.ts
│ │ │ │ ├── tokenLimits.ts
│ │ │ │ ├── turn.test.ts
│ │ │ │ └── turn.ts
│ │ │ ├── fallback/
│ │ │ │ ├── handler.test.ts
│ │ │ │ ├── handler.ts
│ │ │ │ └── types.ts
│ │ │ ├── hooks/
│ │ │ │ ├── hookAggregator.test.ts
│ │ │ │ ├── hookAggregator.ts
│ │ │ │ ├── hookEventHandler.test.ts
│ │ │ │ ├── hookEventHandler.ts
│ │ │ │ ├── hookPlanner.test.ts
│ │ │ │ ├── hookPlanner.ts
│ │ │ │ ├── hookRegistry.test.ts
│ │ │ │ ├── hookRegistry.ts
│ │ │ │ ├── hookRunner.test.ts
│ │ │ │ ├── hookRunner.ts
│ │ │ │ ├── hookSystem.test.ts
│ │ │ │ ├── hookSystem.ts
│ │ │ │ ├── hookTranslator.test.ts
│ │ │ │ ├── hookTranslator.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── runtimeHooks.test.ts
│ │ │ │ ├── trustedHooks.test.ts
│ │ │ │ ├── trustedHooks.ts
│ │ │ │ ├── types.test.ts
│ │ │ │ └── types.ts
│ │ │ ├── ide/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── detect-ide.test.ts
│ │ │ │ ├── detect-ide.ts
│ │ │ │ ├── ide-client.test.ts
│ │ │ │ ├── ide-client.ts
│ │ │ │ ├── ide-connection-utils.test.ts
│ │ │ │ ├── ide-connection-utils.ts
│ │ │ │ ├── ide-installer.test.ts
│ │ │ │ ├── ide-installer.ts
│ │ │ │ ├── ideContext.test.ts
│ │ │ │ ├── ideContext.ts
│ │ │ │ ├── process-utils.test.ts
│ │ │ │ ├── process-utils.ts
│ │ │ │ └── types.ts
│ │ │ ├── index.test.ts
│ │ │ ├── index.ts
│ │ │ ├── mcp/
│ │ │ │ ├── auth-provider.ts
│ │ │ │ ├── google-auth-provider.test.ts
│ │ │ │ ├── google-auth-provider.ts
│ │ │ │ ├── mcp-oauth-provider.test.ts
│ │ │ │ ├── mcp-oauth-provider.ts
│ │ │ │ ├── oauth-provider.test.ts
│ │ │ │ ├── oauth-provider.ts
│ │ │ │ ├── oauth-token-storage.test.ts
│ │ │ │ ├── oauth-token-storage.ts
│ │ │ │ ├── oauth-utils.test.ts
│ │ │ │ ├── oauth-utils.ts
│ │ │ │ ├── sa-impersonation-provider.test.ts
│ │ │ │ ├── sa-impersonation-provider.ts
│ │ │ │ └── token-storage/
│ │ │ │ ├── base-token-storage.test.ts
│ │ │ │ ├── base-token-storage.ts
│ │ │ │ ├── hybrid-token-storage.test.ts
│ │ │ │ ├── hybrid-token-storage.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── keychain-token-storage.test.ts
│ │ │ │ ├── keychain-token-storage.ts
│ │ │ │ └── types.ts
│ │ │ ├── mocks/
│ │ │ │ └── msw.ts
│ │ │ ├── output/
│ │ │ │ ├── json-formatter.test.ts
│ │ │ │ ├── json-formatter.ts
│ │ │ │ ├── stream-json-formatter.test.ts
│ │ │ │ ├── stream-json-formatter.ts
│ │ │ │ └── types.ts
│ │ │ ├── policy/
│ │ │ │ ├── config.test.ts
│ │ │ │ ├── config.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── integrity.test.ts
│ │ │ │ ├── integrity.ts
│ │ │ │ ├── memory-manager-policy.test.ts
│ │ │ │ ├── persistence.test.ts
│ │ │ │ ├── policies/
│ │ │ │ │ ├── conseca.toml
│ │ │ │ │ ├── discovered.toml
│ │ │ │ │ ├── memory-manager.toml
│ │ │ │ │ ├── plan.toml
│ │ │ │ │ ├── read-only.toml
│ │ │ │ │ ├── tracker.toml
│ │ │ │ │ ├── write.toml
│ │ │ │ │ └── yolo.toml
│ │ │ │ ├── policy-engine.test.ts
│ │ │ │ ├── policy-engine.ts
│ │ │ │ ├── policy-updater.test.ts
│ │ │ │ ├── shell-safety.test.ts
│ │ │ │ ├── stable-stringify.ts
│ │ │ │ ├── toml-loader.test.ts
│ │ │ │ ├── toml-loader.ts
│ │ │ │ ├── types.ts
│ │ │ │ ├── utils.test.ts
│ │ │ │ ├── utils.ts
│ │ │ │ └── workspace-policy.test.ts
│ │ │ ├── prompts/
│ │ │ │ ├── mcp-prompts.test.ts
│ │ │ │ ├── mcp-prompts.ts
│ │ │ │ ├── prompt-registry.test.ts
│ │ │ │ ├── prompt-registry.ts
│ │ │ │ ├── promptProvider.test.ts
│ │ │ │ ├── promptProvider.ts
│ │ │ │ ├── snippets-memory-manager.test.ts
│ │ │ │ ├── snippets.legacy.ts
│ │ │ │ ├── snippets.ts
│ │ │ │ ├── utils.test.ts
│ │ │ │ └── utils.ts
│ │ │ ├── resources/
│ │ │ │ ├── resource-registry.test.ts
│ │ │ │ └── resource-registry.ts
│ │ │ ├── routing/
│ │ │ │ ├── modelRouterService.test.ts
│ │ │ │ ├── modelRouterService.ts
│ │ │ │ ├── routingStrategy.ts
│ │ │ │ └── strategies/
│ │ │ │ ├── approvalModeStrategy.test.ts
│ │ │ │ ├── approvalModeStrategy.ts
│ │ │ │ ├── classifierStrategy.test.ts
│ │ │ │ ├── classifierStrategy.ts
│ │ │ │ ├── compositeStrategy.test.ts
│ │ │ │ ├── compositeStrategy.ts
│ │ │ │ ├── defaultStrategy.test.ts
│ │ │ │ ├── defaultStrategy.ts
│ │ │ │ ├── fallbackStrategy.test.ts
│ │ │ │ ├── fallbackStrategy.ts
│ │ │ │ ├── gemmaClassifierStrategy.test.ts
│ │ │ │ ├── gemmaClassifierStrategy.ts
│ │ │ │ ├── numericalClassifierStrategy.test.ts
│ │ │ │ ├── numericalClassifierStrategy.ts
│ │ │ │ ├── overrideStrategy.test.ts
│ │ │ │ └── overrideStrategy.ts
│ │ │ ├── safety/
│ │ │ │ ├── built-in.test.ts
│ │ │ │ ├── built-in.ts
│ │ │ │ ├── checker-runner.test.ts
│ │ │ │ ├── checker-runner.ts
│ │ │ │ ├── conseca/
│ │ │ │ │ ├── conseca.test.ts
│ │ │ │ │ ├── conseca.ts
│ │ │ │ │ ├── integration.test.ts
│ │ │ │ │ ├── policy-enforcer.test.ts
│ │ │ │ │ ├── policy-enforcer.ts
│ │ │ │ │ ├── policy-generator.test.ts
│ │ │ │ │ ├── policy-generator.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── context-builder.test.ts
│ │ │ │ ├── context-builder.ts
│ │ │ │ ├── protocol.ts
│ │ │ │ ├── registry.test.ts
│ │ │ │ └── registry.ts
│ │ │ ├── sandbox/
│ │ │ │ ├── linux/
│ │ │ │ │ ├── LinuxSandboxManager.test.ts
│ │ │ │ │ └── LinuxSandboxManager.ts
│ │ │ │ └── macos/
│ │ │ │ ├── MacOsSandboxManager.integration.test.ts
│ │ │ │ ├── MacOsSandboxManager.test.ts
│ │ │ │ ├── MacOsSandboxManager.ts
│ │ │ │ ├── baseProfile.ts
│ │ │ │ ├── seatbeltArgsBuilder.test.ts
│ │ │ │ └── seatbeltArgsBuilder.ts
│ │ │ ├── scheduler/
│ │ │ │ ├── confirmation.test.ts
│ │ │ │ ├── confirmation.ts
│ │ │ │ ├── policy.test.ts
│ │ │ │ ├── policy.ts
│ │ │ │ ├── scheduler.test.ts
│ │ │ │ ├── scheduler.ts
│ │ │ │ ├── scheduler_parallel.test.ts
│ │ │ │ ├── scheduler_waiting_callback.test.ts
│ │ │ │ ├── state-manager.test.ts
│ │ │ │ ├── state-manager.ts
│ │ │ │ ├── tool-executor.test.ts
│ │ │ │ ├── tool-executor.ts
│ │ │ │ ├── tool-modifier.test.ts
│ │ │ │ ├── tool-modifier.ts
│ │ │ │ └── types.ts
│ │ │ ├── services/
│ │ │ │ ├── FolderTrustDiscoveryService.test.ts
│ │ │ │ ├── FolderTrustDiscoveryService.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── toolOutputMaskingService.test.ts.snap
│ │ │ │ ├── chatCompressionService.test.ts
│ │ │ │ ├── chatCompressionService.ts
│ │ │ │ ├── chatRecordingService.test.ts
│ │ │ │ ├── chatRecordingService.ts
│ │ │ │ ├── contextManager.test.ts
│ │ │ │ ├── contextManager.ts
│ │ │ │ ├── environmentSanitization.test.ts
│ │ │ │ ├── environmentSanitization.ts
│ │ │ │ ├── executionLifecycleService.test.ts
│ │ │ │ ├── executionLifecycleService.ts
│ │ │ │ ├── fileDiscoveryService.test.ts
│ │ │ │ ├── fileDiscoveryService.ts
│ │ │ │ ├── fileKeychain.ts
│ │ │ │ ├── fileSystemService.test.ts
│ │ │ │ ├── fileSystemService.ts
│ │ │ │ ├── gitService.test.ts
│ │ │ │ ├── gitService.ts
│ │ │ │ ├── keychainService.test.ts
│ │ │ │ ├── keychainService.ts
│ │ │ │ ├── keychainTypes.ts
│ │ │ │ ├── loopDetectionService.test.ts
│ │ │ │ ├── loopDetectionService.ts
│ │ │ │ ├── modelConfig.golden.test.ts
│ │ │ │ ├── modelConfig.integration.test.ts
│ │ │ │ ├── modelConfigService.test.ts
│ │ │ │ ├── modelConfigService.ts
│ │ │ │ ├── modelConfigServiceTestUtils.ts
│ │ │ │ ├── sandboxManager.test.ts
│ │ │ │ ├── sandboxManager.ts
│ │ │ │ ├── sandboxManagerFactory.ts
│ │ │ │ ├── sandboxedFileSystemService.test.ts
│ │ │ │ ├── sandboxedFileSystemService.ts
│ │ │ │ ├── scripts/
│ │ │ │ │ └── GeminiSandbox.cs
│ │ │ │ ├── sessionSummaryService.test.ts
│ │ │ │ ├── sessionSummaryService.ts
│ │ │ │ ├── sessionSummaryUtils.test.ts
│ │ │ │ ├── sessionSummaryUtils.ts
│ │ │ │ ├── shellExecutionService.test.ts
│ │ │ │ ├── shellExecutionService.ts
│ │ │ │ ├── test-data/
│ │ │ │ │ ├── resolved-aliases-retry.golden.json
│ │ │ │ │ └── resolved-aliases.golden.json
│ │ │ │ ├── toolOutputMaskingService.test.ts
│ │ │ │ ├── toolOutputMaskingService.ts
│ │ │ │ ├── trackerService.test.ts
│ │ │ │ ├── trackerService.ts
│ │ │ │ ├── trackerTypes.ts
│ │ │ │ ├── windowsSandboxManager.test.ts
│ │ │ │ └── windowsSandboxManager.ts
│ │ │ ├── skills/
│ │ │ │ ├── builtin/
│ │ │ │ │ └── skill-creator/
│ │ │ │ │ ├── SKILL.md
│ │ │ │ │ └── scripts/
│ │ │ │ │ ├── init_skill.cjs
│ │ │ │ │ ├── package_skill.cjs
│ │ │ │ │ └── validate_skill.cjs
│ │ │ │ ├── skillLoader.test.ts
│ │ │ │ ├── skillLoader.ts
│ │ │ │ ├── skillManager.test.ts
│ │ │ │ ├── skillManager.ts
│ │ │ │ └── skillManagerAlias.test.ts
│ │ │ ├── telemetry/
│ │ │ │ ├── activity-detector.test.ts
│ │ │ │ ├── activity-detector.ts
│ │ │ │ ├── activity-monitor.test.ts
│ │ │ │ ├── activity-monitor.ts
│ │ │ │ ├── activity-types.ts
│ │ │ │ ├── billingEvents.test.ts
│ │ │ │ ├── billingEvents.ts
│ │ │ │ ├── clearcut-logger/
│ │ │ │ │ ├── clearcut-logger.test.ts
│ │ │ │ │ ├── clearcut-logger.ts
│ │ │ │ │ └── event-metadata-key.ts
│ │ │ │ ├── config.test.ts
│ │ │ │ ├── config.ts
│ │ │ │ ├── conseca-logger.test.ts
│ │ │ │ ├── conseca-logger.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── file-exporters.test.ts
│ │ │ │ ├── file-exporters.ts
│ │ │ │ ├── gcp-exporters.test.ts
│ │ │ │ ├── gcp-exporters.ts
│ │ │ │ ├── high-water-mark-tracker.test.ts
│ │ │ │ ├── high-water-mark-tracker.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── integration.test.circular.ts
│ │ │ │ ├── llmRole.ts
│ │ │ │ ├── loggers.test.circular.ts
│ │ │ │ ├── loggers.test.ts
│ │ │ │ ├── loggers.ts
│ │ │ │ ├── memory-monitor.test.ts
│ │ │ │ ├── memory-monitor.ts
│ │ │ │ ├── metrics.test.ts
│ │ │ │ ├── metrics.ts
│ │ │ │ ├── rate-limiter.test.ts
│ │ │ │ ├── rate-limiter.ts
│ │ │ │ ├── sanitize.test.ts
│ │ │ │ ├── sanitize.ts
│ │ │ │ ├── sdk.test.ts
│ │ │ │ ├── sdk.ts
│ │ │ │ ├── semantic.test.ts
│ │ │ │ ├── semantic.truncation.test.ts
│ │ │ │ ├── semantic.ts
│ │ │ │ ├── startupProfiler.test.ts
│ │ │ │ ├── startupProfiler.ts
│ │ │ │ ├── telemetry-utils.test.ts
│ │ │ │ ├── telemetry-utils.ts
│ │ │ │ ├── telemetry.test.ts
│ │ │ │ ├── telemetryAttributes.ts
│ │ │ │ ├── tool-call-decision.ts
│ │ │ │ ├── trace.test.ts
│ │ │ │ ├── trace.ts
│ │ │ │ ├── types.ts
│ │ │ │ ├── uiTelemetry.test.ts
│ │ │ │ └── uiTelemetry.ts
│ │ │ ├── test-utils/
│ │ │ │ ├── config.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── mock-message-bus.ts
│ │ │ │ ├── mock-tool.ts
│ │ │ │ └── mockWorkspaceContext.ts
│ │ │ ├── tools/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── read-file.test.ts.snap
│ │ │ │ │ └── shell.test.ts.snap
│ │ │ │ ├── activate-skill.test.ts
│ │ │ │ ├── activate-skill.ts
│ │ │ │ ├── ask-user.test.ts
│ │ │ │ ├── ask-user.ts
│ │ │ │ ├── base-tool-invocation.test.ts
│ │ │ │ ├── confirmation-policy.test.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── definitions/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── coreToolsModelSnapshots.test.ts.snap
│ │ │ │ │ ├── base-declarations.ts
│ │ │ │ │ ├── coreTools.ts
│ │ │ │ │ ├── coreToolsModelSnapshots.test.ts
│ │ │ │ │ ├── dynamic-declaration-helpers.ts
│ │ │ │ │ ├── model-family-sets/
│ │ │ │ │ │ ├── default-legacy.ts
│ │ │ │ │ │ └── gemini-3.ts
│ │ │ │ │ ├── modelFamilyService.ts
│ │ │ │ │ ├── resolver.test.ts
│ │ │ │ │ ├── resolver.ts
│ │ │ │ │ ├── trackerTools.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── diff-utils.test.ts
│ │ │ │ ├── diff-utils.ts
│ │ │ │ ├── diffOptions.test.ts
│ │ │ │ ├── diffOptions.ts
│ │ │ │ ├── edit.test.ts
│ │ │ │ ├── edit.ts
│ │ │ │ ├── enter-plan-mode.test.ts
│ │ │ │ ├── enter-plan-mode.ts
│ │ │ │ ├── exit-plan-mode.test.ts
│ │ │ │ ├── exit-plan-mode.ts
│ │ │ │ ├── get-internal-docs.test.ts
│ │ │ │ ├── get-internal-docs.ts
│ │ │ │ ├── glob.test.ts
│ │ │ │ ├── glob.ts
│ │ │ │ ├── grep-utils.ts
│ │ │ │ ├── grep.test.ts
│ │ │ │ ├── grep.ts
│ │ │ │ ├── jit-context.test.ts
│ │ │ │ ├── jit-context.ts
│ │ │ │ ├── line-endings.test.ts
│ │ │ │ ├── ls.test.ts
│ │ │ │ ├── ls.ts
│ │ │ │ ├── mcp-client-manager.test.ts
│ │ │ │ ├── mcp-client-manager.ts
│ │ │ │ ├── mcp-client.test.ts
│ │ │ │ ├── mcp-client.ts
│ │ │ │ ├── mcp-tool.test.ts
│ │ │ │ ├── mcp-tool.ts
│ │ │ │ ├── memoryTool.test.ts
│ │ │ │ ├── memoryTool.ts
│ │ │ │ ├── message-bus-integration.test.ts
│ │ │ │ ├── modifiable-tool.test.ts
│ │ │ │ ├── modifiable-tool.ts
│ │ │ │ ├── omissionPlaceholderDetector.test.ts
│ │ │ │ ├── omissionPlaceholderDetector.ts
│ │ │ │ ├── read-file.test.ts
│ │ │ │ ├── read-file.ts
│ │ │ │ ├── read-many-files.test.ts
│ │ │ │ ├── read-many-files.ts
│ │ │ │ ├── ripGrep.test.ts
│ │ │ │ ├── ripGrep.ts
│ │ │ │ ├── shell.test.ts
│ │ │ │ ├── shell.ts
│ │ │ │ ├── tool-error.ts
│ │ │ │ ├── tool-names.test.ts
│ │ │ │ ├── tool-names.ts
│ │ │ │ ├── tool-registry.test.ts
│ │ │ │ ├── tool-registry.ts
│ │ │ │ ├── tools.test.ts
│ │ │ │ ├── tools.ts
│ │ │ │ ├── trackerTools.test.ts
│ │ │ │ ├── trackerTools.ts
│ │ │ │ ├── web-fetch.test.ts
│ │ │ │ ├── web-fetch.ts
│ │ │ │ ├── web-search.test.ts
│ │ │ │ ├── web-search.ts
│ │ │ │ ├── write-file.test.ts
│ │ │ │ ├── write-file.ts
│ │ │ │ ├── write-todos.test.ts
│ │ │ │ ├── write-todos.ts
│ │ │ │ ├── xcode-mcp-fix-transport.test.ts
│ │ │ │ └── xcode-mcp-fix-transport.ts
│ │ │ ├── utils/
│ │ │ │ ├── __fixtures__/
│ │ │ │ │ └── dummy.wasm
│ │ │ │ ├── apiConversionUtils.test.ts
│ │ │ │ ├── apiConversionUtils.ts
│ │ │ │ ├── approvalModeUtils.test.ts
│ │ │ │ ├── approvalModeUtils.ts
│ │ │ │ ├── authConsent.test.ts
│ │ │ │ ├── authConsent.ts
│ │ │ │ ├── bfsFileSearch.test.ts
│ │ │ │ ├── bfsFileSearch.ts
│ │ │ │ ├── browser.ts
│ │ │ │ ├── browserConsent.test.ts
│ │ │ │ ├── browserConsent.ts
│ │ │ │ ├── cache.test.ts
│ │ │ │ ├── cache.ts
│ │ │ │ ├── channel.test.ts
│ │ │ │ ├── channel.ts
│ │ │ │ ├── checkpointUtils.test.ts
│ │ │ │ ├── checkpointUtils.ts
│ │ │ │ ├── checks.test.ts
│ │ │ │ ├── checks.ts
│ │ │ │ ├── compatibility.test.ts
│ │ │ │ ├── compatibility.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── customHeaderUtils.test.ts
│ │ │ │ ├── customHeaderUtils.ts
│ │ │ │ ├── deadlineTimer.test.ts
│ │ │ │ ├── deadlineTimer.ts
│ │ │ │ ├── debugLogger.test.ts
│ │ │ │ ├── debugLogger.ts
│ │ │ │ ├── delay.test.ts
│ │ │ │ ├── delay.ts
│ │ │ │ ├── editCorrector.test.ts
│ │ │ │ ├── editCorrector.ts
│ │ │ │ ├── editor.test.ts
│ │ │ │ ├── editor.ts
│ │ │ │ ├── envExpansion.test.ts
│ │ │ │ ├── envExpansion.ts
│ │ │ │ ├── environmentContext.test.ts
│ │ │ │ ├── environmentContext.ts
│ │ │ │ ├── errorParsing.test.ts
│ │ │ │ ├── errorParsing.ts
│ │ │ │ ├── errorReporting.test.ts
│ │ │ │ ├── errorReporting.ts
│ │ │ │ ├── errors.test.ts
│ │ │ │ ├── errors.ts
│ │ │ │ ├── errors_timeout.test.ts
│ │ │ │ ├── events.test.ts
│ │ │ │ ├── events.ts
│ │ │ │ ├── exitCodes.ts
│ │ │ │ ├── extensionLoader.test.ts
│ │ │ │ ├── extensionLoader.ts
│ │ │ │ ├── fastAckHelper.test.ts
│ │ │ │ ├── fastAckHelper.ts
│ │ │ │ ├── fetch.test.ts
│ │ │ │ ├── fetch.ts
│ │ │ │ ├── fileDiffUtils.test.ts
│ │ │ │ ├── fileDiffUtils.ts
│ │ │ │ ├── fileUtils.test.ts
│ │ │ │ ├── fileUtils.ts
│ │ │ │ ├── filesearch/
│ │ │ │ │ ├── crawlCache.test.ts
│ │ │ │ │ ├── crawlCache.ts
│ │ │ │ │ ├── crawler.test.ts
│ │ │ │ │ ├── crawler.ts
│ │ │ │ │ ├── fileSearch.test.ts
│ │ │ │ │ ├── fileSearch.ts
│ │ │ │ │ ├── ignore.test.ts
│ │ │ │ │ ├── ignore.ts
│ │ │ │ │ ├── result-cache.test.ts
│ │ │ │ │ └── result-cache.ts
│ │ │ │ ├── flashFallback.test.ts
│ │ │ │ ├── formatters.test.ts
│ │ │ │ ├── formatters.ts
│ │ │ │ ├── fsErrorMessages.test.ts
│ │ │ │ ├── fsErrorMessages.ts
│ │ │ │ ├── generateContentResponseUtilities.test.ts
│ │ │ │ ├── generateContentResponseUtilities.ts
│ │ │ │ ├── getFolderStructure.test.ts
│ │ │ │ ├── getFolderStructure.ts
│ │ │ │ ├── getPty.ts
│ │ │ │ ├── gitIgnoreParser.test.ts
│ │ │ │ ├── gitIgnoreParser.ts
│ │ │ │ ├── gitUtils.ts
│ │ │ │ ├── googleErrors.test.ts
│ │ │ │ ├── googleErrors.ts
│ │ │ │ ├── googleQuotaErrors.test.ts
│ │ │ │ ├── googleQuotaErrors.ts
│ │ │ │ ├── headless.test.ts
│ │ │ │ ├── headless.ts
│ │ │ │ ├── httpErrors.ts
│ │ │ │ ├── ignoreFileParser.test.ts
│ │ │ │ ├── ignoreFileParser.ts
│ │ │ │ ├── ignorePatterns.test.ts
│ │ │ │ ├── ignorePatterns.ts
│ │ │ │ ├── installationManager.test.ts
│ │ │ │ ├── installationManager.ts
│ │ │ │ ├── language-detection.test.ts
│ │ │ │ ├── language-detection.ts
│ │ │ │ ├── llm-edit-fixer.test.ts
│ │ │ │ ├── llm-edit-fixer.ts
│ │ │ │ ├── markdownUtils.test.ts
│ │ │ │ ├── markdownUtils.ts
│ │ │ │ ├── memoryDiscovery.test.ts
│ │ │ │ ├── memoryDiscovery.ts
│ │ │ │ ├── memoryImportProcessor.test.ts
│ │ │ │ ├── memoryImportProcessor.ts
│ │ │ │ ├── messageInspectors.ts
│ │ │ │ ├── nextSpeakerChecker.test.ts
│ │ │ │ ├── nextSpeakerChecker.ts
│ │ │ │ ├── oauth-flow.test.ts
│ │ │ │ ├── oauth-flow.ts
│ │ │ │ ├── package.test.ts
│ │ │ │ ├── package.ts
│ │ │ │ ├── partUtils.test.ts
│ │ │ │ ├── partUtils.ts
│ │ │ │ ├── pathCorrector.test.ts
│ │ │ │ ├── pathCorrector.ts
│ │ │ │ ├── pathReader.test.ts
│ │ │ │ ├── pathReader.ts
│ │ │ │ ├── paths.test.ts
│ │ │ │ ├── paths.ts
│ │ │ │ ├── planUtils.test.ts
│ │ │ │ ├── planUtils.ts
│ │ │ │ ├── process-utils.test.ts
│ │ │ │ ├── process-utils.ts
│ │ │ │ ├── promptIdContext.ts
│ │ │ │ ├── quotaErrorDetection.ts
│ │ │ │ ├── retry.test.ts
│ │ │ │ ├── retry.ts
│ │ │ │ ├── safeJsonStringify.test.ts
│ │ │ │ ├── safeJsonStringify.ts
│ │ │ │ ├── schemaValidator.test.ts
│ │ │ │ ├── schemaValidator.ts
│ │ │ │ ├── secure-browser-launcher.test.ts
│ │ │ │ ├── secure-browser-launcher.ts
│ │ │ │ ├── security.test.ts
│ │ │ │ ├── security.ts
│ │ │ │ ├── session.ts
│ │ │ │ ├── sessionUtils.test.ts
│ │ │ │ ├── sessionUtils.ts
│ │ │ │ ├── shell-utils.integration.test.ts
│ │ │ │ ├── shell-utils.test.ts
│ │ │ │ ├── shell-utils.ts
│ │ │ │ ├── stdio.test.ts
│ │ │ │ ├── stdio.ts
│ │ │ │ ├── summarizer.test.ts
│ │ │ │ ├── summarizer.ts
│ │ │ │ ├── surface.ts
│ │ │ │ ├── systemEncoding.test.ts
│ │ │ │ ├── systemEncoding.ts
│ │ │ │ ├── terminal.ts
│ │ │ │ ├── terminalSerializer.test.ts
│ │ │ │ ├── terminalSerializer.ts
│ │ │ │ ├── testUtils.ts
│ │ │ │ ├── textUtils.test.ts
│ │ │ │ ├── textUtils.ts
│ │ │ │ ├── thoughtUtils.test.ts
│ │ │ │ ├── thoughtUtils.ts
│ │ │ │ ├── tokenCalculation.test.ts
│ │ │ │ ├── tokenCalculation.ts
│ │ │ │ ├── tool-utils.test.ts
│ │ │ │ ├── tool-utils.ts
│ │ │ │ ├── toolCallContext.test.ts
│ │ │ │ ├── toolCallContext.ts
│ │ │ │ ├── userAccountManager.test.ts
│ │ │ │ ├── userAccountManager.ts
│ │ │ │ ├── version.test.ts
│ │ │ │ ├── version.ts
│ │ │ │ ├── workspaceContext.test.ts
│ │ │ │ └── workspaceContext.ts
│ │ │ └── voice/
│ │ │ ├── responseFormatter.test.ts
│ │ │ └── responseFormatter.ts
│ │ ├── test-setup.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ ├── devtools/
│ │ ├── GEMINI.md
│ │ ├── client/
│ │ │ ├── index.html
│ │ │ └── src/
│ │ │ ├── App.tsx
│ │ │ ├── hooks.ts
│ │ │ └── main.tsx
│ │ ├── esbuild.client.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ ├── tsconfig.build.json
│ │ └── tsconfig.json
│ ├── sdk/
│ │ ├── GEMINI.md
│ │ ├── README.md
│ │ ├── SDK_DESIGN.md
│ │ ├── examples/
│ │ │ ├── session-context.ts
│ │ │ └── simple.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── agent.integration.test.ts
│ │ │ ├── agent.ts
│ │ │ ├── fs.ts
│ │ │ ├── index.ts
│ │ │ ├── session.ts
│ │ │ ├── shell.ts
│ │ │ ├── skills.integration.test.ts
│ │ │ ├── skills.ts
│ │ │ ├── tool.integration.test.ts
│ │ │ ├── tool.test.ts
│ │ │ ├── tool.ts
│ │ │ └── types.ts
│ │ ├── test-data/
│ │ │ ├── agent-async-instructions.json
│ │ │ ├── agent-dynamic-instructions.json
│ │ │ ├── agent-resume-session.json
│ │ │ ├── agent-static-instructions.json
│ │ │ ├── skill-dir-success.json
│ │ │ ├── skill-root-success.json
│ │ │ ├── skills/
│ │ │ │ └── pirate-skill/
│ │ │ │ └── SKILL.md
│ │ │ ├── tool-catchall-error.json
│ │ │ ├── tool-error-recovery.json
│ │ │ └── tool-success.json
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ ├── test-utils/
│ │ ├── GEMINI.md
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── file-system-test-helpers.ts
│ │ │ ├── index.ts
│ │ │ ├── mock-utils.ts
│ │ │ └── test-rig.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ └── vscode-ide-companion/
│ ├── .vscode/
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── .vscodeignore
│ ├── GEMINI.md
│ ├── LICENSE
│ ├── NOTICES.txt
│ ├── README.md
│ ├── development.md
│ ├── esbuild.js
│ ├── package.json
│ ├── scripts/
│ │ ├── check-vscode-release.js
│ │ └── generate-notices.js
│ ├── src/
│ │ ├── diff-manager.ts
│ │ ├── extension.test.ts
│ │ ├── extension.ts
│ │ ├── ide-server.test.ts
│ │ ├── ide-server.ts
│ │ ├── open-files-manager.test.ts
│ │ ├── open-files-manager.ts
│ │ └── utils/
│ │ └── logger.ts
│ └── tsconfig.json
├── schemas/
│ └── settings.schema.json
├── scripts/
│ ├── aggregate_evals.js
│ ├── batch_triage.sh
│ ├── build.js
│ ├── build_binary.js
│ ├── build_package.js
│ ├── build_sandbox.js
│ ├── build_vscode_companion.js
│ ├── changed_prompt.js
│ ├── check-build-status.js
│ ├── check-lockfile.js
│ ├── clean.js
│ ├── cleanup-branches.ts
│ ├── close_duplicate_issues.js
│ ├── copy_bundle_assets.js
│ ├── copy_files.js
│ ├── create_alias.sh
│ ├── deflake.js
│ ├── entitlements.plist
│ ├── generate-git-commit-info.js
│ ├── generate-keybindings-doc.ts
│ ├── generate-settings-doc.ts
│ ├── generate-settings-schema.ts
│ ├── get-release-version.js
│ ├── lint.js
│ ├── local_telemetry.js
│ ├── pre-commit.js
│ ├── prepare-github-release.js
│ ├── prepare-npm-release.js
│ ├── prepare-package.js
│ ├── relabel_issues.sh
│ ├── releasing/
│ │ ├── create-patch-pr.js
│ │ ├── patch-comment.js
│ │ ├── patch-create-comment.js
│ │ └── patch-trigger.js
│ ├── review.sh
│ ├── sandbox_command.js
│ ├── send_gemini_request.sh
│ ├── start.js
│ ├── sync_project_dry_run.js
│ ├── telemetry.js
│ ├── telemetry_gcp.js
│ ├── telemetry_genkit.js
│ ├── telemetry_utils.js
│ ├── test-windows-paths.js
│ ├── tests/
│ │ ├── autogen.test.ts
│ │ ├── generate-keybindings-doc.test.ts
│ │ ├── generate-settings-doc.test.ts
│ │ ├── generate-settings-schema.test.ts
│ │ ├── get-release-version.test.js
│ │ ├── patch-create-comment.test.js
│ │ ├── telemetry_gcp.test.ts
│ │ ├── test-setup.ts
│ │ └── vitest.config.ts
│ ├── utils/
│ │ └── autogen.ts
│ └── version.js
├── sea/
│ ├── sea-launch.cjs
│ └── sea-launch.test.js
├── third_party/
│ └── get-ripgrep/
│ ├── LICENSE
│ ├── package.json
│ └── src/
│ ├── downloadRipGrep.js
│ └── index.js
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .allstar/branch_protection.yaml
================================================
action: 'log'
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
insert_final_newline = true
end_of_line = lf
indent_style = space
indent_size = 2
max_line_length = 80
[Makefile]
indent_style = tab
indent_size = 8
================================================
FILE: .gcp/Dockerfile.gemini-code-builder
================================================
# 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'
================================================
FILE: .gcp/release-docker.yml
================================================
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: 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 3: 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 4: Determine Docker Image Tag
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
id: 'Determine Docker Image Tag'
entrypoint: 'bash'
args:
- '-c'
- |-
SHELL_TAG_NAME="$TAG_NAME"
FINAL_TAG="$SHORT_SHA" # Default to SHA
if [[ "$$SHELL_TAG_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
echo "Release detected."
FINAL_TAG="$${SHELL_TAG_NAME#v}"
else
echo "Development release detected. Using commit SHA as tag."
fi
echo "Determined image tag: $$FINAL_TAG"
echo "$$FINAL_TAG" > /workspace/image_tag.txt
# Step 5: 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: 'bash'
args:
- '-c'
- |-
export GEMINI_SANDBOX_IMAGE_TAG=$$(cat /workspace/image_tag.txt)
echo "Using Docker image tag for build: $$GEMINI_SANDBOX_IMAGE_TAG"
npm run build:sandbox -- --output-file /workspace/final_image_uri.txt
env:
- 'GEMINI_SANDBOX=$_CONTAINER_TOOL'
# 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: 'bash'
args:
- '-c'
- |-
set -e
FINAL_IMAGE_URI=$$(cat /workspace/final_image_uri.txt)
echo "Pushing sandbox image: $${FINAL_IMAGE_URI}"
$_CONTAINER_TOOL push "$${FINAL_IMAGE_URI}"
env:
- 'GEMINI_SANDBOX=$_CONTAINER_TOOL'
options:
defaultLogsBucketBehavior: 'REGIONAL_USER_OWNED_BUCKET'
dynamicSubstitutions: true
substitutions:
_CONTAINER_TOOL: 'docker'
================================================
FILE: .gemini/config.yaml
================================================
# Config for the Gemini Pull Request Review Bot.
# https://github.com/marketplace/gemini-code-assist
have_fun: false
code_review:
disable: false
comment_severity_threshold: 'HIGH'
max_review_comments: -1
pull_request_opened:
help: false
summary: true
code_review: true
include_drafts: false
ignore_patterns: []
================================================
FILE: .gemini/settings.json
================================================
{
"experimental": {
"plan": true,
"extensionReloading": true,
"modelSteering": true,
"memoryManager": true
},
"general": {
"devtools": true
}
}
================================================
FILE: .geminiignore
================================================
packages/core/src/services/scripts/*.exe
================================================
FILE: .gitattributes
================================================
# 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
================================================
FILE: .github/CODEOWNERS
================================================
# By default, require reviews from the maintainers for all files.
* @google-gemini/gemini-cli-maintainers
# Require reviews from the release approvers for critical files.
# These patterns override the rule above.
/package.json @google-gemini/gemini-cli-askmode-approvers
/package-lock.json @google-gemini/gemini-cli-askmode-approvers
/GEMINI.md @google-gemini/gemini-cli-askmode-approvers
/SECURITY.md @google-gemini/gemini-cli-askmode-approvers
/LICENSE @google-gemini/gemini-cli-askmode-approvers
/.github/workflows/ @google-gemini/gemini-cli-askmode-approvers
/packages/cli/package.json @google-gemini/gemini-cli-askmode-approvers
/packages/core/package.json @google-gemini/gemini-cli-askmode-approvers
# Docs have a dedicated approver group in addition to maintainers
/docs/ @google-gemini/gemini-cli-maintainers @google-gemini/gemini-cli-docs
/README.md @google-gemini/gemini-cli-maintainers @google-gemini/gemini-cli-docs
# Prompt contents, tool definitions, and evals require reviews from prompt approvers
/packages/core/src/prompts/ @google-gemini/gemini-cli-prompt-approvers
/packages/core/src/tools/ @google-gemini/gemini-cli-prompt-approvers
/evals/ @google-gemini/gemini-cli-prompt-approvers
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: 'Bug Report'
description: 'Report a bug to help us improve Gemini CLI'
body:
- type: 'markdown'
attributes:
value: |-
> [!IMPORTANT]
> 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). Note that this output contains your email address. Consider removing it before submitting.'
value: |-
<details>
<summary>Client Information</summary>
Run `gemini` to enter the interactive CLI, then run the `/about` command.
```console
> /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.'
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: 'Feature Request'
description: 'Suggest an idea for this project'
labels:
- 'status/need-triage'
type: 'Feature'
body:
- type: 'markdown'
attributes:
value: |-
> [!IMPORTANT]
> 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.'
================================================
FILE: .github/ISSUE_TEMPLATE/website_issue.yml
================================================
name: 'Website issue'
description: 'Report an issue with the Gemini CLI Website and Gemini CLI Extensions Gallery'
title: 'GeminiCLI.com Feedback: [ISSUE]'
labels:
- 'area/extensions'
- 'area/documentation'
body:
- type: 'markdown'
attributes:
value: |-
> [!IMPORTANT]
> Thanks for taking the time to report an issue with the Gemini CLI Website
>
> Please search **[existing issues](https://github.com/google-gemini/gemini-cli/issues?q=is%3Aissue+is%3Aopen+label%3Aarea%2Fwebsite)** to see if a similar feature has already been requested.
- type: 'input'
id: 'url'
attributes:
label: 'URL of the page with the issue'
description: 'Please provide the URL where the issue occurs.'
validations:
required: true
- type: 'textarea'
id: 'problem'
attributes:
label: 'What is the problem?'
description: 'A clear and concise description of what the bug or issue is.'
validations:
required: true
- type: 'textarea'
id: 'expected'
attributes:
label: 'What did you expect to happen?'
validations:
required: true
- type: 'textarea'
id: 'additional-context'
attributes:
label: 'Additional context'
description: 'Add any other context or screenshots about the issue here.'
================================================
FILE: .github/actions/calculate-vars/action.yml
================================================
name: 'Calculate vars'
description: 'Calculate commonly used var in our release process'
inputs:
dry_run:
description: 'Whether or not this is a dry run'
type: 'boolean'
outputs:
is_dry_run:
description: 'Boolean flag indicating if the current run is a dry-run or a production release.'
value: '${{ steps.set_vars.outputs.is_dry_run }}'
runs:
using: 'composite'
steps:
- name: 'Print inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Set vars for simplified logic'
id: 'set_vars'
shell: 'bash'
env:
DRY_RUN_INPUT: '${{ inputs.dry_run }}'
run: |-
is_dry_run="true"
if [[ "${DRY_RUN_INPUT}" == "" || "${DRY_RUN_INPUT}" == "false" ]]; then
is_dry_run="false"
fi
echo "is_dry_run=${is_dry_run}" >> "${GITHUB_OUTPUT}"
================================================
FILE: .github/actions/create-pull-request/action.yml
================================================
name: 'Create Pull Request'
description: 'Creates a pull request.'
inputs:
branch-name:
description: 'The name of the branch to create the PR from.'
required: true
pr-title:
description: 'The title of the pull request.'
required: true
pr-body:
description: 'The body of the pull request.'
required: true
base-branch:
description: 'The branch to merge into.'
required: true
default: 'main'
github-token:
description: 'The GitHub token to use for creating the pull request.'
required: true
dry-run:
description: 'Whether to run in dry-run mode.'
required: false
default: 'false'
working-directory:
description: 'The working directory to run the commands in.'
required: false
default: '.'
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Creates a Pull Request'
if: "inputs.dry-run != 'true'"
env:
GH_TOKEN: '${{ inputs.github-token }}'
INPUTS_BRANCH_NAME: '${{ inputs.branch-name }}'
INPUTS_PR_TITLE: '${{ inputs.pr-title }}'
INPUTS_PR_BODY: '${{ inputs.pr-body }}'
INPUTS_BASE_BRANCH: '${{ inputs.base-branch }}'
shell: 'bash'
working-directory: '${{ inputs.working-directory }}'
run: |
set -e
if ! git ls-remote --exit-code --heads origin "${INPUTS_BRANCH_NAME}"; then
echo "::error::Branch '${INPUTS_BRANCH_NAME}' does not exist on the remote repository."
exit 1
fi
PR_URL=$(gh pr create \
--title "${INPUTS_PR_TITLE}" \
--body "${INPUTS_PR_BODY}" \
--base "${INPUTS_BASE_BRANCH}" \
--head "${INPUTS_BRANCH_NAME}" \
--fill)
gh pr merge "$PR_URL" --auto
================================================
FILE: .github/actions/npm-auth-token/action.yml
================================================
name: 'NPM Auth Token'
description: 'Generates an NPM auth token for publishing a specific package'
inputs:
package-name:
description: 'The name of the package to publish'
required: true
github-token:
description: 'the github token'
required: true
wombat-token-core:
description: 'The npm token for the cli-core package.'
required: true
wombat-token-cli:
description: 'The npm token for the cli package.'
required: true
wombat-token-a2a-server:
description: 'The npm token for the a2a package.'
required: true
outputs:
auth-token:
description: 'The generated NPM auth token'
value: '${{ steps.npm_auth_token.outputs.auth-token }}'
runs:
using: 'composite'
steps:
- name: 'Generate NPM Auth Token'
id: 'npm_auth_token'
shell: 'bash'
run: |
AUTH_TOKEN="${INPUTS_GITHUB_TOKEN}"
PACKAGE_NAME="${INPUTS_PACKAGE_NAME}"
PRIVATE_REPO="@google-gemini/"
if [[ "$PACKAGE_NAME" == "$PRIVATE_REPO"* ]]; then
AUTH_TOKEN="${INPUTS_GITHUB_TOKEN}"
elif [[ "$PACKAGE_NAME" == "@google/gemini-cli" ]]; then
AUTH_TOKEN="${INPUTS_WOMBAT_TOKEN_CLI}"
elif [[ "$PACKAGE_NAME" == "@google/gemini-cli-core" ]]; then
AUTH_TOKEN="${INPUTS_WOMBAT_TOKEN_CORE}"
elif [[ "$PACKAGE_NAME" == "@google/gemini-cli-a2a-server" ]]; then
AUTH_TOKEN="${INPUTS_WOMBAT_TOKEN_A2A_SERVER}"
fi
echo "auth-token=$AUTH_TOKEN" >> $GITHUB_OUTPUT
env:
INPUTS_GITHUB_TOKEN: '${{ inputs.github-token }}'
INPUTS_PACKAGE_NAME: '${{ inputs.package-name }}'
INPUTS_WOMBAT_TOKEN_CLI: '${{ inputs.wombat-token-cli }}'
INPUTS_WOMBAT_TOKEN_CORE: '${{ inputs.wombat-token-core }}'
INPUTS_WOMBAT_TOKEN_A2A_SERVER: '${{ inputs.wombat-token-a2a-server }}'
================================================
FILE: .github/actions/post-coverage-comment/action.yml
================================================
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
os:
description: 'The os for context in messages'
required: true
github_token:
description: 'GitHub token for posting comments'
required: true
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Prepare Coverage Comment'
id: 'prep_coverage_comment'
shell: 'bash'
env:
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'
NODE_VERSION: '${{ inputs.node_version }}'
OS: '${{ inputs.os }}'
run: |-
# 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-${NODE_VERSION}-${OS}' artifact from the main CI run._" >> "${COMMENT_FILE}"
- name: 'Post Coverage Comment'
uses: 'thollander/actions-comment-pull-request@65f9e5c9a1f2cd378bd74b2e057c9736982a8e74' # ratchet: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 }}'
================================================
FILE: .github/actions/publish-release/action.yml
================================================
name: 'Publish Release'
description: 'Builds, prepares, and publishes the gemini-cli packages to npm and creates a GitHub release.'
inputs:
release-version:
description: 'The version to release (e.g., 0.1.11).'
required: true
npm-tag:
description: 'The npm tag to publish with (e.g., latest, preview, nightly).'
required: true
wombat-token-core:
description: 'The npm token for the cli-core package.'
required: true
wombat-token-cli:
description: 'The npm token for the cli package.'
required: true
wombat-token-a2a-server:
description: 'The npm token for the a2a package.'
required: true
github-token:
description: 'The GitHub token for creating the release.'
required: true
github-release-token:
description: 'The GitHub token used specifically for creating the GitHub release (to trigger other workflows).'
required: false
dry-run:
description: 'Whether to run in dry-run mode.'
type: 'string'
required: true
release-tag:
description: 'The release tag for the release (e.g., v0.1.11).'
required: true
previous-tag:
description: 'The previous tag to use for generating release notes.'
required: true
skip-github-release:
description: 'Whether to skip creating a GitHub release.'
type: 'boolean'
required: false
default: false
working-directory:
description: 'The working directory to run the steps in.'
required: false
default: '.'
force-skip-tests:
description: 'Skip tests and validation'
required: false
default: false
skip-branch-cleanup:
description: 'Whether to skip cleaning up the release branch.'
type: 'boolean'
required: false
default: false
gemini_api_key:
description: 'The API key for running integration tests.'
required: true
npm-registry-publish-url:
description: 'npm registry publish url'
required: true
npm-registry-url:
description: 'npm registry url'
required: true
npm-registry-scope:
description: 'npm registry scope'
required: true
cli-package-name:
description: 'The name of the cli package.'
required: true
core-package-name:
description: 'The name of the core package.'
required: true
a2a-package-name:
description: 'The name of the a2a package.'
required: true
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: '👤 Configure Git User'
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
run: |
git config user.name "gemini-cli-robot"
git config user.email "gemini-cli-robot@google.com"
- name: '🌿 Create and switch to a release branch'
working-directory: '${{ inputs.working-directory }}'
id: 'release_branch'
shell: 'bash'
run: |
BRANCH_NAME="release/${INPUTS_RELEASE_TAG}"
git switch -c "${BRANCH_NAME}"
echo "BRANCH_NAME=${BRANCH_NAME}" >> "${GITHUB_OUTPUT}"
env:
INPUTS_RELEASE_TAG: '${{ inputs.release-tag }}'
- name: '⬆️ Update package versions'
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
run: |
npm run release:version "${INPUTS_RELEASE_VERSION}"
env:
INPUTS_RELEASE_VERSION: '${{ inputs.release-version }}'
- name: '💾 Commit and Conditionally Push package versions'
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
env:
BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
DRY_RUN: '${{ inputs.dry-run }}'
RELEASE_TAG: '${{ inputs.release-tag }}'
run: |-
set -e
git add package.json package-lock.json packages/*/package.json
git commit -m "chore(release): ${RELEASE_TAG}"
if [[ "${DRY_RUN}" == "false" ]]; then
echo "Pushing release branch to remote..."
git push --set-upstream origin "${BRANCH_NAME}" --follow-tags
else
echo "Dry run enabled. Skipping push."
fi
- name: '🛠️ Build and Prepare Packages'
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
run: |
npm run build:packages
npm run prepare:package
- name: '🎁 Bundle'
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
run: |
npm run bundle
# TODO: Refactor this github specific publishing script to be generalized based upon inputs.
- name: '📦 Prepare for GitHub release'
if: "inputs.npm-registry-url == 'https://npm.pkg.github.com/'"
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
run: |
node ${{ github.workspace }}/scripts/prepare-github-release.js
- name: 'Configure npm for publishing to npm'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
with:
node-version-file: '${{ inputs.working-directory }}/.nvmrc'
registry-url: '${{inputs.npm-registry-publish-url}}'
scope: '${{inputs.npm-registry-scope}}'
- name: 'Get core Token'
uses: './.github/actions/npm-auth-token'
id: 'core-token'
with:
package-name: '${{ inputs.core-package-name }}'
github-token: '${{ inputs.github-token }}'
wombat-token-core: '${{ inputs.wombat-token-core }}'
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
- name: '📦 Publish CORE to NPM'
working-directory: '${{ inputs.working-directory }}'
env:
NODE_AUTH_TOKEN: '${{ steps.core-token.outputs.auth-token }}'
INPUTS_DRY_RUN: '${{ inputs.dry-run }}'
INPUTS_CORE_PACKAGE_NAME: '${{ inputs.core-package-name }}'
shell: 'bash'
run: |
npm publish \
--dry-run="${INPUTS_DRY_RUN}" \
--workspace="${INPUTS_CORE_PACKAGE_NAME}" \
--no-tag
npm dist-tag rm ${INPUTS_CORE_PACKAGE_NAME} false --silent
- name: '🔗 Install latest core package'
working-directory: '${{ inputs.working-directory }}'
if: "${{ inputs.dry-run != 'true' }}"
shell: 'bash'
run: |
npm install "${INPUTS_CORE_PACKAGE_NAME}@${INPUTS_RELEASE_VERSION}" \
--workspace="${INPUTS_CLI_PACKAGE_NAME}" \
--workspace="${INPUTS_A2A_PACKAGE_NAME}" \
--save-exact
env:
INPUTS_CORE_PACKAGE_NAME: '${{ inputs.core-package-name }}'
INPUTS_RELEASE_VERSION: '${{ inputs.release-version }}'
INPUTS_CLI_PACKAGE_NAME: '${{ inputs.cli-package-name }}'
INPUTS_A2A_PACKAGE_NAME: '${{ inputs.a2a-package-name }}'
- name: '📦 Prepare bundled CLI for npm release'
if: "inputs.npm-registry-url != 'https://npm.pkg.github.com/' && inputs.npm-tag != 'latest'"
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
run: |
node ${{ github.workspace }}/scripts/prepare-npm-release.js
- name: 'Get CLI Token'
uses: './.github/actions/npm-auth-token'
id: 'cli-token'
with:
package-name: '${{ inputs.cli-package-name }}'
github-token: '${{ inputs.github-token }}'
wombat-token-core: '${{ inputs.wombat-token-core }}'
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
- name: '📦 Publish CLI'
working-directory: '${{ inputs.working-directory }}'
env:
NODE_AUTH_TOKEN: '${{ steps.cli-token.outputs.auth-token }}'
INPUTS_DRY_RUN: '${{ inputs.dry-run }}'
INPUTS_CLI_PACKAGE_NAME: '${{ inputs.cli-package-name }}'
shell: 'bash'
run: |
npm publish \
--dry-run="${INPUTS_DRY_RUN}" \
--workspace="${INPUTS_CLI_PACKAGE_NAME}" \
--no-tag
npm dist-tag rm ${INPUTS_CLI_PACKAGE_NAME} false --silent
- name: 'Get a2a-server Token'
uses: './.github/actions/npm-auth-token'
id: 'a2a-token'
with:
package-name: '${{ inputs.a2a-package-name }}'
github-token: '${{ inputs.github-token }}'
wombat-token-core: '${{ inputs.wombat-token-core }}'
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
- name: '📦 Publish a2a'
working-directory: '${{ inputs.working-directory }}'
env:
NODE_AUTH_TOKEN: '${{ steps.a2a-token.outputs.auth-token }}'
INPUTS_DRY_RUN: '${{ inputs.dry-run }}'
INPUTS_A2A_PACKAGE_NAME: '${{ inputs.a2a-package-name }}'
shell: 'bash'
# Tag staging for initial release
run: |
npm publish \
--dry-run="${INPUTS_DRY_RUN}" \
--workspace="${INPUTS_A2A_PACKAGE_NAME}" \
--no-tag
npm dist-tag rm ${INPUTS_A2A_PACKAGE_NAME} false --silent
- name: '🔬 Verify NPM release by version'
uses: './.github/actions/verify-release'
if: "${{ inputs.dry-run != 'true' && inputs.force-skip-tests != 'true' }}"
with:
npm-package: '${{ inputs.cli-package-name }}@${{ inputs.release-version }}'
expected-version: '${{ inputs.release-version }}'
working-directory: '${{ inputs.working-directory }}'
gemini_api_key: '${{ inputs.gemini_api_key }}'
github-token: '${{ inputs.github-token }}'
npm-registry-url: '${{ inputs.npm-registry-url }}'
npm-registry-scope: '${{ inputs.npm-registry-scope }}'
- name: '🏷️ Tag release'
uses: './.github/actions/tag-npm-release'
with:
channel: '${{ inputs.npm-tag }}'
version: '${{ inputs.release-version }}'
dry-run: '${{ inputs.dry-run }}'
github-token: '${{ inputs.github-token }}'
wombat-token-core: '${{ inputs.wombat-token-core }}'
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
cli-package-name: '${{ inputs.cli-package-name }}'
core-package-name: '${{ inputs.core-package-name }}'
a2a-package-name: '${{ inputs.a2a-package-name }}'
working-directory: '${{ inputs.working-directory }}'
- name: '🎉 Create GitHub Release'
working-directory: '${{ inputs.working-directory }}'
if: "${{ inputs.dry-run != 'true' && inputs.skip-github-release != 'true' && inputs.npm-tag != 'dev' && inputs.npm-registry-url != 'https://npm.pkg.github.com/' }}"
env:
GITHUB_TOKEN: '${{ inputs.github-release-token || inputs.github-token }}'
INPUTS_RELEASE_TAG: '${{ inputs.release-tag }}'
STEPS_RELEASE_BRANCH_OUTPUTS_BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
INPUTS_PREVIOUS_TAG: '${{ inputs.previous-tag }}'
shell: 'bash'
run: |
gh release create "${INPUTS_RELEASE_TAG}" \
bundle/gemini.js \
--target "${STEPS_RELEASE_BRANCH_OUTPUTS_BRANCH_NAME}" \
--title "Release ${INPUTS_RELEASE_TAG}" \
--notes-start-tag "${INPUTS_PREVIOUS_TAG}" \
--generate-notes \
${{ inputs.npm-tag != 'latest' && '--prerelease' || '' }}
- name: '🧹 Clean up release branch'
working-directory: '${{ inputs.working-directory }}'
if: "${{ inputs.dry-run != 'true' && inputs.skip-branch-cleanup != 'true' }}"
continue-on-error: true
shell: 'bash'
run: |
echo "Cleaning up release branch ${STEPS_RELEASE_BRANCH_OUTPUTS_BRANCH_NAME}..."
git push origin --delete "${STEPS_RELEASE_BRANCH_OUTPUTS_BRANCH_NAME}"
env:
STEPS_RELEASE_BRANCH_OUTPUTS_BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
================================================
FILE: .github/actions/push-docker/action.yml
================================================
name: 'Push to docker'
description: 'Builds packages and pushes a docker image to GHCR'
inputs:
github-actor:
description: 'Github actor'
required: true
github-secret:
description: 'Github secret'
required: true
ref-name:
description: 'Github ref name'
required: true
github-sha:
description: 'Github Commit SHA Hash'
required: true
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Checkout'
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v4
with:
ref: '${{ inputs.github-sha }}'
fetch-depth: 0
- name: 'Install Dependencies'
shell: 'bash'
run: 'npm install'
- name: 'Set up Docker Buildx'
uses: 'docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435' # ratchet:docker/setup-buildx-action@v3
- name: 'build'
shell: 'bash'
run: 'npm run build'
- name: 'pack @google/gemini-cli'
shell: 'bash'
run: 'npm pack -w @google/gemini-cli --pack-destination ./packages/cli/dist'
- name: 'pack @google/gemini-cli-core'
shell: 'bash'
run: 'npm pack -w @google/gemini-cli-core --pack-destination ./packages/core/dist'
- name: 'Log in to GitHub Container Registry'
uses: 'docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1' # ratchet:docker/login-action@v3
with:
registry: 'ghcr.io'
username: '${{ inputs.github-actor }}'
password: '${{ inputs.github-secret }}'
- name: 'Get branch name'
id: 'branch_name'
shell: 'bash'
run: |
REF_NAME="${INPUTS_REF_NAME}"
echo "name=${REF_NAME%/merge}" >> $GITHUB_OUTPUT
env:
INPUTS_REF_NAME: '${{ inputs.ref-name }}'
- name: 'Build and Push the Docker Image'
uses: 'docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83' # ratchet:docker/build-push-action@v6
with:
context: '.'
file: './Dockerfile'
push: true
provenance: false # avoid pushing 3 images to Aritfact Registry
tags: |
ghcr.io/${{ github.repository }}/cli:${{ steps.branch_name.outputs.name }}
ghcr.io/${{ github.repository }}/cli:${{ inputs.github-sha }}
- name: 'Create issue on failure'
if: |-
${{ failure() }}
shell: 'bash'
env:
GITHUB_TOKEN: '${{ inputs.github-secret }}'
DETAILS_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
run: |-
gh issue create \
--title "Docker build failed" \
--body "The docker build failed. See the full run for details: ${DETAILS_URL}" \
--label "release-failure"
================================================
FILE: .github/actions/push-sandbox/action.yml
================================================
name: 'Build and push sandbox docker'
description: 'Pushes sandbox docker image to container registry'
inputs:
github-actor:
description: 'Github actor'
required: true
github-secret:
description: 'Github secret'
required: true
dockerhub-username:
description: 'Dockerhub username'
required: true
dockerhub-token:
description: 'Dockerhub PAT w/ R+W'
required: true
github-sha:
description: 'Github Commit SHA Hash'
required: true
github-ref-name:
description: 'Github ref name'
required: true
dry-run:
description: 'Whether this is a dry run.'
required: true
type: 'boolean'
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Checkout'
uses: 'actions/checkout@v4'
with:
ref: '${{ inputs.github-sha }}'
fetch-depth: 0
- name: 'Install Dependencies'
shell: 'bash'
run: 'npm install'
- name: 'npm build'
shell: 'bash'
run: 'npm run build'
- name: 'Set up QEMU'
uses: 'docker/setup-qemu-action@v3'
- name: 'Set up Docker Buildx'
uses: 'docker/setup-buildx-action@v3'
- name: 'Log in to GitHub Container Registry'
uses: 'docker/login-action@v3'
with:
registry: 'docker.io'
username: '${{ inputs.dockerhub-username }}'
password: '${{ inputs.dockerhub-token }}'
- name: 'determine image tag'
id: 'image_tag'
shell: 'bash'
run: |-
SHELL_TAG_NAME="${INPUTS_GITHUB_REF_NAME}"
FINAL_TAG="${INPUTS_GITHUB_SHA}"
if [[ "$SHELL_TAG_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
echo "Release detected."
FINAL_TAG="${SHELL_TAG_NAME#v}"
else
echo "Development release detected. Using commit SHA as tag."
fi
echo "Determined image tag: $FINAL_TAG"
echo "FINAL_TAG=$FINAL_TAG" >> $GITHUB_OUTPUT
env:
INPUTS_GITHUB_REF_NAME: '${{ inputs.github-ref-name }}'
INPUTS_GITHUB_SHA: '${{ inputs.github-sha }}'
# We build amd64 just so we can verify it.
# We build and push both amd64 and arm64 in the publish step.
- name: 'build'
id: 'docker_build'
shell: 'bash'
env:
GEMINI_SANDBOX_IMAGE_TAG: '${{ steps.image_tag.outputs.FINAL_TAG }}'
GEMINI_SANDBOX: 'docker'
BUILD_SANDBOX_FLAGS: '--platform linux/amd64 --load'
STEPS_IMAGE_TAG_OUTPUTS_FINAL_TAG: '${{ steps.image_tag.outputs.FINAL_TAG }}'
run: |-
npm run build:sandbox -- \
--image "google/gemini-cli-sandbox:${STEPS_IMAGE_TAG_OUTPUTS_FINAL_TAG}" \
--output-file final_image_uri.txt
echo "uri=$(cat final_image_uri.txt)" >> $GITHUB_OUTPUT
- name: 'verify'
shell: 'bash'
run: |-
docker run --rm --entrypoint sh "${{ steps.docker_build.outputs.uri }}" -lc '
set -e
node -e "const fs=require(\"node:fs\"); JSON.parse(fs.readFileSync(\"/usr/local/share/npm-global/lib/node_modules/@google/gemini-cli/package.json\",\"utf8\")); JSON.parse(fs.readFileSync(\"/usr/local/share/npm-global/lib/node_modules/@google/gemini-cli-core/package.json\",\"utf8\"));"
/usr/local/share/npm-global/bin/gemini --version >/dev/null
'
- name: 'publish'
shell: 'bash'
if: "${{ inputs.dry-run != 'true' }}"
env:
GEMINI_SANDBOX_IMAGE_TAG: '${{ steps.image_tag.outputs.FINAL_TAG }}'
GEMINI_SANDBOX: 'docker'
BUILD_SANDBOX_FLAGS: '--platform linux/amd64,linux/arm64 --push'
STEPS_IMAGE_TAG_OUTPUTS_FINAL_TAG: '${{ steps.image_tag.outputs.FINAL_TAG }}'
run: |-
npm run build:sandbox -- \
--image "google/gemini-cli-sandbox:${STEPS_IMAGE_TAG_OUTPUTS_FINAL_TAG}"
- name: 'Create issue on failure'
if: |-
${{ failure() }}
shell: 'bash'
env:
GITHUB_TOKEN: '${{ inputs.github-secret }}'
DETAILS_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
run: |-
gh issue create \
--title "Docker build failed" \
--body "The docker build failed. See the full run for details: ${DETAILS_URL}" \
--label "release-failure"
================================================
FILE: .github/actions/run-tests/action.yml
================================================
name: 'Run Tests'
description: 'Runs the preflight checks and integration tests.'
inputs:
gemini_api_key:
description: 'The API key for running integration tests.'
required: true
working-directory:
description: 'The working directory to run the tests in.'
required: false
default: '.'
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Run Tests'
env:
GEMINI_API_KEY: '${{ inputs.gemini_api_key }}'
working-directory: '${{ inputs.working-directory }}'
run: |-
echo "::group::Build"
npm run build
echo "::endgroup::"
echo "::group::Unit Tests"
npm run test:ci
echo "::endgroup::"
echo "::group::Integration Tests (no sandbox)"
npm run test:integration:sandbox:none
echo "::endgroup::"
echo "::group::Integration Tests (docker sandbox)"
npm run test:integration:sandbox:docker
echo "::endgroup::"
shell: 'bash'
================================================
FILE: .github/actions/setup-npmrc/action.yml
================================================
name: 'Setup NPMRC'
description: 'Sets up NPMRC with all the correct repos for readonly access.'
inputs:
github-token:
description: 'the github token'
required: true
outputs:
auth-token:
description: 'The generated NPM auth token'
value: '${{ steps.npm_auth_token.outputs.auth-token }}'
runs:
using: 'composite'
steps:
- name: 'Configure .npmrc'
shell: 'bash'
run: |-
echo ""@google-gemini:registry=https://npm.pkg.github.com"" > ~/.npmrc
echo ""//npm.pkg.github.com/:_authToken=${INPUTS_GITHUB_TOKEN}"" >> ~/.npmrc
echo ""@google:registry=https://wombat-dressing-room.appspot.com"" >> ~/.npmrc
env:
INPUTS_GITHUB_TOKEN: '${{ inputs.github-token }}'
================================================
FILE: .github/actions/tag-npm-release/action.yml
================================================
name: 'Tag an NPM release'
description: 'Tags a specific npm version to a specific channel.'
inputs:
channel:
description: 'NPM Channel tag'
required: true
version:
description: 'version'
required: true
dry-run:
description: 'Whether to run in dry-run mode.'
required: true
github-token:
description: 'The GitHub token for creating the release.'
required: true
wombat-token-core:
description: 'The npm token for the wombat @google/gemini-cli-core'
required: true
wombat-token-cli:
description: 'The npm token for wombat @google/gemini-cli'
required: true
wombat-token-a2a-server:
description: 'The npm token for the @google/gemini-cli-a2a-server package.'
required: true
cli-package-name:
description: 'The name of the cli package.'
required: true
core-package-name:
description: 'The name of the core package.'
required: true
a2a-package-name:
description: 'The name of the a2a package.'
required: true
working-directory:
description: 'The working directory to run the commands in.'
required: false
default: '.'
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
with:
node-version-file: '${{ inputs.working-directory }}/.nvmrc'
- name: 'configure .npmrc'
uses: './.github/actions/setup-npmrc'
with:
github-token: '${{ inputs.github-token }}'
- name: 'Get core Token'
uses: './.github/actions/npm-auth-token'
id: 'core-token'
with:
package-name: '${{ inputs.core-package-name }}'
github-token: '${{ inputs.github-token }}'
wombat-token-core: '${{ inputs.wombat-token-core }}'
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
- name: 'Change tag for CORE'
if: |-
${{ inputs.dry-run != 'true' }}
env:
NODE_AUTH_TOKEN: '${{ steps.core-token.outputs.auth-token }}'
INPUTS_CORE_PACKAGE_NAME: '${{ inputs.core-package-name }}'
INPUTS_VERSION: '${{ inputs.version }}'
INPUTS_CHANNEL: '${{ inputs.channel }}'
shell: 'bash'
working-directory: '${{ inputs.working-directory }}'
run: |
npm dist-tag add ${INPUTS_CORE_PACKAGE_NAME}@${INPUTS_VERSION} ${INPUTS_CHANNEL}
- name: 'Get cli Token'
uses: './.github/actions/npm-auth-token'
id: 'cli-token'
with:
package-name: '${{ inputs.cli-package-name }}'
github-token: '${{ inputs.github-token }}'
wombat-token-core: '${{ inputs.wombat-token-core }}'
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
- name: 'Change tag for CLI'
if: |-
${{ inputs.dry-run != 'true' }}
env:
NODE_AUTH_TOKEN: '${{ steps.cli-token.outputs.auth-token }}'
INPUTS_CLI_PACKAGE_NAME: '${{ inputs.cli-package-name }}'
INPUTS_VERSION: '${{ inputs.version }}'
INPUTS_CHANNEL: '${{ inputs.channel }}'
shell: 'bash'
working-directory: '${{ inputs.working-directory }}'
run: |
npm dist-tag add ${INPUTS_CLI_PACKAGE_NAME}@${INPUTS_VERSION} ${INPUTS_CHANNEL}
- name: 'Get a2a Token'
uses: './.github/actions/npm-auth-token'
id: 'a2a-token'
with:
package-name: '${{ inputs.a2a-package-name }}'
github-token: '${{ inputs.github-token }}'
wombat-token-core: '${{ inputs.wombat-token-core }}'
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
- name: 'Change tag for a2a'
if: |-
${{ inputs.dry-run == 'false' }}
env:
NODE_AUTH_TOKEN: '${{ steps.a2a-token.outputs.auth-token }}'
INPUTS_A2A_PACKAGE_NAME: '${{ inputs.a2a-package-name }}'
INPUTS_VERSION: '${{ inputs.version }}'
INPUTS_CHANNEL: '${{ inputs.channel }}'
shell: 'bash'
working-directory: '${{ inputs.working-directory }}'
run: |
npm dist-tag add ${INPUTS_A2A_PACKAGE_NAME}@${INPUTS_VERSION} ${INPUTS_CHANNEL}
- name: 'Log dry run'
if: |-
${{ inputs.dry-run == 'true' }}
shell: 'bash'
working-directory: '${{ inputs.working-directory }}'
run: |
echo "Dry run: Would have added tag '${INPUTS_CHANNEL}' to version '${INPUTS_VERSION}' for ${INPUTS_CLI_PACKAGE_NAME}, ${INPUTS_CORE_PACKAGE_NAME}, and ${INPUTS_A2A_PACKAGE_NAME}."
env:
INPUTS_CHANNEL: '${{ inputs.channel }}'
INPUTS_VERSION: '${{ inputs.version }}'
INPUTS_CLI_PACKAGE_NAME: '${{ inputs.cli-package-name }}'
INPUTS_CORE_PACKAGE_NAME: '${{ inputs.core-package-name }}'
INPUTS_A2A_PACKAGE_NAME: '${{ inputs.a2a-package-name }}'
================================================
FILE: .github/actions/verify-release/action.yml
================================================
name: 'Verify an NPM release'
description: 'Fetches a package from NPM and does some basic smoke tests'
inputs:
npm-package:
description: 'NPM Package'
required: true
default: '@google/gemini-cli@latest'
npm-registry-url:
description: 'NPM Registry URL'
required: true
npm-registry-scope:
description: 'NPM Registry Scope'
required: true
expected-version:
description: 'Expected version'
required: true
gemini_api_key:
description: 'The API key for running integration tests.'
required: true
github-token:
description: 'The GitHub token for running integration tests.'
required: true
working-directory:
description: 'The working directory to run the tests in.'
required: false
default: '.'
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'setup node'
uses: 'actions/setup-node@v4'
with:
node-version: '20'
- name: 'configure .npmrc'
uses: './.github/actions/setup-npmrc'
with:
github-token: '${{ inputs.github-token }}'
- name: 'Clear npm cache'
shell: 'bash'
run: 'npm cache clean --force'
- name: 'Install from NPM'
uses: 'nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08' # ratchet:nick-fields/retry@v3
with:
timeout_seconds: 900
retry_wait_seconds: 30
max_attempts: 10
command: |-
cd ${{ inputs.working-directory }}
npm install --prefer-online --no-cache -g "${{ inputs.npm-package }}"
- name: 'Smoke test - NPM Install'
shell: 'bash'
working-directory: '${{ inputs.working-directory }}'
run: |-
gemini_version=$(gemini --version)
if [ "$gemini_version" != "${INPUTS_EXPECTED_VERSION}" ]; then
echo "❌ NPM Version mismatch: Got $gemini_version from ${INPUTS_NPM_PACKAGE}, expected ${INPUTS_EXPECTED_VERSION}"
exit 1
fi
env:
INPUTS_EXPECTED_VERSION: '${{ inputs.expected-version }}'
INPUTS_NPM_PACKAGE: '${{ inputs.npm-package }}'
- name: 'Clear npm cache'
shell: 'bash'
run: 'npm cache clean --force'
- name: 'Smoke test - NPX Run'
shell: 'bash'
working-directory: '${{ inputs.working-directory }}'
run: |-
gemini_version=$(npx --prefer-online "${INPUTS_NPM_PACKAGE}" --version)
if [ "$gemini_version" != "${INPUTS_EXPECTED_VERSION}" ]; then
echo "❌ NPX Run Version mismatch: Got $gemini_version from ${INPUTS_NPM_PACKAGE}, expected ${INPUTS_EXPECTED_VERSION}"
exit 1
fi
env:
INPUTS_NPM_PACKAGE: '${{ inputs.npm-package }}'
INPUTS_EXPECTED_VERSION: '${{ inputs.expected-version }}'
- name: 'Install dependencies for integration tests'
shell: 'bash'
working-directory: '${{ inputs.working-directory }}'
run: 'npm ci'
- name: '🔬 Run integration tests against NPM release'
working-directory: '${{ inputs.working-directory }}'
env:
GEMINI_API_KEY: '${{ inputs.gemini_api_key }}'
INTEGRATION_TEST_USE_INSTALLED_GEMINI: 'true'
# We must diable CI mode here because it interferes with interactive tests.
# See https://github.com/google-gemini/gemini-cli/issues/10517
CI: 'false'
shell: 'bash'
run: 'npm run test:integration:sandbox:none'
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
day: 'monday'
open-pull-requests-limit: 10
reviewers:
- 'joshualitt'
groups:
npm-dependencies:
patterns:
- '*'
update-types:
- 'minor'
- 'patch'
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'
day: 'monday'
open-pull-requests-limit: 10
reviewers:
- 'joshualitt'
groups:
actions-dependencies:
patterns:
- '*'
update-types:
- 'minor'
- 'patch'
================================================
FILE: .github/pull_request_template.md
================================================
## Summary
<!-- Concisely describe what this PR changes and why. Focus on impact and
urgency. -->
## Details
<!-- Add any extra context and design decisions. Keep it brief but complete. -->
## Related Issues
<!-- Use keywords to auto-close issues (Closes #123, Fixes #456). If this PR is
only related to an issue or is a partial fix, simply reference the issue number
without a keyword (Related to #123). -->
## How to Validate
<!-- List exact steps for reviewers to validate the change. Include commands,
expected results, and edge cases. -->
## Pre-Merge Checklist
<!-- Check all that apply before requesting review or merging. -->
- [ ] Updated relevant documentation and README (if needed)
- [ ] Added/updated tests (if needed)
- [ ] Noted breaking changes (if any)
- [ ] Validated on required platforms/methods:
- [ ] MacOS
- [ ] npm run
- [ ] npx
- [ ] Docker
- [ ] Podman
- [ ] Seatbelt
- [ ] Windows
- [ ] npm run
- [ ] npx
- [ ] Docker
- [ ] Linux
- [ ] npm run
- [ ] npx
- [ ] Docker
================================================
FILE: .github/scripts/backfill-need-triage.cjs
================================================
/* eslint-disable */
/* global require, console, process */
/**
* Script to backfill the 'status/need-triage' label to all open issues
* that are NOT currently labeled with '🔒 maintainer only' or 'help wanted'.
*/
const { execFileSync } = require('child_process');
const isDryRun = process.argv.includes('--dry-run');
const REPO = 'google-gemini/gemini-cli';
/**
* Executes a GitHub CLI command safely using an argument array to prevent command injection.
* @param {string[]} args
* @returns {string|null}
*/
function runGh(args) {
try {
// Using execFileSync with an array of arguments is safe as it doesn't use a shell.
// We set a large maxBuffer (10MB) to handle repositories with many issues.
return execFileSync('gh', args, {
encoding: 'utf8',
maxBuffer: 10 * 1024 * 1024,
stdio: ['ignore', 'pipe', 'pipe'],
}).trim();
} catch (error) {
const stderr = error.stderr ? ` Stderr: ${error.stderr.trim()}` : '';
console.error(
`❌ Error running gh ${args.join(' ')}: ${error.message}${stderr}`,
);
return null;
}
}
async function main() {
console.log('🔐 GitHub CLI security check...');
const authStatus = runGh(['auth', 'status']);
if (authStatus === null) {
console.error('❌ GitHub CLI (gh) is not installed or not authenticated.');
process.exit(1);
}
if (isDryRun) {
console.log('🧪 DRY RUN MODE ENABLED - No changes will be made.\n');
}
console.log(`🔍 Fetching and filtering open issues from ${REPO}...`);
// We use the /issues endpoint with pagination to bypass the 1000-result limit.
// The jq filter ensures we exclude PRs, maintainer-only, help-wanted, and existing status/need-triage.
const jqFilter =
'.[] | select(.pull_request == null) | select([.labels[].name] as $l | (any($l[]; . == "🔒 maintainer only") | not) and (any($l[]; . == "help wanted") | not) and (any($l[]; . == "status/need-triage") | not)) | {number: .number, title: .title}';
const output = runGh([
'api',
`repos/${REPO}/issues?state=open&per_page=100`,
'--paginate',
'--jq',
jqFilter,
]);
if (output === null) {
process.exit(1);
}
const issues = output
.split('\n')
.filter((line) => line.trim())
.map((line) => {
try {
return JSON.parse(line);
} catch (_e) {
console.error(`⚠️ Failed to parse line: ${line}`);
return null;
}
})
.filter(Boolean);
console.log(`✅ Found ${issues.length} issues matching criteria.`);
if (issues.length === 0) {
console.log('✨ No issues need backfilling.');
return;
}
let successCount = 0;
let failCount = 0;
if (isDryRun) {
for (const issue of issues) {
console.log(
`[DRY RUN] Would label issue #${issue.number}: ${issue.title}`,
);
}
successCount = issues.length;
} else {
console.log(`🏷️ Applying labels to ${issues.length} issues...`);
for (const issue of issues) {
const issueNumber = String(issue.number);
console.log(`🏷️ Labeling issue #${issueNumber}: ${issue.title}`);
const result = runGh([
'issue',
'edit',
issueNumber,
'--add-label',
'status/need-triage',
'--repo',
REPO,
]);
if (result !== null) {
successCount++;
} else {
failCount++;
}
}
}
console.log(`\n📊 Summary:`);
console.log(` - Success: ${successCount}`);
console.log(` - Failed: ${failCount}`);
if (failCount > 0) {
console.error(`\n❌ Backfill completed with ${failCount} errors.`);
process.exit(1);
} else {
console.log(`\n🎉 ${isDryRun ? 'Dry run' : 'Backfill'} complete!`);
}
}
main().catch((error) => {
console.error('❌ Unexpected error:', error);
process.exit(1);
});
================================================
FILE: .github/scripts/backfill-pr-notification.cjs
================================================
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/* eslint-disable */
/* global require, console, process */
/**
* Script to backfill a process change notification comment to all open PRs
* not created by members of the 'gemini-cli-maintainers' team.
*
* Skip PRs that are already associated with an issue.
*/
const { execFileSync } = require('child_process');
const isDryRun = process.argv.includes('--dry-run');
const REPO = 'google-gemini/gemini-cli';
const ORG = 'google-gemini';
const TEAM_SLUG = 'gemini-cli-maintainers';
const DISCUSSION_URL =
'https://github.com/google-gemini/gemini-cli/discussions/16706';
/**
* Executes a GitHub CLI command safely using an argument array.
*/
function runGh(args, options = {}) {
const { silent = false } = options;
try {
return execFileSync('gh', args, {
encoding: 'utf8',
maxBuffer: 10 * 1024 * 1024,
stdio: ['ignore', 'pipe', 'pipe'],
}).trim();
} catch (error) {
if (!silent) {
const stderr = error.stderr ? ` Stderr: ${error.stderr.trim()}` : '';
console.error(
`❌ Error running gh ${args.join(' ')}: ${error.message}${stderr}`,
);
}
return null;
}
}
/**
* Checks if a user is a member of the maintainers team.
*/
const membershipCache = new Map();
function isMaintainer(username) {
if (membershipCache.has(username)) return membershipCache.get(username);
// GitHub returns 404 if user is not a member.
// We use silent: true to avoid logging 404s as errors.
const result = runGh(
['api', `orgs/${ORG}/teams/${TEAM_SLUG}/memberships/${username}`],
{ silent: true },
);
const isMember = result !== null;
membershipCache.set(username, isMember);
return isMember;
}
async function main() {
console.log('🔐 GitHub CLI security check...');
if (runGh(['auth', 'status']) === null) {
console.error('❌ GitHub CLI (gh) is not authenticated.');
process.exit(1);
}
if (isDryRun) {
console.log('🧪 DRY RUN MODE ENABLED\n');
}
console.log(`📥 Fetching open PRs from ${REPO}...`);
// Fetch number, author, and closingIssuesReferences to check if linked to an issue
const prsJson = runGh([
'pr',
'list',
'--repo',
REPO,
'--state',
'open',
'--limit',
'1000',
'--json',
'number,author,closingIssuesReferences',
]);
if (prsJson === null) process.exit(1);
const prs = JSON.parse(prsJson);
console.log(`📊 Found ${prs.length} open PRs. Filtering...`);
let targetPrs = [];
for (const pr of prs) {
const author = pr.author.login;
const issueCount = pr.closingIssuesReferences
? pr.closingIssuesReferences.length
: 0;
if (issueCount > 0) {
// Skip if already linked to an issue
continue;
}
if (!isMaintainer(author)) {
targetPrs.push(pr);
}
}
console.log(
`✅ Found ${targetPrs.length} PRs from non-maintainers without associated issues.`,
);
const commentBody =
"\nHi @{AUTHOR}, thank you so much for your contribution to Gemini CLI! We really appreciate the time and effort you've put into this.\n\nWe're making some updates to our contribution process to improve how we track and review changes. Please take a moment to review our recent discussion post: [Improving Our Contribution Process & Introducing New Guidelines](${DISCUSSION_URL}).\n\nKey Update: Starting **January 26, 2026**, the Gemini CLI project will require all pull requests to be associated with an existing issue. Any pull requests not linked to an issue by that date will be automatically closed.\n\nThank you for your understanding and for being a part of our community!\n ".trim();
let successCount = 0;
let skipCount = 0;
let failCount = 0;
for (const pr of targetPrs) {
const prNumber = String(pr.number);
const author = pr.author.login;
// Check if we already commented (idempotency)
// We use silent: true here because view might fail if PR is deleted mid-run
const existingComments = runGh(
[
'pr',
'view',
prNumber,
'--repo',
REPO,
'--json',
'comments',
'--jq',
`.comments[].body | contains("${DISCUSSION_URL}")`,
],
{ silent: true },
);
if (existingComments && existingComments.includes('true')) {
console.log(
`⏭️ PR #${prNumber} already has the notification. Skipping.`,
);
skipCount++;
continue;
}
if (isDryRun) {
console.log(`[DRY RUN] Would notify @${author} on PR #${prNumber}`);
successCount++;
} else {
console.log(`💬 Notifying @${author} on PR #${prNumber}...`);
const personalizedComment = commentBody.replace('{AUTHOR}', author);
const result = runGh([
'pr',
'comment',
prNumber,
'--repo',
REPO,
'--body',
personalizedComment,
]);
if (result !== null) {
successCount++;
} else {
failCount++;
}
}
}
console.log(`\n📊 Summary:`);
console.log(` - Notified: ${successCount}`);
console.log(` - Skipped: ${skipCount}`);
console.log(` - Failed: ${failCount}`);
if (failCount > 0) process.exit(1);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
================================================
FILE: .github/scripts/pr-triage.sh
================================================
#!/usr/bin/env bash
# @license
# Copyright 2026 Google LLC
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
# Initialize a comma-separated string to hold PR numbers that need a comment
PRS_NEEDING_COMMENT=""
# Global cache for issue labels (compatible with Bash 3.2)
# Stores "|ISSUE_NUM:LABELS|" segments
ISSUE_LABELS_CACHE_FLAT="|"
# Function to get labels from an issue (with caching)
get_issue_labels() {
local ISSUE_NUM="${1}"
if [[ -z "${ISSUE_NUM}" || "${ISSUE_NUM}" == "null" || "${ISSUE_NUM}" == "" ]]; then
return
fi
# Check cache
case "${ISSUE_LABELS_CACHE_FLAT}" in
*"|${ISSUE_NUM}:"*)
local suffix="${ISSUE_LABELS_CACHE_FLAT#*|"${ISSUE_NUM}":}"
echo "${suffix%%|*}"
return
;;
*)
# Cache miss, proceed to fetch
;;
esac
echo " 📥 Fetching labels from issue #${ISSUE_NUM}" >&2
local gh_output
if ! gh_output=$(gh issue view "${ISSUE_NUM}" --repo "${GITHUB_REPOSITORY}" --json labels -q '.labels[].name' 2>/dev/null); then
echo " ⚠️ Could not fetch issue #${ISSUE_NUM}" >&2
ISSUE_LABELS_CACHE_FLAT="${ISSUE_LABELS_CACHE_FLAT}${ISSUE_NUM}:|"
return
fi
local labels
labels=$(echo "${gh_output}" | grep -x -E '(area|priority)/.*|help wanted|🔒 maintainer only' | tr '\n' ',' | sed 's/,$//' || echo "")
# Save to flat cache
ISSUE_LABELS_CACHE_FLAT="${ISSUE_LABELS_CACHE_FLAT}${ISSUE_NUM}:${labels}|"
echo "${labels}"
}
# Function to process a single PR with pre-fetched data
process_pr_optimized() {
local PR_NUMBER="${1}"
local IS_DRAFT="${2}"
local ISSUE_NUMBER="${3}"
local CURRENT_LABELS="${4}" # Comma-separated labels
echo "🔄 Processing PR #${PR_NUMBER}"
local LABELS_TO_ADD=""
local LABELS_TO_REMOVE=""
if [[ -z "${ISSUE_NUMBER}" || "${ISSUE_NUMBER}" == "null" || "${ISSUE_NUMBER}" == "" ]]; then
if [[ "${IS_DRAFT}" == "true" ]]; then
echo " 📝 PR #${PR_NUMBER} is a draft and has no linked issue"
if [[ ",${CURRENT_LABELS}," == *",status/need-issue,"* ]]; then
echo " ➖ Removing status/need-issue label"
LABELS_TO_REMOVE="status/need-issue"
fi
else
echo " ⚠️ No linked issue found for PR #${PR_NUMBER}"
if [[ ",${CURRENT_LABELS}," != *",status/need-issue,"* ]]; then
echo " ➕ Adding status/need-issue label"
LABELS_TO_ADD="status/need-issue"
fi
if [[ -z "${PRS_NEEDING_COMMENT}" ]]; then
PRS_NEEDING_COMMENT="${PR_NUMBER}"
else
PRS_NEEDING_COMMENT="${PRS_NEEDING_COMMENT},${PR_NUMBER}"
fi
fi
else
echo " 🔗 Found linked issue #${ISSUE_NUMBER}"
if [[ ",${CURRENT_LABELS}," == *",status/need-issue,"* ]]; then
echo " ➖ Removing status/need-issue label"
LABELS_TO_REMOVE="status/need-issue"
fi
local ISSUE_LABELS
ISSUE_LABELS=$(get_issue_labels "${ISSUE_NUMBER}")
if [[ -n "${ISSUE_LABELS}" ]]; then
local IFS_OLD="${IFS}"
IFS=','
for label in ${ISSUE_LABELS}; do
if [[ -n "${label}" ]] && [[ ",${CURRENT_LABELS}," != *",${label},"* ]]; then
if [[ -z "${LABELS_TO_ADD}" ]]; then
LABELS_TO_ADD="${label}"
else
LABELS_TO_ADD="${LABELS_TO_ADD},${label}"
fi
fi
done
IFS="${IFS_OLD}"
fi
if [[ -z "${LABELS_TO_ADD}" && -z "${LABELS_TO_REMOVE}" ]]; then
echo " ✅ Labels already synchronized"
fi
fi
if [[ -n "${LABELS_TO_ADD}" || -n "${LABELS_TO_REMOVE}" ]]; then
local EDIT_CMD=("gh" "pr" "edit" "${PR_NUMBER}" "--repo" "${GITHUB_REPOSITORY}")
if [[ -n "${LABELS_TO_ADD}" ]]; then
echo " ➕ Syncing labels to add: ${LABELS_TO_ADD}"
EDIT_CMD+=("--add-label" "${LABELS_TO_ADD}")
fi
if [[ -n "${LABELS_TO_REMOVE}" ]]; then
echo " ➖ Syncing labels to remove: ${LABELS_TO_REMOVE}"
EDIT_CMD+=("--remove-label" "${LABELS_TO_REMOVE}")
fi
("${EDIT_CMD[@]}" || true)
fi
}
if [[ -z "${GITHUB_REPOSITORY:-}" ]]; then
echo "‼️ Missing \$GITHUB_REPOSITORY - this must be run from GitHub Actions"
exit 1
fi
if [[ -z "${GITHUB_OUTPUT:-}" ]]; then
echo "‼️ Missing \$GITHUB_OUTPUT - this must be run from GitHub Actions"
exit 1
fi
JQ_EXTRACT_FIELDS='{
number: .number,
isDraft: .isDraft,
issue: (.closingIssuesReferences[0].number // (.body // "" | capture("(^|[^a-zA-Z0-9])#(?<num>[0-9]+)([^a-zA-Z0-9]|$)")? | .num) // "null"),
labels: [.labels[].name] | join(",")
}'
JQ_TSV_FORMAT='"\((.number | tostring))\t\(.isDraft)\t\((.issue // null) | tostring)\t\(.labels)"'
if [[ -n "${PR_NUMBER:-}" ]]; then
echo "🔄 Processing single PR #${PR_NUMBER}"
PR_DATA=$(gh pr view "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" --json number,closingIssuesReferences,isDraft,body,labels 2>/dev/null) || {
echo "❌ Failed to fetch data for PR #${PR_NUMBER}"
exit 1
}
line=$(echo "${PR_DATA}" | jq -r "${JQ_EXTRACT_FIELDS} | ${JQ_TSV_FORMAT}")
IFS=$'\t' read -r pr_num is_draft issue_num current_labels <<< "${line}"
process_pr_optimized "${pr_num}" "${is_draft}" "${issue_num}" "${current_labels}"
else
echo "📥 Getting all open pull requests..."
PR_DATA_ALL=$(gh pr list --repo "${GITHUB_REPOSITORY}" --state open --limit 1000 --json number,closingIssuesReferences,isDraft,body,labels 2>/dev/null) || {
echo "❌ Failed to fetch PR list"
exit 1
}
PR_COUNT=$(echo "${PR_DATA_ALL}" | jq '. | length')
echo "📊 Found ${PR_COUNT} open PRs to process"
# Use a temporary file to avoid masking exit codes in process substitution
tmp_file=$(mktemp)
echo "${PR_DATA_ALL}" | jq -r ".[] | ${JQ_EXTRACT_FIELDS} | ${JQ_TSV_FORMAT}" > "${tmp_file}"
while read -r line; do
[[ -z "${line}" ]] && continue
IFS=$'\t' read -r pr_num is_draft issue_num current_labels <<< "${line}"
process_pr_optimized "${pr_num}" "${is_draft}" "${issue_num}" "${current_labels}"
done < "${tmp_file}"
rm -f "${tmp_file}"
fi
if [[ -z "${PRS_NEEDING_COMMENT}" ]]; then
echo "prs_needing_comment=[]" >> "${GITHUB_OUTPUT}"
else
echo "prs_needing_comment=[${PRS_NEEDING_COMMENT}]" >> "${GITHUB_OUTPUT}"
fi
echo "✅ PR triage completed"
================================================
FILE: .github/scripts/sync-maintainer-labels.cjs
================================================
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
const { Octokit } = require('@octokit/rest');
/**
* Sync Maintainer Labels (Recursive with strict parent-child relationship detection)
* - Uses Native Sub-issues.
* - Uses Markdown Task Lists (- [ ] #123).
* - Filters for OPEN issues only.
* - Skips DUPLICATES.
* - Skips Pull Requests.
* - ONLY labels issues in the PUBLIC (gemini-cli) repo.
*/
const REPO_OWNER = 'google-gemini';
const PUBLIC_REPO = 'gemini-cli';
const PRIVATE_REPO = 'maintainers-gemini-cli';
const ALLOWED_REPOS = [PUBLIC_REPO, PRIVATE_REPO];
const ROOT_ISSUES = [
{ owner: REPO_OWNER, repo: PUBLIC_REPO, number: 15374 },
{ owner: REPO_OWNER, repo: PUBLIC_REPO, number: 15456 },
{ owner: REPO_OWNER, repo: PUBLIC_REPO, number: 15324 },
];
const TARGET_LABEL = '🔒 maintainer only';
const isDryRun =
process.argv.includes('--dry-run') || process.env.DRY_RUN === 'true';
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN,
});
/**
* Extracts child issue references from markdown Task Lists ONLY.
* e.g. - [ ] #123 or - [x] google-gemini/gemini-cli#123
*/
function extractTaskListLinks(text, contextOwner, contextRepo) {
if (!text) return [];
const childIssues = new Map();
const add = (owner, repo, number) => {
if (ALLOWED_REPOS.includes(repo)) {
const key = `${owner}/${repo}#${number}`;
childIssues.set(key, { owner, repo, number: parseInt(number, 10) });
}
};
// 1. Full URLs in task lists
const urlRegex =
/-\s+\[[ x]\].*https:\/\/github\.com\/([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)\/issues\/(\d+)\b/g;
let match;
while ((match = urlRegex.exec(text)) !== null) {
add(match[1], match[2], match[3]);
}
// 2. Cross-repo refs in task lists: owner/repo#123
const crossRepoRegex =
/-\s+\[[ x]\].*([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)#(\d+)\b/g;
while ((match = crossRepoRegex.exec(text)) !== null) {
add(match[1], match[2], match[3]);
}
// 3. Short refs in task lists: #123
const shortRefRegex = /-\s+\[[ x]\].*#(\d+)\b/g;
while ((match = shortRefRegex.exec(text)) !== null) {
add(contextOwner, contextRepo, match[1]);
}
return Array.from(childIssues.values());
}
/**
* Fetches issue data via GraphQL with full pagination for sub-issues, comments, and labels.
*/
async function fetchIssueData(owner, repo, number) {
const query = `
query($owner:String!, $repo:String!, $number:Int!) {
repository(owner:$owner, name:$repo) {
issue(number:$number) {
state
title
body
labels(first: 100) {
nodes { name }
pageInfo { hasNextPage endCursor }
}
subIssues(first: 100) {
nodes {
number
repository {
name
owner { login }
}
}
pageInfo { hasNextPage endCursor }
}
comments(first: 100) {
nodes {
body
}
}
}
}
}
`;
try {
const response = await octokit.graphql(query, { owner, repo, number });
const data = response.repository.issue;
if (!data) return null;
const issue = {
state: data.state,
title: data.title,
body: data.body || '',
labels: data.labels.nodes.map((n) => n.name),
subIssues: [...data.subIssues.nodes],
comments: data.comments.nodes.map((n) => n.body),
};
// Paginate subIssues if there are more than 100
if (data.subIssues.pageInfo.hasNextPage) {
const moreSubIssues = await paginateConnection(
owner,
repo,
number,
'subIssues',
'number repository { name owner { login } }',
data.subIssues.pageInfo.endCursor,
);
issue.subIssues.push(...moreSubIssues);
}
// Paginate labels if there are more than 100 (unlikely but for completeness)
if (data.labels.pageInfo.hasNextPage) {
const moreLabels = await paginateConnection(
owner,
repo,
number,
'labels',
'name',
data.labels.pageInfo.endCursor,
(n) => n.name,
);
issue.labels.push(...moreLabels);
}
// Note: Comments are handled via Task Lists in body + first 100 comments.
// If an issue has > 100 comments with task lists, we'd need to paginate those too.
// Given the 1,100+ issue discovery count, 100 comments is usually sufficient,
// but we can add it for absolute completeness.
// (Skipping for now to avoid excessive API churn unless clearly needed).
return issue;
} catch (error) {
if (error.errors && error.errors.some((e) => e.type === 'NOT_FOUND')) {
return null;
}
throw error;
}
}
/**
* Helper to paginate any GraphQL connection.
*/
async function paginateConnection(
owner,
repo,
number,
connectionName,
nodeFields,
initialCursor,
transformNode = (n) => n,
) {
let additionalNodes = [];
let hasNext = true;
let cursor = initialCursor;
while (hasNext) {
const query = `
query($owner:String!, $repo:String!, $number:Int!, $cursor:String) {
repository(owner:$owner, name:$repo) {
issue(number:$number) {
${connectionName}(first: 100, after: $cursor) {
nodes { ${nodeFields} }
pageInfo { hasNextPage endCursor }
}
}
}
}
`;
const response = await octokit.graphql(query, {
owner,
repo,
number,
cursor,
});
const connection = response.repository.issue[connectionName];
additionalNodes.push(...connection.nodes.map(transformNode));
hasNext = connection.pageInfo.hasNextPage;
cursor = connection.pageInfo.endCursor;
}
return additionalNodes;
}
/**
* Validates if an issue should be processed (Open, not a duplicate, not a PR)
*/
function shouldProcess(issueData) {
if (!issueData) return false;
if (issueData.state !== 'OPEN') return false;
const labels = issueData.labels.map((l) => l.toLowerCase());
if (labels.includes('duplicate') || labels.includes('kind/duplicate')) {
return false;
}
return true;
}
async function getAllDescendants(roots) {
const allDescendants = new Map();
const visited = new Set();
const queue = [...roots];
for (const root of roots) {
visited.add(`${root.owner}/${root.repo}#${root.number}`);
}
console.log(`Starting discovery from ${roots.length} roots...`);
while (queue.length > 0) {
const current = queue.shift();
const currentKey = `${current.owner}/${current.repo}#${current.number}`;
try {
const issueData = await fetchIssueData(
current.owner,
current.repo,
current.number,
);
if (!shouldProcess(issueData)) {
continue;
}
// ONLY add to labeling list if it's in the PUBLIC repository
if (current.repo === PUBLIC_REPO) {
// Don't label the roots themselves
if (
!ROOT_ISSUES.some(
(r) => r.number === current.number && r.repo === current.repo,
)
) {
allDescendants.set(currentKey, {
...current,
title: issueData.title,
labels: issueData.labels,
});
}
}
const children = new Map();
// 1. Process Native Sub-issues
if (issueData.subIssues) {
for (const node of issueData.subIssues) {
const childOwner = node.repository.owner.login;
const childRepo = node.repository.name;
const childNumber = node.number;
const key = `${childOwner}/${childRepo}#${childNumber}`;
children.set(key, {
owner: childOwner,
repo: childRepo,
number: childNumber,
});
}
}
// 2. Process Markdown Task Lists in Body and Comments
let combinedText = issueData.body || '';
if (issueData.comments) {
for (const commentBody of issueData.comments) {
combinedText += '\n' + (commentBody || '');
}
}
const taskListLinks = extractTaskListLinks(
combinedText,
current.owner,
current.repo,
);
for (const link of taskListLinks) {
const key = `${link.owner}/${link.repo}#${link.number}`;
children.set(key, link);
}
// Queue children (regardless of which repo they are in, for recursion)
for (const [key, child] of children) {
if (!visited.has(key)) {
visited.add(key);
queue.push(child);
}
}
} catch (error) {
console.error(`Error processing ${currentKey}: ${error.message}`);
}
}
return Array.from(allDescendants.values());
}
async function run() {
if (isDryRun) {
console.log('=== DRY RUN MODE: No labels will be applied ===');
}
const descendants = await getAllDescendants(ROOT_ISSUES);
console.log(
`\nFound ${descendants.length} total unique open descendant issues in ${PUBLIC_REPO}.`,
);
for (const issueInfo of descendants) {
const issueKey = `${issueInfo.owner}/${issueInfo.repo}#${issueInfo.number}`;
try {
// Data is already available from the discovery phase
const hasLabel = issueInfo.labels.some((l) => l === TARGET_LABEL);
if (!hasLabel) {
if (isDryRun) {
console.log(
`[DRY RUN] Would label ${issueKey}: "${issueInfo.title}"`,
);
} else {
console.log(`Labeling ${issueKey}: "${issueInfo.title}"...`);
await octokit.rest.issues.addLabels({
owner: issueInfo.owner,
repo: issueInfo.repo,
issue_number: issueInfo.number,
labels: [TARGET_LABEL],
});
}
}
// Remove status/need-triage from maintainer-only issues since they
// don't need community triage. We always attempt removal rather than
// checking the (potentially stale) label snapshot, because the
// issue-opened-labeler workflow runs concurrently and may add the
// label after our snapshot was taken.
if (isDryRun) {
console.log(
`[DRY RUN] Would remove status/need-triage from ${issueKey}`,
);
} else {
try {
await octokit.rest.issues.removeLabel({
owner: issueInfo.owner,
repo: issueInfo.repo,
issue_number: issueInfo.number,
name: 'status/need-triage',
});
console.log(`Removed status/need-triage from ${issueKey}`);
} catch (removeError) {
// 404 means the label wasn't present — that's fine.
if (removeError.status === 404) {
console.log(
`status/need-triage not present on ${issueKey}, skipping.`,
);
} else {
throw removeError;
}
}
}
} catch (error) {
console.error(`Error processing label for ${issueKey}: ${error.message}`);
}
}
}
run().catch((error) => {
console.error(error);
process.exit(1);
});
================================================
FILE: .github/workflows/chained_e2e.yml
================================================
name: 'Testing: E2E (Chained)'
on:
push:
branches:
- 'main'
merge_group:
workflow_run:
workflows: ['Trigger E2E']
types: ['completed']
workflow_dispatch:
inputs:
head_sha:
description: 'SHA of the commit to test'
required: true
repo_name:
description: 'Repository name (e.g., owner/repo)'
required: true
concurrency:
group: '${{ github.workflow }}-${{ github.head_ref || github.event.workflow_run.head_branch || github.ref }}'
cancel-in-progress: |-
${{ github.event_name != 'push' && github.event_name != 'merge_group' }}
permissions:
contents: 'read'
statuses: 'write'
jobs:
merge_queue_skipper:
name: 'Merge Queue Skipper'
permissions: 'read-all'
runs-on: 'gemini-cli-ubuntu-16-core'
if: "github.repository == 'google-gemini/gemini-cli'"
outputs:
skip: '${{ steps.merge-queue-e2e-skipper.outputs.skip-check }}'
steps:
- id: 'merge-queue-e2e-skipper'
uses: 'cariad-tech/merge-queue-ci-skipper@1032489e59437862c90a08a2c92809c903883772' # ratchet:cariad-tech/merge-queue-ci-skipper@main
with:
secret: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
continue-on-error: true
download_repo_name:
runs-on: 'gemini-cli-ubuntu-16-core'
if: "github.repository == 'google-gemini/gemini-cli' && (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_run')"
outputs:
repo_name: '${{ steps.output-repo-name.outputs.repo_name }}'
head_sha: '${{ steps.output-repo-name.outputs.head_sha }}'
steps:
- name: 'Mock Repo Artifact'
if: "${{ github.event_name == 'workflow_dispatch' }}"
env:
REPO_NAME: '${{ github.event.inputs.repo_name }}'
run: |
mkdir -p ./pr
echo "${REPO_NAME}" > ./pr/repo_name
- uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
with:
name: 'repo_name'
path: 'pr/'
- name: 'Download the repo_name artifact'
uses: 'actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0' # ratchet:actions/download-artifact@v5
env:
RUN_ID: "${{ github.event_name == 'workflow_run' && github.event.workflow_run.id || github.run_id }}"
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
name: 'repo_name'
run-id: '${{ env.RUN_ID }}'
path: '${{ runner.temp }}/artifacts'
- name: 'Output Repo Name and SHA'
id: 'output-repo-name'
uses: 'actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd' # ratchet:actions/github-script@v8
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
script: |
const fs = require('fs');
const path = require('path');
const temp = '${{ runner.temp }}/artifacts';
const repoPath = path.join(temp, 'repo_name');
if (fs.existsSync(repoPath)) {
const repo_name = String(fs.readFileSync(repoPath)).trim();
core.setOutput('repo_name', repo_name);
}
const shaPath = path.join(temp, 'head_sha');
if (fs.existsSync(shaPath)) {
const head_sha = String(fs.readFileSync(shaPath)).trim();
core.setOutput('head_sha', head_sha);
}
parse_run_context:
name: 'Parse run context'
runs-on: 'gemini-cli-ubuntu-16-core'
needs: 'download_repo_name'
if: "github.repository == 'google-gemini/gemini-cli' && always()"
outputs:
repository: '${{ steps.set_context.outputs.REPO }}'
sha: '${{ steps.set_context.outputs.SHA }}'
steps:
- id: 'set_context'
name: 'Set dynamic repository and SHA'
env:
REPO: '${{ needs.download_repo_name.outputs.repo_name || github.repository }}'
SHA: '${{ needs.download_repo_name.outputs.head_sha || github.event.inputs.head_sha || github.event.workflow_run.head_sha || github.sha }}'
shell: 'bash'
run: |
echo "REPO=$REPO" >> "$GITHUB_OUTPUT"
echo "SHA=$SHA" >> "$GITHUB_OUTPUT"
set_pending_status:
runs-on: 'gemini-cli-ubuntu-16-core'
permissions: 'write-all'
needs:
- 'parse_run_context'
if: "github.repository == 'google-gemini/gemini-cli' && always()"
steps:
- name: 'Set pending status'
uses: 'myrotvorets/set-commit-status-action@16037e056d73b2d3c88e37e393ff369047f70886' # ratchet:myrotvorets/set-commit-status-action@master
if: "github.repository == 'google-gemini/gemini-cli' && always()"
with:
allowForks: 'true'
repo: '${{ github.repository }}'
sha: '${{ needs.parse_run_context.outputs.sha }}'
token: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
status: 'pending'
context: 'E2E (Chained)'
e2e_linux:
name: 'E2E Test (Linux) - ${{ matrix.sandbox }}'
needs:
- 'merge_queue_skipper'
- 'parse_run_context'
runs-on: 'gemini-cli-ubuntu-16-core'
if: |
github.repository == 'google-gemini/gemini-cli' && always() && (needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip != 'true')
strategy:
fail-fast: false
matrix:
sandbox:
- 'sandbox:none'
- 'sandbox:docker'
node-version:
- '20.x'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
with:
ref: '${{ needs.parse_run_context.outputs.sha }}'
repository: '${{ needs.parse_run_context.outputs.repository }}'
- name: 'Set up Node.js ${{ matrix.node-version }}'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
with:
node-version: '${{ matrix.node-version }}'
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Build project'
run: 'npm run build'
- name: 'Set up Docker'
if: "${{matrix.sandbox == 'sandbox:docker'}}"
uses: 'docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435' # ratchet:docker/setup-buildx-action@v3
- name: 'Run E2E tests'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
KEEP_OUTPUT: 'true'
VERBOSE: 'true'
BUILD_SANDBOX_FLAGS: '--cache-from type=gha --cache-to type=gha,mode=max'
shell: 'bash'
run: |
if [[ "${{ matrix.sandbox }}" == "sandbox:docker" ]]; then
npm run test:integration:sandbox:docker
else
npm run test:integration:sandbox:none
fi
e2e_mac:
name: 'E2E Test (macOS)'
needs:
- 'merge_queue_skipper'
- 'parse_run_context'
runs-on: 'macos-latest'
if: |
github.repository == 'google-gemini/gemini-cli' && always() && (needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip != 'true')
steps:
- name: 'Checkout'
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
with:
ref: '${{ needs.parse_run_context.outputs.sha }}'
repository: '${{ needs.parse_run_context.outputs.repository }}'
- name: 'Set up Node.js 20.x'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
with:
node-version: '20.x'
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Build project'
run: 'npm run build'
- name: 'Fix rollup optional dependencies on macOS'
if: "${{runner.os == 'macOS'}}"
run: |
npm cache clean --force
- name: 'Run E2E tests (non-Windows)'
if: "${{runner.os != 'Windows'}}"
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
KEEP_OUTPUT: 'true'
SANDBOX: 'sandbox:none'
VERBOSE: 'true'
run: 'npm run test:integration:sandbox:none'
e2e_windows:
name: 'Slow E2E - Win'
needs:
- 'merge_queue_skipper'
- 'parse_run_context'
if: |
github.repository == 'google-gemini/gemini-cli' && always() && (needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip != 'true')
runs-on: 'gemini-cli-windows-16-core'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
with:
ref: '${{ needs.parse_run_context.outputs.sha }}'
repository: '${{ needs.parse_run_context.outputs.repository }}'
- name: 'Set up Node.js 20.x'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: 'Configure Windows Defender exclusions'
run: |
Add-MpPreference -ExclusionPath $env:GITHUB_WORKSPACE -Force
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\node_modules" -Force
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\packages" -Force
Add-MpPreference -ExclusionPath "$env:TEMP" -Force
shell: 'pwsh'
- name: 'Configure npm for Windows performance'
run: |
npm config set progress false
npm config set audit false
npm config set fund false
npm config set loglevel error
npm config set maxsockets 32
npm config set registry https://registry.npmjs.org/
shell: 'pwsh'
- name: 'Install dependencies'
run: 'npm ci'
shell: 'pwsh'
- name: 'Build project'
run: 'npm run build'
shell: 'pwsh'
- name: 'Ensure Chrome is available'
shell: 'pwsh'
run: |
$chromePaths = @(
"${env:ProgramFiles}\Google\Chrome\Application\chrome.exe",
"${env:ProgramFiles(x86)}\Google\Chrome\Application\chrome.exe"
)
$chromeExists = $chromePaths | Where-Object { Test-Path $_ } | Select-Object -First 1
if (-not $chromeExists) {
Write-Host 'Chrome not found, installing via Chocolatey...'
choco install googlechrome -y --no-progress --ignore-checksums
}
$installed = $chromePaths | Where-Object { Test-Path $_ } | Select-Object -First 1
if ($installed) {
Write-Host "Chrome found at: $installed"
& $installed --version
} else {
Write-Error 'Chrome installation failed'
exit 1
}
- name: 'Run E2E tests'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
KEEP_OUTPUT: 'true'
SANDBOX: 'sandbox:none'
VERBOSE: 'true'
NODE_OPTIONS: '--max-old-space-size=32768 --max-semi-space-size=256'
UV_THREADPOOL_SIZE: '32'
NODE_ENV: 'test'
shell: 'pwsh'
run: 'npm run test:integration:sandbox:none'
evals:
name: 'Evals (ALWAYS_PASSING)'
needs:
- 'merge_queue_skipper'
- 'parse_run_context'
runs-on: 'gemini-cli-ubuntu-16-core'
if: |
github.repository == 'google-gemini/gemini-cli' && always() && (needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip != 'true')
steps:
- name: 'Checkout'
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
with:
ref: '${{ needs.parse_run_context.outputs.sha }}'
repository: '${{ needs.parse_run_context.outputs.repository }}'
fetch-depth: 0
- name: 'Set up Node.js 20.x'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
with:
node-version: '20.x'
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Build project'
run: 'npm run build'
- name: 'Check if evals should run'
id: 'check_evals'
run: |
SHOULD_RUN=$(node scripts/changed_prompt.js)
echo "should_run=$SHOULD_RUN" >> "$GITHUB_OUTPUT"
- name: 'Run Evals (Required to pass)'
if: "${{ steps.check_evals.outputs.should_run == 'true' }}"
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
run: 'npm run test:always_passing_evals'
e2e:
name: 'E2E'
if: |
github.repository == 'google-gemini/gemini-cli' && always() && (needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip != 'true')
needs:
- 'e2e_linux'
- 'e2e_mac'
- 'e2e_windows'
- 'evals'
- 'merge_queue_skipper'
runs-on: 'gemini-cli-ubuntu-16-core'
steps:
- name: 'Check E2E test results'
run: |
if [[ ${NEEDS_E2E_LINUX_RESULT} != 'success' || \
${NEEDS_E2E_MAC_RESULT} != 'success' || \
${NEEDS_E2E_WINDOWS_RESULT} != 'success' || \
${NEEDS_EVALS_RESULT} != 'success' ]]; then
echo "One or more E2E jobs failed."
exit 1
fi
echo "All required E2E jobs passed!"
env:
NEEDS_E2E_LINUX_RESULT: '${{ needs.e2e_linux.result }}'
NEEDS_E2E_MAC_RESULT: '${{ needs.e2e_mac.result }}'
NEEDS_E2E_WINDOWS_RESULT: '${{ needs.e2e_windows.result }}'
NEEDS_EVALS_RESULT: '${{ needs.evals.result }}'
set_workflow_status:
runs-on: 'gemini-cli-ubuntu-16-core'
permissions: 'write-all'
if: "github.repository == 'google-gemini/gemini-cli' && always()"
needs:
- 'parse_run_context'
- 'e2e'
steps:
- name: 'Set workflow status'
uses: 'myrotvorets/set-commit-status-action@16037e056d73b2d3c88e37e393ff369047f70886' # ratchet:myrotvorets/set-commit-status-action@master
if: "github.repository == 'google-gemini/gemini-cli' && always()"
with:
allowForks: 'true'
repo: '${{ github.repository }}'
sha: '${{ needs.parse_run_context.outputs.sha }}'
token: '${{ secrets.GITHUB_TOKEN }}'
status: '${{ needs.e2e.result }}'
context: 'E2E (Chained)'
================================================
FILE: .github/workflows/ci.yml
================================================
name: 'Testing: CI'
on:
push:
branches:
- 'main'
- 'release/**'
pull_request:
branches:
- 'main'
- 'release/**'
merge_group:
workflow_dispatch:
inputs:
branch_ref:
description: 'Branch to run on'
required: true
default: 'main'
type: 'string'
concurrency:
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
cancel-in-progress: |-
${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/heads/release/') }}
permissions:
checks: 'write'
contents: 'read'
statuses: 'write'
defaults:
run:
shell: 'bash'
jobs:
merge_queue_skipper:
permissions: 'read-all'
name: 'Merge Queue Skipper'
runs-on: 'gemini-cli-ubuntu-16-core'
if: "github.repository == 'google-gemini/gemini-cli'"
outputs:
skip: '${{ steps.merge-queue-ci-skipper.outputs.skip-check }}'
steps:
- id: 'merge-queue-ci-skipper'
uses: 'cariad-tech/merge-queue-ci-skipper@1032489e59437862c90a08a2c92809c903883772' # ratchet:cariad-tech/merge-queue-ci-skipper@main
with:
secret: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
lint:
name: 'Lint'
runs-on: 'gemini-cli-ubuntu-16-core'
needs: 'merge_queue_skipper'
if: "github.repository == 'google-gemini/gemini-cli' && needs.merge_queue_skipper.outputs.skip == 'false'"
env:
GEMINI_LINT_TEMP_DIR: '${{ github.workspace }}/.gemini-linters'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
fetch-depth: 0
- name: 'Set up Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4.4.0
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Cache Linters'
uses: 'actions/cache@v4'
with:
path: '${{ env.GEMINI_LINT_TEMP_DIR }}'
key: "${{ runner.os }}-${{ runner.arch }}-linters-${{ hashFiles('scripts/lint.js') }}"
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Cache ESLint'
uses: 'actions/cache@v4'
with:
path: '.eslintcache'
key: "${{ runner.os }}-eslint-${{ hashFiles('package-lock.json', 'eslint.config.js') }}"
- name: 'Validate NOTICES.txt'
run: 'git diff --exit-code packages/vscode-ide-companion/NOTICES.txt'
- name: 'Check lockfile'
run: 'npm run check:lockfile'
- name: 'Install linters'
run: 'node scripts/lint.js --setup'
- name: 'Run ESLint'
run: 'node scripts/lint.js --eslint'
- name: 'Run actionlint'
run: 'node scripts/lint.js --actionlint'
- name: 'Run shellcheck'
run: 'node scripts/lint.js --shellcheck'
- name: 'Run yamllint'
run: 'node scripts/lint.js --yamllint'
- name: 'Run Prettier'
run: 'node scripts/lint.js --prettier'
- name: 'Build docs prerequisites'
run: 'npm run predocs:settings'
- name: 'Verify settings docs'
run: 'npm run docs:settings -- --check'
- name: 'Run sensitive keyword linter'
run: 'node scripts/lint.js --sensitive-keywords'
link_checker:
name: 'Link Checker'
runs-on: 'ubuntu-latest'
if: "github.repository == 'google-gemini/gemini-cli'"
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Link Checker'
uses: 'lycheeverse/lychee-action@885c65f3dc543b57c898c8099f4e08c8afd178a2' # ratchet: lycheeverse/lychee-action@v2.6.1
with:
args: '--verbose --accept 200,503 ./**/*.md'
fail: true
test_linux:
name: 'Test (Linux) - ${{ matrix.node-version }}, ${{ matrix.shard }}'
runs-on: 'gemini-cli-ubuntu-16-core'
needs:
- 'merge_queue_skipper'
if: "github.repository == 'google-gemini/gemini-cli' && needs.merge_queue_skipper.outputs.skip == 'false'"
permissions:
contents: 'read'
checks: 'write'
pull-requests: 'write'
strategy:
matrix:
node-version:
- '20.x'
- '22.x'
- '24.x'
shard:
- 'cli'
- 'others'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Set up Node.js ${{ matrix.node-version }}'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version: '${{ matrix.node-version }}'
cache: 'npm'
- name: 'Build project'
run: 'npm run build'
- name: 'Install dependencies for testing'
run: 'npm ci'
- name: 'Run tests and generate reports'
env:
NO_COLOR: true
run: |
if [[ "${{ matrix.shard }}" == "cli" ]]; then
npm run test:ci --workspace @google/gemini-cli
else
# Explicitly list non-cli packages to ensure they are sharded correctly
npm run test:ci --workspace @google/gemini-cli-core --workspace @google/gemini-cli-a2a-server --workspace gemini-cli-vscode-ide-companion --workspace @google/gemini-cli-test-utils --if-present -- --coverage.enabled=false
npm run test:scripts
fi
- name: 'Bundle'
run: 'npm run bundle'
- name: 'Smoke test bundle'
run: 'node ./bundle/gemini.js --version'
- name: 'Smoke test npx installation'
run: |
# 1. Package the project into a tarball
TARBALL=$(npm pack | tail -n 1)
# 2. Move to a fresh directory for isolation
mkdir -p ../smoke-test-dir
mv "$TARBALL" ../smoke-test-dir/
cd ../smoke-test-dir
# 3. Run npx from the tarball
npx "./$TARBALL" --version
- name: 'Wait for file system sync'
run: 'sleep 2'
- name: 'Publish Test Report (for non-forks)'
if: |-
${{ always() && (github.event.pull_request.head.repo.full_name == github.repository) }}
uses: 'dorny/test-reporter@dc3a92680fcc15842eef52e8c4606ea7ce6bd3f3' # ratchet:dorny/test-reporter@v2
with:
name: 'Test Results (Node ${{ runner.os }}, ${{ matrix.node-version }}, ${{ matrix.shard }})'
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@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
with:
name: 'test-results-fork-${{ runner.os }}-${{ matrix.node-version }}-${{ matrix.shard }}'
path: 'packages/*/junit.xml'
test_mac:
name: 'Test (Mac) - ${{ matrix.node-version }}, ${{ matrix.shard }}'
runs-on: 'macos-latest'
needs:
- 'merge_queue_skipper'
if: "github.repository == 'google-gemini/gemini-cli' && needs.merge_queue_skipper.outputs.skip == 'false'"
permissions:
contents: 'read'
checks: 'write'
pull-requests: 'write'
continue-on-error: true
strategy:
matrix:
node-version:
- '20.x'
- '22.x'
- '24.x'
shard:
- 'cli'
- 'others'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Set up Node.js ${{ matrix.node-version }}'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version: '${{ matrix.node-version }}'
cache: 'npm'
- name: 'Build project'
run: 'npm run build'
- name: 'Install dependencies for testing'
run: 'npm ci'
- name: 'Run tests and generate reports'
env:
NO_COLOR: true
run: |
if [[ "${{ matrix.shard }}" == "cli" ]]; then
npm run test:ci --workspace @google/gemini-cli -- --coverage.enabled=false
else
# Explicitly list non-cli packages to ensure they are sharded correctly
npm run test:ci --workspace @google/gemini-cli-core --workspace @google/gemini-cli-a2a-server --workspace gemini-cli-vscode-ide-companion --workspace @google/gemini-cli-test-utils --if-present -- --coverage.enabled=false
npm run test:scripts
fi
- name: 'Bundle'
run: 'npm run bundle'
- name: 'Smoke test bundle'
run: 'node ./bundle/gemini.js --version'
- name: 'Smoke test npx installation'
run: |
# 1. Package the project into a tarball
TARBALL=$(npm pack | tail -n 1)
# 2. Move to a fresh directory for isolation
mkdir -p ../smoke-test-dir
mv "$TARBALL" ../smoke-test-dir/
cd ../smoke-test-dir
# 3. Run npx from the tarball
npx "./$TARBALL" --version
- name: 'Wait for file system sync'
run: 'sleep 2'
- name: 'Publish Test Report (for non-forks)'
if: |-
${{ always() && (github.event.pull_request.head.repo.full_name == github.repository) }}
uses: 'dorny/test-reporter@dc3a92680fcc15842eef52e8c4606ea7ce6bd3f3' # ratchet:dorny/test-reporter@v2
with:
name: 'Test Results (Node ${{ runner.os }}, ${{ matrix.node-version }}, ${{ matrix.shard }})'
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@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
with:
name: 'test-results-fork-${{ runner.os }}-${{ matrix.node-version }}-${{ matrix.shard }}'
path: 'packages/*/junit.xml'
- name: 'Upload coverage reports'
if: |-
${{ always() }}
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
with:
name: 'coverage-reports-${{ runner.os }}-${{ matrix.node-version }}-${{ matrix.shard }}'
path: 'packages/*/coverage'
codeql:
name: 'CodeQL'
runs-on: 'gemini-cli-ubuntu-16-core'
needs: 'merge_queue_skipper'
if: "github.repository == 'google-gemini/gemini-cli' && needs.merge_queue_skipper.outputs.skip == 'false'"
permissions:
actions: 'read'
contents: 'read'
security-events: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
- name: 'Initialize CodeQL'
uses: 'github/codeql-action/init@df559355d593797519d70b90fc8edd5db049e7a2' # ratchet:github/codeql-action/init@v3
with:
languages: 'javascript'
- name: 'Perform CodeQL Analysis'
uses: 'github/codeql-action/analyze@df559355d593797519d70b90fc8edd5db049e7a2' # ratchet:github/codeql-action/analyze@v3
# Check for changes in bundle size.
bundle_size:
name: 'Check Bundle Size'
needs: 'merge_queue_skipper'
if: "github.repository == 'google-gemini/gemini-cli' && github.event_name == 'pull_request' && needs.merge_queue_skipper.outputs.skip == 'false'"
runs-on: 'gemini-cli-ubuntu-16-core'
permissions:
contents: 'read' # For checkout
pull-requests: 'write' # For commenting
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
fetch-depth: 1
- uses: 'preactjs/compressed-size-action@946a292cd35bd1088e0d7eb92b69d1a8d5b5d76a'
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
pattern: './bundle/**/*.{js,sb}'
minimum-change-threshold: '1000'
compression: 'none'
clean-script: 'clean'
test_windows:
name: 'Slow Test - Win - ${{ matrix.shard }}'
runs-on: 'gemini-cli-windows-16-core'
needs: 'merge_queue_skipper'
if: "github.repository == 'google-gemini/gemini-cli' && needs.merge_queue_skipper.outputs.skip == 'false'"
timeout-minutes: 60
strategy:
matrix:
shard:
- 'cli'
- 'others'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
- name: 'Set up Node.js 20.x'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: 'Configure Windows Defender exclusions'
run: |
Add-MpPreference -ExclusionPath $env:GITHUB_WORKSPACE -Force
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\node_modules" -Force
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\packages" -Force
Add-MpPreference -ExclusionPath "$env:TEMP" -Force
shell: 'pwsh'
- name: 'Configure npm for Windows performance'
run: |
npm config set progress false
npm config set audit false
npm config set fund false
npm config set loglevel error
npm config set maxsockets 32
npm config set registry https://registry.npmjs.org/
shell: 'pwsh'
- name: 'Install dependencies'
run: 'npm ci'
shell: 'pwsh'
- name: 'Build project'
run: 'npm run build'
shell: 'pwsh'
env:
NODE_OPTIONS: '--max-old-space-size=32768 --max-semi-space-size=256'
UV_THREADPOOL_SIZE: '32'
NODE_ENV: 'production'
- name: 'Run tests and generate reports'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
NO_COLOR: true
NODE_OPTIONS: '--max-old-space-size=32768 --max-semi-space-size=256'
UV_THREADPOOL_SIZE: '32'
NODE_ENV: 'test'
run: |
if ("${{ matrix.shard }}" -eq "cli") {
npm run test:ci --workspace @google/gemini-cli -- --coverage.enabled=false
} else {
# Explicitly list non-cli packages to ensure they are sharded correctly
npm run test:ci --workspace @google/gemini-cli-core --workspace @google/gemini-cli-a2a-server --workspace gemini-cli-vscode-ide-companion --workspace @google/gemini-cli-test-utils --if-present -- --coverage.enabled=false
npm run test:scripts
}
shell: 'pwsh'
- name: 'Bundle'
run: 'npm run bundle'
shell: 'pwsh'
- name: 'Smoke test bundle'
run: 'node ./bundle/gemini.js --version'
shell: 'pwsh'
- name: 'Smoke test npx installation'
run: |
# 1. Package the project into a tarball
$PACK_OUTPUT = npm pack
$TARBALL = $PACK_OUTPUT[-1]
# 2. Move to a fresh directory for isolation
New-Item -ItemType Directory -Force -Path ../smoke-test-dir
Move-Item $TARBALL ../smoke-test-dir/
Set-Location ../smoke-test-dir
# 3. Run npx from the tarball
npx "./$TARBALL" --version
shell: 'pwsh'
ci:
name: 'CI'
if: "github.repository == 'google-gemini/gemini-cli' && always()"
needs:
- 'lint'
- 'link_checker'
- 'test_linux'
- 'test_mac'
- 'test_windows'
- 'codeql'
- 'bundle_size'
runs-on: 'gemini-cli-ubuntu-16-core'
steps:
- name: 'Check all job results'
run: |
if [[ (${NEEDS_LINT_RESULT} != 'success' && ${NEEDS_LINT_RESULT} != 'skipped') || \
(${NEEDS_LINK_CHECKER_RESULT} != 'success' && ${NEEDS_LINK_CHECKER_RESULT} != 'skipped') || \
(${NEEDS_TEST_LINUX_RESULT} != 'success' && ${NEEDS_TEST_LINUX_RESULT} != 'skipped') || \
(${NEEDS_TEST_MAC_RESULT} != 'success' && ${NEEDS_TEST_MAC_RESULT} != 'skipped') || \
(${NEEDS_TEST_WINDOWS_RESULT} != 'success' && ${NEEDS_TEST_WINDOWS_RESULT} != 'skipped') || \
(${NEEDS_CODEQL_RESULT} != 'success' && ${NEEDS_CODEQL_RESULT} != 'skipped') || \
(${NEEDS_BUNDLE_SIZE_RESULT} != 'success' && ${NEEDS_BUNDLE_SIZE_RESULT} != 'skipped') ]]; then
echo "One or more CI jobs failed."
exit 1
fi
echo "All CI jobs passed!"
env:
NEEDS_LINT_RESULT: '${{ needs.lint.result }}'
NEEDS_LINK_CHECKER_RESULT: '${{ needs.link_checker.result }}'
NEEDS_TEST_LINUX_RESULT: '${{ needs.test_linux.result }}'
NEEDS_TEST_MAC_RESULT: '${{ needs.test_mac.result }}'
NEEDS_TEST_WINDOWS_RESULT: '${{ needs.test_windows.result }}'
NEEDS_CODEQL_RESULT: '${{ needs.codeql.result }}'
NEEDS_BUNDLE_SIZE_RESULT: '${{ needs.bundle_size.result }}'
================================================
FILE: .github/workflows/community-report.yml
================================================
name: 'Generate Weekly Community Report 📊'
on:
schedule:
- cron: '0 12 * * 1' # Run at 12:00 UTC on Monday
workflow_dispatch:
inputs:
days:
description: 'Number of days to look back for the report'
required: true
default: '7'
jobs:
generate-report:
name: 'Generate Report 📝'
if: |-
${{ github.repository == 'google-gemini/gemini-cli' }}
runs-on: 'ubuntu-latest'
permissions:
issues: 'write'
pull-requests: 'read'
discussions: 'read'
contents: 'read'
id-token: 'write'
steps:
- name: 'Generate GitHub App Token 🔑'
id: 'generate_token'
uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
permission-issues: 'write'
permission-pull-requests: 'read'
permission-discussions: 'read'
permission-contents: 'read'
- name: 'Generate Report 📜'
id: 'report'
env:
GH_TOKEN: '${{ steps.generate_token.outputs.token }}'
REPO: '${{ github.repository }}'
DAYS: '${{ github.event.inputs.days || 7 }}'
run: |-
set -e
START_DATE="$(date -u -d "$DAYS days ago" +'%Y-%m-%d')"
END_DATE="$(date -u +'%Y-%m-%d')"
echo "⏳ Generating report for contributions from ${START_DATE} to ${END_DATE}..."
declare -A author_is_googler
check_googler_status() {
local author="$1"
if [[ "${author}" == *"[bot]" ]]; then
author_is_googler[${author}]=1
return 1
fi
if [[ -v "author_is_googler[${author}]" ]]; then
return "${author_is_googler[${author}]}"
fi
if gh api "orgs/googlers/members/${author}" --silent 2>/dev/null; then
echo "🧑💻 ${author} is a Googler."
author_is_googler[${author}]=0
else
echo "🌍 ${author} is a community contributor."
author_is_googler[${author}]=1
fi
return "${author_is_googler[${author}]}"
}
googler_issues=0
non_googler_issues=0
googler_prs=0
non_googler_prs=0
echo "🔎 Fetching issues and pull requests..."
ITEMS_JSON="$(gh search issues --repo "${REPO}" "created:>${START_DATE}" --json author,isPullRequest --limit 1000)"
for row in $(echo "${ITEMS_JSON}" | jq -r '.[] | @base64'); do
_jq() {
echo "${row}" | base64 --decode | jq -r "${1}"
}
author="$(_jq '.author.login')"
is_pr="$(_jq '.isPullRequest')"
if [[ -z "${author}" || "${author}" == "null" ]]; then
continue
fi
if check_googler_status "${author}"; then
if [[ "${is_pr}" == "true" ]]; then
((googler_prs++))
else
((googler_issues++))
fi
else
if [[ "${is_pr}" == "true" ]]; then
((non_googler_prs++))
else
((non_googler_issues++))
fi
fi
done
googler_discussions=0
non_googler_discussions=0
echo "🗣️ Fetching discussions..."
DISCUSSION_QUERY='''
query($q: String!) {
search(query: $q, type: DISCUSSION, first: 100) {
nodes {
... on Discussion {
author {
login
}
}
}
}
}'''
DISCUSSIONS_JSON="$(gh api graphql -f q="repo:${REPO} created:>${START_DATE}" -f query="${DISCUSSION_QUERY}")"
for row in $(echo "${DISCUSSIONS_JSON}" | jq -r '.data.search.nodes[] | @base64'); do
_jq() {
echo "${row}" | base64 --decode | jq -r "${1}"
}
author="$(_jq '.author.login')"
if [[ -z "${author}" || "${author}" == "null" ]]; then
continue
fi
if check_googler_status "${author}"; then
((googler_discussions++))
else
((non_googler_discussions++))
fi
done
echo "✍️ Generating report content..."
TOTAL_ISSUES=$((googler_issues + non_googler_issues))
TOTAL_PRS=$((googler_prs + non_googler_prs))
TOTAL_DISCUSSIONS=$((googler_discussions + non_googler_discussions))
REPORT_BODY=$(cat <<EOF
### 💖 Community Contribution Report
**Period:** ${START_DATE} to ${END_DATE}
| Category | Googlers | Community | Total |
|---|---:|---:|---:|
| **Issues** | $googler_issues | $non_googler_issues | **$TOTAL_ISSUES** |
| **Pull Requests** | $googler_prs | $non_googler_prs | **$TOTAL_PRS** |
| **Discussions** | $googler_discussions | $non_googler_discussions | **$TOTAL_DISCUSSIONS** |
_This report was generated automatically by a GitHub Action._
EOF
)
echo "report_body<<EOF" >> "${GITHUB_OUTPUT}"
echo "${REPORT_BODY}" >> "${GITHUB_OUTPUT}"
echo "EOF" >> "${GITHUB_OUTPUT}"
echo "📊 Community Contribution Report:"
echo "${REPORT_BODY}"
- name: '🤖 Get Insights from Report'
if: |-
${{ steps.report.outputs.report_body != '' }}
uses: 'google-github-actions/run-gemini-cli@a3bf79042542528e91937b3a3a6fbc4967ee3c31' # ratchet:google-github-actions/run-gemini-cli@v0
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token }}'
REPOSITORY: '${{ github.repository }}'
with:
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
settings: |-
{
"coreTools": [
"run_shell_command(gh issue list)",
"run_shell_command(gh pr list)",
"run_shell_command(gh search issues)",
"run_shell_command(gh search prs)"
]
}
prompt: |-
You are a helpful assistant that analyzes community contribution reports.
Based on the following report, please provide a brief summary and highlight any interesting trends or potential areas for improvement.
Report:
${{ steps.report.outputs.report_body }}
================================================
FILE: .github/workflows/deflake.yml
================================================
name: 'Deflake E2E'
on:
workflow_dispatch:
inputs:
branch_ref:
description: 'Branch to run on'
required: true
default: 'main'
type: 'string'
test_name_pattern:
description: 'The test name pattern to use'
required: false
type: 'string'
runs:
description: 'The number of runs'
required: false
default: 5
type: 'number'
concurrency:
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
cancel-in-progress: |-
${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/heads/release/') }}
jobs:
deflake_e2e_linux:
name: 'E2E Test (Linux) - ${{ matrix.sandbox }}'
runs-on: 'gemini-cli-ubuntu-16-core'
if: "github.repository == 'google-gemini/gemini-cli'"
strategy:
fail-fast: false
matrix:
sandbox:
- 'sandbox:none'
- 'sandbox:docker'
node-version:
- '20.x'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.pull_request.head.sha }}'
repository: '${{ github.repository }}'
- name: 'Set up Node.js ${{ matrix.node-version }}'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
with:
node-version: '${{ matrix.node-version }}'
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Build project'
run: 'npm run build'
- name: 'Set up Docker'
if: "matrix.sandbox == 'sandbox:docker'"
uses: 'docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435' # ratchet:docker/setup-buildx-action@v3
- name: 'Run E2E tests'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
IS_DOCKER: "${{ matrix.sandbox == 'sandbox:docker' }}"
KEEP_OUTPUT: 'true'
RUNS: '${{ github.event.inputs.runs }}'
TEST_NAME_PATTERN: '${{ github.event.inputs.test_name_pattern }}'
VERBOSE: 'true'
shell: 'bash'
run: |
if [[ "${IS_DOCKER}" == "true" ]]; then
npm run deflake:test:integration:sandbox:docker -- --runs="${RUNS}" -- --testNamePattern "'${TEST_NAME_PATTERN}'"
else
npm run deflake:test:integration:sandbox:none -- --runs="${RUNS}" -- --testNamePattern "'${TEST_NAME_PATTERN}'"
fi
deflake_e2e_mac:
name: 'E2E Test (macOS)'
runs-on: 'macos-latest'
if: "github.repository == 'google-gemini/gemini-cli'"
steps:
- name: 'Checkout'
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.pull_request.head.sha }}'
repository: '${{ github.repository }}'
- name: 'Set up Node.js 20.x'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
with:
node-version: '20.x'
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Build project'
run: 'npm run build'
- name: 'Fix rollup optional dependencies on macOS'
if: "runner.os == 'macOS'"
run: |
npm cache clean --force
- name: 'Run E2E tests (non-Windows)'
if: "runner.os != 'Windows'"
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
KEEP_OUTPUT: 'true'
RUNS: '${{ github.event.inputs.runs }}'
SANDBOX: 'sandbox:none'
TEST_NAME_PATTERN: '${{ github.event.inputs.test_name_pattern }}'
VERBOSE: 'true'
run: |
npm run deflake:test:integration:sandbox:none -- --runs="${RUNS}" -- --testNamePattern "'${TEST_NAME_PATTERN}'"
deflake_e2e_windows:
name: 'Slow E2E - Win'
runs-on: 'gemini-cli-windows-16-core'
if: "github.repository == 'google-gemini/gemini-cli'"
steps:
- name: 'Checkout'
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.pull_request.head.sha }}'
repository: '${{ github.repository }}'
- name: 'Set up Node.js 20.x'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: 'Configure Windows Defender exclusions'
run: |
Add-MpPreference -ExclusionPath $env:GITHUB_WORKSPACE -Force
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\node_modules" -Force
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\packages" -Force
Add-MpPreference -ExclusionPath "$env:TEMP" -Force
shell: 'pwsh'
- name: 'Configure npm for Windows performance'
run: |
npm config set progress false
npm config set audit false
npm config set fund false
npm config set loglevel error
npm config set maxsockets 32
npm config set registry https://registry.npmjs.org/
shell: 'pwsh'
- name: 'Install dependencies'
run: 'npm ci'
shell: 'pwsh'
- name: 'Build project'
run: 'npm run build'
shell: 'pwsh'
- name: 'Run E2E tests'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
KEEP_OUTPUT: 'true'
SANDBOX: 'sandbox:none'
VERBOSE: 'true'
NODE_OPTIONS: '--max-old-space-size=32768 --max-semi-space-size=256'
UV_THREADPOOL_SIZE: '32'
NODE_ENV: 'test'
RUNS: '${{ github.event.inputs.runs }}'
TEST_NAME_PATTERN: '${{ github.event.inputs.test_name_pattern }}'
shell: 'pwsh'
run: |
npm run deflake:test:integration:sandbox:none -- --runs="$env:RUNS" -- --testNamePattern "'$env:TEST_NAME_PATTERN'"
================================================
FILE: .github/workflows/docs-page-action.yml
================================================
name: 'Deploy GitHub Pages'
on:
push:
tags: 'v*'
workflow_dispatch:
permissions:
contents: 'read'
pages: 'write'
id-token: 'write'
# Allow only one concurrent deployment, skipping runs queued between the run
# in-progress and latest queued. However, do NOT cancel in-progress runs as we
# want to allow these production deployments to complete.
concurrency:
group: '${{ github.workflow }}'
cancel-in-progress: false
jobs:
build:
if: "github.repository == 'google-gemini/gemini-cli' && !contains(github.ref_name, 'nightly')"
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Setup Pages'
uses: 'actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b' # ratchet:actions/configure-pages@v5
- name: 'Build with Jekyll'
uses: 'actions/jekyll-build-pages@44a6e6beabd48582f863aeeb6cb2151cc1716697' # ratchet:actions/jekyll-build-pages@v1
with:
source: './'
destination: './_site'
- name: 'Upload artifact'
uses: 'actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa' # ratchet:actions/upload-pages-artifact@v3
deploy:
if: "github.repository == 'google-gemini/gemini-cli'"
environment:
name: 'github-pages'
url: '${{ steps.deployment.outputs.page_url }}'
runs-on: 'ubuntu-latest'
needs: 'build'
steps:
- name: 'Deploy to GitHub Pages'
id: 'deployment'
uses: 'actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e' # ratchet:actions/deploy-pages@v4
================================================
FILE: .github/workflows/docs-rebuild.yml
================================================
name: 'Trigger Docs Rebuild'
on:
push:
branches:
- 'main'
paths:
- 'docs/**'
jobs:
trigger-rebuild:
if: "github.repository == 'google-gemini/gemini-cli'"
runs-on: 'ubuntu-latest'
steps:
- name: 'Trigger rebuild'
run: |
curl -X POST \
-H "Content-Type: application/json" \
-d '{}' \
"${{ secrets.DOCS_REBUILD_URL }}"
================================================
FILE: .github/workflows/eval.yml
================================================
name: 'Eval'
on:
workflow_dispatch:
defaults:
run:
shell: 'bash'
permissions:
contents: 'read'
id-token: 'write'
packages: 'read'
jobs:
eval:
name: 'Eval'
if: >-
github.repository == 'google-gemini/gemini-cli'
runs-on: 'ubuntu-latest'
container:
image: 'ghcr.io/google-gemini/gemini-cli-swe-agent-eval@sha256:cd5edc4afd2245c1f575e791c0859b3c084a86bb3bd9a6762296da5162b35a8f'
credentials:
username: '${{ github.actor }}'
password: '${{ secrets.GITHUB_TOKEN }}'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
DEFAULT_VERTEXAI_PROJECT: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
GOOGLE_CLOUD_PROJECT: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
GEMINI_API_KEY: '${{ secrets.EVAL_GEMINI_API_KEY }}'
GCLI_LOCAL_FILE_TELEMETRY: 'True'
EVAL_GCS_BUCKET: '${{ vars.EVAL_GCS_ARTIFACTS_BUCKET }}'
steps:
- name: 'Authenticate to Google Cloud'
id: 'auth'
uses: 'google-github-actions/auth@c200f3691d83b41bf9bbd8638997a462592937ed' # ratchet:exclude pin@v2.1.7
with:
project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
token_format: 'access_token'
access_token_scopes: 'https://www.googleapis.com/auth/cloud-platform'
- name: 'Run evaluation'
working-directory: '/app'
run: |
poetry run exp_run --experiment-mode=on-demand --branch-or-commit="${GITHUB_REF_NAME}" --model-name=gemini-2.5-pro --dataset=swebench_verified --concurrency=15
poetry run python agent_prototypes/scripts/parse_gcli_logs_experiment.py --experiment_dir=experiments/adhoc/gcli_temp_exp --gcs-bucket="${EVAL_GCS_BUCKET}" --gcs-path=gh_action_artifacts
================================================
FILE: .github/workflows/evals-nightly.yml
================================================
name: 'Evals: Nightly'
on:
schedule:
- cron: '0 1 * * *' # Runs at 1 AM every day
workflow_dispatch:
inputs:
run_all:
description: 'Run all evaluations (including usually passing)'
type: 'boolean'
default: true
test_name_pattern:
description: 'Test name pattern or file name'
required: false
type: 'string'
permissions:
contents: 'read'
checks: 'write'
actions: 'read'
jobs:
evals:
name: 'Evals (USUALLY_PASSING) nightly run'
runs-on: 'gemini-cli-ubuntu-16-core'
if: "github.repository == 'google-gemini/gemini-cli'"
strategy:
fail-fast: false
matrix:
model:
- 'gemini-3.1-pro-preview-customtools'
- 'gemini-3-pro-preview'
- 'gemini-3-flash-preview'
- 'gemini-2.5-pro'
- 'gemini-2.5-flash'
- 'gemini-2.5-flash-lite'
run_attempt: [1, 2, 3]
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Set up Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Build project'
run: 'npm run build'
- name: 'Create logs directory'
run: 'mkdir -p evals/logs'
- name: 'Run Evals'
continue-on-error: true
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
GEMINI_MODEL: '${{ matrix.model }}'
RUN_EVALS: "${{ github.event.inputs.run_all != 'false' }}"
TEST_NAME_PATTERN: '${{ github.event.inputs.test_name_pattern }}'
run: |
CMD="npm run test:all_evals"
PATTERN="${TEST_NAME_PATTERN}"
if [[ -n "$PATTERN" ]]; then
if [[ "$PATTERN" == *.ts || "$PATTERN" == *.js || "$PATTERN" == */* ]]; then
$CMD -- "$PATTERN"
else
$CMD -- -t "$PATTERN"
fi
else
$CMD
fi
- name: 'Upload Logs'
if: 'always()'
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
with:
name: 'eval-logs-${{ matrix.model }}-${{ matrix.run_attempt }}'
path: 'evals/logs'
retention-days: 7
aggregate-results:
name: 'Aggregate Results'
needs: ['evals']
if: "github.repository == 'google-gemini/gemini-cli' && always()"
runs-on: 'gemini-cli-ubuntu-16-core'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Download Logs'
uses: 'actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806' # ratchet:actions/download-artifact@v4
with:
path: 'artifacts'
- name: 'Generate Summary'
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: 'node scripts/aggregate_evals.js artifacts >> "$GITHUB_STEP_SUMMARY"'
================================================
FILE: .github/workflows/gemini-automated-issue-dedup.yml
================================================
name: '🏷️ Gemini Automated Issue Deduplication'
on:
issues:
types:
- 'opened'
- 'reopened'
issue_comment:
types:
- 'created'
workflow_dispatch:
inputs:
issue_number:
description: 'issue number to dedup'
required: true
type: 'number'
concurrency:
group: '${{ github.workflow }}-${{ github.event.issue.number }}'
cancel-in-progress: true
defaults:
run:
shell: 'bash'
jobs:
find-duplicates:
if: |-
github.repository == 'google-gemini/gemini-cli' &&
vars.TRIAGE_DEDUPLICATE_ISSUES != '' &&
(github.event_name == 'issues' ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'issue_comment' &&
contains(github.event.comment.body, '@gemini-cli /deduplicate') &&
(github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR')))
permissions:
contents: 'read'
id-token: 'write' # Required for WIF, see https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-google-cloud-platform#adding-permissions-settings
issues: 'read'
statuses: 'read'
packages: 'read'
timeout-minutes: 20
runs-on: 'ubuntu-latest'
outputs:
duplicate_issues_csv: '${{ env.DUPLICATE_ISSUES_CSV }}'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Log in to GitHub Container Registry'
uses: 'docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1' # ratchet:docker/login-action@v3
with:
registry: 'ghcr.io'
username: '${{ github.actor }}'
password: '${{ secrets.GITHUB_TOKEN }}'
- name: 'Find Duplicate Issues'
uses: 'google-github-actions/run-gemini-cli@a3bf79042542528e91937b3a3a6fbc4967ee3c31' # ratchet:google-github-actions/run-gemini-cli@v0
id: 'gemini_issue_deduplication'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
ISSUE_TITLE: '${{ github.event.issue.title }}'
ISSUE_BODY: '${{ github.event.issue.body }}'
ISSUE_NUMBER: '${{ github.event.issue.number }}'
REPOSITORY: '${{ github.repository }}'
FIRESTORE_PROJECT: '${{ vars.FIRESTORE_PROJECT }}'
with:
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
settings: |-
{
"mcpServers": {
"issue_deduplication": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"--network", "host",
"-e", "GITHUB_TOKEN",
"-e", "GEMINI_API_KEY",
"-e", "DATABASE_TYPE",
"-e", "FIRESTORE_DATABASE_ID",
"-e", "GCP_PROJECT",
"-e", "GOOGLE_APPLICATION_CREDENTIALS=/app/gcp-credentials.json",
"-v", "${GOOGLE_APPLICATION_CREDENTIALS}:/app/gcp-credentials.json",
"ghcr.io/google-gemini/gemini-cli-issue-triage@sha256:e3de1523f6c83aabb3c54b76d08940a2bf42febcb789dd2da6f95169641f94d3"
],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}",
"GEMINI_API_KEY": "${{ secrets.GEMINI_API_KEY }}",
"DATABASE_TYPE":"firestore",
"GCP_PROJECT": "${FIRESTORE_PROJECT}",
"FIRESTORE_DATABASE_ID": "(default)",
"GOOGLE_APPLICATION_CREDENTIALS": "${GOOGLE_APPLICATION_CREDENTIALS}"
},
"timeout": 600000
}
},
"maxSessionTurns": 25,
"coreTools": [
"run_shell_command(echo)",
"run_shell_command(gh issue view)"
],
"telemetry": {
"enabled": true,
"target": "gcp"
}
}
prompt: |-
## Role
You are an issue de-duplication assistant. Your goal is to find
duplicate issues for a given issue.
## Steps
1. **Find Potential Duplicates:**
- The repository is ${{ github.repository }} and the issue number is ${{ github.event.issue.number }}.
- Use the `duplicates` tool with the `repo` and `issue_number` to find potential duplicates for the current issue. Do not use the `threshold` parameter.
- If no duplicates are found, you are done.
- Print the JSON output from the `duplicates` tool to the logs.
2. **Refine Duplicates List (if necessary):**
- If the `duplicates` tool returns between 1 and 14 results, you must refine the list.
- For each potential duplicate issue, run `gh issue view <issue-number> --json title,body,comments` to fetch its content.
- Also fetch the content of the original issue: `gh issue view "${ISSUE_NUMBER}" --json title,body,comments`.
- Carefully analyze the content (title, body, comments) of the original issue and all potential duplicates.
- It is very important if the comments on either issue mention that they are not duplicates of each other, to treat them as not duplicates.
- Based on your analysis, create a final list containing only the issues you are highly confident are actual duplicates.
- If your final list is empty, you are done.
- Print to the logs if you omitted any potential duplicates based on your analysis.
- If the `duplicates` tool returned 15+ results, use the top 15 matches (based on descending similarity score value) to perform this step.
3. **Output final duplicates list as CSV:**
- Convert the list of appropriate duplicate issue numbers into a comma-separated list (CSV). If there are no appropriate duplicates, use the empty string.
- Use the "echo" shell command to append the CSV of issue numbers into the filepath referenced by the environment variable "${GITHUB_ENV}":
echo "DUPLICATE_ISSUES_CSV=[DUPLICATE_ISSUES_AS_CSV]" >> "${GITHUB_ENV}"
## Guidelines
- Only use the `duplicates` and `run_shell_command` tools.
- The `run_shell_command` tool can be used with `gh issue view`.
- Do not download or read media files like images, videos, or links. The `--json` flag for `gh issue view` will prevent this.
- Do not modify the issue content or status.
- Do not add comments or labels.
- Reference all shell variables as "${VAR}" (with quotes and braces).
add-comment-and-label:
needs: 'find-duplicates'
if: |-
github.repository == 'google-gemini/gemini-cli' &&
vars.TRIAGE_DEDUPLICATE_ISSUES != '' &&
needs.find-duplicates.outputs.duplicate_issues_csv != '' &&
(
github.event_name == 'issues' ||
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'issue_comment' &&
contains(github.event.comment.body, '@gemini-cli /deduplicate') &&
(
github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR'
)
)
)
permissions:
issues: 'write'
timeout-minutes: 5
runs-on: 'ubuntu-latest'
steps:
- name: 'Generate GitHub App Token'
id: 'generate_token'
uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
permission-issues: 'write'
- name: 'Comment and Label Duplicate Issue'
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
env:
DUPLICATES_OUTPUT: '${{ needs.find-duplicates.outputs.duplicate_issues_csv }}'
with:
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
script: |-
const rawCsv = process.env.DUPLICATES_OUTPUT;
core.info(`Raw duplicates CSV: ${rawCsv}`);
const duplicateIssues = rawCsv.split(',').map(s => s.trim()).filter(s => s);
if (duplicateIssues.length === 0) {
core.info('No duplicate issues found. Nothing to do.');
return;
}
const issueNumber = ${{ github.event.issue.number }};
function formatCommentBody(issues, updated = false) {
const header = updated
? 'Found possible duplicate issues (updated):'
: 'Found possible duplicate issues:';
const issuesList = issues.map(num => `- #${num}`).join('\n');
const footer = 'If you believe this is not a duplicate, please remove the `status/possible-duplicate` label.';
const magicComment = '<!-- gemini-cli-deduplication -->';
return `${header}\n\n${issuesList}\n\n${footer}\n${magicComment}`;
}
const newCommentBody = formatCommentBody(duplicateIssues);
const newUpdatedCommentBody = formatCommentBody(duplicateIssues, true);
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});
const magicComment = '<!-- gemini-cli-deduplication -->';
const existingComment = comments.find(comment =>
comment.user.type === 'Bot' && comment.body.includes(magicComment)
);
let commentMade = false;
if (existingComment) {
// To check if lists are same, just compare the formatted bodies without headers.
const existingBodyForCompare = existingComment.body.substring(existingComment.body.indexOf('- #'));
const newBodyForCompare = newCommentBody.substring(newCommentBody.indexOf('- #'));
if (existingBodyForCompare.trim() !== newBodyForCompare.trim()) {
core.info(`Updating existing comment ${existingComment.id}`);
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.id,
body: newUpdatedCommentBody,
});
commentMade = true;
} else {
core.info('Existing comment is up-to-date. Nothing to do.');
}
} else {
core.info('Creating new comment.');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: newCommentBody,
});
commentMade = true;
}
if (commentMade) {
core.info('Adding "status/possible-duplicate" label.');
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
labels: ['status/possible-duplicate'],
});
}
================================================
FILE: .github/workflows/gemini-automated-issue-triage.yml
================================================
name: '🏷️ Gemini Automated Issue Triage'
on:
issues:
types:
- 'opened'
- 'reopened'
issue_comment:
types:
- 'created'
workflow_dispatch:
inputs:
issue_number:
description: 'issue number to triage'
required: true
type: 'number'
workflow_call:
inputs:
issue_number:
description: 'issue number to triage'
required: false
type: 'string'
concurrency:
group: '${{ github.workflow }}-${{ github.event.issue.number || github.event.inputs.issue_number || inputs.issue_number }}'
cancel-in-progress: true
defaults:
run:
shell: 'bash'
permissions:
contents: 'read'
id-token: 'write'
issues: 'write'
statuses: 'write'
packages: 'read'
actions: 'write' # Required for cancelling a workflow run
jobs:
triage-issue:
if: |-
(github.repository == 'google-gemini/gemini-cli' || github.repository == 'google-gemini/maintainers-gemini-cli') &&
(
github.event_name == 'workflow_dispatch' ||
(
(github.event_name == 'issues' || github.event_name == 'issue_comment') &&
(github.event_name != 'issue_comment' || (
contains(github.event.comment.body, '@gemini-cli /triage') &&
(github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR')
))
)
) &&
!contains(github.event.issue.labels.*.name, 'area/')
timeout-minutes: 5
runs-on: 'ubuntu-latest'
steps:
- name: 'Get issue data for manual trigger'
id: 'get_issue_data'
if: |-
github.event_name == 'workflow_dispatch'
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
script: |
const issueNumber = ${{ github.event.inputs.issue_number || inputs.issue_number }};
const { data: issue } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});
core.setOutput('title', issue.title);
core.setOutput('body', issue.body);
core.setOutput('labels', issue.labels.map(label => label.name).join(','));
return issue;
- name: 'Manual Trigger Pre-flight Checks'
if: |-
github.event_name == 'workflow_dispatch'
env:
ISSUE_NUMBER_INPUT: '${{ github.event.inputs.issue_number || inputs.issue_number }}'
LABELS: '${{ steps.get_issue_data.outputs.labels }}'
run: |
if echo "${LABELS}" | grep -q 'area/'; then
echo "Issue #${ISSUE_NUMBER_INPUT} already has 'area/' label. Stopping workflow."
exit 1
fi
echo "Manual triage checks passed."
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Generate GitHub App Token'
id: 'generate_token'
env:
APP_ID: '${{ secrets.APP_ID }}'
if: |-
${{ env.APP_ID != '' }}
uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
permission-issues: 'write'
- name: 'Get Repository Labels'
id: 'get_labels'
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
script: |-
const { data: labels } = await github.rest.issues.listLabelsForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
});
const allowedLabels = [
'area/agent',
'area/enterprise',
'area/non-interactive',
'area/core',
'area/security',
'area/platform',
'area/extensions',
'area/documentation',
'area/unknown'
];
const labelNames = labels.map(label => label.name).filter(name => allowedLabels.includes(name));
core.setOutput('available_labels', labelNames.join(','));
core.info(`Found ${labelNames.length} labels: ${labelNames.join(', ')}`);
return labelNames;
- name: 'Run Gemini Issue Analysis'
uses: 'google-github-actions/run-gemini-cli@a3bf79042542528e91937b3a3a6fbc4967ee3c31' # ratchet:google-github-actions/run-gemini-cli@v0
id: 'gemini_issue_analysis'
env:
GITHUB_TOKEN: '' # Do not pass any auth token here since this runs on untrusted inputs
ISSUE_TITLE: >-
${{ github.event_name == 'workflow_dispatch' && steps.get_issue_data.outputs.title || github.event.issue.title }}
ISSUE_BODY: >-
${{ github.event_name == 'workflow_dispatch' && steps.get_issue_data.outputs.body || github.event.issue.body }}
ISSUE_NUMBER: >-
${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.issue_number || inputs.issue_number) || github.event.issue.number }}
REPOSITORY: '${{ github.repository }}'
AVAILABLE_LABELS: '${{ steps.get_labels.outputs.available_labels }}'
with:
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
settings: |-
{
"maxSessionTurns": 25,
"telemetry": {
"enabled": true,
"target": "gcp"
},
"coreTools": [
"run_shell_command(echo)"
]
}
prompt: |-
## Role
You are an issue triage assistant. Your role is to analyze a GitHub issue and determine the single most appropriate area/ label based on the definitions provided.
## Steps
1. Review the issue title and body: ${{ env.ISSUE_TITLE }} and ${{ env.ISSUE_BODY }}.
2. Review the available labels: ${{ env.AVAILABLE_LABELS }}.
3. Select exactly one area/ label that best matches the issue based on Reference 1: Area Definitions.
4. Fallback Logic:
- If you cannot confidently determine the correct area/ label from the definitions, you must use area/unknown.
5. Output your selected label in JSON format and nothing else. Example:
{"labels_to_set": ["area/core"]}
## Guidelines
- Your output must contain exactly one area/ label.
- Triage only the current issue based on its title and body.
- Output only valid JSON format.
- Do not include any explanation or additional text, just the JSON.
Reference 1: Area Definitions
area/agent
- Description: Issues related to the "brain" of the CLI. This includes the core agent logic, model quality, tool/function calling, and memory.
- Example Issues:
"I am not getting a reasonable or expected response."
"The model is not calling the tool I expected."
"The web search tool is not working as expected."
"Feature request for a new built-in tool (e.g., read file, write file)."
"The generated code is poor quality or incorrect."
"The model seems stuck in a loop."
"The response from the model is malformed (e.g., broken JSON, bad formatting)."
"Concerns about unnecessary token consumption."
"Issues with how memory or chat history is managed."
"Issues with sub-agents."
"Model is switching from one to another unexpectedly."
area/enterprise
- Description: Issues specific to enterprise-level features, including telemetry, policy, and licenses.
- Example Issues:
"Usage data is not appearing in our telemetry dashboard."
"A user is able to perform an action that should be blocked by an admin policy."
"Questions about billing, licensing tiers, or enterprise quotas."
area/non-interactive
- Description: Issues related to using the CLI in automated or non-interactive environments (headless mode).
- Example Issues:
"Problems using the CLI as an SDK in another surface."
"The CLI is behaving differently when run from a shell script vs. an interactive terminal."
"GitHub action is failing."
"I am having trouble running the CLI in headless mode"
area/core
- Description: Issues with the fundamental CLI app itself. This includes the user interface (UI/UX), installation, OS compatibility, and performance.
- Example Issues:
"I am seeing my screen flicker when using the CLI."
"The output in my terminal is malformed or unreadable."
"Theme changes are not taking effect."
"Keyboard inputs (e.g., arrow keys, Ctrl+C) are not being recognized."
"The CLI failed to install or update."
"An issue specific to running on Windows, macOS, or Linux."
"Problems with command parsing, flags, or argument handling."
"High CPU or memory usage by the CLI process."
"Issues related to multi-modality (e.g., handling image inputs)."
"Problems with the IDE integration connection or installation"
area/security
- Description: Issues related to user authentication, authorization, data security, and privacy.
- Example Issues:
"I am unable to sign in."
"The login flow is selecting the wrong authentication path"
"Problems with API key handling or credential storage."
"A report of a security vulnerability"
"Concerns about data sanitization or potential data leaks."
"Issues or requests related to privacy controls."
"Preventing unauthorized data access."
area/platform
- Description: Issues related to CI/CD, release management, testing, eval infrastructure, capacity, quota management, and sandbox environments.
- Example Issues:
"I am getting a 429 'Resource Exhausted' or 500-level server error."
"General slowness or high latency from the service."
"The build script is broken on the main branch."
"Tests are failing in the CI/CD pipeline."
"Issues with the release management or publishing process."
"User is running out of capacity."
"Problems specific to the sandbox or staging environments."
"Questions about quota limits or requests for increases."
area/extensions
- Description: Issues related to the extension ecosystem, including the marketplace and website.
- Example Issues:
"Bugs related to the extension marketplace website."
"Issues with a specific extension."
"Feature request for the extension ecosystem."
area/documentation
- Description: Issues related to user-facing documentation and other content on the documentation website.
- Example Issues:
"A typo in a README file."
"DOCS: A command is not working as described in the documentation."
"A request for a new documentation page."
"Instructions missing for skills feature"
area/unknown
- Description: Issues that do not clearly fit into any other defined area/ category, or where information is too limited to make a determination. Use this when no other area is appropriate.
- name: 'Apply Labels to Issue'
if: |-
${{ steps.gemini_issue_analysis.outputs.summary != '' }}
env:
REPOSITORY: '${{ github.repository }}'
ISSUE_NUMBER: '${{ github.event.issue.number || github.event.inputs.issue_number }}'
LABELS_OUTPUT: '${{ steps.gemini_issue_analysis.outputs.summary }}'
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
script: |
const rawOutput = process.env.LABELS_OUTPUT;
core.info(`Raw output from model: ${rawOutput}`);
let parsedLabels;
try {
// First, try to parse the raw output as JSON.
parsedLabels = JSON.parse(rawOutput);
} catch (jsonError) {
// If that fails, check for a markdown code block.
core.warning(`Direct JSON parsing failed: ${jsonError.message}. Trying to extract from a markdown block.`);
const jsonMatch = rawOutput.match(/```json\s*([\s\S]*?)\s*```/);
if (jsonMatch && jsonMatch[1]) {
try {
parsedLabels = JSON.parse(jsonMatch[1].trim());
} catch (markdownError) {
core.setFailed(`Failed to parse JSON even after extracting from markdown block: ${markdownError.message}\nRaw output: ${rawOutput}`);
return;
}
} else {
// If no markdown block, try to find a raw JSON object in the output.
// The CLI may include debug/log lines (e.g. telemetry init, YOLO mode)
// before the actual JSON response.
const jsonObjectMatch = rawOutput.match(/(\{[\s\S]*"labels_to_set"[\s\S]*\})/);
if (jsonObjectMatch) {
try {
parsedLabels = JSON.parse(jsonObjectMatch[0]);
} catch (extractError) {
core.setFailed(`Found JSON-like content but failed to parse: ${extractError.message}\nRaw output: ${rawOutput}`);
return;
}
} else {
core.setFailed(`Output is not valid JSON and does not contain extractable JSON.\nRaw output: ${rawOutput}`);
return;
}
}
}
const issueNumber = parseInt(process.env.ISSUE_NUMBER);
const labelsToAdd = parsedLabels.labels_to_set || [];
if (labelsToAdd.length !== 1) {
core.setFailed(`Expected exactly 1 label (area/), but got ${labelsToAdd.length}. Labels: ${labelsToAdd.join(', ')}`);
return;
}
// Set labels based on triage result
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
labels: labelsToAdd
});
core.info(`Successfully added labels for #${issueNumber}: ${labelsToAdd.join(', ')}`);
- name: 'Post Issue Analysis Failure Comment'
if: |-
${{ failure() && steps.gemini_issue_analysis.outcome == 'failure' }}
env:
ISSUE_NUMBER: '${{ github.event.issue.number || github.event.inputs.issue_number }}'
RUN_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
script: |-
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: parseInt(process.env.ISSUE_NUMBER),
body: 'There is a problem with the Gemini CLI issue triaging. Please check the [action logs](${process.env.RUN_URL}) for details.'
})
================================================
FILE: .github/workflows/gemini-scheduled-issue-dedup.yml
================================================
name: '📋 Gemini Scheduled Issue Deduplication'
on:
schedule:
- cron: '0 * * * *' # Runs every hour
workflow_dispatch:
concurrency:
group: '${{ github.workflow }}'
cancel-in-progress: true
defaults:
run:
shell: 'bash'
jobs:
refresh-embeddings:
if: |-
${{ vars.TRIAGE_DEDUPLICATE_ISSUES != '' && github.repository == 'google-gemini/gemini-cli' }}
permissions:
contents: 'read'
id-token: 'write' # Required for WIF, see https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-google-cloud-platform#adding-permissions-settings
issues: 'read'
statuses: 'read'
packages: 'read'
timeout-minutes: 20
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Log in to GitHub Container Registry'
uses: 'docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1' # ratchet:docker/login-action@v3
with:
registry: 'ghcr.io'
username: '${{ github.actor }}'
password: '${{ secrets.GITHUB_TOKEN }}'
- name: 'Run Gemini Issue Deduplication Refresh'
uses: 'google-github-actions/run-gemini-cli@a3bf79042542528e91937b3a3a6fbc4967ee3c31' # ratchet:google-github-actions/run-gemini-cli@v0
id: 'gemini_refresh_embeddings'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
ISSUE_TITLE: '${{ github.event.issue.title }}'
ISSUE_BODY: '${{ github.event.issue.body }}'
ISSUE_NUMBER: '${{ github.event.issue.number }}'
REPOSITORY: '${{ github.repository }}'
FIRESTORE_PROJECT: '${{ vars.FIRESTORE_PROJECT }}'
with:
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
settings: |-
{
"mcpServers": {
"issue_deduplication": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"--network", "host",
"-e", "GITHUB_TOKEN",
"-e", "GEMINI_API_KEY",
"-e", "DATABASE_TYPE",
"-e", "FIRESTORE_DATABASE_ID",
"-e", "GCP_PROJECT",
"-e", "GOOGLE_APPLICATION_CREDENTIALS=/app/gcp-credentials.json",
"-v", "${GOOGLE_APPLICATION_CREDENTIALS}:/app/gcp-credentials.json",
"ghcr.io/google-gemini/gemini-cli-issue-triage@sha256:e3de1523f6c83aabb3c54b76d08940a2bf42febcb789dd2da6f95169641f94d3"
],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}",
"GEMINI_API_KEY": "${{ secrets.GEMINI_API_KEY }}",
"DATABASE_TYPE":"firestore",
"GCP_PROJECT": "${FIRESTORE_PROJECT}",
"FIRESTORE_DATABASE_ID": "(default)",
"GOOGLE_APPLICATION_CREDENTIALS": "${GOOGLE_APPLICATION_CREDENTIALS}"
},
"timeout": 600000
}
},
"maxSessionTurns": 25,
"coreTools": [
"run_shell_command(echo)"
],
"telemetry": {
"enabled": true,
"target": "gcp"
}
}
prompt: |-
## Role
You are a database maintenance assistant for a GitHub issue deduplication system.
## Goal
Your sole responsibility is to refresh the embeddings for all open issues in the repository to ensure the deduplication database is up-to-date.
## Steps
1. **Extract Repository Information:** The repository is ${{ github.repository }}.
2. **Refresh Embeddings:** Call the `refresh` tool with the correct `repo`. Do not use the `force` parameter.
3. **Log Output:** Print the JSON output from the `refresh` tool to the logs.
## Guidelines
- Only use the `refresh` tool.
- Do not attempt to find duplicates or modify any issues.
- Your only task is to call the `refresh` tool and log its output.
================================================
FILE: .github/workflows/gemini-scheduled-issue-triage.yml
================================================
name: '📋 Gemini Scheduled Issue Triage'
on:
issues:
types:
- 'opened'
- 'reopened'
schedule:
- cron: '0 * * * *' # Runs every hour
workflow_dispatch:
concurrency:
group: '${{ github.workflow }}-${{ github.event.number || github.run_id }}'
cancel-in-progress: true
defaults:
run:
shell: 'bash'
permissions:
id-token: 'write'
issues: 'write'
jobs:
triage-issues:
timeout-minutes: 10
if: |-
${{ github.repository == 'google-gemini/gemini-cli' }}
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Generate GitHub App Token'
id: 'generate_token'
uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
permission-issues: 'write'
- name: 'Get issue from event'
if: |-
${{ github.event_name == 'issues' }}
id: 'get_issue_from_event'
env:
ISSUE_EVENT: '${{ toJSON(github.event.issue) }}'
run: |
set -euo pipefail
ISSUE_JSON=$(echo "$ISSUE_EVENT" | jq -c '[{number: .number, title: .title, body: .body}]')
echo "issues_to_triage=${ISSUE_JSON}" >> "${GITHUB_OUTPUT}"
echo "✅ Found issue #${{ github.event.issue.number }} from event to triage! 🎯"
- name: 'Find untriaged issues'
if: |-
${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
id: 'find_issues'
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token }}'
GITHUB_REPOSITORY: '${{ github.repository }}'
run: |-
set -euo pipefail
echo '🔍 Finding issues missing area labels...'
NO_AREA_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue -label:area/core -label:area/agent -label:area/enterprise -label:area/non-interactive -label:area/security -label:area/platform -label:area/extensions -label:area/documentation -label:area/unknown' --limit 100 --json number,title,body)"
echo '🔍 Finding issues missing kind labels...'
NO_KIND_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue -label:kind/bug -label:kind/enhancement -label:kind/customer-issue -label:kind/question' --limit 100 --json number,title,body)"
echo '🏷️ Finding issues missing priority labels...'
NO_PRIORITY_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue -label:priority/p0 -label:priority/p1 -label:priority/p2 -label:priority/p3 -label:priority/unknown' --limit 100 --json number,title,body)"
echo '🔄 Merging and deduplicating issues...'
ISSUES="$(echo "${NO_AREA_ISSUES}" "${NO_KIND_ISSUES}" "${NO_PRIORITY_ISSUES}" | jq -c -s 'add | unique_by(.number)')"
echo '📝 Setting output for GitHub Actions...'
echo "issues_to_triage=${ISSUES}" >> "${GITHUB_OUTPUT}"
ISSUE_COUNT="$(echo "${ISSUES}" | jq 'length')"
echo "✅ Found ${ISSUE_COUNT} unique issues to triage! 🎯"
- name: 'Get Repository Labels'
id: 'get_labels'
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ steps.generate_token.outputs.token }}'
script: |-
const { data: labels } = await github.rest.issues.listLabelsForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
});
const labelNames = labels.map(label => label.name);
core.setOutput('available_labels', labelNames.join(','));
core.info(`Found ${labelNames.length} labels: ${labelNames.join(', ')}`);
return labelNames;
- name: 'Run Gemini Issue Analysis'
if: |-
(steps.get_issue_from_event.outputs.issues_to_triage != '' && steps.get_issue_from_event.outputs.issues_to_triage != '[]') ||
(steps.find_issues.outputs.issues_to_triage != '' && steps.find_issues.outputs.issues_to_triage != '[]')
uses: 'google-github-actions/run-gemini-cli@a3bf79042542528e91937b3a3a6fbc4967ee3c31' # ratchet:google-github-actions/run-gemini-cli@v0
id: 'gemini_issue_analysis'
env:
GITHUB_TOKEN: '' # Do not pass any auth token here since this runs on untrusted inputs
ISSUES_TO_TRIAGE: '${{ steps.get_issue_from_event.outputs.issues_to_triage || steps.find_issues.outputs.issues_to_triage }}'
REPOSITORY: '${{ github.repository }}'
AVAILABLE_LABELS: '${{ steps.get_labels.outputs.available_labels }}'
with:
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
settings: |-
{
"maxSessionTurns": 25,
"coreTools": [
"run_shell_command(echo)"
],
"telemetry": {
"enabled": true,
"target": "gcp"
}
}
prompt: |-
## Role
You are an issue triage assistant. Analyze issues and identify
appropriate labels. Use the available tools to gather information;
do not ask for information to be provided.
## Steps
1. You are only able to use the echo command. Review the available labels in the environment variable: "${AVAILABLE_LABELS}".
2. Check environment variable for issues to triage: $ISSUES_TO_TRIAGE (JSON array of issues)
3. Review the issue title, body and any comments provided in the environment variables.
4. Identify the most relevant labels from the existing labels, specifically focusing on area/*, kind/* and priority/*.
5. Label Policy:
- If the issue already has a kind/ label, do not change it.
- If the issue already has a priority/ label, do not change it.
- If the issue already has an area/ label, do not change it.
- If any of these are missing, select exactly ONE appropriate label for the missing category.
6. Identify other applicable labels based on the issue content, such as status/*, help wanted, good first issue, etc.
7. Give me a single short explanation about why you are selecting each label in the process.
8. Output a JSON array of objects, each containing the issue number
and the labels to add and remove, along with an explanation. For example:
```
[
{
"issue_number": 123,
"labels_to_add": ["area/core", "kind/bug", "priority/p2"],
"labels_to_remove": ["status/need-triage"],
"explanation": "This issue is a UI bug that needs to be addressed with medium priority."
}
]
```
If an issue cannot be classified, do not include it in the output array.
9. For each issue please check if CLI version is present, this is usually in the output of the /about command and will look like 0.1.5
- Anything more than 6 versions older than the most recent should add the status/need-retesting label
10. If you see that the issue doesn't look like it has sufficient information recommend the status/need-information label and leave a comment politely requesting the relevant information, eg.. if repro steps are missing request for repro steps. if version information is missing request for version information into the explanation section below.
11. If you think an issue might be a Priority/P0 do not apply the priority/p0 label. Instead apply a status/manual-triage label and include a note in your explanation.
12. If you are uncertain about a category, use the area/unknown, kind/question, or priority/unknown labels as appropriate. If you are extremely uncertain, apply the status/manual-triage label.
## Guidelines
- Output only valid JSON format
- Do not include any explanation or additional text, just the JSON
- Only use labels that already exist in the repository.
- Do not add comments or modify the issue content.
- Do not remove the following labels maintainer, help wanted or good first issue.
- Triage only the current issue.
- Identify only one area/ label.
- Identify only one kind/ label (Do not apply kind/duplicate or kind/parent-issue)
- Identify only one priority/ label.
- Once you categorize the issue if it needs information bump down the priority by 1 eg.. a p0 would become a p1 a p1 would become a p2. P2 and P3 can stay as is in this scenario.
Categorization Guidelines (Priority):
P0 - Urgent Blocking Issues:
- DO NOT APPLY THIS LABEL AUTOMATICALLY. Use status/manual-triage instead.
- Definition: Urgent, block a significant percentage of the user base, and prevent frequent use of the Gemini CLI.
- This includes core stability blockers (e.g., authentication failures, broken upgrades), critical crashes, and P0 security vulnerabilities.
- Impact: Blocks development or testing for the entire team; Major security vulnerability; Causes data loss or corruption with no workaround; Crashes the application or makes a core feature completely unusable for all or most users.
- Qualifier: Is the main function of the software broken?
P1 - High-Impact Issues:
- Definition: Affect a large number of users, blocking them from using parts of the Gemini CLI, or make the CLI frequently unusable even with workarounds available.
- Impact: A core feature is broken or behaving incorrectly for a large number of users or use cases; Severe performance degradation; No straightforward workaround exists.
- Qualifier: Is a key feature unusable or giving very wrong results?
P2 - Significant Issues:
- Definition: Affect some users significantly, such as preventing the use of certain features or authentication types.
- Can also be issues that many users complain about, causing annoyance or hindering daily use.
- Impact: Affects a non-critical feature or a smaller, specific subset of users; An inconvenient but functional workaround is available; Noticeable UI/UX problems that look unprofessional.
- Qualifier: Is it an annoying but non-blocking problem?
P3 - Low-Impact Issues:
- Definition: Typically usability issues that cause annoyance to a limited user base.
- Includes feature requests that could be addressed in the near future and may be suitable for community contributions.
- Impact: Minor cosmetic issues; An edge-case bug that is very difficult to reproduce and affects a tiny fraction of users.
- Qualifier: Is it a "nice-to-fix" issue?
Categorization Guidelines (Area):
area/agent: Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality
area/core: User Interface, OS Support, Core Functionality
area/documentation: End-user and contributor-facing documentation, website-related
area/enterprise: Telemetry, Policy, Quota / Licensing
area/extensions: Gemini CLI extensions capability
area/non-interactive: GitHub Actions, SDK, 3P Integrations, Shell Scripting, Command line automation
area/platform: Build infra, Release mgmt, Testing, Eval infra, Capacity, Quota mgmt
area/security: security related issues
Additional Context:
- If users are talking about issues where the model gets downgraded from pro to flash then i want you to categorize that as a performance issue.
- This product is designed to use different models eg.. using pro, downgrading to flash etc.
- When users report that they dont expect the model to change those would be categorized as feature requests.
- name: 'Apply Labels to Issues'
if: |-
${{ steps.gemini_issue_analysis.outcome == 'success' &&
steps.gemini_issue_analysis.outputs.summary != '[]' }}
env:
REPOSITORY: '${{ github.repository }}'
LABELS_OUTPUT: '${{ steps.gemini_issue_analysis.outputs.summary }}'
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ steps.generate_token.outputs.token }}'
script: |-
const rawLabels = process.env.LABELS_OUTPUT;
core.info(`Raw labels JSON: ${rawLabels}`);
let parsedLabels;
try {
const jsonMatch = rawLabels.match(/```json\s*([\s\S]*?)\s*```/);
if (!jsonMatch || !jsonMatch[1]) {
throw new Error("Could not find a ```json ... ``` block in the output.");
}
const jsonString = jsonMatch[1].trim();
parsedLabels = JSON.parse(jsonString);
core.info(`Parsed labels JSON: ${JSON.stringify(parsedLabels)}`);
} catch (err) {
core.setFailed(`Failed to parse labels JSON from Gemini output: ${err.message}\nRaw output: ${rawLabels}`);
return;
}
for (const entry of parsedLabels) {
const issueNumber = entry.issue_number;
if (!issueNumber) {
core.info(`Skipping entry with no issue number: ${JSON.stringify(entry)}`);
continue;
}
const labelsToAdd = entry.labels_to_add || [];
labelsToAdd.push('status/bot-triaged');
if (labelsToAdd.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
labels: labelsToAdd
});
const explanation = entry.explanation ? ` - ${entry.explanation}` : '';
core.info(`Successfully added labels for #${issueNumber}: ${labelsToAdd.join(', ')}${explanation}`);
}
if (entry.explanation) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: entry.explanation,
});
}
if ((!entry.labels_to_add || entry.labels_to_add.length === 0) && (!entry.labels_to_remove || entry.labels_to_remove.length === 0)) {
core.info(`No labels to add or remove for #${issueNumber}, leaving as is`);
}
}
================================================
FILE: .github/workflows/gemini-scheduled-pr-triage.yml
================================================
name: 'Gemini Scheduled PR Triage 🚀'
on:
schedule:
- cron: '*/15 * * * *' # Runs every 15 minutes
workflow_dispatch:
jobs:
audit-prs:
timeout-minutes: 15
if: |-
${{ github.repository == 'google-gemini/gemini-cli' }}
permissions:
contents: 'read'
id-token: 'write'
issues: 'write'
pull-requests: 'write'
runs-on: 'ubuntu-latest'
outputs:
prs_needing_comment: '${{ steps.run_triage.outputs.prs_needing_comment }}'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Generate GitHub App Token'
id: 'generate_token'
uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
permission-issues: 'write'
permission-pull-requests: 'write'
- name: 'Run PR Triage Script'
id: 'run_triage'
shell: 'bash'
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token }}'
GITHUB_REPOSITORY: '${{ github.repository }}'
run: |-
./.github/scripts/pr-triage.sh
# If prs_needing_comment is empty, set it to [] explicitly for downstream steps
if [[ -z "$(grep 'prs_needing_comment' "${GITHUB_OUTPUT}" | cut -d'=' -f2-)" ]]; then
echo "prs_needing_comment=[]" >> "${GITHUB_OUTPUT}"
fi
================================================
FILE: .github/workflows/gemini-scheduled-stale-issue-closer.yml
================================================
name: '🔒 Gemini Scheduled Stale Issue Closer'
on:
schedule:
- cron: '0 0 * * 0' # Every Sunday at midnight UTC
workflow_dispatch:
inputs:
dry_run:
description: 'Run in dry-run mode (no changes applied)'
required: false
default: false
type: 'boolean'
concurrency:
group: '${{ github.workflow }}'
cancel-in-progress: true
defaults:
run:
shell: 'bash'
jobs:
close-stale-issues:
if: "github.repository == 'google-gemini/gemini-cli'"
runs-on: 'ubuntu-latest'
permissions:
issues: 'write'
steps:
- name: 'Generate GitHub App Token'
id: 'generate_token'
uses: 'actions/create-github-app-token@v2'
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
permission-issues: 'write'
- name: 'Process Stale Issues'
uses: 'actions/github-script@v7'
env:
DRY_RUN: '${{ inputs.dry_run }}'
with:
github-token: '${{ steps.generate_token.outputs.token }}'
script: |
const dryRun = process.env.DRY_RUN === 'true';
if (dryRun) {
core.info('DRY RUN MODE ENABLED: No changes will be applied.');
}
const batchLabel = 'Stale';
const threeMonthsAgo = new Date();
threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3);
const tenDaysAgo = new Date();
tenDaysAgo.setDate(tenDaysAgo.getDate() - 10);
core.info(`Cutoff date for creation: ${threeMonthsAgo.toISOString()}`);
core.info(`Cutoff date for updates: ${tenDaysAgo.toISOString()}`);
const query = `repo:${context.repo.owner}/${context.repo.repo} is:issue is:open created:<${threeMonthsAgo.toISOString()}`;
core.info(`Searching with query: ${query}`);
const itemsToCheck = await github.paginate(github.rest.search.issuesAndPullRequests, {
q: query,
sort: 'created',
order: 'asc',
per_page: 100
});
core.info(`Found ${itemsToCheck.length} open issues to check.`);
let processedCount = 0;
for (const issue of itemsToCheck) {
const createdAt = new Date(issue.created_at);
const updatedAt = new Date(issue.updated_at);
const reactionCount = issue.reactions.total_count;
// Basic thresholds
if (reactionCount >= 5) {
continue;
}
// Skip if it has a maintainer, help wanted, or Public Roadmap label
const rawLabels = issue.labels.map((l) => l.name);
const lowercaseLabels = rawLabels.map((l) => l.toLowerCase());
if (
lowercaseLabels.some((l) => l.includes('maintainer')) ||
lowercaseLabels.includes('help wanted') ||
rawLabels.includes('🗓️ Public Roadmap')
) {
continue;
}
let isStale = updatedAt < tenDaysAgo;
// If apparently active, check if it's only bot activity
if (!isStale) {
try {
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
per_page: 100,
sort: 'created',
direction: 'desc'
});
const lastHumanComment = comments.data.find(comment => comment.user.type !== 'Bot');
if (lastHumanComment) {
isStale = new Date(lastHumanComment.created_at) < tenDaysAgo;
} else {
// No human comments. Check if creator is human.
if (issue.user.type !== 'Bot') {
isStale = createdAt < tenDaysAgo;
} else {
isStale = true; // Bot created, only bot comments
}
}
} catch (error) {
core.warning(`Failed to fetch comments for issue #${issue.number}: ${error.message}`);
continue;
}
}
if (isStale) {
processedCount++;
const message = `Closing stale issue #${issue.number}: "${issue.title}" (${issue.html_url})`;
core.info(message);
if (!dryRun) {
// Add label
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: [batchLabel]
});
// Add comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: 'Hello! As part of our effort to keep our backlog manageable and focus on the most active issues, we are tidying up older reports.\n\nIt looks like this issue hasn\'t been active for a while, so we are closing it for now. However, if you are still experiencing this bug on the latest stable build, please feel free to comment on this issue or create a new one with updated details.\n\nThank you for your contribution!'
});
// Close issue
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed',
state_reason: 'not_planned'
});
}
}
}
core.info(`\nTotal issues processed: ${processedCount}`);
================================================
FILE: .github/workflows/gemini-scheduled-stale-pr-closer.yml
================================================
name: 'Gemini Scheduled Stale PR Closer'
on:
schedule:
- cron: '0 2 * * *' # Every day at 2 AM UTC
pull_request:
types: ['opened', 'edited']
workflow_dispatch:
inputs:
dry_run:
description: 'Run in dry-run mode'
required: false
default: false
type: 'boolean'
jobs:
close-stale-prs:
if: "github.repository == 'google-gemini/gemini-cli'"
runs-on: 'ubuntu-latest'
permissions:
pull-requests: 'write'
issues: 'write'
steps:
- name: 'Generate GitHub App Token'
id: 'generate_token'
env:
APP_ID: '${{ secrets.APP_ID }}'
if: |-
${{ env.APP_ID != '' }}
uses: 'actions/create-github-app-token@v2'
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
- name: 'Process Stale PRs'
uses: 'actions/github-script@v7'
env:
DRY_RUN: '${{ inputs.dry_run }}'
with:
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
script: |
const dryRun = process.env.DRY_RUN === 'true';
const fourteenDaysAgo = new Date();
fourteenDaysAgo.setDate(fourteenDaysAgo.getDate() - 14);
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
// 1. Fetch maintainers for verification
let maintainerLogins = new Set();
const teams = ['gemini-cli-maintainers', 'gemini-cli-askmode-approvers', 'gemini-cli-docs'];
for (const team_slug of teams) {
try {
const members = await github.paginate(github.rest.teams.listMembersInOrg, {
org: context.repo.owner,
team_slug: team_slug
});
for (const m of members) maintainerLogins.add(m.login.toLowerCase());
core.info(`Successfully fetched ${members.length} team members from ${team_slug}`);
} catch (e) {
// Silently skip if permissions are insufficient; we will rely on author_association
core.debug(`Skipped team fetch for ${team_slug}: ${e.message}`);
}
}
const isMaintainer = async (login, assoc) => {
// Reliably identify maintainers using authorAssociation (provided by GitHub)
// and organization membership (if available).
const isTeamMember = maintainerLogins.has(login.toLowerCase());
const isRepoMaintainer = ['OWNER', 'MEMBER', 'COLLABORATOR'].includes(assoc);
if (isTeamMember || isRepoMaintainer) return true;
// Fallback: Check if user belongs to the 'google' or 'googlers' orgs (requires permission)
try {
const orgs = ['googlers', 'google'];
for (const org of orgs) {
try {
await github.rest.orgs.checkMembershipForUser({ org: org, username: login });
return true;
} catch (e) {
if (e.status !== 404) throw e;
}
}
} catch (e) {
// Gracefully ignore failures here
}
return false;
};
// 2. Fetch all open PRs
let prs = [];
if (context.eventName === 'pull_request') {
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number
});
prs = [pr];
} else {
prs = await github.paginate(github.rest.pulls.list, {
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_
gitextract_3lf9y2ue/ ├── .allstar/ │ └── branch_protection.yaml ├── .editorconfig ├── .gcp/ │ ├── Dockerfile.gemini-code-builder │ └── release-docker.yml ├── .gemini/ │ ├── config.yaml │ └── settings.json ├── .geminiignore ├── .gitattributes ├── .github/ │ ├── CODEOWNERS │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yml │ │ ├── feature_request.yml │ │ └── website_issue.yml │ ├── actions/ │ │ ├── calculate-vars/ │ │ │ └── action.yml │ │ ├── create-pull-request/ │ │ │ └── action.yml │ │ ├── npm-auth-token/ │ │ │ └── action.yml │ │ ├── post-coverage-comment/ │ │ │ └── action.yml │ │ ├── publish-release/ │ │ │ └── action.yml │ │ ├── push-docker/ │ │ │ └── action.yml │ │ ├── push-sandbox/ │ │ │ └── action.yml │ │ ├── run-tests/ │ │ │ └── action.yml │ │ ├── setup-npmrc/ │ │ │ └── action.yml │ │ ├── tag-npm-release/ │ │ │ └── action.yml │ │ └── verify-release/ │ │ └── action.yml │ ├── dependabot.yml │ ├── pull_request_template.md │ ├── scripts/ │ │ ├── backfill-need-triage.cjs │ │ ├── backfill-pr-notification.cjs │ │ ├── pr-triage.sh │ │ └── sync-maintainer-labels.cjs │ └── workflows/ │ ├── chained_e2e.yml │ ├── ci.yml │ ├── community-report.yml │ ├── deflake.yml │ ├── docs-page-action.yml │ ├── docs-rebuild.yml │ ├── eval.yml │ ├── evals-nightly.yml │ ├── gemini-automated-issue-dedup.yml │ ├── gemini-automated-issue-triage.yml │ ├── gemini-scheduled-issue-dedup.yml │ ├── gemini-scheduled-issue-triage.yml │ ├── gemini-scheduled-pr-triage.yml │ ├── gemini-scheduled-stale-issue-closer.yml │ ├── gemini-scheduled-stale-pr-closer.yml │ ├── gemini-self-assign-issue.yml │ ├── issue-opened-labeler.yml │ ├── label-backlog-child-issues.yml │ ├── label-workstream-rollup.yml │ ├── links.yml │ ├── no-response.yml │ ├── pr-contribution-guidelines-notifier.yml │ ├── pr-rate-limiter.yaml │ ├── release-change-tags.yml │ ├── release-manual.yml │ ├── release-nightly.yml │ ├── release-notes.yml │ ├── release-patch-0-from-comment.yml │ ├── release-patch-1-create-pr.yml │ ├── release-patch-2-trigger.yml │ ├── release-patch-3-release.yml │ ├── release-promote.yml │ ├── release-rollback.yml │ ├── release-sandbox.yml │ ├── smoke-test.yml │ ├── stale.yml │ ├── test-build-binary.yml │ ├── trigger_e2e.yml │ ├── unassign-inactive-assignees.yml │ └── verify-release.yml ├── .gitignore ├── .husky/ │ └── pre-commit ├── .lycheeignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc.json ├── .vscode/ │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── .yamllint.yml ├── CONTRIBUTING.md ├── Dockerfile ├── GEMINI.md ├── LICENSE ├── Makefile ├── README.md ├── ROADMAP.md ├── SECURITY.md ├── docs/ │ ├── admin/ │ │ └── enterprise-controls.md │ ├── changelogs/ │ │ ├── index.md │ │ ├── latest.md │ │ └── preview.md │ ├── cli/ │ │ ├── checkpointing.md │ │ ├── cli-reference.md │ │ ├── creating-skills.md │ │ ├── custom-commands.md │ │ ├── enterprise.md │ │ ├── gemini-ignore.md │ │ ├── gemini-md.md │ │ ├── generation-settings.md │ │ ├── headless.md │ │ ├── model-routing.md │ │ ├── model-steering.md │ │ ├── model.md │ │ ├── notifications.md │ │ ├── plan-mode.md │ │ ├── rewind.md │ │ ├── sandbox.md │ │ ├── session-management.md │ │ ├── settings.md │ │ ├── skills.md │ │ ├── system-prompt.md │ │ ├── telemetry.md │ │ ├── themes.md │ │ ├── token-caching.md │ │ ├── trusted-folders.md │ │ └── tutorials/ │ │ ├── automation.md │ │ ├── file-management.md │ │ ├── mcp-setup.md │ │ ├── memory-management.md │ │ ├── plan-mode-steering.md │ │ ├── session-management.md │ │ ├── shell-commands.md │ │ ├── skills-getting-started.md │ │ ├── task-planning.md │ │ └── web-tools.md │ ├── core/ │ │ ├── index.md │ │ ├── local-model-routing.md │ │ ├── remote-agents.md │ │ └── subagents.md │ ├── examples/ │ │ └── proxy-script.md │ ├── extensions/ │ │ ├── best-practices.md │ │ ├── index.md │ │ ├── reference.md │ │ ├── releasing.md │ │ └── writing-extensions.md │ ├── get-started/ │ │ ├── authentication.md │ │ ├── examples.md │ │ ├── gemini-3.md │ │ ├── index.md │ │ └── installation.md │ ├── hooks/ │ │ ├── best-practices.md │ │ ├── index.md │ │ ├── reference.md │ │ └── writing-hooks.md │ ├── ide-integration/ │ │ ├── ide-companion-spec.md │ │ └── index.md │ ├── index.md │ ├── integration-tests.md │ ├── issue-and-pr-automation.md │ ├── local-development.md │ ├── mermaid/ │ │ ├── context.mmd │ │ └── render-path.mmd │ ├── npm.md │ ├── redirects.json │ ├── reference/ │ │ ├── commands.md │ │ ├── configuration.md │ │ ├── keyboard-shortcuts.md │ │ ├── memport.md │ │ ├── policy-engine.md │ │ └── tools.md │ ├── release-confidence.md │ ├── releases.md │ ├── resources/ │ │ ├── faq.md │ │ ├── quota-and-pricing.md │ │ ├── tos-privacy.md │ │ ├── troubleshooting.md │ │ └── uninstall.md │ ├── sidebar.json │ └── tools/ │ ├── activate-skill.md │ ├── ask-user.md │ ├── file-system.md │ ├── internal-docs.md │ ├── mcp-server.md │ ├── memory.md │ ├── planning.md │ ├── shell.md │ ├── todos.md │ ├── web-fetch.md │ └── web-search.md ├── esbuild.config.js ├── eslint.config.js ├── evals/ │ ├── README.md │ ├── answer-vs-act.eval.ts │ ├── app-test-helper.ts │ ├── ask_user.eval.ts │ ├── automated-tool-use.eval.ts │ ├── concurrency-safety.eval.ts │ ├── edit-locations-eval.eval.ts │ ├── frugalReads.eval.ts │ ├── frugalSearch.eval.ts │ ├── generalist_agent.eval.ts │ ├── generalist_delegation.eval.ts │ ├── gitRepo.eval.ts │ ├── grep_search_functionality.eval.ts │ ├── hierarchical_memory.eval.ts │ ├── interactive-hang.eval.ts │ ├── model_steering.eval.ts │ ├── plan_mode.eval.ts │ ├── save_memory.eval.ts │ ├── shell-efficiency.eval.ts │ ├── subagents.eval.ts │ ├── test-helper.ts │ ├── tool_output_masking.eval.ts │ ├── tracker.eval.ts │ ├── validation_fidelity.eval.ts │ ├── validation_fidelity_pre_existing_errors.eval.ts │ └── vitest.config.ts ├── integration-tests/ │ ├── acp-env-auth.test.ts │ ├── acp-telemetry.test.ts │ ├── api-resilience.responses │ ├── api-resilience.test.ts │ ├── browser-agent.cleanup.responses │ ├── browser-agent.confirmation.responses │ ├── browser-agent.interaction.responses │ ├── browser-agent.navigate-snapshot.responses │ ├── browser-agent.screenshot.responses │ ├── browser-agent.sequential.responses │ ├── browser-agent.test.ts │ ├── browser-policy.responses │ ├── browser-policy.test.ts │ ├── checkpointing.test.ts │ ├── clipboard-linux.test.ts │ ├── concurrency-limit.responses │ ├── concurrency-limit.test.ts │ ├── context-compress-interactive.compress-empty.responses │ ├── context-compress-interactive.compress-failure.responses │ ├── context-compress-interactive.compress.responses │ ├── context-compress-interactive.test.ts │ ├── ctrl-c-exit.test.ts │ ├── deprecation-warnings.test.ts │ ├── extensions-install.test.ts │ ├── extensions-reload.test.ts │ ├── file-system-interactive.test.ts │ ├── file-system.test.ts │ ├── flicker-detector.max-height.responses │ ├── flicker.test.ts │ ├── globalSetup.ts │ ├── google_web_search.test.ts │ ├── hooks-agent-flow-multistep.responses │ ├── hooks-agent-flow.responses │ ├── hooks-agent-flow.test.ts │ ├── hooks-system.after-agent.responses │ ├── hooks-system.after-model.responses │ ├── hooks-system.after-tool-context.responses │ ├── hooks-system.allow-tool.responses │ ├── hooks-system.before-agent.responses │ ├── hooks-system.before-model.responses │ ├── hooks-system.before-tool-selection.responses │ ├── hooks-system.before-tool-stop.responses │ ├── hooks-system.block-tool.responses │ ├── hooks-system.compress-auto.responses │ ├── hooks-system.disabled-via-command.responses │ ├── hooks-system.disabled-via-settings.responses │ ├── hooks-system.error-handling.responses │ ├── hooks-system.input-modification.responses │ ├── hooks-system.input-validation.responses │ ├── hooks-system.multiple-events.responses │ ├── hooks-system.notification.responses │ ├── hooks-system.sequential-execution.responses │ ├── hooks-system.session-clear.responses │ ├── hooks-system.session-startup.responses │ ├── hooks-system.tail-tool-call.responses │ ├── hooks-system.telemetry.responses │ ├── hooks-system.test.ts │ ├── json-output.error.responses │ ├── json-output.france.responses │ ├── json-output.session-id.responses │ ├── json-output.test.ts │ ├── list_directory.test.ts │ ├── mcp_server_cyclic_schema.test.ts │ ├── mixed-input-crash.test.ts │ ├── parallel-tools.responses │ ├── parallel-tools.test.ts │ ├── plan-mode.test.ts │ ├── policy-headless-readonly.responses │ ├── policy-headless-shell-allowed.responses │ ├── policy-headless-shell-denied.responses │ ├── policy-headless.test.ts │ ├── read_many_files.test.ts │ ├── replace.test.ts │ ├── resume_repro.responses │ ├── resume_repro.test.ts │ ├── ripgrep-real.test.ts │ ├── run_shell_command.test.ts │ ├── simple-mcp-server.test.ts │ ├── skill-creator-scripts.test.ts │ ├── skill-creator-vulnerabilities.test.ts │ ├── stdin-context.test.ts │ ├── stdout-stderr-output-error.responses │ ├── stdout-stderr-output.responses │ ├── stdout-stderr-output.test.ts │ ├── symlink-install.test.ts │ ├── telemetry.test.ts │ ├── test-helper.ts │ ├── test-mcp-server.ts │ ├── tsconfig.json │ ├── user-policy.responses │ ├── user-policy.test.ts │ ├── utf-bom-encoding.test.ts │ ├── vitest.config.ts │ └── write_file.test.ts ├── package.json ├── packages/ │ ├── a2a-server/ │ │ ├── GEMINI.md │ │ ├── README.md │ │ ├── development-extension-rfc.md │ │ ├── index.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── agent/ │ │ │ │ ├── executor.test.ts │ │ │ │ ├── executor.ts │ │ │ │ ├── task-event-driven.test.ts │ │ │ │ ├── task.test.ts │ │ │ │ └── task.ts │ │ │ ├── commands/ │ │ │ │ ├── command-registry.test.ts │ │ │ │ ├── command-registry.ts │ │ │ │ ├── extensions.test.ts │ │ │ │ ├── extensions.ts │ │ │ │ ├── init.test.ts │ │ │ │ ├── init.ts │ │ │ │ ├── memory.test.ts │ │ │ │ ├── memory.ts │ │ │ │ ├── restore.test.ts │ │ │ │ ├── restore.ts │ │ │ │ └── types.ts │ │ │ ├── config/ │ │ │ │ ├── config.test.ts │ │ │ │ ├── config.ts │ │ │ │ ├── extension.ts │ │ │ │ ├── settings.test.ts │ │ │ │ └── settings.ts │ │ │ ├── http/ │ │ │ │ ├── app.test.ts │ │ │ │ ├── app.ts │ │ │ │ ├── endpoints.test.ts │ │ │ │ ├── requestStorage.ts │ │ │ │ └── server.ts │ │ │ ├── index.ts │ │ │ ├── persistence/ │ │ │ │ ├── gcs.test.ts │ │ │ │ └── gcs.ts │ │ │ ├── types.ts │ │ │ └── utils/ │ │ │ ├── executor_utils.ts │ │ │ ├── logger.ts │ │ │ └── testing_utils.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ ├── cli/ │ │ ├── GEMINI.md │ │ ├── examples/ │ │ │ ├── ask-user-dialog-demo.tsx │ │ │ └── scrollable-list-demo.tsx │ │ ├── index.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── __snapshots__/ │ │ │ │ └── nonInteractiveCli.test.ts.snap │ │ │ ├── acp/ │ │ │ │ ├── acpClient.test.ts │ │ │ │ ├── acpClient.ts │ │ │ │ ├── acpErrors.test.ts │ │ │ │ ├── acpErrors.ts │ │ │ │ ├── acpResume.test.ts │ │ │ │ ├── commandHandler.test.ts │ │ │ │ ├── commandHandler.ts │ │ │ │ ├── commands/ │ │ │ │ │ ├── commandRegistry.ts │ │ │ │ │ ├── extensions.ts │ │ │ │ │ ├── init.ts │ │ │ │ │ ├── memory.ts │ │ │ │ │ ├── restore.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── fileSystemService.test.ts │ │ │ │ └── fileSystemService.ts │ │ │ ├── commands/ │ │ │ │ ├── extensions/ │ │ │ │ │ ├── configure.test.ts │ │ │ │ │ ├── configure.ts │ │ │ │ │ ├── disable.test.ts │ │ │ │ │ ├── disable.ts │ │ │ │ │ ├── enable.test.ts │ │ │ │ │ ├── enable.ts │ │ │ │ │ ├── examples/ │ │ │ │ │ │ ├── custom-commands/ │ │ │ │ │ │ │ ├── .gitignore │ │ │ │ │ │ │ ├── commands/ │ │ │ │ │ │ │ │ └── fs/ │ │ │ │ │ │ │ │ └── grep-code.toml │ │ │ │ │ │ │ └── gemini-extension.json │ │ │ │ │ │ ├── exclude-tools/ │ │ │ │ │ │ │ ├── .gitignore │ │ │ │ │ │ │ └── gemini-extension.json │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ ├── .gitignore │ │ │ │ │ │ │ ├── gemini-extension.json │ │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ │ └── hooks.json │ │ │ │ │ │ │ └── scripts/ │ │ │ │ │ │ │ └── on-start.js │ │ │ │ │ │ ├── mcp-server/ │ │ │ │ │ │ │ ├── .gitignore │ │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ │ ├── example.js │ │ │ │ │ │ │ ├── gemini-extension.json │ │ │ │ │ │ │ └── package.json │ │ │ │ │ │ ├── policies/ │ │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ │ ├── gemini-extension.json │ │ │ │ │ │ │ └── policies/ │ │ │ │ │ │ │ └── policies.toml │ │ │ │ │ │ ├── skills/ │ │ │ │ │ │ │ ├── .gitignore │ │ │ │ │ │ │ ├── gemini-extension.json │ │ │ │ │ │ │ └── skills/ │ │ │ │ │ │ │ └── greeter/ │ │ │ │ │ │ │ └── SKILL.md │ │ │ │ │ │ └── themes-example/ │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ └── gemini-extension.json │ │ │ │ │ ├── install.test.ts │ │ │ │ │ ├── install.ts │ │ │ │ │ ├── link.test.ts │ │ │ │ │ ├── link.ts │ │ │ │ │ ├── list.test.ts │ │ │ │ │ ├── list.ts │ │ │ │ │ ├── new.test.ts │ │ │ │ │ ├── new.ts │ │ │ │ │ ├── uninstall.test.ts │ │ │ │ │ ├── uninstall.ts │ │ │ │ │ ├── update.test.ts │ │ │ │ │ ├── update.ts │ │ │ │ │ ├── utils.ts │ │ │ │ │ ├── validate.test.ts │ │ │ │ │ └── validate.ts │ │ │ │ ├── extensions.test.tsx │ │ │ │ ├── extensions.tsx │ │ │ │ ├── hooks/ │ │ │ │ │ ├── migrate.test.ts │ │ │ │ │ └── migrate.ts │ │ │ │ ├── hooks.tsx │ │ │ │ ├── mcp/ │ │ │ │ │ ├── add.test.ts │ │ │ │ │ ├── add.ts │ │ │ │ │ ├── enableDisable.ts │ │ │ │ │ ├── list.test.ts │ │ │ │ │ ├── list.ts │ │ │ │ │ ├── remove.test.ts │ │ │ │ │ └── remove.ts │ │ │ │ ├── mcp.test.ts │ │ │ │ ├── mcp.ts │ │ │ │ ├── skills/ │ │ │ │ │ ├── disable.test.ts │ │ │ │ │ ├── disable.ts │ │ │ │ │ ├── enable.test.ts │ │ │ │ │ ├── enable.ts │ │ │ │ │ ├── install.test.ts │ │ │ │ │ ├── install.ts │ │ │ │ │ ├── link.test.ts │ │ │ │ │ ├── link.ts │ │ │ │ │ ├── list.test.ts │ │ │ │ │ ├── list.ts │ │ │ │ │ ├── uninstall.test.ts │ │ │ │ │ └── uninstall.ts │ │ │ │ ├── skills.test.tsx │ │ │ │ ├── skills.tsx │ │ │ │ ├── utils.test.ts │ │ │ │ └── utils.ts │ │ │ ├── config/ │ │ │ │ ├── auth.test.ts │ │ │ │ ├── auth.ts │ │ │ │ ├── config.integration.test.ts │ │ │ │ ├── config.test.ts │ │ │ │ ├── config.ts │ │ │ │ ├── extension-manager-agents.test.ts │ │ │ │ ├── extension-manager-hydration.test.ts │ │ │ │ ├── extension-manager-permissions.test.ts │ │ │ │ ├── extension-manager-scope.test.ts │ │ │ │ ├── extension-manager-skills.test.ts │ │ │ │ ├── extension-manager-themes.spec.ts │ │ │ │ ├── extension-manager.test.ts │ │ │ │ ├── extension-manager.ts │ │ │ │ ├── extension.test.ts │ │ │ │ ├── extension.ts │ │ │ │ ├── extensionRegistryClient.test.ts │ │ │ │ ├── extensionRegistryClient.ts │ │ │ │ ├── extensions/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── consent.test.ts.snap │ │ │ │ │ ├── consent.test.ts │ │ │ │ │ ├── consent.ts │ │ │ │ │ ├── extensionEnablement.test.ts │ │ │ │ │ ├── extensionEnablement.ts │ │ │ │ │ ├── extensionSettings.test.ts │ │ │ │ │ ├── extensionSettings.ts │ │ │ │ │ ├── extensionUpdates.test.ts │ │ │ │ │ ├── github.test.ts │ │ │ │ │ ├── github.ts │ │ │ │ │ ├── github_fetch.test.ts │ │ │ │ │ ├── github_fetch.ts │ │ │ │ │ ├── storage.test.ts │ │ │ │ │ ├── storage.ts │ │ │ │ │ ├── update.test.ts │ │ │ │ │ ├── update.ts │ │ │ │ │ ├── variableSchema.ts │ │ │ │ │ ├── variables.test.ts │ │ │ │ │ └── variables.ts │ │ │ │ ├── footerItems.test.ts │ │ │ │ ├── footerItems.ts │ │ │ │ ├── mcp/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── mcpServerEnablement.test.ts │ │ │ │ │ └── mcpServerEnablement.ts │ │ │ │ ├── policy-engine.integration.test.ts │ │ │ │ ├── policy.test.ts │ │ │ │ ├── policy.ts │ │ │ │ ├── sandboxConfig.test.ts │ │ │ │ ├── sandboxConfig.ts │ │ │ │ ├── settingPaths.test.ts │ │ │ │ ├── settingPaths.ts │ │ │ │ ├── settings-validation.test.ts │ │ │ │ ├── settings-validation.ts │ │ │ │ ├── settings.test.ts │ │ │ │ ├── settings.ts │ │ │ │ ├── settingsSchema.test.ts │ │ │ │ ├── settingsSchema.ts │ │ │ │ ├── settings_repro.test.ts │ │ │ │ ├── settings_validation_warning.test.ts │ │ │ │ ├── trustedFolders.test.ts │ │ │ │ ├── trustedFolders.ts │ │ │ │ └── workspace-policy-cli.test.ts │ │ │ ├── core/ │ │ │ │ ├── auth.test.ts │ │ │ │ ├── auth.ts │ │ │ │ ├── initializer.test.ts │ │ │ │ ├── initializer.ts │ │ │ │ ├── theme.test.ts │ │ │ │ └── theme.ts │ │ │ ├── deferred.test.ts │ │ │ ├── deferred.ts │ │ │ ├── gemini.test.tsx │ │ │ ├── gemini.tsx │ │ │ ├── gemini_cleanup.test.tsx │ │ │ ├── integration-tests/ │ │ │ │ └── modelSteering.test.tsx │ │ │ ├── interactiveCli.tsx │ │ │ ├── nonInteractiveCli.test.ts │ │ │ ├── nonInteractiveCli.ts │ │ │ ├── nonInteractiveCliCommands.ts │ │ │ ├── patches/ │ │ │ │ └── is-in-ci.ts │ │ │ ├── services/ │ │ │ │ ├── BuiltinCommandLoader.test.ts │ │ │ │ ├── BuiltinCommandLoader.ts │ │ │ │ ├── CommandService.test.ts │ │ │ │ ├── CommandService.ts │ │ │ │ ├── FileCommandLoader.test.ts │ │ │ │ ├── FileCommandLoader.ts │ │ │ │ ├── McpPromptLoader.test.ts │ │ │ │ ├── McpPromptLoader.ts │ │ │ │ ├── SkillCommandLoader.test.ts │ │ │ │ ├── SkillCommandLoader.ts │ │ │ │ ├── SlashCommandConflictHandler.test.ts │ │ │ │ ├── SlashCommandConflictHandler.ts │ │ │ │ ├── SlashCommandResolver.test.ts │ │ │ │ ├── SlashCommandResolver.ts │ │ │ │ ├── prompt-processors/ │ │ │ │ │ ├── argumentProcessor.test.ts │ │ │ │ │ ├── argumentProcessor.ts │ │ │ │ │ ├── atFileProcessor.test.ts │ │ │ │ │ ├── atFileProcessor.ts │ │ │ │ │ ├── injectionParser.test.ts │ │ │ │ │ ├── injectionParser.ts │ │ │ │ │ ├── shellProcessor.test.ts │ │ │ │ │ ├── shellProcessor.ts │ │ │ │ │ └── types.ts │ │ │ │ └── types.ts │ │ │ ├── test-utils/ │ │ │ │ ├── AppRig.test.tsx │ │ │ │ ├── AppRig.tsx │ │ │ │ ├── MockShellExecutionService.ts │ │ │ │ ├── async.ts │ │ │ │ ├── createExtension.ts │ │ │ │ ├── customMatchers.ts │ │ │ │ ├── fixtures/ │ │ │ │ │ ├── simple.responses │ │ │ │ │ └── steering.responses │ │ │ │ ├── mockCommandContext.test.ts │ │ │ │ ├── mockCommandContext.ts │ │ │ │ ├── mockConfig.ts │ │ │ │ ├── mockDebugLogger.ts │ │ │ │ ├── persistentStateFake.ts │ │ │ │ ├── render.test.tsx │ │ │ │ ├── render.tsx │ │ │ │ ├── settings.ts │ │ │ │ └── svg.ts │ │ │ ├── ui/ │ │ │ │ ├── App.test.tsx │ │ │ │ ├── App.tsx │ │ │ │ ├── AppContainer.test.tsx │ │ │ │ ├── AppContainer.tsx │ │ │ │ ├── IdeIntegrationNudge.test.tsx │ │ │ │ ├── IdeIntegrationNudge.tsx │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── App.test.tsx.snap │ │ │ │ ├── auth/ │ │ │ │ │ ├── ApiAuthDialog.test.tsx │ │ │ │ │ ├── ApiAuthDialog.tsx │ │ │ │ │ ├── AuthDialog.test.tsx │ │ │ │ │ ├── AuthDialog.tsx │ │ │ │ │ ├── AuthInProgress.test.tsx │ │ │ │ │ ├── AuthInProgress.tsx │ │ │ │ │ ├── BannedAccountDialog.test.tsx │ │ │ │ │ ├── BannedAccountDialog.tsx │ │ │ │ │ ├── LoginWithGoogleRestartDialog.test.tsx │ │ │ │ │ ├── LoginWithGoogleRestartDialog.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ ├── ApiAuthDialog.test.tsx.snap │ │ │ │ │ │ ├── AuthDialog.test.tsx.snap │ │ │ │ │ │ ├── BannedAccountDialog.test.tsx.snap │ │ │ │ │ │ └── LoginWithGoogleRestartDialog.test.tsx.snap │ │ │ │ │ ├── useAuth.test.tsx │ │ │ │ │ └── useAuth.ts │ │ │ │ ├── colors.ts │ │ │ │ ├── commands/ │ │ │ │ │ ├── aboutCommand.test.ts │ │ │ │ │ ├── aboutCommand.ts │ │ │ │ │ ├── agentsCommand.test.ts │ │ │ │ │ ├── agentsCommand.ts │ │ │ │ │ ├── authCommand.test.ts │ │ │ │ │ ├── authCommand.ts │ │ │ │ │ ├── bugCommand.test.ts │ │ │ │ │ ├── bugCommand.ts │ │ │ │ │ ├── chatCommand.test.ts │ │ │ │ │ ├── chatCommand.ts │ │ │ │ │ ├── clearCommand.test.ts │ │ │ │ │ ├── clearCommand.ts │ │ │ │ │ ├── commandsCommand.test.ts │ │ │ │ │ ├── commandsCommand.ts │ │ │ │ │ ├── compressCommand.test.ts │ │ │ │ │ ├── compressCommand.ts │ │ │ │ │ ├── copyCommand.test.ts │ │ │ │ │ ├── copyCommand.ts │ │ │ │ │ ├── corgiCommand.test.ts │ │ │ │ │ ├── corgiCommand.ts │ │ │ │ │ ├── directoryCommand.test.tsx │ │ │ │ │ ├── directoryCommand.tsx │ │ │ │ │ ├── docsCommand.test.ts │ │ │ │ │ ├── docsCommand.ts │ │ │ │ │ ├── editorCommand.test.ts │ │ │ │ │ ├── editorCommand.ts │ │ │ │ │ ├── extensionsCommand.test.ts │ │ │ │ │ ├── extensionsCommand.ts │ │ │ │ │ ├── footerCommand.tsx │ │ │ │ │ ├── helpCommand.test.ts │ │ │ │ │ ├── helpCommand.ts │ │ │ │ │ ├── hooksCommand.test.ts │ │ │ │ │ ├── hooksCommand.ts │ │ │ │ │ ├── ideCommand.test.ts │ │ │ │ │ ├── ideCommand.ts │ │ │ │ │ ├── initCommand.test.ts │ │ │ │ │ ├── initCommand.ts │ │ │ │ │ ├── mcpCommand.test.ts │ │ │ │ │ ├── mcpCommand.ts │ │ │ │ │ ├── memoryCommand.test.ts │ │ │ │ │ ├── memoryCommand.ts │ │ │ │ │ ├── modelCommand.test.ts │ │ │ │ │ ├── modelCommand.ts │ │ │ │ │ ├── oncallCommand.tsx │ │ │ │ │ ├── permissionsCommand.test.ts │ │ │ │ │ ├── permissionsCommand.ts │ │ │ │ │ ├── planCommand.test.ts │ │ │ │ │ ├── planCommand.ts │ │ │ │ │ ├── policiesCommand.test.ts │ │ │ │ │ ├── policiesCommand.ts │ │ │ │ │ ├── privacyCommand.test.ts │ │ │ │ │ ├── privacyCommand.ts │ │ │ │ │ ├── profileCommand.ts │ │ │ │ │ ├── quitCommand.test.ts │ │ │ │ │ ├── quitCommand.ts │ │ │ │ │ ├── restoreCommand.test.ts │ │ │ │ │ ├── restoreCommand.ts │ │ │ │ │ ├── resumeCommand.test.ts │ │ │ │ │ ├── resumeCommand.ts │ │ │ │ │ ├── rewindCommand.test.tsx │ │ │ │ │ ├── rewindCommand.tsx │ │ │ │ │ ├── settingsCommand.test.ts │ │ │ │ │ ├── settingsCommand.ts │ │ │ │ │ ├── setupGithubCommand.test.ts │ │ │ │ │ ├── setupGithubCommand.ts │ │ │ │ │ ├── shellsCommand.test.ts │ │ │ │ │ ├── shellsCommand.ts │ │ │ │ │ ├── shortcutsCommand.ts │ │ │ │ │ ├── skillsCommand.test.ts │ │ │ │ │ ├── skillsCommand.ts │ │ │ │ │ ├── statsCommand.test.ts │ │ │ │ │ ├── statsCommand.ts │ │ │ │ │ ├── terminalSetupCommand.test.ts │ │ │ │ │ ├── terminalSetupCommand.ts │ │ │ │ │ ├── themeCommand.test.ts │ │ │ │ │ ├── themeCommand.ts │ │ │ │ │ ├── toolsCommand.test.ts │ │ │ │ │ ├── toolsCommand.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── upgradeCommand.test.ts │ │ │ │ │ ├── upgradeCommand.ts │ │ │ │ │ └── vimCommand.ts │ │ │ │ ├── components/ │ │ │ │ │ ├── AboutBox.test.tsx │ │ │ │ │ ├── AboutBox.tsx │ │ │ │ │ ├── AdminSettingsChangedDialog.test.tsx │ │ │ │ │ ├── AdminSettingsChangedDialog.tsx │ │ │ │ │ ├── AgentConfigDialog.test.tsx │ │ │ │ │ ├── AgentConfigDialog.tsx │ │ │ │ │ ├── AlternateBufferQuittingDisplay.test.tsx │ │ │ │ │ ├── AlternateBufferQuittingDisplay.tsx │ │ │ │ │ ├── AnsiOutput.test.tsx │ │ │ │ │ ├── AnsiOutput.tsx │ │ │ │ │ ├── AppHeader.test.tsx │ │ │ │ │ ├── AppHeader.tsx │ │ │ │ │ ├── AppHeaderIcon.test.tsx │ │ │ │ │ ├── ApprovalModeIndicator.test.tsx │ │ │ │ │ ├── ApprovalModeIndicator.tsx │ │ │ │ │ ├── AsciiArt.ts │ │ │ │ │ ├── AskUserDialog.test.tsx │ │ │ │ │ ├── AskUserDialog.tsx │ │ │ │ │ ├── BackgroundShellDisplay.test.tsx │ │ │ │ │ ├── BackgroundShellDisplay.tsx │ │ │ │ │ ├── Banner.test.tsx │ │ │ │ │ ├── Banner.tsx │ │ │ │ │ ├── BubblingRegression.test.tsx │ │ │ │ │ ├── Checklist.test.tsx │ │ │ │ │ ├── Checklist.tsx │ │ │ │ │ ├── ChecklistItem.test.tsx │ │ │ │ │ ├── ChecklistItem.tsx │ │ │ │ │ ├── CliSpinner.test.tsx │ │ │ │ │ ├── CliSpinner.tsx │ │ │ │ │ ├── ColorsDisplay.test.tsx │ │ │ │ │ ├── ColorsDisplay.tsx │ │ │ │ │ ├── Composer.test.tsx │ │ │ │ │ ├── Composer.tsx │ │ │ │ │ ├── ConfigExtensionDialog.tsx │ │ │ │ │ ├── ConfigInitDisplay.test.tsx │ │ │ │ │ ├── ConfigInitDisplay.tsx │ │ │ │ │ ├── ConsentPrompt.test.tsx │ │ │ │ │ ├── ConsentPrompt.tsx │ │ │ │ │ ├── ConsoleSummaryDisplay.test.tsx │ │ │ │ │ ├── ConsoleSummaryDisplay.tsx │ │ │ │ │ ├── ContextSummaryDisplay.test.tsx │ │ │ │ │ ├── ContextSummaryDisplay.tsx │ │ │ │ │ ├── ContextUsageDisplay.test.tsx │ │ │ │ │ ├── ContextUsageDisplay.tsx │ │ │ │ │ ├── CopyModeWarning.test.tsx │ │ │ │ │ ├── CopyModeWarning.tsx │ │ │ │ │ ├── DebugProfiler.test.tsx │ │ │ │ │ ├── DebugProfiler.tsx │ │ │ │ │ ├── DetailedMessagesDisplay.test.tsx │ │ │ │ │ ├── DetailedMessagesDisplay.tsx │ │ │ │ │ ├── DialogManager.test.tsx │ │ │ │ │ ├── DialogManager.tsx │ │ │ │ │ ├── EditorSettingsDialog.test.tsx │ │ │ │ │ ├── EditorSettingsDialog.tsx │ │ │ │ │ ├── EmptyWalletDialog.test.tsx │ │ │ │ │ ├── EmptyWalletDialog.tsx │ │ │ │ │ ├── ExitPlanModeDialog.test.tsx │ │ │ │ │ ├── ExitPlanModeDialog.tsx │ │ │ │ │ ├── ExitWarning.test.tsx │ │ │ │ │ ├── ExitWarning.tsx │ │ │ │ │ ├── FolderTrustDialog.test.tsx │ │ │ │ │ ├── FolderTrustDialog.tsx │ │ │ │ │ ├── Footer.test.tsx │ │ │ │ │ ├── Footer.tsx │ │ │ │ │ ├── FooterConfigDialog.test.tsx │ │ │ │ │ ├── FooterConfigDialog.tsx │ │ │ │ │ ├── GeminiRespondingSpinner.test.tsx │ │ │ │ │ ├── GeminiRespondingSpinner.tsx │ │ │ │ │ ├── GeminiSpinner.tsx │ │ │ │ │ ├── GradientRegression.test.tsx │ │ │ │ │ ├── Header.test.tsx │ │ │ │ │ ├── Header.tsx │ │ │ │ │ ├── Help.test.tsx │ │ │ │ │ ├── Help.tsx │ │ │ │ │ ├── HistoryItemDisplay.test.tsx │ │ │ │ │ ├── HistoryItemDisplay.tsx │ │ │ │ │ ├── HookStatusDisplay.test.tsx │ │ │ │ │ ├── HookStatusDisplay.tsx │ │ │ │ │ ├── HooksDialog.test.tsx │ │ │ │ │ ├── HooksDialog.tsx │ │ │ │ │ ├── IdeTrustChangeDialog.test.tsx │ │ │ │ │ ├── IdeTrustChangeDialog.tsx │ │ │ │ │ ├── InputPrompt.test.tsx │ │ │ │ │ ├── InputPrompt.tsx │ │ │ │ │ ├── LoadingIndicator.test.tsx │ │ │ │ │ ├── LoadingIndicator.tsx │ │ │ │ │ ├── LogoutConfirmationDialog.test.tsx │ │ │ │ │ ├── LogoutConfirmationDialog.tsx │ │ │ │ │ ├── LoopDetectionConfirmation.test.tsx │ │ │ │ │ ├── LoopDetectionConfirmation.tsx │ │ │ │ │ ├── MainContent.test.tsx │ │ │ │ │ ├── MainContent.tsx │ │ │ │ │ ├── MemoryUsageDisplay.test.tsx │ │ │ │ │ ├── MemoryUsageDisplay.tsx │ │ │ │ │ ├── ModelDialog.test.tsx │ │ │ │ │ ├── ModelDialog.tsx │ │ │ │ │ ├── ModelStatsDisplay.test.tsx │ │ │ │ │ ├── ModelStatsDisplay.tsx │ │ │ │ │ ├── MultiFolderTrustDialog.test.tsx │ │ │ │ │ ├── MultiFolderTrustDialog.tsx │ │ │ │ │ ├── NewAgentsNotification.test.tsx │ │ │ │ │ ├── NewAgentsNotification.tsx │ │ │ │ │ ├── Notifications.test.tsx │ │ │ │ │ ├── Notifications.tsx │ │ │ │ │ ├── OverageMenuDialog.test.tsx │ │ │ │ │ ├── OverageMenuDialog.tsx │ │ │ │ │ ├── PermissionsModifyTrustDialog.test.tsx │ │ │ │ │ ├── PermissionsModifyTrustDialog.tsx │ │ │ │ │ ├── PolicyUpdateDialog.test.tsx │ │ │ │ │ ├── PolicyUpdateDialog.tsx │ │ │ │ │ ├── ProQuotaDialog.test.tsx │ │ │ │ │ ├── ProQuotaDialog.tsx │ │ │ │ │ ├── QueuedMessageDisplay.test.tsx │ │ │ │ │ ├── QueuedMessageDisplay.tsx │ │ │ │ │ ├── QuittingDisplay.test.tsx │ │ │ │ │ ├── QuittingDisplay.tsx │ │ │ │ │ ├── QuotaDisplay.test.tsx │ │ │ │ │ ├── QuotaDisplay.tsx │ │ │ │ │ ├── QuotaStatsInfo.tsx │ │ │ │ │ ├── RawMarkdownIndicator.test.tsx │ │ │ │ │ ├── RawMarkdownIndicator.tsx │ │ │ │ │ ├── RewindConfirmation.test.tsx │ │ │ │ │ ├── RewindConfirmation.tsx │ │ │ │ │ ├── RewindViewer.test.tsx │ │ │ │ │ ├── RewindViewer.tsx │ │ │ │ │ ├── SessionBrowser/ │ │ │ │ │ │ ├── SessionBrowserEmpty.tsx │ │ │ │ │ │ ├── SessionBrowserError.tsx │ │ │ │ │ │ ├── SessionBrowserLoading.tsx │ │ │ │ │ │ ├── SessionBrowserNav.tsx │ │ │ │ │ │ ├── SessionBrowserSearchNav.test.tsx │ │ │ │ │ │ ├── SessionBrowserStates.test.tsx │ │ │ │ │ │ ├── SessionListHeader.tsx │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ ├── SessionBrowserSearchNav.test.tsx.snap │ │ │ │ │ │ │ └── SessionBrowserStates.test.tsx.snap │ │ │ │ │ │ ├── utils.test.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── SessionBrowser.test.tsx │ │ │ │ │ ├── SessionBrowser.tsx │ │ │ │ │ ├── SessionSummaryDisplay.test.tsx │ │ │ │ │ ├── SessionSummaryDisplay.tsx │ │ │ │ │ ├── SettingsDialog.test.tsx │ │ │ │ │ ├── SettingsDialog.tsx │ │ │ │ │ ├── ShellInputPrompt.test.tsx │ │ │ │ │ ├── ShellInputPrompt.tsx │ │ │ │ │ ├── ShellModeIndicator.test.tsx │ │ │ │ │ ├── ShellModeIndicator.tsx │ │ │ │ │ ├── ShortcutsHelp.test.tsx │ │ │ │ │ ├── ShortcutsHelp.tsx │ │ │ │ │ ├── ShortcutsHint.tsx │ │ │ │ │ ├── ShowMoreLines.test.tsx │ │ │ │ │ ├── ShowMoreLines.tsx │ │ │ │ │ ├── ShowMoreLinesLayout.test.tsx │ │ │ │ │ ├── StatsDisplay.test.tsx │ │ │ │ │ ├── StatsDisplay.tsx │ │ │ │ │ ├── StatusDisplay.test.tsx │ │ │ │ │ ├── StatusDisplay.tsx │ │ │ │ │ ├── StickyHeader.test.tsx │ │ │ │ │ ├── StickyHeader.tsx │ │ │ │ │ ├── SuggestionsDisplay.test.tsx │ │ │ │ │ ├── SuggestionsDisplay.tsx │ │ │ │ │ ├── Table.test.tsx │ │ │ │ │ ├── Table.tsx │ │ │ │ │ ├── ThemeDialog.test.tsx │ │ │ │ │ ├── ThemeDialog.tsx │ │ │ │ │ ├── ThemedGradient.test.tsx │ │ │ │ │ ├── ThemedGradient.tsx │ │ │ │ │ ├── Tips.test.tsx │ │ │ │ │ ├── Tips.tsx │ │ │ │ │ ├── ToastDisplay.test.tsx │ │ │ │ │ ├── ToastDisplay.tsx │ │ │ │ │ ├── ToolConfirmationQueue.test.tsx │ │ │ │ │ ├── ToolConfirmationQueue.tsx │ │ │ │ │ ├── ToolStatsDisplay.test.tsx │ │ │ │ │ ├── ToolStatsDisplay.tsx │ │ │ │ │ ├── UpdateNotification.test.tsx │ │ │ │ │ ├── UpdateNotification.tsx │ │ │ │ │ ├── UserIdentity.test.tsx │ │ │ │ │ ├── UserIdentity.tsx │ │ │ │ │ ├── ValidationDialog.test.tsx │ │ │ │ │ ├── ValidationDialog.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ ├── AdminSettingsChangedDialog.test.tsx.snap │ │ │ │ │ │ ├── AlternateBufferQuittingDisplay.test.tsx.snap │ │ │ │ │ │ ├── AppHeader.test.tsx.snap │ │ │ │ │ │ ├── AppHeaderIcon.test.tsx.snap │ │ │ │ │ │ ├── ApprovalModeIndicator.test.tsx.snap │ │ │ │ │ │ ├── AskUserDialog.test.tsx.snap │ │ │ │ │ │ ├── BackgroundShellDisplay.test.tsx.snap │ │ │ │ │ │ ├── Banner.test.tsx.snap │ │ │ │ │ │ ├── Checklist.test.tsx.snap │ │ │ │ │ │ ├── ChecklistItem.test.tsx.snap │ │ │ │ │ │ ├── Composer.test.tsx.snap │ │ │ │ │ │ ├── ConfigInitDisplay.test.tsx.snap │ │ │ │ │ │ ├── ContextSummaryDisplay.test.tsx.snap │ │ │ │ │ │ ├── DetailedMessagesDisplay.test.tsx.snap │ │ │ │ │ │ ├── EditorSettingsDialog.test.tsx.snap │ │ │ │ │ │ ├── EmptyWalletDialog.test.tsx.snap │ │ │ │ │ │ ├── ExitPlanModeDialog.test.tsx.snap │ │ │ │ │ │ ├── Footer.test.tsx.snap │ │ │ │ │ │ ├── FooterConfigDialog.test.tsx.snap │ │ │ │ │ │ ├── HistoryItemDisplay.test.tsx.snap │ │ │ │ │ │ ├── HookStatusDisplay.test.tsx.snap │ │ │ │ │ │ ├── HooksDialog.test.tsx.snap │ │ │ │ │ │ ├── IDEContextDetailDisplay.test.tsx.snap │ │ │ │ │ │ ├── InputPrompt.test.tsx.snap │ │ │ │ │ │ ├── LoadingIndicator.test.tsx.snap │ │ │ │ │ │ ├── LoopDetectionConfirmation.test.tsx.snap │ │ │ │ │ │ ├── MainContent.test.tsx.snap │ │ │ │ │ │ ├── ModelStatsDisplay.test.tsx.snap │ │ │ │ │ │ ├── NewAgentsNotification.test.tsx.snap │ │ │ │ │ │ ├── Notifications.test.tsx.snap │ │ │ │ │ │ ├── OverageMenuDialog.test.tsx.snap │ │ │ │ │ │ ├── PolicyUpdateDialog.test.tsx.snap │ │ │ │ │ │ ├── PrepareLabel.test.tsx.snap │ │ │ │ │ │ ├── QuotaDisplay.test.tsx.snap │ │ │ │ │ │ ├── RewindConfirmation.test.tsx.snap │ │ │ │ │ │ ├── RewindViewer.test.tsx.snap │ │ │ │ │ │ ├── SessionBrowser.test.tsx.snap │ │ │ │ │ │ ├── SessionSummaryDisplay.test.tsx.snap │ │ │ │ │ │ ├── SettingsDialog.test.tsx.snap │ │ │ │ │ │ ├── ShortcutsHelp.test.tsx.snap │ │ │ │ │ │ ├── StatsDisplay.test.tsx.snap │ │ │ │ │ │ ├── StatusDisplay.test.tsx.snap │ │ │ │ │ │ ├── SuggestionsDisplay.test.tsx.snap │ │ │ │ │ │ ├── Table.test.tsx.snap │ │ │ │ │ │ ├── ThemeDialog.test.tsx.snap │ │ │ │ │ │ ├── Tips.test.tsx.snap │ │ │ │ │ │ ├── ToastDisplay.test.tsx.snap │ │ │ │ │ │ ├── ToolConfirmationQueue.test.tsx.snap │ │ │ │ │ │ └── ToolStatsDisplay.test.tsx.snap │ │ │ │ │ ├── messages/ │ │ │ │ │ │ ├── CompressionMessage.test.tsx │ │ │ │ │ │ ├── CompressionMessage.tsx │ │ │ │ │ │ ├── DiffRenderer.test.tsx │ │ │ │ │ │ ├── DiffRenderer.tsx │ │ │ │ │ │ ├── ErrorMessage.test.tsx │ │ │ │ │ │ ├── ErrorMessage.tsx │ │ │ │ │ │ ├── GeminiMessage.test.tsx │ │ │ │ │ │ ├── GeminiMessage.tsx │ │ │ │ │ │ ├── GeminiMessageContent.tsx │ │ │ │ │ │ ├── HintMessage.tsx │ │ │ │ │ │ ├── InfoMessage.test.tsx │ │ │ │ │ │ ├── InfoMessage.tsx │ │ │ │ │ │ ├── ModelMessage.tsx │ │ │ │ │ │ ├── RedirectionConfirmation.test.tsx │ │ │ │ │ │ ├── ShellToolMessage.test.tsx │ │ │ │ │ │ ├── ShellToolMessage.tsx │ │ │ │ │ │ ├── SubagentGroupDisplay.test.tsx │ │ │ │ │ │ ├── SubagentGroupDisplay.tsx │ │ │ │ │ │ ├── SubagentProgressDisplay.test.tsx │ │ │ │ │ │ ├── SubagentProgressDisplay.tsx │ │ │ │ │ │ ├── ThinkingMessage.test.tsx │ │ │ │ │ │ ├── ThinkingMessage.tsx │ │ │ │ │ │ ├── Todo.test.tsx │ │ │ │ │ │ ├── Todo.tsx │ │ │ │ │ │ ├── ToolConfirmationMessage.test.tsx │ │ │ │ │ │ ├── ToolConfirmationMessage.tsx │ │ │ │ │ │ ├── ToolGroupMessage.test.tsx │ │ │ │ │ │ ├── ToolGroupMessage.tsx │ │ │ │ │ │ ├── ToolMessage.test.tsx │ │ │ │ │ │ ├── ToolMessage.tsx │ │ │ │ │ │ ├── ToolMessageFocusHint.test.tsx │ │ │ │ │ │ ├── ToolMessageRawMarkdown.test.tsx │ │ │ │ │ │ ├── ToolOverflowConsistencyChecks.test.tsx │ │ │ │ │ │ ├── ToolResultDisplay.test.tsx │ │ │ │ │ │ ├── ToolResultDisplay.tsx │ │ │ │ │ │ ├── ToolResultDisplayOverflow.test.tsx │ │ │ │ │ │ ├── ToolShared.test.tsx │ │ │ │ │ │ ├── ToolShared.tsx │ │ │ │ │ │ ├── ToolStickyHeaderRegression.test.tsx │ │ │ │ │ │ ├── UserMessage.test.tsx │ │ │ │ │ │ ├── UserMessage.tsx │ │ │ │ │ │ ├── UserShellMessage.tsx │ │ │ │ │ │ ├── WarningMessage.test.tsx │ │ │ │ │ │ ├── WarningMessage.tsx │ │ │ │ │ │ └── __snapshots__/ │ │ │ │ │ │ ├── DiffRenderer.test.tsx.snap │ │ │ │ │ │ ├── ErrorMessage.test.tsx.snap │ │ │ │ │ │ ├── GeminiMessage.test.tsx.snap │ │ │ │ │ │ ├── InfoMessage.test.tsx.snap │ │ │ │ │ │ ├── RedirectionConfirmation.test.tsx.snap │ │ │ │ │ │ ├── ShellToolMessage.test.tsx.snap │ │ │ │ │ │ ├── SubagentGroupDisplay.test.tsx.snap │ │ │ │ │ │ ├── SubagentProgressDisplay.test.tsx.snap │ │ │ │ │ │ ├── ThinkingMessage.test.tsx.snap │ │ │ │ │ │ ├── Todo.test.tsx.snap │ │ │ │ │ │ ├── ToolConfirmationMessage.test.tsx.snap │ │ │ │ │ │ ├── ToolConfirmationMessageOverflow.test.tsx.snap │ │ │ │ │ │ ├── ToolGroupMessage.test.tsx.snap │ │ │ │ │ │ ├── ToolMessage.test.tsx.snap │ │ │ │ │ │ ├── ToolMessageFocusHint.test.tsx.snap │ │ │ │ │ │ ├── ToolMessageRawMarkdown.test.tsx.snap │ │ │ │ │ │ ├── ToolResultDisplay.test.tsx.snap │ │ │ │ │ │ ├── ToolShared.test.tsx.snap │ │ │ │ │ │ ├── ToolStickyHeaderRegression.test.tsx.snap │ │ │ │ │ │ ├── UserMessage.test.tsx.snap │ │ │ │ │ │ └── WarningMessage.test.tsx.snap │ │ │ │ │ ├── shared/ │ │ │ │ │ │ ├── BaseSelectionList.test.tsx │ │ │ │ │ │ ├── BaseSelectionList.tsx │ │ │ │ │ │ ├── BaseSettingsDialog.test.tsx │ │ │ │ │ │ ├── BaseSettingsDialog.tsx │ │ │ │ │ │ ├── DescriptiveRadioButtonSelect.test.tsx │ │ │ │ │ │ ├── DescriptiveRadioButtonSelect.tsx │ │ │ │ │ │ ├── DialogFooter.tsx │ │ │ │ │ │ ├── EnumSelector.test.tsx │ │ │ │ │ │ ├── EnumSelector.tsx │ │ │ │ │ │ ├── ExpandableText.test.tsx │ │ │ │ │ │ ├── ExpandableText.tsx │ │ │ │ │ │ ├── HalfLinePaddedBox.test.tsx │ │ │ │ │ │ ├── HalfLinePaddedBox.tsx │ │ │ │ │ │ ├── HorizontalLine.tsx │ │ │ │ │ │ ├── MaxSizedBox.test.tsx │ │ │ │ │ │ ├── MaxSizedBox.tsx │ │ │ │ │ │ ├── RadioButtonSelect.test.tsx │ │ │ │ │ │ ├── RadioButtonSelect.tsx │ │ │ │ │ │ ├── ScopeSelector.tsx │ │ │ │ │ │ ├── Scrollable.test.tsx │ │ │ │ │ │ ├── Scrollable.tsx │ │ │ │ │ │ ├── ScrollableList.test.tsx │ │ │ │ │ │ ├── ScrollableList.tsx │ │ │ │ │ │ ├── SearchableList.test.tsx │ │ │ │ │ │ ├── SearchableList.tsx │ │ │ │ │ │ ├── SectionHeader.test.tsx │ │ │ │ │ │ ├── SectionHeader.tsx │ │ │ │ │ │ ├── SlicingMaxSizedBox.test.tsx │ │ │ │ │ │ ├── SlicingMaxSizedBox.tsx │ │ │ │ │ │ ├── TabHeader.test.tsx │ │ │ │ │ │ ├── TabHeader.tsx │ │ │ │ │ │ ├── TextInput.test.tsx │ │ │ │ │ │ ├── TextInput.tsx │ │ │ │ │ │ ├── VirtualizedList.test.tsx │ │ │ │ │ │ ├── VirtualizedList.tsx │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ ├── BaseSelectionList.test.tsx.snap │ │ │ │ │ │ │ ├── DescriptiveRadioButtonSelect.test.tsx.snap │ │ │ │ │ │ │ ├── EnumSelector.test.tsx.snap │ │ │ │ │ │ │ ├── ExpandablePrompt.test.tsx.snap │ │ │ │ │ │ │ ├── ExpandableText.test.tsx.snap │ │ │ │ │ │ │ ├── HalfLinePaddedBox.test.tsx.snap │ │ │ │ │ │ │ ├── MaxSizedBox.test.tsx.snap │ │ │ │ │ │ │ ├── Scrollable.test.tsx.snap │ │ │ │ │ │ │ ├── SearchableList.test.tsx.snap │ │ │ │ │ │ │ ├── SectionHeader.test.tsx.snap │ │ │ │ │ │ │ ├── TabHeader.test.tsx.snap │ │ │ │ │ │ │ └── VirtualizedList.test.tsx.snap │ │ │ │ │ │ ├── performance.test.ts │ │ │ │ │ │ ├── text-buffer.test.ts │ │ │ │ │ │ ├── text-buffer.ts │ │ │ │ │ │ ├── vim-buffer-actions.test.ts │ │ │ │ │ │ └── vim-buffer-actions.ts │ │ │ │ │ ├── triage/ │ │ │ │ │ │ ├── TriageDuplicates.tsx │ │ │ │ │ │ └── TriageIssues.tsx │ │ │ │ │ └── views/ │ │ │ │ │ ├── AgentsStatus.tsx │ │ │ │ │ ├── ChatList.test.tsx │ │ │ │ │ ├── ChatList.tsx │ │ │ │ │ ├── ExtensionDetails.test.tsx │ │ │ │ │ ├── ExtensionDetails.tsx │ │ │ │ │ ├── ExtensionRegistryView.test.tsx │ │ │ │ │ ├── ExtensionRegistryView.tsx │ │ │ │ │ ├── ExtensionsList.test.tsx │ │ │ │ │ ├── ExtensionsList.tsx │ │ │ │ │ ├── McpStatus.test.tsx │ │ │ │ │ ├── McpStatus.tsx │ │ │ │ │ ├── SkillsList.test.tsx │ │ │ │ │ ├── SkillsList.tsx │ │ │ │ │ ├── ToolsList.test.tsx │ │ │ │ │ ├── ToolsList.tsx │ │ │ │ │ └── __snapshots__/ │ │ │ │ │ ├── ChatList.test.tsx.snap │ │ │ │ │ ├── McpStatus.test.tsx.snap │ │ │ │ │ └── ToolsList.test.tsx.snap │ │ │ │ ├── constants/ │ │ │ │ │ ├── tips.ts │ │ │ │ │ └── wittyPhrases.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── contexts/ │ │ │ │ │ ├── AppContext.tsx │ │ │ │ │ ├── AskUserActionsContext.tsx │ │ │ │ │ ├── ConfigContext.tsx │ │ │ │ │ ├── KeypressContext.test.tsx │ │ │ │ │ ├── KeypressContext.tsx │ │ │ │ │ ├── MouseContext.test.tsx │ │ │ │ │ ├── MouseContext.tsx │ │ │ │ │ ├── OverflowContext.tsx │ │ │ │ │ ├── ScrollProvider.drag.test.tsx │ │ │ │ │ ├── ScrollProvider.test.tsx │ │ │ │ │ ├── ScrollProvider.tsx │ │ │ │ │ ├── SessionContext.test.tsx │ │ │ │ │ ├── SessionContext.tsx │ │ │ │ │ ├── SettingsContext.test.tsx │ │ │ │ │ ├── SettingsContext.tsx │ │ │ │ │ ├── ShellFocusContext.tsx │ │ │ │ │ ├── StreamingContext.tsx │ │ │ │ │ ├── TerminalContext.test.tsx │ │ │ │ │ ├── TerminalContext.tsx │ │ │ │ │ ├── ToolActionsContext.test.tsx │ │ │ │ │ ├── ToolActionsContext.tsx │ │ │ │ │ ├── UIActionsContext.tsx │ │ │ │ │ ├── UIStateContext.tsx │ │ │ │ │ └── VimModeContext.tsx │ │ │ │ ├── debug.ts │ │ │ │ ├── editors/ │ │ │ │ │ └── editorSettingsManager.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── usePhraseCycler.test.tsx.snap │ │ │ │ │ ├── atCommandProcessor.test.ts │ │ │ │ │ ├── atCommandProcessor.ts │ │ │ │ │ ├── atCommandProcessor_agents.test.ts │ │ │ │ │ ├── creditsFlowHandler.test.ts │ │ │ │ │ ├── creditsFlowHandler.ts │ │ │ │ │ ├── shell-completions/ │ │ │ │ │ │ ├── gitProvider.test.ts │ │ │ │ │ │ ├── gitProvider.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── npmProvider.test.ts │ │ │ │ │ │ ├── npmProvider.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── shellCommandProcessor.test.tsx │ │ │ │ │ ├── shellCommandProcessor.ts │ │ │ │ │ ├── shellReducer.test.ts │ │ │ │ │ ├── shellReducer.ts │ │ │ │ │ ├── slashCommandProcessor.test.tsx │ │ │ │ │ ├── slashCommandProcessor.ts │ │ │ │ │ ├── toolMapping.test.ts │ │ │ │ │ ├── toolMapping.ts │ │ │ │ │ ├── useAlternateBuffer.test.ts │ │ │ │ │ ├── useAlternateBuffer.ts │ │ │ │ │ ├── useAnimatedScrollbar.test.tsx │ │ │ │ │ ├── useAnimatedScrollbar.ts │ │ │ │ │ ├── useApprovalModeIndicator.test.ts │ │ │ │ │ ├── useApprovalModeIndicator.ts │ │ │ │ │ ├── useAtCompletion.test.ts │ │ │ │ │ ├── useAtCompletion.ts │ │ │ │ │ ├── useAtCompletion_agents.test.ts │ │ │ │ │ ├── useBackgroundShellManager.test.tsx │ │ │ │ │ ├── useBackgroundShellManager.ts │ │ │ │ │ ├── useBanner.test.ts │ │ │ │ │ ├── useBanner.ts │ │ │ │ │ ├── useBatchedScroll.test.ts │ │ │ │ │ ├── useBatchedScroll.ts │ │ │ │ │ ├── useCommandCompletion.test.tsx │ │ │ │ │ ├── useCommandCompletion.tsx │ │ │ │ │ ├── useCompletion.ts │ │ │ │ │ ├── useConfirmingTool.ts │ │ │ │ │ ├── useConsoleMessages.test.tsx │ │ │ │ │ ├── useConsoleMessages.ts │ │ │ │ │ ├── useEditorSettings.test.tsx │ │ │ │ │ ├── useEditorSettings.ts │ │ │ │ │ ├── useExtensionRegistry.ts │ │ │ │ │ ├── useExtensionUpdates.test.tsx │ │ │ │ │ ├── useExtensionUpdates.ts │ │ │ │ │ ├── useFlickerDetector.test.ts │ │ │ │ │ ├── useFlickerDetector.ts │ │ │ │ │ ├── useFocus.test.tsx │ │ │ │ │ ├── useFocus.ts │ │ │ │ │ ├── useFolderTrust.test.ts │ │ │ │ │ ├── useFolderTrust.ts │ │ │ │ │ ├── useGeminiStream.test.tsx │ │ │ │ │ ├── useGeminiStream.ts │ │ │ │ │ ├── useGitBranchName.test.tsx │ │ │ │ │ ├── useGitBranchName.ts │ │ │ │ │ ├── useHistoryManager.test.ts │ │ │ │ │ ├── useHistoryManager.ts │ │ │ │ │ ├── useHookDisplayState.test.ts │ │ │ │ │ ├── useHookDisplayState.ts │ │ │ │ │ ├── useIdeTrustListener.test.tsx │ │ │ │ │ ├── useIdeTrustListener.ts │ │ │ │ │ ├── useInactivityTimer.ts │ │ │ │ │ ├── useIncludeDirsTrust.test.tsx │ │ │ │ │ ├── useIncludeDirsTrust.tsx │ │ │ │ │ ├── useInlineEditBuffer.test.ts │ │ │ │ │ ├── useInlineEditBuffer.ts │ │ │ │ │ ├── useInputHistory.test.ts │ │ │ │ │ ├── useInputHistory.ts │ │ │ │ │ ├── useInputHistoryStore.test.ts │ │ │ │ │ ├── useInputHistoryStore.ts │ │ │ │ │ ├── useKeyMatchers.tsx │ │ │ │ │ ├── useKeypress.test.tsx │ │ │ │ │ ├── useKeypress.ts │ │ │ │ │ ├── useKittyKeyboardProtocol.ts │ │ │ │ │ ├── useLoadingIndicator.test.tsx │ │ │ │ │ ├── useLoadingIndicator.ts │ │ │ │ │ ├── useLogger.test.tsx │ │ │ │ │ ├── useLogger.ts │ │ │ │ │ ├── useMcpStatus.test.tsx │ │ │ │ │ ├── useMcpStatus.ts │ │ │ │ │ ├── useMemoryMonitor.test.tsx │ │ │ │ │ ├── useMemoryMonitor.ts │ │ │ │ │ ├── useMessageQueue.test.tsx │ │ │ │ │ ├── useMessageQueue.ts │ │ │ │ │ ├── useModelCommand.test.tsx │ │ │ │ │ ├── useModelCommand.ts │ │ │ │ │ ├── useMouse.test.ts │ │ │ │ │ ├── useMouse.ts │ │ │ │ │ ├── useMouseClick.test.ts │ │ │ │ │ ├── useMouseClick.ts │ │ │ │ │ ├── usePermissionsModifyTrust.test.ts │ │ │ │ │ ├── usePermissionsModifyTrust.ts │ │ │ │ │ ├── usePhraseCycler.test.tsx │ │ │ │ │ ├── usePhraseCycler.ts │ │ │ │ │ ├── usePrivacySettings.test.tsx │ │ │ │ │ ├── usePrivacySettings.ts │ │ │ │ │ ├── usePromptCompletion.ts │ │ │ │ │ ├── useQuotaAndFallback.test.ts │ │ │ │ │ ├── useQuotaAndFallback.ts │ │ │ │ │ ├── useRegistrySearch.ts │ │ │ │ │ ├── useRepeatedKeyPress.ts │ │ │ │ │ ├── useReverseSearchCompletion.test.tsx │ │ │ │ │ ├── useReverseSearchCompletion.tsx │ │ │ │ │ ├── useRewind.test.ts │ │ │ │ │ ├── useRewind.ts │ │ │ │ │ ├── useRunEventNotifications.ts │ │ │ │ │ ├── useSearchBuffer.ts │ │ │ │ │ ├── useSelectionList.test.tsx │ │ │ │ │ ├── useSelectionList.ts │ │ │ │ │ ├── useSessionBrowser.test.ts │ │ │ │ │ ├── useSessionBrowser.ts │ │ │ │ │ ├── useSessionResume.test.ts │ │ │ │ │ ├── useSessionResume.ts │ │ │ │ │ ├── useSettingsCommand.ts │ │ │ │ │ ├── useSettingsNavigation.test.ts │ │ │ │ │ ├── useSettingsNavigation.ts │ │ │ │ │ ├── useShellCompletion.test.ts │ │ │ │ │ ├── useShellCompletion.ts │ │ │ │ │ ├── useShellHistory.test.ts │ │ │ │ │ ├── useShellHistory.ts │ │ │ │ │ ├── useShellInactivityStatus.test.ts │ │ │ │ │ ├── useShellInactivityStatus.ts │ │ │ │ │ ├── useSlashCompletion.test.ts │ │ │ │ │ ├── useSlashCompletion.ts │ │ │ │ │ ├── useSnowfall.test.tsx │ │ │ │ │ ├── useSnowfall.ts │ │ │ │ │ ├── useStateAndRef.ts │ │ │ │ │ ├── useSuspend.test.ts │ │ │ │ │ ├── useSuspend.ts │ │ │ │ │ ├── useTabbedNavigation.test.ts │ │ │ │ │ ├── useTabbedNavigation.ts │ │ │ │ │ ├── useTerminalSize.ts │ │ │ │ │ ├── useTerminalTheme.test.tsx │ │ │ │ │ ├── useTerminalTheme.ts │ │ │ │ │ ├── useThemeCommand.ts │ │ │ │ │ ├── useTimedMessage.ts │ │ │ │ │ ├── useTimer.test.tsx │ │ │ │ │ ├── useTimer.ts │ │ │ │ │ ├── useTips.test.ts │ │ │ │ │ ├── useTips.ts │ │ │ │ │ ├── useToolScheduler.test.ts │ │ │ │ │ ├── useToolScheduler.ts │ │ │ │ │ ├── useTurnActivityMonitor.test.ts │ │ │ │ │ ├── useTurnActivityMonitor.ts │ │ │ │ │ ├── useVisibilityToggle.ts │ │ │ │ │ ├── vim-passthrough.test.tsx │ │ │ │ │ ├── vim.test.tsx │ │ │ │ │ └── vim.ts │ │ │ │ ├── key/ │ │ │ │ │ ├── keyBindings.test.ts │ │ │ │ │ ├── keyBindings.ts │ │ │ │ │ ├── keyMatchers.test.ts │ │ │ │ │ ├── keyMatchers.ts │ │ │ │ │ ├── keyToAnsi.ts │ │ │ │ │ ├── keybindingUtils.test.ts │ │ │ │ │ └── keybindingUtils.ts │ │ │ │ ├── layouts/ │ │ │ │ │ ├── DefaultAppLayout.test.tsx │ │ │ │ │ ├── DefaultAppLayout.tsx │ │ │ │ │ ├── ScreenReaderAppLayout.tsx │ │ │ │ │ └── __snapshots__/ │ │ │ │ │ └── DefaultAppLayout.test.tsx.snap │ │ │ │ ├── noninteractive/ │ │ │ │ │ └── nonInteractiveUi.ts │ │ │ │ ├── privacy/ │ │ │ │ │ ├── CloudFreePrivacyNotice.test.tsx │ │ │ │ │ ├── CloudFreePrivacyNotice.tsx │ │ │ │ │ ├── CloudPaidPrivacyNotice.test.tsx │ │ │ │ │ ├── CloudPaidPrivacyNotice.tsx │ │ │ │ │ ├── GeminiPrivacyNotice.test.tsx │ │ │ │ │ ├── GeminiPrivacyNotice.tsx │ │ │ │ │ ├── PrivacyNotice.test.tsx │ │ │ │ │ └── PrivacyNotice.tsx │ │ │ │ ├── semantic-colors.ts │ │ │ │ ├── state/ │ │ │ │ │ ├── extensions.test.ts │ │ │ │ │ └── extensions.ts │ │ │ │ ├── textConstants.ts │ │ │ │ ├── themes/ │ │ │ │ │ ├── builtin/ │ │ │ │ │ │ ├── dark/ │ │ │ │ │ │ │ ├── ansi-dark.ts │ │ │ │ │ │ │ ├── atom-one-dark.ts │ │ │ │ │ │ │ ├── ayu-dark.ts │ │ │ │ │ │ │ ├── default-dark.ts │ │ │ │ │ │ │ ├── dracula-dark.ts │ │ │ │ │ │ │ ├── github-dark.ts │ │ │ │ │ │ │ ├── holiday-dark.ts │ │ │ │ │ │ │ ├── shades-of-purple-dark.ts │ │ │ │ │ │ │ └── solarized-dark.ts │ │ │ │ │ │ ├── light/ │ │ │ │ │ │ │ ├── ansi-light.ts │ │ │ │ │ │ │ ├── ayu-light.ts │ │ │ │ │ │ │ ├── default-light.ts │ │ │ │ │ │ │ ├── github-light.ts │ │ │ │ │ │ │ ├── googlecode-light.ts │ │ │ │ │ │ │ ├── solarized-light.ts │ │ │ │ │ │ │ └── xcode-light.ts │ │ │ │ │ │ └── no-color.ts │ │ │ │ │ ├── color-utils.test.ts │ │ │ │ │ ├── color-utils.ts │ │ │ │ │ ├── semantic-tokens.ts │ │ │ │ │ ├── theme-manager.test.ts │ │ │ │ │ ├── theme-manager.ts │ │ │ │ │ ├── theme.test.ts │ │ │ │ │ └── theme.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils/ │ │ │ │ ├── CodeColorizer.test.tsx │ │ │ │ ├── CodeColorizer.tsx │ │ │ │ ├── ConsolePatcher.ts │ │ │ │ ├── InlineMarkdownRenderer.tsx │ │ │ │ ├── MarkdownDisplay.test.tsx │ │ │ │ ├── MarkdownDisplay.tsx │ │ │ │ ├── TableRenderer.test.tsx │ │ │ │ ├── TableRenderer.tsx │ │ │ │ ├── __snapshots__/ │ │ │ │ │ ├── CodeColorizer.test.tsx.snap │ │ │ │ │ ├── MarkdownDisplay.test.tsx.snap │ │ │ │ │ ├── TableRenderer.test.tsx.snap │ │ │ │ │ ├── borderStyles.test.tsx.snap │ │ │ │ │ ├── terminalSetup.test.ts.snap │ │ │ │ │ └── textOutput.test.ts.snap │ │ │ │ ├── borderStyles.test.tsx │ │ │ │ ├── borderStyles.ts │ │ │ │ ├── clipboardUtils.test.ts │ │ │ │ ├── clipboardUtils.ts │ │ │ │ ├── clipboardUtils.windows.test.ts │ │ │ │ ├── commandUtils.test.ts │ │ │ │ ├── commandUtils.ts │ │ │ │ ├── computeStats.test.ts │ │ │ │ ├── computeStats.ts │ │ │ │ ├── confirmingTool.ts │ │ │ │ ├── contextUsage.ts │ │ │ │ ├── directoryUtils.test.ts │ │ │ │ ├── directoryUtils.ts │ │ │ │ ├── displayUtils.test.ts │ │ │ │ ├── displayUtils.ts │ │ │ │ ├── editorUtils.ts │ │ │ │ ├── formatters.test.ts │ │ │ │ ├── formatters.ts │ │ │ │ ├── highlight.test.ts │ │ │ │ ├── highlight.ts │ │ │ │ ├── historyExportUtils.ts │ │ │ │ ├── inlineThinkingMode.ts │ │ │ │ ├── input.test.ts │ │ │ │ ├── input.ts │ │ │ │ ├── isNarrowWidth.ts │ │ │ │ ├── markdownParsingUtils.test.ts │ │ │ │ ├── markdownParsingUtils.ts │ │ │ │ ├── markdownUtilities.test.ts │ │ │ │ ├── markdownUtilities.ts │ │ │ │ ├── mouse.test.ts │ │ │ │ ├── mouse.ts │ │ │ │ ├── pendingAttentionNotification.test.ts │ │ │ │ ├── pendingAttentionNotification.ts │ │ │ │ ├── rewindFileOps.test.ts │ │ │ │ ├── rewindFileOps.ts │ │ │ │ ├── shortcutsHelp.ts │ │ │ │ ├── terminalCapabilityManager.test.ts │ │ │ │ ├── terminalCapabilityManager.ts │ │ │ │ ├── terminalSetup.test.ts │ │ │ │ ├── terminalSetup.ts │ │ │ │ ├── terminalUtils.ts │ │ │ │ ├── textOutput.test.ts │ │ │ │ ├── textOutput.ts │ │ │ │ ├── textUtils.test.ts │ │ │ │ ├── textUtils.ts │ │ │ │ ├── toolLayoutUtils.test.ts │ │ │ │ ├── toolLayoutUtils.ts │ │ │ │ ├── ui-sizing.test.ts │ │ │ │ ├── ui-sizing.ts │ │ │ │ ├── updateCheck.test.ts │ │ │ │ ├── updateCheck.ts │ │ │ │ ├── urlSecurityUtils.test.ts │ │ │ │ └── urlSecurityUtils.ts │ │ │ ├── utils/ │ │ │ │ ├── activityLogger.test.ts │ │ │ │ ├── activityLogger.ts │ │ │ │ ├── agentSettings.test.ts │ │ │ │ ├── agentSettings.ts │ │ │ │ ├── agentUtils.test.ts │ │ │ │ ├── agentUtils.ts │ │ │ │ ├── cleanup.test.ts │ │ │ │ ├── cleanup.ts │ │ │ │ ├── commands.test.ts │ │ │ │ ├── commands.ts │ │ │ │ ├── commentJson.test.ts │ │ │ │ ├── commentJson.ts │ │ │ │ ├── deepMerge.test.ts │ │ │ │ ├── deepMerge.ts │ │ │ │ ├── devtoolsService.test.ts │ │ │ │ ├── devtoolsService.ts │ │ │ │ ├── dialogScopeUtils.test.ts │ │ │ │ ├── dialogScopeUtils.ts │ │ │ │ ├── envVarResolver.test.ts │ │ │ │ ├── envVarResolver.ts │ │ │ │ ├── errors.test.ts │ │ │ │ ├── errors.ts │ │ │ │ ├── events.test.ts │ │ │ │ ├── events.ts │ │ │ │ ├── featureToggleUtils.test.ts │ │ │ │ ├── featureToggleUtils.ts │ │ │ │ ├── gitUtils.test.ts │ │ │ │ ├── gitUtils.ts │ │ │ │ ├── handleAutoUpdate.test.ts │ │ │ │ ├── handleAutoUpdate.ts │ │ │ │ ├── hookSettings.test.ts │ │ │ │ ├── hookSettings.ts │ │ │ │ ├── hookUtils.test.ts │ │ │ │ ├── hookUtils.ts │ │ │ │ ├── installationInfo.test.ts │ │ │ │ ├── installationInfo.ts │ │ │ │ ├── jsonoutput.test.ts │ │ │ │ ├── jsonoutput.ts │ │ │ │ ├── logCleanup.test.ts │ │ │ │ ├── logCleanup.ts │ │ │ │ ├── math.test.ts │ │ │ │ ├── math.ts │ │ │ │ ├── persistentState.test.ts │ │ │ │ ├── persistentState.ts │ │ │ │ ├── processUtils.test.ts │ │ │ │ ├── processUtils.ts │ │ │ │ ├── readStdin.test.ts │ │ │ │ ├── readStdin.ts │ │ │ │ ├── readStdin_safety.test.ts │ │ │ │ ├── relaunch.test.ts │ │ │ │ ├── relaunch.ts │ │ │ │ ├── resolvePath.test.ts │ │ │ │ ├── resolvePath.ts │ │ │ │ ├── sandbox-macos-permissive-open.sb │ │ │ │ ├── sandbox-macos-permissive-proxied.sb │ │ │ │ ├── sandbox-macos-restrictive-open.sb │ │ │ │ ├── sandbox-macos-restrictive-proxied.sb │ │ │ │ ├── sandbox-macos-strict-open.sb │ │ │ │ ├── sandbox-macos-strict-proxied.sb │ │ │ │ ├── sandbox.test.ts │ │ │ │ ├── sandbox.ts │ │ │ │ ├── sandboxUtils.test.ts │ │ │ │ ├── sandboxUtils.ts │ │ │ │ ├── sessionCleanup.integration.test.ts │ │ │ │ ├── sessionCleanup.test.ts │ │ │ │ ├── sessionCleanup.ts │ │ │ │ ├── sessionUtils.test.ts │ │ │ │ ├── sessionUtils.ts │ │ │ │ ├── sessions.test.ts │ │ │ │ ├── sessions.ts │ │ │ │ ├── settingsUtils.test.ts │ │ │ │ ├── settingsUtils.ts │ │ │ │ ├── skillSettings.test.ts │ │ │ │ ├── skillSettings.ts │ │ │ │ ├── skillUtils.test.ts │ │ │ │ ├── skillUtils.ts │ │ │ │ ├── spawnWrapper.ts │ │ │ │ ├── startupWarnings.test.ts │ │ │ │ ├── startupWarnings.ts │ │ │ │ ├── terminalNotifications.test.ts │ │ │ │ ├── terminalNotifications.ts │ │ │ │ ├── terminalTheme.ts │ │ │ │ ├── tierUtils.test.ts │ │ │ │ ├── tierUtils.ts │ │ │ │ ├── toolOutputCleanup.test.ts │ │ │ │ ├── updateEventEmitter.test.ts │ │ │ │ ├── updateEventEmitter.ts │ │ │ │ ├── userStartupWarnings.test.ts │ │ │ │ ├── userStartupWarnings.ts │ │ │ │ ├── windowTitle.test.ts │ │ │ │ └── windowTitle.ts │ │ │ ├── validateNonInterActiveAuth.test.ts │ │ │ └── validateNonInterActiveAuth.ts │ │ ├── test-setup.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ ├── core/ │ │ ├── GEMINI.md │ │ ├── index.ts │ │ ├── package.json │ │ ├── scripts/ │ │ │ ├── bundle-browser-mcp.mjs │ │ │ └── compile-windows-sandbox.js │ │ ├── src/ │ │ │ ├── __mocks__/ │ │ │ │ └── fs/ │ │ │ │ └── promises.ts │ │ │ ├── agent/ │ │ │ │ ├── content-utils.test.ts │ │ │ │ ├── content-utils.ts │ │ │ │ ├── mock.test.ts │ │ │ │ ├── mock.ts │ │ │ │ └── types.ts │ │ │ ├── agents/ │ │ │ │ ├── a2a-client-manager.test.ts │ │ │ │ ├── a2a-client-manager.ts │ │ │ │ ├── a2a-errors.test.ts │ │ │ │ ├── a2a-errors.ts │ │ │ │ ├── a2aUtils.test.ts │ │ │ │ ├── a2aUtils.ts │ │ │ │ ├── acknowledgedAgents.test.ts │ │ │ │ ├── acknowledgedAgents.ts │ │ │ │ ├── agent-scheduler.test.ts │ │ │ │ ├── agent-scheduler.ts │ │ │ │ ├── agentLoader.test.ts │ │ │ │ ├── agentLoader.ts │ │ │ │ ├── auth-provider/ │ │ │ │ │ ├── api-key-provider.test.ts │ │ │ │ │ ├── api-key-provider.ts │ │ │ │ │ ├── base-provider.test.ts │ │ │ │ │ ├── base-provider.ts │ │ │ │ │ ├── factory.test.ts │ │ │ │ │ ├── factory.ts │ │ │ │ │ ├── google-credentials-provider.test.ts │ │ │ │ │ ├── google-credentials-provider.ts │ │ │ │ │ ├── http-provider.test.ts │ │ │ │ │ ├── http-provider.ts │ │ │ │ │ ├── oauth2-provider.test.ts │ │ │ │ │ ├── oauth2-provider.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── value-resolver.test.ts │ │ │ │ │ └── value-resolver.ts │ │ │ │ ├── browser/ │ │ │ │ │ ├── analyzeScreenshot.test.ts │ │ │ │ │ ├── analyzeScreenshot.ts │ │ │ │ │ ├── automationOverlay.ts │ │ │ │ │ ├── browser-tools-manifest.json │ │ │ │ │ ├── browserAgentDefinition.ts │ │ │ │ │ ├── browserAgentFactory.test.ts │ │ │ │ │ ├── browserAgentFactory.ts │ │ │ │ │ ├── browserAgentInvocation.test.ts │ │ │ │ │ ├── browserAgentInvocation.ts │ │ │ │ │ ├── browserManager.test.ts │ │ │ │ │ ├── browserManager.ts │ │ │ │ │ ├── inputBlocker.test.ts │ │ │ │ │ ├── inputBlocker.ts │ │ │ │ │ ├── mcpToolWrapper.test.ts │ │ │ │ │ ├── mcpToolWrapper.ts │ │ │ │ │ ├── mcpToolWrapperConfirmation.test.ts │ │ │ │ │ └── modelAvailability.ts │ │ │ │ ├── cli-help-agent.test.ts │ │ │ │ ├── cli-help-agent.ts │ │ │ │ ├── codebase-investigator.test.ts │ │ │ │ ├── codebase-investigator.ts │ │ │ │ ├── generalist-agent.test.ts │ │ │ │ ├── generalist-agent.ts │ │ │ │ ├── local-executor.test.ts │ │ │ │ ├── local-executor.ts │ │ │ │ ├── local-invocation.test.ts │ │ │ │ ├── local-invocation.ts │ │ │ │ ├── memory-manager-agent.test.ts │ │ │ │ ├── memory-manager-agent.ts │ │ │ │ ├── registry.test.ts │ │ │ │ ├── registry.ts │ │ │ │ ├── registry_acknowledgement.test.ts │ │ │ │ ├── remote-invocation.test.ts │ │ │ │ ├── remote-invocation.ts │ │ │ │ ├── subagent-tool-wrapper.test.ts │ │ │ │ ├── subagent-tool-wrapper.ts │ │ │ │ ├── subagent-tool.test.ts │ │ │ │ ├── subagent-tool.ts │ │ │ │ ├── types.ts │ │ │ │ ├── utils.test.ts │ │ │ │ └── utils.ts │ │ │ ├── availability/ │ │ │ │ ├── errorClassification.ts │ │ │ │ ├── fallbackIntegration.test.ts │ │ │ │ ├── modelAvailabilityService.test.ts │ │ │ │ ├── modelAvailabilityService.ts │ │ │ │ ├── modelPolicy.ts │ │ │ │ ├── policyCatalog.test.ts │ │ │ │ ├── policyCatalog.ts │ │ │ │ ├── policyHelpers.test.ts │ │ │ │ ├── policyHelpers.ts │ │ │ │ └── testUtils.ts │ │ │ ├── billing/ │ │ │ │ ├── billing.test.ts │ │ │ │ ├── billing.ts │ │ │ │ └── index.ts │ │ │ ├── code_assist/ │ │ │ │ ├── admin/ │ │ │ │ │ ├── admin_controls.test.ts │ │ │ │ │ ├── admin_controls.ts │ │ │ │ │ ├── mcpUtils.test.ts │ │ │ │ │ └── mcpUtils.ts │ │ │ │ ├── codeAssist.test.ts │ │ │ │ ├── codeAssist.ts │ │ │ │ ├── converter.test.ts │ │ │ │ ├── converter.ts │ │ │ │ ├── experiments/ │ │ │ │ │ ├── client_metadata.test.ts │ │ │ │ │ ├── client_metadata.ts │ │ │ │ │ ├── experiments.test.ts │ │ │ │ │ ├── experiments.ts │ │ │ │ │ ├── experiments_local.test.ts │ │ │ │ │ ├── flagNames.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── oauth-credential-storage.test.ts │ │ │ │ ├── oauth-credential-storage.ts │ │ │ │ ├── oauth2.test.ts │ │ │ │ ├── oauth2.ts │ │ │ │ ├── server.test.ts │ │ │ │ ├── server.ts │ │ │ │ ├── setup.test.ts │ │ │ │ ├── setup.ts │ │ │ │ ├── telemetry.test.ts │ │ │ │ ├── telemetry.ts │ │ │ │ └── types.ts │ │ │ ├── commands/ │ │ │ │ ├── extensions.test.ts │ │ │ │ ├── extensions.ts │ │ │ │ ├── init.test.ts │ │ │ │ ├── init.ts │ │ │ │ ├── memory.test.ts │ │ │ │ ├── memory.ts │ │ │ │ ├── restore.test.ts │ │ │ │ ├── restore.ts │ │ │ │ └── types.ts │ │ │ ├── config/ │ │ │ │ ├── agent-loop-context.ts │ │ │ │ ├── config.test.ts │ │ │ │ ├── config.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── defaultModelConfigs.ts │ │ │ │ ├── extensions/ │ │ │ │ │ ├── integrity.test.ts │ │ │ │ │ ├── integrity.ts │ │ │ │ │ └── integrityTypes.ts │ │ │ │ ├── flashFallback.test.ts │ │ │ │ ├── injectionService.test.ts │ │ │ │ ├── injectionService.ts │ │ │ │ ├── memory.test.ts │ │ │ │ ├── memory.ts │ │ │ │ ├── models.test.ts │ │ │ │ ├── models.ts │ │ │ │ ├── path-validation.test.ts │ │ │ │ ├── projectRegistry.test.ts │ │ │ │ ├── projectRegistry.ts │ │ │ │ ├── sandbox-integration.test.ts │ │ │ │ ├── storage.test.ts │ │ │ │ ├── storage.ts │ │ │ │ ├── storageMigration.test.ts │ │ │ │ ├── storageMigration.ts │ │ │ │ └── trackerFeatureFlag.test.ts │ │ │ ├── confirmation-bus/ │ │ │ │ ├── index.ts │ │ │ │ ├── message-bus.test.ts │ │ │ │ ├── message-bus.ts │ │ │ │ └── types.ts │ │ │ ├── core/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── prompts.test.ts.snap │ │ │ │ ├── apiKeyCredentialStorage.test.ts │ │ │ │ ├── apiKeyCredentialStorage.ts │ │ │ │ ├── baseLlmClient.test.ts │ │ │ │ ├── baseLlmClient.ts │ │ │ │ ├── client.test.ts │ │ │ │ ├── client.ts │ │ │ │ ├── contentGenerator.test.ts │ │ │ │ ├── contentGenerator.ts │ │ │ │ ├── coreToolHookTriggers.test.ts │ │ │ │ ├── coreToolHookTriggers.ts │ │ │ │ ├── coreToolScheduler.test.ts │ │ │ │ ├── coreToolScheduler.ts │ │ │ │ ├── fakeContentGenerator.test.ts │ │ │ │ ├── fakeContentGenerator.ts │ │ │ │ ├── geminiChat.test.ts │ │ │ │ ├── geminiChat.ts │ │ │ │ ├── geminiChat_network_retry.test.ts │ │ │ │ ├── geminiRequest.ts │ │ │ │ ├── localLiteRtLmClient.test.ts │ │ │ │ ├── localLiteRtLmClient.ts │ │ │ │ ├── logger.test.ts │ │ │ │ ├── logger.ts │ │ │ │ ├── loggingContentGenerator.test.ts │ │ │ │ ├── loggingContentGenerator.ts │ │ │ │ ├── prompts-substitution.test.ts │ │ │ │ ├── prompts.test.ts │ │ │ │ ├── prompts.ts │ │ │ │ ├── recordingContentGenerator.test.ts │ │ │ │ ├── recordingContentGenerator.ts │ │ │ │ ├── tokenLimits.test.ts │ │ │ │ ├── tokenLimits.ts │ │ │ │ ├── turn.test.ts │ │ │ │ └── turn.ts │ │ │ ├── fallback/ │ │ │ │ ├── handler.test.ts │ │ │ │ ├── handler.ts │ │ │ │ └── types.ts │ │ │ ├── hooks/ │ │ │ │ ├── hookAggregator.test.ts │ │ │ │ ├── hookAggregator.ts │ │ │ │ ├── hookEventHandler.test.ts │ │ │ │ ├── hookEventHandler.ts │ │ │ │ ├── hookPlanner.test.ts │ │ │ │ ├── hookPlanner.ts │ │ │ │ ├── hookRegistry.test.ts │ │ │ │ ├── hookRegistry.ts │ │ │ │ ├── hookRunner.test.ts │ │ │ │ ├── hookRunner.ts │ │ │ │ ├── hookSystem.test.ts │ │ │ │ ├── hookSystem.ts │ │ │ │ ├── hookTranslator.test.ts │ │ │ │ ├── hookTranslator.ts │ │ │ │ ├── index.ts │ │ │ │ ├── runtimeHooks.test.ts │ │ │ │ ├── trustedHooks.test.ts │ │ │ │ ├── trustedHooks.ts │ │ │ │ ├── types.test.ts │ │ │ │ └── types.ts │ │ │ ├── ide/ │ │ │ │ ├── constants.ts │ │ │ │ ├── detect-ide.test.ts │ │ │ │ ├── detect-ide.ts │ │ │ │ ├── ide-client.test.ts │ │ │ │ ├── ide-client.ts │ │ │ │ ├── ide-connection-utils.test.ts │ │ │ │ ├── ide-connection-utils.ts │ │ │ │ ├── ide-installer.test.ts │ │ │ │ ├── ide-installer.ts │ │ │ │ ├── ideContext.test.ts │ │ │ │ ├── ideContext.ts │ │ │ │ ├── process-utils.test.ts │ │ │ │ ├── process-utils.ts │ │ │ │ └── types.ts │ │ │ ├── index.test.ts │ │ │ ├── index.ts │ │ │ ├── mcp/ │ │ │ │ ├── auth-provider.ts │ │ │ │ ├── google-auth-provider.test.ts │ │ │ │ ├── google-auth-provider.ts │ │ │ │ ├── mcp-oauth-provider.test.ts │ │ │ │ ├── mcp-oauth-provider.ts │ │ │ │ ├── oauth-provider.test.ts │ │ │ │ ├── oauth-provider.ts │ │ │ │ ├── oauth-token-storage.test.ts │ │ │ │ ├── oauth-token-storage.ts │ │ │ │ ├── oauth-utils.test.ts │ │ │ │ ├── oauth-utils.ts │ │ │ │ ├── sa-impersonation-provider.test.ts │ │ │ │ ├── sa-impersonation-provider.ts │ │ │ │ └── token-storage/ │ │ │ │ ├── base-token-storage.test.ts │ │ │ │ ├── base-token-storage.ts │ │ │ │ ├── hybrid-token-storage.test.ts │ │ │ │ ├── hybrid-token-storage.ts │ │ │ │ ├── index.ts │ │ │ │ ├── keychain-token-storage.test.ts │ │ │ │ ├── keychain-token-storage.ts │ │ │ │ └── types.ts │ │ │ ├── mocks/ │ │ │ │ └── msw.ts │ │ │ ├── output/ │ │ │ │ ├── json-formatter.test.ts │ │ │ │ ├── json-formatter.ts │ │ │ │ ├── stream-json-formatter.test.ts │ │ │ │ ├── stream-json-formatter.ts │ │ │ │ └── types.ts │ │ │ ├── policy/ │ │ │ │ ├── config.test.ts │ │ │ │ ├── config.ts │ │ │ │ ├── index.ts │ │ │ │ ├── integrity.test.ts │ │ │ │ ├── integrity.ts │ │ │ │ ├── memory-manager-policy.test.ts │ │ │ │ ├── persistence.test.ts │ │ │ │ ├── policies/ │ │ │ │ │ ├── conseca.toml │ │ │ │ │ ├── discovered.toml │ │ │ │ │ ├── memory-manager.toml │ │ │ │ │ ├── plan.toml │ │ │ │ │ ├── read-only.toml │ │ │ │ │ ├── tracker.toml │ │ │ │ │ ├── write.toml │ │ │ │ │ └── yolo.toml │ │ │ │ ├── policy-engine.test.ts │ │ │ │ ├── policy-engine.ts │ │ │ │ ├── policy-updater.test.ts │ │ │ │ ├── shell-safety.test.ts │ │ │ │ ├── stable-stringify.ts │ │ │ │ ├── toml-loader.test.ts │ │ │ │ ├── toml-loader.ts │ │ │ │ ├── types.ts │ │ │ │ ├── utils.test.ts │ │ │ │ ├── utils.ts │ │ │ │ └── workspace-policy.test.ts │ │ │ ├── prompts/ │ │ │ │ ├── mcp-prompts.test.ts │ │ │ │ ├── mcp-prompts.ts │ │ │ │ ├── prompt-registry.test.ts │ │ │ │ ├── prompt-registry.ts │ │ │ │ ├── promptProvider.test.ts │ │ │ │ ├── promptProvider.ts │ │ │ │ ├── snippets-memory-manager.test.ts │ │ │ │ ├── snippets.legacy.ts │ │ │ │ ├── snippets.ts │ │ │ │ ├── utils.test.ts │ │ │ │ └── utils.ts │ │ │ ├── resources/ │ │ │ │ ├── resource-registry.test.ts │ │ │ │ └── resource-registry.ts │ │ │ ├── routing/ │ │ │ │ ├── modelRouterService.test.ts │ │ │ │ ├── modelRouterService.ts │ │ │ │ ├── routingStrategy.ts │ │ │ │ └── strategies/ │ │ │ │ ├── approvalModeStrategy.test.ts │ │ │ │ ├── approvalModeStrategy.ts │ │ │ │ ├── classifierStrategy.test.ts │ │ │ │ ├── classifierStrategy.ts │ │ │ │ ├── compositeStrategy.test.ts │ │ │ │ ├── compositeStrategy.ts │ │ │ │ ├── defaultStrategy.test.ts │ │ │ │ ├── defaultStrategy.ts │ │ │ │ ├── fallbackStrategy.test.ts │ │ │ │ ├── fallbackStrategy.ts │ │ │ │ ├── gemmaClassifierStrategy.test.ts │ │ │ │ ├── gemmaClassifierStrategy.ts │ │ │ │ ├── numericalClassifierStrategy.test.ts │ │ │ │ ├── numericalClassifierStrategy.ts │ │ │ │ ├── overrideStrategy.test.ts │ │ │ │ └── overrideStrategy.ts │ │ │ ├── safety/ │ │ │ │ ├── built-in.test.ts │ │ │ │ ├── built-in.ts │ │ │ │ ├── checker-runner.test.ts │ │ │ │ ├── checker-runner.ts │ │ │ │ ├── conseca/ │ │ │ │ │ ├── conseca.test.ts │ │ │ │ │ ├── conseca.ts │ │ │ │ │ ├── integration.test.ts │ │ │ │ │ ├── policy-enforcer.test.ts │ │ │ │ │ ├── policy-enforcer.ts │ │ │ │ │ ├── policy-generator.test.ts │ │ │ │ │ ├── policy-generator.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── context-builder.test.ts │ │ │ │ ├── context-builder.ts │ │ │ │ ├── protocol.ts │ │ │ │ ├── registry.test.ts │ │ │ │ └── registry.ts │ │ │ ├── sandbox/ │ │ │ │ ├── linux/ │ │ │ │ │ ├── LinuxSandboxManager.test.ts │ │ │ │ │ └── LinuxSandboxManager.ts │ │ │ │ └── macos/ │ │ │ │ ├── MacOsSandboxManager.integration.test.ts │ │ │ │ ├── MacOsSandboxManager.test.ts │ │ │ │ ├── MacOsSandboxManager.ts │ │ │ │ ├── baseProfile.ts │ │ │ │ ├── seatbeltArgsBuilder.test.ts │ │ │ │ └── seatbeltArgsBuilder.ts │ │ │ ├── scheduler/ │ │ │ │ ├── confirmation.test.ts │ │ │ │ ├── confirmation.ts │ │ │ │ ├── policy.test.ts │ │ │ │ ├── policy.ts │ │ │ │ ├── scheduler.test.ts │ │ │ │ ├── scheduler.ts │ │ │ │ ├── scheduler_parallel.test.ts │ │ │ │ ├── scheduler_waiting_callback.test.ts │ │ │ │ ├── state-manager.test.ts │ │ │ │ ├── state-manager.ts │ │ │ │ ├── tool-executor.test.ts │ │ │ │ ├── tool-executor.ts │ │ │ │ ├── tool-modifier.test.ts │ │ │ │ ├── tool-modifier.ts │ │ │ │ └── types.ts │ │ │ ├── services/ │ │ │ │ ├── FolderTrustDiscoveryService.test.ts │ │ │ │ ├── FolderTrustDiscoveryService.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── toolOutputMaskingService.test.ts.snap │ │ │ │ ├── chatCompressionService.test.ts │ │ │ │ ├── chatCompressionService.ts │ │ │ │ ├── chatRecordingService.test.ts │ │ │ │ ├── chatRecordingService.ts │ │ │ │ ├── contextManager.test.ts │ │ │ │ ├── contextManager.ts │ │ │ │ ├── environmentSanitization.test.ts │ │ │ │ ├── environmentSanitization.ts │ │ │ │ ├── executionLifecycleService.test.ts │ │ │ │ ├── executionLifecycleService.ts │ │ │ │ ├── fileDiscoveryService.test.ts │ │ │ │ ├── fileDiscoveryService.ts │ │ │ │ ├── fileKeychain.ts │ │ │ │ ├── fileSystemService.test.ts │ │ │ │ ├── fileSystemService.ts │ │ │ │ ├── gitService.test.ts │ │ │ │ ├── gitService.ts │ │ │ │ ├── keychainService.test.ts │ │ │ │ ├── keychainService.ts │ │ │ │ ├── keychainTypes.ts │ │ │ │ ├── loopDetectionService.test.ts │ │ │ │ ├── loopDetectionService.ts │ │ │ │ ├── modelConfig.golden.test.ts │ │ │ │ ├── modelConfig.integration.test.ts │ │ │ │ ├── modelConfigService.test.ts │ │ │ │ ├── modelConfigService.ts │ │ │ │ ├── modelConfigServiceTestUtils.ts │ │ │ │ ├── sandboxManager.test.ts │ │ │ │ ├── sandboxManager.ts │ │ │ │ ├── sandboxManagerFactory.ts │ │ │ │ ├── sandboxedFileSystemService.test.ts │ │ │ │ ├── sandboxedFileSystemService.ts │ │ │ │ ├── scripts/ │ │ │ │ │ └── GeminiSandbox.cs │ │ │ │ ├── sessionSummaryService.test.ts │ │ │ │ ├── sessionSummaryService.ts │ │ │ │ ├── sessionSummaryUtils.test.ts │ │ │ │ ├── sessionSummaryUtils.ts │ │ │ │ ├── shellExecutionService.test.ts │ │ │ │ ├── shellExecutionService.ts │ │ │ │ ├── test-data/ │ │ │ │ │ ├── resolved-aliases-retry.golden.json │ │ │ │ │ └── resolved-aliases.golden.json │ │ │ │ ├── toolOutputMaskingService.test.ts │ │ │ │ ├── toolOutputMaskingService.ts │ │ │ │ ├── trackerService.test.ts │ │ │ │ ├── trackerService.ts │ │ │ │ ├── trackerTypes.ts │ │ │ │ ├── windowsSandboxManager.test.ts │ │ │ │ └── windowsSandboxManager.ts │ │ │ ├── skills/ │ │ │ │ ├── builtin/ │ │ │ │ │ └── skill-creator/ │ │ │ │ │ ├── SKILL.md │ │ │ │ │ └── scripts/ │ │ │ │ │ ├── init_skill.cjs │ │ │ │ │ ├── package_skill.cjs │ │ │ │ │ └── validate_skill.cjs │ │ │ │ ├── skillLoader.test.ts │ │ │ │ ├── skillLoader.ts │ │ │ │ ├── skillManager.test.ts │ │ │ │ ├── skillManager.ts │ │ │ │ └── skillManagerAlias.test.ts │ │ │ ├── telemetry/ │ │ │ │ ├── activity-detector.test.ts │ │ │ │ ├── activity-detector.ts │ │ │ │ ├── activity-monitor.test.ts │ │ │ │ ├── activity-monitor.ts │ │ │ │ ├── activity-types.ts │ │ │ │ ├── billingEvents.test.ts │ │ │ │ ├── billingEvents.ts │ │ │ │ ├── clearcut-logger/ │ │ │ │ │ ├── clearcut-logger.test.ts │ │ │ │ │ ├── clearcut-logger.ts │ │ │ │ │ └── event-metadata-key.ts │ │ │ │ ├── config.test.ts │ │ │ │ ├── config.ts │ │ │ │ ├── conseca-logger.test.ts │ │ │ │ ├── conseca-logger.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── file-exporters.test.ts │ │ │ │ ├── file-exporters.ts │ │ │ │ ├── gcp-exporters.test.ts │ │ │ │ ├── gcp-exporters.ts │ │ │ │ ├── high-water-mark-tracker.test.ts │ │ │ │ ├── high-water-mark-tracker.ts │ │ │ │ ├── index.ts │ │ │ │ ├── integration.test.circular.ts │ │ │ │ ├── llmRole.ts │ │ │ │ ├── loggers.test.circular.ts │ │ │ │ ├── loggers.test.ts │ │ │ │ ├── loggers.ts │ │ │ │ ├── memory-monitor.test.ts │ │ │ │ ├── memory-monitor.ts │ │ │ │ ├── metrics.test.ts │ │ │ │ ├── metrics.ts │ │ │ │ ├── rate-limiter.test.ts │ │ │ │ ├── rate-limiter.ts │ │ │ │ ├── sanitize.test.ts │ │ │ │ ├── sanitize.ts │ │ │ │ ├── sdk.test.ts │ │ │ │ ├── sdk.ts │ │ │ │ ├── semantic.test.ts │ │ │ │ ├── semantic.truncation.test.ts │ │ │ │ ├── semantic.ts │ │ │ │ ├── startupProfiler.test.ts │ │ │ │ ├── startupProfiler.ts │ │ │ │ ├── telemetry-utils.test.ts │ │ │ │ ├── telemetry-utils.ts │ │ │ │ ├── telemetry.test.ts │ │ │ │ ├── telemetryAttributes.ts │ │ │ │ ├── tool-call-decision.ts │ │ │ │ ├── trace.test.ts │ │ │ │ ├── trace.ts │ │ │ │ ├── types.ts │ │ │ │ ├── uiTelemetry.test.ts │ │ │ │ └── uiTelemetry.ts │ │ │ ├── test-utils/ │ │ │ │ ├── config.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mock-message-bus.ts │ │ │ │ ├── mock-tool.ts │ │ │ │ └── mockWorkspaceContext.ts │ │ │ ├── tools/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ ├── read-file.test.ts.snap │ │ │ │ │ └── shell.test.ts.snap │ │ │ │ ├── activate-skill.test.ts │ │ │ │ ├── activate-skill.ts │ │ │ │ ├── ask-user.test.ts │ │ │ │ ├── ask-user.ts │ │ │ │ ├── base-tool-invocation.test.ts │ │ │ │ ├── confirmation-policy.test.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── definitions/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── coreToolsModelSnapshots.test.ts.snap │ │ │ │ │ ├── base-declarations.ts │ │ │ │ │ ├── coreTools.ts │ │ │ │ │ ├── coreToolsModelSnapshots.test.ts │ │ │ │ │ ├── dynamic-declaration-helpers.ts │ │ │ │ │ ├── model-family-sets/ │ │ │ │ │ │ ├── default-legacy.ts │ │ │ │ │ │ └── gemini-3.ts │ │ │ │ │ ├── modelFamilyService.ts │ │ │ │ │ ├── resolver.test.ts │ │ │ │ │ ├── resolver.ts │ │ │ │ │ ├── trackerTools.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── diff-utils.test.ts │ │ │ │ ├── diff-utils.ts │ │ │ │ ├── diffOptions.test.ts │ │ │ │ ├── diffOptions.ts │ │ │ │ ├── edit.test.ts │ │ │ │ ├── edit.ts │ │ │ │ ├── enter-plan-mode.test.ts │ │ │ │ ├── enter-plan-mode.ts │ │ │ │ ├── exit-plan-mode.test.ts │ │ │ │ ├── exit-plan-mode.ts │ │ │ │ ├── get-internal-docs.test.ts │ │ │ │ ├── get-internal-docs.ts │ │ │ │ ├── glob.test.ts │ │ │ │ ├── glob.ts │ │ │ │ ├── grep-utils.ts │ │ │ │ ├── grep.test.ts │ │ │ │ ├── grep.ts │ │ │ │ ├── jit-context.test.ts │ │ │ │ ├── jit-context.ts │ │ │ │ ├── line-endings.test.ts │ │ │ │ ├── ls.test.ts │ │ │ │ ├── ls.ts │ │ │ │ ├── mcp-client-manager.test.ts │ │ │ │ ├── mcp-client-manager.ts │ │ │ │ ├── mcp-client.test.ts │ │ │ │ ├── mcp-client.ts │ │ │ │ ├── mcp-tool.test.ts │ │ │ │ ├── mcp-tool.ts │ │ │ │ ├── memoryTool.test.ts │ │ │ │ ├── memoryTool.ts │ │ │ │ ├── message-bus-integration.test.ts │ │ │ │ ├── modifiable-tool.test.ts │ │ │ │ ├── modifiable-tool.ts │ │ │ │ ├── omissionPlaceholderDetector.test.ts │ │ │ │ ├── omissionPlaceholderDetector.ts │ │ │ │ ├── read-file.test.ts │ │ │ │ ├── read-file.ts │ │ │ │ ├── read-many-files.test.ts │ │ │ │ ├── read-many-files.ts │ │ │ │ ├── ripGrep.test.ts │ │ │ │ ├── ripGrep.ts │ │ │ │ ├── shell.test.ts │ │ │ │ ├── shell.ts │ │ │ │ ├── tool-error.ts │ │ │ │ ├── tool-names.test.ts │ │ │ │ ├── tool-names.ts │ │ │ │ ├── tool-registry.test.ts │ │ │ │ ├── tool-registry.ts │ │ │ │ ├── tools.test.ts │ │ │ │ ├── tools.ts │ │ │ │ ├── trackerTools.test.ts │ │ │ │ ├── trackerTools.ts │ │ │ │ ├── web-fetch.test.ts │ │ │ │ ├── web-fetch.ts │ │ │ │ ├── web-search.test.ts │ │ │ │ ├── web-search.ts │ │ │ │ ├── write-file.test.ts │ │ │ │ ├── write-file.ts │ │ │ │ ├── write-todos.test.ts │ │ │ │ ├── write-todos.ts │ │ │ │ ├── xcode-mcp-fix-transport.test.ts │ │ │ │ └── xcode-mcp-fix-transport.ts │ │ │ ├── utils/ │ │ │ │ ├── __fixtures__/ │ │ │ │ │ └── dummy.wasm │ │ │ │ ├── apiConversionUtils.test.ts │ │ │ │ ├── apiConversionUtils.ts │ │ │ │ ├── approvalModeUtils.test.ts │ │ │ │ ├── approvalModeUtils.ts │ │ │ │ ├── authConsent.test.ts │ │ │ │ ├── authConsent.ts │ │ │ │ ├── bfsFileSearch.test.ts │ │ │ │ ├── bfsFileSearch.ts │ │ │ │ ├── browser.ts │ │ │ │ ├── browserConsent.test.ts │ │ │ │ ├── browserConsent.ts │ │ │ │ ├── cache.test.ts │ │ │ │ ├── cache.ts │ │ │ │ ├── channel.test.ts │ │ │ │ ├── channel.ts │ │ │ │ ├── checkpointUtils.test.ts │ │ │ │ ├── checkpointUtils.ts │ │ │ │ ├── checks.test.ts │ │ │ │ ├── checks.ts │ │ │ │ ├── compatibility.test.ts │ │ │ │ ├── compatibility.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── customHeaderUtils.test.ts │ │ │ │ ├── customHeaderUtils.ts │ │ │ │ ├── deadlineTimer.test.ts │ │ │ │ ├── deadlineTimer.ts │ │ │ │ ├── debugLogger.test.ts │ │ │ │ ├── debugLogger.ts │ │ │ │ ├── delay.test.ts │ │ │ │ ├── delay.ts │ │ │ │ ├── editCorrector.test.ts │ │ │ │ ├── editCorrector.ts │ │ │ │ ├── editor.test.ts │ │ │ │ ├── editor.ts │ │ │ │ ├── envExpansion.test.ts │ │ │ │ ├── envExpansion.ts │ │ │ │ ├── environmentContext.test.ts │ │ │ │ ├── environmentContext.ts │ │ │ │ ├── errorParsing.test.ts │ │ │ │ ├── errorParsing.ts │ │ │ │ ├── errorReporting.test.ts │ │ │ │ ├── errorReporting.ts │ │ │ │ ├── errors.test.ts │ │ │ │ ├── errors.ts │ │ │ │ ├── errors_timeout.test.ts │ │ │ │ ├── events.test.ts │ │ │ │ ├── events.ts │ │ │ │ ├── exitCodes.ts │ │ │ │ ├── extensionLoader.test.ts │ │ │ │ ├── extensionLoader.ts │ │ │ │ ├── fastAckHelper.test.ts │ │ │ │ ├── fastAckHelper.ts │ │ │ │ ├── fetch.test.ts │ │ │ │ ├── fetch.ts │ │ │ │ ├── fileDiffUtils.test.ts │ │ │ │ ├── fileDiffUtils.ts │ │ │ │ ├── fileUtils.test.ts │ │ │ │ ├── fileUtils.ts │ │ │ │ ├── filesearch/ │ │ │ │ │ ├── crawlCache.test.ts │ │ │ │ │ ├── crawlCache.ts │ │ │ │ │ ├── crawler.test.ts │ │ │ │ │ ├── crawler.ts │ │ │ │ │ ├── fileSearch.test.ts │ │ │ │ │ ├── fileSearch.ts │ │ │ │ │ ├── ignore.test.ts │ │ │ │ │ ├── ignore.ts │ │ │ │ │ ├── result-cache.test.ts │ │ │ │ │ └── result-cache.ts │ │ │ │ ├── flashFallback.test.ts │ │ │ │ ├── formatters.test.ts │ │ │ │ ├── formatters.ts │ │ │ │ ├── fsErrorMessages.test.ts │ │ │ │ ├── fsErrorMessages.ts │ │ │ │ ├── generateContentResponseUtilities.test.ts │ │ │ │ ├── generateContentResponseUtilities.ts │ │ │ │ ├── getFolderStructure.test.ts │ │ │ │ ├── getFolderStructure.ts │ │ │ │ ├── getPty.ts │ │ │ │ ├── gitIgnoreParser.test.ts │ │ │ │ ├── gitIgnoreParser.ts │ │ │ │ ├── gitUtils.ts │ │ │ │ ├── googleErrors.test.ts │ │ │ │ ├── googleErrors.ts │ │ │ │ ├── googleQuotaErrors.test.ts │ │ │ │ ├── googleQuotaErrors.ts │ │ │ │ ├── headless.test.ts │ │ │ │ ├── headless.ts │ │ │ │ ├── httpErrors.ts │ │ │ │ ├── ignoreFileParser.test.ts │ │ │ │ ├── ignoreFileParser.ts │ │ │ │ ├── ignorePatterns.test.ts │ │ │ │ ├── ignorePatterns.ts │ │ │ │ ├── installationManager.test.ts │ │ │ │ ├── installationManager.ts │ │ │ │ ├── language-detection.test.ts │ │ │ │ ├── language-detection.ts │ │ │ │ ├── llm-edit-fixer.test.ts │ │ │ │ ├── llm-edit-fixer.ts │ │ │ │ ├── markdownUtils.test.ts │ │ │ │ ├── markdownUtils.ts │ │ │ │ ├── memoryDiscovery.test.ts │ │ │ │ ├── memoryDiscovery.ts │ │ │ │ ├── memoryImportProcessor.test.ts │ │ │ │ ├── memoryImportProcessor.ts │ │ │ │ ├── messageInspectors.ts │ │ │ │ ├── nextSpeakerChecker.test.ts │ │ │ │ ├── nextSpeakerChecker.ts │ │ │ │ ├── oauth-flow.test.ts │ │ │ │ ├── oauth-flow.ts │ │ │ │ ├── package.test.ts │ │ │ │ ├── package.ts │ │ │ │ ├── partUtils.test.ts │ │ │ │ ├── partUtils.ts │ │ │ │ ├── pathCorrector.test.ts │ │ │ │ ├── pathCorrector.ts │ │ │ │ ├── pathReader.test.ts │ │ │ │ ├── pathReader.ts │ │ │ │ ├── paths.test.ts │ │ │ │ ├── paths.ts │ │ │ │ ├── planUtils.test.ts │ │ │ │ ├── planUtils.ts │ │ │ │ ├── process-utils.test.ts │ │ │ │ ├── process-utils.ts │ │ │ │ ├── promptIdContext.ts │ │ │ │ ├── quotaErrorDetection.ts │ │ │ │ ├── retry.test.ts │ │ │ │ ├── retry.ts │ │ │ │ ├── safeJsonStringify.test.ts │ │ │ │ ├── safeJsonStringify.ts │ │ │ │ ├── schemaValidator.test.ts │ │ │ │ ├── schemaValidator.ts │ │ │ │ ├── secure-browser-launcher.test.ts │ │ │ │ ├── secure-browser-launcher.ts │ │ │ │ ├── security.test.ts │ │ │ │ ├── security.ts │ │ │ │ ├── session.ts │ │ │ │ ├── sessionUtils.test.ts │ │ │ │ ├── sessionUtils.ts │ │ │ │ ├── shell-utils.integration.test.ts │ │ │ │ ├── shell-utils.test.ts │ │ │ │ ├── shell-utils.ts │ │ │ │ ├── stdio.test.ts │ │ │ │ ├── stdio.ts │ │ │ │ ├── summarizer.test.ts │ │ │ │ ├── summarizer.ts │ │ │ │ ├── surface.ts │ │ │ │ ├── systemEncoding.test.ts │ │ │ │ ├── systemEncoding.ts │ │ │ │ ├── terminal.ts │ │ │ │ ├── terminalSerializer.test.ts │ │ │ │ ├── terminalSerializer.ts │ │ │ │ ├── testUtils.ts │ │ │ │ ├── textUtils.test.ts │ │ │ │ ├── textUtils.ts │ │ │ │ ├── thoughtUtils.test.ts │ │ │ │ ├── thoughtUtils.ts │ │ │ │ ├── tokenCalculation.test.ts │ │ │ │ ├── tokenCalculation.ts │ │ │ │ ├── tool-utils.test.ts │ │ │ │ ├── tool-utils.ts │ │ │ │ ├── toolCallContext.test.ts │ │ │ │ ├── toolCallContext.ts │ │ │ │ ├── userAccountManager.test.ts │ │ │ │ ├── userAccountManager.ts │ │ │ │ ├── version.test.ts │ │ │ │ ├── version.ts │ │ │ │ ├── workspaceContext.test.ts │ │ │ │ └── workspaceContext.ts │ │ │ └── voice/ │ │ │ ├── responseFormatter.test.ts │ │ │ └── responseFormatter.ts │ │ ├── test-setup.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ ├── devtools/ │ │ ├── GEMINI.md │ │ ├── client/ │ │ │ ├── index.html │ │ │ └── src/ │ │ │ ├── App.tsx │ │ │ ├── hooks.ts │ │ │ └── main.tsx │ │ ├── esbuild.client.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── sdk/ │ │ ├── GEMINI.md │ │ ├── README.md │ │ ├── SDK_DESIGN.md │ │ ├── examples/ │ │ │ ├── session-context.ts │ │ │ └── simple.ts │ │ ├── index.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── agent.integration.test.ts │ │ │ ├── agent.ts │ │ │ ├── fs.ts │ │ │ ├── index.ts │ │ │ ├── session.ts │ │ │ ├── shell.ts │ │ │ ├── skills.integration.test.ts │ │ │ ├── skills.ts │ │ │ ├── tool.integration.test.ts │ │ │ ├── tool.test.ts │ │ │ ├── tool.ts │ │ │ └── types.ts │ │ ├── test-data/ │ │ │ ├── agent-async-instructions.json │ │ │ ├── agent-dynamic-instructions.json │ │ │ ├── agent-resume-session.json │ │ │ ├── agent-static-instructions.json │ │ │ ├── skill-dir-success.json │ │ │ ├── skill-root-success.json │ │ │ ├── skills/ │ │ │ │ └── pirate-skill/ │ │ │ │ └── SKILL.md │ │ │ ├── tool-catchall-error.json │ │ │ ├── tool-error-recovery.json │ │ │ └── tool-success.json │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ ├── test-utils/ │ │ ├── GEMINI.md │ │ ├── index.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── file-system-test-helpers.ts │ │ │ ├── index.ts │ │ │ ├── mock-utils.ts │ │ │ └── test-rig.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ └── vscode-ide-companion/ │ ├── .vscode/ │ │ ├── launch.json │ │ └── tasks.json │ ├── .vscodeignore │ ├── GEMINI.md │ ├── LICENSE │ ├── NOTICES.txt │ ├── README.md │ ├── development.md │ ├── esbuild.js │ ├── package.json │ ├── scripts/ │ │ ├── check-vscode-release.js │ │ └── generate-notices.js │ ├── src/ │ │ ├── diff-manager.ts │ │ ├── extension.test.ts │ │ ├── extension.ts │ │ ├── ide-server.test.ts │ │ ├── ide-server.ts │ │ ├── open-files-manager.test.ts │ │ ├── open-files-manager.ts │ │ └── utils/ │ │ └── logger.ts │ └── tsconfig.json ├── schemas/ │ └── settings.schema.json ├── scripts/ │ ├── aggregate_evals.js │ ├── batch_triage.sh │ ├── build.js │ ├── build_binary.js │ ├── build_package.js │ ├── build_sandbox.js │ ├── build_vscode_companion.js │ ├── changed_prompt.js │ ├── check-build-status.js │ ├── check-lockfile.js │ ├── clean.js │ ├── cleanup-branches.ts │ ├── close_duplicate_issues.js │ ├── copy_bundle_assets.js │ ├── copy_files.js │ ├── create_alias.sh │ ├── deflake.js │ ├── entitlements.plist │ ├── generate-git-commit-info.js │ ├── generate-keybindings-doc.ts │ ├── generate-settings-doc.ts │ ├── generate-settings-schema.ts │ ├── get-release-version.js │ ├── lint.js │ ├── local_telemetry.js │ ├── pre-commit.js │ ├── prepare-github-release.js │ ├── prepare-npm-release.js │ ├── prepare-package.js │ ├── relabel_issues.sh │ ├── releasing/ │ │ ├── create-patch-pr.js │ │ ├── patch-comment.js │ │ ├── patch-create-comment.js │ │ └── patch-trigger.js │ ├── review.sh │ ├── sandbox_command.js │ ├── send_gemini_request.sh │ ├── start.js │ ├── sync_project_dry_run.js │ ├── telemetry.js │ ├── telemetry_gcp.js │ ├── telemetry_genkit.js │ ├── telemetry_utils.js │ ├── test-windows-paths.js │ ├── tests/ │ │ ├── autogen.test.ts │ │ ├── generate-keybindings-doc.test.ts │ │ ├── generate-settings-doc.test.ts │ │ ├── generate-settings-schema.test.ts │ │ ├── get-release-version.test.js │ │ ├── patch-create-comment.test.js │ │ ├── telemetry_gcp.test.ts │ │ ├── test-setup.ts │ │ └── vitest.config.ts │ ├── utils/ │ │ └── autogen.ts │ └── version.js ├── sea/ │ ├── sea-launch.cjs │ └── sea-launch.test.js ├── third_party/ │ └── get-ripgrep/ │ ├── LICENSE │ ├── package.json │ └── src/ │ ├── downloadRipGrep.js │ └── index.js └── tsconfig.json
Showing preview only (479K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (5409 symbols across 840 files)
FILE: .github/scripts/backfill-need-triage.cjs
constant REPO (line 12) | const REPO = 'google-gemini/gemini-cli';
function runGh (line 19) | function runGh(args) {
function main (line 37) | async function main() {
FILE: .github/scripts/backfill-pr-notification.cjs
constant REPO (line 20) | const REPO = 'google-gemini/gemini-cli';
constant ORG (line 21) | const ORG = 'google-gemini';
constant TEAM_SLUG (line 22) | const TEAM_SLUG = 'gemini-cli-maintainers';
constant DISCUSSION_URL (line 23) | const DISCUSSION_URL =
function runGh (line 29) | function runGh(args, options = {}) {
function isMaintainer (line 52) | function isMaintainer(username) {
function main (line 67) | async function main() {
FILE: .github/scripts/sync-maintainer-labels.cjs
constant REPO_OWNER (line 19) | const REPO_OWNER = 'google-gemini';
constant PUBLIC_REPO (line 20) | const PUBLIC_REPO = 'gemini-cli';
constant PRIVATE_REPO (line 21) | const PRIVATE_REPO = 'maintainers-gemini-cli';
constant ALLOWED_REPOS (line 22) | const ALLOWED_REPOS = [PUBLIC_REPO, PRIVATE_REPO];
constant ROOT_ISSUES (line 24) | const ROOT_ISSUES = [
constant TARGET_LABEL (line 30) | const TARGET_LABEL = '🔒 maintainer only';
function extractTaskListLinks (line 42) | function extractTaskListLinks(text, contextOwner, contextRepo) {
function fetchIssueData (line 80) | async function fetchIssueData(owner, repo, number) {
function paginateConnection (line 171) | async function paginateConnection(
function shouldProcess (line 214) | function shouldProcess(issueData) {
function getAllDescendants (line 227) | async function getAllDescendants(roots) {
function run (line 319) | async function run() {
FILE: esbuild.config.js
function createWasmPlugins (line 26) | function createWasmPlugins() {
FILE: evals/answer-vs-act.eval.ts
constant FILES (line 11) | const FILES = {
FILE: evals/app-test-helper.ts
type AppEvalCase (line 18) | interface AppEvalCase {
function appEvalTest (line 32) | function appEvalTest(policy: EvalPolicy, evalCase: AppEvalCase) {
FILE: evals/ask_user.eval.ts
function askUserEvalTest (line 11) | function askUserEvalTest(policy: EvalPolicy, evalCase: AppEvalCase) {
FILE: evals/concurrency-safety.eval.ts
constant MUTATION_AGENT_DEFINITION (line 10) | const MUTATION_AGENT_DEFINITION = `---
FILE: evals/gitRepo.eval.ts
constant FILES (line 10) | const FILES = {
FILE: evals/subagents.eval.ts
constant AGENT_DEFINITION (line 10) | const AGENT_DEFINITION = `---
constant INDEX_TS (line 21) | const INDEX_TS = 'export const add = (a: number, b: number) => a + b;';
FILE: evals/test-helper.ts
type EvalPolicy (line 36) | type EvalPolicy = 'ALWAYS_PASSES' | 'USUALLY_PASSES';
function evalTest (line 38) | function evalTest(policy: EvalPolicy, evalCase: EvalCase) {
function runEval (line 165) | function runEval(
function prepareLogDir (line 178) | async function prepareLogDir(name: string) {
function symlinkNodeModules (line 188) | function symlinkNodeModules(testDir: string) {
type EvalCase (line 200) | interface EvalCase {
FILE: evals/tool_output_masking.eval.ts
function findDir (line 14) | function findDir(base: string, name: string): string | null {
FILE: evals/tracker.eval.ts
constant FILES (line 16) | const FILES = {
FILE: integration-tests/acp-env-auth.test.ts
class MockClient (line 19) | class MockClient implements acp.Client {
FILE: integration-tests/acp-telemetry.test.ts
constant SIMPLE_RESPONSE_PATH (line 21) | const SIMPLE_RESPONSE_PATH = 'hooks-system.session-startup.responses';
class SessionUpdateCollector (line 23) | class SessionUpdateCollector implements acp.Client {
FILE: integration-tests/clipboard-linux.test.ts
constant DUMMY_PNG_BASE64 (line 15) | const DUMMY_PNG_BASE64 =
FILE: integration-tests/globalSetup.ts
function setup (line 23) | async function setup() {
function teardown (line 75) | async function teardown() {
FILE: integration-tests/policy-headless.test.ts
type PromptCommand (line 11) | interface PromptCommand {
constant ECHO_PROMPT (line 19) | const ECHO_PROMPT: PromptCommand = {
constant READ_FILE_PROMPT (line 30) | const READ_FILE_PROMPT: PromptCommand = {
function waitForToolCallLog (line 40) | async function waitForToolCallLog(
function verifyToolExecution (line 66) | async function verifyToolExecution(
type TestCase (line 93) | interface TestCase {
FILE: integration-tests/ripgrep-real.test.ts
class MockConfig (line 17) | class MockConfig {
method constructor (line 18) | constructor(private targetDir: string) {}
method getTargetDir (line 20) | getTargetDir() {
method getWorkspaceContext (line 24) | getWorkspaceContext() {
method getDebugMode (line 28) | getDebugMode() {
method getFileFilteringRespectGitIgnore (line 32) | getFileFilteringRespectGitIgnore() {
method getFileFilteringRespectGeminiIgnore (line 36) | getFileFilteringRespectGeminiIgnore() {
method getFileFilteringOptions (line 40) | getFileFilteringOptions() {
method validatePathAccess (line 48) | validatePathAccess() {
FILE: integration-tests/run_shell_command.test.ts
function getLineCountCommand (line 18) | function getLineCountCommand(): { command: string; tool: string } {
function getInvalidCommand (line 30) | function getInvalidCommand(): string {
function getAllowedListCommand (line 42) | function getAllowedListCommand(): string {
function getDisallowedFileReadCommand (line 54) | function getDisallowedFileReadCommand(testFile: string): {
function getChainedEchoCommand (line 70) | function getChainedEchoCommand(): { allowPattern: string; command: strin...
FILE: integration-tests/symlink-install.test.ts
constant BUNDLE_PATH (line 24) | const BUNDLE_PATH = join(__dirname, '..', 'bundle/gemini.js');
FILE: integration-tests/test-mcp-server.ts
class TestMcpServer (line 16) | class TestMcpServer {
method start (line 19) | async start(
method stop (line 66) | async stop(): Promise<void> {
FILE: integration-tests/utf-bom-encoding.test.ts
function runAndAssert (line 62) | async function runAndAssert(
FILE: packages/a2a-server/src/agent/executor.ts
class TaskWrapper (line 45) | class TaskWrapper {
method constructor (line 49) | constructor(task: Task, agentSettings: AgentSettings) {
method id (line 54) | get id() {
method toSDKTask (line 58) | toSDKTask(): SDKTask {
class CoderAgentExecutor (line 84) | class CoderAgentExecutor implements AgentExecutor {
method constructor (line 89) | constructor(private taskStore?: TaskStore) {}
method getConfig (line 91) | private async getConfig(
method reconstruct (line 105) | async reconstruct(
method createTask (line 138) | async createTask(
method getTask (line 164) | getTask(taskId: string): TaskWrapper | undefined {
method getAllTasks (line 168) | getAllTasks(): TaskWrapper[] {
method execute (line 290) | async execute(
FILE: packages/a2a-server/src/agent/task.ts
type UnionKeys (line 70) | type UnionKeys<T> = T extends T ? keyof T : never;
class Task (line 72) | class Task {
method isYoloMatch (line 90) | private get isYoloMatch(): boolean {
method constructor (line 105) | private constructor(
method create (line 134) | static async create(
method getMetadata (line 147) | async getMetadata(): Promise<TaskMetadata> {
method _resetToolCompletionPromise (line 179) | private _resetToolCompletionPromise(): void {
method _registerToolCall (line 189) | private _registerToolCall(toolCallId: string, status: string): void {
method _resolveToolCall (line 200) | private _resolveToolCall(toolCallId: string): void {
method waitForPendingTools (line 212) | async waitForPendingTools(): Promise<void> {
method cancelPendingTools (line 222) | cancelPendingTools(reason: string): void {
method _createTextMessage (line 239) | private _createTextMessage(
method _createStatusUpdateEvent (line 253) | private _createStatusUpdateEvent(
method setTaskStateAndPublishUpdate (line 296) | setTaskStateAndPublishUpdate(
method _schedulerOutputUpdate (line 333) | private _schedulerOutputUpdate(
method setupEventDrivenScheduler (line 381) | private setupEventDrivenScheduler(): Scheduler {
method dispose (line 400) | dispose(): void {
method handleEventDrivenToolCallsUpdate (line 413) | private handleEventDrivenToolCallsUpdate(
method handleEventDrivenToolCall (line 429) | private handleEventDrivenToolCall(tc: ToolCall): void {
method checkInputRequiredState (line 501) | private checkInputRequiredState(): void {
method _pickFields (line 545) | private _pickFields<
method toolStatusMessage (line 558) | private toolStatusMessage(
method getProposedContent (line 609) | private async getProposedContent(
method _applyReplacement (line 635) | private _applyReplacement(
method scheduleToolCalls (line 657) | async scheduleToolCalls(
method acceptAgentMessage (line 767) | async acceptAgentMessage(event: ServerGeminiStreamEvent): Promise<void> {
method _handleToolConfirmationPart (line 879) | private async _handleToolConfirmationPart(part: Part): Promise<boolean> {
method getAndClearCompletedTools (line 1024) | getAndClearCompletedTools(): CompletedToolCall[] {
method addToolResponsesToHistory (line 1033) | addToolResponsesToHistory(completedTools: CompletedToolCall[]): void {
method sendCompletedToolsToLlm (line 1058) | async *sendCompletedToolsToLlm(
method acceptUserMessage (line 1097) | async *acceptUserMessage(
method _sendTextContent (line 1171) | _sendTextContent(content: string, traceId?: string): void {
method _sendThought (line 1192) | _sendThought(content: ThoughtSummary, traceId?: string): void {
method _sendCitation (line 1226) | _sendCitation(citation: string) {
FILE: packages/a2a-server/src/commands/command-registry.ts
class CommandRegistry (line 14) | class CommandRegistry {
method constructor (line 17) | constructor() {
method initialize (line 21) | initialize() {
method register (line 29) | register(command: Command) {
method get (line 42) | get(commandName: string): Command | undefined {
method getAllCommands (line 46) | getAllCommands(): Command[] {
FILE: packages/a2a-server/src/commands/extensions.ts
class ExtensionsCommand (line 14) | class ExtensionsCommand implements Command {
method execute (line 20) | async execute(
class ListExtensionsCommand (line 28) | class ListExtensionsCommand implements Command {
method execute (line 32) | async execute(
FILE: packages/a2a-server/src/commands/init.ts
class InitCommand (line 25) | class InitCommand implements Command {
method handleMessageResult (line 31) | private handleMessageResult(
method handleSubmitPromptResult (line 75) | private async handleSubmitPromptResult(
method execute (line 127) | async execute(
FILE: packages/a2a-server/src/commands/memory.test.ts
method toolRegistry (line 62) | get toolRegistry() {
FILE: packages/a2a-server/src/commands/memory.ts
constant DEFAULT_SANITIZATION_CONFIG (line 20) | const DEFAULT_SANITIZATION_CONFIG = {
class MemoryCommand (line 26) | class MemoryCommand implements Command {
method execute (line 38) | async execute(
class ShowMemoryCommand (line 46) | class ShowMemoryCommand implements Command {
method execute (line 50) | async execute(
class RefreshMemoryCommand (line 59) | class RefreshMemoryCommand implements Command {
method execute (line 63) | async execute(
class ListMemoryCommand (line 72) | class ListMemoryCommand implements Command {
method execute (line 76) | async execute(
class AddMemoryCommand (line 85) | class AddMemoryCommand implements Command {
method execute (line 89) | async execute(
FILE: packages/a2a-server/src/commands/restore.ts
class RestoreCommand (line 21) | class RestoreCommand implements Command {
method execute (line 29) | async execute(
class ListCheckpointsCommand (line 114) | class ListCheckpointsCommand implements Command {
method execute (line 119) | async execute(context: CommandContext): Promise<CommandExecutionRespon...
FILE: packages/a2a-server/src/commands/types.ts
type CommandContext (line 10) | interface CommandContext {
type CommandArgument (line 17) | interface CommandArgument {
type Command (line 23) | interface Command {
type CommandExecutionResponse (line 38) | interface CommandExecutionResponse {
FILE: packages/a2a-server/src/config/config.ts
function loadConfig (line 40) | async function loadConfig(
function setTargetDir (line 199) | function setTargetDir(agentSettings: AgentSettings | undefined): string {
function loadEnvironment (line 227) | function loadEnvironment(): void {
function findEnvFile (line 234) | function findEnvFile(startDir: string): string | null {
function refreshAuthentication (line 263) | async function refreshAuthentication(
FILE: packages/a2a-server/src/config/extension.ts
constant EXTENSIONS_DIRECTORY_NAME (line 20) | const EXTENSIONS_DIRECTORY_NAME = path.join(GEMINI_DIR, 'extensions');
constant EXTENSIONS_CONFIG_FILENAME (line 21) | const EXTENSIONS_CONFIG_FILENAME = 'gemini-extension.json';
constant INSTALL_METADATA_FILENAME (line 22) | const INSTALL_METADATA_FILENAME = '.gemini-extension-install.json';
type ExtensionConfig (line 31) | interface ExtensionConfig {
function loadExtensions (line 39) | function loadExtensions(workspaceDir: string): GeminiCLIExtension[] {
function loadExtensionsFromDir (line 60) | function loadExtensionsFromDir(dir: string): GeminiCLIExtension[] {
function loadExtension (line 78) | function loadExtension(extensionDir: string): GeminiCLIExtension | null {
function getContextFileNames (line 130) | function getContextFileNames(config: ExtensionConfig): string[] {
function loadInstallMetadata (line 139) | function loadInstallMetadata(
FILE: packages/a2a-server/src/config/settings.ts
constant USER_SETTINGS_DIR (line 20) | const USER_SETTINGS_DIR = path.join(homedir(), GEMINI_DIR);
constant USER_SETTINGS_PATH (line 21) | const USER_SETTINGS_PATH = path.join(USER_SETTINGS_DIR, 'settings.json');
type Settings (line 26) | interface Settings {
type SettingsError (line 56) | interface SettingsError {
type CheckpointingSettings (line 61) | interface CheckpointingSettings {
function loadSettings (line 73) | function loadSettings(workspaceDir: string): Settings {
function resolveEnvVarsInString (line 134) | function resolveEnvVarsInString(value: string): string {
function resolveEnvVarsInObject (line 146) | function resolveEnvVarsInObject<T>(obj: T): T {
FILE: packages/a2a-server/src/http/app.ts
type CommandResponse (line 36) | type CommandResponse = {
function updateCoderAgentCardUrl (line 90) | function updateCoderAgentCardUrl(port: number) {
function handleExecuteCommand (line 123) | async function handleExecuteCommand(
function createApp (line 195) | async function createApp() {
function main (line 372) | async function main() {
FILE: packages/a2a-server/src/http/endpoints.test.ts
class MockTask (line 29) | class MockTask {
method constructor (line 41) | constructor(id: string, contextId: string) {
FILE: packages/a2a-server/src/persistence/gcs.test.ts
constant TEST_METADATA_KEY (line 114) | const TEST_METADATA_KEY = METADATA_KEY || '__persistedState';
type MockWriteStream (line 116) | type MockWriteStream = {
type MockFile (line 133) | type MockFile = {
type MockBucket (line 140) | type MockBucket = {
type MockStorageInstance (line 146) | type MockStorageInstance = {
FILE: packages/a2a-server/src/persistence/gcs.ts
type ObjectType (line 21) | type ObjectType = 'metadata' | 'workspace';
class GCSTaskStore (line 33) | class GCSTaskStore implements TaskStore {
method constructor (line 38) | constructor(bucketName: string) {
method initializeBucket (line 50) | private async initializeBucket(): Promise<void> {
method ensureBucketInitialized (line 83) | private async ensureBucketInitialized(): Promise<void> {
method getObjectPath (line 87) | private getObjectPath(taskId: string, type: ObjectType): string {
method save (line 94) | async save(task: SDKTask): Promise<void> {
method load (line 233) | async load(taskId: string): Promise<SDKTask | undefined> {
class NoOpTaskStore (line 305) | class NoOpTaskStore implements TaskStore {
method constructor (line 306) | constructor(private realStore: TaskStore) {}
method save (line 308) | async save(task: SDKTask): Promise<void> {
method load (line 313) | async load(taskId: string): Promise<SDKTask | undefined> {
FILE: packages/a2a-server/src/types.ts
type CoderAgentEvent (line 15) | enum CoderAgentEvent {
type AgentSettings (line 46) | interface AgentSettings {
type ToolCallConfirmation (line 52) | interface ToolCallConfirmation {
type ToolCallUpdate (line 56) | interface ToolCallUpdate {
type TextContent (line 60) | interface TextContent {
type StateChange (line 64) | interface StateChange {
type Thought (line 68) | interface Thought {
type Citation (line 72) | interface Citation {
type ThoughtSummary (line 76) | type ThoughtSummary = {
type ToolConfirmationResponse (line 81) | interface ToolConfirmationResponse {
type CoderAgentMessage (line 86) | type CoderAgentMessage =
type TaskMetadata (line 95) | interface TaskMetadata {
type PersistedStateMetadata (line 116) | interface PersistedStateMetadata {
type PersistedTaskMetadata (line 121) | type PersistedTaskMetadata = { [k: string]: unknown };
constant METADATA_KEY (line 123) | const METADATA_KEY = '__persistedState';
function isAgentSettings (line 125) | function isAgentSettings(value: unknown): value is AgentSettings {
function isPersistedStateMetadata (line 136) | function isPersistedStateMetadata(
function getPersistedState (line 148) | function getPersistedState(
function getContextIdFromMetadata (line 158) | function getContextIdFromMetadata(
function getAgentSettingsFromMetadata (line 168) | function getAgentSettingsFromMetadata(
function setPersistedState (line 181) | function setPersistedState(
FILE: packages/a2a-server/src/utils/executor_utils.ts
function pushTaskStateFailed (line 13) | async function pushTaskStateFailed(
FILE: packages/a2a-server/src/utils/testing_utils.ts
function createMockConfig (line 31) | function createMockConfig(
function createStreamMessageRequest (line 140) | function createStreamMessageRequest(
function assertUniqueFinalEventIsLast (line 191) | function assertUniqueFinalEventIsLast(
function assertTaskCreationAndWorkingStatus (line 214) | function assertTaskCreationAndWorkingStatus(
FILE: packages/cli/examples/ask-user-dialog-demo.tsx
constant DEMO_QUESTIONS (line 13) | const DEMO_QUESTIONS: Question[] = [
FILE: packages/cli/examples/scrollable-list-demo.tsx
type Item (line 21) | interface Item {
FILE: packages/cli/src/acp/acpClient.test.ts
method config (line 180) | get config() {
method config (line 662) | get config() {
method toolRegistry (line 665) | get toolRegistry() {
method start (line 1410) | start(controller) {
FILE: packages/cli/src/acp/acpClient.ts
function hasMeta (line 57) | function hasMeta(obj: unknown): obj is { _meta?: Record<string, unknown>...
function runAcpClient (line 76) | async function runAcpClient(
class GeminiAgent (line 100) | class GeminiAgent {
method constructor (line 107) | constructor(
method initialize (line 114) | async initialize(
method authenticate (line 177) | async authenticate(req: acp.AuthenticateRequest): Promise<void> {
method newSession (line 240) | async newSession({
method loadSession (line 339) | async loadSession({
method initializeSessionConfig (line 409) | private async initializeSessionConfig(
method newSessionConfig (line 445) | async newSessionConfig(
method cancel (line 497) | async cancel(params: acp.CancelNotification): Promise<void> {
method prompt (line 505) | async prompt(params: acp.PromptRequest): Promise<acp.PromptResponse> {
method setSessionMode (line 513) | async setSessionMode(
method unstable_setSessionModel (line 523) | async unstable_setSessionModel(
class Session (line 534) | class Session {
method constructor (line 538) | constructor(
method cancelPendingPrompt (line 546) | async cancelPendingPrompt(): Promise<void> {
method setMode (line 555) | setMode(modeId: acp.SessionModeId): acp.SetSessionModeResponse {
method getAvailableCommands (line 568) | private getAvailableCommands() {
method sendAvailableCommands (line 572) | async sendAvailableCommands(): Promise<void> {
method setModel (line 584) | setModel(modelId: acp.ModelId): acp.SetSessionModelResponse {
method streamHistory (line 589) | async streamHistory(messages: ConversationRecord['messages']): Promise...
method prompt (line 659) | async prompt(params: acp.PromptRequest): Promise<acp.PromptResponse> {
method handleCommand (line 865) | private async handleCommand(
method sendUpdate (line 886) | private async sendUpdate(update: acp.SessionUpdate): Promise<void> {
method runTool (line 895) | private async runTool(
method #resolvePrompt (line 1138) | async #resolvePrompt(
method debug (line 1481) | debug(msg: string) {
function toToolCallContent (line 1488) | function toToolCallContent(toolResult: ToolResult): acp.ToolCallContent ...
function toPermissionOptions (line 1537) | function toPermissionOptions(
function toAcpToolKind (line 1615) | function toAcpToolKind(kind: Kind): acp.ToolKind {
function buildAvailableModes (line 1637) | function buildAvailableModes(isPlanEnabled: boolean): acp.SessionMode[] {
function buildAvailableModels (line 1667) | function buildAvailableModels(
FILE: packages/cli/src/acp/acpErrors.ts
function getAcpErrorMessage (line 14) | function getAcpErrorMessage(error: unknown): string {
function extractRecursiveMessage (line 19) | function extractRecursiveMessage(input: string): string {
FILE: packages/cli/src/acp/acpResume.test.ts
method config (line 100) | get config() {
FILE: packages/cli/src/acp/commandHandler.ts
class CommandHandler (line 14) | class CommandHandler {
method constructor (line 17) | constructor() {
method createRegistry (line 21) | private static createRegistry(): CommandRegistry {
method getAvailableCommands (line 30) | getAvailableCommands(): Array<{ name: string; description: string }> {
method handleCommand (line 41) | async handleCommand(
method runCommand (line 55) | private async runCommand(
method parseSlashCommand (line 94) | private parseSlashCommand(query: string): {
FILE: packages/cli/src/acp/commands/commandRegistry.ts
class CommandRegistry (line 10) | class CommandRegistry {
method register (line 13) | register(command: Command) {
method get (line 26) | get(commandName: string): Command | undefined {
method getAllCommands (line 30) | getAllCommands(): Command[] {
FILE: packages/cli/src/acp/commands/extensions.ts
class ExtensionsCommand (line 25) | class ExtensionsCommand implements Command {
method execute (line 40) | async execute(
class ListExtensionsCommand (line 48) | class ListExtensionsCommand implements Command {
method execute (line 52) | async execute(
class ExploreExtensionsCommand (line 63) | class ExploreExtensionsCommand implements Command {
method execute (line 67) | async execute(
function getEnableDisableContext (line 79) | function getEnableDisableContext(
class EnableExtensionCommand (line 128) | class EnableExtensionCommand implements Command {
method execute (line 132) | async execute(
class DisableExtensionCommand (line 186) | class DisableExtensionCommand implements Command {
method execute (line 190) | async execute(
class InstallExtensionCommand (line 219) | class InstallExtensionCommand implements Command {
method execute (line 223) | async execute(
class LinkExtensionCommand (line 264) | class LinkExtensionCommand implements Command {
method execute (line 268) | async execute(
class UninstallExtensionCommand (line 309) | class UninstallExtensionCommand implements Command {
method execute (line 313) | async execute(
class RestartExtensionCommand (line 365) | class RestartExtensionCommand implements Command {
method execute (line 369) | async execute(
class UpdateExtensionCommand (line 420) | class UpdateExtensionCommand implements Command {
method execute (line 424) | async execute(
FILE: packages/cli/src/acp/commands/init.ts
class InitCommand (line 16) | class InitCommand implements Command {
method execute (line 21) | async execute(
FILE: packages/cli/src/acp/commands/memory.ts
constant DEFAULT_SANITIZATION_CONFIG (line 19) | const DEFAULT_SANITIZATION_CONFIG = {
class MemoryCommand (line 25) | class MemoryCommand implements Command {
method execute (line 36) | async execute(
class ShowMemoryCommand (line 44) | class ShowMemoryCommand implements Command {
method execute (line 48) | async execute(
class RefreshMemoryCommand (line 57) | class RefreshMemoryCommand implements Command {
method execute (line 62) | async execute(
class ListMemoryCommand (line 71) | class ListMemoryCommand implements Command {
method execute (line 75) | async execute(
class AddMemoryCommand (line 84) | class AddMemoryCommand implements Command {
method execute (line 88) | async execute(
FILE: packages/cli/src/acp/commands/restore.ts
class RestoreCommand (line 21) | class RestoreCommand implements Command {
method execute (line 28) | async execute(
class ListCheckpointsCommand (line 115) | class ListCheckpointsCommand implements Command {
method execute (line 119) | async execute(context: CommandContext): Promise<CommandExecutionRespon...
FILE: packages/cli/src/acp/commands/types.ts
type CommandContext (line 10) | interface CommandContext {
type CommandArgument (line 17) | interface CommandArgument {
type Command (line 23) | interface Command {
type CommandExecutionResponse (line 37) | interface CommandExecutionResponse {
FILE: packages/cli/src/acp/fileSystemService.ts
class AcpFileSystemService (line 13) | class AcpFileSystemService implements FileSystemService {
method constructor (line 14) | constructor(
method readTextFile (line 21) | async readTextFile(filePath: string): Promise<string> {
method writeTextFile (line 36) | async writeTextFile(filePath: string, content: string): Promise<void> {
FILE: packages/cli/src/commands/extensions/configure.ts
type ConfigureArgs (line 19) | interface ConfigureArgs {
FILE: packages/cli/src/commands/extensions/disable.test.ts
type MockYargs (line 159) | interface MockYargs {
type TestArgv (line 220) | interface TestArgv {
FILE: packages/cli/src/commands/extensions/disable.ts
type DisableArgs (line 15) | interface DisableArgs {
function handleDisable (line 20) | async function handleDisable(args: DisableArgs) {
FILE: packages/cli/src/commands/extensions/enable.test.ts
method constructor (line 49) | constructor(message: string) {
type MockYargs (line 210) | interface MockYargs {
type TestArgv (line 259) | interface TestArgv {
FILE: packages/cli/src/commands/extensions/enable.ts
type EnableArgs (line 20) | interface EnableArgs {
function handleEnable (line 25) | async function handleEnable(args: EnableArgs) {
FILE: packages/cli/src/commands/extensions/install.test.ts
function createMockExtension (line 174) | function createMockExtension(
FILE: packages/cli/src/commands/extensions/install.ts
type InstallArgs (line 34) | interface InstallArgs {
function handleInstall (line 42) | async function handleInstall(args: InstallArgs) {
FILE: packages/cli/src/commands/extensions/link.test.ts
type MockYargs (line 124) | interface MockYargs {
type TestArgv (line 159) | interface TestArgv {
FILE: packages/cli/src/commands/extensions/link.ts
type InstallArgs (line 24) | interface InstallArgs {
function handleLink (line 29) | async function handleLink(args: InstallArgs) {
FILE: packages/cli/src/commands/extensions/list.ts
function handleList (line 15) | async function handleList(options?: { outputFormat?: 'text' | 'json' }) {
FILE: packages/cli/src/commands/extensions/new.ts
type NewArgs (line 14) | interface NewArgs {
constant EXAMPLES_PATH (line 22) | const EXAMPLES_PATH = join(__dirname, 'examples');
function pathExists (line 24) | async function pathExists(path: string) {
function createDirectory (line 33) | async function createDirectory(path: string) {
function copyDirectory (line 40) | async function copyDirectory(template: string, path: string) {
function handleNew (line 52) | async function handleNew(args: NewArgs) {
function getBoilerplateChoices (line 76) | async function getBoilerplateChoices() {
FILE: packages/cli/src/commands/extensions/uninstall.test.ts
type MockYargs (line 282) | interface MockYargs {
type TestArgv (line 338) | interface TestArgv {
FILE: packages/cli/src/commands/extensions/uninstall.ts
type UninstallArgs (line 15) | interface UninstallArgs {
function handleUninstall (line 20) | async function handleUninstall(args: UninstallArgs) {
FILE: packages/cli/src/commands/extensions/update.test.ts
type MockYargs (line 206) | interface MockYargs {
FILE: packages/cli/src/commands/extensions/update.ts
type UpdateArgs (line 27) | interface UpdateArgs {
function handleUpdate (line 35) | async function handleUpdate(args: UpdateArgs) {
FILE: packages/cli/src/commands/extensions/utils.ts
type ConfigLogger (line 23) | interface ConfigLogger {
type RequestSettingCallback (line 28) | type RequestSettingCallback = (
type RequestConfirmationCallback (line 31) | type RequestConfirmationCallback = (message: string) => Promise<boolean>;
function getExtensionManager (line 54) | async function getExtensionManager() {
function getExtensionAndManager (line 66) | async function getExtensionAndManager(
function configureSpecificSetting (line 83) | async function configureSpecificSetting(
function configureExtension (line 121) | async function configureExtension(
function configureAllExtensions (line 160) | async function configureAllExtensions(
function configureExtensionSettings (line 196) | async function configureExtensionSettings(
function getFormattedSettingValue (line 254) | function getFormattedSettingValue(
FILE: packages/cli/src/commands/extensions/validate.ts
type ValidateArgs (line 19) | interface ValidateArgs {
function handleValidate (line 23) | async function handleValidate(args: ValidateArgs) {
function validateExtension (line 33) | async function validateExtension(args: ValidateArgs) {
FILE: packages/cli/src/commands/hooks/migrate.ts
type MigrateArgs (line 15) | interface MigrateArgs {
constant EVENT_MAPPING (line 22) | const EVENT_MAPPING: Record<string, string> = {
constant TOOL_NAME_MAPPING (line 37) | const TOOL_NAME_MAPPING: Record<string, string> = {
function transformMatcher (line 50) | function transformMatcher(matcher: string | undefined): string | undefin...
function migrateClaudeHook (line 68) | function migrateClaudeHook(claudeHook: unknown): unknown {
function migrateClaudeHooks (line 108) | function migrateClaudeHooks(claudeConfig: unknown): Record<string, unkno...
function handleMigrateFromClaude (line 173) | async function handleMigrateFromClaude() {
FILE: packages/cli/src/commands/mcp/add.ts
function addMcpServer (line 13) | async function addMcpServer(
FILE: packages/cli/src/commands/mcp/enableDisable.ts
constant GREEN (line 18) | const GREEN = '\x1b[32m';
constant YELLOW (line 19) | const YELLOW = '\x1b[33m';
constant RED (line 20) | const RED = '\x1b[31m';
constant RESET (line 21) | const RESET = '\x1b[0m';
type Args (line 23) | interface Args {
function handleEnable (line 28) | async function handleEnable(args: Args): Promise<void> {
function handleDisable (line 74) | async function handleDisable(args: Args): Promise<void> {
FILE: packages/cli/src/commands/mcp/list.test.ts
type MockClient (line 85) | interface MockClient {
type MockExtensionManager (line 91) | interface MockExtensionManager {
type MockTransport (line 95) | interface MockTransport {
FILE: packages/cli/src/commands/mcp/list.ts
function getMcpServersFromConfig (line 33) | async function getMcpServersFromConfig(
function testMCPConnection (line 69) | async function testMCPConnection(
function getServerStatus (line 143) | async function getServerStatus(
function listMcpServers (line 172) | async function listMcpServers(
type ListArgs (line 252) | interface ListArgs {
FILE: packages/cli/src/commands/mcp/remove.ts
function removeMcpServer (line 13) | async function removeMcpServer(
FILE: packages/cli/src/commands/skills/disable.ts
type DisableArgs (line 15) | interface DisableArgs {
function handleDisable (line 20) | async function handleDisable(args: DisableArgs) {
FILE: packages/cli/src/commands/skills/enable.ts
type EnableArgs (line 15) | interface EnableArgs {
function handleEnable (line 19) | async function handleEnable(args: EnableArgs) {
FILE: packages/cli/src/commands/skills/install.ts
type InstallArgs (line 21) | interface InstallArgs {
function handleInstall (line 28) | async function handleInstall(args: InstallArgs) {
FILE: packages/cli/src/commands/skills/link.ts
type LinkArgs (line 18) | interface LinkArgs {
function handleLink (line 24) | async function handleLink(args: LinkArgs) {
FILE: packages/cli/src/commands/skills/list.ts
function handleList (line 14) | async function handleList(args: { all?: boolean }) {
FILE: packages/cli/src/commands/skills/uninstall.ts
type UninstallArgs (line 13) | interface UninstallArgs {
function handleUninstall (line 18) | async function handleUninstall(args: UninstallArgs) {
FILE: packages/cli/src/commands/utils.ts
function exitCli (line 9) | async function exitCli(exitCode = 0) {
FILE: packages/cli/src/config/auth.ts
function validateAuthMethod (line 10) | function validateAuthMethod(authMethod: string): string | null {
FILE: packages/cli/src/config/config.integration.test.ts
constant CLEARCUT_URL (line 45) | const CLEARCUT_URL = 'https://play.googleapis.com/log';
FILE: packages/cli/src/config/config.test.ts
type FileFilteringSettings (line 2887) | type FileFilteringSettings = NonNullable<
FILE: packages/cli/src/config/config.ts
type CliArgs (line 70) | interface CliArgs {
function parseArguments (line 118) | async function parseArguments(
function isDebugMode (line 409) | function isDebugMode(argv: CliArgs): boolean {
type LoadCliConfigOptions (line 418) | interface LoadCliConfigOptions {
function loadCliConfig (line 425) | async function loadCliConfig(
function mergeExcludeTools (line 933) | function mergeExcludeTools(
FILE: packages/cli/src/config/extension-manager.ts
type ExtensionManagerParams (line 87) | interface ExtensionManagerParams {
class ExtensionManager (line 103) | class ExtensionManager extends ExtensionLoader {
method constructor (line 116) | constructor(options: ExtensionManagerParams) {
method getEnablementManager (line 139) | getEnablementManager(): ExtensionEnablementManager {
method verifyExtensionIntegrity (line 143) | async verifyExtensionIntegrity(
method storeExtensionIntegrity (line 150) | async storeExtensionIntegrity(
method setRequestConsent (line 157) | setRequestConsent(
method setRequestSetting (line 163) | setRequestSetting(
method getExtensions (line 169) | getExtensions(): GeminiCLIExtension[] {
method installOrUpdateExtension (line 178) | async installOrUpdateExtension(
method uninstallExtension (line 546) | async uninstallExtension(
method startExtension (line 589) | protected override async startExtension(extension: GeminiCLIExtension) {
method stopExtension (line 596) | protected override async stopExtension(extension: GeminiCLIExtension) {
method loadExtensions (line 606) | async loadExtensions(): Promise<GeminiCLIExtension[]> {
method loadExtension (line 676) | async loadExtension(
method _buildExtension (line 706) | private async _buildExtension(
method restartExtension (line 1001) | override async restartExtension(
method unloadExtension (line 1013) | private unloadExtension(
method loadExtensionConfig (line 1022) | async loadExtensionConfig(extensionDir: string): Promise<ExtensionConf...
method loadExtensionHooks (line 1059) | private async loadExtensionHooks(
method toOutputString (line 1109) | toOutputString(extension: GeminiCLIExtension): string {
method disableExtension (line 1178) | async disableExtension(name: string, scope: SettingScope) {
method enableExtension (line 1213) | async enableExtension(name: string, scope: SettingScope) {
function filterMcpConfig (line 1245) | function filterMcpConfig(original: MCPServerConfig): MCPServerConfig {
function makeWritableRecursive (line 1255) | async function makeWritableRecursive(targetPath: string): Promise<void> {
function copyExtension (line 1271) | async function copyExtension(
function getContextFileNames (line 1279) | function getContextFileNames(config: ExtensionConfig): string[] {
function validateName (line 1288) | function validateName(name: string) {
function inferInstallMetadata (line 1296) | async function inferInstallMetadata(
function getExtensionId (line 1335) | function getExtensionId(
function hashValue (line 1359) | function hashValue(value: string): string {
FILE: packages/cli/src/config/extension.test.ts
type MockKeychainStorage (line 150) | interface MockKeychainStorage {
function isEnabled (line 2345) | function isEnabled(options: { name: string; enabledForPath: string }) {
FILE: packages/cli/src/config/extension.ts
type ExtensionConfig (line 24) | interface ExtensionConfig {
type ExtensionUpdateInfo (line 51) | interface ExtensionUpdateInfo {
function loadInstallMetadata (line 57) | function loadInstallMetadata(
FILE: packages/cli/src/config/extensionRegistryClient.ts
type RegistryExtension (line 15) | interface RegistryExtension {
class ExtensionRegistryClient (line 36) | class ExtensionRegistryClient {
method constructor (line 45) | constructor(registryURI?: string) {
method resetCache (line 51) | static resetCache() {
method getExtensions (line 55) | async getExtensions(
method searchExtensions (line 85) | async searchExtensions(query: string): Promise<RegistryExtension[]> {
method getExtension (line 102) | async getExtension(id: string): Promise<RegistryExtension | undefined> {
method fetchAllExtensions (line 107) | private async fetchAllExtensions(): Promise<RegistryExtension[]> {
FILE: packages/cli/src/config/extensions/consent.test.ts
function expectConsentSnapshot (line 61) | async function expectConsentSnapshot(consentString: string) {
function normalizePathsForSnapshot (line 72) | function normalizePathsForSnapshot(str: string, tempDir: string): string {
FILE: packages/cli/src/config/extensions/consent.ts
constant INSTALL_WARNING_MESSAGE (line 16) | const INSTALL_WARNING_MESSAGE = chalk.yellow(
constant SKILLS_WARNING_MESSAGE (line 20) | const SKILLS_WARNING_MESSAGE = chalk.yellow(
function skillsConsentString (line 27) | async function skillsConsentString(
function requestConsentNonInteractive (line 59) | async function requestConsentNonInteractive(
function requestConsentInteractive (line 78) | async function requestConsentInteractive(
function promptForConsentNonInteractive (line 97) | async function promptForConsentNonInteractive(
function promptForConsentInteractive (line 129) | async function promptForConsentInteractive(
function extensionConsentString (line 147) | async function extensionConsentString(
function renderSkillsList (line 218) | async function renderSkillsList(skills: SkillDefinition[]): Promise<stri...
function maybeRequestConsentOrFail (line 245) | async function maybeRequestConsentOrFail(
FILE: packages/cli/src/config/extensions/extensionEnablement.test.ts
function createTestDir (line 31) | function createTestDir() {
FILE: packages/cli/src/config/extensions/extensionEnablement.ts
type ExtensionEnablementConfig (line 12) | interface ExtensionEnablementConfig {
type AllExtensionsEnablementConfig (line 16) | interface AllExtensionsEnablementConfig {
class Override (line 20) | class Override {
method constructor (line 21) | constructor(
method fromInput (line 27) | static fromInput(inputRule: string, includeSubdirs: boolean): Override {
method fromFileRule (line 34) | static fromFileRule(fileRule: string): Override {
method conflictsWith (line 44) | conflictsWith(other: Override): boolean {
method isEqualTo (line 54) | isEqualTo(other: Override): boolean {
method asRegex (line 62) | asRegex(): RegExp {
method isChildOf (line 66) | isChildOf(parent: Override) {
method output (line 73) | output(): string {
method matchesPath (line 77) | matchesPath(path: string) {
function globToRegex (line 101) | function globToRegex(glob: string): RegExp {
class ExtensionEnablementManager (line 109) | class ExtensionEnablementManager {
method constructor (line 116) | constructor(enabledExtensionNames?: string[]) {
method validateExtensionOverrides (line 126) | validateExtensionOverrides(extensions: GeminiCLIExtension[]) {
method isEnabled (line 145) | isEnabled(extensionName: string, currentPath: string): boolean {
method readConfig (line 179) | readConfig(): AllExtensionsEnablementConfig {
method writeConfig (line 201) | writeConfig(config: AllExtensionsEnablementConfig): void {
method enable (line 206) | enable(
method disable (line 231) | disable(
method remove (line 239) | remove(extensionName: string): void {
FILE: packages/cli/src/config/extensions/extensionSettings.ts
type ExtensionSettingScope (line 19) | enum ExtensionSettingScope {
type ExtensionSetting (line 24) | interface ExtensionSetting {
function maybePromptForSettings (line 62) | async function maybePromptForSettings(
function formatEnvContent (line 139) | function formatEnvContent(settings: Record<string, string>): string {
function promptForSetting (line 160) | async function promptForSetting(
function getScopedEnvContents (line 172) | async function getScopedEnvContents(
function getEnvContents (line 205) | async function getEnvContents(
function updateSetting (line 229) | async function updateSetting(
type settingsChanges (line 306) | interface settingsChanges {
function getSettingsChanges (line 312) | function getSettingsChanges(
function clearSettings (line 340) | async function clearSettings(
function getMissingSettings (line 360) | async function getMissingSettings(
FILE: packages/cli/src/config/extensions/extensionUpdates.test.ts
method constructor (line 116) | constructor(public name: string) {}
method getExtensionDir (line 117) | getExtensionDir() {
method getUserExtensionsDir (line 120) | static getUserExtensionsDir() {
method createTmpDir (line 123) | static createTmpDir() {
FILE: packages/cli/src/config/extensions/github.ts
function cloneFromGit (line 31) | async function cloneFromGit(
type GithubRepoInfo (line 82) | interface GithubRepoInfo {
function tryParseGithubUrl (line 87) | function tryParseGithubUrl(source: string): GithubRepoInfo | null {
function fetchReleaseFromGithub (line 135) | async function fetchReleaseFromGithub(
function checkForExtensionUpdate (line 170) | async function checkForExtensionUpdate(
type GitHubDownloadResult (line 300) | type GitHubDownloadResult =
function downloadFromGitHubRelease (line 319) | async function downloadFromGitHubRelease(
type GithubReleaseData (line 464) | interface GithubReleaseData {
type Asset (line 471) | interface Asset {
function findReleaseAsset (line 476) | function findReleaseAsset(assets: Asset[]): Asset | undefined {
type DownloadOptions (line 513) | interface DownloadOptions {
function downloadFile (line 517) | async function downloadFile(
function extractFile (line 564) | async function extractFile(file: string, dest: string): Promise<void> {
FILE: packages/cli/src/config/extensions/github_fetch.ts
function getGitHubToken (line 9) | function getGitHubToken(): string | undefined {
function fetchJson (line 13) | async function fetchJson<T>(
FILE: packages/cli/src/config/extensions/storage.ts
class ExtensionStorage (line 16) | class ExtensionStorage {
method constructor (line 19) | constructor(extensionName: string) {
method getExtensionDir (line 23) | getExtensionDir(): string {
method getConfigPath (line 30) | getConfigPath(): string {
method getEnvFilePath (line 34) | getEnvFilePath(): string {
method getUserExtensionsDir (line 38) | static getUserExtensionsDir(): string {
method createTmpDir (line 42) | static async createTmpDir(): Promise<string> {
FILE: packages/cli/src/config/extensions/update.ts
type ExtensionUpdateInfo (line 24) | interface ExtensionUpdateInfo {
function updateExtension (line 30) | async function updateExtension(
function updateAllUpdatableExtensions (line 152) | async function updateAllUpdatableExtensions(
type ExtensionUpdateCheckResult (line 180) | interface ExtensionUpdateCheckResult {
function checkForAllExtensionUpdates (line 185) | async function checkForAllExtensionUpdates(
FILE: packages/cli/src/config/extensions/variableSchema.ts
type VariableDefinition (line 7) | interface VariableDefinition {
type VariableSchema (line 14) | interface VariableSchema {
constant PATH_SEPARATOR_DEFINITION (line 18) | const PATH_SEPARATOR_DEFINITION = {
constant VARIABLE_SCHEMA (line 23) | const VARIABLE_SCHEMA = {
FILE: packages/cli/src/config/extensions/variables.ts
constant UNMARSHALL_KEY_IGNORE_LIST (line 15) | const UNMARSHALL_KEY_IGNORE_LIST: Set<string> = new Set<string>([
constant EXTENSIONS_DIRECTORY_NAME (line 21) | const EXTENSIONS_DIRECTORY_NAME = path.join(GEMINI_DIR, 'extensions');
constant EXTENSIONS_CONFIG_FILENAME (line 22) | const EXTENSIONS_CONFIG_FILENAME = 'gemini-extension.json';
constant INSTALL_METADATA_FILENAME (line 23) | const INSTALL_METADATA_FILENAME = '.gemini-extension-install.json';
constant EXTENSION_SETTINGS_FILENAME (line 24) | const EXTENSION_SETTINGS_FILENAME = '.env';
type JsonObject (line 26) | type JsonObject = { [key: string]: JsonValue };
type JsonArray (line 27) | type JsonArray = JsonValue[];
type JsonValue (line 28) | type JsonValue =
type VariableContext (line 36) | type VariableContext = {
function validateVariables (line 40) | function validateVariables(
function hydrateString (line 52) | function hydrateString(str: string, context: VariableContext): string {
function recursivelyHydrateStrings (line 60) | function recursivelyHydrateStrings<T>(
FILE: packages/cli/src/config/footerItems.ts
constant ALL_ITEMS (line 9) | const ALL_ITEMS = [
type FooterItemId (line 62) | type FooterItemId = (typeof ALL_ITEMS)[number]['id'];
constant DEFAULT_ORDER (line 64) | const DEFAULT_ORDER = [
function deriveItemsFromLegacySettings (line 77) | function deriveItemsFromLegacySettings(
constant VALID_IDS (line 114) | const VALID_IDS: Set<string> = new Set(ALL_ITEMS.map((i) => i.id));
function resolveFooterState (line 120) | function resolveFooterState(settings: MergedSettings): {
FILE: packages/cli/src/config/mcp/mcpServerEnablement.test.ts
function createMockEnablement (line 32) | function createMockEnablement(
function setupFsMocks (line 42) | function setupFsMocks(): void {
FILE: packages/cli/src/config/mcp/mcpServerEnablement.ts
type McpServerEnablementState (line 14) | interface McpServerEnablementState {
type McpServerEnablementConfig (line 21) | interface McpServerEnablementConfig {
type McpServerDisplayState (line 28) | interface McpServerDisplayState {
type EnablementCallbacks (line 40) | interface EnablementCallbacks {
type ServerLoadResult (line 48) | interface ServerLoadResult {
function normalizeServerId (line 57) | function normalizeServerId(serverId: string): string {
function isInSettingsList (line 65) | function isInSettingsList(
function canLoadServer (line 100) | async function canLoadServer(
constant MCP_ENABLEMENT_FILENAME (line 181) | const MCP_ENABLEMENT_FILENAME = 'mcp-server-enablement.json';
class McpServerEnablementManager (line 193) | class McpServerEnablementManager {
method getInstance (line 203) | static getInstance(): McpServerEnablementManager {
method resetInstance (line 213) | static resetInstance(): void {
method constructor (line 217) | constructor() {
method isFileEnabled (line 226) | async isFileEnabled(serverName: string): Promise<boolean> {
method isSessionDisabled (line 235) | isSessionDisabled(serverName: string): boolean {
method isEffectivelyEnabled (line 243) | async isEffectivelyEnabled(serverName: string): Promise<boolean> {
method enable (line 254) | async enable(serverName: string): Promise<void> {
method disable (line 268) | async disable(serverName: string): Promise<void> {
method disableForSession (line 277) | disableForSession(serverName: string): void {
method clearSessionDisable (line 284) | clearSessionDisable(serverName: string): void {
method getDisplayState (line 291) | async getDisplayState(serverName: string): Promise<McpServerDisplaySta...
method getAllDisplayStates (line 305) | async getAllDisplayStates(
method getEnablementCallbacks (line 319) | getEnablementCallbacks(): EnablementCallbacks {
method autoEnableServers (line 330) | async autoEnableServers(serverNames: string[]): Promise<string[]> {
method readConfig (line 358) | private async readConfig(): Promise<McpServerEnablementConfig> {
method writeConfig (line 383) | private async writeConfig(config: McpServerEnablementConfig): Promise<...
FILE: packages/cli/src/config/policy.ts
function setAutoAcceptWorkspacePolicies (line 34) | function setAutoAcceptWorkspacePolicies(value: boolean) {
function setDisableWorkspacePolicies (line 48) | function setDisableWorkspacePolicies(value: boolean) {
function createPolicyEngineConfig (line 52) | async function createPolicyEngineConfig(
function createPolicyUpdater (line 74) | function createPolicyUpdater(
type WorkspacePolicyState (line 82) | interface WorkspacePolicyState {
function resolveWorkspacePolicyState (line 90) | async function resolveWorkspacePolicyState(options: {
FILE: packages/cli/src/config/sandboxConfig.test.ts
method constructor (line 20) | constructor(message: string) {
FILE: packages/cli/src/config/sandboxConfig.ts
type SandboxCliArgs (line 23) | interface SandboxCliArgs {
constant VALID_SANDBOX_COMMANDS (line 26) | const VALID_SANDBOX_COMMANDS = [
function isSandboxCommand (line 35) | function isSandboxCommand(
function getSandboxCommand (line 43) | function getSandboxCommand(
function loadSandboxConfig (line 126) | async function loadSandboxConfig(
FILE: packages/cli/src/config/settings-validation.ts
function buildZodSchemaFromJsonSchema (line 17) | function buildZodSchemaFromJsonSchema(def: any): z.ZodTypeAny {
function buildEnumSchema (line 80) | function buildEnumSchema(
function buildObjectShapeFromProperties (line 116) | function buildObjectShapeFromProperties(
function buildPrimitiveSchema (line 129) | function buildPrimitiveSchema(
constant REF_SCHEMAS (line 144) | const REF_SCHEMAS: Record<string, z.ZodTypeAny> = {};
function buildZodSchemaFromDefinition (line 154) | function buildZodSchemaFromDefinition(
function buildZodSchemaFromCollection (line 225) | function buildZodSchemaFromCollection(
function buildSettingsZodSchema (line 264) | function buildSettingsZodSchema(): z.ZodObject<Record<string, z.ZodTypeA...
function validateSettings (line 280) | function validateSettings(data: unknown): {
function formatValidationError (line 292) | function formatValidationError(
FILE: packages/cli/src/config/settings.test.ts
constant MOCK_WORKSPACE_DIR (line 95) | const MOCK_WORKSPACE_DIR = path.resolve(path.resolve('/mock/workspace'));
constant MOCK_WORKSPACE_SETTINGS_PATH (line 97) | const MOCK_WORKSPACE_SETTINGS_PATH = path.join(
type TestSettings (line 104) | type TestSettings = Settings & { [key: string]: unknown };
function setup (line 1906) | function setup({
type TestData (line 3162) | interface TestData {
FILE: packages/cli/src/config/settings.ts
function getMergeStrategyForPath (line 56) | function getMergeStrategyForPath(
constant USER_SETTINGS_PATH (line 79) | const USER_SETTINGS_PATH = Storage.getGlobalSettingsPath();
constant USER_SETTINGS_DIR (line 80) | const USER_SETTINGS_DIR = path.dirname(USER_SETTINGS_PATH);
constant DEFAULT_EXCLUDED_ENV_VARS (line 81) | const DEFAULT_EXCLUDED_ENV_VARS = ['DEBUG', 'DEBUG_MODE'];
constant AUTH_ENV_VAR_WHITELIST (line 83) | const AUTH_ENV_VAR_WHITELIST = [
function sanitizeEnvVar (line 94) | function sanitizeEnvVar(value: string): string {
function getSystemSettingsPath (line 98) | function getSystemSettingsPath(): string {
function getSystemDefaultsPath (line 111) | function getSystemDefaultsPath(): string {
type SettingScope (line 123) | enum SettingScope {
type LoadableSettingScope (line 136) | type LoadableSettingScope =
function isLoadableSettingScope (line 156) | function isLoadableSettingScope(
type CheckpointingSettings (line 162) | interface CheckpointingSettings {
type SummarizeToolOutputSettings (line 166) | interface SummarizeToolOutputSettings {
type LoadingPhrasesMode (line 170) | type LoadingPhrasesMode = 'tips' | 'witty' | 'all' | 'off';
type AccessibilitySettings (line 172) | interface AccessibilitySettings {
type SessionRetentionSettings (line 178) | interface SessionRetentionSettings {
type SettingsError (line 192) | interface SettingsError {
type SettingsFile (line 198) | interface SettingsFile {
function setNestedProperty (line 206) | function setNestedProperty(
function getDefaultsFromSchema (line 232) | function getDefaultsFromSchema(
function mergeSettings (line 247) | function mergeSettings(
function createTestMergedSettings (line 282) | function createTestMergedSettings(
type LoadedSettingsSnapshot (line 297) | interface LoadedSettingsSnapshot {
class LoadedSettings (line 307) | class LoadedSettings {
method constructor (line 308) | constructor(
method merged (line 341) | get merged(): MergedSettings {
method setTrusted (line 345) | setTrusted(isTrusted: boolean): void {
method createEmptyWorkspace (line 357) | private createEmptyWorkspace(workspace: SettingsFile): SettingsFile {
method computeMergedSettings (line 365) | private computeMergedSettings(): MergedSettings {
method computeSnapshot (line 393) | private computeSnapshot(): LoadedSettingsSnapshot {
method subscribe (line 414) | subscribe(listener: () => void): () => void {
method getSnapshot (line 419) | getSnapshot(): LoadedSettingsSnapshot {
method forScope (line 423) | forScope(scope: LoadableSettingScope): SettingsFile {
method isPersistable (line 438) | private isPersistable(settingsFile: SettingsFile): boolean {
method setValue (line 442) | setValue(scope: LoadableSettingScope, key: string, value: unknown): vo...
method setRemoteAdminSettings (line 468) | setRemoteAdminSettings(remoteSettings: AdminControlsSettings): void {
function findEnvFile (line 497) | function findEnvFile(startDir: string): string | null {
function setUpCloudShellEnvironment (line 526) | function setUpCloudShellEnvironment(
function loadEnvironment (line 552) | function loadEnvironment(
function resetSettingsCacheForTesting (line 631) | function resetSettingsCacheForTesting() {
function loadSettings (line 639) | function loadSettings(
function _doLoadSettings (line 651) | function _doLoadSettings(workspaceDir: string): LoadedSettings {
function migrateDeprecatedSettings (line 830) | function migrateDeprecatedSettings(
function saveSettings (line 1058) | function saveSettings(settingsFile: SettingsFile): void {
function saveModelChange (line 1086) | function saveModelChange(
function migrateExperimentalSettings (line 1102) | function migrateExperimentalSettings(
FILE: packages/cli/src/config/settingsSchema.ts
type SettingsType (line 28) | type SettingsType =
type SettingsValue (line 36) | type SettingsValue =
constant TOGGLE_TYPES (line 49) | const TOGGLE_TYPES: ReadonlySet<SettingsType | undefined> = new Set([
type SettingEnumOption (line 54) | interface SettingEnumOption {
function oneLine (line 59) | function oneLine(strings: TemplateStringsArray, ...values: unknown[]): s...
type SettingCollectionDefinition (line 70) | interface SettingCollectionDefinition {
type MergeStrategy (line 88) | enum MergeStrategy {
type SettingDefinition (line 99) | interface SettingDefinition {
type SettingsSchema (line 133) | interface SettingsSchema {
type MemoryImportFormat (line 137) | type MemoryImportFormat = 'tree' | 'flat';
type DnsResolutionOrder (line 138) | type DnsResolutionOrder = 'ipv4first' | 'verbatim';
constant SETTINGS_SCHEMA (line 157) | const SETTINGS_SCHEMA = {
type SettingsSchemaType (line 2490) | type SettingsSchemaType = typeof SETTINGS_SCHEMA;
type SettingsJsonSchemaDefinition (line 2492) | type SettingsJsonSchemaDefinition = Record<string, unknown>;
constant SETTINGS_SCHEMA_DEFINITIONS (line 2494) | const SETTINGS_SCHEMA_DEFINITIONS: Record<
function getSettingsSchema (line 3021) | function getSettingsSchema(): SettingsSchemaType {
type InferSettings (line 3025) | type InferSettings<T extends SettingsSchema> = {
type InferMergedSettings (line 3041) | type InferMergedSettings<T extends SettingsSchema> = {
type Settings (line 3057) | type Settings = InferSettings<SettingsSchemaType>;
type MergedSettings (line 3058) | type MergedSettings = InferMergedSettings<SettingsSchemaType>;
FILE: packages/cli/src/config/settings_repro.test.ts
constant MOCK_WORKSPACE_DIR (line 53) | const MOCK_WORKSPACE_DIR = '/mock/workspace';
FILE: packages/cli/src/config/settings_validation_warning.test.ts
constant MOCK_WORKSPACE_DIR (line 87) | const MOCK_WORKSPACE_DIR = '/mock/workspace';
FILE: packages/cli/src/config/trustedFolders.test.ts
function setup (line 160) | function setup(config: Record<string, TrustLevel>) {
FILE: packages/cli/src/config/trustedFolders.ts
constant TRUSTED_FOLDERS_FILENAME (line 27) | const TRUSTED_FOLDERS_FILENAME = 'trustedFolders.json';
function getUserSettingsDir (line 29) | function getUserSettingsDir(): string {
function getTrustedFoldersPath (line 33) | function getTrustedFoldersPath(): string {
type TrustLevel (line 40) | enum TrustLevel {
function isTrustLevel (line 46) | function isTrustLevel(
type TrustRule (line 56) | interface TrustRule {
type TrustedFoldersError (line 61) | interface TrustedFoldersError {
type TrustedFoldersFile (line 66) | interface TrustedFoldersFile {
type TrustResult (line 71) | interface TrustResult {
function parseTrustedFoldersJson (line 81) | function parseTrustedFoldersJson(content: string): unknown {
function clearRealPathCacheForTesting (line 89) | function clearRealPathCacheForTesting(): void {
function getRealPath (line 93) | function getRealPath(location: string): string {
class LoadedTrustedFolders (line 109) | class LoadedTrustedFolders {
method constructor (line 110) | constructor(
method rules (line 115) | get rules(): TrustRule[] {
method isPathTrusted (line 129) | isPathTrusted(
method setValue (line 172) | async setValue(folderPath: string, trustLevel: TrustLevel): Promise<vo...
function resetTrustedFoldersForTesting (line 244) | function resetTrustedFoldersForTesting(): void {
function loadTrustedFolders (line 249) | function loadTrustedFolders(): LoadedTrustedFolders {
function saveTrustedFolders (line 301) | function saveTrustedFolders(
function isFolderTrustEnabled (line 333) | function isFolderTrustEnabled(settings: Settings): boolean {
function getWorkspaceTrustFromLocalConfig (line 338) | function getWorkspaceTrustFromLocalConfig(
function isWorkspaceTrusted (line 366) | function isWorkspaceTrusted(
FILE: packages/cli/src/core/auth.ts
type InitialAuthResult (line 18) | interface InitialAuthResult {
function performInitialAuth (line 29) | async function performInitialAuth(
FILE: packages/cli/src/core/initializer.ts
type InitializationResult (line 22) | interface InitializationResult {
function initializeApp (line 37) | async function initializeApp(
FILE: packages/cli/src/core/theme.ts
function validateTheme (line 15) | function validateTheme(settings: LoadedSettings): string | null {
FILE: packages/cli/src/deferred.ts
type DeferredCommand (line 16) | interface DeferredCommand {
function setDeferredCommand (line 24) | function setDeferredCommand(command: DeferredCommand) {
function runDeferredCommand (line 28) | async function runDeferredCommand(settings: MergedSettings) {
function defer (line 81) | function defer<T = object, U = object>(
FILE: packages/cli/src/gemini.test.tsx
class MockProcessExitError (line 165) | class MockProcessExitError extends Error {
method constructor (line 166) | constructor(readonly code?: string | number | null | undefined) {
function startTestInteractiveUI (line 1353) | async function startTestInteractiveUI(
FILE: packages/cli/src/gemini.tsx
function validateDnsResolutionOrder (line 94) | function validateDnsResolutionOrder(
function getNodeMemoryArgs (line 111) | function getNodeMemoryArgs(isDebugMode: boolean): string[] {
function setupUnhandledRejectionHandler (line 142) | function setupUnhandledRejectionHandler() {
function startInteractiveUI (line 164) | async function startInteractiveUI(
function main (line 184) | async function main() {
function initializeOutputListenersAndFlush (line 688) | function initializeOutputListenersAndFlush() {
function setupAdminControlsListener (line 724) | function setupAdminControlsListener() {
FILE: packages/cli/src/interactiveCli.tsx
constant SLOW_RENDER_MS (line 50) | const SLOW_RENDER_MS = 200;
function startInteractiveUI (line 52) | async function startInteractiveUI(
function setWindowTitle (line 187) | function setWindowTitle(title: string, settings: LoadedSettings) {
FILE: packages/cli/src/nonInteractiveCli.ts
type RunNonInteractiveParams (line 50) | interface RunNonInteractiveParams {
function runNonInteractive (line 58) | async function runNonInteractive({
FILE: packages/cli/src/services/BuiltinCommandLoader.ts
class BuiltinCommandLoader (line 69) | class BuiltinCommandLoader implements ICommandLoader {
method constructor (line 70) | constructor(private config: Config | null) {}
method loadCommands (line 79) | async loadCommands(_signal: AbortSignal): Promise<SlashCommand[]> {
FILE: packages/cli/src/services/CommandService.test.ts
class MockCommandLoader (line 20) | class MockCommandLoader implements ICommandLoader {
method constructor (line 21) | constructor(private readonly commands: SlashCommand[]) {}
FILE: packages/cli/src/services/CommandService.ts
class CommandService (line 23) | class CommandService {
method constructor (line 29) | private constructor(
method create (line 44) | static async create(
method loadAllCommands (line 65) | private static async loadAllCommands(
method emitConflictEvents (line 87) | private static emitConflictEvents(conflicts: CommandConflict[]): void {
method getCommands (line 112) | getCommands(): readonly SlashCommand[] {
method getConflicts (line 121) | getConflicts(): readonly CommandConflict[] {
FILE: packages/cli/src/services/FileCommandLoader.test.ts
method constructor (line 39) | constructor(
FILE: packages/cli/src/services/FileCommandLoader.ts
type CommandDirectory (line 37) | interface CommandDirectory {
class FileCommandLoader (line 66) | class FileCommandLoader implements ICommandLoader {
method constructor (line 71) | constructor(private readonly config: Config | null) {
method loadCommands (line 88) | async loadCommands(signal: AbortSignal): Promise<SlashCommand[]> {
method getCommandDirectories (line 149) | private getCommandDirectories(): CommandDirectory[] {
method parseAndAdaptFile (line 194) | private async parseAndAdaptFile(
FILE: packages/cli/src/services/McpPromptLoader.ts
class McpPromptLoader (line 25) | class McpPromptLoader implements ICommandLoader {
method constructor (line 26) | constructor(private readonly config: Config | null) {}
method loadCommands (line 35) | loadCommands(_signal: AbortSignal): Promise<SlashCommand[]> {
method parseArgs (line 232) | parseArgs(
FILE: packages/cli/src/services/SkillCommandLoader.ts
class SkillCommandLoader (line 14) | class SkillCommandLoader implements ICommandLoader {
method constructor (line 15) | constructor(private config: Config | null) {}
method loadCommands (line 24) | async loadCommands(_signal: AbortSignal): Promise<SlashCommand[]> {
FILE: packages/cli/src/services/SlashCommandConflictHandler.ts
class SlashCommandConflictHandler (line 21) | class SlashCommandConflictHandler {
method constructor (line 26) | constructor() {
method start (line 30) | start() {
method stop (line 34) | stop() {
method handleConflicts (line 42) | private handleConflicts(payload: SlashCommandConflictsPayload) {
method scheduleFlush (line 61) | private scheduleFlush() {
method flush (line 69) | private flush() {
method emitGroupedFeedback (line 98) | private emitGroupedFeedback(
method emitSingleFeedback (line 122) | private emitSingleFeedback(c: SlashCommandConflict): void {
method capitalize (line 140) | private capitalize(s: string): string {
method getSourceDescription (line 147) | private getSourceDescription(
FILE: packages/cli/src/services/SlashCommandResolver.ts
class CommandRegistry (line 13) | class CommandRegistry {
method finalCommands (line 18) | get finalCommands(): SlashCommand[] {
method conflicts (line 22) | get conflicts(): CommandConflict[] {
class SlashCommandResolver (line 35) | class SlashCommandResolver {
method resolve (line 40) | static resolve(allCommands: SlashCommand[]): {
method handleConflict (line 78) | private static handleConflict(
method prefixExistingCommand (line 118) | private static prefixExistingCommand(
method getRenamedName (line 155) | private static getRenamedName(
method getPrefix (line 174) | private static getPrefix(cmd: SlashCommand): string | undefined {
method trackConflict (line 192) | private static trackConflict(
FILE: packages/cli/src/services/prompt-processors/argumentProcessor.ts
class DefaultArgumentProcessor (line 17) | class DefaultArgumentProcessor implements IPromptProcessor {
method process (line 18) | async process(
FILE: packages/cli/src/services/prompt-processors/atFileProcessor.test.ts
method config (line 34) | get config() {
FILE: packages/cli/src/services/prompt-processors/atFileProcessor.ts
class AtFileProcessor (line 21) | class AtFileProcessor implements IPromptProcessor {
method constructor (line 22) | constructor(private readonly commandName?: string) {}
method process (line 24) | async process(
FILE: packages/cli/src/services/prompt-processors/injectionParser.ts
type Injection (line 10) | interface Injection {
function extractInjections (line 31) | function extractInjections(
FILE: packages/cli/src/services/prompt-processors/shellProcessor.test.ts
function getExpectedEscapedArgForPlatform (line 24) | function getExpectedEscapedArgForPlatform(arg: string): string {
function createPromptPipelineContent (line 39) | function createPromptPipelineContent(text: string): PromptPipelineContent {
constant SUCCESS_RESULT (line 57) | const SUCCESS_RESULT = {
method config (line 92) | get config() {
FILE: packages/cli/src/services/prompt-processors/shellProcessor.ts
class ConfirmationRequiredError (line 24) | class ConfirmationRequiredError extends Error {
method constructor (line 25) | constructor(
type ResolvedShellInjection (line 38) | interface ResolvedShellInjection extends Injection {
class ShellProcessor (line 53) | class ShellProcessor implements IPromptProcessor {
method constructor (line 54) | constructor(private readonly commandName: string) {}
method process (line 56) | async process(
method processString (line 65) | private async processString(
FILE: packages/cli/src/services/prompt-processors/types.ts
type PromptPipelineContent (line 13) | type PromptPipelineContent = PartUnion[];
type IPromptProcessor (line 20) | interface IPromptProcessor {
constant SHORTHAND_ARGS_PLACEHOLDER (line 44) | const SHORTHAND_ARGS_PLACEHOLDER = '{{args}}';
constant SHELL_INJECTION_TRIGGER (line 49) | const SHELL_INJECTION_TRIGGER = '!{';
constant AT_FILE_INJECTION_TRIGGER (line 54) | const AT_FILE_INJECTION_TRIGGER = '@{';
FILE: packages/cli/src/services/types.ts
type ICommandLoader (line 17) | interface ICommandLoader {
type CommandConflict (line 26) | interface CommandConflict {
FILE: packages/cli/src/test-utils/AppRig.tsx
class MockExtensionManager (line 118) | class MockExtensionManager extends ExtensionLoader {
type AppRigOptions (line 144) | interface AppRigOptions {
type PendingConfirmation (line 151) | interface PendingConfirmation {
class AppRig (line 157) | class AppRig {
method constructor (line 173) | constructor(private options: AppRigOptions = {}) {
method initialize (line 182) | async initialize() {
method setupEnvironment (line 226) | private setupEnvironment() {
method createRigSettings (line 244) | private createRigSettings(): LoadedSettings {
method stubRefreshAuth (line 286) | private stubRefreshAuth() {
method setupMessageBusListeners (line 317) | private setupMessageBusListeners() {
method isBusy (line 357) | isBusy(): boolean {
method render (line 396) | async render() {
method setMockCommands (line 425) | setMockCommands(commands: MockShellCommand[]) {
method setToolPolicy (line 429) | setToolPolicy(
method setBreakpoint (line 443) | setBreakpoint(toolName: string | string[] | undefined) {
method removeToolPolicy (line 456) | removeToolPolicy(toolName?: string, source = 'AppRig Override') {
method getTestDir (line 467) | getTestDir(): string {
method getPendingConfirmations (line 471) | getPendingConfirmations() {
method waitUntil (line 475) | private async waitUntil(
method waitForPendingConfirmation (line 499) | async waitForPendingConfirmation(
method waitForNextEvent (line 544) | async waitForNextEvent(
method resolveTool (line 579) | async resolveTool(
method resolveAwaitedTool (line 617) | async resolveAwaitedTool(
method addUserHint (line 627) | async addUserHint(hint: string) {
method drainBreakpointsUntilIdle (line 641) | async drainBreakpointsUntilIdle(
method getConfig (line 660) | getConfig(): Config {
method type (line 665) | async type(text: string) {
method pressEnter (line 675) | async pressEnter() {
method pressKey (line 679) | async pressKey(key: string) {
method lastFrame (line 689) | get lastFrame() {
method getStaticOutput (line 694) | getStaticOutput() {
method waitForOutput (line 699) | async waitForOutput(pattern: string | RegExp, timeout = 30000) {
method waitForIdle (line 714) | async waitForIdle(timeout = 20000) {
method sendMessage (line 718) | async sendMessage(text: string) {
method unmount (line 724) | async unmount() {
FILE: packages/cli/src/test-utils/MockShellExecutionService.ts
type MockShellCommand (line 15) | interface MockShellCommand {
type ShellExecutionServiceExecute (line 21) | type ShellExecutionServiceExecute = (
class MockShellExecutionService (line 30) | class MockShellExecutionService {
method setOriginalImplementation (line 38) | static setOriginalImplementation(
method setPassthrough (line 47) | static setPassthrough(enabled: boolean) {
method setMockCommands (line 51) | static setMockCommands(commands: MockShellCommand[]) {
method reset (line 55) | static reset() {
method execute (line 65) | static async execute(
FILE: packages/cli/src/test-utils/async.ts
function waitFor (line 15) | async function waitFor(
FILE: packages/cli/src/test-utils/createExtension.ts
function createExtension (line 20) | function createExtension({
FILE: packages/cli/src/test-utils/customMatchers.ts
function toMatchSvgSnapshot (line 20) | async function toMatchSvgSnapshot(
function toHaveOnlyValidCharacters (line 81) | function toHaveOnlyValidCharacters(this: Assertion, buffer: TextBuffer) {
type Assertion (line 121) | interface Assertion<T = any> extends CustomMatchers<T> {}
type AsymmetricMatchersContaining (line 123) | interface AsymmetricMatchersContaining extends CustomMatchers {}
type CustomMatchers (line 125) | interface CustomMatchers<T = unknown> {
FILE: packages/cli/src/test-utils/mockCommandContext.ts
type DeepPartial (line 14) | type DeepPartial<T> = T extends object
FILE: packages/cli/src/test-utils/mockConfig.ts
function createMockSettings (line 182) | function createMockSettings(
FILE: packages/cli/src/test-utils/mockDebugLogger.ts
function createMockDebugLogger (line 11) | function createMockDebugLogger(options: { stripAnsi?: boolean } = {}) {
function mockCoreDebugLogger (line 60) | function mockCoreDebugLogger<T extends Record<string, unknown>>(
FILE: packages/cli/src/test-utils/persistentStateFake.ts
class FakePersistentState (line 13) | class FakePersistentState {
method reset (line 25) | reset() {
method mockClear (line 34) | mockClear() {
method setData (line 42) | setData(data: Record<string, unknown>) {
FILE: packages/cli/src/test-utils/render.test.tsx
function TestComponent (line 40) | function TestComponent() {
FILE: packages/cli/src/test-utils/render.tsx
method persistentState (line 68) | get persistentState() {
type TerminalState (line 79) | type TerminalState = {
type RenderMetrics (line 85) | type RenderMetrics = Parameters<NonNullable<RenderOptions['onRender']>>[0];
type InkRenderMetrics (line 87) | interface InkRenderMetrics extends RenderMetrics {
function isInkRenderMetrics (line 92) | function isInkRenderMetrics(
class XtermStdout (line 105) | class XtermStdout extends EventEmitter {
method getColorDepth (line 112) | getColorDepth(): number {
method constructor (line 119) | constructor(state: TerminalState, queue: { promise: Promise<void> }) {
method columns (line 125) | get columns() {
method rows (line 129) | get rows() {
method frames (line 133) | get frames(): string[] {
method waitUntilReady (line 209) | async waitUntilReady() {
class XtermStderr (line 309) | class XtermStderr extends EventEmitter {
method constructor (line 315) | constructor(state: TerminalState, queue: { promise: Promise<void> }) {
class XtermStdin (line 338) | class XtermStdin extends EventEmitter {
method constructor (line 341) | constructor(options: { isTTY?: boolean } = {}) {
method setEncoding (line 352) | setEncoding() {}
method setRawMode (line 353) | setRawMode() {}
method resume (line 354) | resume() {}
method pause (line 355) | pause() {}
method ref (line 356) | ref() {}
method unref (line 357) | unref() {}
type RenderInstance (line 366) | type RenderInstance = {
method get (line 637) | get(target, prop) {
function renderHook (line 768) | function renderHook<Result, Props>(
function renderHookWithProviders (line 831) | async function renderHookWithProviders<Result, Props>(
FILE: packages/cli/src/test-utils/settings.ts
type MockSettingsFile (line 15) | interface MockSettingsFile {
type CreateMockSettingsOptions (line 21) | interface CreateMockSettingsOptions {
FILE: packages/cli/src/ui/AppContainer.test.tsx
function TestContextConsumer (line 130) | function TestContextConsumer() {
function TestChild (line 2582) | function TestChild() {
FILE: packages/cli/src/ui/AppContainer.tsx
function isToolExecuting (line 174) | function isToolExecuting(pendingHistoryItems: HistoryItemWithoutId[]) {
function isToolAwaitingConfirmation (line 185) | function isToolAwaitingConfirmation(
type AppContainerProps (line 197) | interface AppContainerProps {
constant SHELL_WIDTH_FRACTION (line 216) | const SHELL_WIDTH_FRACTION = 0.89;
constant SHELL_HEIGHT_PADDING (line 222) | const SHELL_HEIGHT_PADDING = 10;
FILE: packages/cli/src/ui/IdeIntegrationNudge.tsx
type IdeIntegrationNudgeResult (line 16) | type IdeIntegrationNudgeResult = {
type IdeIntegrationNudgeProps (line 21) | interface IdeIntegrationNudgeProps {
function IdeIntegrationNudge (line 26) | function IdeIntegrationNudge({
FILE: packages/cli/src/ui/auth/ApiAuthDialog.tsx
type ApiAuthDialogProps (line 19) | interface ApiAuthDialogProps {
function ApiAuthDialog (line 26) | function ApiAuthDialog({
FILE: packages/cli/src/ui/auth/AuthDialog.tsx
type AuthDialogProps (line 27) | interface AuthDialogProps {
function AuthDialog (line 36) | function AuthDialog({
FILE: packages/cli/src/ui/auth/AuthInProgress.tsx
type AuthInProgressProps (line 14) | interface AuthInProgressProps {
function AuthInProgress (line 18) | function AuthInProgress({
FILE: packages/cli/src/ui/auth/BannedAccountDialog.test.tsx
constant DEFAULT_SUSPENSION_INFO (line 55) | const DEFAULT_SUSPENSION_INFO: AccountSuspensionInfo = {
FILE: packages/cli/src/ui/auth/BannedAccountDialog.tsx
type BannedAccountDialogProps (line 20) | interface BannedAccountDialogProps {
function BannedAccountDialog (line 26) | function BannedAccountDialog({
FILE: packages/cli/src/ui/auth/LoginWithGoogleRestartDialog.tsx
type LoginWithGoogleRestartDialogProps (line 13) | interface LoginWithGoogleRestartDialogProps {
FILE: packages/cli/src/ui/auth/useAuth.ts
function validateAuthMethodWithSettings (line 21) | function validateAuthMethodWithSettings(
FILE: packages/cli/src/ui/colors.ts
method type (line 11) | get type() {
method Foreground (line 14) | get Foreground() {
method Background (line 17) | get Background() {
method LightBlue (line 20) | get LightBlue() {
method AccentBlue (line 23) | get AccentBlue() {
method AccentPurple (line 26) | get AccentPurple() {
method AccentCyan (line 29) | get AccentCyan() {
method AccentGreen (line 32) | get AccentGreen() {
method AccentYellow (line 35) | get AccentYellow() {
method AccentRed (line 38) | get AccentRed() {
method DiffAdded (line 41) | get DiffAdded() {
method DiffRemoved (line 44) | get DiffRemoved() {
method Comment (line 47) | get Comment() {
method Gray (line 50) | get Gray() {
method DarkGray (line 53) | get DarkGray() {
method InputBackground (line 56) | get InputBackground() {
method MessageBackground (line 59) | get MessageBackground() {
method GradientColors (line 62) | get GradientColors() {
FILE: packages/cli/src/ui/commands/aboutCommand.ts
function getIdeClientName (line 71) | async function getIdeClientName(context: CommandContext) {
FILE: packages/cli/src/ui/commands/agentsCommand.test.ts
method config (line 41) | get config() {
FILE: packages/cli/src/ui/commands/agentsCommand.ts
function enableAction (line 60) | async function enableAction(
function disableAction (line 137) | async function disableAction(
function configAction (line 217) | async function configAction(
function completeAgentsToEnable (line 270) | function completeAgentsToEnable(context: CommandContext, partialArg: str...
function completeAgentsToDisable (line 283) | function completeAgentsToDisable(context: CommandContext, partialArg: st...
function completeAllAgents (line 292) | function completeAllAgents(context: CommandContext, partialArg: string) {
FILE: packages/cli/src/ui/commands/bugCommand.ts
function getIdeClientName (line 136) | async function getIdeClientName(context: CommandContext) {
FILE: packages/cli/src/ui/commands/chatCommand.ts
constant CHECKPOINT_MENU_GROUP (line 32) | const CHECKPOINT_MENU_GROUP = 'checkpoints';
FILE: packages/cli/src/ui/commands/commandsCommand.ts
function listAction (line 23) | async function listAction(
function reloadAction (line 40) | async function reloadAction(
FILE: packages/cli/src/ui/commands/directoryCommand.test.tsx
method config (line 88) | get config() {
FILE: packages/cli/src/ui/commands/directoryCommand.tsx
function finishAddingDirectories (line 30) | async function finishAddingDirectories(
FILE: packages/cli/src/ui/commands/extensionsCommand.ts
function showMessageIfNoExtensions (line 42) | function showMessageIfNoExtensions(
function listAction (line 56) | async function listAction(context: CommandContext) {
function updateAction (line 73) | function updateAction(context: CommandContext, args: string): Promise<vo...
function restartAction (line 155) | async function restartAction(
function exploreAction (line 271) | async function exploreAction(
function getEnableDisableContext (line 328) | function getEnableDisableContext(
function disableAction (line 404) | async function disableAction(context: CommandContext, args: string) {
function enableAction (line 418) | async function enableAction(context: CommandContext, args: string) {
function installAction (line 465) | async function installAction(
function linkAction (line 536) | async function linkAction(context: CommandContext, args: string) {
function uninstallAction (line 601) | async function uninstallAction(context: CommandContext, args: string) {
function configAction (line 661) | async function configAction(context: CommandContext, args: string) {
function completeExtensions (line 736) | function completeExtensions(
function completeExtensionsAndScopes (line 764) | function completeExtensionsAndScopes(
function extensionsCommand (line 861) | function extensionsCommand(
FILE: packages/cli/src/ui/commands/hooksCommand.test.ts
function createMockHook (line 818) | function createMockHook(
FILE: packages/cli/src/ui/commands/hooksCommand.ts
function panelAction (line 27) | function panelAction(
function enableAction (line 55) | async function enableAction(
function disableAction (line 109) | async function disableAction(
function completeEnabledHookNames (line 165) | function completeEnabledHookNames(
function completeDisabledHookNames (line 186) | function completeDisabledHookNames(
function getHookDisplayName (line 207) | function getHookDisplayName(hook: HookRegistryEntry): string {
function enableAllAction (line 214) | async function enableAllAction(
function disableAllAction (line 286) | async function disableAllAction(
FILE: packages/cli/src/ui/commands/ideCommand.ts
function getIdeStatusMessage (line 30) | function getIdeStatusMessage(ideClient: IdeClient): {
function formatFileList (line 59) | function formatFileList(openFiles: File[]): string {
function getIdeStatusMessageWithFiles (line 85) | async function getIdeStatusMessageWithFiles(ideClient: IdeClient): Promi...
function setIdeModeAndSyncConnection (line 121) | async function setIdeModeAndSyncConnection(
FILE: packages/cli/src/ui/commands/mcpCommand.ts
function handleEnableDisable (line 378) | async function handleEnableDisable(
function getEnablementCompletion (line 479) | async function getEnablementCompletion(
FILE: packages/cli/src/ui/commands/modelCommand.test.ts
method config (line 42) | get config() {
method config (line 74) | get config() {
method config (line 107) | get config() {
method config (line 142) | get config() {
FILE: packages/cli/src/ui/commands/planCommand.ts
function copyAction (line 24) | async function copyAction(context: CommandContext) {
FILE: packages/cli/src/ui/commands/policiesCommand.test.ts
method config (line 55) | get config() {
method config (line 93) | get config() {
method config (line 155) | get config() {
FILE: packages/cli/src/ui/commands/policiesCommand.ts
type CategorizedRules (line 11) | interface CategorizedRules {
FILE: packages/cli/src/ui/commands/restoreCommand.test.ts
method config (line 53) | get config() {
FILE: packages/cli/src/ui/commands/restoreCommand.ts
function restoreAction (line 35) | async function restoreAction(
function completion (line 139) | async function completion(
FILE: packages/cli/src/ui/commands/rewindCommand.test.tsx
type RewindViewerProps (line 67) | interface RewindViewerProps {
method config (line 300) | get config() {
method config (line 321) | get config() {
FILE: packages/cli/src/ui/commands/rewindCommand.tsx
function rewindConversation (line 40) | async function rewindConversation(
FILE: packages/cli/src/ui/commands/setupGithubCommand.ts
constant GITHUB_WORKFLOW_PATHS (line 28) | const GITHUB_WORKFLOW_PATHS = [
constant GITHUB_COMMANDS_PATHS (line 37) | const GITHUB_COMMANDS_PATHS = [
constant REPO_DOWNLOAD_URL (line 45) | const REPO_DOWNLOAD_URL =
constant SOURCE_DIR (line 47) | const SOURCE_DIR = 'examples/workflows';
function getOpenUrlsCommands (line 49) | function getOpenUrlsCommands(readmeUrl: string): string[] {
function updateGitignore (line 69) | async function updateGitignore(gitRepoRoot: string): Promise<void> {
function downloadFiles (line 108) | async function downloadFiles({
function createDirectory (line 168) | async function createDirectory(dirPath: string): Promise<void> {
function downloadSetupFiles (line 179) | async function downloadSetupFiles({
FILE: packages/cli/src/ui/commands/skillsCommand.test.ts
method config (line 83) | get config() {
type MockSettings (line 300) | interface MockSettings {
FILE: packages/cli/src/ui/commands/skillsCommand.ts
function listAction (line 31) | async function listAction(
function linkAction (line 78) | async function linkAction(
function disableAction (line 141) | async function disableAction(
function enableAction (line 201) | async function enableAction(
function reloadAction (line 246) | async function reloadAction(
function disableCompletion (line 332) | function disableCompletion(
function enableCompletion (line 346) | function enableCompletion(
FILE: packages/cli/src/ui/commands/statsCommand.test.ts
method config (line 52) | get config() {
method config (line 95) | get config() {
FILE: packages/cli/src/ui/commands/statsCommand.ts
function getUserIdentity (line 24) | function getUserIdentity(context: CommandContext) {
function defaultSessionView (line 39) | async function defaultSessionView(context: CommandContext) {
FILE: packages/cli/src/ui/commands/toolsCommand.ts
function listTools (line 14) | async function listTools(
FILE: packages/cli/src/ui/commands/types.ts
type CommandContext (line 29) | interface CommandContext {
type QuitActionReturn (line 107) | interface QuitActionReturn {
type OpenDialogActionReturn (line 115) | interface OpenDialogActionReturn {
type ConfirmShellCommandsActionReturn (line 136) | interface ConfirmShellCommandsActionReturn {
type ConfirmActionReturn (line 146) | interface ConfirmActionReturn {
type OpenCustomDialogActionReturn (line 156) | interface OpenCustomDialogActionReturn {
type LogoutActionReturn (line 165) | interface LogoutActionReturn {
type SlashCommandActionReturn (line 169) | type SlashCommandActionReturn =
type CommandKind (line 178) | enum CommandKind {
type SlashCommand (line 189) | interface SlashCommand {
FILE: packages/cli/src/ui/components/AboutBox.tsx
type AboutBoxProps (line 14) | interface AboutBoxProps {
FILE: packages/cli/src/ui/components/AgentConfigDialog.test.tsx
type TerminalKeys (line 15) | enum TerminalKeys {
FILE: packages/cli/src/ui/components/AgentConfigDialog.tsx
type AgentConfigField (line 27) | interface AgentConfigField {
constant AGENT_CONFIG_FIELDS (line 39) | const AGENT_CONFIG_FIELDS: AgentConfigField[] = [
type AgentConfigDialogProps (line 106) | interface AgentConfigDialogProps {
function setNestedValue (line 120) | function setNestedValue(obj: unknown, path: string[], value: unknown): u...
function getFieldDefaultFromDefinition (line 156) | function getFieldDefaultFromDefinition(
function AgentConfigDialog (line 190) | function AgentConfigDialog({
FILE: packages/cli/src/ui/components/AnsiOutput.tsx
constant DEFAULT_HEIGHT (line 11) | const DEFAULT_HEIGHT = 24;
type AnsiOutputProps (line 13) | interface AnsiOutputProps {
FILE: packages/cli/src/ui/components/AppHeader.tsx
type AppHeaderProps (line 22) | interface AppHeaderProps {
constant DEFAULT_ICON (line 27) | const DEFAULT_ICON = `▝▜▄
constant MAC_TERMINAL_ICON (line 39) | const MAC_TERMINAL_ICON = `▝▜▄
FILE: packages/cli/src/ui/components/ApprovalModeIndicator.tsx
type ApprovalModeIndicatorProps (line 14) | interface ApprovalModeIndicatorProps {
FILE: packages/cli/src/ui/components/AskUserDialog.tsx
constant DIALOG_PADDING (line 41) | const DIALOG_PADDING = 4;
function isPlainSingleLine (line 46) | function isPlainSingleLine(text: string): boolean {
function autoBoldIfPlain (line 81) | function autoBoldIfPlain(text: string): string {
type AskUserDialogState (line 88) | interface AskUserDialogState {
type AskUserDialogAction (line 94) | type AskUserDialogAction =
function askUserDialogReducerLogic (line 112) | function askUserDialogReducerLogic(
type AskUserDialogProps (line 163) | interface AskUserDialogProps {
type ReviewViewProps (line 196) | interface ReviewViewProps {
type TextQuestionViewProps (line 269) | interface TextQuestionViewProps {
type OptionItem (line 394) | interface OptionItem {
type ChoiceQuestionState (line 402) | interface ChoiceQuestionState {
type ChoiceQuestionAction (line 408) | type ChoiceQuestionAction =
function choiceQuestionReducer (line 418) | function choiceQuestionReducer(
type ChoiceQuestionViewProps (line 489) | interface ChoiceQuestionViewProps {
FILE: packages/cli/src/ui/components/BackgroundShellDisplay.tsx
type BackgroundShellDisplayProps (line 37) | interface BackgroundShellDisplayProps {
constant CONTENT_PADDING_X (line 46) | const CONTENT_PADDING_X = 1;
constant BORDER_WIDTH (line 47) | const BORDER_WIDTH = 2;
constant MAIN_BORDER_HEIGHT (line 48) | const MAIN_BORDER_HEIGHT = 2;
constant HEADER_HEIGHT (line 49) | const HEADER_HEIGHT = 1;
constant FOOTER_HEIGHT (line 50) | const FOOTER_HEIGHT = 1;
constant TOTAL_OVERHEAD_HEIGHT (line 51) | const TOTAL_OVERHEAD_HEIGHT =
constant PROCESS_LIST_HEADER_HEIGHT (line 53) | const PROCESS_LIST_HEADER_HEIGHT = 3;
constant TAB_DISPLAY_HORIZONTAL_PADDING (line 54) | const TAB_DISPLAY_HORIZONTAL_PADDING = 4;
constant LOG_PATH_OVERHEAD (line 55) | const LOG_PATH_OVERHEAD = 7;
FILE: packages/cli/src/ui/components/Banner.tsx
function getFormattedBannerContent (line 12) | function getFormattedBannerContent(
type BannerProps (line 44) | interface BannerProps {
FILE: packages/cli/src/ui/components/Checklist.tsx
type ChecklistProps (line 13) | interface ChecklistProps {
FILE: packages/cli/src/ui/components/ChecklistItem.tsx
type ChecklistStatus (line 12) | type ChecklistStatus =
type ChecklistItemData (line 19) | interface ChecklistItemData {
type ChecklistItemProps (line 63) | interface ChecklistItemProps {
FILE: packages/cli/src/ui/components/CliSpinner.tsx
type SpinnerProps (line 12) | type SpinnerProps = ComponentProps<typeof Spinner>;
FILE: packages/cli/src/ui/components/ColorsDisplay.tsx
type StandardColorRow (line 13) | interface StandardColorRow {
type GradientColorRow (line 19) | interface GradientColorRow {
type BackgroundColorRow (line 25) | interface BackgroundColorRow {
type ColorRow (line 31) | type ColorRow = StandardColorRow | GradientColorRow | BackgroundColorRow;
constant VALUE_COLUMN_WIDTH (line 33) | const VALUE_COLUMN_WIDTH = 10;
constant COLOR_DESCRIPTIONS (line 35) | const COLOR_DESCRIPTIONS: Record<string, string> = {
type ColorsDisplayProps (line 60) | interface ColorsDisplayProps {
function getContrastingTextColor (line 67) | function getContrastingTextColor(hex: string): string {
function renderStandardRow (line 204) | function renderStandardRow({ name, value }: StandardColorRow) {
function renderGradientRow (line 226) | function renderGradientRow({ name, value }: GradientColorRow) {
function renderBackgroundRow (line 252) | function renderBackgroundRow({ name, value }: BackgroundColorRow) {
FILE: packages/cli/src/ui/components/ConfigExtensionDialog.tsx
type ConfigExtensionDialogProps (line 29) | interface ConfigExtensionDialogProps {
type DialogState (line 39) | type DialogState =
function run (line 127) | async function run() {
FILE: packages/cli/src/ui/components/ConsentPrompt.tsx
type ConsentPromptProps (line 13) | type ConsentPromptProps = {
FILE: packages/cli/src/ui/components/ConsoleSummaryDisplay.tsx
type ConsoleSummaryDisplayProps (line 11) | interface ConsoleSummaryDisplayProps {
FILE: packages/cli/src/ui/components/ContextSummaryDisplay.tsx
type ContextSummaryDisplayProps (line 14) | interface ContextSummaryDisplayProps {
FILE: packages/cli/src/ui/components/DebugProfiler.tsx
constant MIN_TIME_FROM_ACTION_TO_BE_IDLE (line 18) | const MIN_TIME_FROM_ACTION_TO_BE_IDLE = 500;
constant ACTION_TIMESTAMP_CAPACITY (line 20) | const ACTION_TIMESTAMP_CAPACITY = 2048;
constant FRAME_TIMESTAMP_CAPACITY (line 21) | const FRAME_TIMESTAMP_CAPACITY = 2048;
method reportAction (line 40) | reportAction() {
method reportFrameRendered (line 51) | reportFrameRendered() {
method checkForIdleFrames (line 74) | checkForIdleFrames() {
method registerFlickerHandler (line 121) | registerFlickerHandler(constrainHeight: boolean) {
FILE: packages/cli/src/ui/components/DetailedMessagesDisplay.tsx
type DetailedMessagesDisplayProps (line 19) | interface DetailedMessagesDisplayProps {
FILE: packages/cli/src/ui/components/DialogManager.tsx
type DialogManagerProps (line 41) | interface DialogManagerProps {
FILE: packages/cli/src/ui/components/EditorSettingsDialog.tsx
type EditorDialogProps (line 29) | interface EditorDialogProps {
function EditorSettingsDialog (line 38) | function EditorSettingsDialog({
FILE: packages/cli/src/ui/components/EmptyWalletDialog.tsx
type EmptyWalletChoice (line 13) | type EmptyWalletChoice = 'get_credits' | 'use_fallback' | 'stop';
type EmptyWalletDialogProps (line 15) | interface EmptyWalletDialogProps {
function EmptyWalletDialog (line 28) | function EmptyWalletDialog({
FILE: packages/cli/src/ui/components/ExitPlanModeDialog.tsx
type ExitPlanModeDialogProps (line 29) | interface ExitPlanModeDialogProps {
type PlanStatus (line 39) | enum PlanStatus {
type PlanContentState (line 45) | interface PlanContentState {
type ApprovalOption (line 52) | enum ApprovalOption {
function usePlanContent (line 64) | function usePlanContent(planPath: string, config: Config): PlanContentSt...
FILE: packages/cli/src/ui/components/FolderTrustDialog.tsx
type FolderTrustChoice (line 33) | enum FolderTrustChoice {
type FolderTrustDialogProps (line 39) | interface FolderTrustDialogProps {
FILE: packages/cli/src/ui/components/Footer.test.tsx
method isDevelopment (line 31) | get isDevelopment() {
FILE: packages/cli/src/ui/components/Footer.tsx
type CwdIndicatorProps (line 33) | interface CwdIndicatorProps {
type SandboxIndicatorProps (line 60) | interface SandboxIndicatorProps {
type FooterRowItem (line 102) | interface FooterRowItem {
constant COLUMN_GAP (line 112) | const COLUMN_GAP = 3;
function isFooterItemId (line 166) | function isFooterItemId(id: string): id is FooterItemId {
type FooterColumn (line 170) | interface FooterColumn {
FILE: packages/cli/src/ui/components/FooterConfigDialog.tsx
type FooterConfigDialogProps (line 23) | interface FooterConfigDialogProps {
type FooterConfigItem (line 27) | interface FooterConfigItem {
type FooterConfigState (line 35) | interface FooterConfigState {
type FooterConfigAction (line 40) | type FooterConfigAction =
function footerConfigReducer (line 45) | function footerConfigReducer(
FILE: packages/cli/src/ui/components/GeminiRespondingSpinner.tsx
type GeminiRespondingSpinnerProps (line 19) | interface GeminiRespondingSpinnerProps {
FILE: packages/cli/src/ui/components/GeminiSpinner.tsx
constant COLOR_CYCLE_DURATION_MS (line 15) | const COLOR_CYCLE_DURATION_MS = 4000;
type GeminiSpinnerProps (line 17) | interface GeminiSpinnerProps {
FILE: packages/cli/src/ui/components/Header.tsx
type HeaderProps (line 15) | interface HeaderProps {
FILE: packages/cli/src/ui/components/Help.tsx
type Help (line 16) | interface Help {
FILE: packages/cli/src/ui/components/HistoryItemDisplay.tsx
type HistoryItemDisplayProps (line 41) | interface HistoryItemDisplayProps {
FILE: packages/cli/src/ui/components/HookStatusDisplay.tsx
type HookStatusDisplayProps (line 12) | interface HookStatusDisplayProps {
FILE: packages/cli/src/ui/components/HooksDialog.tsx
type HookEntry (line 18) | interface HookEntry {
type HooksDialogProps (line 33) | interface HooksDialogProps {
constant DEFAULT_MAX_VISIBLE_HOOKS (line 41) | const DEFAULT_MAX_VISIBLE_HOOKS = 8;
FILE: packages/cli/src/ui/components/IdeTrustChangeDialog.tsx
type IdeTrustChangeDialogProps (line 14) | interface IdeTrustChangeDialogProps {
FILE: packages/cli/src/ui/components/InputPrompt.test.tsx
function clean (line 4846) | function clean(str: string | undefined): string {
FILE: packages/cli/src/ui/components/InputPrompt.tsx
function isTerminalPasteTrusted (line 89) | function isTerminalPasteTrusted(
type InputPromptProps (line 98) | interface InputPromptProps {
function isLargePaste (line 143) | function isLargePaste(text: string): boolean {
constant DOUBLE_TAB_CLEAN_UI_TOGGLE_WINDOW_MS (line 151) | const DOUBLE_TAB_CLEAN_UI_TOGGLE_WINDOW_MS = 350;
function tryTogglePasteExpansion (line 157) | function tryTogglePasteExpansion(buffer: TextBuffer): boolean {
FILE: packages/cli/src/ui/components/LoadingIndicator.tsx
type LoadingIndicatorProps (line 19) | interface LoadingIndicatorProps {
FILE: packages/cli/src/ui/components/LogoutConfirmationDialog.tsx
type LogoutChoice (line 16) | enum LogoutChoice {
type LogoutConfirmationDialogProps (line 21) | interface LogoutConfirmationDialogProps {
FILE: packages/cli/src/ui/components/LoopDetectionConfirmation.tsx
type LoopDetectionConfirmationResult (line 15) | type LoopDetectionConfirmationResult = {
type LoopDetectionConfirmationProps (line 19) | interface LoopDetectionConfirmationProps {
function LoopDetectionConfirmation (line 23) | function LoopDetectionConfirmation({
FILE: packages/cli/src/ui/components/ModelDialog.test.tsx
method constructor (line 42) | constructor(model: string) {
type MockConfig (line 60) | interface MockConfig extends Partial<Config> {
FILE: packages/cli/src/ui/components/ModelDialog.tsx
type ModelDialogProps (line 34) | interface ModelDialogProps {
function ModelDialog (line 38) | function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
FILE: packages/cli/src/ui/components/ModelStatsDisplay.tsx
type StatRowData (line 30) | interface StatRowData {
type RoleMetrics (line 38) | type RoleMetrics = NonNullable<NonNullable<ModelMetrics['roles']>[LlmRol...
type ModelStatsDisplayProps (line 40) | interface ModelStatsDisplayProps {
FILE: packages/cli/src/ui/components/MultiFolderTrustDialog.tsx
type MultiFolderTrustChoice (line 22) | enum MultiFolderTrustChoice {
type MultiFolderTrustDialogProps (line 28) | interface MultiFolderTrustDialogProps {
FILE: packages/cli/src/ui/components/NewAgentsNotification.tsx
type NewAgentsChoice (line 17) | enum NewAgentsChoice {
type NewAgentsNotificationProps (line 22) | interface NewAgentsNotificationProps {
FILE: packages/cli/src/ui/components/Notifications.tsx
constant MAX_STARTUP_WARNING_SHOW_COUNT (line 35) | const MAX_STARTUP_WARNING_SHOW_COUNT = 3;
FILE: packages/cli/src/ui/components/OverageMenuDialog.tsx
type OverageMenuChoice (line 13) | type OverageMenuChoice =
type OverageMenuDialogProps (line 19) | interface OverageMenuDialogProps {
function OverageMenuDialog (line 32) | function OverageMenuDialog({
FILE: packages/cli/src/ui/components/PermissionsModifyTrustDialog.tsx
type PermissionsDialogProps (line 19) | interface PermissionsDialogProps {
type PermissionsModifyTrustDialogProps (line 23) | interface PermissionsModifyTrustDialogProps extends PermissionsDialogPro...
function PermissionsModifyTrustDialog (line 28) | function PermissionsModifyTrustDialog({
FILE: packages/cli/src/ui/components/PolicyUpdateDialog.tsx
type PolicyUpdateChoice (line 24) | enum PolicyUpdateChoice {
type PolicyUpdateDialogProps (line 29) | interface PolicyUpdateDialogProps {
FILE: packages/cli/src/ui/components/ProQuotaDialog.tsx
type ProQuotaDialogProps (line 14) | interface ProQuotaDialogProps {
function ProQuotaDialog (line 27) | function ProQuotaDialog({
FILE: packages/cli/src/ui/components/QueuedMessageDisplay.tsx
constant MAX_DISPLAYED_QUEUED_MESSAGES (line 9) | const MAX_DISPLAYED_QUEUED_MESSAGES = 3;
type QueuedMessageDisplayProps (line 11) | interface QueuedMessageDisplayProps {
FILE: packages/cli/src/ui/components/QuotaDisplay.tsx
type QuotaDisplayProps (line 16) | interface QuotaDisplayProps {
FILE: packages/cli/src/ui/components/QuotaStatsInfo.tsx
type QuotaStatsInfoProps (line 17) | interface QuotaStatsInfoProps {
FILE: packages/cli/src/ui/components/RewindConfirmation.tsx
type RewindOutcome (line 21) | enum RewindOutcome {
constant REWIND_OPTIONS (line 28) | const REWIND_OPTIONS: Array<RadioSelectItem<RewindOutcome>> = [
type RewindConfirmationProps (line 51) | interface RewindConfirmationProps {
FILE: packages/cli/src/ui/components/RewindViewer.tsx
type RewindViewerProps (line 27) | interface RewindViewerProps {
constant MAX_LINES_PER_BOX (line 37) | const MAX_LINES_PER_BOX = 2;
FILE: packages/cli/src/ui/components/SessionBrowser.tsx
type SessionBrowserProps (line 25) | interface SessionBrowserProps {
type SessionBrowserState (line 40) | interface SessionBrowserState {
constant SESSIONS_PER_PAGE (line 107) | const SESSIONS_PER_PAGE = 20;
constant FIXED_SESSION_COLUMNS_WIDTH (line 111) | const FIXED_SESSION_COLUMNS_WIDTH = 30;
function SessionBrowserView (line 682) | function SessionBrowserView({
function SessionBrowser (line 713) | function SessionBrowser({
FILE: packages/cli/src/ui/components/SessionSummaryDisplay.tsx
type SessionSummaryDisplayProps (line 12) | interface SessionSummaryDisplayProps {
FILE: packages/cli/src/ui/components/SettingsDialog.test.tsx
type TerminalKeys (line 39) | enum TerminalKeys {
type StringEnum (line 62) | enum StringEnum {
constant ENUM_SETTING (line 68) | const ENUM_SETTING: SettingDefinition = {
constant MINIMAL_GENERAL_SCHEMA (line 93) | const MINIMAL_GENERAL_SCHEMA = {
constant ENUM_FAKE_SCHEMA (line 109) | const ENUM_FAKE_SCHEMA: SettingsSchemaType = {
constant ARRAY_FAKE_SCHEMA (line 121) | const ARRAY_FAKE_SCHEMA: SettingsSchemaType = {
constant TOOLS_SHELL_FAKE_SCHEMA (line 178) | const TOOLS_SHELL_FAKE_SCHEMA: SettingsSchemaType = {
FILE: packages/cli/src/ui/components/SettingsDialog.tsx
type FzfResult (line 49) | interface FzfResult {
type SettingsDialogProps (line 57) | interface SettingsDialogProps {
constant MAX_ITEMS_TO_SHOW (line 63) | const MAX_ITEMS_TO_SHOW = 8;
constant KEY_UP (line 65) | const KEY_UP = new KeyBinding('up');
constant KEY_CTRL_P (line 66) | const KEY_CTRL_P = new KeyBinding('ctrl+p');
constant KEY_DOWN (line 67) | const KEY_DOWN = new KeyBinding('down');
constant KEY_CTRL_N (line 68) | const KEY_CTRL_N = new KeyBinding('ctrl+n');
function getActiveRestartRequiredSettings (line 73) | function getActiveRestartRequiredSettings(
function SettingsDialog (line 97) | function SettingsDialog({
FILE: packages/cli/src/ui/components/ShellInputPrompt.tsx
type ShellInputPromptProps (line 16) | interface ShellInputPromptProps {
FILE: packages/cli/src/ui/components/ShortcutsHelp.tsx
type ShortcutItem (line 16) | type ShortcutItem = {
FILE: packages/cli/src/ui/components/ShowMoreLines.tsx
type ShowMoreLinesProps (line 13) | interface ShowMoreLinesProps {
FILE: packages/cli/src/ui/components/StatsDisplay.tsx
type StatRowProps (line 43) | interface StatRowProps {
type SubStatRowProps (line 59) | interface SubStatRowProps {
type SectionProps (line 75) | interface SectionProps {
type StatsDisplayProps (line 512) | interface StatsDisplayProps {
FILE: packages/cli/src/ui/components/StatusDisplay.test.tsx
type UIStateOverrides (line 37) | type UIStateOverrides = Partial<Omit<UIState, 'buffer'>> & {
FILE: packages/cli/src/ui/components/StatusDisplay.tsx
type StatusDisplayProps (line 16) | interface StatusDisplayProps {
FILE: packages/cli/src/ui/components/StickyHeader.tsx
type StickyHeaderProps (line 11) | interface StickyHeaderProps {
FILE: packages/cli/src/ui/components/SuggestionsDisplay.tsx
type Suggestion (line 14) | interface Suggestion {
type SuggestionsDisplayProps (line 24) | interface SuggestionsDisplayProps {
constant MAX_SUGGESTIONS_TO_SHOW (line 35) | const MAX_SUGGESTIONS_TO_SHOW = 8;
function SuggestionsDisplay (line 38) | function SuggestionsDisplay({
FILE: packages/cli/src/ui/components/Table.tsx
type Column (line 11) | interface Column<T> {
type TableProps (line 21) | interface TableProps<T> {
function Table (line 26) | function Table<T>({ data, columns }: TableProps<T>) {
FILE: packages/cli/src/ui/components/ThemeDialog.test.tsx
method isDevelopment (line 21) | get isDevelopment() {
FILE: packages/cli/src/ui/components/ThemeDialog.tsx
type ThemeDialogProps (line 29) | interface ThemeDialogProps {
function generateThemeItem (line 49) | function generateThemeItem(
function ThemeDialog (line 80) | function ThemeDialog({
FILE: packages/cli/src/ui/components/Tips.tsx
type TipsProps (line 12) | interface TipsProps {
FILE: packages/cli/src/ui/components/ToastDisplay.tsx
function shouldShowToast (line 13) | function shouldShowToast(uiState: UIState): boolean {
FILE: packages/cli/src/ui/components/ToolConfirmationQueue.tsx
function getConfirmationHeader (line 21) | function getConfirmationHeader(
type ToolConfirmationQueueProps (line 36) | interface ToolConfirmationQueueProps {
FILE: packages/cli/src/ui/components/ToolStatsDisplay.tsx
constant TOOL_NAME_COL_WIDTH (line 21) | const TOOL_NAME_COL_WIDTH = 25;
constant CALLS_COL_WIDTH (line 22) | const CALLS_COL_WIDTH = 8;
constant SUCCESS_RATE_COL_WIDTH (line 23) | const SUCCESS_RATE_COL_WIDTH = 15;
constant AVG_DURATION_COL_WIDTH (line 24) | const AVG_DURATION_COL_WIDTH = 15;
FILE: packages/cli/src/ui/components/UpdateNotification.tsx
type UpdateNotificationProps (line 10) | interface UpdateNotificationProps {
FILE: packages/cli/src/ui/components/UserIdentity.tsx
type UserIdentityProps (line 18) | interface UserIdentityProps {
FILE: packages/cli/src/ui/components/ValidationDialog.tsx
type ValidationDialogProps (line 22) | interface ValidationDialogProps {
type DialogState (line 29) | type DialogState = 'choosing' | 'waiting' | 'complete' | 'error';
function ValidationDialog (line 31) | function ValidationDialog({
FILE: packages/cli/src/ui/components/messages/CompressionMessage.tsx
type CompressionDisplayProps (line 14) | interface CompressionDisplayProps {
function CompressionMessage (line 22) | function CompressionMessage({
FILE: packages/cli/src/ui/components/messages/DiffRenderer.tsx
type DiffLine (line 17) | interface DiffLine {
function parseDiffWithLineNumbers (line 24) | function parseDiffWithLineNumbers(diffContent: string): DiffLine[] {
type DiffRendererProps (line 84) | interface DiffRendererProps {
constant DEFAULT_TAB_WIDTH (line 93) | const DEFAULT_TAB_WIDTH = 4;
FILE: packages/cli/src/ui/components/messages/ErrorMessage.tsx
type ErrorMessageProps (line 11) | interface ErrorMessageProps {
FILE: packages/cli/src/ui/components/messages/GeminiMessage.tsx
type GeminiMessageProps (line 14) | interface GeminiMessageProps {
FILE: packages/cli/src/ui/components/messages/GeminiMessageContent.tsx
type GeminiMessageContentProps (line 12) | interface GeminiMessageContentProps {
FILE: packages/cli/src/ui/components/messages/HintMessage.tsx
type HintMessageProps (line 14) | interface HintMessageProps {
FILE: packages/cli/src/ui/components/messages/InfoMessage.tsx
type InfoMessageProps (line 12) | interface InfoMessageProps {
FILE: packages/cli/src/ui/components/messages/ModelMessage.tsx
type ModelMessageProps (line 12) | interface ModelMessageProps {
FILE: packages/cli/src/ui/components/messages/ShellToolMessage.tsx
type ShellToolMessageProps (line 38) | interface ShellToolMessageProps extends ToolMessageProps {
FILE: packages/cli/src/ui/components/messages/SubagentGroupDisplay.tsx
type SubagentGroupDisplayProps (line 23) | interface SubagentGroupDisplayProps {
FILE: packages/cli/src/ui/components/messages/SubagentProgressDisplay.tsx
type SubagentProgressDisplayProps (line 20) | interface SubagentProgressDisplayProps {
FILE: packages/cli/src/ui/components/messages/ThinkingMessage.tsx
type ThinkingMessageProps (line 14) | interface ThinkingMessageProps {
constant THINKING_LEFT_PADDING (line 20) | const THINKING_LEFT_PADDING = 1;
function normalizeThoughtLines (line 22) | function normalizeThoughtLines(thought: ThoughtSummary): string[] {
FILE: packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx
type ToolConfirmationMessageProps (line 47) | interface ToolConfirmationMessageProps {
constant REDIRECTION_WARNING_NOTE_LABEL (line 57) | const REDIRECTION_WARNING_NOTE_LABEL = 'Note: ';
constant REDIRECTION_WARNING_NOTE_TEXT (line 58) | const REDIRECTION_WARNING_NOTE_TEXT =
constant REDIRECTION_WARNING_TIP_LABEL (line 60) | const REDIRECTION_WARNING_TIP_LABEL = 'Tip: ';
FILE: packages/cli/src/ui/components/messages/ToolGroupMessage.tsx
type ToolGroupMessageProps (line 31) | interface ToolGroupMessageProps {
constant TOOL_MESSAGE_HORIZONTAL_MARGIN (line 43) | const TOOL_MESSAGE_HORIZONTAL_MARGIN = 4;
FILE: packages/cli/src/ui/components/messages/ToolMessage.tsx
type ToolMessageProps (line 30) | interface ToolMessageProps extends IndividualToolCallDisplay {
FILE: packages/cli/src/ui/components/messages/ToolResultDisplay.tsx
type ToolResultDisplayProps (line 29) | interface ToolResultDisplayProps {
type FileDiffResult (line 39) | interface FileDiffResult {
FILE: packages/cli/src/ui/components/messages/ToolShared.tsx
constant STATUS_INDICATOR_WIDTH (line 29) | const STATUS_INDICATOR_WIDTH = 3;
function isShellTool (line 34) | function isShellTool(name: string): boolean {
function isThisShellFocusable (line 45) | function isThisShellFocusable(
function isThisShellFocused (line 60) | function isThisShellFocused(
function useFocusHint (line 78) | function useFocusHint(
type TextEmphasis (line 135) | type TextEmphasis = 'high' | 'medium' | 'low';
type ToolStatusIndicatorProps (line 137) | type ToolStatusIndicatorProps = {
type ToolInfoProps (line 190) | type ToolInfoProps = {
type McpProgressIndicatorProps (line 249) | interface McpProgressIndicatorProps {
FILE: packages/cli/src/ui/components/messages/UserMessage.tsx
type UserMessageProps (line 20) | interface UserMessageProps {
FILE: packages/cli/src/ui/components/messages/UserShellMessage.tsx
type UserShellMessageProps (line 13) | interface UserShellMessageProps {
FILE: packages/cli/src/ui/components/messages/WarningMessage.tsx
type WarningMessageProps (line 12) | interface WarningMessageProps {
FILE: packages/cli/src/ui/components/shared/BaseSelectionList.tsx
type RenderItemContext (line 16) | interface RenderItemContext {
type BaseSelectionListProps (line 22) | interface BaseSelectionListProps<
function BaseSelectionList (line 55) | function BaseSelectionList<
FILE: packages/cli/src/ui/components/shared/BaseSettingsDialog.test.tsx
type TerminalKeys (line 19) | enum TerminalKeys {
FILE: packages/cli/src/ui/components/shared/BaseSettingsDialog.tsx
type SettingsDialogItem (line 31) | interface SettingsDialogItem {
type BaseSettingsDialogProps (line 55) | interface BaseSettingsDialogProps {
function BaseSettingsDialog (line 123) | function BaseSettingsDialog({
FILE: packages/cli/src/ui/components/shared/DescriptiveRadioButtonSelect.tsx
type DescriptiveRadioSelectItem (line 13) | interface DescriptiveRadioSelectItem<T> extends SelectionListItem<T> {
type DescriptiveRadioButtonSelectProps (line 18) | interface DescriptiveRadioButtonSelectProps<T> {
function DescriptiveRadioButtonSelect (line 42) | function DescriptiveRadioButtonSelect<T>({
FILE: packages/cli/src/ui/components/shared/DialogFooter.tsx
type DialogFooterProps (line 11) | interface DialogFooterProps {
FILE: packages/cli/src/ui/components/shared/EnumSelector.test.tsx
constant LANGUAGE_OPTIONS (line 13) | const LANGUAGE_OPTIONS: readonly SettingEnumOption[] = [
constant NUMERIC_OPTIONS (line 20) | const NUMERIC_OPTIONS: readonly SettingEnumOption[] = [
FILE: packages/cli/src/ui/components/shared/EnumSelector.tsx
type EnumSelectorProps (line 13) | interface EnumSelectorProps {
function EnumSelector (line 23) | function EnumSelector({
FILE: packages/cli/src/ui/components/shared/ExpandableText.tsx
constant MAX_WIDTH (line 11) | const MAX_WIDTH = 150;
type ExpandableTextProps (line 13) | interface ExpandableTextProps {
FILE: packages/cli/src/ui/components/shared/HalfLinePaddedBox.tsx
type HalfLinePaddedBoxProps (line 19) | interface HalfLinePaddedBoxProps {
FILE: packages/cli/src/ui/components/shared/HorizontalLine.tsx
type HorizontalLineProps (line 11) | interface HorizontalLineProps {
FILE: packages/cli/src/ui/components/shared/MaxSizedBox.tsx
constant MINIMUM_MAX_HEIGHT (line 21) | const MINIMUM_MAX_HEIGHT = 2;
type MaxSizedBoxProps (line 23) | interface MaxSizedBoxProps {
FILE: packages/cli/src/ui/components/shared/RadioButtonSelect.test.tsx
type RadioRenderItemFn (line 38) | type RadioRenderItemFn = (
FILE: packages/cli/src/ui/components/shared/RadioButtonSelect.tsx
type RadioSelectItem (line 20) | interface RadioSelectItem<T> extends SelectionListItem<T> {
type RadioButtonSelectProps (line 31) | interface RadioButtonSelectProps<T> {
function RadioButtonSelect (line 63) | function RadioButtonSelect<T>({
FILE: packages/cli/src/ui/components/shared/ScopeSelector.tsx
type ScopeSelectorProps (line 13) | interface ScopeSelectorProps {
function ScopeSelector (line 24) | function ScopeSelector({
FILE: packages/cli/src/ui/components/shared/Scrollable.tsx
type ScrollableProps (line 26) | interface ScrollableProps {
FILE: packages/cli/src/ui/components/shared/ScrollableList.test.tsx
type Item (line 31) | interface Item {
FILE: packages/cli/src/ui/components/shared/ScrollableList.tsx
constant ANIMATION_FRAME_DURATION_MS (line 28) | const ANIMATION_FRAME_DURATION_MS = 33;
type VirtualizedListProps (line 30) | type VirtualizedListProps<T> = {
type ScrollableListProps (line 39) | interface ScrollableListProps<T> extends VirtualizedListProps<T> {
type ScrollableListRef (line 44) | type ScrollableListRef<T> = VirtualizedListRef<T>;
function ScrollableList (line 46) | function ScrollableList<T>(
FILE: packages/cli/src/ui/components/shared/SearchableList.tsx
type GenericListItem (line 20) | interface GenericListItem {
type SearchListState (line 30) | interface SearchListState<T extends GenericListItem> {
type SearchableListProps (line 41) | interface SearchableListProps<T extends GenericListItem> {
function SearchableList (line 77) | function SearchableList<T extends GenericListItem>({
FILE: packages/cli/src/ui/components/shared/SlicingMaxSizedBox.tsx
constant MAXIMUM_RESULT_DISPLAY_CHARACTERS (line 12) | const MAXIMUM_RESULT_DISPLAY_CHARACTERS = 20000;
type SlicingMaxSizedBoxProps (line 14) | interface SlicingMaxSizedBoxProps<T>
function SlicingMaxSizedBox (line 27) | function SlicingMaxSizedBox<T>({
FILE: packages/cli/src/ui/components/shared/TabHeader.test.tsx
constant MOCK_TABS (line 11) | const MOCK_TABS: Tab[] = [
FILE: packages/cli/src/ui/components/shared/TabHeader.tsx
type Tab (line 14) | interface Tab {
type TabHeaderProps (line 28) | interface TabHeaderProps {
function TabHeader (line 61) | function TabHeader({
FILE: packages/cli/src/ui/components/shared/TextInput.tsx
type TextInputProps (line 18) | interface TextInputProps {
function TextInput (line 26) | function TextInput({
FILE: packages/cli/src/ui/components/shared/VirtualizedList.tsx
constant SCROLL_TO_ITEM_END (line 23) | const SCROLL_TO_ITEM_END = Number.MAX_SAFE_INTEGER;
type VirtualizedListProps (line 25) | type VirtualizedListProps<T> = {
type VirtualizedListRef (line 35) | type VirtualizedListRef<T> = {
function findLastIndex (line 57) | function findLastIndex<T>(
function VirtualizedList (line 69) | function VirtualizedList<T>(
FILE: packages/cli/src/ui/components/shared/text-buffer.test.ts
function createStateWithTransformations (line 75) | function createStateWithTransformations(
FILE: packages/cli/src/ui/components/shared/text-buffer.ts
constant LARGE_PASTE_LINE_THRESHOLD (line 35) | const LARGE_PASTE_LINE_THRESHOLD = 5;
constant LARGE_PASTE_CHAR_THRESHOLD (line 36) | const LARGE_PASTE_CHAR_THRESHOLD = 500;
constant PASTED_TEXT_PLACEHOLDER_REGEX (line 39) | const PASTED_TEXT_PLACEHOLDER_REGEX =
function expandPastePlaceholders (line 43) | function expandPastePlaceholders(
type Direction (line 53) | type Direction =
function findPrevWordBoundary (line 370) | function findPrevWordBoundary(line: string, cursorCol: number): number {
function findNextWordBoundary (line 391) | function findNextWordBoundary(line: string, cursorCol: number): number {
type Viewport (line 751) | interface Viewport {
function clamp (line 756) | function clamp(v: number, min: number, max: number): number {
type UseTextBufferProps (line 762) | interface UseTextBufferProps {
type UndoHistoryEntry (line 776) | interface UndoHistoryEntry {
function calculateInitialCursorPosition (line 784) | function calculateInitialCursorPosition(
function offsetToLogicalPos (line 811) | function offsetToLogicalPos(
function logicalPosToOffset (line 864) | function logicalPosToOffset(
type Transformation (line 892) | interface Transformation {
function getTransformedImagePath (line 903) | function getTransformedImagePath(filePath: string): string {
function calculateTransformationsForLine (line 938) | function calculateTransformationsForLine(
function calculateTransformations (line 990) | function calculateTransformations(lines: string[]): Transformation[][] {
function getTransformUnderCursor (line 994) | function getTransformUnderCursor(
type ExpandedPasteInfo (line 1014) | interface ExpandedPasteInfo {
function getExpandedPasteAtLine (line 1026) | function getExpandedPasteAtLine(
function shiftExpandedRegions (line 1044) | function shiftExpandedRegions(
function detachExpandedPaste (line 1097) | function detachExpandedPaste(state: TextBufferState): TextBufferState {
type AtomicPlaceholder (line 1116) | interface AtomicPlaceholder {
function findAtomicPlaceholderForBackspace (line 1127) | function findAtomicPlaceholderForBackspace(
function findAtomicPlaceholderForDelete (line 1149) | function findAtomicPlaceholderForDelete(
function calculateTransformedLine (line 1168) | function calculateTransformedLine(
type VisualLayout (line 1244) | interface VisualLayout {
type LineLayoutResult (line 1258) | interface LineLayoutResult {
function getLineLayoutCacheKey (line 1270) | function getLineLayoutCacheKey(
function calculateLayout (line 1286) | function calculateLayout(
function calculateVisualCursorFromLayout (line 1483) | function calculateVisualCursorFromLayout(
type TextBufferState (line 1556) | interface TextBufferState {
function generatePastedTextId (line 1593) | function generatePastedTextId(
function collectPlaceholderIdsFromLines (line 1612) | function collectPlaceholderIdsFromLines(lines: string[]): Set<string> {
function pruneOrphanedPastedContent (line 1627) | function pruneOrphanedPastedContent(
type TextBufferAction (line 1653) | type TextBufferAction =
type TextBufferOptions (line 1780) | interface TextBufferOptions {
function textBufferReducerLogic (line 1785) | function textBufferReducerLogic(
function textBufferReducer (line 2777) | function textBufferReducer(
function useTextBuffer (line 2830) | function useTextBuffer({
type TextBuffer (line 3897) | interface TextBuffer {
FILE: packages/cli/src/ui/components/shared/vim-buffer-actions.test.ts
type FindActionCase (line 1958) | type FindActionCase = {
FILE: packages/cli/src/ui/components/shared/vim-buffer-actions.ts
type VimAction (line 25) | type VimAction = Extract<
function findCharInLine (line 95) | function findCharInLine(
function clampNormalCursor (line 126) | function clampNormalCursor(state: TextBufferState): TextBufferState {
function extractRange (line 135) | function extractRange(
function handleVimAction (line 164) | function handleVimAction(
FILE: packages/cli/src/ui/components/triage/TriageDuplicates.tsx
type Issue (line 20) | interface Issue {
type Candidate (line 33) | interface Candidate extends Issue {
type RankedCandidateInfo (line 39) | interface RankedCandidateInfo {
type GeminiRecommendation (line 45) | interface GeminiRecommendation {
type AnalysisResult (line 53) | interface AnalysisResult {
type ProcessedIssue (line 59) | interface ProcessedIssue {
type TriageState (line 66) | interface TriageState {
type FocusSection (line 82) | type FocusSection = 'target' | 'candidates' | 'candidate_detail';
constant VISIBLE_LINES_COLLAPSED (line 84) | const VISIBLE_LINES_COLLAPSED = 6;
constant VISIBLE_LINES_EXPANDED (line 85) | const VISIBLE_LINES_EXPANDED = 20;
constant VISIBLE_LINES_DETAIL (line 86) | const VISIBLE_LINES_DETAIL = 25;
constant VISIBLE_CANDIDATES (line 87) | const VISIBLE_CANDIDATES = 5;
constant MAX_CONCURRENT_ANALYSIS (line 88) | const MAX_CONCURRENT_ANALYSIS = 10;
FILE: packages/cli/src/ui/components/triage/TriageIssues.tsx
type Issue (line 22) | interface Issue {
type AnalysisResult (line 33) | interface AnalysisResult {
type ProcessedIssue (line 39) | interface ProcessedIssue {
type TriageState (line 45) | interface TriageState {
constant VISIBLE_LINES_COLLAPSED (line 54) | const VISIBLE_LINES_COLLAPSED = 8;
constant VISIBLE_LINES_EXPANDED (line 55) | const VISIBLE_LINES_EXPANDED = 20;
constant MAX_CONCURRENT_ANALYSIS (line 56) | const MAX_CONCURRENT_ANALYSIS = 10;
FILE: packages/cli/src/ui/components/views/AgentsStatus.tsx
type AgentsStatusProps (line 13) | interface AgentsStatusProps {
FILE: packages/cli/src/ui/components/views/ChatList.tsx
type ChatListProps (line 12) | interface ChatListProps {
FILE: packages/cli/src/ui/components/views/ExtensionDetails.tsx
type ExtensionDetailsProps (line 16) | interface ExtensionDetailsProps {
function ExtensionDetails (line 25) | function ExtensionDetails({
FILE: packages/cli/src/ui/components/views/ExtensionRegistryView.tsx
type ExtensionRegistryViewProps (line 27) | interface ExtensionRegistryViewProps {
type ExtensionItem (line 36) | interface ExtensionItem extends GenericListItem {
function ExtensionRegistryView (line 40) | function ExtensionRegistryView({
FILE: packages/cli/src/ui/components/views/ExtensionsList.tsx
type ExtensionsList (line 14) | interface ExtensionsList {
FILE: packages/cli/src/ui/components/views/McpStatus.tsx
type McpStatusProps (line 19) | interface McpStatusProps {
FILE: packages/cli/src/ui/components/views/SkillsList.tsx
type SkillsListProps (line 12) | interface SkillsListProps {
FILE: packages/cli/src/ui/components/views/ToolsList.tsx
type ToolsListProps (line 13) | interface ToolsListProps {
FILE: packages/cli/src/ui/constants.ts
constant SHELL_COMMAND_NAME (line 7) | const SHELL_COMMAND_NAME = 'Shell Command';
constant SHELL_NAME (line 9) | const SHELL_NAME = 'Shell';
constant MAX_GEMINI_MESSAGE_LINES (line 15) | const MAX_GEMINI_MESSAGE_LINES = 65536;
constant SHELL_FOCUS_HINT_DELAY_MS (line 17) | const SHELL_FOCUS_HINT_DELAY_MS = 5000;
constant TOOL_STATUS (line 20) | const TOOL_STATUS = {
constant MAX_MCP_RESOURCES_TO_SHOW (line 30) | const MAX_MCP_RESOURCES_TO_SHOW = 10;
constant WARNING_PROMPT_DURATION_MS (line 32) | const WARNING_PROMPT_DURATION_MS = 3000;
constant QUEUE_ERROR_DISPLAY_DURATION_MS (line 33) | const QUEUE_ERROR_DISPLAY_DURATION_MS = 3000;
constant SHELL_ACTION_REQUIRED_TITLE_DELAY_MS (line 34) | const SHELL_ACTION_REQUIRED_TITLE_DELAY_MS = 30000;
constant SHELL_SILENT_WORKING_TITLE_DELAY_MS (line 35) | const SHELL_SILENT_WORKING_TITLE_DELAY_MS = 120000;
constant EXPAND_HINT_DURATION_MS (line 36) | const EXPAND_HINT_DURATION_MS = 5000;
constant DEFAULT_BACKGROUND_OPACITY (line 38) | const DEFAULT_BACKGROUND_OPACITY = 0.16;
constant DEFAULT_INPUT_BACKGROUND_OPACITY (line 39) | const DEFAULT_INPUT_BACKGROUND_OPACITY = 0.24;
constant DEFAULT_SELECTION_OPACITY (line 40) | const DEFAULT_SELECTION_OPACITY = 0.2;
constant DEFAULT_BORDER_OPACITY (line 41) | const DEFAULT_BORDER_OPACITY = 0.4;
constant KEYBOARD_SHORTCUTS_URL (line 43) | const KEYBOARD_SHORTCUTS_URL =
constant LRU_BUFFER_PERF_CACHE_LIMIT (line 45) | const LRU_BUFFER_PERF_CACHE_LIMIT = 20000;
constant ACTIVE_SHELL_MAX_LINES (line 48) | const ACTIVE_SHELL_MAX_LINES = 15;
constant COMPLETED_SHELL_MAX_LINES (line 51) | const COMPLETED_SHELL_MAX_LINES = 15;
constant SUBAGENT_MAX_LINES (line 54) | const SUBAGENT_MAX_LINES = 15;
constant MIN_TERMINAL_WIDTH_FOR_FULL_LABEL (line 57) | const MIN_TERMINAL_WIDTH_FOR_FULL_LABEL = 100;
constant DEFAULT_COMPRESSION_THRESHOLD (line 60) | const DEFAULT_COMPRESSION_THRESHOLD = 0.5;
FILE: packages/cli/src/ui/constants/tips.ts
constant INFORMATIVE_TIPS (line 7) | const INFORMATIVE_TIPS = [
FILE: packages/cli/src/ui/constants/wittyPhrases.ts
constant WITTY_LOADING_PHRASES (line 7) | const WITTY_LOADING_PHRASES = [
FILE: packages/cli/src/ui/contexts/AppContext.tsx
type AppState (line 10) | interface AppState {
FILE: packages/cli/src/ui/contexts/AskUserActionsContext.tsx
type AskUserState (line 11) | interface AskUserState {
type AskUserActionsContextValue (line 16) | interface AskUserActionsContextValue {
type AskUserActionsProviderProps (line 40) | interface AskUserActionsProviderProps {
FILE: packages/cli/src/ui/contexts/KeypressContext.test.tsx
constant PASTE_START (line 32) | const PASTE_START = '\x1B[200~';
constant PASTE_END (line 33) | const PASTE_END = '\x1B[201~';
constant INCOMPLETE_KITTY_SEQUENCE (line 36) | const INCOMPLETE_KITTY_SEQUENCE = '\x1b[97;135';
class MockStdin (line 38) | class MockStdin extends EventEmitter {
method write (line 46) | write(text: string) {
FILE: packages/cli/src/ui/contexts/KeypressContext.tsx
constant BACKSLASH_ENTER_TIMEOUT (line 27) | const BACKSLASH_ENTER_TIMEOUT = 5;
constant ESC_TIMEOUT (line 28) | const ESC_TIMEOUT = 50;
constant PASTE_TIMEOUT (line 29) | const PASTE_TIMEOUT = 30_000;
constant FAST_RETURN_TIMEOUT (line 30) | const FAST_RETURN_TIMEOUT = 30;
type KeypressPriority (line 32) | enum KeypressPriority {
constant KEY_INFO_MAP (line 40) | const KEY_INFO_MAP: Record<
constant KITTY_CODE_MAP (line 130) | const KITTY_CODE_MAP: Record<number, { name: string; sequence?: string }...
constant NUMPAD_MAP (line 170) | const NUMPAD_MAP: Record<string, string> = {
function charLengthAt (line 189) | function charLengthAt(str: string, i: number): number {
constant MAC_ALT_KEY_CHARACTER_MAP (line 201) | const MAC_ALT_KEY_CHARACTER_MAP: Record<string, string> = {
function nonKeyboardEventFilter (line 210) | function nonKeyboardEventFilter(
function bufferFastReturn (line 229) | function bufferFastReturn(keypressHandler: KeypressHandler): KeypressHan...
function bufferBackslashEnter (line 256) | function bufferBackslashEnter(
function bufferPaste (line 304) | function bufferPaste(keypressHandler: KeypressHandler): KeypressHandler {
function createDataListener (line 358) | function createDataListener(keypressHandler: KeypressHandler) {
type Key (line 734) | interface Key {
type KeypressHandler (line 744) | type KeypressHandler = (key: Key) => boolean | void;
type KeypressContextValue (line 746) | interface KeypressContextValue {
function useKeypressContext (line 758) | function useKeypressContext() {
function KeypressProvider (line 768) | function KeypressProvider({
FILE: packages/cli/src/ui/contexts/MouseContext.test.tsx
class MockStdin (line 36) | class MockStdin extends EventEmitter {
method write (line 44) | write(text: string) {
FILE: packages/cli/src/ui/contexts/MouseContext.tsx
constant MAX_MOUSE_BUFFER_SIZE (line 33) | const MAX_MOUSE_BUFFER_SIZE = 4096;
type MouseContextValue (line 35) | interface MouseContextValue {
function useMouseContext (line 42) | function useMouseContext() {
function useMouse (line 50) | function useMouse(handler: MouseHandler, { isActive = true } = {}) {
function MouseProvider (line 63) | function MouseProvider({
FILE: packages/cli/src/ui/contexts/OverflowContext.tsx
type OverflowState (line 18) | interface OverflowState {
type OverflowActions (line 22) | interface OverflowActions {
FILE: packages/cli/src/ui/contexts/ScrollProvider.tsx
type ScrollState (line 20) | interface ScrollState {
type ScrollableEntry (line 26) | interface ScrollableEntry {
type ScrollContextType (line 36) | interface ScrollContextType {
FILE: packages/cli/src/ui/contexts/SessionContext.test.tsx
class ErrorBoundary (line 17) | class ErrorBoundary extends Component<
method constructor (line 21) | constructor(props: { children: ReactNode; onError: (error: Error) => v...
method getDerivedStateFromError (line 26) | static getDerivedStateFromError(_error: Error) {
method componentDidCatch (line 30) | override componentDidCatch(error: Error) {
method render (line 34) | override render() {
FILE: packages/cli/src/ui/contexts/SessionContext.tsx
type ToolCallDecision (line 24) | enum ToolCallDecision {
function areModelMetricsEqual (line 31) | function areModelMetricsEqual(a: ModelMetrics, b: ModelMetrics): boolean {
function areToolCallStatsEqual (line 53) | function areToolCallStatsEqual(a: ToolCallStats, b: ToolCallStats): bool...
function areMetricsEqual (line 77) | function areMetricsEqual(a: SessionMetrics, b: SessionMetrics): boolean {
type SessionStatsState (line 144) | interface SessionStatsState {
type ComputedSessionStats (line 152) | interface ComputedSessionStats {
type SessionStatsContextValue (line 171) | interface SessionStatsContextValue {
FILE: packages/cli/src/ui/contexts/SettingsContext.test.tsx
class ErrorBoundary (line 38) | class ErrorBoundary extends Component<
method constructor (line 42) | constructor(props: { children: ReactNode; onError: (error: Error) => v...
method getDerivedStateFromError (line 47) | static getDerivedStateFromError(_error: Error) {
method componentDidCatch (line 51) | override componentDidCatch(error: Error) {
method render (line 55) | override render() {
FILE: packages/cli/src/ui/contexts/SettingsContext.tsx
type SettingsState (line 29) | interface SettingsState extends LoadedSettingsSnapshot {
type SettingsStoreValue (line 33) | interface SettingsStoreValue {
FILE: packages/cli/src/ui/contexts/TerminalContext.tsx
type TerminalEventHandler (line 18) | type TerminalEventHandler = (event: string) => void;
type TerminalContextValue (line 20) | interface TerminalContextValue {
function useTerminalContext (line 30) | function useTerminalContext() {
function TerminalProvider (line 40) | function TerminalProvider({ children }: { children: React.ReactNode }) {
FILE: packages/cli/src/ui/contexts/ToolActionsContext.tsx
type LegacyConfirmationDetails (line 26) | type LegacyConfirmationDetails = SerializableConfirmationDetails & {
function hasLegacyCallback (line 33) | function hasLegacyCallback(
type ToolActionsContextValue (line 43) | interface ToolActionsContextValue {
type ToolActionsProviderProps (line 63) | interface ToolActionsProviderProps {
FILE: packages/cli/src/ui/contexts/UIActionsContext.tsx
type UIActions (line 23) | interface UIActions {
FILE: packages/cli/src/ui/contexts/UIStateContext.tsx
type ProQuotaDialogRequest (line 39) | interface ProQuotaDialogRequest {
type ValidationDialogRequest (line 49) | interface ValidationDialogRequest {
type OverageMenuIntent (line 57) | type OverageMenuIntent =
type OverageMenuDialogRequest (line 63) | interface OverageMenuDialogRequest {
type EmptyWalletIntent (line 73) | type EmptyWalletIntent = 'get_credits' | 'use_fallback' | 'stop';
type EmptyWalletDialogRequest (line 75) | interface EmptyWalletDialogRequest {
type QuotaState (line 89) | interface QuotaState {
type AccountSuspensionInfo (line 99) | interface AccountSuspensionInfo {
type UIState (line 105) | interface UIState {
FILE: packages/cli/src/ui/contexts/VimModeContext.tsx
type VimMode (line 11) | type VimMode = 'NORMAL' | 'INSERT';
type VimModeContextType (line 13) | interface VimModeContextType {
FILE: packages/cli/src/ui/editors/editorSettingsManager.ts
type EditorDisplay (line 14) | interface EditorDisplay {
class EditorSettingsManager (line 20) | class EditorSettingsManager {
method constructor (line 23) | constructor() {
method getAvailableEditorDisplays (line 52) | getAvailableEditorDisplays(): EditorDisplay[] {
FILE: packages/cli/src/ui/hooks/atCommandProcessor.test.ts
function createTestFile (line 49) | async function createTestFile(fullPath: string, fileContents: string) {
function getRelativePath (line 55) | function getRelativePath(absolutePath: string): string {
method isPathAllowed (line 99) | isPathAllowed(this: Config, absolutePath: string): boolean {
method validatePathAccess (line 116) | validatePathAccess(this: Config, absolutePath: string): string | null {
FILE: packages/cli/src/ui/hooks/atCommandProcessor.ts
constant REF_CONTENT_HEADER (line 30) | const REF_CONTENT_HEADER = `\n${REFERENCE_CONTENT_START}`;
constant REF_CONTENT_FOOTER (line 31) | const REF_CONTENT_FOOTER = `\n${REFERENCE_CONTENT_END}`;
function escapeAtSymbols (line 36) | function escapeAtSymbols(text: string): string {
function unescapeLiteralAt (line 43) | function unescapeLiteralAt(text: string): string {
constant AT_COMMAND_PATH_REGEX_SOURCE (line 62) | const AT_COMMAND_PATH_REGEX_SOURCE =
type HandleAtCommandParams (line 65) | interface HandleAtCommandParams {
type HandleAtCommandResult (line 75) | interface HandleAtCommandResult {
type AtCommandPart (line 80) | interface AtCommandPart {
function parseAllAtCommands (line 89) | function parseAllAtCommands(
function categorizeAtCommands (line 141) | function categorizeAtCommands(
function checkPermissions (line 179) | async function checkPermissions(
type ResolvedFile (line 204) | interface ResolvedFile {
type IgnoredFile (line 211) | interface IgnoredFile {
function resolveFilePaths (line 219) | async function resolveFilePaths(
function constructInitialQuery (line 376) | function constructInitialQuery(
function readMcpResources (line 407) | async function readMcpResources(
function readLocalFiles (line 502) | async function readLocalFiles(
function reportIgnoredFiles (line 617) | function reportIgnoredFiles(
function handleAtCommand (line 662) | async function handleAtCommand({
function convertResourceContentsToParts (line 756) | function convertResourceContentsToParts(response: {
FILE: packages/cli/src/ui/hooks/atCommandProcessor_agents.test.ts
method isPathAllowed (line 87) | isPathAllowed(this: Config, absolutePath: string): boolean {
method validatePathAccess (line 104) | validatePathAccess(this: Config, absolutePath: string): string | null {
FILE: packages/cli/src/ui/hooks/creditsFlowHandler.test.ts
function makeArgs (line 79) | function makeArgs(
FILE: packages/cli/src/ui/hooks/creditsFlowHandler.ts
type CreditsFlowArgs (line 37) | interface CreditsFlowArgs {
function handleCreditsFlow (line 65) | async function handleCreditsFlow(
function handleOverageMenu (line 101) | async function handleOverageMenu(
function handleEmptyWalletMenu (line 191) | async function handleEmptyWalletMenu(
function logOverageOptionSelected (line 273) | function logOverageOptionSelected(
function logCreditPurchaseClick (line 289) | function logCreditPurchaseClick(
function openG1Url (line 298) | async function openG1Url(
FILE: packages/cli/src/ui/hooks/shell-completions/gitProvider.ts
constant GIT_SUBCOMMANDS (line 14) | const GIT_SUBCOMMANDS = [
method getCompletions (line 30) | async getCompletions(
FILE: packages/cli/src/ui/hooks/shell-completions/index.ts
function getArgumentCompletions (line 13) | async function getArgumentCompletions(
FILE: packages/cli/src/ui/hooks/shell-completions/npmProvider.ts
constant NPM_SUBCOMMANDS (line 12) | const NPM_SUBCOMMANDS = [
method getCompletions (line 25) | async getCompletions(
FILE: packages/cli/src/ui/hooks/shell-completions/types.ts
type CompletionResult (line 9) | interface CompletionResult {
type ShellCompletionProvider (line 16) | interface ShellCompletionProvider {
FILE: packages/cli/src/ui/hooks/shellCommandProcessor.test.tsx
function TestComponent (line 145) | function TestComponent({
method current (line 169) | get current() {
FILE: packages/cli/src/ui/hooks/shellCommandProcessor.ts
constant OUTPUT_UPDATE_INTERVAL_MS (line 34) | const OUTPUT_UPDATE_INTERVAL_MS = 1000;
constant RESTORE_VISIBILITY_DELAY_MS (line 35) | const RESTORE_VISIBILITY_DELAY_MS = 300;
constant MAX_OUTPUT_LENGTH (line 36) | const MAX_OUTPUT_LENGTH = 10000;
function addShellCommandToGeminiHistory (line 38) | function addShellCommandToGeminiHistory(
FILE: packages/cli/src/ui/hooks/shellReducer.ts
type BackgroundShell (line 9) | interface BackgroundShell {
type ShellState (line 19) | interface ShellState {
type ShellAction (line 26) | type ShellAction =
function shellReducer (line 49) | function shellReducer(
FILE: packages/cli/src/ui/hooks/slashCommandProcessor.test.tsx
function createTestCommand (line 110) | function createTestCommand(
method current (line 240) | get current() {
FILE: packages/cli/src/ui/hooks/slashCommandProcessor.ts
type SlashCommandProcessorActions (line 67) | interface SlashCommandProcessorActions {
FILE: packages/cli/src/ui/hooks/toolMapping.ts
function mapToDisplay (line 24) | function mapToDisplay(
FILE: packages/cli/src/ui/hooks/useAnimatedScrollbar.ts
function useAnimatedScrollbar (line 12) | function useAnimatedScrollbar(
FILE: packages/cli/src/ui/hooks/useApprovalModeIndicator.test.ts
type MockConfigInstanceShape (line 41) | interface MockConfigInstanceShape {
type UseKeypressHandler (line 65) | type UseKeypressHandler = (key: Key) => void;
FILE: packages/cli/src/ui/hooks/useApprovalModeIndicator.ts
type UseApprovalModeIndicatorArgs (line 18) | interface UseApprovalModeIndicatorArgs {
function useApprovalModeIndicator (line 26) | function useApprovalModeIndicator({
FILE: packages/cli/src/ui/hooks/useAtCompletion.test.ts
function useTestHarnessForAtCompletion (line 28) | function useTestHarnessForAtCompletion(
FILE: packages/cli/src/ui/hooks/useAtCompletion.ts
constant DEFAULT_SEARCH_TIMEOUT_MS (line 24) | const DEFAULT_SEARCH_TIMEOUT_MS = 5000;
type AtCompletionStatus (line 26) | enum AtCompletionStatus {
type AtCompletionState (line 34) | interface AtCompletionState {
type AtCompletionAction (line 41) | type AtCompletionAction =
function atCompletionReducer (line 57) | function atCompletionReducer(
type UseAtCompletionProps (line 104) | interface UseAtCompletionProps {
type ResourceSuggestionCandidate (line 113) | interface ResourceSuggestionCandidate {
function buildResourceCandidates (line 118) | function buildResourceCandidates(
function buildAgentCandidates (line 142) | function buildAgentCandidates(config?: Config): Suggestion[] {
function searchResourceCandidates (line 154) | async function searchResourceCandidates(
function searchAgentCandidates (line 182) | async function searchAgentCandidates(
function useAtCompletion (line 204) | function useAtCompletion(props: UseAtCompletionProps): void {
FILE: packages/cli/src/ui/hooks/useAtCompletion_agents.test.ts
function useTestHarnessForAtCompletion (line 18) | function useTestHarnessForAtCompletion(
FILE: packages/cli/src/ui/hooks/useBackgroundShellManager.test.tsx
function TestComponent (line 26) | function TestComponent({ p }: { p: BackgroundShellManagerProps }) {
method current (line 33) | get current() {
FILE: packages/cli/src/ui/hooks/useBackgroundShellManager.ts
type BackgroundShellManagerProps (line 10) | interface BackgroundShellManagerProps {
function useBackgroundShellManager (line 20) | function useBackgroundShellManager({
FILE: packages/cli/src/ui/hooks/useBanner.ts
constant DEFAULT_MAX_BANNER_SHOWN_COUNT (line 11) | const DEFAULT_MAX_BANNER_SHOWN_COUNT = 5;
type BannerData (line 13) | interface BannerData {
function useBanner (line 18) | function useBanner(bannerData: BannerData) {
FILE: packages/cli/src/ui/hooks/useBatchedScroll.ts
function useBatchedScroll (line 14) | function useBatchedScroll(currentScrollTop: number) {
FILE: packages/cli/src/ui/hooks/useCommandCompletion.test.tsx
function useTextBufferForTest (line 158) | function useTextBufferForTest(text: string, cursorOffset?: number) {
function TestComponent (line 171) | function TestComponent({
method current (line 213) | get current() {
function TestComponent (line 732) | function TestComponent() {
function TestComponent (line 765) | function TestComponent() {
function TestComponent (line 800) | function TestComponent() {
FILE: packages/cli/src/ui/hooks/useCommandCompletion.tsx
type CompletionMode (line 25) | enum CompletionMode {
type UseCommandCompletionReturn (line 33) | interface UseCommandCompletionReturn {
type UseCommandCompletionOptions (line 65) | interface UseCommandCompletionOptions {
function useCommandCompletion (line 76) | function useCommandCompletion({
FILE: packages/cli/src/ui/hooks/useCompletion.ts
type UseCompletionReturn (line 14) | interface UseCompletionReturn {
function useCompletion (line 30) | function useCompletion(): UseCompletionReturn {
FILE: packages/cli/src/ui/hooks/useConfirmingTool.ts
function useConfirmingTool (line 20) | function useConfirmingTool(): ConfirmingToolState | null {
FILE: packages/cli/src/ui/hooks/useConsoleMessages.test.tsx
function TestComponent (line 71) | function TestComponent() {
method current (line 78) | get current() {
FILE: packages/cli/src/ui/hooks/useConsoleMessages.ts
type UseConsoleMessagesReturn (line 21) | interface UseConsoleMessagesReturn {
type Action (line 26) | type Action =
function consoleMessagesReducer (line 30) | function consoleMessagesReducer(
function useConsoleMessages (line 70) | function useConsoleMessages(): UseConsoleMessagesReturn {
type UseErrorCountReturn (line 183) | interface UseErrorCountReturn {
function useErrorCount (line 188) | function useErrorCount(): UseErrorCountReturn {
FILE: packages/cli/src/ui/hooks/useEditorSettings.test.tsx
function TestComponent (line 52) | function TestComponent() {
FILE: packages/cli/src/ui/hooks/useEditorSettings.ts
type UseEditorSettingsReturn (line 25) | interface UseEditorSettingsReturn {
FILE: packages/cli/src/ui/hooks/useExtensionRegistry.ts
type UseExtensionRegistryResult (line 13) | interface UseExtensionRegistryResult {
function useExtensionRegistry (line 20) | function useExtensionRegistry(
FILE: packages/cli/src/ui/hooks/useExtensionUpdates.test.tsx
function TestComponent (line 125) | function TestComponent() {
function TestComponent (line 175) | function TestComponent() {
function TestComponent (line 253) | function TestComponent() {
function TestComponent (line 336) | function TestComponent() {
FILE: packages/cli/src/ui/hooks/useExtensionUpdates.ts
type ConfirmationRequestWrapper (line 28) | type ConfirmationRequestWrapper = {
type ConfirmationRequestAction (line 33) | type ConfirmationRequestAction =
function confirmationRequestsReducer (line 37) | function confirmationRequestsReducer(
function shouldDoUpdate (line 129) | function shouldDoUpdate(extension: GeminiCLIExtension): boolean {
FILE: packages/cli/src/ui/hooks/useFlickerDetector.ts
function useFlickerDetector (line 21) | function useFlickerDetector(
FILE: packages/cli/src/ui/hooks/useFocus.test.tsx
function TestComponent (line 52) | function TestComponent() {
method current (line 59) | get current() {
FILE: packages/cli/src/ui/hooks/useFocus.ts
constant ENABLE_FOCUS_REPORTING (line 12) | const ENABLE_FOCUS_REPORTING = '\x1b[?1004h';
constant DISABLE_FOCUS_REPORTING (line 13) | const DISABLE_FOCUS_REPORTING = '\x1b[?1004l';
constant FOCUS_IN (line 16) | const FOCUS_IN = '\x1b[I';
constant FOCUS_OUT (line 17) | const FOCUS_OUT = '\x1b[O';
FILE: packages/cli/src/ui/hooks/useGeminiStream.ts
type ToolResponseWithParts (line 95) | type ToolResponseWithParts = ToolCallResponseInfo & {
type BackgroundedToolInfo (line 99) | interface BackgroundedToolInfo {
type StreamProcessingStatus (line 105) | enum StreamProcessingStatus {
constant SUPPRESSED_TOOL_ERRORS_NOTE (line 111) | const SUPPRESSED_TOOL_ERRORS_NOTE =
constant LOW_VERBOSITY_FAILURE_NOTE (line 113) | const LOW_VERBOSITY_FAILURE_NOTE =
function getBackgroundedToolInfo (line 116) | function getBackgroundedToolInfo(
function isBackgroundableExecutingToolCall (line 136) | function isBackgroundableExecutingToolCall(
function showCitations (line 145) | function showCitations(settings: LoadedSettings): boolean {
function calculateStreamingState (line 156) | function calculateStreamingState(
FILE: packages/cli/src/ui/hooks/useGitBranchName.test.tsx
constant CWD (line 50) | const CWD = '/test/project';
constant GIT_LOGS_HEAD_PATH (line 51) | const GIT_LOGS_HEAD_PATH = path.join(CWD, '.git', 'logs', 'HEAD');
function TestComponent (line 67) | function TestComponent() {
method current (line 74) | get current() {
FILE: packages/cli/src/ui/hooks/useGitBranchName.ts
function useGitBranchName (line 13) | function useGitBranchName(cwd: string): string | undefined {
FILE: packages/cli/src/ui/hooks/useHistoryManager.ts
type HistoryItemUpdater (line 12) | type HistoryItemUpdater = (
type UseHistoryManagerReturn (line 16) | interface UseHistoryManagerReturn {
function useHistory (line 37) | function useHistory({
FILE: packages/cli/src/ui/hooks/useIdeTrustListener.test.tsx
function TestComponent (line 83) | function TestComponent() {
method current (line 96) | get current() {
FILE: packages/cli/src/ui/hooks/useIdeTrustListener.ts
type RestartReason (line 23) | type RestartReason = 'NONE' | 'CONNECTION_CHANGE' | 'TRUST_CHANGE';
function useIdeTrustListener (line 30) | function useIdeTrustListener() {
FILE: packages/cli/src/ui/hooks/useIncludeDirsTrust.tsx
function finishAddingDirectories (line 19) | async function finishAddingDirectories(
function useIncludeDirsTrust (line 57) | function useIncludeDirsTrust(
FILE: packages/cli/src/ui/hooks/useInlineEditBuffer.ts
type EditBufferState (line 10) | interface EditBufferState {
type EditBufferAction (line 16) | type EditBufferAction =
function editBufferReducer (line 33) | function editBufferReducer(
type UseEditBufferProps (line 114) | interface UseEditBufferProps {
function useInlineEditBuffer (line 118) | function useInlineEditBuffer({ onCommit }: UseEditBufferProps) {
FILE: packages/cli/src/ui/hooks/useInputHistory.ts
type UseInputHistoryProps (line 10) | interface UseInputHistoryProps {
type UseInputHistoryReturn (line 19) | interface UseInputHistoryReturn {
function useInputHistory (line 25) | function useInputHistory({
FILE: packages/cli/src/ui/hooks/useInputHistoryStore.ts
type Logger (line 10) | interface Logger {
type UseInputHistoryStoreReturn (line 14) | interface UseInputHistoryStoreReturn {
function useInputHistoryStore (line 24) | function useInputHistoryStore(): UseInputHistoryStoreReturn {
FILE: packages/cli/src/ui/hooks/useKeyMatchers.tsx
function useKeyMatchers (line 30) | function useKeyMatchers(): KeyMatchers {
FILE: packages/cli/src/ui/hooks/useKeypress.test.tsx
constant PASTE_START (line 23) | const PASTE_START = '\x1B[200~';
constant PASTE_END (line 24) | const PASTE_END = '\x1B[201~';
class MockStdin (line 26) | class MockStdin extends EventEmitter {
method write (line 35) | write(text: string) {
FILE: packages/cli/src/ui/hooks/useKeypress.ts
function useKeypress (line 25) | function useKeypress(
FILE: packages/cli/src/ui/hooks/useKittyKeyboardProtocol.ts
type KittyProtocolStatus (line 10) | interface KittyProtocolStatus {
function useKittyKeyboardProtocol (line 19) | function useKittyKeyboardProtocol(): KittyProtocolStatus {
FILE: packages/cli/src/ui/hooks/useLoadingIndicator.test.tsx
function TestComponent (line 41) | function TestComponent({
method current (line 74) | get current() {
FILE: packages/cli/src/ui/hooks/useLoadingIndicator.ts
constant LOW_VERBOSITY_RETRY_HINT_ATTEMPT_THRESHOLD (line 17) | const LOW_VERBOSITY_RETRY_HINT_ATTEMPT_THRESHOLD = 2;
type UseLoadingIndicatorProps (line 19) | interface UseLoadingIndicatorProps {
FILE: packages/cli/src/ui/hooks/useMcpStatus.test.tsx
function TestComponent (line 38) | function TestComponent({ config }: { config: Config }) {
method current (line 45) | get current() {
FILE: packages/cli/src/ui/hooks/useMcpStatus.ts
function useMcpStatus (line 15) | function useMcpStatus(config: Config) {
FILE: packages/cli/src/ui/hooks/useMemoryMonitor.test.tsx
function TestComponent (line 30) | function TestComponent() {
FILE: packages/cli/src/ui/hooks/useMemoryMonitor.ts
constant MEMORY_WARNING_THRESHOLD (line 11) | const MEMORY_WARNING_THRESHOLD = 7 * 1024 * 1024 * 1024;
constant MEMORY_CHECK_INTERVAL (line 12) | const MEMORY_CHECK_INTERVAL = 60 * 1000;
type MemoryMonitorOptions (line 14) | interface MemoryMonitorOptions {
FILE: packages/cli/src/ui/hooks/useMessageQueue.test.tsx
function TestComponent (line 34) | function TestComponent(props: typeof initialProps) {
method current (line 41) | get current() {
FILE: packages/cli/src/ui/hooks/useMessageQueue.ts
type UseMessageQueueOptions (line 10) | interface UseMessageQueueOptions {
type UseMessageQueueReturn (line 17) | interface UseMessageQueueReturn {
function useMessageQueue (line 30) | function useMessageQueue({
FILE: packages/cli/src/ui/hooks/useModelCommand.test.tsx
function TestComponent (line 15) | function TestComponent() {
FILE: packages/cli/src/ui/hooks/useModelCommand.ts
type UseModelCommandReturn (line 9) | interface UseModelCommandReturn {
FILE: packages/cli/src/ui/hooks/useMouse.ts
function useMouse (line 23) | function useMouse(
FILE: packages/cli/src/ui/hooks/usePermissionsModifyTrust.ts
type TrustState (line 22) | interface TrustState {
function getInitialTrustState (line 28) | function getInitialTrustState(
FILE: packages/cli/src/ui/hooks/usePhraseCycler.ts
constant PHRASE_CHANGE_INTERVAL_MS (line 12) | const PHRASE_CHANGE_INTERVAL_MS = 15000;
constant INTERACTIVE_SHELL_WAITING_PHRASE (line 13) | const INTERACTIVE_SHELL_WAITING_PHRASE =
FILE: packages/cli/src/ui/hooks/usePrivacySettings.test.tsx
function TestComponent (line 38) | function TestComponent() {
method current (line 45) | get current() {
FILE: packages/cli/src/ui/hooks/usePrivacySettings.ts
type PrivacyState (line 16) | interface PrivacyState {
function getCodeAssistServerOrFail (line 92) | function getCodeAssistServerOrFail(config: Config): CodeAssistServer {
function getRemoteDataCollectionOptIn (line 102) | async function getRemoteDataCollectionOptIn(
function setRemoteDataCollectionOptIn (line 129) | async function setRemoteDataCollectionOptIn(
FILE: packages/cli/src/ui/hooks/usePromptCompletion.ts
constant PROMPT_COMPLETION_MIN_LENGTH (line 18) | const PROMPT_COMPLETION_MIN_LENGTH = 5;
constant PROMPT_COMPLETION_DEBOUNCE_MS (line 19) | const PROMPT_COMPLETION_DEBOUNCE_MS = 250;
type PromptCompletion (line 21) | interface PromptCompletion {
type UsePromptCompletionOptions (line 30) | interface UsePromptCompletionOptions {
function usePromptCompletion (line 35) | function usePromptCompletion({
FILE: packages/cli/src/ui/hooks/useQuotaAndFallback.test.ts
type SpyInstance (line 45) | type SpyInstance = ReturnType<typeof vi.spyOn>;
FILE: packages/cli/src/ui/hooks/useQuotaAndFallback.ts
type UseQuotaAndFallbackArgs (line 37) | interface UseQuotaAndFallbackArgs {
function useQuotaAndFallback (line 48) | function useQuotaAndFallback({
function getResetTimeMessage (line 318) | function getResetTimeMessage(delayMs: number): string {
FILE: packages/cli/src/ui/hooks/useRegistrySearch.ts
type UseRegistrySearchResult (line 12) | interface UseRegistrySearchResult<T extends GenericListItem> {
function useRegistrySearch (line 20) | function useRegistrySearch<T extends GenericListItem>(props: {
FILE: packages/cli/src/ui/hooks/useRepeatedKeyPress.ts
type UseRepeatedKeyPressOptions (line 9) | interface UseRepeatedKeyPressOptions {
function useRepeatedKeyPress (line 15) | function useRepeatedKeyPress(options: UseRepeatedKeyPressOptions) {
FILE: packages/cli/src/ui/hooks/useReverseSearchCompletion.test.tsx
function useTextBufferForTest (line 22) | function useTextBufferForTest(text: string) {
FILE: packages/cli/src/ui/hooks/useReverseSearchCompletion.tsx
function useDebouncedValue (line 12) | function useDebouncedValue<T>(value: T, delay = 200): T {
type UseReverseSearchCompletionReturn (line 21) | interface UseReverseSearchCompletionReturn {
function useReverseSearchCompletion (line 33) | function useReverseSearchCompletion(
FILE: packages/cli/src/ui/hooks/useRewind.ts
function useRewind (line 18) | function useRewind(conversation: ConversationRecord) {
FILE: packages/cli/src/ui/hooks/useRunEventNotifications.ts
constant ATTENTION_NOTIFICATION_COOLDOWN_MS (line 20) | const ATTENTION_NOTIFICATION_COOLDOWN_MS = 20_000;
type RunEventNotificationParams (line 22) | interface RunEventNotificationParams {
function useRunEventNotifications (line 37) | function useRunEventNotifications({
FILE: packages/cli/src/ui/hooks/useSearchBuffer.ts
constant MIN_VIEWPORT_WIDTH (line 13) | const MIN_VIEWPORT_WIDTH = 20;
constant VIEWPORT_WIDTH_OFFSET (line 14) | const VIEWPORT_WIDTH_OFFSET = 8;
type UseSearchBufferProps (line 16) | interface UseSearchBufferProps {
function useSearchBuffer (line 21) | function useSearchBuffer({
FILE: packages/cli/src/ui/hooks/useSelectionList.test.tsx
type UseKeypressMockOptions (line 19) | type UseKeypressMockOptions = { isActive: boolean };
function TestComponent (line 88) | function TestComponent(props: typeof initialProps) {
method current (line 99) | get current() {
function TestComponent (line 1096) | function TestComponent(props: typeof initialProps) {
FILE: packages/cli/src/ui/hooks/useSelectionList.ts
type SelectionListItem (line 13) | interface SelectionListItem<T> {
type BaseSelectionItem (line 20) | interface BaseSelectionItem {
type UseSelectionListOptions (line 25) | interface UseSelectionListOptions<T> {
type UseSelectionListResult (line 37) | interface UseSelectionListResult {
type SelectionListState (line 42) | interface SelectionListState {
type SelectionListAction (line 51) | type SelectionListAction =
constant NUMBER_INPUT_TIMEOUT_MS (line 79) | const NUMBER_INPUT_TIMEOUT_MS = 1000;
function selectionListReducer (line 162) | function selectionListReducer(
function areBaseItemsEqual (line 250) | function areBaseItemsEqual(
function toBaseItems (line 266) | function toBaseItems<T>(
function useSelectionList (line 283) | function useSelectionList<T>({
FILE: packages/cli/src/ui/hooks/useSessionBrowser.test.ts
constant MOCKED_PROJECT_TEMP_DIR (line 52) | const MOCKED_PROJECT_TEMP_DIR = '/test/project/temp';
constant MOCKED_CHATS_DIR (line 53) | const MOCKED_CHATS_DIR = '/test/project/temp/chats';
constant MOCKED_SESSION_ID (line 54) | const MOCKED_SESSION_ID = 'test-session-123';
constant MOCKED_CURRENT_SESSION_ID (line 55) | const MOCKED_CURRENT_SESSION_ID = 'current-session-id';
FILE: packages/cli/src/ui/hooks/useSessionResume.ts
type UseSessionResumeParams (line 19) | interface UseSessionResumeParams {
function useSessionResume (line 34) | function useSessionResume({
FILE: packages/cli/src/ui/hooks/useSettingsCommand.ts
function useSettingsCommand (line 9) | function useSettingsCommand() {
FILE: packages/cli/src/ui/hooks/useSettingsNavigation.ts
type UseSettingsNavigationProps (line 9) | interface UseSettingsNavigationProps {
type NavState (line 14) | type NavState = {
type NavAction (line 19) | type NavAction = { type: 'MOVE_UP' } | { type: 'MOVE_DOWN' };
function calculateSlidingWindow (line 21) | function calculateSlidingWindow(
function createNavReducer (line 40) | function createNavReducer(
function useSettingsNavigation (line 82) | function useSettingsNavigation({
FILE: packages/cli/src/ui/hooks/useShellCompletion.ts
constant MAX_SHELL_SUGGESTIONS (line 18) | const MAX_SHELL_SUGGESTIONS = 100;
constant FS_COMPLETION_DEBOUNCE_MS (line 23) | const FS_COMPLETION_DEBOUNCE_MS = 50;
constant UNIX_SHELL_SPECIAL_CHARS (line 30) | const UNIX_SHELL_SPECIAL_CHARS = /[ \t\n\r'"()&|;<>!#$`{}[\]*?\\]/g;
function escapeShellPath (line 35) | function escapeShellPath(segment: string): string {
type TokenInfo (line 42) | interface TokenInfo {
function getTokenAtCursor (line 59) | function getTokenAtCursor(
function scanPathExecutables (line 183) | async function scanPathExecutables(
function expandTilde (line 305) | function expandTilde(inputPath: string): [string, boolean] {
function resolvePathCompletions (line 316) | async function resolvePathCompletions(
type UseShellCompletionProps (line 419) | interface UseShellCompletionProps {
type UseShellCompletionReturn (line 434) | interface UseShellCompletionReturn {
constant EMPTY_TOKENS (line 441) | const EMPTY_TOKENS: string[] = [];
function useShellCompletion (line 443) | function useShellCompletion({
FILE: packages/cli/src/ui/hooks/useShellHistory.test.ts
class Storage (line 42) | class Storage {
method getGlobalSettingsPath (line 43) | static getGlobalSettingsPath(): string {
method getProjectTempDir (line 46) | getProjectTempDir(): string {
method getHistoryFilePath (line 49) | getHistoryFilePath(): string {
method initialize (line 58) | initialize(): Promise<undefined> {
constant MOCKED_PROJECT_ROOT (line 70) | const MOCKED_PROJECT_ROOT = '/test/project';
constant MOCKED_HOME_DIR (line 71) | const MOCKED_HOME_DIR = '/test/home';
constant MOCKED_PROJECT_HASH (line 72) | const MOCKED_PROJECT_HASH = 'mocked_hash';
constant MOCKED_HISTORY_DIR (line 74) | const MOCKED_HISTORY_DIR = path.join(
constant MOCKED_HISTORY_FILE (line 80) | const MOCKED_HISTORY_FILE = path.join(MOCKED_HISTORY_DIR, 'shell_history');
FILE: packages/cli/src/ui/hooks/useShellHistory.ts
constant MAX_HISTORY_LENGTH (line 12) | const MAX_HISTORY_LENGTH = 100;
type UseShellHistoryReturn (line 14) | interface UseShellHistoryReturn {
function getHistoryFilePath (line 22) | async function getHistoryFilePath(
function readHistoryFile (line 32) | async function readHistoryFile(filePath: string): Promise<string[]> {
function writeHistoryFile (line 61) | async function writeHistoryFile(
function useShellHistory (line 73) | function useShellHistory(
FILE: packages/cli/src/ui/hooks/useShellInactivityStatus.ts
type ShellInactivityStatusProps (line 17) | interface ShellInactivityStatusProps {
type InactivityStatus (line 26) | type InactivityStatus = 'none' | 'action_required' | 'silent_working';
type ShellInactivityStatus (line 28) | interface ShellInactivityStatus {
FILE: packages/cli/src/ui/hooks/useSlashCompletion.test.ts
type TestSlashCommand (line 20) | type TestSlashCommand = Omit<SlashCommand, 'kind'> &
function createTestCommand (line 23) | function createTestCommand(command: TestSlashCommand): SlashCommand {
function simulateFuzzyMatching (line 41) | function simulateFuzzyMatching(items: readonly string[], query: string) {
function useTestHarnessForSlashCompletion (line 145) | function useTestHarnessForSlashCompletion(
FILE: packages/cli/src/ui/hooks/useSlashCompletion.ts
type FzfCommandResult (line 18) | type FzfCommandResult = {
type FzfCommandCacheEntry (line 27) | interface FzfCommandCacheEntry {
function logErrorSafely (line 33) | function logErrorSafely(error: unknown, context: string): void {
function matchesCommand (line 43) | function matchesCommand(cmd: SlashCommand, query: string): boolean {
type CommandParserResult (line 51) | interface CommandParserResult {
function useCommandParser (line 62) | function useCommandParser(
type SuggestionsResult (line 192) | interface SuggestionsResult {
type CompletionPositions (line 197) | interface CompletionPositions {
type PerfectMatchResult (line 202) | interface PerfectMatchResult {
function useCommandSuggestions (line 206) | function useCommandSuggestions(
function useCompletionPositions (line 421) | function useCompletionPositions(
function usePerfectMatch (line 453) | function usePerfectMatch(
function getCommandFromSuggestion (line 493) | function getCommandFromSuggestion(
type UseSlashCompletionProps (line 512) | interface UseSlashCompletionProps {
function useSlashCompletion (line 522) | function useSlashCompletion(props: UseSlashCompletionProps): {
FILE: packages/cli/src/ui/hooks/useSnowfall.ts
type Snowflake (line 16) | interface Snowflake {
constant SNOW_CHARS (line 22) | const SNOW_CHARS = ['*', '.', '·', '+'];
constant FRAME_RATE (line 23) | const FRAME_RATE = 150;
FILE: packages/cli/src/ui/hooks/useSuspend.ts
type UseSuspendProps (line 26) | interface UseSuspendProps {
function useSuspend (line 34) | function useSuspend({
FILE: packages/cli/src/ui/hooks/useTabbedNavigation.ts
type UseTabbedNavigationOptions (line 15) | interface UseTabbedNavigationOptions {
type UseTabbedNavigationResult (line 37) | interface UseTabbedNavigationResult {
type TabbedNavigationState (line 52) | interface TabbedNavigationState {
type TabbedNavigationAction (line 59) | type TabbedNavigationAction =
function tabbedNavigationReducer (line 69) | function tabbedNavigationReducer(
function useTabbedNavigation (line 141) | function useTabbedNavigation({
FILE: packages/cli/src/ui/hooks/useTerminalSize.ts
function useTerminalSize (line 9) | function useTerminalSize(): { columns: number; rows: number } {
FILE: packages/cli/src/ui/hooks/useTerminalTheme.ts
function useTerminalTheme (line 21) | function useTerminalTheme(
FILE: packages/cli/src/ui/hooks/useThemeCommand.ts
type UseThemeCommandReturn (line 18) | interface UseThemeCommandReturn {
FILE: packages/cli/src/ui/hooks/useTimedMessage.ts
function useTimedMessage (line 13) | function useTimedMessage<T>(durationMs: number) {
FILE: packages/cli/src/ui/hooks/useTimer.test.tsx
function TestComponent (line 26) | function TestComponent({
method current (line 41) | get current() {
FILE: packages/cli/src/ui/hooks/useTips.ts
type UseTipsResult (line 10) | interface UseTipsResult {
function useTips (line 14) | function useTips(): UseTipsResult {
FILE: packages/cli/src/ui/hooks/useToolScheduler.ts
type ScheduleFn (line 22) | type ScheduleFn = (
type MarkToolsAsSubmittedFn (line 27) | type MarkToolsAsSubmittedFn = (callIds: string[]) => void;
type CancelAllFn (line 28) | type CancelAllFn = (signal: AbortSignal) => void;
type TrackedToolCall (line 34) | type TrackedToolCall = ToolCall & {
type TrackedScheduledToolCall (line 39) | type TrackedScheduledToolCall = Extract<
type TrackedValidatingToolCall (line 43) | type TrackedValidatingToolCall = Extract<
type TrackedWaitingToolCall (line 47) | type TrackedWaitingToolCall = Extract<
type TrackedExecutingToolCall (line 51) | type TrackedExecutingToolCall = Extract<
type TrackedCompletedToolCall (line 55) | type TrackedCompletedToolCall = Extract<
type TrackedCancelledToolCall (line 59) | type TrackedCancelledToolCall = Extract<
function useToolScheduler (line 67) | function useToolScheduler(
function adaptToolCalls (line 266) | function adaptToolCalls(
FILE: packages/cli/src/ui/hooks/useTurnActivityMonitor.ts
type TurnActivityStatus (line 12) | interface TurnActivityStatus {
FILE: packages/cli/src/ui/hooks/useVisibilityToggle.ts
constant APPROVAL_MODE_REVEAL_DURATION_MS (line 10) | const APPROVAL_MODE_REVEAL_DURATION_MS = 1200;
constant FOCUS_UI_ENABLED_STATE_KEY (line 11) | const FOCUS_UI_ENABLED_STATE_KEY = 'focusUiEnabled';
function useVisibilityToggle (line 13) | function useVisibilityToggle() {
FILE: packages/cli/src/ui/hooks/vim.test.tsx
constant TEST_SEQUENCES (line 84) | const TEST_SEQUENCES = {
method cursor (line 119) | get cursor() {
method cursor (line 122) | set cursor(newPos: [number, number]) {
type VimActionType (line 1547) | type VimActionType =
type VimReducerTestCase (line 1558) | type VimReducerTestCase = {
type FindCase (line 2137) | type FindCase = {
type OperatorFindCase (line 2291) | type OperatorFindCase = {
FILE: packages/cli/src/ui/hooks/vim.ts
type VimMode (line 16) | type VimMode = 'NORMAL' | 'INSERT';
constant DIGIT_MULTIPLIER (line 19) | const DIGIT_MULTIPLIER = 10;
constant DEFAULT_COUNT (line 20) | const DEFAULT_COUNT = 1;
constant DIGIT_1_TO_9 (line 21) | const DIGIT_1_TO_9 = /^[1-9]$/;
constant DOUBLE_ESCAPE_TIMEOUT_MS (line 22) | const DOUBLE_ESCAPE_TIMEOUT_MS = 500;
constant CMD_TYPES (line 25) | const CMD_TYPES = {
type PendingFindOp (line 76) | type PendingFindOp = {
type VimState (line 88) | type VimState = {
type VimAction (line 97) | type VimAction =
function useVim (line 187) | function useVim(buffer: TextBuffer, onSubmit?: (value: string) => void) {
FILE: packages/cli/src/ui/key/keyBindings.ts
type Command (line 17) | enum Command {
class KeyBinding (line 112) | class KeyBinding {
method constructor (line 153) | constructor(pattern: string) {
method matches (line 213) | matches(key: Key): boolean {
method equals (line 223) | equals(other: KeyBinding): boolean {
type KeyBindingConfig (line 237) | type KeyBindingConfig = Map<Command, readonly KeyBinding[]>;
type CommandCategory (line 404) | interface CommandCategory {
function loadCustomKeybindings (line 670) | async function loadCustomKeybindings(): Promise<{
FILE: packages/cli/src/ui/key/keyMatchers.ts
function matchCommand (line 18) | function matchCommand(
type KeyMatcher (line 31) | type KeyMatcher = (key: Key) => boolean;
type KeyMatchers (line 36) | type KeyMatchers = {
function createKeyMatchers (line 43) | function createKeyMatchers(
function loadKeyMatchers (line 69) | async function loadKeyMatchers(): Promise<{
FILE: packages/cli/src/ui/key/keyToAnsi.ts
constant SPECIAL_KEYS (line 11) | const SPECIAL_KEYS: Record<string, string> = {
function keyToAnsi (line 34) | function keyToAnsi(key: Key): string | null {
FILE: packages/cli/src/ui/key/keybindingUtils.ts
constant KEY_NAME_MAP (line 18) | const KEY_NAME_MAP: Record<string, string> = {
type ModifierMap (line 35) | interface ModifierMap {
constant MODIFIER_MAPS (line 42) | const MODIFIER_MAPS: Record<string, ModifierMap> = {
function formatKeyBinding (line 72) | function formatKeyBinding(
function formatCommand (line 98) | function formatCommand(
FILE: packages/cli/src/ui/noninteractive/nonInteractiveUi.ts
function createNonInteractiveUI (line 15) | function createNonInteractiveUI(): CommandContext['ui'] {
FILE: packages/cli/src/ui/privacy/CloudFreePrivacyNotice.tsx
type CloudFreePrivacyNoticeProps (line 15) | interface CloudFreePrivacyNoticeProps {
FILE: packages/cli/src/ui/privacy/CloudPaidPrivacyNotice.tsx
type CloudPaidPrivacyNoticeProps (line 11) | interface CloudPaidPrivacyNoticeProps {
FILE: packages/cli/src/ui/privacy/GeminiPrivacyNotice.tsx
type GeminiPrivacyNoticeProps (line 11) | interface GeminiPrivacyNoticeProps {
FILE: packages/cli/src/ui/privacy/PrivacyNotice.tsx
type PrivacyNoticeProps (line 13) | interface PrivacyNoticeProps {
FILE: packages/cli/src/ui/semantic-colors.ts
method text (line 11) | get text() {
method background (line 14) | get background() {
method border (line 17) | get border() {
method ui (line 20) | get ui() {
method status (line 23) | get status() {
FILE: packages/cli/src/ui/state/extensions.ts
type ExtensionUpdateState (line 10) | enum ExtensionUpdateState {
type ExtensionUpdateStatus (line 22) | interface ExtensionUpdateStatus {
type ExtensionUpdatesState (line 27) | interface ExtensionUpdatesState {
type ScheduledUpdate (line 34) | interface ScheduledUpdate {
type ScheduleUpdateArgs (line 40) | interface ScheduleUpdateArgs {
type OnCompleteUpdate (line 46) | type OnCompleteUpdate = (updateInfos: ExtensionUpdateInfo[]) => void;
type ExtensionUpdateAction (line 54) | type ExtensionUpdateAction =
function extensionUpdatesReducer (line 69) | function extensionUpdatesReducer(
FILE: packages/cli/src/ui/textConstants.ts
constant SCREEN_READER_USER_PREFIX (line 7) | const SCREEN_READER_USER_PREFIX = 'User: ';
constant SCREEN_READER_MODEL_PREFIX (line 9) | const SCREEN_READER_MODEL_PREFIX = 'Model: ';
constant SCREEN_READER_LOADING (line 11) | const SCREEN_READER_LOADING = 'loading';
constant SCREEN_READER_RESPONDING (line 13) | const SCREEN_READER_RESPONDING = 'responding';
constant REDIRECTION_WARNING_NOTE_LABEL (line 15) | const REDIRECTION_WARNING_NOTE_LABEL = 'Note: ';
constant REDIRECTION_WARNING_NOTE_TEXT (line 16) | const REDIRECTION_WARNING_NOTE_TEXT =
constant REDIRECTION_WARNING_TIP_LABEL (line 18) | const REDIRECTION_WARNING_TIP_LABEL = 'Tip: ';
FILE: packages/cli/src/ui/themes/builtin/dark/ansi-dark.ts
constant ANSI (line 30) | const ANSI: Theme = new Theme(
FILE: packages/cli/src/ui/themes/color-utils.ts
function isValidColor (line 34) | function isValidColor(color: string): boolean {
function getSafeLowColorBackground (line 62) | function getSafeLowColorBackground(
constant LIGHT_THEME_LUMINANCE_THRESHOLD (line 85) | const LIGHT_THEME_LUMINANCE_THRESHOLD = 140;
constant DARK_THEME_LUMINANCE_THRESHOLD (line 86) | const DARK_THEME_LUMINANCE_THRESHOLD = 110;
function shouldSwitchTheme (line 98) | function shouldSwitchTheme(
function parseColor (line 129) | function parseColor(rHex: string, gHex: string, bHex: string): string {
FILE: packages/cli/src/ui/themes/semantic-tokens.ts
type SemanticColors (line 9) | interface SemanticColors {
FILE: packages/cli/src/ui/themes/theme-manager.ts
type ThemeDisplay (line 44) | interface ThemeDisplay {
constant DEFAULT_THEME (line 50) | const DEFAULT_THEME: Theme = DefaultDark;
class ThemeManager (line 52) | class ThemeManager {
method constructor (line 68) | constructor(dependencies?: { fs?: typeof fs; homedir?: () => string }) {
method setTerminalBackground (line 93) | setTerminalBackground(color: string | undefined): void {
method getTerminalBackground (line 100) | getTerminalBackground(): string | undefined {
method clearCache (line 104) | private clearCache(): void {
method isDefaultTheme (line 110) | isDefaultTheme(themeName: string | undefined): boolean {
method loadCustomThemes (line 122) | loadCustomThemes(customThemesSettings?: Record<string, CustomTheme>): ...
method registerExtensionThemes (line 169) | registerExtensionThemes(
method unregisterExtensionThemes (line 223) | unregisterExtensionThemes(
method hasExtensionThemes (line 243) | hasExtensionThemes(extensionName: string): boolean {
method clearExtensionThemes (line 253) | clearExtensionThemes(): void {
method clearFileThemes (line 261) | clearFileThemes(): void {
method reinitialize (line 269) | reinitialize(dependencies: { fs?: typeof fs; homedir?: () => string })...
method resetForTesting (line 282) | resetForTesting(dependencies?: {
method setActiveTheme (line 296) | setActiveTheme(themeName: string | undefined): boolean {
method getActiveTheme (line 312) | getActiveTheme(): Theme {
method getColors (line 349) | getColors(): ColorsTheme {
method getSemanticColors (line 397) | getSemanticColors(): SemanticColors {
method isThemeCompatible (line 437) | isThemeCompatible(
method _getAllCustomThemes (line 461) | private _getAllCustomThemes(): Theme[] {
method getCustomThemeNames (line 473) | getCustomThemeNames(): string[] {
method isCustomTheme (line 482) | isCustomTheme(themeName: string): boolean {
method getAvailableThemes (line 493) | getAvailableThemes(): ThemeDisplay[] {
method getTheme (line 539) | getTheme(themeName: string): Theme | undefined {
method getAllThemes (line 547) | getAllThemes(): Theme[] {
method isPath (line 551) | private isPath(themeName: string): boolean {
method loadThemeFromFile (line 559) | private loadThemeFromFile(themePath: string): Theme | undefined {
method findThemeByName (line 622) | findThemeByName(themeName: string | undefined): Theme | undefined {
FILE: packages/cli/src/ui/themes/theme.ts
constant INK_SUPPORTED_NAMES (line 21) | const INK_SUPPORTED_NAMES = new Set([
constant CSS_NAME_TO_HEX_MAP (line 43) | const CSS_NAME_TO_HEX_MAP = Object.fromEntries(
constant INK_NAME_TO_HEX_MAP (line 50) | const INK_NAME_TO_HEX_MAP: Readonly<Record<string, string>> = {
function getLuminance (line 68) | function getLuminance(color: string): number {
function resolveColor (line 86) | function resolveColor(colorValue: string): string | undefined {
function interpolateColor (line 120) | function interpolateColor(
function getThemeTypeFromBackgroundColor (line 143) | function getThemeTypeFromBackgroundColor(
type ThemeType (line 161) | type ThemeType = 'light' | 'dark' | 'ansi' | 'custom';
type ColorsTheme (line 163) | interface ColorsTheme {
class Theme (line 251) | class Theme {
method constructor (line 269) | constructor(
method getInkColor (line 343) | getInkColor(hljsClass: string): string | undefined {
method _resolveColor (line 352) | private static _resolveColor(colorValue: string): string | undefined {
method _buildColorMap (line 362) | protected _buildColorMap(
function createCustomTheme (line 394) | function createCustomTheme(customTheme: CustomTheme): Theme {
function validateCustomTheme (line 629) | function validateCustomTheme(customTheme: Partial<CustomTheme>): {
function isValidThemeName (line 652) | function isValidThemeName(name: string): boolean {
function pickDefaultThemeName (line 668) | function pickDefaultThemeName(
FILE: packages/cli/src/ui/types.ts
type AuthState (line 27) | enum AuthState {
type StreamingState (line 41) | enum StreamingState {
type GeminiEventType (line 48) | enum GeminiEventType {
type ToolCallStatus (line 54) | enum ToolCallStatus {
function mapCoreStatusToDisplayStatus (line 66) | function mapCoreStatusToDisplayStatus(
type ToolCallEvent (line 89) | interface ToolCallEvent {
type IndividualToolCallDisplay (line 100) | interface IndividualToolCallDisplay {
type CompressionProps (line 122) | interface CompressionProps {
type HistoryItemBase (line 134) | interface HistoryItemBase {
type HistoryItemUser (line 138) | type HistoryItemUser = HistoryItemBase & {
type HistoryItemGemini (line 143) | type HistoryItemGemini = HistoryItemBase & {
type HistoryItemGeminiContent (line 148) | type HistoryItemGeminiContent = HistoryItemBase & {
type HistoryItemInfo (line 153) | type HistoryItemInfo = HistoryItemBase & {
type HistoryItemError (line 162) | type HistoryItemError = HistoryItemBase & {
type HistoryItemWarning (line 167) | type HistoryItemWarning = HistoryItemBase & {
type HistoryItemAbout (line 172) | type HistoryItemAbout = HistoryItemBase & {
type HistoryItemHelp (line 185) | type HistoryItemHelp = HistoryItemBase & {
type HistoryItemQuotaBase (line 190) | interface HistoryItemQuotaBase extends HistoryItemBase {
type QuotaStats (line 200) | interface QuotaStats {
type HistoryItemStats (line 206) | type HistoryItemStats = HistoryItemQuotaBase & {
type HistoryItemModelStats (line 213) | type HistoryItemModelStats = HistoryItemQuotaBase & {
type HistoryItemToolStats (line 217) | type HistoryItemToolStats = HistoryItemBase & {
type HistoryItemModel (line 221) | type HistoryItemModel = HistoryItemBase & {
type HistoryItemQuit (line 226) | type HistoryItemQuit = HistoryItemBase & {
type HistoryItemToolGroup (line 231) | type HistoryItemToolGroup = HistoryItemBase & {
type HistoryItemUserShell (line 240) | type HistoryItemUserShell = HistoryItemBase & {
type HistoryItemCompression (line 245) | type HistoryItemCompression = HistoryItemBase & {
type HistoryItemExtensionsList (line 250) | type HistoryItemExtensionsList = HistoryItemBase & {
type ChatDetail (line 255) | interface ChatDetail {
type HistoryItemThinking (line 260) | type HistoryItemThinking = HistoryItemBase & {
type HistoryItemHint (line 265) | type HistoryItemHint = HistoryItemBase & {
type HistoryItemChatList (line 270) | type HistoryItemChatList = HistoryItemBase & {
type ToolDefinition (line 275) | interface ToolDefinition {
type HistoryItemToolsList (line 281) | type HistoryItemToolsList = HistoryItemBase & {
type HistoryItemSkillsList (line 287) | type HistoryItemSkillsList = HistoryItemBase & {
type AgentDefinitionJson (line 293) | type AgentDefinitionJson = Pick<
type HistoryItemAgentsList (line 298) | type HistoryItemAgentsList = HistoryItemBase & {
type JsonMcpTool (line 305) | interface JsonMcpTool {
type JsonMcpPrompt (line 315) | interface JsonMcpPrompt {
type JsonMcpResource (line 321) | interface JsonMcpResource {
type HistoryItemMcpStatus (line 329) | type HistoryItemMcpStatus = HistoryItemBase & {
type HistoryItemWithoutId (line 359) | type HistoryItemWithoutId =
type HistoryItem (line 385) | type HistoryItem = HistoryItemWithoutId & { id: number };
type MessageType (line 388) | enum MessageType {
type Message (line 411) | type Message =
type ConsoleMessageItem (line 463) | interface ConsoleMessageItem {
type SubmitPromptResult (line 473) | interface SubmitPromptResult {
type SlashCommandProcessorResult (line 481) | type SlashCommandProcessorResult =
type ConfirmationRequest (line 493) | interface ConfirmationRequest {
type LoopDetectionConfirmationRequest (line 498) | interface LoopDetectionConfirmationRequest {
type PermissionConfirmationRequest (line 502) | interface PermissionConfirmationRequest {
type ActiveHook (line 507) | interface ActiveHook {
FILE: packages/cli/src/ui/utils/CodeColorizer.tsx
function renderHastNode (line 30) | function renderHastNode(
function highlightAndRenderLine (line 96) | function highlightAndRenderLine(
function colorizeLine (line 116) | function colorizeLine(
type ColorizeCodeOptions (line 125) | interface ColorizeCodeOptions {
function colorizeCode (line 141) | function colorizeCode({
FILE: packages/cli/src/ui/utils/ConsolePatcher.ts
type ConsolePatcherParams (line 12) | interface ConsolePatcherParams {
class ConsolePatcher (line 18) | class ConsolePatcher {
method constructor (line 27) | constructor(params: ConsolePatcherParams) {
method patch (line 31) | patch() {
FILE: packages/cli/src/ui/utils/InlineMarkdownRenderer.tsx
type RenderInlineProps (line 12) | interface RenderInlineProps {
FILE: packages/cli/src/ui/utils/MarkdownDisplay.tsx
type MarkdownDisplayProps (line 16) | interface MarkdownDisplayProps {
constant EMPTY_LINE_HEIGHT (line 26) | const EMPTY_LINE_HEIGHT = 1;
constant CODE_BLOCK_PREFIX_PADDING (line 27) | const CODE_BLOCK_PREFIX_PADDING = 1;
constant LIST_ITEM_PREFIX_PADDING (line 28) | const LIST_ITEM_PREFIX_PADDING = 1;
constant LIST_ITEM_TEXT_FLEX_GROW (line 29) | const LIST_ITEM_TEXT_FLEX_GROW = 1;
function addContentBlock (line 81) | function addContentBlock(block: React.ReactNode) {
type RenderCodeBlockProps (line 319) | interface RenderCodeBlockProps {
type RenderListItemProps (line 402) | interface RenderListItemProps {
type RenderTableProps (line 440) | interface RenderTableProps {
FILE: packages/cli/src/ui/utils/TableRenderer.tsx
type TableRendererProps (line 23) | interface TableRendererProps {
constant MIN_COLUMN_WIDTH (line 29) | const MIN_COLUMN_WIDTH = 5;
constant COLUMN_PADDING (line 30) | const COLUMN_PADDING = 2;
constant TABLE_MARGIN (line 31) | const TABLE_MARGIN = 2;
type ProcessedLine (line 56) | interface ProcessedLine {
FILE: packages/cli/src/ui/utils/borderStyles.ts
function isTrackedToolCall (line 19) | function isTrackedToolCall(
function getToolGroupBorderAppearance (line 28) | function getToolGroupBorderAppearance(
FILE: packages/cli/src/ui/utils/clipboardUtils.test.ts
type ClipboardUtilsModule (line 81) | type ClipboardUtilsModule = typeof import('./clipboardUtils.js');
FILE: packages/cli/src/ui/utils/clipboardUtils.ts
constant IMAGE_EXTENSIONS (line 22) | const IMAGE_EXTENSIONS = [
constant PATH_PREFIX_PATTERN (line 32) | const PATH_PREFIX_PATTERN = /^([/~.]|[a-zA-Z]:|\\\\)/;
function getUserLinuxClipboardTool (line 38) | function getUserLinuxClipboardTool(): typeof linuxClipboardTool {
function saveFromCommand (line 64) | async function saveFromCommand(
function checkWlPasteForImage (line 131) | async function checkWlPasteForImage() {
function checkXclipForImage (line 144) | async function checkXclipForImage() {
function clipboardHasImage (line 164) | async function clipboardHasImage(): Promise<boolean> {
function saveFileWithWlPaste (line 208) | async function saveFileWithWlPaste(tempFilePath: string) {
function getProjectClipboardImagesDir (line 258) | async function getProjectClipboardImagesDir(
function saveClipboardImage (line 272) | async function saveClipboardImage(
function cleanupOldClipboardImages (line 397) | async function cleanupOldClipboardImages(
function isValidFilePath (line 496) | function isValidFilePath(p: string): boolean {
function parsePastedPaths (line 511) | function parsePastedPaths(text: string): string | null {
FILE: packages/cli/src/ui/utils/commandUtils.test.ts
constant ESC (line 19) | const ESC = '\u001B';
constant BEL (line 20) | const BEL = '\u0007';
type MockChildProcess (line 99) | interface MockChildProcess extends EventEmitter {
FILE: packages/cli/src/ui/utils/commandUtils.ts
constant AT_COMMAND_DETECT_REGEX (line 18) | const AT_COMMAND_DETECT_REGEX = new RegExp(
constant ESC (line 62) | const ESC = '\u001B';
constant BEL (line 63) | const BEL = '\u0007';
constant MAX_OSC52_SEQUENCE_BYTES (line 66) | const MAX_OSC52_SEQUENCE_BYTES = 100_000;
constant OSC52_HEADER (line 67) | const OSC52_HEADER = `${ESC}]52;c;`;
constant OSC52_FOOTER (line 68) | const OSC52_FOOTER = BEL;
constant MAX_OSC52_BODY_B64_BYTES (line 69) | const MAX_OSC52_BODY_B64_BYTES =
constant MAX_OSC52_DATA_BYTES (line 73) | const MAX_OSC52_DATA_BYTES = Math.floor(MAX_OSC52_BODY_B64_BYTES / 4) * 3;
constant SCREEN_DCS_CHUNK_SIZE (line 76) | const SCREEN_DCS_CHUNK_SIZE = 240;
type TtyTarget (line 78) | type TtyTarget = { stream: Writable; closeAfter: boolean } | null;
function isAutoExecutableCommand (line 320) | function isAutoExecutableCommand(
FILE: packages/cli/src/ui/utils/computeStats.ts
function calculateErrorRate (line 13) | function calculateErrorRate(metrics: ModelMetrics): number {
function calculateAverageLatency (line 20) | function calculateAverageLatency(metrics: ModelMetrics): number {
function calculateCacheHitRate (line 27) | function calculateCacheHitRate(metrics: ModelMetrics): number {
FILE: packages/cli/src/ui/utils/confirmingTool.ts
type ConfirmingToolState (line 14) | interface ConfirmingToolState {
function getConfirmingToolState (line 23) | function getConfirmingToolState(
FILE: packages/cli/src/ui/utils/contextUsage.ts
function getContextUsagePercentage (line 9) | function getContextUsagePercentage(
function isContextUsageHigh (line 23) | function isContextUsageHigh(
FILE: packages/cli/src/ui/utils/directoryUtils.test.ts
type MockDirent (line 52) | interface MockDirent {
function createMockDir (line 57) | function createMockDir(entries: MockDirent[]) {
FILE: packages/cli/src/ui/utils/directoryUtils.ts
constant MAX_SUGGESTIONS (line 12) | const MAX_SUGGESTIONS = 50;
constant MATCH_BUFFER_MULTIPLIER (line 13) | const MATCH_BUFFER_MULTIPLIER = 3;
function expandHomeDir (line 15) | function expandHomeDir(p: string): string {
type ParsedPath (line 28) | interface ParsedPath {
function parsePartialPath (line 35) | function parsePartialPath(partialPath: string): ParsedPath {
function getDirectorySuggestions (line 94) | async function getDirectorySuggestions(
type BatchAddResult (line 143) | interface BatchAddResult {
function batchAddDirectories (line 152) | function batchAddDirectories(
FILE: packages/cli/src/ui/utils/displayUtils.ts
constant TOOL_SUCCESS_RATE_HIGH (line 10) | const TOOL_SUCCESS_RATE_HIGH = 95;
constant TOOL_SUCCESS_RATE_MEDIUM (line 11) | const TOOL_SUCCESS_RATE_MEDIUM = 85;
constant USER_AGREEMENT_RATE_HIGH (line 13) | const USER_AGREEMENT_RATE_HIGH = 75;
constant USER_AGREEMENT_RATE_MEDIUM (line 14) | const USER_AGREEMENT_RATE_MEDIUM = 45;
constant CACHE_EFFICIENCY_HIGH (line 16) | const CACHE_EFFICIENCY_HIGH = 40;
constant CACHE_EFFICIENCY_MEDIUM (line 17) | const CACHE_EFFICIENCY_MEDIUM = 15;
constant QUOTA_THRESHOLD_HIGH (line 19) | const QUOTA_THRESHOLD_HIGH = 20;
constant QUOTA_THRESHOLD_MEDIUM (line 20) | const QUOTA_THRESHOLD_MEDIUM = 5;
constant QUOTA_USED_WARNING_THRESHOLD (line 22) | const QUOTA_USED_WARNING_THRESHOLD = 80;
constant QUOTA_USED_CRITICAL_THRESHOLD (line 23) | const QUOTA_USED_CRITICAL_THRESHOLD = 95;
FILE: packages/cli/src/ui/utils/editorUtils.ts
function openFileInEditor (line 27) | async function openFileInEditor(
FILE: packages/cli/src/ui/utils/formatters.ts
function stripReferenceContent (line 91) | function stripReferenceContent(text: string): string {
FILE: packages/cli/src/ui/utils/highlight.ts
type HighlightToken (line 16) | type HighlightToken = {
constant HIGHLIGHT_REGEX (line 27) | const HIGHLIGHT_REGEX = new RegExp(
function parseInputForHighlighting (line 36) | function parseInputForHighlighting(
function parseSegmentsFromTokens (line 134) | function parseSegmentsFromTokens(
FILE: packages/cli/src/ui/utils/historyExportUtils.ts
function serializeHistoryToMarkdown (line 14) | function serializeHistoryToMarkdown(
type ExportHistoryOptions (line 53) | interface ExportHistoryOptions {
function exportHistoryToFile (line 61) | async function exportHistoryToFile(
FILE: packages/cli/src/ui/utils/inlineThinkingMode.ts
type InlineThinkingMode (line 9) | type InlineThinkingMode = 'off' | 'full';
function getInlineThinkingMode (line 11) | function getInlineThinkingMode(
FILE: packages/cli/src/ui/utils/input.ts
constant ESC (line 7) | const ESC = '\u001B';
constant SGR_EVENT_PREFIX (line 8) | const SGR_EVENT_PREFIX = `${ESC}[<`;
constant X11_EVENT_PREFIX (line 9) | const X11_EVENT_PREFIX = `${ESC}[M`;
constant SGR_MOUSE_REGEX (line 12) | const SGR_MOUSE_REGEX = /^\x1b\[<(\d+);(\d+);(\d+)([mM])/;
constant X11_MOUSE_REGEX (line 15) | const X11_MOUSE_REGEX = /^\x1b\[M([\s\S]{3})/;
function couldBeSGRMouseSequence (line 17) | function couldBeSGRMouseSequence(buffer: string): boolean {
function couldBeMouseSequence (line 27) | function couldBeMouseSequence(buffer: string): boolean {
function getMouseSequenceLength (line 50) | function getMouseSequenceLength(buffer: string): number {
FILE: packages/cli/src/ui/utils/isNarrowWidth.ts
function isNarrowWidth (line 7) | function isNarrowWidth(width: number): boolean {
FILE: packages/cli/src/ui/utils/markdownParsingUtils.ts
constant BOLD_MARKER_LENGTH (line 17) | const BOLD_MARKER_LENGTH = 2;
constant ITALIC_MARKER_LENGTH (line 18) | const ITALIC_MARKER_LENGTH = 1;
constant STRIKETHROUGH_MARKER_LENGTH (line 19) | const STRIKETHROUGH_MARKER_LENGTH = 2;
constant INLINE_CODE_MARKER_LENGTH (line 20) | const INLINE_CODE_MARKER_LENGTH = 1;
constant UNDERLINE_TAG_START_LENGTH (line 21) | const UNDERLINE_TAG_START_LENGTH = 3;
constant UNDERLINE_TAG_END_LENGTH (line 22) | const UNDERLINE_TAG_END_LENGTH = 4;
FILE: packages/cli/src/ui/utils/mouse.ts
type MouseEventName (line 16) | type MouseEventName =
constant DOUBLE_CLICK_THRESHOLD_MS (line 30) | const DOUBLE_CLICK_THRESHOLD_MS = 400;
constant DOUBLE_CLICK_DISTANCE_TOLERANCE (line 31) | const DOUBLE_CLICK_DISTANCE_TOLERANCE = 2;
type MouseEvent (line 33) | interface MouseEvent {
type MouseHandler (line 43) | type MouseHandler = (event: MouseEvent) => void | boolean;
function getMouseEventName (line 45) | function getMouseEventName(
function getButtonFromCode (line 79) | function getButtonFromCode(code: number): MouseEvent['button'] {
function parseSGRMouseEvent (line 93) | function parseSGRMouseEvent(
function parseX11MouseEvent (line 131) | function parseX11MouseEvent(
function parseMouseEvent (line 209) | function parseMouseEvent(
function isIncompleteMouseSequence (line 215) | function isIncompleteMouseSequence(buffer: string): boolean {
FILE: packages/cli/src/ui/utils/pendingAttentionNotification.ts
type PendingAttentionNotification (line 16) | interface PendingAttentionNotification {
function keyFromReactNode (line 21) | function keyFromReactNode(node: ReactNode): string {
function getPendingAttentionNotification (line 31) | function getPendingAttentionNotification(
FILE: packages/cli/src/ui/utils/rewindFileOps.ts
type FileChangeDetail (line 20) | interface FileChangeDetail {
type FileChangeStats (line 25) | interface FileChangeStats {
function calculateTurnStats (line 41) | function calculateTurnStats(
function calculateRewindImpact (line 91) | function calculateRewindImpact(
function revertFileChanges (line 149) | async function revertFileChanges(
FILE: packages/cli/src/ui/utils/shortcutsHelp.ts
function useIsHelpDismissKey (line 11) | function useIsHelpDismissKey(): (key: Key) => boolean {
FILE: packages/cli/src/ui/utils/terminalCapabilityManager.ts
type TerminalBackgroundColor (line 19) | type TerminalBackgroundColor = string | undefined;
constant TERMINAL_CLEANUP_SEQUENCE (line 21) | const TERMINAL_CLEANUP_SEQUENCE = '\x1b[<u\x1b[>4;0m\x1b[?2004l';
function cleanupTerminalOnExit (line 23) | function cleanupTerminalOnExit() {
class TerminalCapabilityManager (line 38) | class TerminalCapabilityManager {
method queryBackgroundColor (line 54) | static queryBackgroundColor(stdout: {
method constructor (line 84) | private constructor() {}
method getInstance (line 86) | static getInstance(): TerminalCapabilityManager {
method resetInstanceForTesting (line 93) | static resetInstanceForTesting(): void {
method detectCapabilities (line 102) | async detectCapabilities(): Promise<void> {
method enableSupportedModes (line 243) | enableSupportedModes() {
method getTerminalBackgroundColor (line 260) | getTerminalBackgroundColor(): TerminalBackgroundColor {
method getTerminalName (line 264) | getTerminalName(): string | undefined {
method isKittyProtocolEnabled (line 268) | isKittyProtocolEnabled(): boolean {
method supportsOsc9Notifications (line 272) | supportsOsc9Notifications(env: NodeJS.ProcessEnv = process.env): boole...
method hasOsc9TerminalSignature (line 284) | private hasOsc9TerminalSignature(value: string | undefined): boolean {
FILE: packages/cli/src/ui/utils/terminalSetup.ts
type AddItemFn (line 41) | type AddItemFn = UseHistoryManagerReturn['addItem'];
constant VSCODE_SHIFT_ENTER_SEQUENCE (line 43) | const VSCODE_SHIFT_ENTER_SEQUENCE = '\\\r\n';
function stripJsonComments (line 51) | function stripJsonComments(content: string): string {
type TerminalSetupResult (line 56) | interface TerminalSetupResult {
type SupportedTerminal (line 62) | type SupportedTerminal = 'vscode' | 'cursor' | 'windsurf' | 'antigravity';
type TerminalData (line 67) | interface TerminalData {
constant TERMINAL_DATA (line 71) | const TERMINAL_DATA: Record<SupportedTerminal, TerminalData> = {
function getSupportedTerminalData (line 81) | function getSupportedTerminalData(
type Keybinding (line 87) | type Keybinding = {
function isKeybinding (line 93) | function isKeybinding(kb: unknown): kb is Keybinding {
function hasOurBinding (line 100) | function hasOurBinding(
function getTerminalProgram (line 114) | function getTerminalProgram(): SupportedTerminal | null {
function detectTerminal (line 147) | async function detectTerminal(): Promise<SupportedTerminal | null> {
function backupFile (line 181) | async function backupFile(filePath: string): Promise<void> {
function getVSCodeStyleConfigDir (line 193) | function getVSCodeStyleConfigDir(appName: string): string | null {
function configureVSCodeStyle (line 215) | async function configureVSCodeStyle(
function shouldPromptForTerminalSetup (line 380) | async function shouldPromptForTerminalSetup(): Promise<boolean> {
function terminalSetup (line 442) | async function terminalSetup(): Promise<TerminalSetupResult> {
constant TERMINAL_SETUP_CONSENT_MESSAGE (line 473) | const TERMINAL_SETUP_CONSENT_MESSAGE =
function formatTerminalSetupResultMessage (line 477) | function formatTerminalSetupResultMessage(
type UseTerminalSetupPromptParams (line 488) | interface UseTerminalSetupPromptParams {
function useTerminalSetupPrompt (line 496) | function useTerminalSetupPrompt({
FILE: packages/cli/src/ui/utils/terminalUtils.ts
function getColorDepth (line 13) | function getColorDepth(): number {
function isLowColorDepth (line 20) | function isLowColorDepth(): boolean {
function isITerm2 (line 29) | function isITerm2(): boolean {
function resetITerm2Cache (line 43) | function resetITerm2Cache(): void {
FILE: packages/cli/src/ui/utils/textOutput.ts
class TextOutput (line 14) | class TextOutput {
method constructor (line 18) | constructor(outputStream: NodeJS.WriteStream = process.stdout) {
method write (line 26) | write(str: string): void {
method writeOnNewLine (line 43) | writeOnNewLine(str: string): void {
method ensureTrailingNewline (line 54) | ensureTrailingNewline(): void {
FILE: packages/cli/src/ui/utils/textUtils.ts
function isAscii (line 36) | function isAscii(str: string): boolean {
constant MAX_STRING_LENGTH_TO_CACHE (line 46) | const MAX_STRING_LENGTH_TO_CACHE = 1000;
function toCodePoints (line 51) | function toCodePoints(str: string): string[] {
function cpLen (line 75) | function cpLen(str: string): number {
function cpIndexToOffset (line 85) | function cpIndexToOffset(str: string, cpIndex: number): number {
function cpSlice (line 89) | function cpSlice(str: string, start: number, end?: number): string {
function stripUnsafeCharacters (line 120) | function stripUnsafeCharacters(str: string): string {
function sanitizeForDisplay (line 141) | function sanitizeForDisplay(str: string, maxLength?: number): string {
function normalizeEscapedNewlines (line 158) | function normalizeEscapedNewlines(value: string): string {
function escapeAnsiCtrlCodes (line 215) | function escapeAnsiCtrlCodes<T>(obj: T): T {
FILE: packages/cli/src/ui/utils/toolLayoutUtils.test.ts
type CalculateToolContentMaxLinesTestCase (line 21) | interface CalculateToolContentMaxLinesTestCase {
type CalculateShellMaxLinesTestCase (line 86) | interface CalculateShellMaxLinesTestCase {
FILE: packages/cli/src/ui/utils/toolLayoutUtils.ts
constant TOOL_RESULT_STATIC_HEIGHT (line 18) | const TOOL_RESULT_STATIC_HEIGHT = 1;
constant TOOL_RESULT_ASB_RESERVED_LINE_COUNT (line 19) | const TOOL_RESULT_ASB_RESERVED_LINE_COUNT = 6;
constant TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT (line 20) | const TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT = 2;
constant TOOL_RESULT_MIN_LINES_SHOWN (line 21) | const TOOL_RESULT_MIN_LINES_SHOWN = 2;
constant SHELL_CONTENT_OVERHEAD (line 27) | const SHELL_CONTENT_OVERHEAD =
function calculateToolContentMaxLines (line 38) | function calculateToolContentMaxLines(options: {
function calculateShellMaxLines (line 75) | function calculateShellMaxLines(options: {
FILE: packages/cli/src/ui/utils/updateCheck.ts
constant FETCH_TIMEOUT_MS (line 17) | const FETCH_TIMEOUT_MS = 2000;
type UpdateInfo (line 20) | interface UpdateInfo {
type UpdateObject (line 27) | interface UpdateObject {
function getBestAvailableUpdate (line 36) | function getBestAvailableUpdate(
function checkForUpdates (line 50) | async function checkForUpdates(
FILE: packages/cli/src/ui/utils/urlSecurityUtils.ts
type DeceptiveUrlDetails (line 12) | interface DeceptiveUrlDetails {
function containsDeceptiveMarkers (line 25) | function containsDeceptiveMarkers(hostname: string): boolean {
function toUnicodeUrl (line 41) | function toUnicodeUrl(urlInput: string | URL): string {
function getDeceptiveUrlDetails (line 68) | function getDeceptiveUrlDetails(
FILE: packages/cli/src/utils/activityLogger.ts
constant ACTIVITY_ID_HEADER (line 22) | const ACTIVITY_ID_HEADER = 'x-activity-request-id';
constant MAX_BUFFER_SIZE (line 23) | const MAX_BUFFER_SIZE = 100;
function isHeaderRecord (line 25) | function isHeaderRecord(
function isRequestOptions (line 31) | function isRequestOptions(value: unknown): value is http.RequestOptions {
function isIncomingMessageCallback (line 40) | function isIncomingMessageCallback(
type HttpRequestArgs (line 46) | type HttpRequestArgs =
function callHttpRequest (line 54) | function callHttpRequest(
type NetworkLog (line 101) | interface NetworkLog {
type PartialNetworkLog (line 124) | type PartialNetworkLog = { id: string } & Partial<NetworkLog>;
class ActivityLogger (line 130) | class ActivityLogger extends EventEmitter {
method getInstance (line 144) | static getInstance(): ActivityLogger {
method enableNetworkLogging (line 151) | enableNetworkLogging() {
method disableNetworkLogging (line 156) | disableNetworkLogging() {
method isNetworkLoggingEnabled (line 160) | isNetworkLoggingEnabled(): boolean {
method drainBufferedLogs (line 168) | drainBufferedLogs(): {
method getBufferedLogs (line 184) | getBufferedLogs(): {
method clearBufferedLogs (line 199) | clearBufferedLogs(): void {
method stringifyHeaders (line 205) | private stringifyHeaders(headers: unknown): Record<string, string> {
method sanitizeNetworkLog (line 223) | private sanitizeNetworkLog(
method emitNetworkEvent (line 260) | emitNetworkEvent(p
Copy disabled (too large)
Download .json
Condensed preview — 2279 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (16,404K chars).
[
{
"path": ".allstar/branch_protection.yaml",
"chars": 14,
"preview": "action: 'log'\n"
},
{
"path": ".editorconfig",
"chars": 183,
"preview": "root = true\n\n[*]\ncharset = utf-8\ninsert_final_newline = true\nend_of_line = lf\nindent_style = space\nindent_size = 2\nmax_l"
},
{
"path": ".gcp/Dockerfile.gemini-code-builder",
"chars": 3917,
"preview": "# Use a common base image like Debian.\n# Using 'bookworm-slim' for a balance of size and compatibility.\nFROM debian:book"
},
{
"path": ".gcp/release-docker.yml",
"chars": 2517,
"preview": "steps:\n # Step 1: Install root dependencies (includes workspaces)\n - name: 'us-west1-docker.pkg.dev/gemini-code-dev/ge"
},
{
"path": ".gemini/config.yaml",
"chars": 335,
"preview": "# Config for the Gemini Pull Request Review Bot.\n# https://github.com/marketplace/gemini-code-assist\nhave_fun: false\ncod"
},
{
"path": ".gemini/settings.json",
"chars": 172,
"preview": "{\n \"experimental\": {\n \"plan\": true,\n \"extensionReloading\": true,\n \"modelSteering\": true,\n \"memoryManager\": "
},
{
"path": ".geminiignore",
"chars": 41,
"preview": "packages/core/src/services/scripts/*.exe\n"
},
{
"path": ".gitattributes",
"chars": 650,
"preview": "# Set the default behavior for all files to automatically handle line endings.\n# This will ensure that all text files ar"
},
{
"path": ".github/CODEOWNERS",
"chars": 1207,
"preview": "# By default, require reviews from the maintainers for all files.\n* @google-gemini/gemini-cli-maintainers\n\n# Require rev"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 1716,
"preview": "name: 'Bug Report'\ndescription: 'Report a bug to help us improve Gemini CLI'\nbody:\n - type: 'markdown'\n attributes:\n"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yml",
"chars": 1056,
"preview": "name: 'Feature Request'\ndescription: 'Suggest an idea for this project'\nlabels:\n - 'status/need-triage'\ntype: 'Feature'"
},
{
"path": ".github/ISSUE_TEMPLATE/website_issue.yml",
"chars": 1322,
"preview": "name: 'Website issue'\ndescription: 'Report an issue with the Gemini CLI Website and Gemini CLI Extensions Gallery'\ntitle"
},
{
"path": ".github/actions/calculate-vars/action.yml",
"chars": 899,
"preview": "name: 'Calculate vars'\ndescription: 'Calculate commonly used var in our release process'\n\ninputs:\n dry_run:\n descrip"
},
{
"path": ".github/actions/create-pull-request/action.yml",
"chars": 1856,
"preview": "name: 'Create Pull Request'\ndescription: 'Creates a pull request.'\n\ninputs:\n branch-name:\n description: 'The name of"
},
{
"path": ".github/actions/npm-auth-token/action.yml",
"chars": 1839,
"preview": "name: 'NPM Auth Token'\ndescription: 'Generates an NPM auth token for publishing a specific package'\n\ninputs:\n package-n"
},
{
"path": ".github/actions/post-coverage-comment/action.yml",
"chars": 5209,
"preview": "name: 'Post Coverage Comment Action'\ndescription: 'Prepares and posts a code coverage comment to a PR.'\n\ninputs:\n cli_j"
},
{
"path": ".github/actions/publish-release/action.yml",
"chars": 11768,
"preview": "name: 'Publish Release'\ndescription: 'Builds, prepares, and publishes the gemini-cli packages to npm and creates a GitHu"
},
{
"path": ".github/actions/push-docker/action.yml",
"chars": 2847,
"preview": "name: 'Push to docker'\ndescription: 'Builds packages and pushes a docker image to GHCR'\n\ninputs:\n github-actor:\n des"
},
{
"path": ".github/actions/push-sandbox/action.yml",
"chars": 4355,
"preview": "name: 'Build and push sandbox docker'\ndescription: 'Pushes sandbox docker image to container registry'\n\ninputs:\n github"
},
{
"path": ".github/actions/run-tests/action.yml",
"chars": 1099,
"preview": "name: 'Run Tests'\ndescription: 'Runs the preflight checks and integration tests.'\n\ninputs:\n gemini_api_key:\n descrip"
},
{
"path": ".github/actions/setup-npmrc/action.yml",
"chars": 731,
"preview": "name: 'Setup NPMRC'\ndescription: 'Sets up NPMRC with all the correct repos for readonly access.'\n\ninputs:\n github-token"
},
{
"path": ".github/actions/tag-npm-release/action.yml",
"chars": 5061,
"preview": "name: 'Tag an NPM release'\ndescription: 'Tags a specific npm version to a specific channel.'\n\ninputs:\n channel:\n des"
},
{
"path": ".github/actions/verify-release/action.yml",
"chars": 3482,
"preview": "name: 'Verify an NPM release'\ndescription: 'Fetches a package from NPM and does some basic smoke tests'\n\ninputs:\n npm-p"
},
{
"path": ".github/dependabot.yml",
"chars": 652,
"preview": "version: 2\nupdates:\n - package-ecosystem: 'npm'\n directory: '/'\n schedule:\n interval: 'weekly'\n day: 'm"
},
{
"path": ".github/pull_request_template.md",
"chars": 1054,
"preview": "## Summary\n\n<!-- Concisely describe what this PR changes and why. Focus on impact and\nurgency. -->\n\n## Details\n\n<!-- Add"
},
{
"path": ".github/scripts/backfill-need-triage.cjs",
"chars": 3792,
"preview": "/* eslint-disable */\n/* global require, console, process */\n\n/**\n * Script to backfill the 'status/need-triage' label to"
},
{
"path": ".github/scripts/backfill-pr-notification.cjs",
"chars": 5315,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/* eslint-disable */\n/* global "
},
{
"path": ".github/scripts/pr-triage.sh",
"chars": 6674,
"preview": "#!/usr/bin/env bash\n# @license\n# Copyright 2026 Google LLC\n# SPDX-License-Identifier: Apache-2.0\n\nset -euo pipefail\n\n# I"
},
{
"path": ".github/scripts/sync-maintainer-labels.cjs",
"chars": 11119,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nconst { Octokit } = require('@o"
},
{
"path": ".github/workflows/chained_e2e.yml",
"chars": 14330,
"preview": "name: 'Testing: E2E (Chained)'\n\non:\n push:\n branches:\n - 'main'\n merge_group:\n workflow_run:\n workflows: ["
},
{
"path": ".github/workflows/ci.yml",
"chars": 17635,
"preview": "name: 'Testing: CI'\n\non:\n push:\n branches:\n - 'main'\n - 'release/**'\n pull_request:\n branches:\n -"
},
{
"path": ".github/workflows/community-report.yml",
"chars": 7142,
"preview": "name: 'Generate Weekly Community Report 📊'\n\non:\n schedule:\n - cron: '0 12 * * 1' # Run at 12:00 UTC on Monday\n work"
},
{
"path": ".github/workflows/deflake.yml",
"chars": 6000,
"preview": "name: 'Deflake E2E'\n\non:\n workflow_dispatch:\n inputs:\n branch_ref:\n description: 'Branch to run on'\n "
},
{
"path": ".github/workflows/docs-page-action.yml",
"chars": 1662,
"preview": "name: 'Deploy GitHub Pages'\n\non:\n push:\n tags: 'v*'\n workflow_dispatch:\n\npermissions:\n contents: 'read'\n pages: '"
},
{
"path": ".github/workflows/docs-rebuild.yml",
"chars": 412,
"preview": "name: 'Trigger Docs Rebuild'\non:\n push:\n branches:\n - 'main'\n paths:\n - 'docs/**'\njobs:\n trigger-rebui"
},
{
"path": ".github/workflows/eval.yml",
"chars": 1853,
"preview": "name: 'Eval'\n\non:\n workflow_dispatch:\n\ndefaults:\n run:\n shell: 'bash'\n\npermissions:\n contents: 'read'\n id-token: "
},
{
"path": ".github/workflows/evals-nightly.yml",
"chars": 3180,
"preview": "name: 'Evals: Nightly'\n\non:\n schedule:\n - cron: '0 1 * * *' # Runs at 1 AM every day\n workflow_dispatch:\n inputs"
},
{
"path": ".github/workflows/gemini-automated-issue-dedup.yml",
"chars": 12146,
"preview": "name: '🏷️ Gemini Automated Issue Deduplication'\n\non:\n issues:\n types:\n - 'opened'\n - 'reopened'\n issue_co"
},
{
"path": ".github/workflows/gemini-automated-issue-triage.yml",
"chars": 16589,
"preview": "name: '🏷️ Gemini Automated Issue Triage'\n\non:\n issues:\n types:\n - 'opened'\n - 'reopened'\n issue_comment:\n"
},
{
"path": ".github/workflows/gemini-scheduled-issue-dedup.yml",
"chars": 4698,
"preview": "name: '📋 Gemini Scheduled Issue Deduplication'\n\non:\n schedule:\n - cron: '0 * * * *' # Runs every hour\n workflow_dis"
},
{
"path": ".github/workflows/gemini-scheduled-issue-triage.yml",
"chars": 15611,
"preview": "name: '📋 Gemini Scheduled Issue Triage'\n\non:\n issues:\n types:\n - 'opened'\n - 'reopened'\n schedule:\n - "
},
{
"path": ".github/workflows/gemini-scheduled-pr-triage.yml",
"chars": 1557,
"preview": "name: 'Gemini Scheduled PR Triage 🚀'\n\non:\n schedule:\n - cron: '*/15 * * * *' # Runs every 15 minutes\n workflow_disp"
},
{
"path": ".github/workflows/gemini-scheduled-stale-issue-closer.yml",
"chars": 6047,
"preview": "name: '🔒 Gemini Scheduled Stale Issue Closer'\n\non:\n schedule:\n - cron: '0 0 * * 0' # Every Sunday at midnight UTC\n "
},
{
"path": ".github/workflows/gemini-scheduled-stale-pr-closer.yml",
"chars": 12049,
"preview": "name: 'Gemini Scheduled Stale PR Closer'\n\non:\n schedule:\n - cron: '0 2 * * *' # Every day at 2 AM UTC\n pull_request"
},
{
"path": ".github/workflows/gemini-self-assign-issue.yml",
"chars": 6230,
"preview": "name: 'Assign Issue on Comment'\n\non:\n issue_comment:\n types:\n - 'created'\n\nconcurrency:\n group: '${{ github.wo"
},
{
"path": ".github/workflows/issue-opened-labeler.yml",
"chars": 1632,
"preview": "name: '🏷️ Issue Opened Labeler'\n\non:\n issues:\n types:\n - 'opened'\n\njobs:\n label-issue:\n runs-on: 'ubuntu-la"
},
{
"path": ".github/workflows/label-backlog-child-issues.yml",
"chars": 1570,
"preview": "name: 'Label Child Issues for Project Rollup'\n\non:\n issues:\n types: ['opened', 'edited', 'reopened']\n schedule:\n "
},
{
"path": ".github/workflows/label-workstream-rollup.yml",
"chars": 6549,
"preview": "name: 'Label Workstream Rollup'\n\non:\n issues:\n types: ['opened', 'edited', 'reopened']\n schedule:\n - cron: '0 * "
},
{
"path": ".github/workflows/links.yml",
"chars": 670,
"preview": "name: 'Links'\n\non:\n push:\n branches: ['main']\n pull_request:\n branches: ['main']\n repository_dispatch:\n workfl"
},
{
"path": ".github/workflows/no-response.yml",
"chars": 1247,
"preview": "name: 'No Response'\n\n# Run as a daily cron at 1:45 AM\non:\n schedule:\n - cron: '45 1 * * *'\n workflow_dispatch:\n\njob"
},
{
"path": ".github/workflows/pr-contribution-guidelines-notifier.yml",
"chars": 5546,
"preview": "name: '🏷️ PR Contribution Guidelines Notifier'\n\non:\n pull_request:\n types:\n - 'opened'\n\njobs:\n notify-process-"
},
{
"path": ".github/workflows/pr-rate-limiter.yaml",
"chars": 791,
"preview": "# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\n\nname: 'PR rate limiter'\n\npermissions:"
},
{
"path": ".github/workflows/release-change-tags.yml",
"chars": 2103,
"preview": "name: 'Release: Change Tags'\n\non:\n workflow_dispatch:\n inputs:\n version:\n description: 'The package vers"
},
{
"path": ".github/workflows/release-manual.yml",
"chars": 5126,
"preview": "name: 'Release: Manual'\n\non:\n workflow_dispatch:\n inputs:\n version:\n description: 'The version to releas"
},
{
"path": ".github/workflows/release-nightly.yml",
"chars": 6560,
"preview": "name: 'Release: Nightly'\n\non:\n schedule:\n - cron: '0 0 * * *'\n workflow_dispatch:\n inputs:\n dry_run:\n "
},
{
"path": ".github/workflows/release-notes.yml",
"chars": 3816,
"preview": "# This workflow is triggered on every new release.\n# It uses Gemini to generate release notes and creates a PR with the "
},
{
"path": ".github/workflows/release-patch-0-from-comment.yml",
"chars": 9226,
"preview": "name: 'Release: Patch (0) from Comment'\n\non:\n issue_comment:\n types: ['created']\n\njobs:\n slash-command:\n runs-on"
},
{
"path": ".github/workflows/release-patch-1-create-pr.yml",
"chars": 4812,
"preview": "name: 'Release: Patch (1) Create PR'\n\nrun-name: >-\n Release Patch (1) Create PR | S:${{ inputs.channel }} | C:${{ input"
},
{
"path": ".github/workflows/release-patch-2-trigger.yml",
"chars": 3468,
"preview": "name: 'Release: Patch (2) Trigger'\n\nrun-name: >-\n Release Patch (2) Trigger |\n ${{ github.event.pull_request.number &&"
},
{
"path": ".github/workflows/release-patch-3-release.yml",
"chars": 11777,
"preview": "name: 'Release: Patch (3) Release'\n\nrun-name: >-\n Release Patch (3) Release | T:${{ inputs.type }} | R:${{ inputs.relea"
},
{
"path": ".github/workflows/release-promote.yml",
"chars": 17866,
"preview": "name: 'Release: Promote'\n\non:\n workflow_dispatch:\n inputs:\n dry_run:\n description: 'Run a dry-run of the"
},
{
"path": ".github/workflows/release-rollback.yml",
"chars": 9834,
"preview": "name: 'Release: Rollback change'\n\non:\n workflow_dispatch:\n inputs:\n rollback_origin:\n description: 'The "
},
{
"path": ".github/workflows/release-sandbox.yml",
"chars": 1783,
"preview": "name: 'Release Sandbox'\n\non:\n workflow_dispatch:\n inputs:\n ref:\n description: 'The branch, tag, or SHA t"
},
{
"path": ".github/workflows/smoke-test.yml",
"chars": 1614,
"preview": "name: 'On Merge Smoke Test'\n\non:\n push:\n branches:\n - 'main'\n - 'release/**'\n workflow_dispatch:\n inpu"
},
{
"path": ".github/workflows/stale.yml",
"chars": 1867,
"preview": "name: 'Mark stale issues and pull requests'\n\n# Run as a daily cron at 1:30 AM\non:\n schedule:\n - cron: '30 1 * * *'\n "
},
{
"path": ".github/workflows/test-build-binary.yml",
"chars": 6095,
"preview": "name: 'Test Build Binary'\n\non:\n workflow_dispatch:\n\npermissions:\n contents: 'read'\n\ndefaults:\n run:\n shell: 'bash'"
},
{
"path": ".github/workflows/trigger_e2e.yml",
"chars": 1233,
"preview": "name: 'Trigger E2E'\n\non:\n workflow_dispatch:\n inputs:\n repo_name:\n description: 'Repository name (e.g., "
},
{
"path": ".github/workflows/unassign-inactive-assignees.yml",
"chars": 12600,
"preview": "name: 'Unassign Inactive Issue Assignees'\n\n# This workflow runs daily and scans every open \"help wanted\" issue that has\n"
},
{
"path": ".github/workflows/verify-release.yml",
"chars": 1715,
"preview": "name: 'Verify NPM release tag'\n\non:\n workflow_dispatch:\n inputs:\n version:\n description: 'The expected G"
},
{
"path": ".gitignore",
"chars": 1082,
"preview": "# API keys and secrets\n.env\n.env~\n\n# gemini-cli settings\n# We want to keep the .gemini in the root of the repo and ignor"
},
{
"path": ".husky/pre-commit",
"chars": 273,
"preview": "npm run pre-commit || {\n echo ''\n echo '===================================================='\n echo 'pre-commit check"
},
{
"path": ".lycheeignore",
"chars": 302,
"preview": "http://localhost:16686/\nhttps://github.com/google-gemini/gemini-cli/issues/new/choose\nhttps://github.com/google-gemini/m"
},
{
"path": ".npmrc",
"chars": 57,
"preview": "@google:registry=https://wombat-dressing-room.appspot.com"
},
{
"path": ".nvmrc",
"chars": 3,
"preview": "20\n"
},
{
"path": ".prettierignore",
"chars": 296,
"preview": "**/bundle\n**/coverage\n**/dist\n**/.git\n**/node_modules\n.docker\n.DS_Store\n.env\n.gemini/\n.idea\n.integration-tests/\n*.iml\n*."
},
{
"path": ".prettierrc.json",
"chars": 273,
"preview": "{\n \"semi\": true,\n \"trailingComma\": \"all\",\n \"singleQuote\": true,\n \"printWidth\": 80,\n \"tabWidth\": 2,\n \"overrides\": ["
},
{
"path": ".vscode/extensions.json",
"chars": 113,
"preview": "{\n \"recommendations\": [\n \"vitest.explorer\",\n \"esbenp.prettier-vscode\",\n \"dbaeumer.vscode-eslint\"\n ]\n}\n"
},
{
"path": ".vscode/launch.json",
"chars": 2995,
"preview": "{\n // Use IntelliSense to learn about possible attributes.\n // Hover to view descriptions of existing attributes.\n //"
},
{
"path": ".vscode/settings.json",
"chars": 632,
"preview": "{\n \"typescript.tsserver.experimental.enableProjectDiagnostics\": true,\n \"editor.tabSize\": 2,\n \"editor.rulers\": [80],\n "
},
{
"path": ".vscode/tasks.json",
"chars": 544,
"preview": "{\n \"version\": \"2.0.0\",\n \"tasks\": [\n {\n \"type\": \"npm\",\n \"script\": \"build\",\n \"group\": {\n \"kind\""
},
{
"path": ".yamllint.yml",
"chars": 1581,
"preview": "rules:\n anchors:\n forbid-duplicated-anchors: true\n forbid-undeclared-aliases: true\n forbid-unused-anchors: tru"
},
{
"path": "CONTRIBUTING.md",
"chars": 20099,
"preview": "# How to contribute\n\nWe would love to accept your patches and contributions to this project. This\ndocument includes:\n\n- "
},
{
"path": "Dockerfile",
"chars": 1580,
"preview": "FROM docker.io/library/node:20-slim\n\nARG SANDBOX_NAME=\"gemini-cli-sandbox\"\nARG CLI_VERSION_ARG\nENV SANDBOX=\"$SANDBOX_NAM"
},
{
"path": "GEMINI.md",
"chars": 4090,
"preview": "# Gemini CLI Project Context\n\nGemini CLI is an open-source AI agent that brings the power of Gemini directly\ninto the te"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "Makefile",
"chars": 1336,
"preview": "# Makefile for gemini-cli\n\n.PHONY: help install build build-sandbox build-all test lint format preflight clean start deb"
},
{
"path": "README.md",
"chars": 12127,
"preview": "# Gemini CLI\n\n[](https:/"
},
{
"path": "ROADMAP.md",
"chars": 5746,
"preview": "# Gemini CLI Roadmap\n\nThe\n[Official Gemini CLI Roadmap](https://github.com/orgs/google-gemini/projects/11/)\n\nGemini CLI "
},
{
"path": "SECURITY.md",
"chars": 423,
"preview": "# Reporting Security Issues\n\nTo report a security issue, please use [https://g.co/vulnz](https://g.co/vulnz).\nWe use g.c"
},
{
"path": "docs/admin/enterprise-controls.md",
"chars": 6443,
"preview": "# Enterprise Admin Controls\n\nGemini CLI empowers enterprise administrators to manage and enforce security\npolicies and c"
},
{
"path": "docs/changelogs/index.md",
"chars": 50839,
"preview": "# Gemini CLI release notes\n\nGemini CLI has three major release channels: nightly, preview, and stable. For\nmost users, w"
},
{
"path": "docs/changelogs/latest.md",
"chars": 29838,
"preview": "# Latest stable release: v0.34.0\n\nReleased: March 17, 2026\n\nFor most users, our latest stable release is the recommended"
},
{
"path": "docs/changelogs/preview.md",
"chars": 23451,
"preview": "# Preview release: v0.35.0-preview.2\n\nReleased: March 19, 2026\n\nOur preview release includes the latest, new, and experi"
},
{
"path": "docs/cli/checkpointing.md",
"chars": 3112,
"preview": "# Checkpointing\n\nThe Gemini CLI includes a Checkpointing feature that automatically saves a\nsnapshot of your project's s"
},
{
"path": "docs/cli/cli-reference.md",
"chars": 15946,
"preview": "# Gemini CLI cheatsheet\n\nThis page provides a reference for commonly used Gemini CLI commands, options,\nand parameters.\n"
},
{
"path": "docs/cli/creating-skills.md",
"chars": 2358,
"preview": "# Creating Agent Skills\n\nThis guide provides an overview of how to create your own Agent Skills to extend\nthe capabiliti"
},
{
"path": "docs/cli/custom-commands.md",
"chars": 12038,
"preview": "# Custom commands\n\nCustom commands let you save and reuse your favorite or most frequently used\nprompts as personal shor"
},
{
"path": "docs/cli/enterprise.md",
"chars": 19110,
"preview": "# Gemini CLI for the enterprise\n\nThis document outlines configuration patterns and best practices for deploying\nand mana"
},
{
"path": "docs/cli/gemini-ignore.md",
"chars": 2073,
"preview": "# Ignoring files\n\nThis document provides an overview of the Gemini Ignore (`.geminiignore`)\nfeature of the Gemini CLI.\n\n"
},
{
"path": "docs/cli/gemini-md.md",
"chars": 3946,
"preview": "# Provide context with GEMINI.md files\n\nContext files, which use the default name `GEMINI.md`, are a powerful feature\nfo"
},
{
"path": "docs/cli/generation-settings.md",
"chars": 6411,
"preview": "# Advanced Model Configuration\n\nThis guide details the Model Configuration system within the Gemini CLI.\nDesigned for re"
},
{
"path": "docs/cli/headless.md",
"chars": 1578,
"preview": "# Headless mode reference\n\nHeadless mode provides a programmatic interface to Gemini CLI, returning\nstructured text or J"
},
{
"path": "docs/cli/model-routing.md",
"chars": 2788,
"preview": "# Model routing\n\nGemini CLI includes a model routing feature that automatically switches to a\nfallback model in case of "
},
{
"path": "docs/cli/model-steering.md",
"chars": 2882,
"preview": "# Model steering (experimental)\n\nModel steering lets you provide real-time guidance and feedback to Gemini CLI\nwhile it "
},
{
"path": "docs/cli/model.md",
"chars": 2730,
"preview": "# Gemini CLI model selection (`/model` command)\n\nSelect your Gemini CLI model. The `/model` command lets you configure t"
},
{
"path": "docs/cli/notifications.md",
"chars": 1893,
"preview": "# Notifications (experimental)\n\nGemini CLI can send system notifications to alert you when a session completes\nor when i"
},
{
"path": "docs/cli/plan-mode.md",
"chars": 18287,
"preview": "# Plan Mode\n\nPlan Mode is a read-only environment for architecting robust solutions before\nimplementation. With Plan Mod"
},
{
"path": "docs/cli/rewind.md",
"chars": 2330,
"preview": "# Rewind\n\nThe `/rewind` command lets you go back to a previous state in your conversation\nand, optionally, revert any fi"
},
{
"path": "docs/cli/sandbox.md",
"chars": 8008,
"preview": "# Sandboxing in the Gemini CLI\n\nThis document provides a guide to sandboxing in the Gemini CLI, including\nprerequisites,"
},
{
"path": "docs/cli/session-management.md",
"chars": 6097,
"preview": "# Session management\n\nSession management saves your conversation history so you can resume your work\nwhere you left off."
},
{
"path": "docs/cli/settings.md",
"chars": 28921,
"preview": "# Gemini CLI settings (`/settings` command)\n\nControl your Gemini CLI experience with the `/settings` command. The `/sett"
},
{
"path": "docs/cli/skills.md",
"chars": 5840,
"preview": "# Agent Skills\n\nAgent Skills allow you to extend Gemini CLI with specialized expertise,\nprocedural workflows, and task-s"
},
{
"path": "docs/cli/system-prompt.md",
"chars": 4589,
"preview": "# System Prompt Override (GEMINI_SYSTEM_MD)\n\nThe core system instructions that guide Gemini CLI can be completely replac"
},
{
"path": "docs/cli/telemetry.md",
"chars": 28392,
"preview": "# Observability with OpenTelemetry\n\nObservability is the key to turning experimental AI into reliable software.\nGemini C"
},
{
"path": "docs/cli/themes.md",
"chars": 7960,
"preview": "# Themes\n\nGemini CLI supports a variety of themes to customize its color scheme and\nappearance. You can change the theme"
},
{
"path": "docs/cli/token-caching.md",
"chars": 754,
"preview": "# Token caching and cost optimization\n\nGemini CLI automatically optimizes API costs through token caching when using\nAPI"
},
{
"path": "docs/cli/trusted-folders.md",
"chars": 4996,
"preview": "# Trusted Folders\n\nThe Trusted Folders feature is a security setting that gives you control over\nwhich projects can use "
},
{
"path": "docs/cli/tutorials/automation.md",
"chars": 7141,
"preview": "# Automate tasks with headless mode\n\nAutomate tasks with Gemini CLI. Learn how to use headless mode, pipe data into\nGemi"
},
{
"path": "docs/cli/tutorials/file-management.md",
"chars": 4472,
"preview": "# File management with Gemini CLI\n\nExplore, analyze, and modify your codebase using Gemini CLI. In this guide,\nyou'll le"
},
{
"path": "docs/cli/tutorials/mcp-setup.md",
"chars": 3245,
"preview": "# Set up an MCP server\n\nConnect Gemini CLI to your external databases and services. In this guide,\nyou'll learn how to e"
},
{
"path": "docs/cli/tutorials/memory-management.md",
"chars": 4384,
"preview": "# Manage context and memory\n\nControl what Gemini CLI knows about you and your projects. In this guide, you'll\nlearn how "
},
{
"path": "docs/cli/tutorials/plan-mode-steering.md",
"chars": 3502,
"preview": "# Use Plan Mode with model steering for complex tasks\n\nArchitecting a complex solution requires precision. By combining "
},
{
"path": "docs/cli/tutorials/session-management.md",
"chars": 3309,
"preview": "# Manage sessions and history\n\nResume, browse, and rewind your conversations with Gemini CLI. In this guide,\nyou'll lear"
},
{
"path": "docs/cli/tutorials/shell-commands.md",
"chars": 3617,
"preview": "# Execute shell commands\n\nUse the CLI to run builds, manage git, and automate system tasks without leaving\nthe conversat"
},
{
"path": "docs/cli/tutorials/skills-getting-started.md",
"chars": 3253,
"preview": "# Get started with Agent Skills\n\nAgent Skills extend Gemini CLI with specialized expertise. In this guide, you'll\nlearn "
},
{
"path": "docs/cli/tutorials/task-planning.md",
"chars": 3025,
"preview": "# Plan tasks with todos\n\nKeep complex jobs on the rails with Gemini CLI's built-in task planning. In this\nguide, you'll "
},
{
"path": "docs/cli/tutorials/web-tools.md",
"chars": 2524,
"preview": "# Web search and fetch\n\nAccess the live internet directly from your prompt. In this guide, you'll learn\nhow to search fo"
},
{
"path": "docs/core/index.md",
"chars": 5024,
"preview": "# Gemini CLI core\n\nGemini CLI's core package (`packages/core`) is the backend portion of Gemini\nCLI, handling communicat"
},
{
"path": "docs/core/local-model-routing.md",
"chars": 6846,
"preview": "# Local Model Routing (experimental)\n\nGemini CLI supports using a local model for\n[routing decisions](../cli/model-routi"
},
{
"path": "docs/core/remote-agents.md",
"chars": 14771,
"preview": "# Remote Subagents (experimental)\n\nGemini CLI supports connecting to remote subagents using the Agent-to-Agent\n(A2A) pro"
},
{
"path": "docs/core/subagents.md",
"chars": 16017,
"preview": "# Subagents (experimental)\n\nSubagents are specialized agents that operate within your main Gemini CLI\nsession. They are "
},
{
"path": "docs/examples/proxy-script.md",
"chars": 2823,
"preview": "# Example proxy script\n\nThe following is an example of a proxy script that can be used with the\n`GEMINI_SANDBOX_PROXY_CO"
},
{
"path": "docs/extensions/best-practices.md",
"chars": 5732,
"preview": "# Gemini CLI extension best practices\n\nThis guide covers best practices for developing, securing, and maintaining\nGemini"
},
{
"path": "docs/extensions/index.md",
"chars": 1781,
"preview": "# Gemini CLI extensions\n\nGemini CLI extensions package prompts, MCP servers, custom commands, themes,\nhooks, sub-agents,"
},
{
"path": "docs/extensions/reference.md",
"chars": 11232,
"preview": "# Extension reference\n\nThis guide covers the `gemini extensions` commands and the structure of the\n`gemini-extension.jso"
},
{
"path": "docs/extensions/releasing.md",
"chars": 6443,
"preview": "# Release extensions\n\nRelease Gemini CLI extensions to your users through a Git repository or GitHub\nReleases.\n\nGit repo"
},
{
"path": "docs/extensions/writing-extensions.md",
"chars": 11829,
"preview": "# Build Gemini CLI extensions\n\nGemini CLI extensions let you expand the capabilities of Gemini CLI by adding\ncustom tool"
},
{
"path": "docs/get-started/authentication.md",
"chars": 14041,
"preview": "# Gemini CLI authentication setup\n\nTo use Gemini CLI, you'll need to authenticate with Google. This guide helps you\nquic"
},
{
"path": "docs/get-started/examples.md",
"chars": 4440,
"preview": "# Gemini CLI examples\n\nGemini CLI helps you automate common engineering tasks by combining AI reasoning\nwith local syste"
},
{
"path": "docs/get-started/gemini-3.md",
"chars": 4617,
"preview": "# Gemini 3 Pro and Gemini 3 Flash on Gemini CLI\n\nGemini 3 Pro and Gemini 3 Flash are available on Gemini CLI for all use"
},
{
"path": "docs/get-started/index.md",
"chars": 2502,
"preview": "# Get started with Gemini CLI\n\nWelcome to Gemini CLI! This guide will help you install, configure, and start\nusing the G"
},
{
"path": "docs/get-started/installation.md",
"chars": 4961,
"preview": "# Gemini CLI installation, execution, and releases\n\nThis document provides an overview of Gemini CLI's system requiremen"
},
{
"path": "docs/hooks/best-practices.md",
"chars": 17574,
"preview": "# Hooks Best Practices\n\nThis guide covers security considerations, performance optimization, debugging\ntechniques, and p"
},
{
"path": "docs/hooks/index.md",
"chars": 8234,
"preview": "# Gemini CLI hooks\n\nHooks are scripts or programs that Gemini CLI executes at specific points in the\nagentic loop, allow"
},
{
"path": "docs/hooks/reference.md",
"chars": 13270,
"preview": "# Hooks reference\n\nThis document provides the technical specification for Gemini CLI hooks,\nincluding JSON schemas and A"
},
{
"path": "docs/hooks/writing-hooks.md",
"chars": 11559,
"preview": "# Writing hooks for Gemini CLI\n\nThis guide will walk you through creating hooks for Gemini CLI, from a simple\nlogging ho"
},
{
"path": "docs/ide-integration/ide-companion-spec.md",
"chars": 10764,
"preview": "# Gemini CLI companion plugin: Interface specification\n\n> Last Updated: September 15, 2025\n\nThis document defines the co"
},
{
"path": "docs/ide-integration/index.md",
"chars": 8674,
"preview": "# IDE integration\n\nGemini CLI can integrate with your IDE to provide a more seamless and\ncontext-aware experience. This "
},
{
"path": "docs/index.md",
"chars": 5990,
"preview": "# Gemini CLI documentation\n\nGemini CLI brings the power of Gemini models directly into your terminal. Use it\nto understa"
},
{
"path": "docs/integration-tests.md",
"chars": 5860,
"preview": "# Integration tests\n\nThis document provides information about the integration testing framework used\nin this project.\n\n#"
},
{
"path": "docs/issue-and-pr-automation.md",
"chars": 8610,
"preview": "# Automation and triage processes\n\nThis document provides a detailed overview of the automated processes we use to\nmanag"
},
{
"path": "docs/local-development.md",
"chars": 4887,
"preview": "# Local development guide\n\nThis guide provides instructions for setting up and using local development\nfeatures for Gemi"
},
{
"path": "docs/mermaid/context.mmd",
"chars": 3106,
"preview": "graph LR\n %% --- Style Definitions ---\n classDef new fill:#98fb98,color:#000\n classDef changed fill:#add8e6,col"
},
{
"path": "docs/mermaid/render-path.mmd",
"chars": 1647,
"preview": "graph TD\n %% --- Style Definitions ---\n classDef new fill:#98fb98,color:#000\n classDef changed fill:#add8e6,col"
},
{
"path": "docs/npm.md",
"chars": 2548,
"preview": "# Package overview\n\nThis monorepo contains two main packages: `@google/gemini-cli` and\n`@google/gemini-cli-core`.\n\n## `@"
},
{
"path": "docs/redirects.json",
"chars": 922,
"preview": "{\n \"/docs/architecture\": \"/docs/cli/index\",\n \"/docs/cli/commands\": \"/docs/reference/commands\",\n \"/docs/cli\": \"/docs\","
},
{
"path": "docs/reference/commands.md",
"chars": 23720,
"preview": "# CLI commands\n\nGemini CLI supports several built-in commands to help you manage your session,\ncustomize the interface, "
},
{
"path": "docs/reference/configuration.md",
"chars": 82560,
"preview": "# Gemini CLI configuration\n\nGemini CLI offers several ways to configure its behavior, including environment\nvariables, c"
},
{
"path": "docs/reference/keyboard-shortcuts.md",
"chars": 17190,
"preview": "# Gemini CLI keyboard shortcuts\n\nGemini CLI ships with a set of default keyboard shortcuts for editing input,\nnavigating"
},
{
"path": "docs/reference/memport.md",
"chars": 6387,
"preview": "# Memory Import Processor\n\nThe Memory Import Processor is a feature that allows you to modularize your\nGEMINI.md files b"
},
{
"path": "docs/reference/policy-engine.md",
"chars": 16085,
"preview": "# Policy engine\n\nThe Gemini CLI includes a powerful policy engine that provides fine-grained\ncontrol over tool execution"
},
{
"path": "docs/reference/tools.md",
"chars": 9690,
"preview": "# Tools reference\n\nGemini CLI uses tools to interact with your local environment, access\ninformation, and perform action"
},
{
"path": "docs/release-confidence.md",
"chars": 5629,
"preview": "# Release confidence strategy\n\nThis document outlines the strategy for gaining confidence in every release of\nthe Gemini"
},
{
"path": "docs/releases.md",
"chars": 22942,
"preview": "# Gemini CLI releases\n\n## `dev` vs `prod` environment\n\nOur release flows support both `dev` and `prod` environments.\n\nTh"
},
{
"path": "docs/resources/faq.md",
"chars": 8089,
"preview": "# Frequently asked questions (FAQ)\n\nThis page provides answers to common questions and solutions to frequent\nproblems en"
},
{
"path": "docs/resources/quota-and-pricing.md",
"chars": 7904,
"preview": "# Gemini CLI: Quotas and pricing\n\nGemini CLI offers a generous free tier that covers many individual developers'\nuse cas"
},
{
"path": "docs/resources/tos-privacy.md",
"chars": 6670,
"preview": "# Gemini CLI: License, Terms of Service, and Privacy Notices\n\nGemini CLI is an open-source tool that lets you interact w"
},
{
"path": "docs/resources/troubleshooting.md",
"chars": 10435,
"preview": "# Troubleshooting guide\n\nThis guide provides solutions to common issues and debugging tips, including\ntopics on:\n\n- Auth"
},
{
"path": "docs/resources/uninstall.md",
"chars": 1519,
"preview": "# Uninstalling the CLI\n\nYour uninstall method depends on how you ran the CLI. Follow the instructions\nfor either npx or "
},
{
"path": "docs/sidebar.json",
"chars": 7973,
"preview": "[\n {\n \"label\": \"docs_tab\",\n \"items\": [\n {\n \"label\": \"Get started\",\n \"items\": [\n { \"la"
},
{
"path": "docs/tools/activate-skill.md",
"chars": 1518,
"preview": "# Activate skill tool (`activate_skill`)\n\nThe `activate_skill` tool lets Gemini CLI load specialized procedural expertis"
},
{
"path": "docs/tools/ask-user.md",
"chars": 2798,
"preview": "# Ask User Tool\n\nThe `ask_user` tool lets Gemini CLI ask you one or more questions to gather\npreferences, clarify requir"
},
{
"path": "docs/tools/file-system.md",
"chars": 5127,
"preview": "# File system tools reference\n\nThe Gemini CLI core provides a suite of tools for interacting with the local\nfile system."
},
{
"path": "docs/tools/internal-docs.md",
"chars": 1683,
"preview": "# Internal documentation tool (`get_internal_docs`)\n\nThe `get_internal_docs` tool lets Gemini CLI access its own technic"
},
{
"path": "docs/tools/mcp-server.md",
"chars": 39146,
"preview": "# MCP servers with the Gemini CLI\n\nThis document provides a guide to configuring and using Model Context Protocol\n(MCP) "
},
{
"path": "docs/tools/memory.md",
"chars": 1172,
"preview": "# Memory tool (`save_memory`)\n\nThe `save_memory` tool allows the Gemini agent to persist specific facts, user\npreference"
},
{
"path": "docs/tools/planning.md",
"chars": 2491,
"preview": "# Gemini CLI planning tools\n\nPlanning tools let Gemini CLI switch into a safe, read-only \"Plan Mode\" for\nresearching and"
},
{
"path": "docs/tools/shell.md",
"chars": 7250,
"preview": "# Shell tool (`run_shell_command`)\n\nThe `run_shell_command` tool allows the Gemini model to execute commands\ndirectly on"
},
{
"path": "docs/tools/todos.md",
"chars": 1246,
"preview": "# Todo tool (`write_todos`)\n\nThe `write_todos` tool allows the Gemini agent to maintain an internal list of\nsubtasks for"
},
{
"path": "docs/tools/web-fetch.md",
"chars": 1194,
"preview": "# Web fetch tool (`web_fetch`)\n\nThe `web_fetch` tool allows the Gemini agent to retrieve and process content\nfrom specif"
},
{
"path": "docs/tools/web-search.md",
"chars": 1149,
"preview": "# Web search tool (`google_web_search`)\n\nThe `google_web_search` tool allows the Gemini agent to retrieve up-to-date\ninf"
},
{
"path": "esbuild.config.js",
"chars": 4150,
"preview": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport path from 'node:path';\ni"
},
{
"path": "eslint.config.js",
"chars": 12685,
"preview": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport eslint from '@eslint/js'"
},
{
"path": "evals/README.md",
"chars": 12116,
"preview": "# Behavioral Evals\n\nBehavioral evaluations (evals) are tests designed to validate the agent's\nbehavior in response to sp"
},
{
"path": "evals/answer-vs-act.eval.ts",
"chars": 4657,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } fro"
},
{
"path": "evals/app-test-helper.ts",
"chars": 2378,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { AppRig } from '../pack"
},
{
"path": "evals/ask_user.eval.ts",
"chars": 4448,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } fro"
},
{
"path": "evals/automated-tool-use.eval.ts",
"chars": 4567,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } fro"
},
{
"path": "evals/concurrency-safety.eval.ts",
"chars": 1638,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { expect } from 'vitest'"
},
{
"path": "evals/edit-locations-eval.eval.ts",
"chars": 2777,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } fro"
},
{
"path": "evals/frugalReads.eval.ts",
"chars": 9025,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } fro"
},
{
"path": "evals/frugalSearch.eval.ts",
"chars": 3141,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } fro"
},
{
"path": "evals/generalist_agent.eval.ts",
"chars": 1242,
"preview": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } fro"
},
{
"path": "evals/generalist_delegation.eval.ts",
"chars": 4639,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } fro"
},
{
"path": "evals/gitRepo.eval.ts",
"chars": 2474,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } fro"
},
{
"path": "evals/grep_search_functionality.eval.ts",
"chars": 4887,
"preview": "/**\n * @license\n * Copyright 202 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } from"
},
{
"path": "evals/hierarchical_memory.eval.ts",
"chars": 3228,
"preview": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } fro"
},
{
"path": "evals/interactive-hang.eval.ts",
"chars": 2262,
"preview": "import { describe, expect } from 'vitest';\nimport { evalTest } from './test-helper.js';\n\ndescribe('interactive_commands'"
},
{
"path": "evals/model_steering.eval.ts",
"chars": 3016,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } fro"
},
{
"path": "evals/plan_mode.eval.ts",
"chars": 7456,
"preview": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect } fro"
}
]
// ... and 2079 more files (download for full content)
About this extraction
This page contains the full source code of the google-gemini/gemini-cli GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 2279 files (18.6 MB), approximately 4.1M tokens, and a symbol index with 5409 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.