Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 29a634446b | |||
| 8573650253 | |||
| 220888ac2d | |||
| b2f775921d | |||
| f7b2632939 | |||
| 8379099e85 | |||
| 3061555d28 | |||
| 22fb83320e | |||
| 63e4bb985b | |||
| fe890429a4 | |||
| 655165cde4 | |||
| 17557b1aeb | |||
| 9600da2c8f | |||
| 2b6dab6136 | |||
| ac9025e9fc | |||
| fafe3e35d2 | |||
| f16f1cced3 | |||
| 963631a3d4 | |||
| 6d7974f1ef | |||
| 34a9d6e421 | |||
| 00b7781c3c | |||
| e827cfdf83 | |||
| cb35ee6710 | |||
| cb289e0724 | |||
| c5ad0abb5d | |||
| e664cc20fe | |||
| 485f3d92d8 | |||
| 5333e5ab20 | |||
| 166845d933 | |||
| 55620235c0 | |||
| 366f9e4766 | |||
| 06e7621b26 | |||
| 8d05bdbe49 | |||
| 5b1f7375a3 | |||
| d613dd05db | |||
| a6d43cba2d | |||
| 161ba28966 | |||
| 05aa1465fe | |||
| 8f6edc50c1 | |||
| 88ddcab616 |
@@ -2,8 +2,7 @@
|
||||
"experimental": {
|
||||
"extensionReloading": true,
|
||||
"modelSteering": true,
|
||||
"memoryManager": true,
|
||||
"topicUpdateNarration": true
|
||||
"memoryManager": true
|
||||
},
|
||||
"general": {
|
||||
"devtools": true
|
||||
|
||||
@@ -85,17 +85,25 @@ accessible.
|
||||
|
||||
- **Callouts**: Use GitHub-flavored markdown alerts to highlight important
|
||||
information. To ensure the formatting is preserved by `npm run format`, place
|
||||
an empty line, then the `<!-- prettier-ignore -->` comment directly before
|
||||
the callout block. The callout type (`[!TYPE]`) should be on the first line,
|
||||
followed by a newline, and then the content, with each subsequent line of
|
||||
content starting with `>`. Available types are `NOTE`, `TIP`, `IMPORTANT`,
|
||||
`WARNING`, and `CAUTION`.
|
||||
an empty line, then a prettier ignore comment directly before the callout
|
||||
block. Use `<!-- prettier-ignore -->` for standard Markdown files (`.md`) and
|
||||
`{/* prettier-ignore */}` for MDX files (`.mdx`). The callout type (`[!TYPE]`)
|
||||
should be on the first line, followed by a newline, and then the content, with
|
||||
each subsequent line of content starting with `>`. Available types are `NOTE`,
|
||||
`TIP`, `IMPORTANT`, `WARNING`, and `CAUTION`.
|
||||
|
||||
Example:
|
||||
Example (.md):
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!NOTE]
|
||||
> This is an example of a multi-line note that will be preserved
|
||||
> by Prettier.
|
||||
|
||||
Example (.mdx):
|
||||
|
||||
{/* prettier-ignore */}
|
||||
> [!NOTE]
|
||||
> This is an example of a multi-line note that will be preserved
|
||||
> by Prettier.
|
||||
|
||||
### Links
|
||||
@@ -118,6 +126,7 @@ accessible.
|
||||
<!-- prettier-ignore -->
|
||||
> [!NOTE]
|
||||
> This is an experimental feature currently under active development.
|
||||
(Note: Use `{/* prettier-ignore */}` if editing an `.mdx` file.)
|
||||
|
||||
- **Headings:** Use hierarchical headings to support the user journey.
|
||||
- **Procedures:**
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
||||
|
||||
name: 'Agent Session Drift Check'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'release/**'
|
||||
paths:
|
||||
- 'packages/cli/src/nonInteractiveCli.ts'
|
||||
- 'packages/cli/src/nonInteractiveCliAgentSession.ts'
|
||||
|
||||
concurrency:
|
||||
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
check-drift:
|
||||
name: 'Check Agent Session Drift'
|
||||
runs-on: 'ubuntu-latest'
|
||||
if: "github.repository == 'google-gemini/gemini-cli'"
|
||||
permissions:
|
||||
contents: 'read'
|
||||
pull-requests: 'write'
|
||||
steps:
|
||||
- name: 'Detect drift and comment'
|
||||
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea' # ratchet:actions/github-script@v8
|
||||
with:
|
||||
script: |-
|
||||
// === Pair configuration — append here to cover more pairs ===
|
||||
const PAIRS = [
|
||||
{
|
||||
legacy: 'packages/cli/src/nonInteractiveCli.ts',
|
||||
session: 'packages/cli/src/nonInteractiveCliAgentSession.ts',
|
||||
label: 'non-interactive CLI',
|
||||
},
|
||||
// Future pairs can be added here. Remember to also add both
|
||||
// paths to the `paths:` filter at the top of this workflow.
|
||||
// Example:
|
||||
// {
|
||||
// legacy: 'packages/core/src/agents/local-invocation.ts',
|
||||
// session: 'packages/core/src/agents/local-session-invocation.ts',
|
||||
// label: 'local subagent invocation',
|
||||
// },
|
||||
];
|
||||
// ============================================================
|
||||
|
||||
const prNumber = context.payload.pull_request.number;
|
||||
const { owner, repo } = context.repo;
|
||||
|
||||
// Use the API to list changed files — no checkout/git diff needed.
|
||||
const files = await github.paginate(github.rest.pulls.listFiles, {
|
||||
owner,
|
||||
repo,
|
||||
pull_number: prNumber,
|
||||
per_page: 100,
|
||||
});
|
||||
const changed = new Set(files.map((f) => f.filename));
|
||||
|
||||
const warnings = [];
|
||||
for (const { legacy, session, label } of PAIRS) {
|
||||
const legacyChanged = changed.has(legacy);
|
||||
const sessionChanged = changed.has(session);
|
||||
if (legacyChanged && !sessionChanged) {
|
||||
warnings.push(
|
||||
`**${label}**: \`${legacy}\` was modified but \`${session}\` was not.`,
|
||||
);
|
||||
} else if (!legacyChanged && sessionChanged) {
|
||||
warnings.push(
|
||||
`**${label}**: \`${session}\` was modified but \`${legacy}\` was not.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const MARKER = '<!-- agent-session-drift-check -->';
|
||||
|
||||
// Look up our existing drift comment (for upsert/cleanup).
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner,
|
||||
repo,
|
||||
issue_number: prNumber,
|
||||
per_page: 100,
|
||||
});
|
||||
const existing = comments.find(
|
||||
(c) => c.user?.type === 'Bot' && c.body?.includes(MARKER),
|
||||
);
|
||||
|
||||
if (warnings.length === 0) {
|
||||
core.info('No drift detected.');
|
||||
// If drift was previously flagged and is now resolved, remove the comment.
|
||||
if (existing) {
|
||||
await github.rest.issues.deleteComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: existing.id,
|
||||
});
|
||||
core.info(`Deleted stale drift comment ${existing.id}.`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const body = [
|
||||
MARKER,
|
||||
'### ⚠️ Invocation Drift Warning',
|
||||
'',
|
||||
'The following file pairs should generally be kept in sync during the AgentSession migration:',
|
||||
'',
|
||||
...warnings.map((w) => `- ${w}`),
|
||||
'',
|
||||
'If this is intentional (e.g., a bug fix specific to one implementation), you can ignore this comment.',
|
||||
'',
|
||||
'_This check will be removed once the legacy implementations are deleted._',
|
||||
].join('\n');
|
||||
|
||||
if (existing) {
|
||||
core.info(`Updating existing drift comment ${existing.id}.`);
|
||||
await github.rest.issues.updateComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: existing.id,
|
||||
body,
|
||||
});
|
||||
} else {
|
||||
core.info('Creating new drift comment.');
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: prNumber,
|
||||
body,
|
||||
});
|
||||
}
|
||||
@@ -183,7 +183,7 @@ jobs:
|
||||
needs:
|
||||
- 'merge_queue_skipper'
|
||||
- 'parse_run_context'
|
||||
runs-on: 'macos-latest'
|
||||
runs-on: 'macos-latest-large'
|
||||
if: |
|
||||
github.repository == 'google-gemini/gemini-cli' && always() && (needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip != 'true')
|
||||
steps:
|
||||
|
||||
@@ -102,6 +102,12 @@ jobs:
|
||||
- name: 'Run yamllint'
|
||||
run: 'node scripts/lint.js --yamllint'
|
||||
|
||||
- name: 'Build project for typecheck'
|
||||
run: 'npm run build'
|
||||
|
||||
- name: 'Run typecheck'
|
||||
run: 'npm run typecheck'
|
||||
|
||||
- name: 'Run Prettier'
|
||||
run: 'node scripts/lint.js --prettier'
|
||||
|
||||
@@ -224,7 +230,7 @@ jobs:
|
||||
|
||||
test_mac:
|
||||
name: 'Test (Mac) - ${{ matrix.node-version }}, ${{ matrix.shard }}'
|
||||
runs-on: 'macos-latest'
|
||||
runs-on: 'macos-latest-large'
|
||||
needs:
|
||||
- 'merge_queue_skipper'
|
||||
if: "github.repository == 'google-gemini/gemini-cli' && needs.merge_queue_skipper.outputs.skip == 'false'"
|
||||
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
|
||||
deflake_e2e_mac:
|
||||
name: 'E2E Test (macOS)'
|
||||
runs-on: 'macos-latest'
|
||||
runs-on: 'macos-latest-large'
|
||||
if: "github.repository == 'google-gemini/gemini-cli'"
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
|
||||
@@ -22,3 +22,4 @@ Thumbs.db
|
||||
.pytest_cache
|
||||
**/SKILL.md
|
||||
packages/sdk/test-data/*.json
|
||||
*.mdx
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# How to contribute
|
||||
|
||||
We would love to accept your patches and contributions to this project. This
|
||||
document includes:
|
||||
Contributions and patches to this project are welcome. This document includes:
|
||||
|
||||
- **[Before you begin](#before-you-begin):** Essential steps to take before
|
||||
becoming a Gemini CLI contributor.
|
||||
@@ -12,7 +11,7 @@ document includes:
|
||||
- **[Documentation contribution process](#documentation-contribution-process):**
|
||||
How to contribute documentation to Gemini CLI.
|
||||
|
||||
We're looking forward to seeing your contributions!
|
||||
Your contributions are appreciated!
|
||||
|
||||
## Before you begin
|
||||
|
||||
@@ -42,13 +41,13 @@ This project follows
|
||||
The process for contributing code is as follows:
|
||||
|
||||
1. **Find an issue** that you want to work on. If an issue is tagged as
|
||||
`🔒Maintainers only`, this means it is reserved for project maintainers. We
|
||||
will not accept pull requests related to these issues. In the near future,
|
||||
we will explicitly mark issues looking for contributions using the
|
||||
`🔒Maintainers only`, this means it is reserved for project maintainers.
|
||||
Pull requests related to these issues are not accepted. In the near future,
|
||||
issues looking for contributions will be explicitly marked using the
|
||||
`help-wanted` label. If you believe an issue is a good candidate for
|
||||
community contribution, please leave a comment on the issue. A maintainer
|
||||
will review it and apply the `help-wanted` label if appropriate. Only
|
||||
maintainers should attempt to add the `help-wanted` label to an issue.
|
||||
community contribution, leave a comment on the issue. A maintainer will
|
||||
review it and apply the `help-wanted` label if appropriate. Only maintainers
|
||||
add the `help-wanted` label to an issue.
|
||||
2. **Fork the repository** and create a new branch.
|
||||
3. **Make your changes** in the `packages/` directory.
|
||||
4. **Ensure all checks pass** by running `npm run preflight`.
|
||||
@@ -56,22 +55,21 @@ The process for contributing code is as follows:
|
||||
|
||||
### Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use [GitHub pull requests](https://docs.github.com/articles/about-pull-requests)
|
||||
for this purpose.
|
||||
All submissions, including submissions by project members, require review.
|
||||
Gemini CLI uses
|
||||
[GitHub pull requests](https://docs.github.com/articles/about-pull-requests) for
|
||||
this purpose.
|
||||
|
||||
To assist with the review process, we provide an automated review tool that
|
||||
helps detect common anti-patterns, testing issues, and other best practices that
|
||||
are easy to miss.
|
||||
To assist with the review process, an automated review tool helps detect common
|
||||
anti-patterns, testing issues, and other best practices that are easy to miss.
|
||||
|
||||
#### Using the automated review tool
|
||||
|
||||
You can run the review tool in two ways:
|
||||
|
||||
1. **Using the helper script (Recommended):** We provide a script that
|
||||
automatically handles checking out the PR into a separate worktree,
|
||||
installing dependencies, building the project, and launching the review
|
||||
tool.
|
||||
1. **Using the helper script (Recommended):** A script automatically handles
|
||||
checking out the PR into a separate worktree, installing dependencies,
|
||||
building the project, and launching the review tool.
|
||||
|
||||
```bash
|
||||
./scripts/review.sh <PR_NUMBER> [model]
|
||||
@@ -97,7 +95,7 @@ You can run the review tool in two ways:
|
||||
/review-frontend <PR_NUMBER>
|
||||
```
|
||||
|
||||
Replace `<PR_NUMBER>` with your pull request number. Reviewers should use this
|
||||
Replace `<PR_NUMBER>` with your pull request number. Reviewers must use this
|
||||
tool to augment, not replace, their manual review process.
|
||||
|
||||
### Self-assigning and unassigning issues
|
||||
@@ -105,39 +103,39 @@ tool to augment, not replace, their manual review process.
|
||||
To assign an issue to yourself, simply add a comment with the text `/assign`. To
|
||||
unassign yourself from an issue, add a comment with the text `/unassign`.
|
||||
|
||||
The comment must contain only that text and nothing else. These commands will
|
||||
assign or unassign the issue as requested, provided the conditions are met
|
||||
(e.g., an issue must be unassigned to be assigned).
|
||||
The comment must contain only that text and nothing else. These commands assign
|
||||
or unassign the issue as requested, provided the conditions are met (for
|
||||
example, an issue must be unassigned to be assigned).
|
||||
|
||||
Please note that you can have a maximum of 3 issues assigned to you at any given
|
||||
time and that only
|
||||
Note that you can have a maximum of 3 issues assigned to you at any given time
|
||||
and that only
|
||||
[issues labeled "help wanted"](https://github.com/google-gemini/gemini-cli/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22help%20wanted%22)
|
||||
may be self-assigned.
|
||||
|
||||
### Pull request guidelines
|
||||
|
||||
To help us review and merge your PRs quickly, please follow these guidelines.
|
||||
PRs that do not meet these standards may be closed.
|
||||
To ensure quick review and merging of your PRs, follow these guidelines. PRs
|
||||
that do not meet these standards may be closed.
|
||||
|
||||
#### 1. Link to an existing issue
|
||||
|
||||
All PRs should be linked to an existing issue in our tracker. This ensures that
|
||||
All PRs must be linked to an existing issue in our tracker. This ensures that
|
||||
every change has been discussed and is aligned with the project's goals before
|
||||
any code is written.
|
||||
|
||||
- **For bug fixes:** The PR should be linked to the bug report issue.
|
||||
- **For features:** The PR should be linked to the feature request or proposal
|
||||
- **For bug fixes:** The PR must be linked to the bug report issue.
|
||||
- **For features:** The PR must be linked to the feature request or proposal
|
||||
issue that has been approved by a maintainer.
|
||||
|
||||
If an issue for your change doesn't exist, we will automatically close your PR
|
||||
along with a comment reminding you to associate the PR with an issue. The ideal
|
||||
workflow starts with an issue that has been reviewed and approved by a
|
||||
maintainer. Please **open the issue first** and wait for feedback before you
|
||||
start coding.
|
||||
If an issue for your change doesn't exist, Gemini CLI automatically closes your
|
||||
PR along with a comment reminding you to associate the PR with an issue. The
|
||||
ideal workflow starts with an issue that has been reviewed and approved by a
|
||||
maintainer. **Open the issue first** and wait for feedback before you start
|
||||
coding.
|
||||
|
||||
#### 2. Keep it small and focused
|
||||
|
||||
We favor small, atomic PRs that address a single issue or add a single,
|
||||
Gemini CLI favors small, atomic PRs that address a single issue or add a single,
|
||||
self-contained feature.
|
||||
|
||||
- **Do:** Create a PR that fixes one specific bug or adds one specific feature.
|
||||
@@ -149,9 +147,9 @@ can be reviewed and merged independently.
|
||||
|
||||
#### 3. Use draft PRs for work in progress
|
||||
|
||||
If you'd like to get early feedback on your work, please use GitHub's **Draft
|
||||
Pull Request** feature. This signals to the maintainers that the PR is not yet
|
||||
ready for a formal review but is open for discussion and initial feedback.
|
||||
To get early feedback on your work, use GitHub's **Draft Pull Request** feature.
|
||||
This signals to the maintainers that the PR is not yet ready for a formal review
|
||||
but is open for discussion and initial feedback.
|
||||
|
||||
#### 4. Ensure all checks pass
|
||||
|
||||
@@ -170,7 +168,7 @@ See more about writing documentation:
|
||||
|
||||
#### 6. Write clear commit messages and a good PR description
|
||||
|
||||
Your PR should have a clear, descriptive title and a detailed description of the
|
||||
Your PR must have a clear, descriptive title and a detailed description of the
|
||||
changes. Follow the [Conventional Commits](https://www.conventionalcommits.org/)
|
||||
standard for your commit messages.
|
||||
|
||||
@@ -178,21 +176,19 @@ standard for your commit messages.
|
||||
- **Bad PR title:** `Made some changes`
|
||||
|
||||
In the PR description, explain the "why" behind your changes and link to the
|
||||
relevant issue (e.g., `Fixes #123`).
|
||||
relevant issue (for example, `Fixes #123`).
|
||||
|
||||
### Forking
|
||||
|
||||
If you are forking the repository you will be able to run the Build, Test and
|
||||
Integration test workflows. However in order to make the integration tests run
|
||||
you'll need to add a
|
||||
If you fork the repository, you can run the Build, Test and Integration test
|
||||
workflows. To run the integration tests, add a
|
||||
[GitHub Repository Secret](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository)
|
||||
with a value of `GEMINI_API_KEY` and set that to a valid API key that you have
|
||||
available. Your key and secret are private to your repo; no one without access
|
||||
can see your key and you cannot see any secrets related to this repo.
|
||||
with a value of `GEMINI_API_KEY` and set that to a valid API key. Your key and
|
||||
secret are private to your repo; no one without access can see your key and you
|
||||
cannot see any secrets related to this repo.
|
||||
|
||||
Additionally you will need to click on the `Actions` tab and enable workflows
|
||||
for your repository, you'll find it's the large blue button in the center of the
|
||||
screen.
|
||||
Additionally, click on the `Actions` tab and enable workflows for your
|
||||
repository. It is the large blue button in the center of the screen.
|
||||
|
||||
### Development setup and workflow
|
||||
|
||||
@@ -204,9 +200,9 @@ development setup of this project.
|
||||
**Prerequisites:**
|
||||
|
||||
1. **Node.js**:
|
||||
- **Development:** Please use Node.js `~20.19.0`. This specific version is
|
||||
required due to an upstream development dependency issue. You can use a
|
||||
tool like [nvm](https://github.com/nvm-sh/nvm) to manage Node.js versions.
|
||||
- **Development:** Use Node.js `~20.19.0`. This specific version is required
|
||||
due to an upstream development dependency issue. Use a tool like
|
||||
[nvm](https://github.com/nvm-sh/nvm) to manage Node.js versions.
|
||||
- **Production:** For running the CLI in a production environment, any
|
||||
version of Node.js `>=20` is acceptable.
|
||||
2. **Git**
|
||||
@@ -261,10 +257,10 @@ command from the root directory:
|
||||
npm start
|
||||
```
|
||||
|
||||
If you'd like to run the source build outside of the gemini-cli folder, you can
|
||||
utilize `npm link path/to/gemini-cli/packages/cli` (see:
|
||||
To run the source build outside of the gemini-cli folder, use
|
||||
`npm link path/to/gemini-cli/packages/cli` (see:
|
||||
[docs](https://docs.npmjs.com/cli/v9/commands/npm-link)) or
|
||||
`alias gemini="node path/to/gemini-cli/packages/cli"` to run with `gemini`
|
||||
`alias gemini="node path/to/gemini-cli/packages/cli"` to run with `gemini`.
|
||||
|
||||
### Running tests
|
||||
|
||||
@@ -284,8 +280,8 @@ comprehensive check, it is recommended to run `npm run preflight`.
|
||||
|
||||
#### Integration tests
|
||||
|
||||
The integration tests are designed to validate the end-to-end functionality of
|
||||
the Gemini CLI. They are not run as part of the default `npm run test` command.
|
||||
The integration tests validate the end-to-end functionality of the Gemini CLI.
|
||||
They are not run as part of the default `npm run test` command.
|
||||
|
||||
To run the integration tests, use the following command:
|
||||
|
||||
@@ -293,8 +289,7 @@ To run the integration tests, use the following command:
|
||||
npm run test:e2e
|
||||
```
|
||||
|
||||
For more detailed information on the integration testing framework, please see
|
||||
the
|
||||
For more detailed information on the integration testing framework, see the
|
||||
[Integration Tests documentation](https://geminicli.com/docs/integration-tests).
|
||||
|
||||
### Linting and preflight checks
|
||||
@@ -305,8 +300,8 @@ To ensure code quality and formatting consistency, run the preflight check:
|
||||
npm run preflight
|
||||
```
|
||||
|
||||
This command will run ESLint, Prettier, all tests, and other checks as defined
|
||||
in the project's `package.json`.
|
||||
This command runs ESLint, Prettier, all tests, and other checks as defined in
|
||||
the project's `package.json`.
|
||||
|
||||
_ProTip_
|
||||
|
||||
@@ -346,8 +341,8 @@ npm run lint
|
||||
|
||||
### Coding conventions
|
||||
|
||||
- Please adhere to the coding style, patterns, and conventions used throughout
|
||||
the existing codebase.
|
||||
- Adhere to the coding style, patterns, and conventions used throughout the
|
||||
existing codebase.
|
||||
- Consult
|
||||
[GEMINI.md](https://github.com/google-gemini/gemini-cli/blob/main/GEMINI.md)
|
||||
(typically found in the project root) for specific instructions related to
|
||||
@@ -470,8 +465,8 @@ sandbox.
|
||||
|
||||
### Manual publish
|
||||
|
||||
We publish an artifact for each commit to our internal registry. But if you need
|
||||
to manually cut a local build, then run the following commands:
|
||||
Gemini CLI publishes an artifact for each commit to an internal registry. To
|
||||
manually cut a local build, use these commands:
|
||||
|
||||
```
|
||||
npm run clean
|
||||
@@ -483,8 +478,8 @@ npm publish --workspaces
|
||||
|
||||
## Documentation contribution process
|
||||
|
||||
Our documentation must be kept up-to-date with our code contributions. We want
|
||||
our documentation to be clear, concise, and helpful to our users. We value:
|
||||
Gemini CLI documentation must be kept up-to-date with code contributions.
|
||||
Documentation should be clear, concise, and helpful to users. Gemini CLI values:
|
||||
|
||||
- **Clarity:** Use simple and direct language. Avoid jargon where possible.
|
||||
- **Accuracy:** Ensure all information is correct and up-to-date.
|
||||
@@ -494,13 +489,12 @@ our documentation to be clear, concise, and helpful to our users. We value:
|
||||
|
||||
### Getting started
|
||||
|
||||
The process for contributing to the documentation is similar to contributing
|
||||
code.
|
||||
Documentation contributions follow a process similar to code contributions.
|
||||
|
||||
1. **Fork the repository** and create a new branch.
|
||||
2. **Make your changes** in the `/docs` directory.
|
||||
3. **Preview your changes locally** in Markdown rendering.
|
||||
4. **Lint and format your changes.** Our preflight check includes linting and
|
||||
4. **Lint and format your changes.** The preflight check includes linting and
|
||||
formatting for documentation files.
|
||||
```bash
|
||||
npm run preflight
|
||||
@@ -519,9 +513,9 @@ as the table of contents. When adding new documentation:
|
||||
|
||||
### Style guide
|
||||
|
||||
We follow the
|
||||
Gemini CLI follows the
|
||||
[Google Developer Documentation Style Guide](https://developers.google.com/style).
|
||||
Please refer to it for guidance on writing style, tone, and formatting.
|
||||
Refer to it for guidance on writing style, tone, and formatting.
|
||||
|
||||
#### Key style points
|
||||
|
||||
@@ -534,8 +528,8 @@ Please refer to it for guidance on writing style, tone, and formatting.
|
||||
|
||||
### Linting and formatting
|
||||
|
||||
We use `prettier` to enforce a consistent style across our documentation. The
|
||||
`npm run preflight` command will check for any linting issues.
|
||||
Gemini CLI uses `prettier` to enforce a consistent style across our
|
||||
documentation. The `npm run preflight` command checks for any linting issues.
|
||||
|
||||
You can also run the linter and formatter separately:
|
||||
|
||||
@@ -543,12 +537,10 @@ You can also run the linter and formatter separately:
|
||||
- `npm run format` - Auto-format markdown files
|
||||
- `npm run lint:fix` - Auto-fix linting issues where possible
|
||||
|
||||
Please make sure your contributions are free of linting errors before submitting
|
||||
a pull request.
|
||||
Ensure your contributions are free of linting errors before submitting a pull
|
||||
request.
|
||||
|
||||
### Before you submit
|
||||
|
||||
Before submitting your documentation pull request, please:
|
||||
### Before submitting
|
||||
|
||||
1. Run `npm run preflight` to ensure all checks pass.
|
||||
2. Review your changes for clarity and accuracy.
|
||||
@@ -562,10 +554,10 @@ Before submitting your documentation pull request, please:
|
||||
|
||||
If you have questions about contributing documentation:
|
||||
|
||||
- Check our [FAQ](https://geminicli.com/docs/resources/faq).
|
||||
- Check the [FAQ](https://geminicli.com/docs/resources/faq).
|
||||
- Review existing documentation for examples.
|
||||
- Open [an issue](https://github.com/google-gemini/gemini-cli/issues) to discuss
|
||||
your proposed changes.
|
||||
- Reach out to the maintainers.
|
||||
|
||||
We appreciate your contributions to making Gemini CLI documentation better!
|
||||
Gemini CLI appreciates your contributions to making its documentation better!
|
||||
|
||||
@@ -18,6 +18,27 @@ on GitHub.
|
||||
| [Preview](preview.md) | Experimental features ready for early feedback. |
|
||||
| [Stable](latest.md) | Stable, recommended for general use. |
|
||||
|
||||
## Announcements: v0.38.0 - 2026-04-14
|
||||
|
||||
- **Chapters Narrative Flow:** Group agent interactions into "Chapters" based on
|
||||
intent and tool usage for better session structure
|
||||
([#23150](https://github.com/google-gemini/gemini-cli/pull/23150) by
|
||||
@Abhijit-2592,
|
||||
[#24079](https://github.com/google-gemini/gemini-cli/pull/24079) by
|
||||
@gundermanc).
|
||||
- **Context Compression Service:** Advanced context management to efficiently
|
||||
distill conversation history
|
||||
([#24483](https://github.com/google-gemini/gemini-cli/pull/24483) by
|
||||
@joshualitt).
|
||||
- **UI Flicker & UX Enhancements:** Solved rendering flicker with "Terminal
|
||||
Buffer" mode and introduced selective topic expansion
|
||||
([#24512](https://github.com/google-gemini/gemini-cli/pull/24512) by
|
||||
@jacob314, [#24793](https://github.com/google-gemini/gemini-cli/pull/24793) by
|
||||
@Abhijit-2592).
|
||||
- **Persistent Policy Approvals:** Implemented context-aware persistent
|
||||
approvals for tool execution
|
||||
([#23257](https://github.com/google-gemini/gemini-cli/pull/23257) by @jerop).
|
||||
|
||||
## Announcements: v0.37.0 - 2026-04-08
|
||||
|
||||
- **Dynamic Sandbox Expansion:** Implemented dynamic sandbox expansion and
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Latest stable release: v0.37.1
|
||||
# Latest stable release: v0.38.1
|
||||
|
||||
Released: April 09, 2026
|
||||
Released: April 15, 2026
|
||||
|
||||
For most users, our latest stable release is the recommended release. Install
|
||||
the latest stable version with:
|
||||
@@ -11,415 +11,261 @@ npm install -g @google/gemini-cli
|
||||
|
||||
## Highlights
|
||||
|
||||
- **Dynamic Sandbox Expansion:** Implemented dynamic sandbox expansion and
|
||||
worktree support for both Linux and Windows, enhancing development flexibility
|
||||
in restricted environments.
|
||||
- **Tool-Based Topic Grouping (Chapters):** Introduced "Chapters" to logically
|
||||
group agent interactions based on tool usage and intent, providing a clearer
|
||||
narrative flow in long sessions.
|
||||
- **Enhanced Browser Agent:** Added persistent session management, dynamic
|
||||
read-only tool discovery, and sandbox-aware initialization for the browser
|
||||
agent.
|
||||
- **Security & Permission Hardening:** Implemented secret visibility lockdown
|
||||
for environment files and integrated integrity controls for Windows
|
||||
sandboxing.
|
||||
- **Chapters Narrative Flow:** Introduced tool-based topic grouping ("Chapters")
|
||||
to provide better session structure and narrative continuity in long-running
|
||||
tasks.
|
||||
- **Context Compression Service:** Implemented a dedicated service for advanced
|
||||
context management, efficiently distilling conversation history to preserve
|
||||
focus and tokens.
|
||||
- **Enhanced UI Stability & UX:** Introduced a new "Terminal Buffer" mode to
|
||||
solve rendering flicker, along with selective topic expansion and improved
|
||||
tool confirmation layouts.
|
||||
- **Context-Aware Policy Approvals:** Users can now grant persistent,
|
||||
context-aware approvals for tools, significantly reducing manual confirmation
|
||||
overhead for trusted workflows.
|
||||
- **Background Process Monitoring:** New tools for monitoring and inspecting
|
||||
background shell processes, providing better visibility into asynchronous
|
||||
tasks.
|
||||
|
||||
## What's Changed
|
||||
|
||||
- fix(acp): handle all InvalidStreamError types gracefully in prompt
|
||||
[#24540](https://github.com/google-gemini/gemini-cli/pull/24540)
|
||||
- feat(acp): add support for /about command
|
||||
[#24649](https://github.com/google-gemini/gemini-cli/pull/24649)
|
||||
- feat(acp): add /help command
|
||||
[#24839](https://github.com/google-gemini/gemini-cli/pull/24839)
|
||||
- feat(evals): centralize test agents into test-utils for reuse by @Samee24 in
|
||||
[#23616](https://github.com/google-gemini/gemini-cli/pull/23616)
|
||||
- revert: chore(config): disable agents by default by @abhipatel12 in
|
||||
[#23672](https://github.com/google-gemini/gemini-cli/pull/23672)
|
||||
- fix(plan): update telemetry attribute keys and add timestamp by @Adib234 in
|
||||
[#23685](https://github.com/google-gemini/gemini-cli/pull/23685)
|
||||
- fix(core): prevent premature MCP discovery completion by @jackwotherspoon in
|
||||
[#23637](https://github.com/google-gemini/gemini-cli/pull/23637)
|
||||
- feat(browser): add maxActionsPerTask for browser agent setting by
|
||||
@cynthialong0-0 in
|
||||
[#23216](https://github.com/google-gemini/gemini-cli/pull/23216)
|
||||
- fix(core): improve agent loader error formatting for empty paths by
|
||||
@adamfweidman in
|
||||
[#23690](https://github.com/google-gemini/gemini-cli/pull/23690)
|
||||
- fix(cli): only show updating spinner when auto-update is in progress by
|
||||
@scidomino in [#23709](https://github.com/google-gemini/gemini-cli/pull/23709)
|
||||
- Refine onboarding metrics to log the duration explicitly and use the tier
|
||||
name. by @yunaseoul in
|
||||
[#23678](https://github.com/google-gemini/gemini-cli/pull/23678)
|
||||
- chore(tools): add toJSON to tools and invocations to reduce logging verbosity
|
||||
by @alisa-alisa in
|
||||
[#22899](https://github.com/google-gemini/gemini-cli/pull/22899)
|
||||
- fix(cli): stabilize copy mode to prevent flickering and cursor resets by
|
||||
@mattKorwel in
|
||||
[#22584](https://github.com/google-gemini/gemini-cli/pull/22584)
|
||||
- fix(test): move flaky ctrl-c-exit test to non-blocking suite by @mattKorwel in
|
||||
[#23732](https://github.com/google-gemini/gemini-cli/pull/23732)
|
||||
- feat(skills): add ci skill for automated failure replication by @mattKorwel in
|
||||
[#23720](https://github.com/google-gemini/gemini-cli/pull/23720)
|
||||
- feat(sandbox): implement forbiddenPaths for OS-specific sandbox managers by
|
||||
@ehedlund in [#23282](https://github.com/google-gemini/gemini-cli/pull/23282)
|
||||
- fix(core): conditionally expose additional_permissions in shell tool by
|
||||
@galz10 in [#23729](https://github.com/google-gemini/gemini-cli/pull/23729)
|
||||
- refactor(core): standardize OS-specific sandbox tests and extract linux helper
|
||||
methods by @ehedlund in
|
||||
[#23715](https://github.com/google-gemini/gemini-cli/pull/23715)
|
||||
- format recently added script by @scidomino in
|
||||
[#23739](https://github.com/google-gemini/gemini-cli/pull/23739)
|
||||
- fix(ui): prevent over-eager slash subcommand completion by @keithguerin in
|
||||
[#20136](https://github.com/google-gemini/gemini-cli/pull/20136)
|
||||
- Fix dynamic model routing for gemini 3.1 pro to customtools model by
|
||||
@kevinjwang1 in
|
||||
[#23641](https://github.com/google-gemini/gemini-cli/pull/23641)
|
||||
- feat(core): support inline agentCardJson for remote agents by @adamfweidman in
|
||||
[#23743](https://github.com/google-gemini/gemini-cli/pull/23743)
|
||||
- fix(cli): skip console log/info in headless mode by @cynthialong0-0 in
|
||||
[#22739](https://github.com/google-gemini/gemini-cli/pull/22739)
|
||||
- test(core): install bubblewrap on Linux CI for sandbox integration tests by
|
||||
@ehedlund in [#23583](https://github.com/google-gemini/gemini-cli/pull/23583)
|
||||
- docs(reference): split tools table into category sections by @sheikhlimon in
|
||||
[#21516](https://github.com/google-gemini/gemini-cli/pull/21516)
|
||||
- fix(browser): detect embedded URLs in query params to prevent allowedDomains
|
||||
bypass by @tony-shi in
|
||||
[#23225](https://github.com/google-gemini/gemini-cli/pull/23225)
|
||||
- fix(browser): add proxy bypass constraint to domain restriction system prompt
|
||||
by @tony-shi in
|
||||
[#23229](https://github.com/google-gemini/gemini-cli/pull/23229)
|
||||
- fix(policy): relax write_file argsPattern in plan mode to allow paths without
|
||||
session ID by @Adib234 in
|
||||
[#23695](https://github.com/google-gemini/gemini-cli/pull/23695)
|
||||
- docs: fix grammar in CONTRIBUTING and numbering in sandbox docs by
|
||||
@splint-disk-8i in
|
||||
[#23448](https://github.com/google-gemini/gemini-cli/pull/23448)
|
||||
- fix(acp): allow attachments by adding a permission prompt by @sripasg in
|
||||
[#23680](https://github.com/google-gemini/gemini-cli/pull/23680)
|
||||
- fix(core): thread AbortSignal to chat compression requests (#20405) by
|
||||
@SH20RAJ in [#20778](https://github.com/google-gemini/gemini-cli/pull/20778)
|
||||
- feat(core): implement Windows sandbox dynamic expansion Phase 1 and 2.1 by
|
||||
@scidomino in [#23691](https://github.com/google-gemini/gemini-cli/pull/23691)
|
||||
- Add note about root privileges in sandbox docs by @diodesign in
|
||||
[#23314](https://github.com/google-gemini/gemini-cli/pull/23314)
|
||||
- docs(core): document agent_card_json string literal options for remote agents
|
||||
by @adamfweidman in
|
||||
[#23797](https://github.com/google-gemini/gemini-cli/pull/23797)
|
||||
- fix(cli): resolve TTY hang on headless environments by unconditionally
|
||||
resuming process.stdin before React Ink launch by @cocosheng-g in
|
||||
[#23673](https://github.com/google-gemini/gemini-cli/pull/23673)
|
||||
- fix(ui): cleanup estimated string length hacks in composer by @keithguerin in
|
||||
[#23694](https://github.com/google-gemini/gemini-cli/pull/23694)
|
||||
- feat(browser): dynamically discover read-only tools by @cynthialong0-0 in
|
||||
[#23805](https://github.com/google-gemini/gemini-cli/pull/23805)
|
||||
- docs: clarify policy requirement for `general.plan.directory` in settings
|
||||
schema by @jerop in
|
||||
[#23784](https://github.com/google-gemini/gemini-cli/pull/23784)
|
||||
- Revert "perf(cli): optimize --version startup time (#23671)" by @scidomino in
|
||||
[#23812](https://github.com/google-gemini/gemini-cli/pull/23812)
|
||||
- don't silence errors from wombat by @scidomino in
|
||||
[#23822](https://github.com/google-gemini/gemini-cli/pull/23822)
|
||||
- fix(ui): prevent escape key from cancelling requests in shell mode by
|
||||
@PrasannaPal21 in
|
||||
[#21245](https://github.com/google-gemini/gemini-cli/pull/21245)
|
||||
- Changelog for v0.36.0-preview.0 by @gemini-cli-robot in
|
||||
[#23702](https://github.com/google-gemini/gemini-cli/pull/23702)
|
||||
- feat(core,ui): Add experiment-gated support for gemini flash 3.1 lite by
|
||||
@chrstnb in [#23794](https://github.com/google-gemini/gemini-cli/pull/23794)
|
||||
- Changelog for v0.36.0-preview.3 by @gemini-cli-robot in
|
||||
[#23827](https://github.com/google-gemini/gemini-cli/pull/23827)
|
||||
- new linting check: github-actions-pinning by @alisa-alisa in
|
||||
[#23808](https://github.com/google-gemini/gemini-cli/pull/23808)
|
||||
- fix(cli): show helpful guidance when no skills are available by @Niralisj in
|
||||
[#23785](https://github.com/google-gemini/gemini-cli/pull/23785)
|
||||
- fix: Chat logs and errors handle tail tool calls correctly by @googlestrobe in
|
||||
[#22460](https://github.com/google-gemini/gemini-cli/pull/22460)
|
||||
- Don't try removing a tag from a non-existent release. by @scidomino in
|
||||
[#23830](https://github.com/google-gemini/gemini-cli/pull/23830)
|
||||
- fix(cli): allow ask question dialog to take full window height by @jacob314 in
|
||||
[#23693](https://github.com/google-gemini/gemini-cli/pull/23693)
|
||||
- fix(core): strip leading underscores from error types in telemetry by
|
||||
@yunaseoul in [#23824](https://github.com/google-gemini/gemini-cli/pull/23824)
|
||||
- Changelog for v0.35.0 by @gemini-cli-robot in
|
||||
[#23819](https://github.com/google-gemini/gemini-cli/pull/23819)
|
||||
- feat(evals): add reliability harvester and 500/503 retry support by
|
||||
@alisa-alisa in
|
||||
[#23626](https://github.com/google-gemini/gemini-cli/pull/23626)
|
||||
- feat(sandbox): dynamic Linux sandbox expansion and worktree support by @galz10
|
||||
in [#23692](https://github.com/google-gemini/gemini-cli/pull/23692)
|
||||
- Merge examples of use into quickstart documentation by @diodesign in
|
||||
[#23319](https://github.com/google-gemini/gemini-cli/pull/23319)
|
||||
- fix(cli): prioritize primary name matches in slash command search by @sehoon38
|
||||
in [#23850](https://github.com/google-gemini/gemini-cli/pull/23850)
|
||||
- Changelog for v0.35.1 by @gemini-cli-robot in
|
||||
[#23840](https://github.com/google-gemini/gemini-cli/pull/23840)
|
||||
- fix(browser): keep input blocker active across navigations by @kunal-10-cloud
|
||||
in [#22562](https://github.com/google-gemini/gemini-cli/pull/22562)
|
||||
- feat(core): new skill to look for duplicated code while reviewing PRs by
|
||||
@devr0306 in [#23704](https://github.com/google-gemini/gemini-cli/pull/23704)
|
||||
- fix(core): replace hardcoded non-interactive ASK_USER denial with explicit
|
||||
policy rules by @ruomengz in
|
||||
[#23668](https://github.com/google-gemini/gemini-cli/pull/23668)
|
||||
- fix(plan): after exiting plan mode switches model to a flash model by @Adib234
|
||||
in [#23885](https://github.com/google-gemini/gemini-cli/pull/23885)
|
||||
- feat(gcp): add development worker infrastructure by @mattKorwel in
|
||||
[#23814](https://github.com/google-gemini/gemini-cli/pull/23814)
|
||||
- fix(a2a-server): A2A server should execute ask policies in interactive mode by
|
||||
@kschaab in [#23831](https://github.com/google-gemini/gemini-cli/pull/23831)
|
||||
- feat(core): define TrajectoryProvider interface by @sehoon38 in
|
||||
[#23050](https://github.com/google-gemini/gemini-cli/pull/23050)
|
||||
- Docs: Update quotas and pricing by @jkcinouye in
|
||||
[#23835](https://github.com/google-gemini/gemini-cli/pull/23835)
|
||||
- fix(core): allow disabling environment variable redaction by @galz10 in
|
||||
[#23927](https://github.com/google-gemini/gemini-cli/pull/23927)
|
||||
- feat(cli): enable notifications cross-platform via terminal bell fallback by
|
||||
@genneth in [#21618](https://github.com/google-gemini/gemini-cli/pull/21618)
|
||||
- feat(sandbox): implement secret visibility lockdown for env files by
|
||||
@DavidAPierce in
|
||||
[#23712](https://github.com/google-gemini/gemini-cli/pull/23712)
|
||||
- fix(core): remove shell outputChunks buffer caching to prevent memory bloat
|
||||
and sanitize prompt input by @spencer426 in
|
||||
[#23751](https://github.com/google-gemini/gemini-cli/pull/23751)
|
||||
- feat(core): implement persistent browser session management by @kunal-10-cloud
|
||||
in [#21306](https://github.com/google-gemini/gemini-cli/pull/21306)
|
||||
- refactor(core): delegate sandbox denial parsing to SandboxManager by
|
||||
@scidomino in [#23928](https://github.com/google-gemini/gemini-cli/pull/23928)
|
||||
- dep(update) Update Ink version to 6.5.0 by @jacob314 in
|
||||
[#23843](https://github.com/google-gemini/gemini-cli/pull/23843)
|
||||
- Docs: Update 'docs-writer' skill for relative links by @jkcinouye in
|
||||
[#21463](https://github.com/google-gemini/gemini-cli/pull/21463)
|
||||
- Changelog for v0.36.0-preview.4 by @gemini-cli-robot in
|
||||
[#23935](https://github.com/google-gemini/gemini-cli/pull/23935)
|
||||
- fix(acp): Update allow approval policy flow for ACP clients to fix config
|
||||
persistence and compatible with TUI by @sripasg in
|
||||
[#23818](https://github.com/google-gemini/gemini-cli/pull/23818)
|
||||
- Changelog for v0.35.2 by @gemini-cli-robot in
|
||||
[#23960](https://github.com/google-gemini/gemini-cli/pull/23960)
|
||||
- ACP integration documents by @g-samroberts in
|
||||
[#22254](https://github.com/google-gemini/gemini-cli/pull/22254)
|
||||
- fix(core): explicitly set error names to avoid bundling renaming issues by
|
||||
@yunaseoul in [#23913](https://github.com/google-gemini/gemini-cli/pull/23913)
|
||||
- feat(core): subagent isolation and cleanup hardening by @abhipatel12 in
|
||||
[#23903](https://github.com/google-gemini/gemini-cli/pull/23903)
|
||||
- disable extension-reload test by @scidomino in
|
||||
[#24018](https://github.com/google-gemini/gemini-cli/pull/24018)
|
||||
- feat(core): add forbiddenPaths to GlobalSandboxOptions and refactor
|
||||
createSandboxManager by @ehedlund in
|
||||
[#23936](https://github.com/google-gemini/gemini-cli/pull/23936)
|
||||
- refactor(core): improve ignore resolution and fix directory-matching bug by
|
||||
@ehedlund in [#23816](https://github.com/google-gemini/gemini-cli/pull/23816)
|
||||
- revert(core): support custom base URL via env vars by @spencer426 in
|
||||
[#23976](https://github.com/google-gemini/gemini-cli/pull/23976)
|
||||
- Increase memory limited for eslint. by @jacob314 in
|
||||
[#24022](https://github.com/google-gemini/gemini-cli/pull/24022)
|
||||
- fix(acp): prevent crash on empty response in ACP mode by @sripasg in
|
||||
[#23952](https://github.com/google-gemini/gemini-cli/pull/23952)
|
||||
- feat(core): Land `AgentHistoryProvider`. by @joshualitt in
|
||||
[#23978](https://github.com/google-gemini/gemini-cli/pull/23978)
|
||||
- fix(core): switch to subshells for shell tool wrapping to fix heredocs and
|
||||
edge cases by @abhipatel12 in
|
||||
[#24024](https://github.com/google-gemini/gemini-cli/pull/24024)
|
||||
- Debug command. by @jacob314 in
|
||||
[#23851](https://github.com/google-gemini/gemini-cli/pull/23851)
|
||||
- Changelog for v0.36.0-preview.5 by @gemini-cli-robot in
|
||||
[#24046](https://github.com/google-gemini/gemini-cli/pull/24046)
|
||||
- Fix test flakes by globally mocking ink-spinner by @jacob314 in
|
||||
[#24044](https://github.com/google-gemini/gemini-cli/pull/24044)
|
||||
- Enable network access in sandbox configuration by @galz10 in
|
||||
[#24055](https://github.com/google-gemini/gemini-cli/pull/24055)
|
||||
- feat(context): add configurable memoryBoundaryMarkers setting by @SandyTao520
|
||||
in [#24020](https://github.com/google-gemini/gemini-cli/pull/24020)
|
||||
- feat(core): implement windows sandbox expansion and denial detection by
|
||||
@scidomino in [#24027](https://github.com/google-gemini/gemini-cli/pull/24027)
|
||||
- fix(core): resolve ACP Operation Aborted Errors in grep_search by @ivanporty
|
||||
in [#23821](https://github.com/google-gemini/gemini-cli/pull/23821)
|
||||
- fix(hooks): prevent SessionEnd from firing twice in non-interactive mode by
|
||||
@krishdef7 in [#22139](https://github.com/google-gemini/gemini-cli/pull/22139)
|
||||
- Re-word intro to Gemini 3 page. by @g-samroberts in
|
||||
[#24069](https://github.com/google-gemini/gemini-cli/pull/24069)
|
||||
- fix(cli): resolve layout contention and flashing loop in StatusRow by
|
||||
@keithguerin in
|
||||
[#24065](https://github.com/google-gemini/gemini-cli/pull/24065)
|
||||
- fix(sandbox): implement Windows Mandatory Integrity Control for GeminiSandbox
|
||||
by @galz10 in [#24057](https://github.com/google-gemini/gemini-cli/pull/24057)
|
||||
- feat(core): implement tool-based topic grouping (Chapters) by @Abhijit-2592 in
|
||||
[#23150](https://github.com/google-gemini/gemini-cli/pull/23150)
|
||||
- feat(cli): support 'tab to queue' for messages while generating by @gundermanc
|
||||
in [#24052](https://github.com/google-gemini/gemini-cli/pull/24052)
|
||||
- feat(core): agnostic background task UI with CompletionBehavior by
|
||||
@adamfweidman in
|
||||
[#22740](https://github.com/google-gemini/gemini-cli/pull/22740)
|
||||
- UX for topic narration tool by @gundermanc in
|
||||
[#24079](https://github.com/google-gemini/gemini-cli/pull/24079)
|
||||
- fix: shellcheck warnings in scripts by @scidomino in
|
||||
[#24035](https://github.com/google-gemini/gemini-cli/pull/24035)
|
||||
- test(evals): add comprehensive subagent delegation evaluations by @abhipatel12
|
||||
in [#24132](https://github.com/google-gemini/gemini-cli/pull/24132)
|
||||
- fix(a2a-server): prioritize ADC before evaluating headless constraints for
|
||||
auth initialization by @spencer426 in
|
||||
[#23614](https://github.com/google-gemini/gemini-cli/pull/23614)
|
||||
- Text can be added after /plan command by @rambleraptor in
|
||||
[#22833](https://github.com/google-gemini/gemini-cli/pull/22833)
|
||||
- fix(cli): resolve missing F12 logs via global console store by @scidomino in
|
||||
[#24235](https://github.com/google-gemini/gemini-cli/pull/24235)
|
||||
- fix broken tests by @scidomino in
|
||||
[#24279](https://github.com/google-gemini/gemini-cli/pull/24279)
|
||||
- fix(evals): add update_topic behavioral eval by @gundermanc in
|
||||
[#24223](https://github.com/google-gemini/gemini-cli/pull/24223)
|
||||
- feat(core): Unified Context Management and Tool Distillation. by @joshualitt
|
||||
in [#24157](https://github.com/google-gemini/gemini-cli/pull/24157)
|
||||
- Default enable narration for the team. by @gundermanc in
|
||||
[#24224](https://github.com/google-gemini/gemini-cli/pull/24224)
|
||||
- fix(core): ensure default agents provide tools and use model-specific schemas
|
||||
by @abhipatel12 in
|
||||
[#24268](https://github.com/google-gemini/gemini-cli/pull/24268)
|
||||
- feat(cli): show Flash Lite Preview model regardless of user tier by @sehoon38
|
||||
in [#23904](https://github.com/google-gemini/gemini-cli/pull/23904)
|
||||
- feat(cli): implement compact tool output by @jwhelangoog in
|
||||
[#20974](https://github.com/google-gemini/gemini-cli/pull/20974)
|
||||
- Add security settings for tool sandboxing by @galz10 in
|
||||
[#23923](https://github.com/google-gemini/gemini-cli/pull/23923)
|
||||
- chore(test-utils): switch integration tests to use PREVIEW_GEMINI_MODEL by
|
||||
@sehoon38 in [#24276](https://github.com/google-gemini/gemini-cli/pull/24276)
|
||||
- feat(core): enable topic update narration for legacy models by @Abhijit-2592
|
||||
in [#24241](https://github.com/google-gemini/gemini-cli/pull/24241)
|
||||
- feat(core): add project-level memory scope to save_memory tool by @SandyTao520
|
||||
in [#24161](https://github.com/google-gemini/gemini-cli/pull/24161)
|
||||
- test(integration): fix plan mode write denial test false positive by @sehoon38
|
||||
in [#24299](https://github.com/google-gemini/gemini-cli/pull/24299)
|
||||
- feat(plan): support `Plan` mode in untrusted folders by @Adib234 in
|
||||
[#17586](https://github.com/google-gemini/gemini-cli/pull/17586)
|
||||
- fix(core): enable mid-stream retries for all models and re-enable compression
|
||||
test by @sehoon38 in
|
||||
[#24302](https://github.com/google-gemini/gemini-cli/pull/24302)
|
||||
- Changelog for v0.36.0-preview.6 by @gemini-cli-robot in
|
||||
[#24082](https://github.com/google-gemini/gemini-cli/pull/24082)
|
||||
- Changelog for v0.35.3 by @gemini-cli-robot in
|
||||
[#24083](https://github.com/google-gemini/gemini-cli/pull/24083)
|
||||
- feat(cli): add auth info to footer by @sehoon38 in
|
||||
[#24042](https://github.com/google-gemini/gemini-cli/pull/24042)
|
||||
- fix(browser): reset action counter for each agent session and let it ignore
|
||||
internal actions by @cynthialong0-0 in
|
||||
[#24228](https://github.com/google-gemini/gemini-cli/pull/24228)
|
||||
- feat(plan): promote planning feature to stable by @ruomengz in
|
||||
[#24282](https://github.com/google-gemini/gemini-cli/pull/24282)
|
||||
- fix(browser): terminate subagent immediately on domain restriction violations
|
||||
by @gsquared94 in
|
||||
[#24313](https://github.com/google-gemini/gemini-cli/pull/24313)
|
||||
- feat(cli): add UI to update extensions by @ruomengz in
|
||||
[#23682](https://github.com/google-gemini/gemini-cli/pull/23682)
|
||||
- Fix(browser): terminate immediately for "browser is already running" error by
|
||||
@cynthialong0-0 in
|
||||
[#24233](https://github.com/google-gemini/gemini-cli/pull/24233)
|
||||
- docs: Add 'plan' option to approval mode in CLI reference by @YifanRuan in
|
||||
[#24134](https://github.com/google-gemini/gemini-cli/pull/24134)
|
||||
- fix(core): batch macOS seatbelt rules into a profile file to prevent ARG_MAX
|
||||
errors by @ehedlund in
|
||||
[#24255](https://github.com/google-gemini/gemini-cli/pull/24255)
|
||||
- fix(core): fix race condition between browser agent and main closing process
|
||||
by @cynthialong0-0 in
|
||||
[#24340](https://github.com/google-gemini/gemini-cli/pull/24340)
|
||||
- perf(build): optimize build scripts for parallel execution and remove
|
||||
redundant checks by @sehoon38 in
|
||||
[#24307](https://github.com/google-gemini/gemini-cli/pull/24307)
|
||||
- ci: install bubblewrap on Linux for release workflows by @ehedlund in
|
||||
[#24347](https://github.com/google-gemini/gemini-cli/pull/24347)
|
||||
- chore(release): allow bundling for all builds, including stable by @sehoon38
|
||||
in [#24305](https://github.com/google-gemini/gemini-cli/pull/24305)
|
||||
- Revert "Add security settings for tool sandboxing" by @jerop in
|
||||
[#24357](https://github.com/google-gemini/gemini-cli/pull/24357)
|
||||
- docs: update subagents docs to not be experimental by @abhipatel12 in
|
||||
[#24343](https://github.com/google-gemini/gemini-cli/pull/24343)
|
||||
- fix(core): implement **read and **write commands in sandbox managers by
|
||||
@galz10 in [#24283](https://github.com/google-gemini/gemini-cli/pull/24283)
|
||||
- don't try to remove tags in dry run by @scidomino in
|
||||
[#24356](https://github.com/google-gemini/gemini-cli/pull/24356)
|
||||
- fix(config): disable JIT context loading by default by @SandyTao520 in
|
||||
[#24364](https://github.com/google-gemini/gemini-cli/pull/24364)
|
||||
- test(sandbox): add integration test for dynamic permission expansion by
|
||||
@galz10 in [#24359](https://github.com/google-gemini/gemini-cli/pull/24359)
|
||||
- docs(policy): remove unsupported mcpName wildcard edge case by @abhipatel12 in
|
||||
[#24133](https://github.com/google-gemini/gemini-cli/pull/24133)
|
||||
- docs: fix broken GEMINI.md link in CONTRIBUTING.md by @Panchal-Tirth in
|
||||
[#24182](https://github.com/google-gemini/gemini-cli/pull/24182)
|
||||
- feat(core): infrastructure for event-driven subagent history by @abhipatel12
|
||||
in [#23914](https://github.com/google-gemini/gemini-cli/pull/23914)
|
||||
- fix(core): resolve Plan Mode deadlock during plan file creation due to sandbox
|
||||
restrictions by @DavidAPierce in
|
||||
[#24047](https://github.com/google-gemini/gemini-cli/pull/24047)
|
||||
- fix(core): fix browser agent UX issues and improve E2E test reliability by
|
||||
@gsquared94 in
|
||||
[#24312](https://github.com/google-gemini/gemini-cli/pull/24312)
|
||||
- fix(ui): wrap topic and intent fields in TopicMessage by @jwhelangoog in
|
||||
[#24386](https://github.com/google-gemini/gemini-cli/pull/24386)
|
||||
- refactor(core): Centralize context management logic into src/context by
|
||||
@joshualitt in
|
||||
[#24380](https://github.com/google-gemini/gemini-cli/pull/24380)
|
||||
- fix(core): pin AuthType.GATEWAY to use Gemini 3.1 Pro/Flash Lite by default by
|
||||
@sripasg in [#24375](https://github.com/google-gemini/gemini-cli/pull/24375)
|
||||
- feat(ui): add Tokyo Night theme by @danrneal in
|
||||
[#24054](https://github.com/google-gemini/gemini-cli/pull/24054)
|
||||
- fix(cli): refactor test config loading and mock debugLogger in test-setup by
|
||||
@mattKorwel in
|
||||
[#24389](https://github.com/google-gemini/gemini-cli/pull/24389)
|
||||
- Set memoryManager to false in settings.json by @mattKorwel in
|
||||
[#24393](https://github.com/google-gemini/gemini-cli/pull/24393)
|
||||
- ink 6.6.3 by @jacob314 in
|
||||
[#24372](https://github.com/google-gemini/gemini-cli/pull/24372)
|
||||
- fix(core): resolve subagent chat recording gaps and directory inheritance by
|
||||
- fix(patch): cherry-pick 050c303 to release/v0.38.0-pr-25317 to patch version
|
||||
v0.38.0 and create version 0.38.1 by @gemini-cli-robot in
|
||||
[#25466](https://github.com/google-gemini/gemini-cli/pull/25466)
|
||||
- fix(cli): refresh slash command list after /skills reload by @NTaylorMullen in
|
||||
[#24454](https://github.com/google-gemini/gemini-cli/pull/24454)
|
||||
- Update README.md for links. by @g-samroberts in
|
||||
[#22759](https://github.com/google-gemini/gemini-cli/pull/22759)
|
||||
- fix(core): ensure complete_task tool calls are recorded in chat history by
|
||||
@abhipatel12 in
|
||||
[#24368](https://github.com/google-gemini/gemini-cli/pull/24368)
|
||||
- fix(cli): cap shell output at 10 MB to prevent RangeError crash by @ProthamD
|
||||
in [#24168](https://github.com/google-gemini/gemini-cli/pull/24168)
|
||||
- feat(plan): conditionally add enter/exit plan mode tools based on current mode
|
||||
by @ruomengz in
|
||||
[#24378](https://github.com/google-gemini/gemini-cli/pull/24378)
|
||||
- feat(core): prioritize discussion before formal plan approval by @jerop in
|
||||
[#24423](https://github.com/google-gemini/gemini-cli/pull/24423)
|
||||
- fix(ui): add accelerated scrolling on alternate buffer mode by @devr0306 in
|
||||
[#23940](https://github.com/google-gemini/gemini-cli/pull/23940)
|
||||
- feat(core): populate sandbox forbidden paths with project ignore file contents
|
||||
by @ehedlund in
|
||||
[#24038](https://github.com/google-gemini/gemini-cli/pull/24038)
|
||||
- fix(core): ensure blue border overlay and input blocker to act correctly
|
||||
depending on browser agent activities by @cynthialong0-0 in
|
||||
[#24385](https://github.com/google-gemini/gemini-cli/pull/24385)
|
||||
- fix(ui): removed additional vertical padding for tables by @devr0306 in
|
||||
[#24381](https://github.com/google-gemini/gemini-cli/pull/24381)
|
||||
- fix(build): upload full bundle directory archive to GitHub releases by
|
||||
@sehoon38 in [#24403](https://github.com/google-gemini/gemini-cli/pull/24403)
|
||||
- fix(build): wire bundle:browser-mcp into bundle pipeline by @gsquared94 in
|
||||
[#24424](https://github.com/google-gemini/gemini-cli/pull/24424)
|
||||
- feat(browser): add sandbox-aware browser agent initialization by @gsquared94
|
||||
in [#24419](https://github.com/google-gemini/gemini-cli/pull/24419)
|
||||
- feat(core): enhance tracker task schemas for detailed titles and descriptions
|
||||
by @anj-s in [#23902](https://github.com/google-gemini/gemini-cli/pull/23902)
|
||||
- refactor(core): Unified context management settings schema by @joshualitt in
|
||||
[#24391](https://github.com/google-gemini/gemini-cli/pull/24391)
|
||||
- feat(core): update browser agent prompt to check open pages first when
|
||||
bringing up by @cynthialong0-0 in
|
||||
[#24431](https://github.com/google-gemini/gemini-cli/pull/24431)
|
||||
- fix(acp) refactor(core,cli): centralize model discovery logic in
|
||||
ModelConfigService by @sripasg in
|
||||
[#24392](https://github.com/google-gemini/gemini-cli/pull/24392)
|
||||
- Changelog for v0.36.0-preview.7 by @gemini-cli-robot in
|
||||
[#24346](https://github.com/google-gemini/gemini-cli/pull/24346)
|
||||
- fix: update task tracker storage location in system prompt by @anj-s in
|
||||
[#24034](https://github.com/google-gemini/gemini-cli/pull/24034)
|
||||
- feat(browser): supersede stale snapshots to reclaim context-window tokens by
|
||||
[#24437](https://github.com/google-gemini/gemini-cli/pull/24437)
|
||||
- feat(policy): explicitly allow web_fetch in plan mode with ask_user by
|
||||
@Adib234 in [#24456](https://github.com/google-gemini/gemini-cli/pull/24456)
|
||||
- fix(core): refactor linux sandbox to fix ARG_MAX crashes by @ehedlund in
|
||||
[#24286](https://github.com/google-gemini/gemini-cli/pull/24286)
|
||||
- feat(config): add experimental.adk.agentSessionNoninteractiveEnabled setting
|
||||
by @adamfweidman in
|
||||
[#24439](https://github.com/google-gemini/gemini-cli/pull/24439)
|
||||
- Changelog for v0.36.0-preview.8 by @gemini-cli-robot in
|
||||
[#24453](https://github.com/google-gemini/gemini-cli/pull/24453)
|
||||
- feat(cli): change default loadingPhrases to 'off' to hide tips by @keithguerin
|
||||
in [#24342](https://github.com/google-gemini/gemini-cli/pull/24342)
|
||||
- fix(cli): ensure agent stops when all declinable tools are cancelled by
|
||||
@NTaylorMullen in
|
||||
[#24479](https://github.com/google-gemini/gemini-cli/pull/24479)
|
||||
- fix(core): enhance sandbox usability and fix build error by @galz10 in
|
||||
[#24460](https://github.com/google-gemini/gemini-cli/pull/24460)
|
||||
- Terminal Serializer Optimization by @jacob314 in
|
||||
[#24485](https://github.com/google-gemini/gemini-cli/pull/24485)
|
||||
- Auto configure memory. by @jacob314 in
|
||||
[#24474](https://github.com/google-gemini/gemini-cli/pull/24474)
|
||||
- Unused error variables in catch block are not allowed by @alisa-alisa in
|
||||
[#24487](https://github.com/google-gemini/gemini-cli/pull/24487)
|
||||
- feat(core): add background memory service for skill extraction by @SandyTao520
|
||||
in [#24274](https://github.com/google-gemini/gemini-cli/pull/24274)
|
||||
- feat: implement high-signal PR regression check for evaluations by
|
||||
@alisa-alisa in
|
||||
[#23937](https://github.com/google-gemini/gemini-cli/pull/23937)
|
||||
- Fix shell output display by @jacob314 in
|
||||
[#24490](https://github.com/google-gemini/gemini-cli/pull/24490)
|
||||
- fix(ui): resolve unwanted vertical spacing around various tool output
|
||||
treatments by @jwhelangoog in
|
||||
[#24449](https://github.com/google-gemini/gemini-cli/pull/24449)
|
||||
- revert(cli): bring back input box and footer visibility in copy mode by
|
||||
@sehoon38 in [#24504](https://github.com/google-gemini/gemini-cli/pull/24504)
|
||||
- fix(cli): prevent crash in AnsiOutputText when handling non-array data by
|
||||
@sehoon38 in [#24498](https://github.com/google-gemini/gemini-cli/pull/24498)
|
||||
- feat(cli): support default values for environment variables by @ruomengz in
|
||||
[#24469](https://github.com/google-gemini/gemini-cli/pull/24469)
|
||||
- Implement background process monitoring and inspection tools by @cocosheng-g
|
||||
in [#23799](https://github.com/google-gemini/gemini-cli/pull/23799)
|
||||
- docs(browser-agent): update stale browser agent documentation by @gsquared94
|
||||
in [#24463](https://github.com/google-gemini/gemini-cli/pull/24463)
|
||||
- fix: enable browser_agent in integration tests and add localhost fixture tests
|
||||
by @gsquared94 in
|
||||
[#24523](https://github.com/google-gemini/gemini-cli/pull/24523)
|
||||
- fix(browser): handle computer-use model detection for analyze_screenshot by
|
||||
@gsquared94 in
|
||||
[#24440](https://github.com/google-gemini/gemini-cli/pull/24440)
|
||||
- docs(core): add subagent tool isolation draft doc by @akh64bit in
|
||||
[#23275](https://github.com/google-gemini/gemini-cli/pull/23275)
|
||||
- fix(patch): cherry-pick 64c928f to release/v0.37.0-preview.0-pr-23257 to patch
|
||||
version v0.37.0-preview.0 and create version 0.37.0-preview.1 by
|
||||
@gemini-cli-robot in
|
||||
[#24561](https://github.com/google-gemini/gemini-cli/pull/24561)
|
||||
- fix(patch): cherry-pick cb7f7d6 to release/v0.37.0-preview.1-pr-24342 to patch
|
||||
version v0.37.0-preview.1 and create version 0.37.0-preview.2 by
|
||||
@gemini-cli-robot in
|
||||
[#24842](https://github.com/google-gemini/gemini-cli/pull/24842)
|
||||
[#24502](https://github.com/google-gemini/gemini-cli/pull/24502)
|
||||
- feat(core): Land ContextCompressionService by @joshualitt in
|
||||
[#24483](https://github.com/google-gemini/gemini-cli/pull/24483)
|
||||
- feat(core): scope subagent workspace directories via AsyncLocalStorage by
|
||||
@SandyTao520 in
|
||||
[#24445](https://github.com/google-gemini/gemini-cli/pull/24445)
|
||||
- Update ink version to 6.6.7 by @jacob314 in
|
||||
[#24514](https://github.com/google-gemini/gemini-cli/pull/24514)
|
||||
- fix(acp): handle all InvalidStreamError types gracefully in prompt by @sripasg
|
||||
in [#24540](https://github.com/google-gemini/gemini-cli/pull/24540)
|
||||
- Fix crash when vim editor is not found in PATH on Windows by
|
||||
@Nagajyothi-tammisetti in
|
||||
[#22423](https://github.com/google-gemini/gemini-cli/pull/22423)
|
||||
- fix(core): move project memory dir under tmp directory by @SandyTao520 in
|
||||
[#24542](https://github.com/google-gemini/gemini-cli/pull/24542)
|
||||
- Enable 'Other' option for yesno question type by @ruomengz in
|
||||
[#24545](https://github.com/google-gemini/gemini-cli/pull/24545)
|
||||
- fix(cli): clear stale retry/loading state after cancellation (#21096) by
|
||||
@Aaxhirrr in [#21960](https://github.com/google-gemini/gemini-cli/pull/21960)
|
||||
- Changelog for v0.37.0-preview.0 by @gemini-cli-robot in
|
||||
[#24464](https://github.com/google-gemini/gemini-cli/pull/24464)
|
||||
- feat(core): implement context-aware persistent policy approvals by @jerop in
|
||||
[#23257](https://github.com/google-gemini/gemini-cli/pull/23257)
|
||||
- docs: move agent disabling instructions and update remote agent status by
|
||||
@jackwotherspoon in
|
||||
[#24559](https://github.com/google-gemini/gemini-cli/pull/24559)
|
||||
- feat(cli): migrate nonInteractiveCli to LegacyAgentSession by @adamfweidman in
|
||||
[#22987](https://github.com/google-gemini/gemini-cli/pull/22987)
|
||||
- fix(core): unsafe type assertions in Core File System #19712 by
|
||||
@aniketsaurav18 in
|
||||
[#19739](https://github.com/google-gemini/gemini-cli/pull/19739)
|
||||
- fix(ui): hide model quota in /stats and refactor quota display by @danzaharia1
|
||||
in [#24206](https://github.com/google-gemini/gemini-cli/pull/24206)
|
||||
- Changelog for v0.36.0 by @gemini-cli-robot in
|
||||
[#24558](https://github.com/google-gemini/gemini-cli/pull/24558)
|
||||
- Changelog for v0.37.0-preview.1 by @gemini-cli-robot in
|
||||
[#24568](https://github.com/google-gemini/gemini-cli/pull/24568)
|
||||
- docs: add missing .md extensions to internal doc links by @ishaan-arora-1 in
|
||||
[#24145](https://github.com/google-gemini/gemini-cli/pull/24145)
|
||||
- fix(ui): fixed table styling by @devr0306 in
|
||||
[#24565](https://github.com/google-gemini/gemini-cli/pull/24565)
|
||||
- fix(core): pass includeDirectories to sandbox configuration by @galz10 in
|
||||
[#24573](https://github.com/google-gemini/gemini-cli/pull/24573)
|
||||
- feat(ui): enable "TerminalBuffer" mode to solve flicker by @jacob314 in
|
||||
[#24512](https://github.com/google-gemini/gemini-cli/pull/24512)
|
||||
- docs: clarify release coordination by @scidomino in
|
||||
[#24575](https://github.com/google-gemini/gemini-cli/pull/24575)
|
||||
- fix(core): remove broken PowerShell translation and fix native \_\_write in
|
||||
Windows sandbox by @scidomino in
|
||||
[#24571](https://github.com/google-gemini/gemini-cli/pull/24571)
|
||||
- Add instructions for how to start react in prod and force react to prod mode
|
||||
by @jacob314 in
|
||||
[#24590](https://github.com/google-gemini/gemini-cli/pull/24590)
|
||||
- feat(cli): minimalist sandbox status labels by @galz10 in
|
||||
[#24582](https://github.com/google-gemini/gemini-cli/pull/24582)
|
||||
- Feat/browser agent metrics by @kunal-10-cloud in
|
||||
[#24210](https://github.com/google-gemini/gemini-cli/pull/24210)
|
||||
- test: fix Windows CI execution and resolve exposed platform failures by
|
||||
@ehedlund in [#24476](https://github.com/google-gemini/gemini-cli/pull/24476)
|
||||
- feat(core,cli): prioritize summary for topics (#24608) by @Abhijit-2592 in
|
||||
[#24609](https://github.com/google-gemini/gemini-cli/pull/24609)
|
||||
- show color by @jacob314 in
|
||||
[#24613](https://github.com/google-gemini/gemini-cli/pull/24613)
|
||||
- feat(cli): enable compact tool output by default (#24509) by @jwhelangoog in
|
||||
[#24510](https://github.com/google-gemini/gemini-cli/pull/24510)
|
||||
- fix(core): inject skill system instructions into subagent prompts if activated
|
||||
by @abhipatel12 in
|
||||
[#24620](https://github.com/google-gemini/gemini-cli/pull/24620)
|
||||
- fix(core): improve windows sandbox reliability and fix integration tests by
|
||||
@ehedlund in [#24480](https://github.com/google-gemini/gemini-cli/pull/24480)
|
||||
- fix(core): ensure sandbox approvals are correctly persisted and matched for
|
||||
proactive expansions by @galz10 in
|
||||
[#24577](https://github.com/google-gemini/gemini-cli/pull/24577)
|
||||
- feat(cli) Scrollbar for input prompt by @jacob314 in
|
||||
[#21992](https://github.com/google-gemini/gemini-cli/pull/21992)
|
||||
- Do not run pr-eval workflow when no steering changes detected by @alisa-alisa
|
||||
in [#24621](https://github.com/google-gemini/gemini-cli/pull/24621)
|
||||
- Fix restoration of topic headers. by @gundermanc in
|
||||
[#24650](https://github.com/google-gemini/gemini-cli/pull/24650)
|
||||
- feat(core): discourage update topic tool for simple tasks by @Samee24 in
|
||||
[#24640](https://github.com/google-gemini/gemini-cli/pull/24640)
|
||||
- fix(core): ensure global temp directory is always in sandbox allowed paths by
|
||||
@galz10 in [#24638](https://github.com/google-gemini/gemini-cli/pull/24638)
|
||||
- fix(core): detect uninitialized lines by @jacob314 in
|
||||
[#24646](https://github.com/google-gemini/gemini-cli/pull/24646)
|
||||
- docs: update sandboxing documentation and toolSandboxing settings by @galz10
|
||||
in [#24655](https://github.com/google-gemini/gemini-cli/pull/24655)
|
||||
- feat(cli): enhance tool confirmation UI and selection layout by @galz10 in
|
||||
[#24376](https://github.com/google-gemini/gemini-cli/pull/24376)
|
||||
- feat(acp): add support for `/about` command by @sripasg in
|
||||
[#24649](https://github.com/google-gemini/gemini-cli/pull/24649)
|
||||
- feat(cli): add role specific metrics to /stats by @cynthialong0-0 in
|
||||
[#24659](https://github.com/google-gemini/gemini-cli/pull/24659)
|
||||
- split context by @jacob314 in
|
||||
[#24623](https://github.com/google-gemini/gemini-cli/pull/24623)
|
||||
- fix(cli): remove -S from shebang to fix Windows and BSD execution by
|
||||
@scidomino in [#24756](https://github.com/google-gemini/gemini-cli/pull/24756)
|
||||
- Fix issue where topic headers can be posted back to back by @gundermanc in
|
||||
[#24759](https://github.com/google-gemini/gemini-cli/pull/24759)
|
||||
- fix(core): handle partial llm_request in BeforeModel hook override by
|
||||
@krishdef7 in [#22326](https://github.com/google-gemini/gemini-cli/pull/22326)
|
||||
- fix(ui): improve narration suppression and reduce flicker by @gundermanc in
|
||||
[#24635](https://github.com/google-gemini/gemini-cli/pull/24635)
|
||||
- fix(ui): fixed auth race condition causing logo to flicker by @devr0306 in
|
||||
[#24652](https://github.com/google-gemini/gemini-cli/pull/24652)
|
||||
- fix(browser): remove premature browser cleanup after subagent invocation by
|
||||
@gsquared94 in
|
||||
[#24753](https://github.com/google-gemini/gemini-cli/pull/24753)
|
||||
- Revert "feat(core,cli): prioritize summary for topics (#24608)" by
|
||||
@Abhijit-2592 in
|
||||
[#24777](https://github.com/google-gemini/gemini-cli/pull/24777)
|
||||
- relax tool sandboxing overrides for plan mode to match defaults. by
|
||||
@DavidAPierce in
|
||||
[#24762](https://github.com/google-gemini/gemini-cli/pull/24762)
|
||||
- fix(cli): respect global environment variable allowlist by @scidomino in
|
||||
[#24767](https://github.com/google-gemini/gemini-cli/pull/24767)
|
||||
- fix(cli): ensure skills list outputs to stdout in non-interactive environments
|
||||
by @spencer426 in
|
||||
[#24566](https://github.com/google-gemini/gemini-cli/pull/24566)
|
||||
- Add an eval for and fix unsafe cloning behavior. by @gundermanc in
|
||||
[#24457](https://github.com/google-gemini/gemini-cli/pull/24457)
|
||||
- fix(policy): allow complete_task in plan mode by @abhipatel12 in
|
||||
[#24771](https://github.com/google-gemini/gemini-cli/pull/24771)
|
||||
- feat(telemetry): add browser agent clearcut metrics by @gsquared94 in
|
||||
[#24688](https://github.com/google-gemini/gemini-cli/pull/24688)
|
||||
- feat(cli): support selective topic expansion and click-to-expand by
|
||||
@Abhijit-2592 in
|
||||
[#24793](https://github.com/google-gemini/gemini-cli/pull/24793)
|
||||
- temporarily disable sandbox integration test on windows by @ehedlund in
|
||||
[#24786](https://github.com/google-gemini/gemini-cli/pull/24786)
|
||||
- Remove flakey test by @scidomino in
|
||||
[#24837](https://github.com/google-gemini/gemini-cli/pull/24837)
|
||||
- Alisa/approve button by @alisa-alisa in
|
||||
[#24645](https://github.com/google-gemini/gemini-cli/pull/24645)
|
||||
- feat(hooks): display hook system messages in UI by @mbleigh in
|
||||
[#24616](https://github.com/google-gemini/gemini-cli/pull/24616)
|
||||
- fix(core): propagate BeforeModel hook model override end-to-end by @krishdef7
|
||||
in [#24784](https://github.com/google-gemini/gemini-cli/pull/24784)
|
||||
- chore: fix formatting for behavioral eval skill reference file by @abhipatel12
|
||||
in [#24846](https://github.com/google-gemini/gemini-cli/pull/24846)
|
||||
- fix: use directory junctions on Windows for skill linking by @enjoykumawat in
|
||||
[#24823](https://github.com/google-gemini/gemini-cli/pull/24823)
|
||||
- fix(cli): prevent multiple banner increments on remount by @sehoon38 in
|
||||
[#24843](https://github.com/google-gemini/gemini-cli/pull/24843)
|
||||
- feat(acp): add /help command by @sripasg in
|
||||
[#24839](https://github.com/google-gemini/gemini-cli/pull/24839)
|
||||
- fix(core): remove tmux alternate buffer warning by @jackwotherspoon in
|
||||
[#24852](https://github.com/google-gemini/gemini-cli/pull/24852)
|
||||
- Improve sandbox error matching and caching by @DavidAPierce in
|
||||
[#24550](https://github.com/google-gemini/gemini-cli/pull/24550)
|
||||
- feat(core): add agent protocol UI types and experimental flag by @mbleigh in
|
||||
[#24275](https://github.com/google-gemini/gemini-cli/pull/24275)
|
||||
- feat(core): use experiment flags for default fetch timeouts by @yunaseoul in
|
||||
[#24261](https://github.com/google-gemini/gemini-cli/pull/24261)
|
||||
- Revert "fix(ui): improve narration suppression and reduce flicker (#2… by
|
||||
@gundermanc in
|
||||
[#24857](https://github.com/google-gemini/gemini-cli/pull/24857)
|
||||
- refactor(cli): remove duplication in interactive shell awaiting input hint by
|
||||
@JayadityaGit in
|
||||
[#24801](https://github.com/google-gemini/gemini-cli/pull/24801)
|
||||
- refactor(core): make LegacyAgentSession dependencies optional by @mbleigh in
|
||||
[#24287](https://github.com/google-gemini/gemini-cli/pull/24287)
|
||||
- Changelog for v0.37.0-preview.2 by @gemini-cli-robot in
|
||||
[#24848](https://github.com/google-gemini/gemini-cli/pull/24848)
|
||||
- fix(cli): always show shell command description or actual command by @jacob314
|
||||
in [#24774](https://github.com/google-gemini/gemini-cli/pull/24774)
|
||||
- Added flag for ept size and increased default size by @devr0306 in
|
||||
[#24859](https://github.com/google-gemini/gemini-cli/pull/24859)
|
||||
- fix(core): dispose Scheduler to prevent McpProgress listener leak by
|
||||
@Anjaligarhwal in
|
||||
[#24870](https://github.com/google-gemini/gemini-cli/pull/24870)
|
||||
- fix(cli): switch default back to terminalBuffer=false and fix regressions
|
||||
introduced for that mode by @jacob314 in
|
||||
[#24873](https://github.com/google-gemini/gemini-cli/pull/24873)
|
||||
- feat(cli): switch to ctrl+g from ctrl-x by @jacob314 in
|
||||
[#24861](https://github.com/google-gemini/gemini-cli/pull/24861)
|
||||
- fix: isolate concurrent browser agent instances by @gsquared94 in
|
||||
[#24794](https://github.com/google-gemini/gemini-cli/pull/24794)
|
||||
- docs: update MCP server OAuth redirect port documentation by @adamfweidman in
|
||||
[#24844](https://github.com/google-gemini/gemini-cli/pull/24844)
|
||||
|
||||
**Full Changelog**:
|
||||
https://github.com/google-gemini/gemini-cli/compare/v0.36.0...v0.37.1
|
||||
https://github.com/google-gemini/gemini-cli/compare/v0.38.0...v0.38.1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Preview release: v0.38.0-preview.0
|
||||
# Preview release: v0.39.0-preview.0
|
||||
|
||||
Released: April 08, 2026
|
||||
Released: April 14, 2026
|
||||
|
||||
Our preview release includes the latest, new, and experimental features. This
|
||||
release may not be as stable as our [latest weekly release](latest.md).
|
||||
@@ -13,256 +13,245 @@ npm install -g @google/gemini-cli@preview
|
||||
|
||||
## Highlights
|
||||
|
||||
- **Context Management:** Introduced a Context Compression Service to optimize
|
||||
context window usage and landed a background memory service for skill
|
||||
extraction.
|
||||
- **Enhanced Security:** Implemented context-aware persistent policy approvals
|
||||
for smarter tool permissions and enabled `web_fetch` in plan mode with user
|
||||
confirmation.
|
||||
- **Workflow Monitoring:** Added background process monitoring and inspection
|
||||
tools for better visibility into long-running tasks.
|
||||
- **UI/UX Refinements:** Enhanced the tool confirmation UI, selection layout,
|
||||
and added support for selective topic expansion and click-to-expand.
|
||||
- **Core Stability:** Improved sandbox reliability on Linux and Windows,
|
||||
resolved shebang compatibility issues, and fixed various crashes in the CLI
|
||||
and core services.
|
||||
- **Refactored Subagents and Unified Tooling:** Consolidate subagent tools into
|
||||
a single `invoke_subagent` tool, removed legacy wrapping tools, and improved
|
||||
turn limits for codebase investigator.
|
||||
- **Advanced Memory and Skill Management:** Introduced `/memory` inbox for
|
||||
reviewing extracted skills and added skill patching support, enhancing agent
|
||||
learning and persistence.
|
||||
- **Expanded Test and Evaluation Infrastructure:** Added memory and CPU
|
||||
performance integration test harnesses and generalized evaluation
|
||||
infrastructure for better suite organization.
|
||||
- **Sandbox and Security Hardening:** Centralized sandbox paths for Linux and
|
||||
macOS, enforced read-only security for async git worktree resolution, and
|
||||
optimized Windows sandbox initialization.
|
||||
- **Enhanced CLI UX and UI Stability:** Improved scroll momentum, added a
|
||||
`debugRainbow` setting, and resolved various memory leaks and PTY exhaustion
|
||||
issues for a smoother terminal experience.
|
||||
|
||||
## What's Changed
|
||||
|
||||
- fix(cli): refresh slash command list after /skills reload by @NTaylorMullen in
|
||||
[#24454](https://github.com/google-gemini/gemini-cli/pull/24454)
|
||||
- Update README.md for links. by @g-samroberts in
|
||||
[#22759](https://github.com/google-gemini/gemini-cli/pull/22759)
|
||||
- fix(core): ensure complete_task tool calls are recorded in chat history by
|
||||
@abhipatel12 in
|
||||
[#24437](https://github.com/google-gemini/gemini-cli/pull/24437)
|
||||
- feat(policy): explicitly allow web_fetch in plan mode with ask_user by
|
||||
@Adib234 in [#24456](https://github.com/google-gemini/gemini-cli/pull/24456)
|
||||
- fix(core): refactor linux sandbox to fix ARG_MAX crashes by @ehedlund in
|
||||
[#24286](https://github.com/google-gemini/gemini-cli/pull/24286)
|
||||
- feat(config): add experimental.adk.agentSessionNoninteractiveEnabled setting
|
||||
by @adamfweidman in
|
||||
[#24439](https://github.com/google-gemini/gemini-cli/pull/24439)
|
||||
- Changelog for v0.36.0-preview.8 by @gemini-cli-robot in
|
||||
[#24453](https://github.com/google-gemini/gemini-cli/pull/24453)
|
||||
- feat(cli): change default loadingPhrases to 'off' to hide tips by @keithguerin
|
||||
in [#24342](https://github.com/google-gemini/gemini-cli/pull/24342)
|
||||
- fix(cli): ensure agent stops when all declinable tools are cancelled by
|
||||
@NTaylorMullen in
|
||||
[#24479](https://github.com/google-gemini/gemini-cli/pull/24479)
|
||||
- fix(core): enhance sandbox usability and fix build error by @galz10 in
|
||||
[#24460](https://github.com/google-gemini/gemini-cli/pull/24460)
|
||||
- Terminal Serializer Optimization by @jacob314 in
|
||||
[#24485](https://github.com/google-gemini/gemini-cli/pull/24485)
|
||||
- Auto configure memory. by @jacob314 in
|
||||
[#24474](https://github.com/google-gemini/gemini-cli/pull/24474)
|
||||
- Unused error variables in catch block are not allowed by @alisa-alisa in
|
||||
[#24487](https://github.com/google-gemini/gemini-cli/pull/24487)
|
||||
- feat(core): add background memory service for skill extraction by @SandyTao520
|
||||
in [#24274](https://github.com/google-gemini/gemini-cli/pull/24274)
|
||||
- feat: implement high-signal PR regression check for evaluations by
|
||||
@alisa-alisa in
|
||||
[#23937](https://github.com/google-gemini/gemini-cli/pull/23937)
|
||||
- Fix shell output display by @jacob314 in
|
||||
[#24490](https://github.com/google-gemini/gemini-cli/pull/24490)
|
||||
- fix(ui): resolve unwanted vertical spacing around various tool output
|
||||
treatments by @jwhelangoog in
|
||||
[#24449](https://github.com/google-gemini/gemini-cli/pull/24449)
|
||||
- revert(cli): bring back input box and footer visibility in copy mode by
|
||||
@sehoon38 in [#24504](https://github.com/google-gemini/gemini-cli/pull/24504)
|
||||
- fix(cli): prevent crash in AnsiOutputText when handling non-array data by
|
||||
@sehoon38 in [#24498](https://github.com/google-gemini/gemini-cli/pull/24498)
|
||||
- feat(cli): support default values for environment variables by @ruomengz in
|
||||
[#24469](https://github.com/google-gemini/gemini-cli/pull/24469)
|
||||
- Implement background process monitoring and inspection tools by @cocosheng-g
|
||||
in [#23799](https://github.com/google-gemini/gemini-cli/pull/23799)
|
||||
- docs(browser-agent): update stale browser agent documentation by @gsquared94
|
||||
in [#24463](https://github.com/google-gemini/gemini-cli/pull/24463)
|
||||
- fix: enable browser_agent in integration tests and add localhost fixture tests
|
||||
by @gsquared94 in
|
||||
[#24523](https://github.com/google-gemini/gemini-cli/pull/24523)
|
||||
- fix(browser): handle computer-use model detection for analyze_screenshot by
|
||||
@gsquared94 in
|
||||
[#24502](https://github.com/google-gemini/gemini-cli/pull/24502)
|
||||
- feat(core): Land ContextCompressionService by @joshualitt in
|
||||
[#24483](https://github.com/google-gemini/gemini-cli/pull/24483)
|
||||
- feat(core): scope subagent workspace directories via AsyncLocalStorage by
|
||||
- refactor(plan): simplify policy priorities and consolidate read-only rules by
|
||||
@ruomengz in [#24849](https://github.com/google-gemini/gemini-cli/pull/24849)
|
||||
- feat(test-utils): add memory usage integration test harness by @sripasg in
|
||||
[#24876](https://github.com/google-gemini/gemini-cli/pull/24876)
|
||||
- feat(memory): add /memory inbox command for reviewing extracted skills by
|
||||
@SandyTao520 in
|
||||
[#24445](https://github.com/google-gemini/gemini-cli/pull/24445)
|
||||
- Update ink version to 6.6.7 by @jacob314 in
|
||||
[#24514](https://github.com/google-gemini/gemini-cli/pull/24514)
|
||||
- fix(acp): handle all InvalidStreamError types gracefully in prompt by @sripasg
|
||||
in [#24540](https://github.com/google-gemini/gemini-cli/pull/24540)
|
||||
- Fix crash when vim editor is not found in PATH on Windows by
|
||||
@Nagajyothi-tammisetti in
|
||||
[#22423](https://github.com/google-gemini/gemini-cli/pull/22423)
|
||||
- fix(core): move project memory dir under tmp directory by @SandyTao520 in
|
||||
[#24542](https://github.com/google-gemini/gemini-cli/pull/24542)
|
||||
- Enable 'Other' option for yesno question type by @ruomengz in
|
||||
[#24545](https://github.com/google-gemini/gemini-cli/pull/24545)
|
||||
- fix(cli): clear stale retry/loading state after cancellation (#21096) by
|
||||
@Aaxhirrr in [#21960](https://github.com/google-gemini/gemini-cli/pull/21960)
|
||||
- Changelog for v0.37.0-preview.0 by @gemini-cli-robot in
|
||||
[#24464](https://github.com/google-gemini/gemini-cli/pull/24464)
|
||||
- feat(core): implement context-aware persistent policy approvals by @jerop in
|
||||
[#23257](https://github.com/google-gemini/gemini-cli/pull/23257)
|
||||
- docs: move agent disabling instructions and update remote agent status by
|
||||
@jackwotherspoon in
|
||||
[#24559](https://github.com/google-gemini/gemini-cli/pull/24559)
|
||||
- feat(cli): migrate nonInteractiveCli to LegacyAgentSession by @adamfweidman in
|
||||
[#22987](https://github.com/google-gemini/gemini-cli/pull/22987)
|
||||
- fix(core): unsafe type assertions in Core File System #19712 by
|
||||
@aniketsaurav18 in
|
||||
[#19739](https://github.com/google-gemini/gemini-cli/pull/19739)
|
||||
- fix(ui): hide model quota in /stats and refactor quota display by @danzaharia1
|
||||
in [#24206](https://github.com/google-gemini/gemini-cli/pull/24206)
|
||||
- Changelog for v0.36.0 by @gemini-cli-robot in
|
||||
[#24558](https://github.com/google-gemini/gemini-cli/pull/24558)
|
||||
- Changelog for v0.37.0-preview.1 by @gemini-cli-robot in
|
||||
[#24568](https://github.com/google-gemini/gemini-cli/pull/24568)
|
||||
- docs: add missing .md extensions to internal doc links by @ishaan-arora-1 in
|
||||
[#24145](https://github.com/google-gemini/gemini-cli/pull/24145)
|
||||
- fix(ui): fixed table styling by @devr0306 in
|
||||
[#24565](https://github.com/google-gemini/gemini-cli/pull/24565)
|
||||
- fix(core): pass includeDirectories to sandbox configuration by @galz10 in
|
||||
[#24573](https://github.com/google-gemini/gemini-cli/pull/24573)
|
||||
- feat(ui): enable "TerminalBuffer" mode to solve flicker by @jacob314 in
|
||||
[#24512](https://github.com/google-gemini/gemini-cli/pull/24512)
|
||||
- docs: clarify release coordination by @scidomino in
|
||||
[#24575](https://github.com/google-gemini/gemini-cli/pull/24575)
|
||||
- fix(core): remove broken PowerShell translation and fix native \_\_write in
|
||||
Windows sandbox by @scidomino in
|
||||
[#24571](https://github.com/google-gemini/gemini-cli/pull/24571)
|
||||
- Add instructions for how to start react in prod and force react to prod mode
|
||||
by @jacob314 in
|
||||
[#24590](https://github.com/google-gemini/gemini-cli/pull/24590)
|
||||
- feat(cli): minimalist sandbox status labels by @galz10 in
|
||||
[#24582](https://github.com/google-gemini/gemini-cli/pull/24582)
|
||||
- Feat/browser agent metrics by @kunal-10-cloud in
|
||||
[#24210](https://github.com/google-gemini/gemini-cli/pull/24210)
|
||||
- test: fix Windows CI execution and resolve exposed platform failures by
|
||||
@ehedlund in [#24476](https://github.com/google-gemini/gemini-cli/pull/24476)
|
||||
- feat(core,cli): prioritize summary for topics (#24608) by @Abhijit-2592 in
|
||||
[#24609](https://github.com/google-gemini/gemini-cli/pull/24609)
|
||||
- show color by @jacob314 in
|
||||
[#24613](https://github.com/google-gemini/gemini-cli/pull/24613)
|
||||
- feat(cli): enable compact tool output by default (#24509) by @jwhelangoog in
|
||||
[#24510](https://github.com/google-gemini/gemini-cli/pull/24510)
|
||||
- fix(core): inject skill system instructions into subagent prompts if activated
|
||||
by @abhipatel12 in
|
||||
[#24620](https://github.com/google-gemini/gemini-cli/pull/24620)
|
||||
- fix(core): improve windows sandbox reliability and fix integration tests by
|
||||
@ehedlund in [#24480](https://github.com/google-gemini/gemini-cli/pull/24480)
|
||||
- fix(core): ensure sandbox approvals are correctly persisted and matched for
|
||||
proactive expansions by @galz10 in
|
||||
[#24577](https://github.com/google-gemini/gemini-cli/pull/24577)
|
||||
- feat(cli) Scrollbar for input prompt by @jacob314 in
|
||||
[#21992](https://github.com/google-gemini/gemini-cli/pull/21992)
|
||||
- Do not run pr-eval workflow when no steering changes detected by @alisa-alisa
|
||||
in [#24621](https://github.com/google-gemini/gemini-cli/pull/24621)
|
||||
- Fix restoration of topic headers. by @gundermanc in
|
||||
[#24650](https://github.com/google-gemini/gemini-cli/pull/24650)
|
||||
- feat(core): discourage update topic tool for simple tasks by @Samee24 in
|
||||
[#24640](https://github.com/google-gemini/gemini-cli/pull/24640)
|
||||
- fix(core): ensure global temp directory is always in sandbox allowed paths by
|
||||
@galz10 in [#24638](https://github.com/google-gemini/gemini-cli/pull/24638)
|
||||
- fix(core): detect uninitialized lines by @jacob314 in
|
||||
[#24646](https://github.com/google-gemini/gemini-cli/pull/24646)
|
||||
- docs: update sandboxing documentation and toolSandboxing settings by @galz10
|
||||
in [#24655](https://github.com/google-gemini/gemini-cli/pull/24655)
|
||||
- feat(cli): enhance tool confirmation UI and selection layout by @galz10 in
|
||||
[#24376](https://github.com/google-gemini/gemini-cli/pull/24376)
|
||||
- feat(acp): add support for `/about` command by @sripasg in
|
||||
[#24649](https://github.com/google-gemini/gemini-cli/pull/24649)
|
||||
- feat(cli): add role specific metrics to /stats by @cynthialong0-0 in
|
||||
[#24659](https://github.com/google-gemini/gemini-cli/pull/24659)
|
||||
- split context by @jacob314 in
|
||||
[#24623](https://github.com/google-gemini/gemini-cli/pull/24623)
|
||||
- fix(cli): remove -S from shebang to fix Windows and BSD execution by
|
||||
@scidomino in [#24756](https://github.com/google-gemini/gemini-cli/pull/24756)
|
||||
- Fix issue where topic headers can be posted back to back by @gundermanc in
|
||||
[#24759](https://github.com/google-gemini/gemini-cli/pull/24759)
|
||||
- fix(core): handle partial llm_request in BeforeModel hook override by
|
||||
@krishdef7 in [#22326](https://github.com/google-gemini/gemini-cli/pull/22326)
|
||||
- fix(ui): improve narration suppression and reduce flicker by @gundermanc in
|
||||
[#24635](https://github.com/google-gemini/gemini-cli/pull/24635)
|
||||
- fix(ui): fixed auth race condition causing logo to flicker by @devr0306 in
|
||||
[#24652](https://github.com/google-gemini/gemini-cli/pull/24652)
|
||||
- fix(browser): remove premature browser cleanup after subagent invocation by
|
||||
@gsquared94 in
|
||||
[#24753](https://github.com/google-gemini/gemini-cli/pull/24753)
|
||||
- Revert "feat(core,cli): prioritize summary for topics (#24608)" by
|
||||
@Abhijit-2592 in
|
||||
[#24777](https://github.com/google-gemini/gemini-cli/pull/24777)
|
||||
- relax tool sandboxing overrides for plan mode to match defaults. by
|
||||
@DavidAPierce in
|
||||
[#24762](https://github.com/google-gemini/gemini-cli/pull/24762)
|
||||
- fix(cli): respect global environment variable allowlist by @scidomino in
|
||||
[#24767](https://github.com/google-gemini/gemini-cli/pull/24767)
|
||||
- fix(cli): ensure skills list outputs to stdout in non-interactive environments
|
||||
[#24544](https://github.com/google-gemini/gemini-cli/pull/24544)
|
||||
- chore(release): bump version to 0.39.0-nightly.20260408.e77b22e63 by
|
||||
@gemini-cli-robot in
|
||||
[#24939](https://github.com/google-gemini/gemini-cli/pull/24939)
|
||||
- fix(core): ensure robust sandbox cleanup in all process execution paths by
|
||||
@ehedlund in [#24763](https://github.com/google-gemini/gemini-cli/pull/24763)
|
||||
- chore: update ink version to 6.6.8 by @jacob314 in
|
||||
[#24934](https://github.com/google-gemini/gemini-cli/pull/24934)
|
||||
- Changelog for v0.38.0-preview.0 by @gemini-cli-robot in
|
||||
[#24938](https://github.com/google-gemini/gemini-cli/pull/24938)
|
||||
- chore: ignore conductor directory by @JayadityaGit in
|
||||
[#22128](https://github.com/google-gemini/gemini-cli/pull/22128)
|
||||
- Changelog for v0.37.0 by @gemini-cli-robot in
|
||||
[#24940](https://github.com/google-gemini/gemini-cli/pull/24940)
|
||||
- feat(plan): require user confirmation for activate_skill in Plan Mode by
|
||||
@ruomengz in [#24946](https://github.com/google-gemini/gemini-cli/pull/24946)
|
||||
- feat(test-utils): add CPU performance integration test harness by @sripasg in
|
||||
[#24951](https://github.com/google-gemini/gemini-cli/pull/24951)
|
||||
- fix(cli-ui): enable Ctrl+Backspace for word deletion in Windows Terminal by
|
||||
@dogukanozen in
|
||||
[#21447](https://github.com/google-gemini/gemini-cli/pull/21447)
|
||||
- test(sdk): add unit tests for GeminiCliSession by @AdamyaSingh7 in
|
||||
[#21897](https://github.com/google-gemini/gemini-cli/pull/21897)
|
||||
- fix(core): resolve windows symlink bypass and stabilize sandbox integration
|
||||
tests by @ehedlund in
|
||||
[#24834](https://github.com/google-gemini/gemini-cli/pull/24834)
|
||||
- fix(cli): restore file path display in edit and write tool confirmations by
|
||||
@jwhelangoog in
|
||||
[#24974](https://github.com/google-gemini/gemini-cli/pull/24974)
|
||||
- feat(core): refine shell tool description display logic by @jwhelangoog in
|
||||
[#24903](https://github.com/google-gemini/gemini-cli/pull/24903)
|
||||
- fix(core): dynamic session ID injection to resolve resume bugs by @scidomino
|
||||
in [#24972](https://github.com/google-gemini/gemini-cli/pull/24972)
|
||||
- Update ink version to 6.6.9 by @jacob314 in
|
||||
[#24980](https://github.com/google-gemini/gemini-cli/pull/24980)
|
||||
- Generalize evals infra to support more types of evals, organization and
|
||||
queuing of named suites by @gundermanc in
|
||||
[#24941](https://github.com/google-gemini/gemini-cli/pull/24941)
|
||||
- fix(cli): optimize startup with lightweight parent process by @sehoon38 in
|
||||
[#24667](https://github.com/google-gemini/gemini-cli/pull/24667)
|
||||
- refactor(sandbox): use centralized sandbox paths in macOS Seatbelt
|
||||
implementation by @ehedlund in
|
||||
[#24984](https://github.com/google-gemini/gemini-cli/pull/24984)
|
||||
- feat(cli): refine tool output formatting for compact mode by @jwhelangoog in
|
||||
[#24677](https://github.com/google-gemini/gemini-cli/pull/24677)
|
||||
- fix(sdk): skip broken sendStream tests to unblock nightly by @SandyTao520 in
|
||||
[#25000](https://github.com/google-gemini/gemini-cli/pull/25000)
|
||||
- refactor(core): use centralized path resolution for Linux sandbox by @ehedlund
|
||||
in [#24985](https://github.com/google-gemini/gemini-cli/pull/24985)
|
||||
- Support ctrl+shift+g by @jacob314 in
|
||||
[#25035](https://github.com/google-gemini/gemini-cli/pull/25035)
|
||||
- feat(core): refactor subagent tool to unified invoke_subagent tool by
|
||||
@abhipatel12 in
|
||||
[#24489](https://github.com/google-gemini/gemini-cli/pull/24489)
|
||||
- fix(core): add explicit git identity env vars to prevent sandbox checkpointing
|
||||
error by @mrpmohiburrahman in
|
||||
[#19775](https://github.com/google-gemini/gemini-cli/pull/19775)
|
||||
- fix: respect hideContextPercentage when FooterConfigDialog is closed without
|
||||
changes by @chernistry in
|
||||
[#24773](https://github.com/google-gemini/gemini-cli/pull/24773)
|
||||
- fix(cli): suppress unhandled AbortError logs during request cancellation by
|
||||
@euxaristia in
|
||||
[#22621](https://github.com/google-gemini/gemini-cli/pull/22621)
|
||||
- Automated documentation audit by @g-samroberts in
|
||||
[#24567](https://github.com/google-gemini/gemini-cli/pull/24567)
|
||||
- feat(cli): implement useAgentStream hook by @mbleigh in
|
||||
[#24292](https://github.com/google-gemini/gemini-cli/pull/24292)
|
||||
- refactor(plan) Clean default plan toml by @ruomengz in
|
||||
[#25037](https://github.com/google-gemini/gemini-cli/pull/25037)
|
||||
- refactor(core): remove legacy subagent wrapping tools by @abhipatel12 in
|
||||
[#25053](https://github.com/google-gemini/gemini-cli/pull/25053)
|
||||
- fix(core): honor retryDelay in RetryInfo for 503 errors by @yunaseoul in
|
||||
[#25057](https://github.com/google-gemini/gemini-cli/pull/25057)
|
||||
- fix(core): remediate subagent memory leaks using AbortSignal in MessageBus by
|
||||
@abhipatel12 in
|
||||
[#25048](https://github.com/google-gemini/gemini-cli/pull/25048)
|
||||
- feat(cli): wire up useAgentStream in AppContainer by @mbleigh in
|
||||
[#24297](https://github.com/google-gemini/gemini-cli/pull/24297)
|
||||
- feat(core): migrate chat recording to JSONL streaming by @spencer426 in
|
||||
[#23749](https://github.com/google-gemini/gemini-cli/pull/23749)
|
||||
- fix(core): clear 5-minute timeouts in oauth flow to prevent memory leaks by
|
||||
@spencer426 in
|
||||
[#24968](https://github.com/google-gemini/gemini-cli/pull/24968)
|
||||
- fix(sandbox): centralize async git worktree resolution and enforce read-only
|
||||
security by @ehedlund in
|
||||
[#25040](https://github.com/google-gemini/gemini-cli/pull/25040)
|
||||
- feat(test): add high-volume shell test and refine perf harness by @sripasg in
|
||||
[#24983](https://github.com/google-gemini/gemini-cli/pull/24983)
|
||||
- fix(core): silently handle EPERM when listing dir structure by @scidomino in
|
||||
[#25066](https://github.com/google-gemini/gemini-cli/pull/25066)
|
||||
- Changelog for v0.37.1 by @gemini-cli-robot in
|
||||
[#25055](https://github.com/google-gemini/gemini-cli/pull/25055)
|
||||
- fix: decode Uint8Array and multi-byte UTF-8 in API error messages by
|
||||
@kimjune01 in [#23341](https://github.com/google-gemini/gemini-cli/pull/23341)
|
||||
- Automated documentation audit results by @g-samroberts in
|
||||
[#22755](https://github.com/google-gemini/gemini-cli/pull/22755)
|
||||
- debugging(ui): add optional debugRainbow setting by @jacob314 in
|
||||
[#25088](https://github.com/google-gemini/gemini-cli/pull/25088)
|
||||
- fix: resolve lifecycle memory leaks by cleaning up listeners and root closures
|
||||
by @spencer426 in
|
||||
[#24566](https://github.com/google-gemini/gemini-cli/pull/24566)
|
||||
- Add an eval for and fix unsafe cloning behavior. by @gundermanc in
|
||||
[#24457](https://github.com/google-gemini/gemini-cli/pull/24457)
|
||||
- fix(policy): allow complete_task in plan mode by @abhipatel12 in
|
||||
[#24771](https://github.com/google-gemini/gemini-cli/pull/24771)
|
||||
- feat(telemetry): add browser agent clearcut metrics by @gsquared94 in
|
||||
[#24688](https://github.com/google-gemini/gemini-cli/pull/24688)
|
||||
- feat(cli): support selective topic expansion and click-to-expand by
|
||||
@Abhijit-2592 in
|
||||
[#24793](https://github.com/google-gemini/gemini-cli/pull/24793)
|
||||
- temporarily disable sandbox integration test on windows by @ehedlund in
|
||||
[#24786](https://github.com/google-gemini/gemini-cli/pull/24786)
|
||||
- Remove flakey test by @scidomino in
|
||||
[#24837](https://github.com/google-gemini/gemini-cli/pull/24837)
|
||||
- Alisa/approve button by @alisa-alisa in
|
||||
[#24645](https://github.com/google-gemini/gemini-cli/pull/24645)
|
||||
- feat(hooks): display hook system messages in UI by @mbleigh in
|
||||
[#24616](https://github.com/google-gemini/gemini-cli/pull/24616)
|
||||
- fix(core): propagate BeforeModel hook model override end-to-end by @krishdef7
|
||||
in [#24784](https://github.com/google-gemini/gemini-cli/pull/24784)
|
||||
- chore: fix formatting for behavioral eval skill reference file by @abhipatel12
|
||||
in [#24846](https://github.com/google-gemini/gemini-cli/pull/24846)
|
||||
- fix: use directory junctions on Windows for skill linking by @enjoykumawat in
|
||||
[#24823](https://github.com/google-gemini/gemini-cli/pull/24823)
|
||||
- fix(cli): prevent multiple banner increments on remount by @sehoon38 in
|
||||
[#24843](https://github.com/google-gemini/gemini-cli/pull/24843)
|
||||
- feat(acp): add /help command by @sripasg in
|
||||
[#24839](https://github.com/google-gemini/gemini-cli/pull/24839)
|
||||
- fix(core): remove tmux alternate buffer warning by @jackwotherspoon in
|
||||
[#24852](https://github.com/google-gemini/gemini-cli/pull/24852)
|
||||
- Improve sandbox error matching and caching by @DavidAPierce in
|
||||
[#24550](https://github.com/google-gemini/gemini-cli/pull/24550)
|
||||
- feat(core): add agent protocol UI types and experimental flag by @mbleigh in
|
||||
[#24275](https://github.com/google-gemini/gemini-cli/pull/24275)
|
||||
- feat(core): use experiment flags for default fetch timeouts by @yunaseoul in
|
||||
[#24261](https://github.com/google-gemini/gemini-cli/pull/24261)
|
||||
- Revert "fix(ui): improve narration suppression and reduce flicker (#2… by
|
||||
[#25049](https://github.com/google-gemini/gemini-cli/pull/25049)
|
||||
- docs(cli): updates f12 description to be more precise by @JayadityaGit in
|
||||
[#15816](https://github.com/google-gemini/gemini-cli/pull/15816)
|
||||
- fix(cli): mark /settings as unsafe to run concurrently by @jacob314 in
|
||||
[#25061](https://github.com/google-gemini/gemini-cli/pull/25061)
|
||||
- fix(core): remove buffer slice to prevent OOM on large output streams by
|
||||
@spencer426 in
|
||||
[#25094](https://github.com/google-gemini/gemini-cli/pull/25094)
|
||||
- feat(core): persist subagent agentId in tool call records by @abhipatel12 in
|
||||
[#25092](https://github.com/google-gemini/gemini-cli/pull/25092)
|
||||
- chore(core): increase codebase investigator turn limits to 50 by @abhipatel12
|
||||
in [#25125](https://github.com/google-gemini/gemini-cli/pull/25125)
|
||||
- refactor(core): consolidate execute() arguments into ExecuteOptions by
|
||||
@mbleigh in [#25101](https://github.com/google-gemini/gemini-cli/pull/25101)
|
||||
- feat(core): add Strategic Re-evaluation guidance to system prompt by
|
||||
@aishaneeshah in
|
||||
[#25062](https://github.com/google-gemini/gemini-cli/pull/25062)
|
||||
- fix(core): preserve shell execution config fields on update by
|
||||
@jasonmatthewsuhari in
|
||||
[#25113](https://github.com/google-gemini/gemini-cli/pull/25113)
|
||||
- docs: add vi shortcuts and clarify MCP sandbox setup by @chrisjcthomas in
|
||||
[#21679](https://github.com/google-gemini/gemini-cli/pull/21679)
|
||||
- fix(cli): pass session id to interactive shell executions by
|
||||
@jasonmatthewsuhari in
|
||||
[#25114](https://github.com/google-gemini/gemini-cli/pull/25114)
|
||||
- fix(cli): resolve text sanitization data loss due to C1 control characters by
|
||||
@euxaristia in
|
||||
[#22624](https://github.com/google-gemini/gemini-cli/pull/22624)
|
||||
- feat(core): add large memory regression test by @cynthialong0-0 in
|
||||
[#25059](https://github.com/google-gemini/gemini-cli/pull/25059)
|
||||
- fix(core): resolve PTY exhaustion and orphan MCP subprocess leaks by
|
||||
@spencer426 in
|
||||
[#25079](https://github.com/google-gemini/gemini-cli/pull/25079)
|
||||
- chore(deps): update vulnerable dependencies via npm audit fix by @scidomino in
|
||||
[#25140](https://github.com/google-gemini/gemini-cli/pull/25140)
|
||||
- perf(sandbox): optimize Windows sandbox initialization via native ACL
|
||||
application by @ehedlund in
|
||||
[#25077](https://github.com/google-gemini/gemini-cli/pull/25077)
|
||||
- chore: switch from keytar to @github/keytar by @cocosheng-g in
|
||||
[#25143](https://github.com/google-gemini/gemini-cli/pull/25143)
|
||||
- fix: improve audio MIME normalization and validation in file reads by
|
||||
@junaiddshaukat in
|
||||
[#21636](https://github.com/google-gemini/gemini-cli/pull/21636)
|
||||
- docs: Update docs-audit to include changes in PR body by @g-samroberts in
|
||||
[#25153](https://github.com/google-gemini/gemini-cli/pull/25153)
|
||||
- docs: correct documentation for enforced authentication type by @cocosheng-g
|
||||
in [#25142](https://github.com/google-gemini/gemini-cli/pull/25142)
|
||||
- fix(cli): exclude update_topic from confirmation queue count by @Abhijit-2592
|
||||
in [#24945](https://github.com/google-gemini/gemini-cli/pull/24945)
|
||||
- Memory fix for trace's streamWrapper. by @anthraxmilkshake in
|
||||
[#25089](https://github.com/google-gemini/gemini-cli/pull/25089)
|
||||
- fix(core): fix quota footer for non-auto models and improve display by
|
||||
@jackwotherspoon in
|
||||
[#25121](https://github.com/google-gemini/gemini-cli/pull/25121)
|
||||
- docs(contributing): clarify self-assignment policy for issues by @jmr in
|
||||
[#23087](https://github.com/google-gemini/gemini-cli/pull/23087)
|
||||
- feat(core): add skill patching support with /memory inbox integration by
|
||||
@SandyTao520 in
|
||||
[#25148](https://github.com/google-gemini/gemini-cli/pull/25148)
|
||||
- Stop suppressing thoughts and text in model response by @gundermanc in
|
||||
[#25073](https://github.com/google-gemini/gemini-cli/pull/25073)
|
||||
- fix(release): prefix git hash in nightly versions to prevent semver
|
||||
normalization by @SandyTao520 in
|
||||
[#25304](https://github.com/google-gemini/gemini-cli/pull/25304)
|
||||
- feat(cli): extract QuotaContext and resolve infinite render loop by @Adib234
|
||||
in [#24959](https://github.com/google-gemini/gemini-cli/pull/24959)
|
||||
- refactor(core): extract and centralize sandbox path utilities by @ehedlund in
|
||||
[#25305](https://github.com/google-gemini/gemini-cli/pull/25305)
|
||||
- feat(ui): added enhancements to scroll momentum by @devr0306 in
|
||||
[#24447](https://github.com/google-gemini/gemini-cli/pull/24447)
|
||||
- fix(core): replace custom binary detection with isbinaryfile to correctly
|
||||
handle UTF-8 (U+FFFD) by @Anjaligarhwal in
|
||||
[#25297](https://github.com/google-gemini/gemini-cli/pull/25297)
|
||||
- feat(agent): implement tool-controlled display protocol (Steps 2-3) by
|
||||
@mbleigh in [#25134](https://github.com/google-gemini/gemini-cli/pull/25134)
|
||||
- Stop showing scrollbar unless we are in terminalBuffer mode by @jacob314 in
|
||||
[#25320](https://github.com/google-gemini/gemini-cli/pull/25320)
|
||||
- feat: support auth block in MCP servers config in agents by @TanmayVartak in
|
||||
[#24770](https://github.com/google-gemini/gemini-cli/pull/24770)
|
||||
- fix(core): expose GEMINI_PLANS_DIR to hook environment by @Adib234 in
|
||||
[#25296](https://github.com/google-gemini/gemini-cli/pull/25296)
|
||||
- feat(core): implement silent fallback for Plan Mode model routing by @jerop in
|
||||
[#25317](https://github.com/google-gemini/gemini-cli/pull/25317)
|
||||
- fix: correct redirect count increment in fetchJson by @KevinZhao in
|
||||
[#24896](https://github.com/google-gemini/gemini-cli/pull/24896)
|
||||
- fix(core): prevent secondary crash in ModelRouterService finally block by
|
||||
@gundermanc in
|
||||
[#24857](https://github.com/google-gemini/gemini-cli/pull/24857)
|
||||
- refactor(cli): remove duplication in interactive shell awaiting input hint by
|
||||
@JayadityaGit in
|
||||
[#24801](https://github.com/google-gemini/gemini-cli/pull/24801)
|
||||
- refactor(core): make LegacyAgentSession dependencies optional by @mbleigh in
|
||||
[#24287](https://github.com/google-gemini/gemini-cli/pull/24287)
|
||||
- Changelog for v0.37.0-preview.2 by @gemini-cli-robot in
|
||||
[#24848](https://github.com/google-gemini/gemini-cli/pull/24848)
|
||||
- fix(cli): always show shell command description or actual command by @jacob314
|
||||
in [#24774](https://github.com/google-gemini/gemini-cli/pull/24774)
|
||||
- Added flag for ept size and increased default size by @devr0306 in
|
||||
[#24859](https://github.com/google-gemini/gemini-cli/pull/24859)
|
||||
- fix(core): dispose Scheduler to prevent McpProgress listener leak by
|
||||
@Anjaligarhwal in
|
||||
[#24870](https://github.com/google-gemini/gemini-cli/pull/24870)
|
||||
- fix(cli): switch default back to terminalBuffer=false and fix regressions
|
||||
introduced for that mode by @jacob314 in
|
||||
[#24873](https://github.com/google-gemini/gemini-cli/pull/24873)
|
||||
- feat(cli): switch to ctrl+g from ctrl-x by @jacob314 in
|
||||
[#24861](https://github.com/google-gemini/gemini-cli/pull/24861)
|
||||
- fix: isolate concurrent browser agent instances by @gsquared94 in
|
||||
[#24794](https://github.com/google-gemini/gemini-cli/pull/24794)
|
||||
- docs: update MCP server OAuth redirect port documentation by @adamfweidman in
|
||||
[#24844](https://github.com/google-gemini/gemini-cli/pull/24844)
|
||||
[#25333](https://github.com/google-gemini/gemini-cli/pull/25333)
|
||||
- feat(core): introduce decoupled ContextManager and Sidecar architecture by
|
||||
@joshualitt in
|
||||
[#24752](https://github.com/google-gemini/gemini-cli/pull/24752)
|
||||
- docs(core): update generalist agent documentation by @abhipatel12 in
|
||||
[#25325](https://github.com/google-gemini/gemini-cli/pull/25325)
|
||||
- chore(mcp): check MCP error code over brittle string match by @jackwotherspoon
|
||||
in [#25381](https://github.com/google-gemini/gemini-cli/pull/25381)
|
||||
- feat(plan): update plan mode prompt to allow showing plan content by @ruomengz
|
||||
in [#25058](https://github.com/google-gemini/gemini-cli/pull/25058)
|
||||
- test(core): improve sandbox integration test coverage and fix OS-specific
|
||||
failures by @ehedlund in
|
||||
[#25307](https://github.com/google-gemini/gemini-cli/pull/25307)
|
||||
- fix(core): use debug level for keychain fallback logging by @ehedlund in
|
||||
[#25398](https://github.com/google-gemini/gemini-cli/pull/25398)
|
||||
- feat(test): add a performance test in asian language by @cynthialong0-0 in
|
||||
[#25392](https://github.com/google-gemini/gemini-cli/pull/25392)
|
||||
- feat(cli): enable mouse clicking for cursor positioning in AskUser multi-line
|
||||
answers by @Adib234 in
|
||||
[#24630](https://github.com/google-gemini/gemini-cli/pull/24630)
|
||||
- fix(core): detect kmscon terminal as supporting true color by @claygeo in
|
||||
[#25282](https://github.com/google-gemini/gemini-cli/pull/25282)
|
||||
- ci: add agent session drift check workflow by @adamfweidman in
|
||||
[#25389](https://github.com/google-gemini/gemini-cli/pull/25389)
|
||||
- use macos-latest-large runner where applicable. by @scidomino in
|
||||
[#25413](https://github.com/google-gemini/gemini-cli/pull/25413)
|
||||
- Changelog for v0.37.2 by @gemini-cli-robot in
|
||||
[#25336](https://github.com/google-gemini/gemini-cli/pull/25336)
|
||||
|
||||
**Full Changelog**:
|
||||
https://github.com/google-gemini/gemini-cli/compare/v0.37.0-preview.2...v0.38.0-preview.0
|
||||
https://github.com/google-gemini/gemini-cli/compare/v0.38.0-preview.0...v0.39.0-preview.0
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
# Auto Memory
|
||||
|
||||
Auto Memory is an experimental feature that mines your past Gemini CLI sessions
|
||||
in the background and turns recurring workflows into reusable
|
||||
[Agent Skills](./skills.md). You review, accept, or discard each extracted skill
|
||||
before it becomes available to future sessions.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!NOTE]
|
||||
> This is an experimental feature currently under active development.
|
||||
|
||||
## Overview
|
||||
|
||||
Every session you run with Gemini CLI is recorded locally as a transcript. Auto
|
||||
Memory scans those transcripts for procedural patterns that recur across
|
||||
sessions, then drafts each pattern as a `SKILL.md` file in a project-local
|
||||
inbox. You inspect the draft, decide whether it captures real expertise, and
|
||||
promote it to your global or workspace skills directory if you want it.
|
||||
|
||||
You'll use Auto Memory when you want to:
|
||||
|
||||
- **Capture team workflows** that you find yourself walking the agent through
|
||||
more than once.
|
||||
- **Codify hard-won fixes** for project-specific landmines so future sessions
|
||||
avoid them.
|
||||
- **Bootstrap a skills library** without writing every `SKILL.md` by hand.
|
||||
|
||||
Auto Memory complements—but does not replace—the
|
||||
[`save_memory` tool](../tools/memory.md), which captures single facts into
|
||||
`GEMINI.md`. Auto Memory captures multi-step procedures into skills.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Gemini CLI installed and authenticated.
|
||||
- At least 10 user messages across recent, idle sessions in the project. Auto
|
||||
Memory ignores active or trivial sessions.
|
||||
|
||||
## How to enable Auto Memory
|
||||
|
||||
Auto Memory is off by default. Enable it in your settings file:
|
||||
|
||||
1. Open your global settings file at `~/.gemini/settings.json`. If you only
|
||||
want Auto Memory in one project, edit `.gemini/settings.json` in that
|
||||
project instead.
|
||||
|
||||
2. Add the experimental flag:
|
||||
|
||||
```json
|
||||
{
|
||||
"experimental": {
|
||||
"autoMemory": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Restart Gemini CLI. The flag requires a restart because the extraction
|
||||
service starts during session boot.
|
||||
|
||||
## How Auto Memory works
|
||||
|
||||
Auto Memory runs as a background task on session startup. It does not block the
|
||||
UI, consume your interactive turns, or surface tool prompts.
|
||||
|
||||
1. **Eligibility scan.** The service indexes recent sessions from
|
||||
`~/.gemini/tmp/<project>/chats/`. Sessions are eligible only if they have
|
||||
been idle for at least three hours and contain at least 10 user messages.
|
||||
2. **Lock acquisition.** A lock file in the project's memory directory
|
||||
coordinates across multiple CLI instances so extraction runs at most once at
|
||||
a time.
|
||||
3. **Sub-agent extraction.** A specialized sub-agent (named `confucius`)
|
||||
reviews the session index, reads any sessions that look like they contain
|
||||
repeated procedural workflows, and drafts new `SKILL.md` files. Its
|
||||
instructions tell it to default to creating zero skills unless the evidence
|
||||
is strong, so most runs produce no inbox items.
|
||||
4. **Patch validation.** If the sub-agent proposes edits to skills outside the
|
||||
inbox (for example, an existing global skill), it writes a unified diff
|
||||
`.patch` file. Auto Memory dry-runs each patch and discards any that do not
|
||||
apply cleanly.
|
||||
5. **Notification.** When a run produces new skills or patches, Gemini CLI
|
||||
surfaces an inline message telling you how many items are waiting.
|
||||
|
||||
## How to review extracted skills
|
||||
|
||||
Use the `/memory inbox` slash command to open the inbox dialog at any time:
|
||||
|
||||
**Command:** `/memory inbox`
|
||||
|
||||
The dialog lists each draft skill with its name, description, and source
|
||||
sessions. From there you can:
|
||||
|
||||
- **Read** the full `SKILL.md` body before deciding.
|
||||
- **Promote** a skill to your user (`~/.gemini/skills/`) or workspace
|
||||
(`.gemini/skills/`) directory.
|
||||
- **Discard** a skill you do not want.
|
||||
- **Apply** or reject a `.patch` proposal against an existing skill.
|
||||
|
||||
Promoted skills become discoverable in the next session and follow the standard
|
||||
[skill discovery precedence](./skills.md#skill-discovery-tiers).
|
||||
|
||||
## How to disable Auto Memory
|
||||
|
||||
To turn off background extraction, set the flag back to `false` in your settings
|
||||
file and restart Gemini CLI:
|
||||
|
||||
```json
|
||||
{
|
||||
"experimental": {
|
||||
"autoMemory": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Disabling the flag stops the background service immediately on the next session
|
||||
start. Existing inbox items remain on disk; you can either drain them with
|
||||
`/memory inbox` first or remove the project memory directory manually.
|
||||
|
||||
## Data and privacy
|
||||
|
||||
- Auto Memory only reads session files that already exist locally on your
|
||||
machine. Nothing is uploaded to Gemini outside the normal API calls the
|
||||
extraction sub-agent makes during its run.
|
||||
- The sub-agent is instructed to redact secrets, tokens, and credentials it
|
||||
encounters and to never copy large tool outputs verbatim.
|
||||
- Drafted skills live in your project's memory directory until you promote or
|
||||
discard them. They are not automatically loaded into any session.
|
||||
|
||||
## Limitations
|
||||
|
||||
- The sub-agent runs on a preview Gemini Flash model. Extraction quality depends
|
||||
on the model's ability to recognize durable patterns versus one-off incidents.
|
||||
- Auto Memory does not extract skills from the current session. It only
|
||||
considers sessions that have been idle for three hours or more.
|
||||
- Inbox items are stored per project. Skills extracted in one workspace are not
|
||||
visible from another until you promote them to the user-scope skills
|
||||
directory.
|
||||
|
||||
## Next steps
|
||||
|
||||
- Learn how skills are discovered and activated in [Agent Skills](./skills.md).
|
||||
- Explore the [memory management tutorial](./tutorials/memory-management.md) for
|
||||
the complementary `save_memory` and `GEMINI.md` workflows.
|
||||
- Review the experimental settings catalog in
|
||||
[Settings](./settings.md#experimental).
|
||||
@@ -5,6 +5,9 @@ and parameters.
|
||||
|
||||
## CLI commands
|
||||
|
||||
Gemini CLI provides a range of commands for starting sessions, updating the
|
||||
application, and managing extensions and MCP servers.
|
||||
|
||||
| Command | Description | Example |
|
||||
| ---------------------------------- | ---------------------------------- | ------------------------------------------------------------ |
|
||||
| `gemini` | Start interactive REPL | `gemini` |
|
||||
@@ -17,10 +20,14 @@ and parameters.
|
||||
| `gemini -r "<session-id>" "query"` | Resume session by ID | `gemini -r "abc123" "Finish this PR"` |
|
||||
| `gemini update` | Update to latest version | `gemini update` |
|
||||
| `gemini extensions` | Manage extensions | See [Extensions Management](#extensions-management) |
|
||||
| `gemini hooks` | Manage hooks | See [Hooks Management](#hooks-management) |
|
||||
| `gemini mcp` | Configure MCP servers | See [MCP Server Management](#mcp-server-management) |
|
||||
| `gemini skills` | Manage agent skills | See [Skills Management](#skills-management) |
|
||||
|
||||
### Positional arguments
|
||||
|
||||
Use positional arguments to provide a prompt directly from the command line.
|
||||
|
||||
| Argument | Type | Description |
|
||||
| -------- | ----------------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| `query` | string (variadic) | Positional prompt. Defaults to interactive mode in a TTY. Use `-p/--prompt` for non-interactive execution. |
|
||||
@@ -42,6 +49,8 @@ These commands are available within the interactive REPL.
|
||||
|
||||
## CLI Options
|
||||
|
||||
Configure the behavior of Gemini CLI using these command-line options.
|
||||
|
||||
| Option | Alias | Type | Default | Description |
|
||||
| -------------------------------- | ----- | ------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `--debug` | `-d` | boolean | `false` | Run in debug mode with verbose logging |
|
||||
@@ -85,6 +94,8 @@ These are convenient shortcuts that map to specific models:
|
||||
|
||||
## Extensions management
|
||||
|
||||
Manage your Gemini CLI extensions with these commands.
|
||||
|
||||
| Command | Description | Example |
|
||||
| -------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------ |
|
||||
| `gemini extensions install <source>` | Install extension from Git URL or local path | `gemini extensions install https://github.com/user/my-extension` |
|
||||
@@ -99,11 +110,24 @@ These are convenient shortcuts that map to specific models:
|
||||
| `gemini extensions link <path>` | Link local extension for development | `gemini extensions link /path/to/extension` |
|
||||
| `gemini extensions new <path>` | Create new extension from template | `gemini extensions new ./my-extension` |
|
||||
| `gemini extensions validate <path>` | Validate extension structure | `gemini extensions validate ./my-extension` |
|
||||
| `gemini extensions configure <name>` | Configure an extension | `gemini extensions configure my-extension` |
|
||||
|
||||
See [Extensions Documentation](../extensions/index.md) for more details.
|
||||
|
||||
## Hooks management
|
||||
|
||||
Manage your Gemini CLI hooks with these commands.
|
||||
|
||||
| Command | Description | Example |
|
||||
| ---------------------- | -------------------- | ---------------------- |
|
||||
| `gemini hooks migrate` | Migrate legacy hooks | `gemini hooks migrate` |
|
||||
|
||||
See [Hooks Documentation](../hooks/index.md) for more details.
|
||||
|
||||
## MCP server management
|
||||
|
||||
Manage your Model Context Protocol (MCP) servers with these commands.
|
||||
|
||||
| Command | Description | Example |
|
||||
| ------------------------------------------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
||||
| `gemini mcp add <name> <command>` | Add stdio-based MCP server | `gemini mcp add github npx -y @modelcontextprotocol/server-github` |
|
||||
@@ -113,11 +137,15 @@ See [Extensions Documentation](../extensions/index.md) for more details.
|
||||
| `gemini mcp add <name> <command> --include-tools tool1,tool2` | Add with specific tools | `gemini mcp add github npx -y @modelcontextprotocol/server-github --include-tools list_repos,get_pr` |
|
||||
| `gemini mcp remove <name>` | Remove an MCP server | `gemini mcp remove github` |
|
||||
| `gemini mcp list` | List all configured MCP servers | `gemini mcp list` |
|
||||
| `gemini mcp enable <name>` | Enable an MCP server | `gemini mcp enable github` |
|
||||
| `gemini mcp disable <name>` | Disable an MCP server | `gemini mcp disable github` |
|
||||
|
||||
See [MCP Server Integration](../tools/mcp-server.md) for more details.
|
||||
|
||||
## Skills management
|
||||
|
||||
Manage your agent skills with these commands.
|
||||
|
||||
| Command | Description | Example |
|
||||
| -------------------------------- | ------------------------------------- | ------------------------------------------------- |
|
||||
| `gemini skills list` | List all discovered agent skills | `gemini skills list` |
|
||||
|
||||
@@ -507,7 +507,7 @@ events. For more information, see the [telemetry documentation](./telemetry.md).
|
||||
You can enforce a specific authentication method for all users by setting the
|
||||
`security.auth.enforcedType` in the system-level `settings.json` file. This
|
||||
prevents users from choosing a different authentication method. See the
|
||||
[Authentication docs](../get-started/authentication.md) for more details.
|
||||
[Authentication docs](../get-started/authentication.mdx) for more details.
|
||||
|
||||
**Example:** Enforce the use of Google login for all users.
|
||||
|
||||
|
||||
@@ -130,7 +130,9 @@ These are the only allowed tools:
|
||||
[`cli_help`](../core/subagents.md#cli-help-agent)
|
||||
- **Interaction:** [`ask_user`](../tools/ask-user.md)
|
||||
- **MCP tools (Read):** Read-only [MCP tools](../tools/mcp-server.md) (for
|
||||
example, `github_read_issue`, `postgres_read_schema`) are allowed.
|
||||
example, `github_read_issue`, `postgres_read_schema`) and core
|
||||
[MCP resource tools](../tools/mcp-resources.md) (`list_mcp_resources`,
|
||||
`read_mcp_resource`) are allowed.
|
||||
- **Planning (Write):**
|
||||
[`write_file`](../tools/file-system.md#3-write_file-writefile) and
|
||||
[`replace`](../tools/file-system.md#6-replace-edit) only allowed for `.md`
|
||||
|
||||
@@ -24,20 +24,22 @@ they appear in the UI.
|
||||
|
||||
### General
|
||||
|
||||
| UI Label | Setting | Description | Default |
|
||||
| ----------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
|
||||
| Vim Mode | `general.vimMode` | Enable Vim keybindings | `false` |
|
||||
| Default Approval Mode | `general.defaultApprovalMode` | The default approval mode for tool execution. 'default' prompts for approval, 'auto_edit' auto-approves edit tools, and 'plan' is read-only mode. YOLO mode (auto-approve all actions) can only be enabled via command line (--yolo or --approval-mode=yolo). | `"default"` |
|
||||
| Enable Auto Update | `general.enableAutoUpdate` | Enable automatic updates. | `true` |
|
||||
| Enable Notifications | `general.enableNotifications` | Enable run-event notifications for action-required prompts and session completion. | `false` |
|
||||
| Enable Plan Mode | `general.plan.enabled` | Enable Plan Mode for read-only safety during planning. | `true` |
|
||||
| Plan Directory | `general.plan.directory` | The directory where planning artifacts are stored. If not specified, defaults to the system temporary directory. A custom directory requires a policy to allow write access in Plan Mode. | `undefined` |
|
||||
| Plan Model Routing | `general.plan.modelRouting` | Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pro for the planning phase and Flash for the implementation phase. | `true` |
|
||||
| Retry Fetch Errors | `general.retryFetchErrors` | Retry on "exception TypeError: fetch failed sending request" errors. | `true` |
|
||||
| Max Chat Model Attempts | `general.maxAttempts` | Maximum number of attempts for requests to the main chat model. Cannot exceed 10. | `10` |
|
||||
| Debug Keystroke Logging | `general.debugKeystrokeLogging` | Enable debug logging of keystrokes to the console. | `false` |
|
||||
| Enable Session Cleanup | `general.sessionRetention.enabled` | Enable automatic session cleanup | `true` |
|
||||
| Keep chat history | `general.sessionRetention.maxAge` | Automatically delete chats older than this time period (e.g., "30d", "7d", "24h", "1w") | `"30d"` |
|
||||
| UI Label | Setting | Description | Default |
|
||||
| ----------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
|
||||
| Vim Mode | `general.vimMode` | Enable Vim keybindings | `false` |
|
||||
| Default Approval Mode | `general.defaultApprovalMode` | The default approval mode for tool execution. 'default' prompts for approval, 'auto_edit' auto-approves edit tools, and 'plan' is read-only mode. YOLO mode (auto-approve all actions) can only be enabled via command line (--yolo or --approval-mode=yolo). | `"default"` |
|
||||
| Enable Auto Update | `general.enableAutoUpdate` | Enable automatic updates. | `true` |
|
||||
| Enable Terminal Notifications | `general.enableNotifications` | Enable terminal run-event notifications for action-required prompts and session completion. | `false` |
|
||||
| Terminal Notification Method | `general.notificationMethod` | How to send terminal notifications. | `"auto"` |
|
||||
| Enable Plan Mode | `general.plan.enabled` | Enable Plan Mode for read-only safety during planning. | `true` |
|
||||
| Plan Directory | `general.plan.directory` | The directory where planning artifacts are stored. If not specified, defaults to the system temporary directory. A custom directory requires a policy to allow write access in Plan Mode. | `undefined` |
|
||||
| Plan Model Routing | `general.plan.modelRouting` | Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pro for the planning phase and Flash for the implementation phase. | `true` |
|
||||
| Retry Fetch Errors | `general.retryFetchErrors` | Retry on "exception TypeError: fetch failed sending request" errors. | `true` |
|
||||
| Max Chat Model Attempts | `general.maxAttempts` | Maximum number of attempts for requests to the main chat model. Cannot exceed 10. | `10` |
|
||||
| Debug Keystroke Logging | `general.debugKeystrokeLogging` | Enable debug logging of keystrokes to the console. | `false` |
|
||||
| Enable Session Cleanup | `general.sessionRetention.enabled` | Enable automatic session cleanup | `true` |
|
||||
| Keep chat history | `general.sessionRetention.maxAge` | Automatically delete chats older than this time period (e.g., "30d", "7d", "24h", "1w") | `"30d"` |
|
||||
| Topic & Update Narration | `general.topicUpdateNarration` | Enable the Topic & Update communication model for reduced chattiness and structured progress reporting. | `true` |
|
||||
|
||||
### Output
|
||||
|
||||
@@ -159,17 +161,17 @@ they appear in the UI.
|
||||
|
||||
### Experimental
|
||||
|
||||
| UI Label | Setting | Description | Default |
|
||||
| ---------------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
||||
| Enable Git Worktrees | `experimental.worktrees` | Enable automated Git worktree management for parallel work. | `false` |
|
||||
| Use OSC 52 Paste | `experimental.useOSC52Paste` | Use OSC 52 for pasting. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` |
|
||||
| Use OSC 52 Copy | `experimental.useOSC52Copy` | Use OSC 52 for copying. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` |
|
||||
| Model Steering | `experimental.modelSteering` | Enable model steering (user hints) to guide the model during tool execution. | `false` |
|
||||
| Direct Web Fetch | `experimental.directWebFetch` | Enable web fetch behavior that bypasses LLM summarization. | `false` |
|
||||
| Memory Manager Agent | `experimental.memoryManager` | Replace the built-in save_memory tool with a memory manager subagent that supports adding, removing, de-duplicating, and organizing memories. | `false` |
|
||||
| Use the generalist profile to manage agent contexts. | `experimental.generalistProfile` | Suitable for general coding and software development tasks. | `false` |
|
||||
| Enable Context Management | `experimental.contextManagement` | Enable logic for context management. | `false` |
|
||||
| Topic & Update Narration | `experimental.topicUpdateNarration` | Enable the experimental Topic & Update communication model for reduced chattiness and structured progress reporting. | `false` |
|
||||
| UI Label | Setting | Description | Default |
|
||||
| ---------------------------------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
||||
| Enable Git Worktrees | `experimental.worktrees` | Enable automated Git worktree management for parallel work. | `false` |
|
||||
| Use OSC 52 Paste | `experimental.useOSC52Paste` | Use OSC 52 for pasting. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` |
|
||||
| Use OSC 52 Copy | `experimental.useOSC52Copy` | Use OSC 52 for copying. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` |
|
||||
| Model Steering | `experimental.modelSteering` | Enable model steering (user hints) to guide the model during tool execution. | `false` |
|
||||
| Direct Web Fetch | `experimental.directWebFetch` | Enable web fetch behavior that bypasses LLM summarization. | `false` |
|
||||
| Memory Manager Agent | `experimental.memoryManager` | Replace the built-in save_memory tool with a memory manager subagent that supports adding, removing, de-duplicating, and organizing memories. | `false` |
|
||||
| Auto Memory | `experimental.autoMemory` | Automatically extract reusable skills from past sessions in the background. Review results with /memory inbox. | `false` |
|
||||
| Use the generalist profile to manage agent contexts. | `experimental.generalistProfile` | Suitable for general coding and software development tasks. | `false` |
|
||||
| Enable Context Management | `experimental.contextManagement` | Enable logic for context management. | `false` |
|
||||
|
||||
### Skills
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ project-specific behavior or create a customized persona.
|
||||
|
||||
You can set the environment variable temporarily in your shell, or persist it
|
||||
via a `.gemini/.env` file. See
|
||||
[Persisting Environment Variables](../get-started/authentication.md#persisting-environment-variables).
|
||||
[Persisting Environment Variables](../get-started/authentication.mdx#persisting-environment-variables).
|
||||
|
||||
- Use the project default path (`.gemini/system.md`):
|
||||
- `GEMINI_SYSTEM_MD=true` or `GEMINI_SYSTEM_MD=1`
|
||||
|
||||
@@ -124,3 +124,5 @@ immediately. Force a reload with:
|
||||
- Explore the [Command reference](../../reference/commands.md) for more
|
||||
`/memory` options.
|
||||
- Read the technical spec for [Project context](../../cli/gemini-md.md).
|
||||
- Try the experimental [Auto Memory](../auto-memory.md) feature to extract
|
||||
reusable skills from your past sessions automatically.
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Tabs, TabItem } from '@astrojs/starlight/components';
|
||||
|
||||
# Gemini CLI authentication setup
|
||||
|
||||
To use Gemini CLI, you'll need to authenticate with Google. This guide helps you
|
||||
quickly find the best way to sign in based on your account type and how you're
|
||||
using the CLI.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!TIP]
|
||||
> Looking for a high-level comparison of all available subscriptions?
|
||||
> To compare features and find the right quota for your needs, see our
|
||||
@@ -23,7 +24,7 @@ Select the authentication method that matches your situation in the table below:
|
||||
| Organization users with a company, school, or Google Workspace account | [Sign in with Google](#login-google) | [Yes](#set-gcp) |
|
||||
| AI Studio user with a Gemini API key | [Use Gemini API Key](#gemini-api) | No |
|
||||
| Google Cloud Vertex AI user | [Vertex AI](#vertex-ai) | [Yes](#set-gcp) |
|
||||
| [Headless mode](#headless) | [Use Gemini API Key](#gemini-api) or<br> [Vertex AI](#vertex-ai) | No (for Gemini API Key)<br> [Yes](#set-gcp) (for Vertex AI) |
|
||||
| [Headless mode](#headless) | [Use Gemini API Key](#gemini-api) or<br /> [Vertex AI](#vertex-ai) | No (for Gemini API Key)<br /> [Yes](#set-gcp) (for Vertex AI) |
|
||||
|
||||
### What is my Google account type?
|
||||
|
||||
@@ -84,19 +85,24 @@ To authenticate and use Gemini CLI with a Gemini API key:
|
||||
|
||||
2. Set the `GEMINI_API_KEY` environment variable to your key. For example:
|
||||
|
||||
**macOS/Linux**
|
||||
<Tabs>
|
||||
<TabItem label="macOS/Linux">
|
||||
|
||||
```bash
|
||||
# Replace YOUR_GEMINI_API_KEY with the key from AI Studio
|
||||
export GEMINI_API_KEY="YOUR_GEMINI_API_KEY"
|
||||
```
|
||||
```bash
|
||||
# Replace YOUR_GEMINI_API_KEY with the key from AI Studio
|
||||
export GEMINI_API_KEY="YOUR_GEMINI_API_KEY"
|
||||
```
|
||||
|
||||
**Windows (PowerShell)**
|
||||
</TabItem>
|
||||
<TabItem label="Windows (PowerShell)">
|
||||
|
||||
```powershell
|
||||
# Replace YOUR_GEMINI_API_KEY with the key from AI Studio
|
||||
$env:GEMINI_API_KEY="YOUR_GEMINI_API_KEY"
|
||||
```
|
||||
```powershell
|
||||
# Replace YOUR_GEMINI_API_KEY with the key from AI Studio
|
||||
$env:GEMINI_API_KEY="YOUR_GEMINI_API_KEY"
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
To make this setting persistent, see
|
||||
[Persisting Environment Variables](#persisting-vars).
|
||||
@@ -109,7 +115,6 @@ To authenticate and use Gemini CLI with a Gemini API key:
|
||||
|
||||
4. Select **Use Gemini API key**.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!WARNING]
|
||||
> Treat API keys, especially for services like Gemini, as sensitive
|
||||
> credentials. Protect them to prevent unauthorized access and potential misuse
|
||||
@@ -131,21 +136,26 @@ or the location where you want to run your jobs.
|
||||
|
||||
For example:
|
||||
|
||||
**macOS/Linux**
|
||||
<Tabs>
|
||||
<TabItem label="macOS/Linux">
|
||||
|
||||
```bash
|
||||
```bash
|
||||
# Replace with your project ID and desired location (for example, us-central1)
|
||||
export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
|
||||
export GOOGLE_CLOUD_LOCATION="YOUR_PROJECT_LOCATION"
|
||||
```
|
||||
```
|
||||
|
||||
**Windows (PowerShell)**
|
||||
</TabItem>
|
||||
<TabItem label="Windows (PowerShell)">
|
||||
|
||||
```powershell
|
||||
```powershell
|
||||
# Replace with your project ID and desired location (for example, us-central1)
|
||||
$env:GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
|
||||
$env:GOOGLE_CLOUD_LOCATION="YOUR_PROJECT_LOCATION"
|
||||
```
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
To make any Vertex AI environment variable settings persistent, see
|
||||
[Persisting Environment Variables](#persisting-vars).
|
||||
@@ -157,17 +167,22 @@ Consider this authentication method if you have Google Cloud CLI installed.
|
||||
If you have previously set `GOOGLE_API_KEY` or `GEMINI_API_KEY`, you must unset
|
||||
them to use ADC.
|
||||
|
||||
**macOS/Linux**
|
||||
<Tabs>
|
||||
<TabItem label="macOS/Linux">
|
||||
|
||||
```bash
|
||||
```bash
|
||||
unset GOOGLE_API_KEY GEMINI_API_KEY
|
||||
```
|
||||
```
|
||||
|
||||
**Windows (PowerShell)**
|
||||
</TabItem>
|
||||
<TabItem label="Windows (PowerShell)">
|
||||
|
||||
```powershell
|
||||
```powershell
|
||||
Remove-Item Env:\GOOGLE_API_KEY, Env:\GEMINI_API_KEY -ErrorAction Ignore
|
||||
```
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
1. Verify you have a Google Cloud project and Vertex AI API is enabled.
|
||||
|
||||
@@ -195,17 +210,22 @@ pipelines, or if your organization restricts user-based ADC or API key creation.
|
||||
If you have previously set `GOOGLE_API_KEY` or `GEMINI_API_KEY`, you must unset
|
||||
them:
|
||||
|
||||
**macOS/Linux**
|
||||
<Tabs>
|
||||
<TabItem label="macOS/Linux">
|
||||
|
||||
```bash
|
||||
```bash
|
||||
unset GOOGLE_API_KEY GEMINI_API_KEY
|
||||
```
|
||||
```
|
||||
|
||||
**Windows (PowerShell)**
|
||||
</TabItem>
|
||||
<TabItem label="Windows (PowerShell)">
|
||||
|
||||
```powershell
|
||||
```powershell
|
||||
Remove-Item Env:\GOOGLE_API_KEY, Env:\GEMINI_API_KEY -ErrorAction Ignore
|
||||
```
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
1. [Create a service account and key](https://cloud.google.com/iam/docs/keys-create-delete)
|
||||
and download the provided JSON file. Assign the "Vertex AI User" role to the
|
||||
@@ -214,19 +234,24 @@ Remove-Item Env:\GOOGLE_API_KEY, Env:\GEMINI_API_KEY -ErrorAction Ignore
|
||||
2. Set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable to the JSON
|
||||
file's absolute path. For example:
|
||||
|
||||
**macOS/Linux**
|
||||
<Tabs>
|
||||
<TabItem label="macOS/Linux">
|
||||
|
||||
```bash
|
||||
# Replace /path/to/your/keyfile.json with the actual path
|
||||
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/keyfile.json"
|
||||
```
|
||||
```bash
|
||||
# Replace /path/to/your/keyfile.json with the actual path
|
||||
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/keyfile.json"
|
||||
```
|
||||
|
||||
**Windows (PowerShell)**
|
||||
</TabItem>
|
||||
<TabItem label="Windows (PowerShell)">
|
||||
|
||||
```powershell
|
||||
# Replace C:\path\to\your\keyfile.json with the actual path
|
||||
$env:GOOGLE_APPLICATION_CREDENTIALS="C:\path\to\your\keyfile.json"
|
||||
```
|
||||
```powershell
|
||||
# Replace C:\path\to\your\keyfile.json with the actual path
|
||||
$env:GOOGLE_APPLICATION_CREDENTIALS="C:\path\to\your\keyfile.json"
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
3. [Configure your Google Cloud Project](#set-gcp).
|
||||
|
||||
@@ -238,7 +263,6 @@ Remove-Item Env:\GOOGLE_API_KEY, Env:\GEMINI_API_KEY -ErrorAction Ignore
|
||||
|
||||
5. Select **Vertex AI**.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!WARNING]
|
||||
> Protect your service account key file as it gives access to
|
||||
> your resources.
|
||||
@@ -250,19 +274,24 @@ Remove-Item Env:\GOOGLE_API_KEY, Env:\GEMINI_API_KEY -ErrorAction Ignore
|
||||
|
||||
2. Set the `GOOGLE_API_KEY` environment variable:
|
||||
|
||||
**macOS/Linux**
|
||||
<Tabs>
|
||||
<TabItem label="macOS/Linux">
|
||||
|
||||
```bash
|
||||
# Replace YOUR_GOOGLE_API_KEY with your Vertex AI API key
|
||||
export GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"
|
||||
```
|
||||
```bash
|
||||
# Replace YOUR_GOOGLE_API_KEY with your Vertex AI API key
|
||||
export GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"
|
||||
```
|
||||
|
||||
**Windows (PowerShell)**
|
||||
</TabItem>
|
||||
<TabItem label="Windows (PowerShell)">
|
||||
|
||||
```powershell
|
||||
# Replace YOUR_GOOGLE_API_KEY with your Vertex AI API key
|
||||
$env:GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"
|
||||
```
|
||||
```powershell
|
||||
# Replace YOUR_GOOGLE_API_KEY with your Vertex AI API key
|
||||
$env:GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
If you see errors like `"API keys are not supported by this API..."`, your
|
||||
organization might restrict API key usage for this service. Try the other
|
||||
@@ -280,7 +309,6 @@ Remove-Item Env:\GOOGLE_API_KEY, Env:\GEMINI_API_KEY -ErrorAction Ignore
|
||||
|
||||
## Set your Google Cloud project <a id="set-gcp"></a>
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!IMPORTANT]
|
||||
> Most individual Google accounts (free and paid) don't require a
|
||||
> Google Cloud project for authentication.
|
||||
@@ -308,19 +336,24 @@ To configure Gemini CLI to use a Google Cloud project, do the following:
|
||||
|
||||
For example, to set the `GOOGLE_CLOUD_PROJECT_ID` variable:
|
||||
|
||||
**macOS/Linux**
|
||||
<Tabs>
|
||||
<TabItem label="macOS/Linux">
|
||||
|
||||
```bash
|
||||
# Replace YOUR_PROJECT_ID with your actual Google Cloud project ID
|
||||
export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
|
||||
```
|
||||
```bash
|
||||
# Replace YOUR_PROJECT_ID with your actual Google Cloud project ID
|
||||
export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
|
||||
```
|
||||
|
||||
**Windows (PowerShell)**
|
||||
</TabItem>
|
||||
<TabItem label="Windows (PowerShell)">
|
||||
|
||||
```powershell
|
||||
# Replace YOUR_PROJECT_ID with your actual Google Cloud project ID
|
||||
$env:GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
|
||||
```
|
||||
```powershell
|
||||
# Replace YOUR_PROJECT_ID with your actual Google Cloud project ID
|
||||
$env:GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
To make this setting persistent, see
|
||||
[Persisting Environment Variables](#persisting-vars).
|
||||
@@ -333,21 +366,29 @@ persist them with the following methods:
|
||||
1. **Add your environment variables to your shell configuration file:** Append
|
||||
the environment variable commands to your shell's startup file.
|
||||
|
||||
**macOS/Linux** (for example, `~/.bashrc`, `~/.zshrc`, or `~/.profile`):
|
||||
<Tabs>
|
||||
<TabItem label="macOS/Linux">
|
||||
|
||||
```bash
|
||||
echo 'export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
(for example, `~/.bashrc`, `~/.zshrc`, or `~/.profile`):
|
||||
|
||||
**Windows (PowerShell)** (for example, `$PROFILE`):
|
||||
```bash
|
||||
echo 'export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
```powershell
|
||||
Add-Content -Path $PROFILE -Value '$env:GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"'
|
||||
. $PROFILE
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem label="Windows (PowerShell)">
|
||||
|
||||
(for example, `$PROFILE`):
|
||||
|
||||
```powershell
|
||||
Add-Content -Path $PROFILE -Value '$env:GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"'
|
||||
. $PROFILE
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!WARNING]
|
||||
> Be aware that when you export API keys or service account
|
||||
> paths in your shell configuration file, any process launched from that
|
||||
@@ -361,25 +402,30 @@ persist them with the following methods:
|
||||
|
||||
Example for user-wide settings:
|
||||
|
||||
**macOS/Linux**
|
||||
<Tabs>
|
||||
<TabItem label="macOS/Linux">
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.gemini
|
||||
cat >> ~/.gemini/.env <<'EOF'
|
||||
GOOGLE_CLOUD_PROJECT="your-project-id"
|
||||
# Add other variables like GEMINI_API_KEY as needed
|
||||
EOF
|
||||
```
|
||||
```bash
|
||||
mkdir -p ~/.gemini
|
||||
cat >> ~/.gemini/.env <<'EOF'
|
||||
GOOGLE_CLOUD_PROJECT="your-project-id"
|
||||
# Add other variables like GEMINI_API_KEY as needed
|
||||
EOF
|
||||
```
|
||||
|
||||
**Windows (PowerShell)**
|
||||
</TabItem>
|
||||
<TabItem label="Windows (PowerShell)">
|
||||
|
||||
```powershell
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.gemini"
|
||||
@"
|
||||
GOOGLE_CLOUD_PROJECT="your-project-id"
|
||||
# Add other variables like GEMINI_API_KEY as needed
|
||||
"@ | Out-File -FilePath "$env:USERPROFILE\.gemini\.env" -Encoding utf8 -Append
|
||||
```
|
||||
```powershell
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.gemini"
|
||||
@"
|
||||
GOOGLE_CLOUD_PROJECT="your-project-id"
|
||||
# Add other variables like GEMINI_API_KEY as needed
|
||||
"@ | Out-File -FilePath "$env:USERPROFILE\.gemini\.env" -Encoding utf8 -Append
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Variables are loaded from the first file found, not merged.
|
||||
|
||||
@@ -24,7 +24,8 @@ Once Gemini CLI is installed, run Gemini CLI from your command line:
|
||||
gemini
|
||||
```
|
||||
|
||||
For more installation options, see [Gemini CLI Installation](./installation.md).
|
||||
For more installation options, see
|
||||
[Gemini CLI Installation](./installation.mdx).
|
||||
|
||||
## Authenticate
|
||||
|
||||
@@ -46,7 +47,7 @@ cases, you can log in with your existing Google account:
|
||||
|
||||
Certain account types may require you to configure a Google Cloud project. For
|
||||
more information, including other authentication methods, see
|
||||
[Gemini CLI Authentication Setup](./authentication.md).
|
||||
[Gemini CLI Authentication Setup](./authentication.mdx).
|
||||
|
||||
## Configure
|
||||
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
# Gemini CLI installation, execution, and releases
|
||||
|
||||
This document provides an overview of Gemini CLI's system requirements,
|
||||
installation methods, and release types.
|
||||
|
||||
## Recommended system specifications
|
||||
|
||||
- **Operating System:**
|
||||
- macOS 15+
|
||||
- Windows 11 24H2+
|
||||
- Ubuntu 20.04+
|
||||
- **Hardware:**
|
||||
- "Casual" usage: 4GB+ RAM (short sessions, common tasks and edits)
|
||||
- "Power" usage: 16GB+ RAM (long sessions, large codebases, deep context)
|
||||
- **Runtime:** Node.js 20.0.0+
|
||||
- **Shell:** Bash, Zsh, or PowerShell
|
||||
- **Location:**
|
||||
[Gemini Code Assist supported locations](https://developers.google.com/gemini-code-assist/resources/available-locations#americas)
|
||||
- **Internet connection required**
|
||||
|
||||
## Install Gemini CLI
|
||||
|
||||
We recommend most users install Gemini CLI using one of the following
|
||||
installation methods:
|
||||
|
||||
- npm
|
||||
- Homebrew
|
||||
- MacPorts
|
||||
- Anaconda
|
||||
|
||||
Note that Gemini CLI comes pre-installed on
|
||||
[**Cloud Shell**](https://docs.cloud.google.com/shell/docs) and
|
||||
[**Cloud Workstations**](https://cloud.google.com/workstations).
|
||||
|
||||
### Install globally with npm
|
||||
|
||||
```bash
|
||||
npm install -g @google/gemini-cli
|
||||
```
|
||||
|
||||
### Install globally with Homebrew (macOS/Linux)
|
||||
|
||||
```bash
|
||||
brew install gemini-cli
|
||||
```
|
||||
|
||||
### Install globally with MacPorts (macOS)
|
||||
|
||||
```bash
|
||||
sudo port install gemini-cli
|
||||
```
|
||||
|
||||
### Install with Anaconda (for restricted environments)
|
||||
|
||||
```bash
|
||||
# Create and activate a new environment
|
||||
conda create -y -n gemini_env -c conda-forge nodejs
|
||||
conda activate gemini_env
|
||||
|
||||
# Install Gemini CLI globally via npm (inside the environment)
|
||||
npm install -g @google/gemini-cli
|
||||
```
|
||||
|
||||
## Run Gemini CLI
|
||||
|
||||
For most users, we recommend running Gemini CLI with the `gemini` command:
|
||||
|
||||
```bash
|
||||
gemini
|
||||
```
|
||||
|
||||
For a list of options and additional commands, see the
|
||||
[CLI cheatsheet](../cli/cli-reference.md).
|
||||
|
||||
You can also run Gemini CLI using one of the following advanced methods:
|
||||
|
||||
- Run instantly with npx. You can run Gemini CLI without permanent installation.
|
||||
- In a sandbox. This method offers increased security and isolation.
|
||||
- From the source. This is recommended for contributors to the project.
|
||||
|
||||
### Run instantly with npx
|
||||
|
||||
```bash
|
||||
# Using npx (no installation required)
|
||||
npx @google/gemini-cli
|
||||
```
|
||||
|
||||
You can also execute the CLI directly from the main branch on GitHub, which is
|
||||
helpful for testing features still in development:
|
||||
|
||||
```bash
|
||||
npx https://github.com/google-gemini/gemini-cli
|
||||
```
|
||||
|
||||
### Run in a sandbox (Docker/Podman)
|
||||
|
||||
For security and isolation, Gemini CLI can be run inside a container. This is
|
||||
the default way that the CLI executes tools that might have side effects.
|
||||
|
||||
- **Directly from the registry:** You can run the published sandbox image
|
||||
directly. This is useful for environments where you only have Docker and want
|
||||
to run the CLI.
|
||||
```bash
|
||||
# Run the published sandbox image
|
||||
docker run --rm -it us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.1.1
|
||||
```
|
||||
- **Using the `--sandbox` flag:** If you have Gemini CLI installed locally
|
||||
(using the standard installation described above), you can instruct it to run
|
||||
inside the sandbox container.
|
||||
```bash
|
||||
gemini --sandbox -y -p "your prompt here"
|
||||
```
|
||||
|
||||
### Run from source (recommended for Gemini CLI contributors)
|
||||
|
||||
Contributors to the project will want to run the CLI directly from the source
|
||||
code.
|
||||
|
||||
- **Development mode:** This method provides hot-reloading and is useful for
|
||||
active development.
|
||||
```bash
|
||||
# From the root of the repository
|
||||
npm run start
|
||||
```
|
||||
- **Production mode (React optimizations):** This method runs the CLI with React
|
||||
production mode enabled, which is useful for testing performance without
|
||||
development overhead.
|
||||
```bash
|
||||
# From the root of the repository
|
||||
npm run start:prod
|
||||
```
|
||||
- **Production-like mode (linked package):** This method simulates a global
|
||||
installation by linking your local package. It's useful for testing a local
|
||||
build in a production workflow.
|
||||
|
||||
```bash
|
||||
# Link the local cli package to your global node_modules
|
||||
npm link packages/cli
|
||||
|
||||
# Now you can run your local version using the `gemini` command
|
||||
gemini
|
||||
```
|
||||
|
||||
## Releases
|
||||
|
||||
Gemini CLI has three release channels: nightly, preview, and stable. For most
|
||||
users, we recommend the stable release, which is the default installation.
|
||||
|
||||
### Stable
|
||||
|
||||
New stable releases are published each week. The stable release is the promotion
|
||||
of last week's `preview` release along with any bug fixes. The stable release
|
||||
uses `latest` tag, but omitting the tag also installs the latest stable release
|
||||
by default:
|
||||
|
||||
```bash
|
||||
# Both commands install the latest stable release.
|
||||
npm install -g @google/gemini-cli
|
||||
npm install -g @google/gemini-cli@latest
|
||||
```
|
||||
|
||||
### Preview
|
||||
|
||||
New preview releases will be published each week. These releases are not fully
|
||||
vetted and may contain regressions or other outstanding issues. Try out the
|
||||
preview release by using the `preview` tag:
|
||||
|
||||
```bash
|
||||
npm install -g @google/gemini-cli@preview
|
||||
```
|
||||
|
||||
### Nightly
|
||||
|
||||
Nightly releases are published every day. The nightly release includes all
|
||||
changes from the main branch at time of release. It should be assumed there are
|
||||
pending validations and issues. You can help test the latest changes by
|
||||
installing with the `nightly` tag:
|
||||
|
||||
```bash
|
||||
npm install -g @google/gemini-cli@nightly
|
||||
```
|
||||
@@ -0,0 +1,201 @@
|
||||
import { Tabs, TabItem } from '@astrojs/starlight/components';
|
||||
|
||||
# Gemini CLI installation, execution, and releases
|
||||
|
||||
This document provides an overview of Gemini CLI's system requirements,
|
||||
installation methods, and release types.
|
||||
|
||||
## Recommended system specifications
|
||||
|
||||
- **Operating System:**
|
||||
- macOS 15+
|
||||
- Windows 11 24H2+
|
||||
- Ubuntu 20.04+
|
||||
- **Hardware:**
|
||||
- "Casual" usage: 4GB+ RAM (short sessions, common tasks and edits)
|
||||
- "Power" usage: 16GB+ RAM (long sessions, large codebases, deep context)
|
||||
- **Runtime:** Node.js 20.0.0+
|
||||
- **Shell:** Bash, Zsh, or PowerShell
|
||||
- **Location:**
|
||||
[Gemini Code Assist supported locations](https://developers.google.com/gemini-code-assist/resources/available-locations#americas)
|
||||
- **Internet connection required**
|
||||
|
||||
## Install Gemini CLI
|
||||
|
||||
We recommend most users install Gemini CLI using one of the following
|
||||
installation methods. Note that Gemini CLI comes pre-installed on
|
||||
[**Cloud Shell**](https://docs.cloud.google.com/shell/docs) and
|
||||
[**Cloud Workstations**](https://cloud.google.com/workstations).
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="npm">
|
||||
|
||||
Install globally with npm:
|
||||
|
||||
```bash
|
||||
npm install -g @google/gemini-cli
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Homebrew (macOS/Linux)">
|
||||
|
||||
Install globally with Homebrew:
|
||||
|
||||
```bash
|
||||
brew install gemini-cli
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="MacPorts (macOS)">
|
||||
|
||||
Install globally with MacPorts:
|
||||
|
||||
```bash
|
||||
sudo port install gemini-cli
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Anaconda">
|
||||
|
||||
Install with Anaconda (for restricted environments):
|
||||
|
||||
```bash
|
||||
# Create and activate a new environment
|
||||
conda create -y -n gemini_env -c conda-forge nodejs
|
||||
conda activate gemini_env
|
||||
|
||||
# Install Gemini CLI globally via npm (inside the environment)
|
||||
npm install -g @google/gemini-cli
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Run Gemini CLI
|
||||
|
||||
For most users, we recommend running Gemini CLI with the `gemini` command:
|
||||
|
||||
```bash
|
||||
gemini
|
||||
```
|
||||
|
||||
For a list of options and additional commands, see the
|
||||
[CLI cheatsheet](../cli/cli-reference.md).
|
||||
|
||||
You can also run Gemini CLI using one of the following advanced methods:
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="npx">
|
||||
|
||||
Run instantly with npx. You can run Gemini CLI without permanent installation.
|
||||
|
||||
```bash
|
||||
# Using npx (no installation required)
|
||||
npx @google/gemini-cli
|
||||
```
|
||||
|
||||
You can also execute the CLI directly from the main branch on GitHub, which is
|
||||
helpful for testing features still in development:
|
||||
|
||||
```bash
|
||||
npx https://github.com/google-gemini/gemini-cli
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Docker/Podman Sandbox">
|
||||
|
||||
For security and isolation, Gemini CLI can be run inside a container. This is
|
||||
the default way that the CLI executes tools that might have side effects.
|
||||
|
||||
- **Directly from the registry:** You can run the published sandbox image
|
||||
directly. This is useful for environments where you only have Docker and want
|
||||
to run the CLI.
|
||||
```bash
|
||||
# Run the published sandbox image
|
||||
docker run --rm -it us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.1.1
|
||||
```
|
||||
- **Using the `--sandbox` flag:** If you have Gemini CLI installed locally
|
||||
(using the standard installation described above), you can instruct it to run
|
||||
inside the sandbox container.
|
||||
```bash
|
||||
gemini --sandbox -y -p "your prompt here"
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="From source">
|
||||
|
||||
Contributors to the project will want to run the CLI directly from the source
|
||||
code.
|
||||
|
||||
- **Development mode:** This method provides hot-reloading and is useful for
|
||||
active development.
|
||||
```bash
|
||||
# From the root of the repository
|
||||
npm run start
|
||||
```
|
||||
- **Production mode (React optimizations):** This method runs the CLI with React
|
||||
production mode enabled, which is useful for testing performance without
|
||||
development overhead.
|
||||
```bash
|
||||
# From the root of the repository
|
||||
npm run start:prod
|
||||
```
|
||||
- **Production-like mode (linked package):** This method simulates a global
|
||||
installation by linking your local package. It's useful for testing a local
|
||||
build in a production workflow.
|
||||
|
||||
```bash
|
||||
# Link the local cli package to your global node_modules
|
||||
npm link packages/cli
|
||||
|
||||
# Now you can run your local version using the `gemini` command
|
||||
gemini
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Releases
|
||||
|
||||
Gemini CLI has three release channels: stable, preview, and nightly. For most
|
||||
users, we recommend the stable release, which is the default installation.
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Stable">
|
||||
|
||||
Stable releases are published each week. A stable release is created from the
|
||||
previous week's preview release along with any bug fixes. The stable release
|
||||
uses the `latest` tag. Omitting the tag also installs the latest stable
|
||||
release by default.
|
||||
|
||||
```bash
|
||||
# Both commands install the latest stable release.
|
||||
npm install -g @google/gemini-cli
|
||||
npm install -g @google/gemini-cli@latest
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Preview">
|
||||
|
||||
New preview releases will be published each week. These releases are not fully
|
||||
vetted and may contain regressions or other outstanding issues. Try out the
|
||||
preview release by using the `preview` tag:
|
||||
|
||||
```bash
|
||||
npm install -g @google/gemini-cli@preview
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Nightly">
|
||||
|
||||
Nightly releases are published every day. The nightly release includes all
|
||||
changes from the main branch at time of release. It should be assumed there are
|
||||
pending validations and issues. You can help test the latest changes by
|
||||
installing with the `nightly` tag:
|
||||
|
||||
```bash
|
||||
npm install -g @google/gemini-cli@nightly
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@@ -15,9 +15,9 @@ npm install -g @google/gemini-cli
|
||||
Jump in to Gemini CLI.
|
||||
|
||||
- **[Quickstart](./get-started/index.md):** Your first session with Gemini CLI.
|
||||
- **[Installation](./get-started/installation.md):** How to install Gemini CLI
|
||||
- **[Installation](./get-started/installation.mdx):** How to install Gemini CLI
|
||||
on your system.
|
||||
- **[Authentication](./get-started/authentication.md):** Setup instructions for
|
||||
- **[Authentication](./get-started/authentication.mdx):** Setup instructions for
|
||||
personal and enterprise accounts.
|
||||
- **[CLI cheatsheet](./cli/cli-reference.md):** A quick reference for common
|
||||
commands and options.
|
||||
|
||||
@@ -134,10 +134,15 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
- **Default:** `true`
|
||||
|
||||
- **`general.enableNotifications`** (boolean):
|
||||
- **Description:** Enable run-event notifications for action-required prompts
|
||||
and session completion.
|
||||
- **Description:** Enable terminal run-event notifications for action-required
|
||||
prompts and session completion.
|
||||
- **Default:** `false`
|
||||
|
||||
- **`general.notificationMethod`** (enum):
|
||||
- **Description:** How to send terminal notifications.
|
||||
- **Default:** `"auto"`
|
||||
- **Values:** `"auto"`, `"osc9"`, `"osc777"`, `"bell"`
|
||||
|
||||
- **`general.checkpointing.enabled`** (boolean):
|
||||
- **Description:** Enable session checkpointing for recovery
|
||||
- **Default:** `false`
|
||||
@@ -193,6 +198,11 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
- **Description:** Minimum retention period (safety limit, defaults to "1d")
|
||||
- **Default:** `"1d"`
|
||||
|
||||
- **`general.topicUpdateNarration`** (boolean):
|
||||
- **Description:** Enable the Topic & Update communication model for reduced
|
||||
chattiness and structured progress reporting.
|
||||
- **Default:** `true`
|
||||
|
||||
#### `output`
|
||||
|
||||
- **`output.format`** (enum):
|
||||
@@ -1719,6 +1729,12 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.autoMemory`** (boolean):
|
||||
- **Description:** Automatically extract reusable skills from past sessions in
|
||||
the background. Review results with /memory inbox.
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.generalistProfile`** (boolean):
|
||||
- **Description:** Suitable for general coding and software development tasks.
|
||||
- **Default:** `false`
|
||||
@@ -1730,8 +1746,7 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.topicUpdateNarration`** (boolean):
|
||||
- **Description:** Enable the experimental Topic & Update communication model
|
||||
for reduced chattiness and structured progress reporting.
|
||||
- **Description:** Deprecated: Use general.topicUpdateNarration instead.
|
||||
- **Default:** `false`
|
||||
|
||||
#### `skills`
|
||||
@@ -2070,7 +2085,7 @@ within your user's home folder.
|
||||
Environment variables are a common way to configure applications, especially for
|
||||
sensitive information like API keys or for settings that might change between
|
||||
environments. For authentication setup, see the
|
||||
[Authentication documentation](../get-started/authentication.md) which covers
|
||||
[Authentication documentation](../get-started/authentication.mdx) which covers
|
||||
all available authentication methods.
|
||||
|
||||
The CLI automatically loads environment variables from an `.env` file. The
|
||||
@@ -2091,7 +2106,7 @@ the `advanced.excludedEnvVars` setting in your `settings.json` file.
|
||||
- **`GEMINI_API_KEY`**:
|
||||
- Your API key for the Gemini API.
|
||||
- One of several available
|
||||
[authentication methods](../get-started/authentication.md).
|
||||
[authentication methods](../get-started/authentication.mdx).
|
||||
- Set this in your shell profile (for example, `~/.bashrc`, `~/.zshrc`) or an
|
||||
`.env` file.
|
||||
- **`GEMINI_MODEL`**:
|
||||
@@ -2148,6 +2163,21 @@ the `advanced.excludedEnvVars` setting in your `settings.json` file.
|
||||
- When set, overrides the default API version used by the SDK.
|
||||
- Example: `export GOOGLE_GENAI_API_VERSION="v1"` (Windows PowerShell:
|
||||
`$env:GOOGLE_GENAI_API_VERSION="v1"`)
|
||||
- **`GOOGLE_GEMINI_BASE_URL`**:
|
||||
- Overrides the default base URL for Gemini API requests (when using
|
||||
`gemini-api-key` authentication).
|
||||
- Must be a valid URL. For security, it must use HTTPS unless pointing to
|
||||
`localhost` (or `127.0.0.1` / `[::1]`).
|
||||
- Example: `export GOOGLE_GEMINI_BASE_URL="https://my-proxy.com"` (Windows
|
||||
PowerShell: `$env:GOOGLE_GEMINI_BASE_URL="https://my-proxy.com"`)
|
||||
- **`GOOGLE_VERTEX_BASE_URL`**:
|
||||
- Overrides the default base URL for Vertex AI API requests (when using
|
||||
`vertex-ai` authentication).
|
||||
- Must be a valid URL. For security, it must use HTTPS unless pointing to
|
||||
`localhost` (or `127.0.0.1` / `[::1]`).
|
||||
- Example: `export GOOGLE_VERTEX_BASE_URL="https://my-vertex-proxy.com"`
|
||||
(Windows PowerShell:
|
||||
`$env:GOOGLE_VERTEX_BASE_URL="https://my-vertex-proxy.com"`)
|
||||
- **`OTLP_GOOGLE_CLOUD_PROJECT`**:
|
||||
- Your Google Cloud Project ID for Telemetry in Google Cloud
|
||||
- Example: `export OTLP_GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"` (Windows
|
||||
@@ -2515,29 +2545,29 @@ image separately and reference that image in your sandbox configuration.
|
||||
|
||||
## Usage statistics
|
||||
|
||||
To help us improve Gemini CLI, we collect anonymized usage statistics. This data
|
||||
helps us understand how the CLI is used, identify common issues, and prioritize
|
||||
new features.
|
||||
To improve Gemini CLI, Gemini CLI collects anonymized usage statistics. This
|
||||
data helps identify common issues and prioritize new features.
|
||||
|
||||
**What we collect:**
|
||||
**Collected data:**
|
||||
|
||||
- **Tool calls:** We log the names of the tools that are called, whether they
|
||||
succeed or fail, and how long they take to execute. We do not collect the
|
||||
arguments passed to the tools or any data returned by them.
|
||||
- **API requests:** We log the Gemini model used for each request, the duration
|
||||
of the request, and whether it was successful. We do not collect the content
|
||||
of the prompts or responses.
|
||||
- **Session information:** We collect information about the configuration of the
|
||||
CLI, such as the enabled tools and the approval mode.
|
||||
- **Tool calls:** Gemini CLI logs the names of the tools that are called,
|
||||
whether they succeed or fail, and how long they take to execute. Gemini CLI
|
||||
does not collect the arguments passed to the tools or any data returned by
|
||||
them.
|
||||
- **API requests:** Gemini CLI logs the Gemini model used for each request, the
|
||||
duration of the request, and whether it was successful. Gemini CLI does not
|
||||
collect the content of the prompts or responses.
|
||||
- **Session information:** Gemini CLI collects information about the
|
||||
configuration of the CLI, such as the enabled tools and the approval mode.
|
||||
|
||||
**What we DON'T collect:**
|
||||
**Data NOT collected:**
|
||||
|
||||
- **Personally identifiable information (PII):** We do not collect any personal
|
||||
information, such as your name, email address, or API keys.
|
||||
- **Prompt and response content:** We do not log the content of your prompts or
|
||||
the responses from the Gemini model.
|
||||
- **File content:** We do not log the content of any files that are read or
|
||||
written by the CLI.
|
||||
- **Personally identifiable information (PII):** Gemini CLI does not collect
|
||||
personal information, such as your name, email address, or API keys.
|
||||
- **Prompt and response content:** Gemini CLI does not log the content of your
|
||||
prompts or the responses from the Gemini model.
|
||||
- **File content:** Gemini CLI does not log the content of any files that are
|
||||
read or written by the CLI.
|
||||
|
||||
**How to opt out:**
|
||||
|
||||
|
||||
@@ -120,6 +120,12 @@ There are three possible decisions a rule can enforce:
|
||||
|
||||
### Priority system and tiers
|
||||
|
||||
> [!WARNING] The **Workspace** tier (project-level policies) is currently
|
||||
> non-functional. Defining policies in a workspace's `.gemini/policies`
|
||||
> directory will not have any effect. See
|
||||
> [issue #18186](https://github.com/google-gemini/gemini-cli/issues/18186). Use
|
||||
> User or Admin policies instead.
|
||||
|
||||
The policy engine uses a sophisticated priority system to resolve conflicts when
|
||||
multiple rules match a single tool call. The core principle is simple: **the
|
||||
rule with the highest priority wins**.
|
||||
@@ -127,13 +133,13 @@ rule with the highest priority wins**.
|
||||
To provide a clear hierarchy, policies are organized into three tiers. Each tier
|
||||
has a designated number that forms the base of the final priority calculation.
|
||||
|
||||
| Tier | Base | Description |
|
||||
| :-------- | :--- | :-------------------------------------------------------------------------------- |
|
||||
| Default | 1 | Built-in policies that ship with Gemini CLI. |
|
||||
| Extension | 2 | Policies defined in extensions. |
|
||||
| Workspace | 3 | Policies defined in the current workspace's configuration directory. |
|
||||
| User | 4 | Custom policies defined by the user. |
|
||||
| Admin | 5 | Policies managed by an administrator (for example, in an enterprise environment). |
|
||||
| Tier | Base | Description |
|
||||
| :-------- | :--- | :-------------------------------------------------------------------------------------------- |
|
||||
| Default | 1 | Built-in policies that ship with Gemini CLI. |
|
||||
| Extension | 2 | Policies defined in extensions. |
|
||||
| Workspace | 3 | **(Currently disabled)** Policies defined in the current workspace's configuration directory. |
|
||||
| User | 4 | Custom policies defined by the user. |
|
||||
| Admin | 5 | Policies managed by an administrator (for example, in an enterprise environment). |
|
||||
|
||||
Within a TOML policy file, you assign a priority value from **0 to 999**. The
|
||||
engine transforms this into a final priority using the following formula:
|
||||
@@ -214,11 +220,11 @@ User, and (if configured) Admin directories.
|
||||
|
||||
### Policy locations
|
||||
|
||||
| Tier | Type | Location |
|
||||
| :------------ | :----- | :---------------------------------------- |
|
||||
| **User** | Custom | `~/.gemini/policies/*.toml` |
|
||||
| **Workspace** | Custom | `$WORKSPACE_ROOT/.gemini/policies/*.toml` |
|
||||
| **Admin** | System | _See below (OS specific)_ |
|
||||
| Tier | Type | Location |
|
||||
| :------------ | :----- | :------------------------------------------------------- |
|
||||
| **User** | Custom | `~/.gemini/policies/*.toml` |
|
||||
| **Workspace** | Custom | **(Disabled)** `$WORKSPACE_ROOT/.gemini/policies/*.toml` |
|
||||
| **Admin** | System | _See below (OS specific)_ |
|
||||
|
||||
#### System-wide policies (Admin)
|
||||
|
||||
|
||||
@@ -92,6 +92,13 @@ each tool.
|
||||
| [`ask_user`](../tools/ask-user.md) | `Communicate` | Requests clarification or missing information via an interactive dialog. |
|
||||
| [`write_todos`](../tools/todos.md) | `Other` | Maintains an internal list of subtasks. The model uses this to track its own progress. |
|
||||
|
||||
### MCP
|
||||
|
||||
| Tool | Kind | Description |
|
||||
| :------------------------------------------------ | :------- | :--------------------------------------------------------------------- |
|
||||
| [`list_mcp_resources`](../tools/mcp-resources.md) | `Search` | Lists all available resources exposed by connected MCP servers. |
|
||||
| [`read_mcp_resource`](../tools/mcp-resources.md) | `Read` | Reads the content of a specific Model Context Protocol (MCP) resource. |
|
||||
|
||||
### Memory
|
||||
|
||||
| Tool | Kind | Description |
|
||||
|
||||
@@ -96,6 +96,11 @@
|
||||
]
|
||||
},
|
||||
{ "label": "Agent Skills", "slug": "docs/cli/skills" },
|
||||
{
|
||||
"label": "Auto Memory",
|
||||
"badge": "🔬",
|
||||
"slug": "docs/cli/auto-memory"
|
||||
},
|
||||
{ "label": "Checkpointing", "slug": "docs/cli/checkpointing" },
|
||||
{ "label": "Headless mode", "slug": "docs/cli/headless" },
|
||||
{
|
||||
@@ -122,7 +127,14 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{ "label": "MCP servers", "slug": "docs/tools/mcp-server" },
|
||||
{
|
||||
"label": "MCP servers",
|
||||
"collapsed": true,
|
||||
"items": [
|
||||
{ "label": "Overview", "slug": "docs/tools/mcp-server" },
|
||||
{ "label": "Resource tools", "slug": "docs/tools/mcp-resources" }
|
||||
]
|
||||
},
|
||||
{ "label": "Model routing", "slug": "docs/cli/model-routing" },
|
||||
{ "label": "Model selection", "slug": "docs/cli/model" },
|
||||
{
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# MCP resource tools
|
||||
|
||||
MCP resource tools let Gemini CLI discover and retrieve data from contextual
|
||||
resources exposed by Model Context Protocol (MCP) servers.
|
||||
|
||||
## 1. `list_mcp_resources` (ListMcpResources)
|
||||
|
||||
`list_mcp_resources` retrieves a list of all available resources from connected
|
||||
MCP servers. This is primarily a discovery tool that helps the model understand
|
||||
what external data sources are available for reference.
|
||||
|
||||
- **Tool name:** `list_mcp_resources`
|
||||
- **Display name:** List MCP Resources
|
||||
- **Kind:** `Search`
|
||||
- **File:** `list-mcp-resources.ts`
|
||||
- **Parameters:**
|
||||
- `serverName` (string, optional): An optional filter to list resources from a
|
||||
specific server.
|
||||
- **Behavior:**
|
||||
- Iterates through all connected MCP servers.
|
||||
- Fetches the list of resources each server exposes.
|
||||
- Formats the results into a plain-text list of URIs and descriptions.
|
||||
- **Output (`llmContent`):** A formatted list of available resources, including
|
||||
their URI, server name, and optional description.
|
||||
- **Confirmation:** No. This is a read-only discovery tool.
|
||||
|
||||
## 2. `read_mcp_resource` (ReadMcpResource)
|
||||
|
||||
`read_mcp_resource` retrieves the content of a specific resource identified by
|
||||
its URI.
|
||||
|
||||
- **Tool name:** `read_mcp_resource`
|
||||
- **Display name:** Read MCP Resource
|
||||
- **Kind:** `Read`
|
||||
- **File:** `read-mcp-resource.ts`
|
||||
- **Parameters:**
|
||||
- `uri` (string, required): The URI of the MCP resource to read.
|
||||
- **Behavior:**
|
||||
- Locates the resource and its associated server by URI.
|
||||
- Calls the server's `resources/read` method.
|
||||
- Processes the response, extracting text or binary data.
|
||||
- **Output (`llmContent`):** The content of the resource. For binary data, it
|
||||
returns a placeholder indicating the data type.
|
||||
- **Confirmation:** No. This is a read-only retrieval tool.
|
||||
@@ -64,7 +64,8 @@ Gemini CLI supports three MCP transport types:
|
||||
|
||||
Some MCP servers expose contextual “resources” in addition to the tools and
|
||||
prompts. Gemini CLI discovers these automatically and gives you the possibility
|
||||
to reference them in the chat.
|
||||
to reference them in the chat. For more information on the tools used to
|
||||
interact with these resources, see [MCP resource tools](mcp-resources.md).
|
||||
|
||||
### Discovery and listing
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ import path from 'node:path';
|
||||
|
||||
describe('Background Process Monitoring', () => {
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'should naturally use read output tool to find token',
|
||||
prompt:
|
||||
"Run the script using 'bash generate_token.sh'. It will emit a token after a short delay and continue running. Find the token and tell me what it is.",
|
||||
@@ -50,6 +52,8 @@ sleep 100
|
||||
});
|
||||
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'should naturally use list tool to verify multiple processes',
|
||||
prompt:
|
||||
"Start three background processes that run 'sleep 100', 'sleep 200', and 'sleep 300' respectively. Verify that all three are currently running.",
|
||||
|
||||
@@ -17,9 +17,17 @@ describe('CliHelpAgent Delegation', () => {
|
||||
timeout: 60000,
|
||||
assert: async (rig, _result) => {
|
||||
const toolLogs = rig.readToolLogs();
|
||||
const toolCallIndex = toolLogs.findIndex(
|
||||
(log) => log.toolRequest.name === 'cli_help',
|
||||
);
|
||||
const toolCallIndex = toolLogs.findIndex((log) => {
|
||||
if (log.toolRequest.name === 'invoke_agent') {
|
||||
try {
|
||||
const args = JSON.parse(log.toolRequest.args);
|
||||
return args.agent_name === 'cli_help';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
expect(toolCallIndex).toBeGreaterThan(-1);
|
||||
expect(toolCallIndex).toBeLessThan(5); // Called within first 5 turns
|
||||
},
|
||||
|
||||
@@ -16,6 +16,7 @@ import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import os from 'node:os';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { vi } from 'vitest';
|
||||
import {
|
||||
Config,
|
||||
type ConfigParameters,
|
||||
@@ -52,6 +53,7 @@ export interface ComponentEvalCase extends BaseEvalCase {
|
||||
export class ComponentRig {
|
||||
public config: Config | undefined;
|
||||
public testDir: string;
|
||||
public homeDir: string;
|
||||
public sessionId: string;
|
||||
|
||||
constructor(
|
||||
@@ -61,6 +63,9 @@ export class ComponentRig {
|
||||
this.testDir = fs.mkdtempSync(
|
||||
path.join(os.tmpdir(), `gemini-component-rig-${uniqueId.slice(0, 8)}-`),
|
||||
);
|
||||
this.homeDir = fs.mkdtempSync(
|
||||
path.join(os.tmpdir(), `gemini-component-home-${uniqueId.slice(0, 8)}-`),
|
||||
);
|
||||
this.sessionId = `test-session-${uniqueId}`;
|
||||
}
|
||||
|
||||
@@ -89,12 +94,23 @@ export class ComponentRig {
|
||||
this.config = makeFakeConfig(configParams);
|
||||
await this.config.initialize();
|
||||
|
||||
// Refresh auth using USE_GEMINI to initialize the real BaseLlmClient
|
||||
// Refresh auth using USE_GEMINI to initialize the real BaseLlmClient.
|
||||
// This must happen BEFORE stubbing GEMINI_CLI_HOME because OAuth credential
|
||||
// lookup resolves through homedir() → GEMINI_CLI_HOME.
|
||||
await this.config.refreshAuth(AuthType.USE_GEMINI);
|
||||
|
||||
// Isolate storage paths (session files, skills, extraction state) by
|
||||
// pointing GEMINI_CLI_HOME at a per-test temp directory. Storage resolves
|
||||
// global paths through `homedir()` which reads this env var. This is set
|
||||
// after auth so credential lookup uses the real home directory.
|
||||
vi.stubEnv('GEMINI_CLI_HOME', this.homeDir);
|
||||
}
|
||||
|
||||
async cleanup() {
|
||||
await this.config?.dispose();
|
||||
vi.unstubAllEnvs();
|
||||
fs.rmSync(this.testDir, { recursive: true, force: true });
|
||||
fs.rmSync(this.homeDir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,11 +26,22 @@ describe('generalist_agent', () => {
|
||||
prompt:
|
||||
'Please use the generalist agent to create a file called "generalist_test_file.txt" containing exactly the following text: success',
|
||||
assert: async (rig) => {
|
||||
// 1) Verify the generalist agent was invoked
|
||||
const foundToolCall = await rig.waitForToolCall('generalist');
|
||||
// 1) Verify the generalist agent was invoked via invoke_agent
|
||||
const foundToolCall = await rig.waitForToolCall(
|
||||
'invoke_agent',
|
||||
undefined,
|
||||
(args) => {
|
||||
try {
|
||||
const parsed = JSON.parse(args);
|
||||
return parsed.agent_name === 'generalist';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
);
|
||||
expect(
|
||||
foundToolCall,
|
||||
'Expected to find a tool call for generalist agent',
|
||||
'Expected to find an invoke_agent tool call for generalist agent',
|
||||
).toBeTruthy();
|
||||
|
||||
// 2) Verify the file was created as expected
|
||||
|
||||
@@ -298,6 +298,8 @@ describe('plan_mode', () => {
|
||||
});
|
||||
|
||||
evalTest('ALWAYS_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'should transition from plan mode to normal execution and create a plan file from scratch',
|
||||
params: {
|
||||
settings,
|
||||
@@ -333,7 +335,7 @@ describe('plan_mode', () => {
|
||||
|
||||
expect(
|
||||
planWrite?.toolRequest.success,
|
||||
`Expected write_file to succeed, but got error: ${planWrite?.toolRequest.error}`,
|
||||
`Expected write_file to succeed, but got error: ${(planWrite?.toolRequest as any).error}`,
|
||||
).toBe(true);
|
||||
|
||||
assertModelHasOutput(result);
|
||||
@@ -341,6 +343,8 @@ describe('plan_mode', () => {
|
||||
});
|
||||
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'should not exit plan mode or draft before informal agreement',
|
||||
approvalMode: ApprovalMode.PLAN,
|
||||
params: {
|
||||
|
||||
@@ -145,22 +145,30 @@ describe('save_memory', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const ignoringDbSchemaLocation =
|
||||
"Agent ignores workspace's database schema location";
|
||||
const savingDbSchemaLocationAsProjectMemory =
|
||||
'Agent saves workspace database schema location as project memory';
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: ignoringDbSchemaLocation,
|
||||
name: savingDbSchemaLocationAsProjectMemory,
|
||||
prompt: `The database schema for this workspace is located in \`db/schema.sql\`.`,
|
||||
assert: async (rig, result) => {
|
||||
await rig.waitForTelemetryReady();
|
||||
const wasToolCalled = rig
|
||||
.readToolLogs()
|
||||
.some((log) => log.toolRequest.name === 'save_memory');
|
||||
const wasToolCalled = await rig.waitForToolCall(
|
||||
'save_memory',
|
||||
undefined,
|
||||
(args) => {
|
||||
try {
|
||||
const params = JSON.parse(args);
|
||||
return params.scope === 'project';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
);
|
||||
expect(
|
||||
wasToolCalled,
|
||||
'save_memory should not be called for workspace-specific information',
|
||||
).toBe(false);
|
||||
'Expected save_memory to be called with scope="project" for workspace-specific information',
|
||||
).toBe(true);
|
||||
|
||||
assertModelHasOutput(result);
|
||||
},
|
||||
@@ -188,42 +196,59 @@ describe('save_memory', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const ignoringBuildArtifactLocation =
|
||||
'Agent ignores workspace build artifact location';
|
||||
const savingBuildArtifactLocationAsProjectMemory =
|
||||
'Agent saves workspace build artifact location as project memory';
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: ignoringBuildArtifactLocation,
|
||||
name: savingBuildArtifactLocationAsProjectMemory,
|
||||
prompt: `In this workspace, build artifacts are stored in the \`dist/artifacts\` directory.`,
|
||||
assert: async (rig, result) => {
|
||||
await rig.waitForTelemetryReady();
|
||||
const wasToolCalled = rig
|
||||
.readToolLogs()
|
||||
.some((log) => log.toolRequest.name === 'save_memory');
|
||||
const wasToolCalled = await rig.waitForToolCall(
|
||||
'save_memory',
|
||||
undefined,
|
||||
(args) => {
|
||||
try {
|
||||
const params = JSON.parse(args);
|
||||
return params.scope === 'project';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
);
|
||||
expect(
|
||||
wasToolCalled,
|
||||
'save_memory should not be called for workspace-specific information',
|
||||
).toBe(false);
|
||||
'Expected save_memory to be called with scope="project" for workspace-specific information',
|
||||
).toBe(true);
|
||||
|
||||
assertModelHasOutput(result);
|
||||
},
|
||||
});
|
||||
|
||||
const ignoringMainEntryPoint = "Agent ignores workspace's main entry point";
|
||||
const savingMainEntryPointAsProjectMemory =
|
||||
'Agent saves workspace main entry point as project memory';
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: ignoringMainEntryPoint,
|
||||
name: savingMainEntryPointAsProjectMemory,
|
||||
prompt: `The main entry point for this workspace is \`src/index.js\`.`,
|
||||
assert: async (rig, result) => {
|
||||
await rig.waitForTelemetryReady();
|
||||
const wasToolCalled = rig
|
||||
.readToolLogs()
|
||||
.some((log) => log.toolRequest.name === 'save_memory');
|
||||
const wasToolCalled = await rig.waitForToolCall(
|
||||
'save_memory',
|
||||
undefined,
|
||||
(args) => {
|
||||
try {
|
||||
const params = JSON.parse(args);
|
||||
return params.scope === 'project';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
);
|
||||
expect(
|
||||
wasToolCalled,
|
||||
'save_memory should not be called for workspace-specific information',
|
||||
).toBe(false);
|
||||
'Expected save_memory to be called with scope="project" for workspace-specific information',
|
||||
).toBe(true);
|
||||
|
||||
assertModelHasOutput(result);
|
||||
},
|
||||
@@ -317,13 +342,13 @@ describe('save_memory', () => {
|
||||
'Please save any persistent preferences or facts about me from our conversation to memory.',
|
||||
assert: async (rig, result) => {
|
||||
const wasToolCalled = await rig.waitForToolCall(
|
||||
'save_memory',
|
||||
'invoke_agent',
|
||||
undefined,
|
||||
(args) => /vitest/i.test(args),
|
||||
(args) => /save_memory/i.test(args) && /vitest/i.test(args),
|
||||
);
|
||||
expect(
|
||||
wasToolCalled,
|
||||
'Expected save_memory to be called with the Vitest preference from the conversation history',
|
||||
'Expected invoke_agent to be called with save_memory agent and the Vitest preference from the conversation history',
|
||||
).toBe(true);
|
||||
|
||||
assertModelHasOutput(result);
|
||||
@@ -379,8 +404,15 @@ describe('save_memory', () => {
|
||||
],
|
||||
prompt: 'Please save the preferences I mentioned earlier to memory.',
|
||||
assert: async (rig, result) => {
|
||||
const wasToolCalled = await rig.waitForToolCall('save_memory');
|
||||
expect(wasToolCalled, 'Expected save_memory to be called').toBe(true);
|
||||
const wasToolCalled = await rig.waitForToolCall(
|
||||
'invoke_agent',
|
||||
undefined,
|
||||
(args) => /save_memory/i.test(args),
|
||||
);
|
||||
expect(
|
||||
wasToolCalled,
|
||||
'Expected invoke_agent to be called with save_memory agent',
|
||||
).toBe(true);
|
||||
|
||||
assertModelHasOutput(result);
|
||||
},
|
||||
|
||||
@@ -0,0 +1,349 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import fsp from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { describe, expect } from 'vitest';
|
||||
import {
|
||||
type Config,
|
||||
ApprovalMode,
|
||||
SESSION_FILE_PREFIX,
|
||||
getProjectHash,
|
||||
startMemoryService,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { componentEvalTest } from './component-test-helper.js';
|
||||
|
||||
interface SeedSession {
|
||||
sessionId: string;
|
||||
summary: string;
|
||||
userTurns: string[];
|
||||
timestampOffsetMinutes: number;
|
||||
}
|
||||
|
||||
interface MessageRecord {
|
||||
id: string;
|
||||
timestamp: string;
|
||||
type: string;
|
||||
content: Array<{ text: string }>;
|
||||
}
|
||||
|
||||
const WORKSPACE_FILES = {
|
||||
'package.json': JSON.stringify(
|
||||
{
|
||||
name: 'skill-extraction-eval',
|
||||
private: true,
|
||||
scripts: {
|
||||
build: 'echo build',
|
||||
lint: 'echo lint',
|
||||
test: 'echo test',
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
'README.md': `# Skill Extraction Eval
|
||||
|
||||
This workspace exists to exercise background skill extraction from prior chats.
|
||||
`,
|
||||
};
|
||||
|
||||
function buildMessages(userTurns: string[]): MessageRecord[] {
|
||||
const baseTime = new Date(Date.now() - 6 * 60 * 60 * 1000).toISOString();
|
||||
return userTurns.flatMap((text, index) => [
|
||||
{
|
||||
id: `u${index + 1}`,
|
||||
timestamp: baseTime,
|
||||
type: 'user',
|
||||
content: [{ text }],
|
||||
},
|
||||
{
|
||||
id: `a${index + 1}`,
|
||||
timestamp: baseTime,
|
||||
type: 'gemini',
|
||||
content: [{ text: `Acknowledged: ${index + 1}` }],
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
async function seedSessions(
|
||||
config: Config,
|
||||
sessions: SeedSession[],
|
||||
): Promise<void> {
|
||||
const chatsDir = path.join(config.storage.getProjectTempDir(), 'chats');
|
||||
await fsp.mkdir(chatsDir, { recursive: true });
|
||||
|
||||
const projectRoot = config.storage.getProjectRoot();
|
||||
|
||||
for (const session of sessions) {
|
||||
const timestamp = new Date(
|
||||
Date.now() - session.timestampOffsetMinutes * 60 * 1000,
|
||||
)
|
||||
.toISOString()
|
||||
.slice(0, 16)
|
||||
.replace(/:/g, '-');
|
||||
const filename = `${SESSION_FILE_PREFIX}${timestamp}-${session.sessionId.slice(0, 8)}.json`;
|
||||
const conversation = {
|
||||
sessionId: session.sessionId,
|
||||
projectHash: getProjectHash(projectRoot),
|
||||
summary: session.summary,
|
||||
startTime: new Date(Date.now() - 7 * 60 * 60 * 1000).toISOString(),
|
||||
lastUpdated: new Date(Date.now() - 4 * 60 * 60 * 1000).toISOString(),
|
||||
messages: buildMessages(session.userTurns),
|
||||
};
|
||||
|
||||
await fsp.writeFile(
|
||||
path.join(chatsDir, filename),
|
||||
JSON.stringify(conversation, null, 2),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function runExtractionAndReadState(config: Config): Promise<{
|
||||
state: { runs: Array<{ sessionIds: string[]; skillsCreated: string[] }> };
|
||||
skillsDir: string;
|
||||
}> {
|
||||
await startMemoryService(config);
|
||||
|
||||
const memoryDir = config.storage.getProjectMemoryTempDir();
|
||||
const skillsDir = config.storage.getProjectSkillsMemoryDir();
|
||||
const statePath = path.join(memoryDir, '.extraction-state.json');
|
||||
|
||||
const raw = await fsp.readFile(statePath, 'utf-8');
|
||||
const state = JSON.parse(raw) as {
|
||||
runs?: Array<{ sessionIds?: string[]; skillsCreated?: string[] }>;
|
||||
};
|
||||
if (!Array.isArray(state.runs) || state.runs.length === 0) {
|
||||
throw new Error('Skill extraction finished without writing any run state');
|
||||
}
|
||||
|
||||
return {
|
||||
state: {
|
||||
runs: state.runs.map((run) => ({
|
||||
sessionIds: Array.isArray(run.sessionIds) ? run.sessionIds : [],
|
||||
skillsCreated: Array.isArray(run.skillsCreated)
|
||||
? run.skillsCreated
|
||||
: [],
|
||||
})),
|
||||
},
|
||||
skillsDir,
|
||||
};
|
||||
}
|
||||
|
||||
async function readSkillBodies(skillsDir: string): Promise<string[]> {
|
||||
try {
|
||||
const entries = await fsp.readdir(skillsDir, { withFileTypes: true });
|
||||
const skillDirs = entries.filter((entry) => entry.isDirectory());
|
||||
const bodies = await Promise.all(
|
||||
skillDirs.map((entry) =>
|
||||
fsp.readFile(path.join(skillsDir, entry.name, 'SKILL.md'), 'utf-8'),
|
||||
),
|
||||
);
|
||||
return bodies;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared configOverrides for all skill extraction component evals.
|
||||
* - experimentalAutoMemory: enables the Auto Memory skill extraction pipeline.
|
||||
* - approvalMode: YOLO auto-approves tool calls (write_file, read_file) so the
|
||||
* background agent can execute without interactive confirmation.
|
||||
*/
|
||||
const EXTRACTION_CONFIG_OVERRIDES = {
|
||||
experimentalAutoMemory: true,
|
||||
approvalMode: ApprovalMode.YOLO,
|
||||
};
|
||||
|
||||
describe('Skill Extraction', () => {
|
||||
componentEvalTest('USUALLY_PASSES', {
|
||||
suiteName: 'skill-extraction',
|
||||
suiteType: 'component-level',
|
||||
name: 'ignores one-off incidents even when session summaries look similar',
|
||||
files: WORKSPACE_FILES,
|
||||
timeout: 180000,
|
||||
configOverrides: EXTRACTION_CONFIG_OVERRIDES,
|
||||
setup: async (config) => {
|
||||
await seedSessions(config, [
|
||||
{
|
||||
sessionId: 'incident-login-redirect',
|
||||
summary: 'Debug login redirect loop in staging',
|
||||
timestampOffsetMinutes: 420,
|
||||
userTurns: [
|
||||
'We only need a one-off fix for incident INC-4412 on branch hotfix/login-loop.',
|
||||
'The exact failing string is ERR_REDIRECT_4412 and this workaround is incident-specific.',
|
||||
'Patch packages/auth/src/redirect.ts just for this branch and do not generalize it.',
|
||||
'The thing that worked was deleting the stale staging cookie before retrying.',
|
||||
'This is not a normal workflow and should not become a reusable instruction.',
|
||||
'It only reproduced against the 2026-04-08 staging rollout.',
|
||||
'After the cookie clear, the branch-specific redirect logic passed.',
|
||||
'Do not turn this incident writeup into a standing process.',
|
||||
'Yes, the hotfix worked for this exact redirect-loop incident.',
|
||||
'Close out INC-4412 once the staging login succeeds again.',
|
||||
],
|
||||
},
|
||||
{
|
||||
sessionId: 'incident-login-timeout',
|
||||
summary: 'Debug login callback timeout in staging',
|
||||
timestampOffsetMinutes: 360,
|
||||
userTurns: [
|
||||
'This is another one-off staging incident, this time TICKET-991 for callback timeout.',
|
||||
'The exact failing string is ERR_CALLBACK_TIMEOUT_991 and it is unrelated to the redirect loop.',
|
||||
'The temporary fix was rotating the staging secret and deleting a bad feature-flag row.',
|
||||
'Do not write a generic login-debugging playbook from this.',
|
||||
'This only applied to the callback timeout during the April rollout.',
|
||||
'The successful fix was specific to the stale secret in staging.',
|
||||
'It does not define a durable repo workflow for future tasks.',
|
||||
'After rotating the secret, the callback timeout stopped reproducing.',
|
||||
'Treat this as incident response only, not a reusable skill.',
|
||||
'Once staging passed again, we closed TICKET-991.',
|
||||
],
|
||||
},
|
||||
]);
|
||||
},
|
||||
assert: async (config) => {
|
||||
const { state, skillsDir } = await runExtractionAndReadState(config);
|
||||
const skillBodies = await readSkillBodies(skillsDir);
|
||||
|
||||
expect(state.runs).toHaveLength(1);
|
||||
expect(state.runs[0].sessionIds).toHaveLength(2);
|
||||
expect(state.runs[0].skillsCreated).toEqual([]);
|
||||
expect(skillBodies).toEqual([]);
|
||||
},
|
||||
});
|
||||
|
||||
componentEvalTest('USUALLY_PASSES', {
|
||||
suiteName: 'skill-extraction',
|
||||
suiteType: 'component-level',
|
||||
name: 'extracts a repeated project-specific workflow into a skill',
|
||||
files: WORKSPACE_FILES,
|
||||
timeout: 180000,
|
||||
configOverrides: EXTRACTION_CONFIG_OVERRIDES,
|
||||
setup: async (config) => {
|
||||
await seedSessions(config, [
|
||||
{
|
||||
sessionId: 'settings-docs-regen-1',
|
||||
summary: 'Update settings docs after adding a config option',
|
||||
timestampOffsetMinutes: 420,
|
||||
userTurns: [
|
||||
'When we add a new config option, we have to regenerate the settings docs in a specific order.',
|
||||
'The sequence that worked was npm run predocs:settings, npm run schema:settings, then npm run docs:settings.',
|
||||
'Do not hand-edit generated settings docs.',
|
||||
'If predocs is skipped, the generated schema docs miss the new defaults.',
|
||||
'Update the source first, then run that generation sequence.',
|
||||
'After regenerating, verify the schema output and docs changed together.',
|
||||
'We used this same sequence the last time we touched settings docs.',
|
||||
'That ordered workflow passed and produced the expected generated files.',
|
||||
'Please keep the exact command order because reversing it breaks the output.',
|
||||
'Yes, the generated settings docs were correct after those three commands.',
|
||||
],
|
||||
},
|
||||
{
|
||||
sessionId: 'settings-docs-regen-2',
|
||||
summary: 'Regenerate settings schema docs for another new setting',
|
||||
timestampOffsetMinutes: 360,
|
||||
userTurns: [
|
||||
'We are touching another setting, so follow the same settings-doc regeneration workflow again.',
|
||||
'Run npm run predocs:settings before npm run schema:settings and npm run docs:settings.',
|
||||
'The project keeps generated settings docs in sync through those commands, not manual edits.',
|
||||
'Skipping predocs caused stale defaults in the generated output before.',
|
||||
'Change the source, then execute the same three commands in order.',
|
||||
'Verify both the schema artifact and docs update together after regeneration.',
|
||||
'This is the recurring workflow we use whenever a setting changes.',
|
||||
'The exact order worked again on this second settings update.',
|
||||
'Please preserve that ordering constraint for future settings changes.',
|
||||
'Confirmed: the settings docs regenerated correctly with the same command sequence.',
|
||||
],
|
||||
},
|
||||
]);
|
||||
},
|
||||
assert: async (config) => {
|
||||
const { state, skillsDir } = await runExtractionAndReadState(config);
|
||||
const skillBodies = await readSkillBodies(skillsDir);
|
||||
const combinedSkills = skillBodies.join('\n\n');
|
||||
|
||||
expect(state.runs).toHaveLength(1);
|
||||
expect(state.runs[0].sessionIds).toHaveLength(2);
|
||||
expect(state.runs[0].skillsCreated.length).toBeGreaterThanOrEqual(1);
|
||||
expect(skillBodies.length).toBeGreaterThanOrEqual(1);
|
||||
expect(combinedSkills).toContain('npm run predocs:settings');
|
||||
expect(combinedSkills).toContain('npm run schema:settings');
|
||||
expect(combinedSkills).toContain('npm run docs:settings');
|
||||
expect(combinedSkills).toMatch(/Verification/i);
|
||||
|
||||
// Verify the extraction agent activated skill-creator for design guidance.
|
||||
expect(config.getSkillManager().isSkillActive('skill-creator')).toBe(
|
||||
true,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentEvalTest('USUALLY_PASSES', {
|
||||
suiteName: 'skill-extraction',
|
||||
suiteType: 'component-level',
|
||||
name: 'extracts a repeated multi-step migration workflow with ordering constraints',
|
||||
files: WORKSPACE_FILES,
|
||||
timeout: 180000,
|
||||
configOverrides: EXTRACTION_CONFIG_OVERRIDES,
|
||||
setup: async (config) => {
|
||||
await seedSessions(config, [
|
||||
{
|
||||
sessionId: 'db-migration-v12',
|
||||
summary: 'Run database migration for v12 schema update',
|
||||
timestampOffsetMinutes: 420,
|
||||
userTurns: [
|
||||
'Every time we change the database schema we follow a specific migration workflow.',
|
||||
'First run npm run db:check to verify no pending migrations conflict.',
|
||||
'Then run npm run db:migrate to apply the new migration files.',
|
||||
'After migration, always run npm run db:validate to confirm schema integrity.',
|
||||
'If db:validate fails, immediately run npm run db:rollback before anything else.',
|
||||
'Never skip db:check — last time we did, two migrations collided and corrupted the index.',
|
||||
'The ordering is critical: check, migrate, validate. Reversing migrate and validate caused silent data loss before.',
|
||||
'This v12 migration passed after following that exact sequence.',
|
||||
'We use this same three-step workflow every time the schema changes.',
|
||||
'Confirmed: db:check, db:migrate, db:validate completed successfully for v12.',
|
||||
],
|
||||
},
|
||||
{
|
||||
sessionId: 'db-migration-v13',
|
||||
summary: 'Run database migration for v13 schema update',
|
||||
timestampOffsetMinutes: 360,
|
||||
userTurns: [
|
||||
'New schema change for v13, following the same database migration workflow as before.',
|
||||
'Start with npm run db:check to ensure no conflicting pending migrations.',
|
||||
'Then npm run db:migrate to apply the v13 migration files.',
|
||||
'Then npm run db:validate to confirm the schema is consistent.',
|
||||
'If validation fails, run npm run db:rollback immediately — do not attempt manual fixes.',
|
||||
'We learned the hard way that skipping db:check causes index corruption.',
|
||||
'The check-migrate-validate order is mandatory for every schema change.',
|
||||
'This is the same recurring workflow we used for v12 and earlier migrations.',
|
||||
'The v13 migration passed with the same three-step sequence.',
|
||||
'Confirmed: the standard db migration workflow succeeded again for v13.',
|
||||
],
|
||||
},
|
||||
]);
|
||||
},
|
||||
assert: async (config) => {
|
||||
const { state, skillsDir } = await runExtractionAndReadState(config);
|
||||
const skillBodies = await readSkillBodies(skillsDir);
|
||||
const combinedSkills = skillBodies.join('\n\n');
|
||||
|
||||
expect(state.runs).toHaveLength(1);
|
||||
expect(state.runs[0].sessionIds).toHaveLength(2);
|
||||
expect(state.runs[0].skillsCreated.length).toBeGreaterThanOrEqual(1);
|
||||
expect(skillBodies.length).toBeGreaterThanOrEqual(1);
|
||||
expect(combinedSkills).toContain('npm run db:check');
|
||||
expect(combinedSkills).toContain('npm run db:migrate');
|
||||
expect(combinedSkills).toContain('npm run db:validate');
|
||||
expect(combinedSkills).toMatch(/rollback/i);
|
||||
|
||||
// Verify the extraction agent activated skill-creator for design guidance.
|
||||
expect(config.getSkillManager().isSkillActive('skill-creator')).toBe(
|
||||
true,
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, expect } from 'vitest';
|
||||
import { TRACKER_CREATE_TASK_TOOL_NAME } from '@google/gemini-cli-core';
|
||||
import { evalTest, TEST_AGENTS } from './test-helper.js';
|
||||
|
||||
describe('subtask delegation eval test cases', () => {
|
||||
/**
|
||||
* Checks that the main agent can correctly decompose a complex, sequential
|
||||
* task into subtasks using the task tracker and delegate each to the appropriate expert subagent.
|
||||
*
|
||||
* The task requires:
|
||||
* 1. Reading requirements (researcher)
|
||||
* 2. Implementing logic (developer)
|
||||
* 3. Documenting (doc expert)
|
||||
*/
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'should delegate sequential subtasks to relevant experts using the task tracker',
|
||||
params: {
|
||||
settings: {
|
||||
experimental: {
|
||||
enableAgents: true,
|
||||
taskTracker: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
prompt:
|
||||
'Please read the requirements in requirements.txt using a researcher, then implement the requested logic in src/logic.ts using a developer, and finally document the implementation in docs/logic.md using a documentation expert.',
|
||||
files: {
|
||||
'.gemini/agents/researcher.md': `---
|
||||
name: researcher
|
||||
description: Expert in reading files and extracting requirements.
|
||||
tools:
|
||||
- read_file
|
||||
---
|
||||
You are the researcher. Read the provided file and extract requirements.`,
|
||||
'.gemini/agents/developer.md': `---
|
||||
name: developer
|
||||
description: Expert in implementing logic in TypeScript.
|
||||
tools:
|
||||
- write_file
|
||||
---
|
||||
You are the developer. Implement the requested logic in the specified file.`,
|
||||
'.gemini/agents/doc-expert.md': `---
|
||||
name: doc-expert
|
||||
description: Expert in writing technical documentation.
|
||||
tools:
|
||||
- write_file
|
||||
---
|
||||
You are the doc expert. Document the provided implementation clearly.`,
|
||||
'requirements.txt':
|
||||
'Implement a function named "calculateSum" that adds two numbers.',
|
||||
},
|
||||
assert: async (rig, _result) => {
|
||||
// Verify tracker tasks were created
|
||||
const wasCreateCalled = await rig.waitForToolCall(
|
||||
TRACKER_CREATE_TASK_TOOL_NAME,
|
||||
);
|
||||
expect(wasCreateCalled).toBe(true);
|
||||
|
||||
const toolLogs = rig.readToolLogs();
|
||||
const createCalls = toolLogs.filter(
|
||||
(l) => l.toolRequest.name === TRACKER_CREATE_TASK_TOOL_NAME,
|
||||
);
|
||||
expect(createCalls.length).toBeGreaterThanOrEqual(3);
|
||||
|
||||
await rig.expectToolCallSuccess([
|
||||
'researcher',
|
||||
'developer',
|
||||
'doc-expert',
|
||||
]);
|
||||
|
||||
const logicFile = rig.readFile('src/logic.ts');
|
||||
const docFile = rig.readFile('docs/logic.md');
|
||||
|
||||
expect(logicFile).toContain('calculateSum');
|
||||
expect(docFile).toBeTruthy();
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that the main agent can delegate a batch of independent subtasks
|
||||
* to multiple subagents in parallel using the task tracker to manage state.
|
||||
*/
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'should delegate independent subtasks to specialists using the task tracker',
|
||||
params: {
|
||||
settings: {
|
||||
experimental: {
|
||||
enableAgents: true,
|
||||
taskTracker: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
prompt:
|
||||
'Please update the project for internationalization (i18n), audit the security of the current code, and update the CSS to use a blue theme. Use specialized experts for each task.',
|
||||
files: {
|
||||
...TEST_AGENTS.I18N_AGENT.asFile(),
|
||||
...TEST_AGENTS.SECURITY_AGENT.asFile(),
|
||||
...TEST_AGENTS.CSS_AGENT.asFile(),
|
||||
'index.ts': 'console.log("Hello World");',
|
||||
},
|
||||
assert: async (rig, _result) => {
|
||||
// Verify tracker tasks were created
|
||||
const wasCreateCalled = await rig.waitForToolCall(
|
||||
TRACKER_CREATE_TASK_TOOL_NAME,
|
||||
);
|
||||
expect(wasCreateCalled).toBe(true);
|
||||
|
||||
const toolLogs = rig.readToolLogs();
|
||||
const createCalls = toolLogs.filter(
|
||||
(l) => l.toolRequest.name === TRACKER_CREATE_TASK_TOOL_NAME,
|
||||
);
|
||||
expect(createCalls.length).toBeGreaterThanOrEqual(3);
|
||||
|
||||
await rig.expectToolCallSuccess([
|
||||
TEST_AGENTS.I18N_AGENT.name,
|
||||
TEST_AGENTS.SECURITY_AGENT.name,
|
||||
TEST_AGENTS.CSS_AGENT.name,
|
||||
]);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -119,6 +119,8 @@ describe('tracker_mode', () => {
|
||||
});
|
||||
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'should correctly identify the task tracker storage location from the system prompt',
|
||||
params: {
|
||||
settings: { experimental: { taskTracker: true } },
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"paths": {
|
||||
"@google/gemini-cli-core": ["../packages/core/index.ts"],
|
||||
"@google/gemini-cli": ["../packages/cli/index.ts"]
|
||||
}
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"exclude": ["logs"],
|
||||
"references": [{ "path": "../packages/core" }, { "path": "../packages/cli" }]
|
||||
}
|
||||
@@ -7,6 +7,8 @@
|
||||
import { evalTest, TestRig } from './test-helper.js';
|
||||
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'Reproduction: Agent uses Object.create() for cloning/delegation',
|
||||
prompt:
|
||||
'Create a utility function `createScopedConfig(config: Config, additionalDirectories: string[]): Config` in `packages/core/src/config/scoped-config.ts` that returns a new Config instance. This instance should override `getWorkspaceContext()` to include the additional directories, but delegate all other method calls (like `isPathAllowed` or `validatePathAccess`) to the original config. Note that `Config` is a complex class with private state and cannot be easily shallow-copied or reconstructed.',
|
||||
|
||||
@@ -21,6 +21,8 @@ describe('update_topic_behavior', () => {
|
||||
* more than 1/4 turns.
|
||||
*/
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'update_topic should be used at start, end and middle for complex tasks',
|
||||
prompt: `Create a simple users REST API using Express.
|
||||
1. Initialize a new npm project and install express.
|
||||
@@ -41,7 +43,7 @@ describe('update_topic_behavior', () => {
|
||||
2,
|
||||
),
|
||||
'.gemini/settings.json': JSON.stringify({
|
||||
experimental: {
|
||||
general: {
|
||||
topicUpdateNarration: true,
|
||||
},
|
||||
}),
|
||||
@@ -117,13 +119,15 @@ describe('update_topic_behavior', () => {
|
||||
});
|
||||
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'update_topic should NOT be used for informational coding tasks (Obvious)',
|
||||
approvalMode: 'default',
|
||||
prompt:
|
||||
'Explain the difference between Map and Object in JavaScript and provide a performance-focused code snippet for each.',
|
||||
files: {
|
||||
'.gemini/settings.json': JSON.stringify({
|
||||
experimental: {
|
||||
general: {
|
||||
topicUpdateNarration: true,
|
||||
},
|
||||
}),
|
||||
@@ -142,6 +146,8 @@ describe('update_topic_behavior', () => {
|
||||
});
|
||||
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'update_topic should NOT be used for surgical symbol searches (Grey Area)',
|
||||
approvalMode: 'default',
|
||||
prompt:
|
||||
@@ -150,7 +156,7 @@ describe('update_topic_behavior', () => {
|
||||
'packages/core/src/tools/tool-names.ts':
|
||||
"export const UPDATE_TOPIC_TOOL_NAME = 'update_topic';",
|
||||
'.gemini/settings.json': JSON.stringify({
|
||||
experimental: {
|
||||
general: {
|
||||
topicUpdateNarration: true,
|
||||
},
|
||||
}),
|
||||
@@ -169,6 +175,8 @@ describe('update_topic_behavior', () => {
|
||||
});
|
||||
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'update_topic should be used for medium complexity multi-step tasks',
|
||||
prompt:
|
||||
'Refactor the `users-api` project. Move the routing logic from src/app.ts into a new file src/routes.ts, and update app.ts to use the new routes file.',
|
||||
@@ -196,7 +204,7 @@ app.post('/users', (req, res) => {
|
||||
export default app;
|
||||
`,
|
||||
'.gemini/settings.json': JSON.stringify({
|
||||
experimental: {
|
||||
general: {
|
||||
topicUpdateNarration: true,
|
||||
},
|
||||
}),
|
||||
@@ -212,7 +220,9 @@ export default app;
|
||||
expect(topicCalls.length).toBeGreaterThanOrEqual(2);
|
||||
|
||||
// Verify it actually did the refactoring to ensure it didn't just fail immediately
|
||||
expect(fs.existsSync(path.join(rig.testDir, 'src/routes.ts'))).toBe(true);
|
||||
expect(fs.existsSync(path.join(rig.testDir!, 'src/routes.ts'))).toBe(
|
||||
true,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -224,6 +234,8 @@ export default app;
|
||||
* the prompt change that improves the behavior.
|
||||
*/
|
||||
evalTest('USUALLY_PASSES', {
|
||||
suiteName: 'default',
|
||||
suiteType: 'behavioral',
|
||||
name: 'update_topic should not be called twice in a row',
|
||||
prompt: `
|
||||
We need to build a C compiler.
|
||||
@@ -237,7 +249,7 @@ export default app;
|
||||
files: {
|
||||
'package.json': JSON.stringify({ name: 'test-project' }),
|
||||
'.gemini/settings.json': JSON.stringify({
|
||||
experimental: {
|
||||
general: {
|
||||
topicUpdateNarration: true,
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -39,7 +39,11 @@ describe('web-fetch rate limiting', () => {
|
||||
const rateLimitedCalls = toolLogs.filter(
|
||||
(log) =>
|
||||
log.toolRequest.name === 'web_fetch' &&
|
||||
log.toolRequest.error?.includes('Rate limit exceeded'),
|
||||
(
|
||||
('error' in log.toolRequest
|
||||
? (log.toolRequest as unknown as Record<string, string>)['error']
|
||||
: '') as string
|
||||
)?.includes('Rate limit exceeded'),
|
||||
);
|
||||
|
||||
expect(rateLimitedCalls.length).toBeGreaterThan(0);
|
||||
|
||||
@@ -164,7 +164,8 @@ describe.skipIf(skipFlaky)(
|
||||
);
|
||||
expect(blockHook).toBeDefined();
|
||||
expect(
|
||||
blockHook?.hookCall.stdout + blockHook?.hookCall.stderr,
|
||||
(blockHook?.hookCall.stdout || '') +
|
||||
(blockHook?.hookCall.stderr || ''),
|
||||
).toContain(blockMsg);
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"functionCall":{"name":"list_mcp_resources","args":{}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}]}
|
||||
{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"Here are the resources: test://resource1"}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}]}
|
||||
@@ -0,0 +1,2 @@
|
||||
{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"functionCall":{"name":"read_mcp_resource","args":{"uri":"test://resource1"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}]}
|
||||
{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"The content is: content of resource 1"}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}]}
|
||||
@@ -0,0 +1,4 @@
|
||||
{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"functionCall":{"name":"list_mcp_resources","args":{}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}]}
|
||||
{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"Here are the resources: test://resource1"}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}]}
|
||||
{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"functionCall":{"name":"read_mcp_resource","args":{"uri":"test://resource1"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}]}
|
||||
{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"The content is: content of resource 1"}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}]}
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { TestRig } from './test-helper.js';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import fs from 'node:fs';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
describe('mcp-resources-integration', () => {
|
||||
let rig: TestRig;
|
||||
|
||||
beforeEach(() => {
|
||||
rig = new TestRig();
|
||||
});
|
||||
|
||||
afterEach(async () => await rig.cleanup());
|
||||
|
||||
it('should list mcp resources', async () => {
|
||||
await rig.setup('mcp-list-resources-test', {
|
||||
settings: {
|
||||
model: {
|
||||
name: 'gemini-3-flash-preview',
|
||||
},
|
||||
},
|
||||
fakeResponsesPath: join(__dirname, 'mcp-list-resources.responses'),
|
||||
});
|
||||
|
||||
// Workaround for ProjectRegistry save issue
|
||||
const userGeminiDir = join(rig.homeDir!, '.gemini');
|
||||
fs.writeFileSync(join(userGeminiDir, 'projects.json'), '{"projects":{}}');
|
||||
|
||||
// Add a dummy server to get setup done
|
||||
rig.addTestMcpServer('resource-server', {
|
||||
name: 'resource-server',
|
||||
tools: [],
|
||||
});
|
||||
|
||||
// Overwrite the script with resource support
|
||||
const scriptPath = join(rig.testDir!, 'test-mcp-resource-server.mjs');
|
||||
const scriptContent = `
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
import {
|
||||
ListResourcesRequestSchema,
|
||||
} from '@modelcontextprotocol/sdk/types.js';
|
||||
|
||||
const server = new Server(
|
||||
{
|
||||
name: 'resource-server',
|
||||
version: '1.0.0',
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
resources: {},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
||||
return {
|
||||
resources: [
|
||||
{
|
||||
uri: 'test://resource1',
|
||||
name: 'Resource 1',
|
||||
mimeType: 'text/plain',
|
||||
description: 'A test resource',
|
||||
}
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
`;
|
||||
fs.writeFileSync(scriptPath, scriptContent);
|
||||
|
||||
const output = await rig.run({
|
||||
args: 'List all available MCP resources.',
|
||||
env: { GEMINI_API_KEY: 'dummy' },
|
||||
});
|
||||
|
||||
const foundCall = await rig.waitForToolCall('list_mcp_resources');
|
||||
expect(foundCall).toBeTruthy();
|
||||
expect(output).toContain('test://resource1');
|
||||
}, 60000);
|
||||
|
||||
it('should read mcp resource', async () => {
|
||||
await rig.setup('mcp-read-resource-test', {
|
||||
settings: {
|
||||
model: {
|
||||
name: 'gemini-3-flash-preview',
|
||||
},
|
||||
},
|
||||
fakeResponsesPath: join(__dirname, 'mcp-read-resource.responses'),
|
||||
});
|
||||
|
||||
// Workaround for ProjectRegistry save issue
|
||||
const userGeminiDir = join(rig.homeDir!, '.gemini');
|
||||
fs.writeFileSync(join(userGeminiDir, 'projects.json'), '{"projects":{}}');
|
||||
|
||||
// Add a dummy server to get setup done
|
||||
rig.addTestMcpServer('resource-server', {
|
||||
name: 'resource-server',
|
||||
tools: [],
|
||||
});
|
||||
|
||||
// Overwrite the script with resource support
|
||||
const scriptPath = join(rig.testDir!, 'test-mcp-resource-server.mjs');
|
||||
const scriptContent = `
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
import {
|
||||
ListResourcesRequestSchema,
|
||||
ReadResourceRequestSchema,
|
||||
} from '@modelcontextprotocol/sdk/types.js';
|
||||
|
||||
const server = new Server(
|
||||
{
|
||||
name: 'resource-server',
|
||||
version: '1.0.0',
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
resources: {},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// Need to provide list resources so the tool is active!
|
||||
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
||||
return {
|
||||
resources: [
|
||||
{
|
||||
uri: 'test://resource1',
|
||||
name: 'Resource 1',
|
||||
mimeType: 'text/plain',
|
||||
description: 'A test resource',
|
||||
}
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
||||
if (request.params.uri === 'test://resource1') {
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: 'test://resource1',
|
||||
mimeType: 'text/plain',
|
||||
text: 'This is the content of resource 1',
|
||||
}
|
||||
],
|
||||
};
|
||||
}
|
||||
throw new Error('Resource not found');
|
||||
});
|
||||
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
`;
|
||||
fs.writeFileSync(scriptPath, scriptContent);
|
||||
|
||||
const output = await rig.run({
|
||||
args: 'Read the MCP resource test://resource1.',
|
||||
env: { GEMINI_API_KEY: 'dummy' },
|
||||
});
|
||||
|
||||
const foundCall = await rig.waitForToolCall('read_mcp_resource');
|
||||
expect(foundCall).toBeTruthy();
|
||||
expect(output).toContain('content of resource 1');
|
||||
}, 60000);
|
||||
});
|
||||
@@ -108,7 +108,7 @@ describe('Plan Mode', () => {
|
||||
).toBeDefined();
|
||||
expect(
|
||||
planWrite?.toolRequest.success,
|
||||
`Expected write_file to succeed, but it failed with error: ${planWrite?.toolRequest.error}`,
|
||||
`Expected write_file to succeed, but it failed with error: ${'error' in (planWrite?.toolRequest || {}) ? (planWrite?.toolRequest as unknown as Record<string, string>)['error'] : 'unknown'}`,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
@@ -221,7 +221,7 @@ describe('Plan Mode', () => {
|
||||
).toBeDefined();
|
||||
expect(
|
||||
planWrite?.toolRequest.success,
|
||||
`Expected write_file to succeed, but it failed with error: ${planWrite?.toolRequest.error}`,
|
||||
`Expected write_file to succeed, but it failed with error: ${'error' in (planWrite?.toolRequest || {}) ? (planWrite?.toolRequest as unknown as Record<string, string>)['error'] : 'unknown'}`,
|
||||
).toBe(true);
|
||||
});
|
||||
it('should switch from a pro model to a flash model after exiting plan mode', async () => {
|
||||
@@ -270,13 +270,24 @@ describe('Plan Mode', () => {
|
||||
);
|
||||
|
||||
const apiRequests = rig.readAllApiRequest();
|
||||
const modelNames = apiRequests.map((r) => r.attributes?.model || 'unknown');
|
||||
const modelNames = apiRequests.map(
|
||||
(r) =>
|
||||
('model' in (r.attributes || {})
|
||||
? (r.attributes as unknown as Record<string, string>)['model']
|
||||
: 'unknown') || 'unknown',
|
||||
);
|
||||
|
||||
const proRequests = apiRequests.filter((r) =>
|
||||
r.attributes?.model?.includes('pro'),
|
||||
('model' in (r.attributes || {})
|
||||
? (r.attributes as unknown as Record<string, string>)['model']
|
||||
: 'unknown'
|
||||
)?.includes('pro'),
|
||||
);
|
||||
const flashRequests = apiRequests.filter((r) =>
|
||||
r.attributes?.model?.includes('flash'),
|
||||
('model' in (r.attributes || {})
|
||||
? (r.attributes as unknown as Record<string, string>)['model']
|
||||
: 'unknown'
|
||||
)?.includes('flash'),
|
||||
);
|
||||
|
||||
expect(
|
||||
|
||||
@@ -5,5 +5,9 @@
|
||||
"allowJs": true
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"references": [{ "path": "../packages/core" }]
|
||||
"references": [
|
||||
{ "path": "../packages/core" },
|
||||
{ "path": "../packages/test-utils" },
|
||||
{ "path": "../packages/cli" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -489,8 +489,12 @@ async function generateSharedLargeChatData(tempDir: string) {
|
||||
|
||||
// Wait for streams to finish
|
||||
await Promise.all([
|
||||
new Promise((res) => activeResponsesStream.on('finish', res)),
|
||||
new Promise((res) => resumeResponsesStream.on('finish', res)),
|
||||
new Promise((res) =>
|
||||
activeResponsesStream.on('finish', () => res(undefined)),
|
||||
),
|
||||
new Promise((res) =>
|
||||
resumeResponsesStream.on('finish', () => res(undefined)),
|
||||
),
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@google/gemini-cli",
|
||||
"version": "0.39.0-nightly.20260408.e77b22e63",
|
||||
"version": "0.40.0-nightly.20260414.g5b1f7375a",
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
@@ -14,7 +14,7 @@
|
||||
"url": "git+https://github.com/google-gemini/gemini-cli.git"
|
||||
},
|
||||
"config": {
|
||||
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.39.0-nightly.20260408.e77b22e63"
|
||||
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.40.0-nightly.20260414.g5b1f7375a"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "cross-env NODE_ENV=development node scripts/start.js",
|
||||
@@ -62,7 +62,7 @@
|
||||
"lint:ci": "npm run lint:all",
|
||||
"lint:all": "node scripts/lint.js",
|
||||
"format": "prettier --experimental-cli --write .",
|
||||
"typecheck": "npm run typecheck --workspaces --if-present",
|
||||
"typecheck": "npm run typecheck --workspaces --if-present && tsc -b evals/tsconfig.json integration-tests/tsconfig.json memory-tests/tsconfig.json",
|
||||
"preflight": "npm run clean && npm ci && npm run format && npm run build && npm run lint:ci && npm run typecheck && npm run test:ci",
|
||||
"prepare": "husky && npm run bundle",
|
||||
"prepare:package": "node scripts/prepare-package.js",
|
||||
@@ -94,6 +94,7 @@
|
||||
],
|
||||
"devDependencies": {
|
||||
"@agentclientprotocol/sdk": "^0.16.1",
|
||||
"read-package-up": "^11.0.0",
|
||||
"@octokit/rest": "^22.0.0",
|
||||
"@types/marked": "^5.0.2",
|
||||
"@types/mime-types": "^3.0.1",
|
||||
@@ -137,6 +138,7 @@
|
||||
"strip-ansi": "^7.1.2",
|
||||
"ts-prune": "^0.10.3",
|
||||
"tsx": "^4.20.3",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.30.1",
|
||||
"vitest": "^3.2.4",
|
||||
"yargs": "^17.7.2"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@google/gemini-cli-a2a-server",
|
||||
"version": "0.39.0-nightly.20260408.e77b22e63",
|
||||
"version": "0.40.0-nightly.20260414.g5b1f7375a",
|
||||
"description": "Gemini CLI A2A Server",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@google/gemini-cli",
|
||||
"version": "0.39.0-nightly.20260408.e77b22e63",
|
||||
"version": "0.40.0-nightly.20260414.g5b1f7375a",
|
||||
"description": "Gemini CLI",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
@@ -27,7 +27,7 @@
|
||||
"dist"
|
||||
],
|
||||
"config": {
|
||||
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.39.0-nightly.20260408.e77b22e63"
|
||||
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.40.0-nightly.20260414.g5b1f7375a"
|
||||
},
|
||||
"dependencies": {
|
||||
"@agentclientprotocol/sdk": "^0.16.1",
|
||||
|
||||
@@ -135,10 +135,10 @@ export class InboxMemoryCommand implements Command {
|
||||
context: CommandContext,
|
||||
_: string[],
|
||||
): Promise<CommandExecutionResponse> {
|
||||
if (!context.agentContext.config.isMemoryManagerEnabled()) {
|
||||
if (!context.agentContext.config.isAutoMemoryEnabled()) {
|
||||
return {
|
||||
name: this.name,
|
||||
data: 'The memory inbox requires the experimental memory manager. Enable it with: experimental.memoryManager = true in settings.',
|
||||
data: 'The memory inbox requires Auto Memory. Enable it with: experimental.autoMemory = true in settings.',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -990,9 +990,12 @@ export async function loadCliConfig(
|
||||
disabledSkills: settings.skills?.disabled,
|
||||
experimentalJitContext: settings.experimental?.jitContext,
|
||||
experimentalMemoryManager: settings.experimental?.memoryManager,
|
||||
experimentalAutoMemory: settings.experimental?.autoMemory,
|
||||
contextManagement,
|
||||
modelSteering: settings.experimental?.modelSteering,
|
||||
topicUpdateNarration: settings.experimental?.topicUpdateNarration,
|
||||
topicUpdateNarration:
|
||||
settings.general?.topicUpdateNarration ??
|
||||
settings.experimental?.topicUpdateNarration,
|
||||
noBrowser: !!process.env['NO_BROWSER'],
|
||||
summarizeToolOutput: settings.model?.summarizeToolOutput,
|
||||
ideMode,
|
||||
|
||||
@@ -256,14 +256,29 @@ const SETTINGS_SCHEMA = {
|
||||
},
|
||||
enableNotifications: {
|
||||
type: 'boolean',
|
||||
label: 'Enable Notifications',
|
||||
label: 'Enable Terminal Notifications',
|
||||
category: 'General',
|
||||
requiresRestart: false,
|
||||
default: false,
|
||||
description:
|
||||
'Enable run-event notifications for action-required prompts and session completion.',
|
||||
'Enable terminal run-event notifications for action-required prompts and session completion.',
|
||||
showInDialog: true,
|
||||
},
|
||||
notificationMethod: {
|
||||
type: 'enum',
|
||||
label: 'Terminal Notification Method',
|
||||
category: 'General',
|
||||
requiresRestart: false,
|
||||
default: 'auto',
|
||||
description: 'How to send terminal notifications.',
|
||||
showInDialog: true,
|
||||
options: [
|
||||
{ value: 'auto', label: 'Auto' },
|
||||
{ value: 'osc9', label: 'OSC 9' },
|
||||
{ value: 'osc777', label: 'OSC 777' },
|
||||
{ value: 'bell', label: 'Bell' },
|
||||
],
|
||||
},
|
||||
checkpointing: {
|
||||
type: 'object',
|
||||
label: 'Checkpointing',
|
||||
@@ -403,6 +418,16 @@ const SETTINGS_SCHEMA = {
|
||||
},
|
||||
description: 'Settings for automatic session cleanup.',
|
||||
},
|
||||
topicUpdateNarration: {
|
||||
type: 'boolean',
|
||||
label: 'Topic & Update Narration',
|
||||
category: 'General',
|
||||
requiresRestart: false,
|
||||
default: true,
|
||||
description:
|
||||
'Enable the Topic & Update communication model for reduced chattiness and structured progress reporting.',
|
||||
showInDialog: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
output: {
|
||||
@@ -2188,6 +2213,16 @@ const SETTINGS_SCHEMA = {
|
||||
'Replace the built-in save_memory tool with a memory manager subagent that supports adding, removing, de-duplicating, and organizing memories.',
|
||||
showInDialog: true,
|
||||
},
|
||||
autoMemory: {
|
||||
type: 'boolean',
|
||||
label: 'Auto Memory',
|
||||
category: 'Experimental',
|
||||
requiresRestart: true,
|
||||
default: false,
|
||||
description:
|
||||
'Automatically extract reusable skills from past sessions in the background. Review results with /memory inbox.',
|
||||
showInDialog: true,
|
||||
},
|
||||
generalistProfile: {
|
||||
type: 'boolean',
|
||||
label: 'Use the generalist profile to manage agent contexts.',
|
||||
@@ -2213,9 +2248,8 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'Experimental',
|
||||
requiresRestart: false,
|
||||
default: false,
|
||||
description:
|
||||
'Enable the experimental Topic & Update communication model for reduced chattiness and structured progress reporting.',
|
||||
showInDialog: true,
|
||||
description: 'Deprecated: Use general.topicUpdateNarration instead.',
|
||||
showInDialog: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -88,7 +88,7 @@ describe('SkillCommandLoader', () => {
|
||||
type: 'tool',
|
||||
toolName: ACTIVATE_SKILL_TOOL_NAME,
|
||||
toolArgs: { name: 'test-skill' },
|
||||
postSubmitPrompt: undefined,
|
||||
postSubmitPrompt: 'Use the skill test-skill',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -46,7 +46,10 @@ export class SkillCommandLoader implements ICommandLoader {
|
||||
type: 'tool',
|
||||
toolName: ACTIVATE_SKILL_TOOL_NAME,
|
||||
toolArgs: { name: skill.name },
|
||||
postSubmitPrompt: args.trim().length > 0 ? args.trim() : undefined,
|
||||
postSubmitPrompt:
|
||||
args.trim().length > 0
|
||||
? args.trim()
|
||||
: `Use the skill ${skill.name}`,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -39,11 +39,13 @@ export const createMockConfig = (overrides: Partial<Config> = {}): Config =>
|
||||
fireSessionStartEvent: vi.fn().mockResolvedValue(undefined),
|
||||
})),
|
||||
isMemoryManagerEnabled: vi.fn(() => false),
|
||||
isAutoMemoryEnabled: vi.fn(() => false),
|
||||
getListExtensions: vi.fn(() => false),
|
||||
getExtensions: vi.fn(() => []),
|
||||
getListSessions: vi.fn(() => false),
|
||||
getDeleteSession: vi.fn(() => undefined),
|
||||
setSessionId: vi.fn(),
|
||||
resetNewSessionState: vi.fn(),
|
||||
getSessionId: vi.fn().mockReturnValue('mock-session-id'),
|
||||
getWorktreeSettings: vi.fn(() => undefined),
|
||||
getContentGeneratorConfig: vi.fn(() => ({ authType: 'google' })),
|
||||
|
||||
@@ -53,6 +53,7 @@ const mocks = vi.hoisted(() => ({
|
||||
const terminalNotificationsMocks = vi.hoisted(() => ({
|
||||
notifyViaTerminal: vi.fn().mockResolvedValue(true),
|
||||
isNotificationsEnabled: vi.fn(() => true),
|
||||
getNotificationMethod: vi.fn(() => 'auto'),
|
||||
buildRunEventNotificationContent: vi.fn((event) => ({
|
||||
title: 'Mock Notification',
|
||||
subtitle: 'Mock Subtitle',
|
||||
@@ -194,6 +195,7 @@ vi.mock('./hooks/useShellInactivityStatus.js', () => ({
|
||||
vi.mock('../utils/terminalNotifications.js', () => ({
|
||||
notifyViaTerminal: terminalNotificationsMocks.notifyViaTerminal,
|
||||
isNotificationsEnabled: terminalNotificationsMocks.isNotificationsEnabled,
|
||||
getNotificationMethod: terminalNotificationsMocks.getNotificationMethod,
|
||||
buildRunEventNotificationContent:
|
||||
terminalNotificationsMocks.buildRunEventNotificationContent,
|
||||
}));
|
||||
|
||||
@@ -181,7 +181,10 @@ import { useTimedMessage } from './hooks/useTimedMessage.js';
|
||||
import { useIsHelpDismissKey } from './utils/shortcutsHelp.js';
|
||||
import { useSuspend } from './hooks/useSuspend.js';
|
||||
import { useRunEventNotifications } from './hooks/useRunEventNotifications.js';
|
||||
import { isNotificationsEnabled } from '../utils/terminalNotifications.js';
|
||||
import {
|
||||
isNotificationsEnabled,
|
||||
getNotificationMethod,
|
||||
} from '../utils/terminalNotifications.js';
|
||||
import {
|
||||
getLastTurnToolCallIds,
|
||||
isToolExecuting,
|
||||
@@ -225,6 +228,7 @@ export const AppContainer = (props: AppContainerProps) => {
|
||||
const settings = useSettings();
|
||||
const { reset } = useOverflowActions()!;
|
||||
const notificationsEnabled = isNotificationsEnabled(settings);
|
||||
const notificationMethod = getNotificationMethod(settings);
|
||||
|
||||
const { setOptions, dumpCurrentFrame, startRecording, stopRecording } =
|
||||
useContext(InkAppContext);
|
||||
@@ -482,8 +486,8 @@ export const AppContainer = (props: AppContainerProps) => {
|
||||
setConfigInitialized(true);
|
||||
startupProfiler.flush(config);
|
||||
|
||||
// Fire-and-forget memory service (skill extraction from past sessions)
|
||||
if (config.isMemoryManagerEnabled()) {
|
||||
// Fire-and-forget Auto Memory service (skill extraction from past sessions)
|
||||
if (config.isAutoMemoryEnabled()) {
|
||||
startMemoryService(config).catch((e) => {
|
||||
debugLogger.error('Failed to start memory service:', e);
|
||||
});
|
||||
@@ -973,6 +977,7 @@ Logging in with Google... Restarting Gemini CLI to continue.
|
||||
openAgentConfigDialog,
|
||||
openPermissionsDialog,
|
||||
quit: (messages: HistoryItem[]) => {
|
||||
closeThemeDialog();
|
||||
setQuittingMessages(messages);
|
||||
setTimeout(async () => {
|
||||
await runExitCleanup();
|
||||
@@ -1001,6 +1006,7 @@ Logging in with Google... Restarting Gemini CLI to continue.
|
||||
[
|
||||
setAuthState,
|
||||
openThemeDialog,
|
||||
closeThemeDialog,
|
||||
openEditorDialog,
|
||||
openSettingsDialog,
|
||||
openSessionBrowser,
|
||||
@@ -2284,6 +2290,7 @@ Logging in with Google... Restarting Gemini CLI to continue.
|
||||
|
||||
useRunEventNotifications({
|
||||
notificationsEnabled,
|
||||
notificationMethod,
|
||||
isFocused,
|
||||
hasReceivedFocusEvent,
|
||||
streamingState,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { render } from '../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
||||
import { ApiAuthDialog } from './ApiAuthDialog.js';
|
||||
@@ -40,11 +40,16 @@ vi.mock('../components/shared/text-buffer.js', async (importOriginal) => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('../contexts/UIStateContext.js', () => ({
|
||||
useUIState: vi.fn(() => ({
|
||||
terminalWidth: 80,
|
||||
})),
|
||||
}));
|
||||
vi.mock('../contexts/UIStateContext.js', async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import('../contexts/UIStateContext.js')>();
|
||||
return {
|
||||
...actual,
|
||||
useUIState: vi.fn(() => ({
|
||||
terminalWidth: 80,
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
const mockedUseKeypress = useKeypress as Mock;
|
||||
const mockedUseTextBuffer = useTextBuffer as Mock;
|
||||
@@ -73,7 +78,7 @@ describe('ApiAuthDialog', () => {
|
||||
});
|
||||
|
||||
it('renders correctly', async () => {
|
||||
const { lastFrame, unmount } = await render(
|
||||
const { lastFrame, unmount } = await renderWithProviders(
|
||||
<ApiAuthDialog onSubmit={onSubmit} onCancel={onCancel} />,
|
||||
);
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -81,7 +86,7 @@ describe('ApiAuthDialog', () => {
|
||||
});
|
||||
|
||||
it('renders with a defaultValue', async () => {
|
||||
const { unmount } = await render(
|
||||
const { unmount } = await renderWithProviders(
|
||||
<ApiAuthDialog
|
||||
onSubmit={onSubmit}
|
||||
onCancel={onCancel}
|
||||
@@ -111,7 +116,7 @@ describe('ApiAuthDialog', () => {
|
||||
'calls $expectedCall.name when $keyName is pressed',
|
||||
async ({ keyName, sequence, expectedCall, args }) => {
|
||||
mockBuffer.text = 'submitted-key'; // Set for the onSubmit case
|
||||
const { unmount } = await render(
|
||||
const { unmount } = await renderWithProviders(
|
||||
<ApiAuthDialog onSubmit={onSubmit} onCancel={onCancel} />,
|
||||
);
|
||||
// calls[0] is the ApiAuthDialog's useKeypress (Ctrl+C handler)
|
||||
@@ -133,7 +138,7 @@ describe('ApiAuthDialog', () => {
|
||||
);
|
||||
|
||||
it('displays an error message', async () => {
|
||||
const { lastFrame, unmount } = await render(
|
||||
const { lastFrame, unmount } = await renderWithProviders(
|
||||
<ApiAuthDialog
|
||||
onSubmit={onSubmit}
|
||||
onCancel={onCancel}
|
||||
@@ -146,7 +151,7 @@ describe('ApiAuthDialog', () => {
|
||||
});
|
||||
|
||||
it('calls clearApiKey and clears buffer when Ctrl+C is pressed', async () => {
|
||||
const { unmount } = await render(
|
||||
const { unmount } = await renderWithProviders(
|
||||
<ApiAuthDialog onSubmit={onSubmit} onCancel={onCancel} />,
|
||||
);
|
||||
// Call 0 is ApiAuthDialog (isActive: true)
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('clearCommand', () => {
|
||||
agentContext: {
|
||||
config: {
|
||||
getEnableHooks: vi.fn().mockReturnValue(false),
|
||||
setSessionId: vi.fn(),
|
||||
resetNewSessionState: vi.fn(),
|
||||
getMessageBus: vi.fn().mockReturnValue(undefined),
|
||||
getHookSystem: vi.fn().mockReturnValue({
|
||||
fireSessionEndEvent: vi.fn().mockResolvedValue(undefined),
|
||||
@@ -74,6 +74,9 @@ describe('clearCommand', () => {
|
||||
|
||||
expect(mockResetChat).toHaveBeenCalledTimes(1);
|
||||
expect(mockHintClear).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
mockContext.services.agentContext?.config.resetNewSessionState,
|
||||
).toHaveBeenCalledTimes(1);
|
||||
expect(uiTelemetryService.clear).toHaveBeenCalled();
|
||||
expect(uiTelemetryService.clear).toHaveBeenCalledTimes(1);
|
||||
expect(mockContext.ui.clear).toHaveBeenCalledTimes(1);
|
||||
|
||||
@@ -39,7 +39,7 @@ export const clearCommand: SlashCommand = {
|
||||
let newSessionId: string | undefined;
|
||||
if (config) {
|
||||
newSessionId = randomUUID();
|
||||
config.setSessionId(newSessionId);
|
||||
config.resetNewSessionState(newSessionId);
|
||||
}
|
||||
|
||||
if (geminiClient) {
|
||||
|
||||
@@ -473,7 +473,7 @@ describe('memoryCommand', () => {
|
||||
|
||||
const mockConfig = {
|
||||
reloadSkills: vi.fn(),
|
||||
isMemoryManagerEnabled: vi.fn().mockReturnValue(true),
|
||||
isAutoMemoryEnabled: vi.fn().mockReturnValue(true),
|
||||
};
|
||||
const context = createMockCommandContext({
|
||||
services: {
|
||||
@@ -491,11 +491,11 @@ describe('memoryCommand', () => {
|
||||
expect(result).toHaveProperty('component');
|
||||
});
|
||||
|
||||
it('should return info message when memory manager is disabled', () => {
|
||||
it('should return info message when auto memory is disabled', () => {
|
||||
if (!inboxCommand.action) throw new Error('Command has no action');
|
||||
|
||||
const mockConfig = {
|
||||
isMemoryManagerEnabled: vi.fn().mockReturnValue(false),
|
||||
isAutoMemoryEnabled: vi.fn().mockReturnValue(false),
|
||||
};
|
||||
const context = createMockCommandContext({
|
||||
services: {
|
||||
@@ -509,7 +509,7 @@ describe('memoryCommand', () => {
|
||||
type: 'message',
|
||||
messageType: 'info',
|
||||
content:
|
||||
'The memory inbox requires the experimental memory manager. Enable it with: experimental.memoryManager = true in settings.',
|
||||
'The memory inbox requires Auto Memory. Enable it with: experimental.autoMemory = true in settings.',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -145,12 +145,12 @@ export const memoryCommand: SlashCommand = {
|
||||
};
|
||||
}
|
||||
|
||||
if (!config.isMemoryManagerEnabled()) {
|
||||
if (!config.isAutoMemoryEnabled()) {
|
||||
return {
|
||||
type: 'message',
|
||||
messageType: 'info',
|
||||
content:
|
||||
'The memory inbox requires the experimental memory manager. Enable it with: experimental.memoryManager = true in settings.',
|
||||
'The memory inbox requires Auto Memory. Enable it with: experimental.autoMemory = true in settings.',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@ import {
|
||||
useReducer,
|
||||
useContext,
|
||||
} from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { Box, Text, type DOMElement } from 'ink';
|
||||
import { useMouseClick } from '../hooks/useMouseClick.js';
|
||||
import { theme } from '../semantic-colors.js';
|
||||
import { checkExhaustive, type Question } from '@google/gemini-cli-core';
|
||||
import { BaseSelectionList } from './shared/BaseSelectionList.js';
|
||||
@@ -85,6 +86,24 @@ function autoBoldIfPlain(text: string): string {
|
||||
return text;
|
||||
}
|
||||
|
||||
const ClickableCheckbox: React.FC<{
|
||||
isChecked: boolean;
|
||||
onClick: () => void;
|
||||
}> = ({ isChecked, onClick }) => {
|
||||
const ref = useRef<DOMElement>(null);
|
||||
useMouseClick(ref, () => {
|
||||
onClick();
|
||||
});
|
||||
|
||||
return (
|
||||
<Box ref={ref}>
|
||||
<Text color={isChecked ? theme.status.success : theme.text.secondary}>
|
||||
[{isChecked ? 'x' : ' '}]
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
interface AskUserDialogState {
|
||||
answers: { [key: string]: string };
|
||||
isEditingCustomOption: boolean;
|
||||
@@ -919,13 +938,14 @@ const ChoiceQuestionView: React.FC<ChoiceQuestionViewProps> = ({
|
||||
return (
|
||||
<Box flexDirection="row">
|
||||
{showCheck && (
|
||||
<Text
|
||||
color={
|
||||
isChecked ? theme.status.success : theme.text.secondary
|
||||
}
|
||||
>
|
||||
[{isChecked ? 'x' : ' '}]
|
||||
</Text>
|
||||
<ClickableCheckbox
|
||||
isChecked={isChecked}
|
||||
onClick={() => {
|
||||
if (!context.isSelected) {
|
||||
handleSelect(optionItem);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Text color={theme.text.primary}> </Text>
|
||||
<TextInput
|
||||
@@ -966,13 +986,14 @@ const ChoiceQuestionView: React.FC<ChoiceQuestionViewProps> = ({
|
||||
<Box flexDirection="column">
|
||||
<Box flexDirection="row">
|
||||
{showCheck && (
|
||||
<Text
|
||||
color={
|
||||
isChecked ? theme.status.success : theme.text.secondary
|
||||
}
|
||||
>
|
||||
[{isChecked ? 'x' : ' '}]
|
||||
</Text>
|
||||
<ClickableCheckbox
|
||||
isChecked={isChecked}
|
||||
onClick={() => {
|
||||
if (!context.isSelected) {
|
||||
handleSelect(optionItem);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Text color={labelColor} bold={optionItem.type === 'done'}>
|
||||
{' '}
|
||||
|
||||
@@ -67,47 +67,47 @@
|
||||
<text x="0" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">Enable Notifications</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs">Enable Terminal Notifications</text>
|
||||
<text x="828" y="308" fill="#afafaf" textLength="45" lengthAdjust="spacingAndGlyphs">false</text>
|
||||
<text x="891" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="738" lengthAdjust="spacingAndGlyphs">Enable run-event notifications for action-required prompts and session completion.</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="756" lengthAdjust="spacingAndGlyphs">Enable terminal run-event notifications for action-required prompts and session com…</text>
|
||||
<text x="891" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="252" lengthAdjust="spacingAndGlyphs">Terminal Notification Method</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">Auto</text>
|
||||
<text x="891" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="315" lengthAdjust="spacingAndGlyphs">How to send terminal notifications.</text>
|
||||
<text x="891" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="410" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="410" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="891" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="461" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="461" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="891" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="891" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Retry Fetch Errors</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="512" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="612" lengthAdjust="spacingAndGlyphs">Retry on "exception TypeError: fetch failed sending request" errors.</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="891" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -67,47 +67,47 @@
|
||||
<text x="0" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">Enable Notifications</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs">Enable Terminal Notifications</text>
|
||||
<text x="828" y="308" fill="#afafaf" textLength="45" lengthAdjust="spacingAndGlyphs">false</text>
|
||||
<text x="891" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="738" lengthAdjust="spacingAndGlyphs">Enable run-event notifications for action-required prompts and session completion.</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="756" lengthAdjust="spacingAndGlyphs">Enable terminal run-event notifications for action-required prompts and session com…</text>
|
||||
<text x="891" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="252" lengthAdjust="spacingAndGlyphs">Terminal Notification Method</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">Auto</text>
|
||||
<text x="891" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="315" lengthAdjust="spacingAndGlyphs">How to send terminal notifications.</text>
|
||||
<text x="891" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="410" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="410" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="891" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="461" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="461" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="891" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="891" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Retry Fetch Errors</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="512" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="612" lengthAdjust="spacingAndGlyphs">Retry on "exception TypeError: fetch failed sending request" errors.</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="891" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -67,47 +67,47 @@
|
||||
<text x="0" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">Enable Notifications</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs">Enable Terminal Notifications</text>
|
||||
<text x="828" y="308" fill="#afafaf" textLength="45" lengthAdjust="spacingAndGlyphs">false</text>
|
||||
<text x="891" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="738" lengthAdjust="spacingAndGlyphs">Enable run-event notifications for action-required prompts and session completion.</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="756" lengthAdjust="spacingAndGlyphs">Enable terminal run-event notifications for action-required prompts and session com…</text>
|
||||
<text x="891" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="252" lengthAdjust="spacingAndGlyphs">Terminal Notification Method</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">Auto</text>
|
||||
<text x="891" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="315" lengthAdjust="spacingAndGlyphs">How to send terminal notifications.</text>
|
||||
<text x="891" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="410" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="410" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="891" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="461" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="461" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="891" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="891" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Retry Fetch Errors</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="512" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="612" lengthAdjust="spacingAndGlyphs">Retry on "exception TypeError: fetch failed sending request" errors.</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="891" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -67,47 +67,47 @@
|
||||
<text x="0" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">Enable Notifications</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs">Enable Terminal Notifications</text>
|
||||
<text x="828" y="308" fill="#afafaf" textLength="45" lengthAdjust="spacingAndGlyphs">false</text>
|
||||
<text x="891" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="738" lengthAdjust="spacingAndGlyphs">Enable run-event notifications for action-required prompts and session completion.</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="756" lengthAdjust="spacingAndGlyphs">Enable terminal run-event notifications for action-required prompts and session com…</text>
|
||||
<text x="891" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="252" lengthAdjust="spacingAndGlyphs">Terminal Notification Method</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">Auto</text>
|
||||
<text x="891" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="315" lengthAdjust="spacingAndGlyphs">How to send terminal notifications.</text>
|
||||
<text x="891" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="410" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="410" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="891" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="461" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="461" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="891" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="891" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Retry Fetch Errors</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="512" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="612" lengthAdjust="spacingAndGlyphs">Retry on "exception TypeError: fetch failed sending request" errors.</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="891" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -67,47 +67,47 @@
|
||||
<text x="0" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">Enable Notifications</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs">Enable Terminal Notifications</text>
|
||||
<text x="828" y="308" fill="#afafaf" textLength="45" lengthAdjust="spacingAndGlyphs">false</text>
|
||||
<text x="891" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="738" lengthAdjust="spacingAndGlyphs">Enable run-event notifications for action-required prompts and session completion.</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="756" lengthAdjust="spacingAndGlyphs">Enable terminal run-event notifications for action-required prompts and session com…</text>
|
||||
<text x="891" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="252" lengthAdjust="spacingAndGlyphs">Terminal Notification Method</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">Auto</text>
|
||||
<text x="891" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="315" lengthAdjust="spacingAndGlyphs">How to send terminal notifications.</text>
|
||||
<text x="891" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="410" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="410" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="891" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="461" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="461" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="891" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="891" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Retry Fetch Errors</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="512" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="612" lengthAdjust="spacingAndGlyphs">Retry on "exception TypeError: fetch failed sending request" errors.</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="891" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -56,47 +56,47 @@
|
||||
<text x="0" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">Enable Notifications</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs">Enable Terminal Notifications</text>
|
||||
<text x="828" y="308" fill="#afafaf" textLength="45" lengthAdjust="spacingAndGlyphs">false</text>
|
||||
<text x="891" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="738" lengthAdjust="spacingAndGlyphs">Enable run-event notifications for action-required prompts and session completion.</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="756" lengthAdjust="spacingAndGlyphs">Enable terminal run-event notifications for action-required prompts and session com…</text>
|
||||
<text x="891" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="252" lengthAdjust="spacingAndGlyphs">Terminal Notification Method</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">Auto</text>
|
||||
<text x="891" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="315" lengthAdjust="spacingAndGlyphs">How to send terminal notifications.</text>
|
||||
<text x="891" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="410" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="410" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="891" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="461" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="461" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="891" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="891" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Retry Fetch Errors</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="512" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="612" lengthAdjust="spacingAndGlyphs">Retry on "exception TypeError: fetch failed sending request" errors.</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="891" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -67,47 +67,47 @@
|
||||
<text x="0" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">Enable Notifications</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs">Enable Terminal Notifications</text>
|
||||
<text x="828" y="308" fill="#afafaf" textLength="45" lengthAdjust="spacingAndGlyphs">false</text>
|
||||
<text x="891" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="738" lengthAdjust="spacingAndGlyphs">Enable run-event notifications for action-required prompts and session completion.</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="756" lengthAdjust="spacingAndGlyphs">Enable terminal run-event notifications for action-required prompts and session com…</text>
|
||||
<text x="891" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="252" lengthAdjust="spacingAndGlyphs">Terminal Notification Method</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">Auto</text>
|
||||
<text x="891" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="315" lengthAdjust="spacingAndGlyphs">How to send terminal notifications.</text>
|
||||
<text x="891" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="410" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="410" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="891" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="461" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="461" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="891" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="891" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Retry Fetch Errors</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="512" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="612" lengthAdjust="spacingAndGlyphs">Retry on "exception TypeError: fetch failed sending request" errors.</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="891" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -67,47 +67,47 @@
|
||||
<text x="0" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">Enable Notifications</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs">Enable Terminal Notifications</text>
|
||||
<text x="828" y="308" fill="#afafaf" textLength="45" lengthAdjust="spacingAndGlyphs">false</text>
|
||||
<text x="891" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="738" lengthAdjust="spacingAndGlyphs">Enable run-event notifications for action-required prompts and session completion.</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="756" lengthAdjust="spacingAndGlyphs">Enable terminal run-event notifications for action-required prompts and session com…</text>
|
||||
<text x="891" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="252" lengthAdjust="spacingAndGlyphs">Terminal Notification Method</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">Auto</text>
|
||||
<text x="891" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="315" lengthAdjust="spacingAndGlyphs">How to send terminal notifications.</text>
|
||||
<text x="891" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="410" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="410" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="891" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="461" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="461" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="891" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="891" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Retry Fetch Errors</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="512" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="612" lengthAdjust="spacingAndGlyphs">Retry on "exception TypeError: fetch failed sending request" errors.</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="891" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -67,47 +67,47 @@
|
||||
<text x="0" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="291" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="180" lengthAdjust="spacingAndGlyphs">Enable Notifications</text>
|
||||
<text x="45" y="308" fill="#ffffff" textLength="261" lengthAdjust="spacingAndGlyphs">Enable Terminal Notifications</text>
|
||||
<text x="828" y="308" fill="#afafaf" textLength="45" lengthAdjust="spacingAndGlyphs">false</text>
|
||||
<text x="891" y="308" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="738" lengthAdjust="spacingAndGlyphs">Enable run-event notifications for action-required prompts and session completion.</text>
|
||||
<text x="45" y="325" fill="#afafaf" textLength="756" lengthAdjust="spacingAndGlyphs">Enable terminal run-event notifications for action-required prompts and session com…</text>
|
||||
<text x="891" y="325" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="342" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="359" fill="#ffffff" textLength="252" lengthAdjust="spacingAndGlyphs">Terminal Notification Method</text>
|
||||
<text x="837" y="359" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">Auto</text>
|
||||
<text x="891" y="359" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="45" y="376" fill="#afafaf" textLength="315" lengthAdjust="spacingAndGlyphs">How to send terminal notifications.</text>
|
||||
<text x="891" y="376" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="393" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="410" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="45" y="410" fill="#ffffff" textLength="144" lengthAdjust="spacingAndGlyphs">Enable Plan Mode</text>
|
||||
<text x="837" y="410" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="410" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="45" y="427" fill="#afafaf" textLength="486" lengthAdjust="spacingAndGlyphs">Enable Plan Mode for read-only safety during planning.</text>
|
||||
<text x="891" y="427" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="444" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="461" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="45" y="461" fill="#ffffff" textLength="126" lengthAdjust="spacingAndGlyphs">Plan Directory</text>
|
||||
<text x="792" y="461" fill="#afafaf" textLength="81" lengthAdjust="spacingAndGlyphs">undefined</text>
|
||||
<text x="891" y="461" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="45" y="478" fill="#afafaf" textLength="720" lengthAdjust="spacingAndGlyphs">The directory where planning artifacts are stored. If not specified, defaults t…</text>
|
||||
<text x="891" y="478" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="495" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Retry Fetch Errors</text>
|
||||
<text x="45" y="512" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Plan Model Routing</text>
|
||||
<text x="837" y="512" fill="#afafaf" textLength="36" lengthAdjust="spacingAndGlyphs">true</text>
|
||||
<text x="891" y="512" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="612" lengthAdjust="spacingAndGlyphs">Retry on "exception TypeError: fetch failed sending request" errors.</text>
|
||||
<text x="45" y="529" fill="#afafaf" textLength="765" lengthAdjust="spacingAndGlyphs">Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr…</text>
|
||||
<text x="891" y="529" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="891" y="546" fill="#878787" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -19,8 +19,11 @@ exports[`SettingsDialog > Initial Rendering > should render settings list with v
|
||||
│ Enable Auto Update true │
|
||||
│ Enable automatic updates. │
|
||||
│ │
|
||||
│ Enable Notifications false │
|
||||
│ Enable run-event notifications for action-required prompts and session completion. │
|
||||
│ Enable Terminal Notifications false │
|
||||
│ Enable terminal run-event notifications for action-required prompts and session com… │
|
||||
│ │
|
||||
│ Terminal Notification Method Auto │
|
||||
│ How to send terminal notifications. │
|
||||
│ │
|
||||
│ Enable Plan Mode true │
|
||||
│ Enable Plan Mode for read-only safety during planning. │
|
||||
@@ -31,9 +34,6 @@ exports[`SettingsDialog > Initial Rendering > should render settings list with v
|
||||
│ Plan Model Routing true │
|
||||
│ Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr… │
|
||||
│ │
|
||||
│ Retry Fetch Errors true │
|
||||
│ Retry on "exception TypeError: fetch failed sending request" errors. │
|
||||
│ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ Apply To │
|
||||
@@ -65,8 +65,11 @@ exports[`SettingsDialog > Snapshot Tests > should render 'accessibility settings
|
||||
│ Enable Auto Update true │
|
||||
│ Enable automatic updates. │
|
||||
│ │
|
||||
│ Enable Notifications false │
|
||||
│ Enable run-event notifications for action-required prompts and session completion. │
|
||||
│ Enable Terminal Notifications false │
|
||||
│ Enable terminal run-event notifications for action-required prompts and session com… │
|
||||
│ │
|
||||
│ Terminal Notification Method Auto │
|
||||
│ How to send terminal notifications. │
|
||||
│ │
|
||||
│ Enable Plan Mode true │
|
||||
│ Enable Plan Mode for read-only safety during planning. │
|
||||
@@ -77,9 +80,6 @@ exports[`SettingsDialog > Snapshot Tests > should render 'accessibility settings
|
||||
│ Plan Model Routing true │
|
||||
│ Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr… │
|
||||
│ │
|
||||
│ Retry Fetch Errors true │
|
||||
│ Retry on "exception TypeError: fetch failed sending request" errors. │
|
||||
│ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ Apply To │
|
||||
@@ -111,8 +111,11 @@ exports[`SettingsDialog > Snapshot Tests > should render 'all boolean settings d
|
||||
│ Enable Auto Update true* │
|
||||
│ Enable automatic updates. │
|
||||
│ │
|
||||
│ Enable Notifications false │
|
||||
│ Enable run-event notifications for action-required prompts and session completion. │
|
||||
│ Enable Terminal Notifications false │
|
||||
│ Enable terminal run-event notifications for action-required prompts and session com… │
|
||||
│ │
|
||||
│ Terminal Notification Method Auto │
|
||||
│ How to send terminal notifications. │
|
||||
│ │
|
||||
│ Enable Plan Mode true │
|
||||
│ Enable Plan Mode for read-only safety during planning. │
|
||||
@@ -123,9 +126,6 @@ exports[`SettingsDialog > Snapshot Tests > should render 'all boolean settings d
|
||||
│ Plan Model Routing true │
|
||||
│ Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr… │
|
||||
│ │
|
||||
│ Retry Fetch Errors true │
|
||||
│ Retry on "exception TypeError: fetch failed sending request" errors. │
|
||||
│ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ Apply To │
|
||||
@@ -157,8 +157,11 @@ exports[`SettingsDialog > Snapshot Tests > should render 'default state' correct
|
||||
│ Enable Auto Update true │
|
||||
│ Enable automatic updates. │
|
||||
│ │
|
||||
│ Enable Notifications false │
|
||||
│ Enable run-event notifications for action-required prompts and session completion. │
|
||||
│ Enable Terminal Notifications false │
|
||||
│ Enable terminal run-event notifications for action-required prompts and session com… │
|
||||
│ │
|
||||
│ Terminal Notification Method Auto │
|
||||
│ How to send terminal notifications. │
|
||||
│ │
|
||||
│ Enable Plan Mode true │
|
||||
│ Enable Plan Mode for read-only safety during planning. │
|
||||
@@ -169,9 +172,6 @@ exports[`SettingsDialog > Snapshot Tests > should render 'default state' correct
|
||||
│ Plan Model Routing true │
|
||||
│ Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr… │
|
||||
│ │
|
||||
│ Retry Fetch Errors true │
|
||||
│ Retry on "exception TypeError: fetch failed sending request" errors. │
|
||||
│ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ Apply To │
|
||||
@@ -203,8 +203,11 @@ exports[`SettingsDialog > Snapshot Tests > should render 'file filtering setting
|
||||
│ Enable Auto Update true │
|
||||
│ Enable automatic updates. │
|
||||
│ │
|
||||
│ Enable Notifications false │
|
||||
│ Enable run-event notifications for action-required prompts and session completion. │
|
||||
│ Enable Terminal Notifications false │
|
||||
│ Enable terminal run-event notifications for action-required prompts and session com… │
|
||||
│ │
|
||||
│ Terminal Notification Method Auto │
|
||||
│ How to send terminal notifications. │
|
||||
│ │
|
||||
│ Enable Plan Mode true │
|
||||
│ Enable Plan Mode for read-only safety during planning. │
|
||||
@@ -215,9 +218,6 @@ exports[`SettingsDialog > Snapshot Tests > should render 'file filtering setting
|
||||
│ Plan Model Routing true │
|
||||
│ Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr… │
|
||||
│ │
|
||||
│ Retry Fetch Errors true │
|
||||
│ Retry on "exception TypeError: fetch failed sending request" errors. │
|
||||
│ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ Apply To │
|
||||
@@ -249,8 +249,11 @@ exports[`SettingsDialog > Snapshot Tests > should render 'focused on scope selec
|
||||
│ Enable Auto Update true │
|
||||
│ Enable automatic updates. │
|
||||
│ │
|
||||
│ Enable Notifications false │
|
||||
│ Enable run-event notifications for action-required prompts and session completion. │
|
||||
│ Enable Terminal Notifications false │
|
||||
│ Enable terminal run-event notifications for action-required prompts and session com… │
|
||||
│ │
|
||||
│ Terminal Notification Method Auto │
|
||||
│ How to send terminal notifications. │
|
||||
│ │
|
||||
│ Enable Plan Mode true │
|
||||
│ Enable Plan Mode for read-only safety during planning. │
|
||||
@@ -261,9 +264,6 @@ exports[`SettingsDialog > Snapshot Tests > should render 'focused on scope selec
|
||||
│ Plan Model Routing true │
|
||||
│ Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr… │
|
||||
│ │
|
||||
│ Retry Fetch Errors true │
|
||||
│ Retry on "exception TypeError: fetch failed sending request" errors. │
|
||||
│ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ > Apply To │
|
||||
@@ -295,8 +295,11 @@ exports[`SettingsDialog > Snapshot Tests > should render 'mixed boolean and numb
|
||||
│ Enable Auto Update false* │
|
||||
│ Enable automatic updates. │
|
||||
│ │
|
||||
│ Enable Notifications false │
|
||||
│ Enable run-event notifications for action-required prompts and session completion. │
|
||||
│ Enable Terminal Notifications false │
|
||||
│ Enable terminal run-event notifications for action-required prompts and session com… │
|
||||
│ │
|
||||
│ Terminal Notification Method Auto │
|
||||
│ How to send terminal notifications. │
|
||||
│ │
|
||||
│ Enable Plan Mode true │
|
||||
│ Enable Plan Mode for read-only safety during planning. │
|
||||
@@ -307,9 +310,6 @@ exports[`SettingsDialog > Snapshot Tests > should render 'mixed boolean and numb
|
||||
│ Plan Model Routing true │
|
||||
│ Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr… │
|
||||
│ │
|
||||
│ Retry Fetch Errors true │
|
||||
│ Retry on "exception TypeError: fetch failed sending request" errors. │
|
||||
│ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ Apply To │
|
||||
@@ -341,8 +341,11 @@ exports[`SettingsDialog > Snapshot Tests > should render 'tools and security set
|
||||
│ Enable Auto Update true │
|
||||
│ Enable automatic updates. │
|
||||
│ │
|
||||
│ Enable Notifications false │
|
||||
│ Enable run-event notifications for action-required prompts and session completion. │
|
||||
│ Enable Terminal Notifications false │
|
||||
│ Enable terminal run-event notifications for action-required prompts and session com… │
|
||||
│ │
|
||||
│ Terminal Notification Method Auto │
|
||||
│ How to send terminal notifications. │
|
||||
│ │
|
||||
│ Enable Plan Mode true │
|
||||
│ Enable Plan Mode for read-only safety during planning. │
|
||||
@@ -353,9 +356,6 @@ exports[`SettingsDialog > Snapshot Tests > should render 'tools and security set
|
||||
│ Plan Model Routing true │
|
||||
│ Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr… │
|
||||
│ │
|
||||
│ Retry Fetch Errors true │
|
||||
│ Retry on "exception TypeError: fetch failed sending request" errors. │
|
||||
│ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ Apply To │
|
||||
@@ -387,8 +387,11 @@ exports[`SettingsDialog > Snapshot Tests > should render 'various boolean settin
|
||||
│ Enable Auto Update false* │
|
||||
│ Enable automatic updates. │
|
||||
│ │
|
||||
│ Enable Notifications false │
|
||||
│ Enable run-event notifications for action-required prompts and session completion. │
|
||||
│ Enable Terminal Notifications false │
|
||||
│ Enable terminal run-event notifications for action-required prompts and session com… │
|
||||
│ │
|
||||
│ Terminal Notification Method Auto │
|
||||
│ How to send terminal notifications. │
|
||||
│ │
|
||||
│ Enable Plan Mode true │
|
||||
│ Enable Plan Mode for read-only safety during planning. │
|
||||
@@ -399,9 +402,6 @@ exports[`SettingsDialog > Snapshot Tests > should render 'various boolean settin
|
||||
│ Plan Model Routing true │
|
||||
│ Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pr… │
|
||||
│ │
|
||||
│ Retry Fetch Errors true │
|
||||
│ Retry on "exception TypeError: fetch failed sending request" errors. │
|
||||
│ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ Apply To │
|
||||
|
||||
@@ -11,12 +11,12 @@ exports[`Initial Theme Selection > should default to a dark theme when terminal
|
||||
│ ● 4. Default Dark (Matches terminal) │ 3 a, b = 0, 1 │ │
|
||||
│ 5. Dracula Dark │ 4 for _ in range(n): │ │
|
||||
│ 6. GitHub Dark │ 5 a, b = b, a + b │ │
|
||||
│ 7. Holiday Dark │ 6 return a │ │
|
||||
│ 8. Shades Of Purple Dark │ │ │
|
||||
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Tokyo Night Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. ANSI Light │ │ │
|
||||
│ 12. Ayu Light └─────────────────────────────────────────────────┘ │
|
||||
│ 7. GitHub Dark Colorblind Dark │ 6 return a │ │
|
||||
│ 8. Holiday Dark │ │ │
|
||||
│ 9. Shades Of Purple Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Solarized Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Tokyo Night Dark │ │ │
|
||||
│ 12. ANSI Light └─────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||
@@ -34,14 +34,14 @@ exports[`Initial Theme Selection > should default to a light theme when terminal
|
||||
│ 2. Ayu Light │ 1 # function │ │
|
||||
│ ● 3. Default Light │ 2 def fibonacci(n): │ │
|
||||
│ 4. GitHub Light │ 3 a, b = 0, 1 │ │
|
||||
│ 5. Google Code Light │ 4 for _ in range(n): │ │
|
||||
│ 6. Solarized Light │ 5 a, b = b, a + b │ │
|
||||
│ 7. Xcode Light │ 6 return a │ │
|
||||
│ 8. ANSI Dark (Incompatible) │ │ │
|
||||
│ 9. Atom One Dark (Incompatible) │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Ayu Dark (Incompatible) │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Default Dark (Incompatible) │ │ │
|
||||
│ 12. Dracula Dark (Incompatible) └─────────────────────────────────────────────────┘ │
|
||||
│ 5. GitHub Light Colorblind Light (Mat… │ 4 for _ in range(n): │ │
|
||||
│ 6. Google Code Light │ 5 a, b = b, a + b │ │
|
||||
│ 7. Solarized Light │ 6 return a │ │
|
||||
│ 8. Xcode Light │ │ │
|
||||
│ 9. ANSI Dark (Incompatible) │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Atom One Dark (Incompatible) │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Ayu Dark (Incompatible) │ │ │
|
||||
│ 12. Default Dark (Incompatible) └─────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||
@@ -61,12 +61,12 @@ exports[`Initial Theme Selection > should use the theme from settings even if te
|
||||
│ 4. Default Dark (Matches terminal) │ 3 a, b = 0, 1 │ │
|
||||
│ 5. Dracula Dark │ 4 for _ in range(n): │ │
|
||||
│ 6. GitHub Dark │ 5 a, b = b, a + b │ │
|
||||
│ 7. Holiday Dark │ 6 return a │ │
|
||||
│ 8. Shades Of Purple Dark │ │ │
|
||||
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Tokyo Night Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. ANSI Light │ │ │
|
||||
│ 12. Ayu Light └─────────────────────────────────────────────────┘ │
|
||||
│ 7. GitHub Dark Colorblind Dark │ 6 return a │ │
|
||||
│ 8. Holiday Dark │ │ │
|
||||
│ 9. Shades Of Purple Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Solarized Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Tokyo Night Dark │ │ │
|
||||
│ 12. ANSI Light └─────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||
@@ -100,12 +100,12 @@ exports[`ThemeDialog Snapshots > should render correctly in theme selection mode
|
||||
│ 4. Default Dark │ 3 a, b = 0, 1 │ │
|
||||
│ 5. Dracula Dark │ 4 for _ in range(n): │ │
|
||||
│ 6. GitHub Dark │ 5 a, b = b, a + b │ │
|
||||
│ 7. Holiday Dark │ 6 return a │ │
|
||||
│ 8. Shades Of Purple Dark │ │ │
|
||||
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Tokyo Night Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. ANSI Light │ │ │
|
||||
│ 12. Ayu Light └─────────────────────────────────────────────────┘ │
|
||||
│ 7. GitHub Dark Colorblind Dark │ 6 return a │ │
|
||||
│ 8. Holiday Dark │ │ │
|
||||
│ 9. Shades Of Purple Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Solarized Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Tokyo Night Dark │ │ │
|
||||
│ 12. ANSI Light └─────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||
@@ -125,12 +125,12 @@ exports[`ThemeDialog Snapshots > should render correctly in theme selection mode
|
||||
│ 4. Default Dark │ 3 a, b = 0, 1 │ │
|
||||
│ 5. Dracula Dark │ 4 for _ in range(n): │ │
|
||||
│ 6. GitHub Dark │ 5 a, b = b, a + b │ │
|
||||
│ 7. Holiday Dark │ 6 return a │ │
|
||||
│ 8. Shades Of Purple Dark │ │ │
|
||||
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Tokyo Night Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. ANSI Light │ │ │
|
||||
│ 12. Ayu Light └─────────────────────────────────────────────────┘ │
|
||||
│ 7. GitHub Dark Colorblind Dark │ 6 return a │ │
|
||||
│ 8. Holiday Dark │ │ │
|
||||
│ 9. Shades Of Purple Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Solarized Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Tokyo Night Dark │ │ │
|
||||
│ 12. ANSI Light └─────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ╭─────────────────────────────────────────────────╮ │
|
||||
│ │ DEVELOPER TOOLS (Not visible to users) │ │
|
||||
|
||||
@@ -246,11 +246,10 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
(showClosingBorder ? 1 : 0);
|
||||
} else if (isTopicToolCall) {
|
||||
// Topic Message Spacing Breakdown:
|
||||
// 1. Top Margin (1): Always present for spacing.
|
||||
// 2. Topic Content (1).
|
||||
// 3. Bottom Margin (1): Always present around TopicMessage for breathing room.
|
||||
// 4. Closing Border (1): Added if transition logic (showClosingBorder) requires it.
|
||||
height += 1 + 1 + 1 + (showClosingBorder ? 1 : 0);
|
||||
// 1. Topic Content (1).
|
||||
// 2. Bottom Margin (1): Always present around TopicMessage for breathing room.
|
||||
// 3. Closing Border (1): Added if transition logic (showClosingBorder) requires it.
|
||||
height += 1 + 1 + (showClosingBorder ? 1 : 0);
|
||||
} else if (isCompact) {
|
||||
// Compact Tool: Always renders as a single dense line.
|
||||
height += 1;
|
||||
@@ -439,7 +438,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
{isCompact ? (
|
||||
<DenseToolMessage {...commonProps} />
|
||||
) : isTopicToolCall ? (
|
||||
<Box marginTop={1} marginBottom={1}>
|
||||
<Box marginBottom={1}>
|
||||
<TopicMessage {...commonProps} />
|
||||
</Box>
|
||||
) : isShellToolCall ? (
|
||||
|
||||
@@ -77,8 +77,7 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders header when scrolled
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders mixed tool calls including update_topic 1`] = `
|
||||
"
|
||||
Testing Topic: This is the description
|
||||
" Testing Topic: This is the description
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ read_file Read a file │
|
||||
@@ -143,8 +142,7 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders two tool groups where
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders update_topic tool call using TopicMessage > update_topic_tool 1`] = `
|
||||
"
|
||||
Testing Topic: This is the description
|
||||
" Testing Topic: This is the description
|
||||
"
|
||||
`;
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
||||
import { act } from 'react';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import {
|
||||
BaseSelectionList,
|
||||
@@ -14,8 +15,10 @@ import {
|
||||
import { useSelectionList } from '../../hooks/useSelectionList.js';
|
||||
import { Text } from 'ink';
|
||||
import type { theme } from '../../semantic-colors.js';
|
||||
import { useMouseClick } from '../../hooks/useMouseClick.js';
|
||||
|
||||
vi.mock('../../hooks/useSelectionList.js');
|
||||
vi.mock('../../hooks/useMouseClick.js');
|
||||
|
||||
const mockTheme = {
|
||||
text: { primary: 'COLOR_PRIMARY', secondary: 'COLOR_SECONDARY' },
|
||||
@@ -35,6 +38,7 @@ describe('BaseSelectionList', () => {
|
||||
const mockOnSelect = vi.fn();
|
||||
const mockOnHighlight = vi.fn();
|
||||
const mockRenderItem = vi.fn();
|
||||
const mockSetActiveIndex = vi.fn();
|
||||
|
||||
const items = [
|
||||
{ value: 'A', label: 'Item A', key: 'A' },
|
||||
@@ -54,7 +58,7 @@ describe('BaseSelectionList', () => {
|
||||
) => {
|
||||
vi.mocked(useSelectionList).mockReturnValue({
|
||||
activeIndex,
|
||||
setActiveIndex: vi.fn(),
|
||||
setActiveIndex: mockSetActiveIndex,
|
||||
});
|
||||
|
||||
mockRenderItem.mockImplementation(
|
||||
@@ -484,6 +488,79 @@ describe('BaseSelectionList', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mouse Interaction', () => {
|
||||
it('should register mouse click handler for each item', async () => {
|
||||
const { unmount } = await renderComponent();
|
||||
|
||||
// items are A, B (disabled), C
|
||||
expect(useMouseClick).toHaveBeenCalledTimes(3);
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('should update activeIndex on first click and call onSelect on second click', async () => {
|
||||
const { unmount, waitUntilReady } = await renderComponent();
|
||||
await waitUntilReady();
|
||||
|
||||
// items[0] is 'A' (enabled)
|
||||
// items[1] is 'B' (disabled)
|
||||
// items[2] is 'C' (enabled)
|
||||
|
||||
// Get the mouse click handler for the third item (index 2)
|
||||
const mouseClickHandler = (useMouseClick as Mock).mock.calls[2][1];
|
||||
|
||||
// First click on item C
|
||||
act(() => {
|
||||
mouseClickHandler();
|
||||
});
|
||||
|
||||
expect(mockSetActiveIndex).toHaveBeenCalledWith(2);
|
||||
expect(mockOnSelect).not.toHaveBeenCalled();
|
||||
|
||||
// Now simulate being on item C (isSelected = true)
|
||||
// Rerender or update mocks for the next check
|
||||
await renderComponent({}, 2);
|
||||
|
||||
// Get the updated mouse click handler for item C
|
||||
// useMouseClick is called 3 more times on rerender
|
||||
const updatedMouseClickHandler = (useMouseClick as Mock).mock.calls[5][1];
|
||||
|
||||
// Second click on item C
|
||||
act(() => {
|
||||
updatedMouseClickHandler();
|
||||
});
|
||||
|
||||
expect(mockOnSelect).toHaveBeenCalledWith('C');
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('should not call onSelect when a disabled item is clicked', async () => {
|
||||
const { unmount, waitUntilReady } = await renderComponent();
|
||||
await waitUntilReady();
|
||||
|
||||
// items[1] is 'B' (disabled)
|
||||
const mouseClickHandler = (useMouseClick as Mock).mock.calls[1][1];
|
||||
|
||||
act(() => {
|
||||
mouseClickHandler();
|
||||
});
|
||||
|
||||
expect(mockSetActiveIndex).not.toHaveBeenCalled();
|
||||
expect(mockOnSelect).not.toHaveBeenCalled();
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('should pass isActive: isFocused to useMouseClick', async () => {
|
||||
const { unmount } = await renderComponent({ isFocused: false });
|
||||
|
||||
expect(useMouseClick).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
expect.any(Function),
|
||||
{ isActive: false },
|
||||
);
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Scroll Arrows (showScrollArrows)', () => {
|
||||
const longList = Array.from({ length: 10 }, (_, i) => ({
|
||||
value: `Item ${i + 1}`,
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
*/
|
||||
|
||||
import type React from 'react';
|
||||
import { useState } from 'react';
|
||||
import { Text, Box } from 'ink';
|
||||
import { useState, useRef } from 'react';
|
||||
import { Text, Box, type DOMElement } from 'ink';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import {
|
||||
useSelectionList,
|
||||
type SelectionListItem,
|
||||
} from '../../hooks/useSelectionList.js';
|
||||
import { useMouseClick } from '../../hooks/useMouseClick.js';
|
||||
|
||||
export interface RenderItemContext {
|
||||
isSelected: boolean;
|
||||
@@ -38,6 +39,119 @@ export interface BaseSelectionListProps<
|
||||
renderItem: (item: TItem, context: RenderItemContext) => React.ReactNode;
|
||||
}
|
||||
|
||||
interface SelectionListItemRowProps<
|
||||
T,
|
||||
TItem extends SelectionListItem<T> = SelectionListItem<T>,
|
||||
> {
|
||||
item: TItem;
|
||||
itemIndex: number;
|
||||
isSelected: boolean;
|
||||
isFocused: boolean;
|
||||
showNumbers: boolean;
|
||||
selectedIndicator: string;
|
||||
numberColumnWidth: number;
|
||||
onSelect: (value: T) => void;
|
||||
setActiveIndex: (index: number) => void;
|
||||
renderItem: (item: TItem, context: RenderItemContext) => React.ReactNode;
|
||||
}
|
||||
|
||||
function SelectionListItemRow<
|
||||
T,
|
||||
TItem extends SelectionListItem<T> = SelectionListItem<T>,
|
||||
>({
|
||||
item,
|
||||
itemIndex,
|
||||
isSelected,
|
||||
isFocused,
|
||||
showNumbers,
|
||||
selectedIndicator,
|
||||
numberColumnWidth,
|
||||
onSelect,
|
||||
setActiveIndex,
|
||||
renderItem,
|
||||
}: SelectionListItemRowProps<T, TItem>) {
|
||||
const containerRef = useRef<DOMElement>(null);
|
||||
|
||||
useMouseClick(
|
||||
containerRef,
|
||||
() => {
|
||||
if (!item.disabled) {
|
||||
if (isSelected) {
|
||||
// Second click on the same item triggers submission
|
||||
onSelect(item.value);
|
||||
} else {
|
||||
// First click highlights the item
|
||||
setActiveIndex(itemIndex);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ isActive: isFocused },
|
||||
);
|
||||
|
||||
let titleColor = theme.text.primary;
|
||||
let numberColor = theme.text.primary;
|
||||
|
||||
if (isSelected) {
|
||||
titleColor = theme.ui.focus;
|
||||
numberColor = theme.ui.focus;
|
||||
} else if (item.disabled) {
|
||||
titleColor = theme.text.secondary;
|
||||
numberColor = theme.text.secondary;
|
||||
}
|
||||
|
||||
if (!isFocused && !item.disabled) {
|
||||
numberColor = theme.text.secondary;
|
||||
}
|
||||
|
||||
if (!showNumbers) {
|
||||
numberColor = theme.text.secondary;
|
||||
}
|
||||
|
||||
const itemNumberText = `${String(itemIndex + 1).padStart(
|
||||
numberColumnWidth,
|
||||
)}.`;
|
||||
|
||||
return (
|
||||
<Box
|
||||
ref={containerRef}
|
||||
key={item.key}
|
||||
alignItems="flex-start"
|
||||
backgroundColor={isSelected ? theme.background.focus : undefined}
|
||||
>
|
||||
{/* Radio button indicator */}
|
||||
<Box minWidth={2} flexShrink={0}>
|
||||
<Text
|
||||
color={isSelected ? theme.ui.focus : theme.text.primary}
|
||||
aria-hidden
|
||||
>
|
||||
{isSelected ? selectedIndicator : ' '}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
{/* Item number */}
|
||||
{showNumbers && !item.hideNumber && (
|
||||
<Box
|
||||
marginRight={1}
|
||||
flexShrink={0}
|
||||
minWidth={itemNumberText.length}
|
||||
aria-state={{ checked: isSelected }}
|
||||
>
|
||||
<Text color={numberColor}>{itemNumberText}</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Custom content via render prop */}
|
||||
<Box flexGrow={1}>
|
||||
{renderItem(item, {
|
||||
isSelected,
|
||||
titleColor,
|
||||
numberColor,
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base component for selection lists that provides common UI structure
|
||||
* and keyboard navigation logic via the useSelectionList hook.
|
||||
@@ -70,7 +184,7 @@ export function BaseSelectionList<
|
||||
selectedIndicator = '●',
|
||||
renderItem,
|
||||
}: BaseSelectionListProps<T, TItem>): React.JSX.Element {
|
||||
const { activeIndex } = useSelectionList({
|
||||
const { activeIndex, setActiveIndex } = useSelectionList({
|
||||
items,
|
||||
initialIndex,
|
||||
onSelect,
|
||||
@@ -107,10 +221,12 @@ export function BaseSelectionList<
|
||||
);
|
||||
const numberColumnWidth = String(items.length).length;
|
||||
|
||||
const showArrows = showScrollArrows && items.length > maxItemsToShow;
|
||||
|
||||
return (
|
||||
<Box flexDirection="column">
|
||||
{/* Use conditional coloring instead of conditional rendering */}
|
||||
{showScrollArrows && items.length > maxItemsToShow && (
|
||||
{showArrows && (
|
||||
<Text
|
||||
color={
|
||||
effectiveScrollOffset > 0
|
||||
@@ -126,71 +242,24 @@ export function BaseSelectionList<
|
||||
const itemIndex = effectiveScrollOffset + index;
|
||||
const isSelected = activeIndex === itemIndex;
|
||||
|
||||
// Determine colors based on selection and disabled state
|
||||
let titleColor = theme.text.primary;
|
||||
let numberColor = theme.text.primary;
|
||||
|
||||
if (isSelected) {
|
||||
titleColor = theme.ui.focus;
|
||||
numberColor = theme.ui.focus;
|
||||
} else if (item.disabled) {
|
||||
titleColor = theme.text.secondary;
|
||||
numberColor = theme.text.secondary;
|
||||
}
|
||||
|
||||
if (!isFocused && !item.disabled) {
|
||||
numberColor = theme.text.secondary;
|
||||
}
|
||||
|
||||
if (!showNumbers) {
|
||||
numberColor = theme.text.secondary;
|
||||
}
|
||||
|
||||
const itemNumberText = `${String(itemIndex + 1).padStart(
|
||||
numberColumnWidth,
|
||||
)}.`;
|
||||
|
||||
return (
|
||||
<Box
|
||||
<SelectionListItemRow
|
||||
key={item.key}
|
||||
alignItems="flex-start"
|
||||
backgroundColor={isSelected ? theme.background.focus : undefined}
|
||||
>
|
||||
{/* Radio button indicator */}
|
||||
<Box minWidth={2} flexShrink={0}>
|
||||
<Text
|
||||
color={isSelected ? theme.ui.focus : theme.text.primary}
|
||||
aria-hidden
|
||||
>
|
||||
{isSelected ? selectedIndicator : ' '}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
{/* Item number */}
|
||||
{showNumbers && !item.hideNumber && (
|
||||
<Box
|
||||
marginRight={1}
|
||||
flexShrink={0}
|
||||
minWidth={itemNumberText.length}
|
||||
aria-state={{ checked: isSelected }}
|
||||
>
|
||||
<Text color={numberColor}>{itemNumberText}</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Custom content via render prop */}
|
||||
<Box flexGrow={1}>
|
||||
{renderItem(item, {
|
||||
isSelected,
|
||||
titleColor,
|
||||
numberColor,
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
item={item}
|
||||
itemIndex={itemIndex}
|
||||
isSelected={isSelected}
|
||||
isFocused={isFocused}
|
||||
showNumbers={showNumbers}
|
||||
selectedIndicator={selectedIndicator}
|
||||
numberColumnWidth={numberColumnWidth}
|
||||
onSelect={onSelect}
|
||||
setActiveIndex={setActiveIndex}
|
||||
renderItem={renderItem}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
{showScrollArrows && items.length > maxItemsToShow && (
|
||||
{showArrows && (
|
||||
<Text
|
||||
color={
|
||||
effectiveScrollOffset + maxItemsToShow < items.length
|
||||
|
||||
@@ -11,12 +11,17 @@ import { act } from 'react';
|
||||
import { TextInput } from './TextInput.js';
|
||||
import { useKeypress } from '../../hooks/useKeypress.js';
|
||||
import { useTextBuffer, type TextBuffer } from './text-buffer.js';
|
||||
import { useMouseClick } from '../../hooks/useMouseClick.js';
|
||||
|
||||
// Mocks
|
||||
vi.mock('../../hooks/useKeypress.js', () => ({
|
||||
useKeypress: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../hooks/useMouseClick.js', () => ({
|
||||
useMouseClick: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('./text-buffer.js', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('./text-buffer.js')>();
|
||||
const mockTextBuffer = {
|
||||
@@ -69,6 +74,7 @@ vi.mock('./text-buffer.js', async (importOriginal) => {
|
||||
|
||||
const mockedUseKeypress = useKeypress as Mock;
|
||||
const mockedUseTextBuffer = useTextBuffer as Mock;
|
||||
const mockedUseMouseClick = useMouseClick as Mock;
|
||||
|
||||
describe('TextInput', () => {
|
||||
const onCancel = vi.fn();
|
||||
@@ -84,6 +90,7 @@ describe('TextInput', () => {
|
||||
cursor: [0, 0],
|
||||
visualCursor: [0, 0],
|
||||
viewportVisualLines: [''],
|
||||
visualScrollRow: 0,
|
||||
pastedContent: {} as Record<string, string>,
|
||||
handleInput: vi.fn((key) => {
|
||||
if (key.sequence) {
|
||||
@@ -408,4 +415,36 @@ describe('TextInput', () => {
|
||||
expect(lastFrame()).toContain('line2');
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('registers mouse click handler for free-form text input', async () => {
|
||||
const { unmount } = await render(
|
||||
<TextInput buffer={mockBuffer} onSubmit={onSubmit} onCancel={onCancel} />,
|
||||
);
|
||||
|
||||
expect(mockedUseMouseClick).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
expect.any(Function),
|
||||
expect.objectContaining({ isActive: true, name: 'left-press' }),
|
||||
);
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('registers mouse click handler for placeholder view', async () => {
|
||||
mockBuffer.text = '';
|
||||
const { unmount } = await render(
|
||||
<TextInput
|
||||
buffer={mockBuffer}
|
||||
placeholder="test"
|
||||
onSubmit={onSubmit}
|
||||
onCancel={onCancel}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(mockedUseMouseClick).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
expect.any(Function),
|
||||
expect.objectContaining({ isActive: true, name: 'left-press' }),
|
||||
);
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
import type React from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import { Text, Box } from 'ink';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { Text, Box, type DOMElement } from 'ink';
|
||||
import { useKeypress, type Key } from '../../hooks/useKeypress.js';
|
||||
import chalk from 'chalk';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
@@ -14,6 +14,7 @@ import { expandPastePlaceholders, type TextBuffer } from './text-buffer.js';
|
||||
import { cpSlice, cpIndexToOffset } from '../../utils/textUtils.js';
|
||||
import { Command } from '../../key/keyMatchers.js';
|
||||
import { useKeyMatchers } from '../../hooks/useKeyMatchers.js';
|
||||
import { useMouseClick } from '../../hooks/useMouseClick.js';
|
||||
|
||||
export interface TextInputProps {
|
||||
buffer: TextBuffer;
|
||||
@@ -31,6 +32,8 @@ export function TextInput({
|
||||
focus = true,
|
||||
}: TextInputProps): React.JSX.Element {
|
||||
const keyMatchers = useKeyMatchers();
|
||||
const containerRef = useRef<DOMElement>(null);
|
||||
|
||||
const {
|
||||
text,
|
||||
handleInput,
|
||||
@@ -40,6 +43,17 @@ export function TextInput({
|
||||
} = buffer;
|
||||
const [cursorVisualRowAbsolute, cursorVisualColAbsolute] = visualCursor;
|
||||
|
||||
useMouseClick(
|
||||
containerRef,
|
||||
(_event, relativeX, relativeY) => {
|
||||
if (focus) {
|
||||
const visRowAbsolute = visualScrollRow + relativeY;
|
||||
buffer.moveToVisualPosition(visRowAbsolute, relativeX);
|
||||
}
|
||||
},
|
||||
{ isActive: focus, name: 'left-press' },
|
||||
);
|
||||
|
||||
const handleKeyPress = useCallback(
|
||||
(key: Key) => {
|
||||
if (key.name === 'escape' && onCancel) {
|
||||
@@ -64,7 +78,7 @@ export function TextInput({
|
||||
|
||||
if (showPlaceholder) {
|
||||
return (
|
||||
<Box>
|
||||
<Box ref={containerRef}>
|
||||
{focus ? (
|
||||
<Text terminalCursorFocus={focus} terminalCursorPosition={0}>
|
||||
{chalk.inverse(placeholder[0] || ' ')}
|
||||
@@ -78,7 +92,7 @@ export function TextInput({
|
||||
}
|
||||
|
||||
return (
|
||||
<Box flexDirection="column">
|
||||
<Box ref={containerRef} flexDirection="column">
|
||||
{viewportVisualLines.map((lineText, idx) => {
|
||||
const currentVisualRow = visualScrollRow + idx;
|
||||
const isCursorLine =
|
||||
|
||||
@@ -858,11 +858,81 @@ describe('useSlashCommandProcessor', () => {
|
||||
});
|
||||
|
||||
describe('Lifecycle', () => {
|
||||
it('removes the IDE status listener on unmount after async initialization', async () => {
|
||||
let resolveIdeClient:
|
||||
| ((client: {
|
||||
addStatusChangeListener: (listener: () => void) => void;
|
||||
removeStatusChangeListener: (listener: () => void) => void;
|
||||
}) => void)
|
||||
| undefined;
|
||||
const addStatusChangeListener = vi.fn();
|
||||
const removeStatusChangeListener = vi.fn();
|
||||
|
||||
mockIdeClientGetInstance.mockImplementation(
|
||||
() =>
|
||||
new Promise((resolve) => {
|
||||
resolveIdeClient = resolve;
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await setupProcessorHook();
|
||||
|
||||
await act(async () => {
|
||||
resolveIdeClient?.({
|
||||
addStatusChangeListener,
|
||||
removeStatusChangeListener,
|
||||
});
|
||||
});
|
||||
|
||||
result.unmount();
|
||||
unmountHook = undefined;
|
||||
|
||||
expect(addStatusChangeListener).toHaveBeenCalledTimes(1);
|
||||
expect(removeStatusChangeListener).toHaveBeenCalledTimes(1);
|
||||
expect(removeStatusChangeListener).toHaveBeenCalledWith(
|
||||
addStatusChangeListener.mock.calls[0]?.[0],
|
||||
);
|
||||
});
|
||||
|
||||
it('does not register an IDE status listener if unmounted before async initialization resolves', async () => {
|
||||
let resolveIdeClient:
|
||||
| ((client: {
|
||||
addStatusChangeListener: (listener: () => void) => void;
|
||||
removeStatusChangeListener: (listener: () => void) => void;
|
||||
}) => void)
|
||||
| undefined;
|
||||
const addStatusChangeListener = vi.fn();
|
||||
const removeStatusChangeListener = vi.fn();
|
||||
|
||||
mockIdeClientGetInstance.mockImplementation(
|
||||
() =>
|
||||
new Promise((resolve) => {
|
||||
resolveIdeClient = resolve;
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await setupProcessorHook();
|
||||
|
||||
result.unmount();
|
||||
unmountHook = undefined;
|
||||
|
||||
await act(async () => {
|
||||
resolveIdeClient?.({
|
||||
addStatusChangeListener,
|
||||
removeStatusChangeListener,
|
||||
});
|
||||
});
|
||||
|
||||
expect(addStatusChangeListener).not.toHaveBeenCalled();
|
||||
expect(removeStatusChangeListener).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should abort command loading when the hook unmounts', async () => {
|
||||
const abortSpy = vi.spyOn(AbortController.prototype, 'abort');
|
||||
const { unmount } = await setupProcessorHook();
|
||||
|
||||
unmount();
|
||||
unmountHook = undefined;
|
||||
|
||||
expect(abortSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@@ -281,10 +281,16 @@ export const useSlashCommandProcessor = (
|
||||
const listener = () => {
|
||||
reloadCommands();
|
||||
};
|
||||
let isActive = true;
|
||||
let activeIdeClient: IdeClient | undefined;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
(async () => {
|
||||
const ideClient = await IdeClient.getInstance();
|
||||
if (!isActive) {
|
||||
return;
|
||||
}
|
||||
activeIdeClient = ideClient;
|
||||
ideClient.addStatusChangeListener(listener);
|
||||
})();
|
||||
|
||||
@@ -307,11 +313,8 @@ export const useSlashCommandProcessor = (
|
||||
coreEvents.on('extensionsStopping', extensionEventListener);
|
||||
|
||||
return () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
(async () => {
|
||||
const ideClient = await IdeClient.getInstance();
|
||||
ideClient.removeStatusChangeListener(listener);
|
||||
})();
|
||||
isActive = false;
|
||||
activeIdeClient?.removeStatusChangeListener(listener);
|
||||
removeMCPStatusChangeListener(listener);
|
||||
coreEvents.off('extensionsStarting', extensionEventListener);
|
||||
coreEvents.off('extensionsStopping', extensionEventListener);
|
||||
|
||||
@@ -15,12 +15,14 @@ import { getPendingAttentionNotification } from '../utils/pendingAttentionNotifi
|
||||
import {
|
||||
buildRunEventNotificationContent,
|
||||
notifyViaTerminal,
|
||||
type TerminalNotificationMethod,
|
||||
} from '../../utils/terminalNotifications.js';
|
||||
|
||||
const ATTENTION_NOTIFICATION_COOLDOWN_MS = 20_000;
|
||||
|
||||
interface RunEventNotificationParams {
|
||||
notificationsEnabled: boolean;
|
||||
notificationMethod: TerminalNotificationMethod;
|
||||
isFocused: boolean;
|
||||
hasReceivedFocusEvent: boolean;
|
||||
streamingState: StreamingState;
|
||||
@@ -36,6 +38,7 @@ interface RunEventNotificationParams {
|
||||
|
||||
export function useRunEventNotifications({
|
||||
notificationsEnabled,
|
||||
notificationMethod,
|
||||
isFocused,
|
||||
hasReceivedFocusEvent,
|
||||
streamingState,
|
||||
@@ -124,11 +127,13 @@ export function useRunEventNotifications({
|
||||
void notifyViaTerminal(
|
||||
notificationsEnabled,
|
||||
buildRunEventNotificationContent(pendingAttentionNotification.event),
|
||||
notificationMethod,
|
||||
);
|
||||
}, [
|
||||
isFocused,
|
||||
hasReceivedFocusEvent,
|
||||
notificationsEnabled,
|
||||
notificationMethod,
|
||||
pendingAttentionNotification,
|
||||
]);
|
||||
|
||||
@@ -159,12 +164,14 @@ export function useRunEventNotifications({
|
||||
type: 'session_complete',
|
||||
detail: 'Gemini CLI finished responding.',
|
||||
}),
|
||||
notificationMethod,
|
||||
);
|
||||
}, [
|
||||
streamingState,
|
||||
isFocused,
|
||||
hasReceivedFocusEvent,
|
||||
notificationsEnabled,
|
||||
notificationMethod,
|
||||
hasPendingActionRequired,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from '../../theme.js';
|
||||
import { interpolateColor } from '../../color-utils.js';
|
||||
|
||||
const githubDarkColorblindColors: ColorsTheme = {
|
||||
type: 'dark',
|
||||
Background: '#0d1117',
|
||||
Foreground: '#e6edf3',
|
||||
LightBlue: '#a5d6ff',
|
||||
AccentBlue: '#79c0ff',
|
||||
AccentPurple: '#d2a8ff',
|
||||
AccentCyan: '#a5d6ff',
|
||||
AccentGreen: '#a5d6ff',
|
||||
AccentYellow: '#d29922',
|
||||
AccentRed: '#f0883e',
|
||||
DiffAdded: '#0d161f',
|
||||
DiffRemoved: '#1d150e',
|
||||
Comment: '#7d8590',
|
||||
Gray: '#7d8590',
|
||||
DarkGray: interpolateColor('#7d8590', '#0d1117', 0.5),
|
||||
GradientColors: ['#58a6ff', '#f0883e'],
|
||||
};
|
||||
|
||||
export const GitHubDarkColorblind: Theme = new Theme(
|
||||
'GitHub Dark Colorblind',
|
||||
'dark',
|
||||
{
|
||||
hljs: {
|
||||
display: 'block',
|
||||
overflowX: 'auto',
|
||||
padding: '0.5em',
|
||||
color: githubDarkColorblindColors.Foreground,
|
||||
background: githubDarkColorblindColors.Background,
|
||||
},
|
||||
'hljs-comment': {
|
||||
color: githubDarkColorblindColors.Comment,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'hljs-quote': {
|
||||
color: githubDarkColorblindColors.Comment,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'hljs-keyword': {
|
||||
color: githubDarkColorblindColors.AccentRed,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-selector-tag': {
|
||||
color: githubDarkColorblindColors.AccentRed,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-subst': {
|
||||
color: githubDarkColorblindColors.Foreground,
|
||||
},
|
||||
'hljs-number': {
|
||||
color: githubDarkColorblindColors.LightBlue,
|
||||
},
|
||||
'hljs-literal': {
|
||||
color: githubDarkColorblindColors.LightBlue,
|
||||
},
|
||||
'hljs-variable': {
|
||||
color: githubDarkColorblindColors.Foreground,
|
||||
},
|
||||
'hljs-template-variable': {
|
||||
color: githubDarkColorblindColors.Foreground,
|
||||
},
|
||||
'hljs-tag .hljs-attr': {
|
||||
color: githubDarkColorblindColors.AccentYellow,
|
||||
},
|
||||
'hljs-string': {
|
||||
color: githubDarkColorblindColors.AccentCyan,
|
||||
},
|
||||
'hljs-doctag': {
|
||||
color: githubDarkColorblindColors.AccentCyan,
|
||||
},
|
||||
'hljs-title': {
|
||||
color: githubDarkColorblindColors.AccentPurple,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-section': {
|
||||
color: githubDarkColorblindColors.AccentPurple,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-selector-id': {
|
||||
color: githubDarkColorblindColors.AccentPurple,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-type': {
|
||||
color: githubDarkColorblindColors.AccentGreen,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-class .hljs-title': {
|
||||
color: githubDarkColorblindColors.AccentGreen,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-tag': {
|
||||
color: githubDarkColorblindColors.AccentGreen,
|
||||
},
|
||||
'hljs-name': {
|
||||
color: githubDarkColorblindColors.AccentGreen,
|
||||
},
|
||||
'hljs-attribute': {
|
||||
color: githubDarkColorblindColors.LightBlue,
|
||||
},
|
||||
'hljs-regexp': {
|
||||
color: githubDarkColorblindColors.AccentCyan,
|
||||
},
|
||||
'hljs-link': {
|
||||
color: githubDarkColorblindColors.AccentCyan,
|
||||
},
|
||||
'hljs-symbol': {
|
||||
color: githubDarkColorblindColors.AccentPurple,
|
||||
},
|
||||
'hljs-bullet': {
|
||||
color: githubDarkColorblindColors.AccentPurple,
|
||||
},
|
||||
'hljs-built_in': {
|
||||
color: githubDarkColorblindColors.LightBlue,
|
||||
},
|
||||
'hljs-builtin-name': {
|
||||
color: githubDarkColorblindColors.LightBlue,
|
||||
},
|
||||
'hljs-meta': {
|
||||
color: githubDarkColorblindColors.LightBlue,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-deletion': {
|
||||
background: '#682d0f',
|
||||
color: githubDarkColorblindColors.AccentRed,
|
||||
},
|
||||
'hljs-addition': {
|
||||
background: '#0c2d6b',
|
||||
color: githubDarkColorblindColors.AccentGreen,
|
||||
},
|
||||
'hljs-emphasis': {
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'hljs-strong': {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
githubDarkColorblindColors,
|
||||
);
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from '../../theme.js';
|
||||
import { interpolateColor } from '../../color-utils.js';
|
||||
|
||||
const githubLightColorblindColors: ColorsTheme = {
|
||||
type: 'light',
|
||||
Background: '#ffffff',
|
||||
Foreground: '#1f2328',
|
||||
LightBlue: '#0a3069',
|
||||
AccentBlue: '#0550ae',
|
||||
AccentPurple: '#8250df',
|
||||
AccentCyan: '#0a3069',
|
||||
AccentGreen: '#0969da',
|
||||
AccentYellow: '#9a6700',
|
||||
AccentRed: '#bc4c00',
|
||||
DiffAdded: '#ddf4ff',
|
||||
DiffRemoved: '#fff1e5',
|
||||
Comment: '#656d76',
|
||||
Gray: '#656d76',
|
||||
DarkGray: interpolateColor('#656d76', '#ffffff', 0.5),
|
||||
GradientColors: ['#0969da', '#bc4c00'],
|
||||
};
|
||||
|
||||
export const GitHubLightColorblind: Theme = new Theme(
|
||||
'GitHub Light Colorblind',
|
||||
'light',
|
||||
{
|
||||
hljs: {
|
||||
display: 'block',
|
||||
overflowX: 'auto',
|
||||
padding: '0.5em',
|
||||
color: githubLightColorblindColors.Foreground,
|
||||
background: githubLightColorblindColors.Background,
|
||||
},
|
||||
'hljs-comment': {
|
||||
color: githubLightColorblindColors.Comment,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'hljs-quote': {
|
||||
color: githubLightColorblindColors.Comment,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'hljs-keyword': {
|
||||
color: githubLightColorblindColors.AccentRed,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-selector-tag': {
|
||||
color: githubLightColorblindColors.AccentRed,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-subst': {
|
||||
color: githubLightColorblindColors.Foreground,
|
||||
},
|
||||
'hljs-number': {
|
||||
color: githubLightColorblindColors.LightBlue,
|
||||
},
|
||||
'hljs-literal': {
|
||||
color: githubLightColorblindColors.LightBlue,
|
||||
},
|
||||
'hljs-variable': {
|
||||
color: githubLightColorblindColors.Foreground,
|
||||
},
|
||||
'hljs-template-variable': {
|
||||
color: githubLightColorblindColors.Foreground,
|
||||
},
|
||||
'hljs-tag .hljs-attr': {
|
||||
color: githubLightColorblindColors.AccentYellow,
|
||||
},
|
||||
'hljs-string': {
|
||||
color: githubLightColorblindColors.AccentCyan,
|
||||
},
|
||||
'hljs-doctag': {
|
||||
color: githubLightColorblindColors.AccentCyan,
|
||||
},
|
||||
'hljs-title': {
|
||||
color: githubLightColorblindColors.AccentPurple,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-section': {
|
||||
color: githubLightColorblindColors.AccentPurple,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-selector-id': {
|
||||
color: githubLightColorblindColors.AccentPurple,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-type': {
|
||||
color: githubLightColorblindColors.AccentGreen,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-class .hljs-title': {
|
||||
color: githubLightColorblindColors.AccentGreen,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-tag': {
|
||||
color: githubLightColorblindColors.AccentGreen,
|
||||
},
|
||||
'hljs-name': {
|
||||
color: githubLightColorblindColors.AccentGreen,
|
||||
},
|
||||
'hljs-attribute': {
|
||||
color: githubLightColorblindColors.LightBlue,
|
||||
},
|
||||
'hljs-regexp': {
|
||||
color: githubLightColorblindColors.AccentCyan,
|
||||
},
|
||||
'hljs-link': {
|
||||
color: githubLightColorblindColors.AccentCyan,
|
||||
},
|
||||
'hljs-symbol': {
|
||||
color: githubLightColorblindColors.AccentPurple,
|
||||
},
|
||||
'hljs-bullet': {
|
||||
color: githubLightColorblindColors.AccentPurple,
|
||||
},
|
||||
'hljs-built_in': {
|
||||
color: githubLightColorblindColors.LightBlue,
|
||||
},
|
||||
'hljs-builtin-name': {
|
||||
color: githubLightColorblindColors.LightBlue,
|
||||
},
|
||||
'hljs-meta': {
|
||||
color: githubLightColorblindColors.LightBlue,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-deletion': {
|
||||
background: '#fff1e5',
|
||||
color: githubLightColorblindColors.AccentRed,
|
||||
},
|
||||
'hljs-addition': {
|
||||
background: '#ddf4ff',
|
||||
color: githubLightColorblindColors.AccentGreen,
|
||||
},
|
||||
'hljs-emphasis': {
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'hljs-strong': {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
githubLightColorblindColors,
|
||||
);
|
||||
@@ -10,6 +10,8 @@ import { AtomOneDark } from './builtin/dark/atom-one-dark.js';
|
||||
import { Dracula } from './builtin/dark/dracula-dark.js';
|
||||
import { GitHubDark } from './builtin/dark/github-dark.js';
|
||||
import { GitHubLight } from './builtin/light/github-light.js';
|
||||
import { GitHubDarkColorblind } from './builtin/dark/github-dark-colorblind.js';
|
||||
import { GitHubLightColorblind } from './builtin/light/github-light-colorblind.js';
|
||||
import { GoogleCode } from './builtin/light/googlecode-light.js';
|
||||
import { Holiday } from './builtin/dark/holiday-dark.js';
|
||||
import { DefaultLight } from './builtin/light/default-light.js';
|
||||
@@ -79,6 +81,8 @@ class ThemeManager {
|
||||
DefaultDark,
|
||||
GitHubDark,
|
||||
GitHubLight,
|
||||
GitHubDarkColorblind,
|
||||
GitHubLightColorblind,
|
||||
GoogleCode,
|
||||
Holiday,
|
||||
ShadesOfPurple,
|
||||
|
||||
@@ -365,76 +365,123 @@ describe('TerminalCapabilityManager', () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe('supportsOsc9Notifications', () => {
|
||||
describe('isTmux', () => {
|
||||
const manager = TerminalCapabilityManager.getInstance();
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: 'WezTerm (terminal name)',
|
||||
terminalName: 'WezTerm',
|
||||
env: {},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: 'iTerm.app (terminal name)',
|
||||
terminalName: 'iTerm.app',
|
||||
env: {},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: 'ghostty (terminal name)',
|
||||
terminalName: 'ghostty',
|
||||
env: {},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: 'kitty (terminal name)',
|
||||
terminalName: 'kitty',
|
||||
env: {},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: 'some-other-term (terminal name)',
|
||||
terminalName: 'some-other-term',
|
||||
env: {},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: 'iTerm.app (TERM_PROGRAM)',
|
||||
terminalName: undefined,
|
||||
env: { TERM_PROGRAM: 'iTerm.app' },
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: 'vscode (TERM_PROGRAM)',
|
||||
terminalName: undefined,
|
||||
env: { TERM_PROGRAM: 'vscode' },
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: 'xterm-kitty (TERM)',
|
||||
terminalName: undefined,
|
||||
env: { TERM: 'xterm-kitty' },
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: 'xterm-256color (TERM)',
|
||||
terminalName: undefined,
|
||||
env: { TERM: 'xterm-256color' },
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: 'Windows Terminal (WT_SESSION)',
|
||||
terminalName: 'iTerm.app',
|
||||
env: { WT_SESSION: 'some-guid' },
|
||||
expected: false,
|
||||
},
|
||||
])(
|
||||
'should return $expected for $name',
|
||||
({ terminalName, env, expected }) => {
|
||||
vi.spyOn(manager, 'getTerminalName').mockReturnValue(terminalName);
|
||||
expect(manager.supportsOsc9Notifications(env)).toBe(expected);
|
||||
},
|
||||
);
|
||||
it('returns true when TMUX is set', () => {
|
||||
expect(manager.isTmux({ TMUX: '1' })).toBe(true);
|
||||
expect(manager.isTmux({ TMUX: 'tmux-1234' })).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when TMUX is not set', () => {
|
||||
expect(manager.isTmux({})).toBe(false);
|
||||
expect(manager.isTmux({ STY: '1' })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isScreen', () => {
|
||||
const manager = TerminalCapabilityManager.getInstance();
|
||||
|
||||
it('returns true when STY is set', () => {
|
||||
expect(manager.isScreen({ STY: '1' })).toBe(true);
|
||||
expect(manager.isScreen({ STY: 'screen.1234' })).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when STY is not set', () => {
|
||||
expect(manager.isScreen({})).toBe(false);
|
||||
expect(manager.isScreen({ TMUX: '1' })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isITerm2', () => {
|
||||
const manager = TerminalCapabilityManager.getInstance();
|
||||
|
||||
it('returns true when iTerm is in terminal name', () => {
|
||||
vi.spyOn(manager, 'getTerminalName').mockReturnValue('iTerm.app');
|
||||
expect(manager.isITerm2({})).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true when TERM_PROGRAM is iTerm.app', () => {
|
||||
vi.spyOn(manager, 'getTerminalName').mockReturnValue(undefined);
|
||||
expect(manager.isITerm2({ TERM_PROGRAM: 'iTerm.app' })).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false otherwise', () => {
|
||||
vi.spyOn(manager, 'getTerminalName').mockReturnValue('xterm');
|
||||
expect(manager.isITerm2({ TERM_PROGRAM: 'Apple_Terminal' })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAlacritty', () => {
|
||||
const manager = TerminalCapabilityManager.getInstance();
|
||||
|
||||
it('returns true when ALACRITTY_WINDOW_ID is set', () => {
|
||||
vi.spyOn(manager, 'getTerminalName').mockReturnValue(undefined);
|
||||
expect(manager.isAlacritty({ ALACRITTY_WINDOW_ID: '123' })).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true when TERM is alacritty', () => {
|
||||
vi.spyOn(manager, 'getTerminalName').mockReturnValue(undefined);
|
||||
expect(manager.isAlacritty({ TERM: 'alacritty' })).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true when terminal name contains alacritty', () => {
|
||||
vi.spyOn(manager, 'getTerminalName').mockReturnValue('alacritty');
|
||||
expect(manager.isAlacritty({})).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false otherwise', () => {
|
||||
vi.spyOn(manager, 'getTerminalName').mockReturnValue(undefined);
|
||||
expect(manager.isAlacritty({ TERM: 'xterm' })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAppleTerminal', () => {
|
||||
const manager = TerminalCapabilityManager.getInstance();
|
||||
|
||||
it('returns true when apple_terminal is in terminal name', () => {
|
||||
vi.spyOn(manager, 'getTerminalName').mockReturnValue('apple_terminal');
|
||||
expect(manager.isAppleTerminal({})).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true when TERM_PROGRAM is Apple_Terminal', () => {
|
||||
vi.spyOn(manager, 'getTerminalName').mockReturnValue(undefined);
|
||||
expect(manager.isAppleTerminal({ TERM_PROGRAM: 'Apple_Terminal' })).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it('returns false otherwise', () => {
|
||||
vi.spyOn(manager, 'getTerminalName').mockReturnValue('xterm');
|
||||
expect(manager.isAppleTerminal({ TERM_PROGRAM: 'iTerm.app' })).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isVSCodeTerminal', () => {
|
||||
const manager = TerminalCapabilityManager.getInstance();
|
||||
|
||||
it('returns true when TERM_PROGRAM is vscode', () => {
|
||||
expect(manager.isVSCodeTerminal({ TERM_PROGRAM: 'vscode' })).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false otherwise', () => {
|
||||
expect(manager.isVSCodeTerminal({ TERM_PROGRAM: 'iTerm.app' })).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isWindowsTerminal', () => {
|
||||
const manager = TerminalCapabilityManager.getInstance();
|
||||
|
||||
it('returns true when WT_SESSION is set', () => {
|
||||
expect(manager.isWindowsTerminal({ WT_SESSION: 'some-guid' })).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false otherwise', () => {
|
||||
expect(manager.isWindowsTerminal({})).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -284,31 +284,43 @@ export class TerminalCapabilityManager {
|
||||
);
|
||||
}
|
||||
|
||||
supportsOsc9Notifications(env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
if (env['WT_SESSION']) {
|
||||
return false;
|
||||
}
|
||||
isTmux(env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
return !!env['TMUX'];
|
||||
}
|
||||
|
||||
return (
|
||||
this.hasOsc9TerminalSignature(this.getTerminalName()) ||
|
||||
this.hasOsc9TerminalSignature(env['TERM_PROGRAM']) ||
|
||||
this.hasOsc9TerminalSignature(env['TERM'])
|
||||
isScreen(env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
return !!env['STY'];
|
||||
}
|
||||
|
||||
isITerm2(env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
return !!(
|
||||
this.getTerminalName()?.toLowerCase().includes('iterm') ||
|
||||
env['TERM_PROGRAM']?.toLowerCase().includes('iterm')
|
||||
);
|
||||
}
|
||||
|
||||
private hasOsc9TerminalSignature(value: string | undefined): boolean {
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const normalized = value.toLowerCase();
|
||||
return (
|
||||
normalized.includes('wezterm') ||
|
||||
normalized.includes('ghostty') ||
|
||||
normalized.includes('iterm') ||
|
||||
normalized.includes('kitty')
|
||||
isAlacritty(env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
return !!(
|
||||
this.getTerminalName()?.toLowerCase().includes('alacritty') ||
|
||||
env['ALACRITTY_WINDOW_ID'] ||
|
||||
env['TERM']?.toLowerCase().includes('alacritty')
|
||||
);
|
||||
}
|
||||
|
||||
isAppleTerminal(env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
return !!(
|
||||
this.getTerminalName()?.toLowerCase().includes('apple_terminal') ||
|
||||
env['TERM_PROGRAM']?.toLowerCase().includes('apple_terminal')
|
||||
);
|
||||
}
|
||||
|
||||
isVSCodeTerminal(env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
return !!env['TERM_PROGRAM']?.toLowerCase().includes('vscode');
|
||||
}
|
||||
|
||||
isWindowsTerminal(env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
return !!env['WT_SESSION'];
|
||||
}
|
||||
}
|
||||
|
||||
export const terminalCapabilityManager =
|
||||
|
||||
@@ -8,8 +8,13 @@ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { spawn, exec, execFile, execSync } from 'node:child_process';
|
||||
import os from 'node:os';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { start_sandbox } from './sandbox.js';
|
||||
import { FatalSandboxError, type SandboxConfig } from '@google/gemini-cli-core';
|
||||
import {
|
||||
FatalSandboxError,
|
||||
homedir,
|
||||
type SandboxConfig,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { createMockSandboxConfig } from '@google/gemini-cli-test-utils';
|
||||
import { EventEmitter } from 'node:events';
|
||||
|
||||
@@ -133,6 +138,7 @@ describe('sandbox', () => {
|
||||
afterEach(() => {
|
||||
process.env = originalEnv;
|
||||
process.argv = originalArgv;
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
describe('start_sandbox', () => {
|
||||
@@ -171,6 +177,105 @@ describe('sandbox', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should resolve custom seatbelt profile from user home directory', async () => {
|
||||
vi.mocked(os.platform).mockReturnValue('darwin');
|
||||
vi.stubEnv('SEATBELT_PROFILE', 'custom-test');
|
||||
vi.mocked(fs.existsSync).mockImplementation((p) =>
|
||||
String(p).includes(
|
||||
path.join(homedir(), '.gemini', 'sandbox-macos-custom-test.sb'),
|
||||
),
|
||||
);
|
||||
const config: SandboxConfig = createMockSandboxConfig({
|
||||
command: 'sandbox-exec',
|
||||
image: 'some-image',
|
||||
});
|
||||
|
||||
interface MockProcess extends EventEmitter {
|
||||
stdout: EventEmitter;
|
||||
stderr: EventEmitter;
|
||||
}
|
||||
const mockSpawnProcess = new EventEmitter() as MockProcess;
|
||||
mockSpawnProcess.stdout = new EventEmitter();
|
||||
mockSpawnProcess.stderr = new EventEmitter();
|
||||
vi.mocked(spawn).mockReturnValue(
|
||||
mockSpawnProcess as unknown as ReturnType<typeof spawn>,
|
||||
);
|
||||
|
||||
const promise = start_sandbox(config, [], undefined, ['arg1']);
|
||||
|
||||
setTimeout(() => {
|
||||
mockSpawnProcess.emit('close', 0);
|
||||
}, 10);
|
||||
|
||||
await expect(promise).resolves.toBe(0);
|
||||
expect(spawn).toHaveBeenCalledWith(
|
||||
'sandbox-exec',
|
||||
expect.any(Array),
|
||||
expect.objectContaining({ stdio: 'inherit' }),
|
||||
);
|
||||
const spawnArgs = vi.mocked(spawn).mock.calls[0]?.[1];
|
||||
expect(spawnArgs).toEqual(
|
||||
expect.arrayContaining(['-f', expect.any(String)]),
|
||||
);
|
||||
const profileArg = spawnArgs?.[spawnArgs.indexOf('-f') + 1];
|
||||
expect(profileArg).toEqual(
|
||||
expect.stringContaining(
|
||||
path.join(homedir(), '.gemini', 'sandbox-macos-custom-test.sb'),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('should fall back to project .gemini directory when user profile is missing', async () => {
|
||||
vi.mocked(os.platform).mockReturnValue('darwin');
|
||||
vi.stubEnv('SEATBELT_PROFILE', 'custom-test');
|
||||
vi.mocked(fs.existsSync).mockImplementation((p) => {
|
||||
const s = String(p);
|
||||
return (
|
||||
s.includes(path.join('.gemini', 'sandbox-macos-custom-test.sb')) &&
|
||||
!s.includes(path.join(homedir(), '.gemini'))
|
||||
);
|
||||
});
|
||||
const config: SandboxConfig = createMockSandboxConfig({
|
||||
command: 'sandbox-exec',
|
||||
image: 'some-image',
|
||||
});
|
||||
|
||||
interface MockProcess extends EventEmitter {
|
||||
stdout: EventEmitter;
|
||||
stderr: EventEmitter;
|
||||
}
|
||||
const mockSpawnProcess = new EventEmitter() as MockProcess;
|
||||
mockSpawnProcess.stdout = new EventEmitter();
|
||||
mockSpawnProcess.stderr = new EventEmitter();
|
||||
vi.mocked(spawn).mockReturnValue(
|
||||
mockSpawnProcess as unknown as ReturnType<typeof spawn>,
|
||||
);
|
||||
|
||||
const promise = start_sandbox(config, [], undefined, ['arg1']);
|
||||
|
||||
setTimeout(() => {
|
||||
mockSpawnProcess.emit('close', 0);
|
||||
}, 10);
|
||||
|
||||
await expect(promise).resolves.toBe(0);
|
||||
expect(spawn).toHaveBeenCalledWith(
|
||||
'sandbox-exec',
|
||||
expect.any(Array),
|
||||
expect.objectContaining({ stdio: 'inherit' }),
|
||||
);
|
||||
const spawnArgs = vi.mocked(spawn).mock.calls[0]?.[1];
|
||||
expect(spawnArgs).toEqual(
|
||||
expect.arrayContaining(['-f', expect.any(String)]),
|
||||
);
|
||||
const profileArg = spawnArgs?.[spawnArgs.indexOf('-f') + 1];
|
||||
expect(profileArg).toEqual(
|
||||
expect.stringContaining(
|
||||
path.join('.gemini', 'sandbox-macos-custom-test.sb'),
|
||||
),
|
||||
);
|
||||
expect(profileArg).not.toContain(homedir());
|
||||
});
|
||||
|
||||
it('should throw FatalSandboxError if seatbelt profile is missing', async () => {
|
||||
vi.mocked(os.platform).mockReturnValue('darwin');
|
||||
vi.mocked(fs.existsSync).mockReturnValue(false);
|
||||
|
||||
@@ -68,9 +68,17 @@ export async function start_sandbox(
|
||||
let profileFile = fileURLToPath(
|
||||
new URL(`sandbox-macos-${profile}.sb`, import.meta.url),
|
||||
);
|
||||
// if profile name is not recognized, then look for file under project settings directory
|
||||
// if profile name is not recognized, look in user-level ~/.gemini first,
|
||||
// then fall back to project-level .gemini. path.basename() strips any
|
||||
// directory separators to prevent path traversal via SEATBELT_PROFILE.
|
||||
if (!BUILTIN_SEATBELT_PROFILES.includes(profile)) {
|
||||
profileFile = path.join(GEMINI_DIR, `sandbox-macos-${profile}.sb`);
|
||||
const safeProfile = path.basename(profile);
|
||||
const fileName = `sandbox-macos-${safeProfile}.sb`;
|
||||
const userProfileFile = path.join(homedir(), GEMINI_DIR, fileName);
|
||||
const projectProfileFile = path.join(GEMINI_DIR, fileName);
|
||||
profileFile = fs.existsSync(userProfileFile)
|
||||
? userProfileFile
|
||||
: projectProfileFile;
|
||||
}
|
||||
if (!fs.existsSync(profileFile)) {
|
||||
throw new FatalSandboxError(
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
MAX_NOTIFICATION_SUBTITLE_CHARS,
|
||||
MAX_NOTIFICATION_TITLE_CHARS,
|
||||
notifyViaTerminal,
|
||||
TerminalNotificationMethod,
|
||||
} from './terminalNotifications.js';
|
||||
|
||||
const writeToStdout = vi.hoisted(() => vi.fn());
|
||||
@@ -24,38 +25,19 @@ vi.mock('@google/gemini-cli-core', () => ({
|
||||
}));
|
||||
|
||||
describe('terminal notifications', () => {
|
||||
const originalPlatform = process.platform;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
vi.unstubAllEnvs();
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: 'darwin',
|
||||
configurable: true,
|
||||
});
|
||||
vi.stubEnv('TMUX', '');
|
||||
vi.stubEnv('STY', '');
|
||||
vi.stubEnv('WT_SESSION', '');
|
||||
vi.stubEnv('TERM_PROGRAM', '');
|
||||
vi.stubEnv('TERM', '');
|
||||
vi.stubEnv('ALACRITTY_WINDOW_ID', '');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: originalPlatform,
|
||||
configurable: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('emits notification on non-macOS platforms', async () => {
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: 'linux',
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
const shown = await notifyViaTerminal(true, {
|
||||
title: 't',
|
||||
body: 'b',
|
||||
});
|
||||
|
||||
expect(shown).toBe(true);
|
||||
expect(writeToStdout).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns false without writing when disabled', async () => {
|
||||
@@ -68,8 +50,7 @@ describe('terminal notifications', () => {
|
||||
expect(writeToStdout).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('emits OSC 9 notification when supported terminal is detected', async () => {
|
||||
vi.stubEnv('WT_SESSION', '');
|
||||
it('emits OSC 9 notification when iTerm2 is detected', async () => {
|
||||
vi.stubEnv('TERM_PROGRAM', 'iTerm.app');
|
||||
|
||||
const shown = await notifyViaTerminal(true, {
|
||||
@@ -85,23 +66,57 @@ describe('terminal notifications', () => {
|
||||
expect(emitted.endsWith('\x07')).toBe(true);
|
||||
});
|
||||
|
||||
it('emits BEL fallback when OSC 9 is not supported', async () => {
|
||||
vi.stubEnv('TERM_PROGRAM', '');
|
||||
vi.stubEnv('TERM', '');
|
||||
|
||||
it('emits OSC 777 for unknown terminals', async () => {
|
||||
const shown = await notifyViaTerminal(true, {
|
||||
title: 'Title',
|
||||
subtitle: 'Subtitle',
|
||||
body: 'Body',
|
||||
});
|
||||
|
||||
expect(shown).toBe(true);
|
||||
expect(writeToStdout).toHaveBeenCalledTimes(1);
|
||||
const emitted = String(writeToStdout.mock.calls[0][0]);
|
||||
expect(emitted.startsWith('\x1b]777;notify;')).toBe(true);
|
||||
});
|
||||
|
||||
it('uses BEL when Windows Terminal is detected', async () => {
|
||||
vi.stubEnv('WT_SESSION', '1');
|
||||
|
||||
const shown = await notifyViaTerminal(true, {
|
||||
title: 'Title',
|
||||
body: 'Body',
|
||||
});
|
||||
|
||||
expect(shown).toBe(true);
|
||||
expect(writeToStdout).toHaveBeenCalledWith('\x07');
|
||||
});
|
||||
|
||||
it('uses BEL fallback when WT_SESSION is set', async () => {
|
||||
vi.stubEnv('WT_SESSION', '1');
|
||||
vi.stubEnv('TERM_PROGRAM', 'WezTerm');
|
||||
it('uses BEL when Alacritty is detected', async () => {
|
||||
vi.stubEnv('ALACRITTY_WINDOW_ID', '1');
|
||||
|
||||
const shown = await notifyViaTerminal(true, {
|
||||
title: 'Title',
|
||||
body: 'Body',
|
||||
});
|
||||
|
||||
expect(shown).toBe(true);
|
||||
expect(writeToStdout).toHaveBeenCalledWith('\x07');
|
||||
});
|
||||
|
||||
it('uses BEL when Apple Terminal is detected', async () => {
|
||||
vi.stubEnv('TERM_PROGRAM', 'Apple_Terminal');
|
||||
|
||||
const shown = await notifyViaTerminal(true, {
|
||||
title: 'Title',
|
||||
body: 'Body',
|
||||
});
|
||||
|
||||
expect(shown).toBe(true);
|
||||
expect(writeToStdout).toHaveBeenCalledWith('\x07');
|
||||
});
|
||||
|
||||
it('uses BEL when VSCode Terminal is detected', async () => {
|
||||
vi.stubEnv('TERM_PROGRAM', 'vscode');
|
||||
|
||||
const shown = await notifyViaTerminal(true, {
|
||||
title: 'Title',
|
||||
@@ -127,7 +142,6 @@ describe('terminal notifications', () => {
|
||||
});
|
||||
|
||||
it('strips terminal control sequences and newlines from payload text', async () => {
|
||||
vi.stubEnv('WT_SESSION', '');
|
||||
vi.stubEnv('TERM_PROGRAM', 'iTerm.app');
|
||||
|
||||
const shown = await notifyViaTerminal(true, {
|
||||
@@ -162,4 +176,124 @@ describe('terminal notifications', () => {
|
||||
MAX_NOTIFICATION_BODY_CHARS,
|
||||
);
|
||||
});
|
||||
|
||||
it('emits OSC 9 notification when method is explicitly set to osc9', async () => {
|
||||
// Explicitly set terminal to something that would normally use BEL
|
||||
vi.stubEnv('WT_SESSION', '1');
|
||||
|
||||
const shown = await notifyViaTerminal(
|
||||
true,
|
||||
{
|
||||
title: 'Explicit OSC 9',
|
||||
body: 'Body',
|
||||
},
|
||||
TerminalNotificationMethod.Osc9,
|
||||
);
|
||||
|
||||
expect(shown).toBe(true);
|
||||
expect(writeToStdout).toHaveBeenCalledTimes(1);
|
||||
const emitted = String(writeToStdout.mock.calls[0][0]);
|
||||
expect(emitted.startsWith('\x1b]9;')).toBe(true);
|
||||
expect(emitted.endsWith('\x07')).toBe(true);
|
||||
expect(emitted).toContain('Explicit OSC 9');
|
||||
});
|
||||
|
||||
it('emits OSC 777 notification when method is explicitly set to osc777', async () => {
|
||||
// Explicitly set terminal to something that would normally use BEL
|
||||
vi.stubEnv('WT_SESSION', '1');
|
||||
const shown = await notifyViaTerminal(
|
||||
true,
|
||||
{
|
||||
title: 'Explicit OSC 777',
|
||||
body: 'Body',
|
||||
},
|
||||
TerminalNotificationMethod.Osc777,
|
||||
);
|
||||
|
||||
expect(shown).toBe(true);
|
||||
expect(writeToStdout).toHaveBeenCalledTimes(1);
|
||||
const emitted = String(writeToStdout.mock.calls[0][0]);
|
||||
expect(emitted.startsWith('\x1b]777;notify;')).toBe(true);
|
||||
expect(emitted.endsWith('\x07')).toBe(true);
|
||||
expect(emitted).toContain('Explicit OSC 777');
|
||||
});
|
||||
|
||||
it('emits BEL notification when method is explicitly set to bell', async () => {
|
||||
// Explicitly set terminal to something that supports OSC 9
|
||||
vi.stubEnv('TERM_PROGRAM', 'iTerm.app');
|
||||
|
||||
const shown = await notifyViaTerminal(
|
||||
true,
|
||||
{
|
||||
title: 'Explicit BEL',
|
||||
body: 'Body',
|
||||
},
|
||||
TerminalNotificationMethod.Bell,
|
||||
);
|
||||
|
||||
expect(shown).toBe(true);
|
||||
expect(writeToStdout).toHaveBeenCalledTimes(1);
|
||||
expect(writeToStdout).toHaveBeenCalledWith('\x07');
|
||||
});
|
||||
|
||||
it('replaces semicolons with colons in OSC 777 to avoid breaking the sequence', async () => {
|
||||
const shown = await notifyViaTerminal(
|
||||
true,
|
||||
{
|
||||
title: 'Title; with; semicolons',
|
||||
subtitle: 'Sub;title',
|
||||
body: 'Body; with; semicolons',
|
||||
},
|
||||
TerminalNotificationMethod.Osc777,
|
||||
);
|
||||
|
||||
expect(shown).toBe(true);
|
||||
const emitted = String(writeToStdout.mock.calls[0][0]);
|
||||
|
||||
// Format: \x1b]777;notify;title;body\x07
|
||||
expect(emitted).toContain('Title: with: semicolons');
|
||||
expect(emitted).toContain('Sub:title');
|
||||
expect(emitted).toContain('Body: with: semicolons');
|
||||
expect(emitted).not.toContain('Title; with; semicolons');
|
||||
expect(emitted).not.toContain('Body; with; semicolons');
|
||||
|
||||
// Extract everything after '\x1b]777;notify;' and before '\x07'
|
||||
const payload = emitted.slice('\x1b]777;notify;'.length, -1);
|
||||
|
||||
// There should be exactly one semicolon separating title and body
|
||||
const semicolonsCount = (payload.match(/;/g) || []).length;
|
||||
expect(semicolonsCount).toBe(1);
|
||||
});
|
||||
|
||||
it('wraps OSC sequence in tmux passthrough when TMUX env var is set', async () => {
|
||||
vi.stubEnv('TMUX', '1');
|
||||
vi.stubEnv('TERM_PROGRAM', 'iTerm.app');
|
||||
|
||||
const shown = await notifyViaTerminal(true, {
|
||||
title: 'Title',
|
||||
body: 'Body',
|
||||
});
|
||||
|
||||
expect(shown).toBe(true);
|
||||
expect(writeToStdout).toHaveBeenCalledTimes(1);
|
||||
const emitted = String(writeToStdout.mock.calls[0][0]);
|
||||
expect(emitted.startsWith('\x1bPtmux;\x1b\x1b]9;')).toBe(true);
|
||||
expect(emitted.endsWith('\x1b\\')).toBe(true);
|
||||
});
|
||||
|
||||
it('wraps OSC sequence in GNU screen passthrough when STY env var is set', async () => {
|
||||
vi.stubEnv('STY', '1');
|
||||
vi.stubEnv('TERM_PROGRAM', 'iTerm.app');
|
||||
|
||||
const shown = await notifyViaTerminal(true, {
|
||||
title: 'Title',
|
||||
body: 'Body',
|
||||
});
|
||||
|
||||
expect(shown).toBe(true);
|
||||
expect(writeToStdout).toHaveBeenCalledTimes(1);
|
||||
const emitted = String(writeToStdout.mock.calls[0][0]);
|
||||
expect(emitted.startsWith('\x1bP\x1b]9;')).toBe(true);
|
||||
expect(emitted.endsWith('\x1b\\')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,12 +15,8 @@ export const MAX_NOTIFICATION_BODY_CHARS = 180;
|
||||
|
||||
const BEL = '\x07';
|
||||
const OSC9_PREFIX = '\x1b]9;';
|
||||
const OSC9_SEPARATOR = ' | ';
|
||||
const MAX_OSC9_MESSAGE_CHARS =
|
||||
MAX_NOTIFICATION_TITLE_CHARS +
|
||||
MAX_NOTIFICATION_SUBTITLE_CHARS +
|
||||
MAX_NOTIFICATION_BODY_CHARS +
|
||||
OSC9_SEPARATOR.length * 2;
|
||||
const OSC777_PREFIX = '\x1b]777;notify;';
|
||||
const OSC_TEXT_SEPARATOR = ' | ';
|
||||
|
||||
export interface RunEventNotificationContent {
|
||||
title: string;
|
||||
@@ -81,36 +77,100 @@ export function isNotificationsEnabled(settings: LoadedSettings): boolean {
|
||||
return general?.enableNotifications === true;
|
||||
}
|
||||
|
||||
function buildTerminalNotificationMessage(
|
||||
content: RunEventNotificationContent,
|
||||
): string {
|
||||
const pieces = [content.title, content.subtitle, content.body].filter(
|
||||
Boolean,
|
||||
);
|
||||
const combined = pieces.join(OSC9_SEPARATOR);
|
||||
return sanitizeForDisplay(combined, MAX_OSC9_MESSAGE_CHARS);
|
||||
export enum TerminalNotificationMethod {
|
||||
Auto = 'auto',
|
||||
Osc9 = 'osc9',
|
||||
Osc777 = 'osc777',
|
||||
Bell = 'bell',
|
||||
}
|
||||
|
||||
export function getNotificationMethod(
|
||||
settings: LoadedSettings,
|
||||
): TerminalNotificationMethod {
|
||||
switch (settings.merged.general?.notificationMethod) {
|
||||
case TerminalNotificationMethod.Osc9:
|
||||
return TerminalNotificationMethod.Osc9;
|
||||
case TerminalNotificationMethod.Osc777:
|
||||
return TerminalNotificationMethod.Osc777;
|
||||
case TerminalNotificationMethod.Bell:
|
||||
return TerminalNotificationMethod.Bell;
|
||||
default:
|
||||
return TerminalNotificationMethod.Auto;
|
||||
}
|
||||
}
|
||||
|
||||
function wrapWithPassthrough(sequence: string): string {
|
||||
const capabilityManager = TerminalCapabilityManager.getInstance();
|
||||
if (capabilityManager.isTmux()) {
|
||||
// eslint-disable-next-line no-control-regex
|
||||
return `\x1bPtmux;${sequence.replace(/\x1b/g, '\x1b\x1b')}\x1b\\`;
|
||||
} else if (capabilityManager.isScreen()) {
|
||||
return `\x1bP${sequence}\x1b\\`;
|
||||
}
|
||||
return sequence;
|
||||
}
|
||||
|
||||
function emitOsc9Notification(content: RunEventNotificationContent): void {
|
||||
const message = buildTerminalNotificationMessage(content);
|
||||
if (!TerminalCapabilityManager.getInstance().supportsOsc9Notifications()) {
|
||||
writeToStdout(BEL);
|
||||
return;
|
||||
}
|
||||
const sanitized = sanitizeNotificationContent(content);
|
||||
const pieces = [sanitized.title, sanitized.subtitle, sanitized.body].filter(
|
||||
Boolean,
|
||||
);
|
||||
const combined = pieces.join(OSC_TEXT_SEPARATOR);
|
||||
|
||||
writeToStdout(`${OSC9_PREFIX}${message}${BEL}`);
|
||||
writeToStdout(wrapWithPassthrough(`${OSC9_PREFIX}${combined}${BEL}`));
|
||||
}
|
||||
|
||||
function emitOsc777Notification(content: RunEventNotificationContent): void {
|
||||
const sanitized = sanitizeNotificationContent(content);
|
||||
const bodyParts = [sanitized.subtitle, sanitized.body].filter(Boolean);
|
||||
const body = bodyParts.join(OSC_TEXT_SEPARATOR);
|
||||
|
||||
// Replace ';' with ':' to avoid breaking the OSC 777 sequence
|
||||
const safeTitle = sanitized.title.replace(/;/g, ':');
|
||||
const safeBody = body.replace(/;/g, ':');
|
||||
|
||||
writeToStdout(
|
||||
wrapWithPassthrough(`${OSC777_PREFIX}${safeTitle};${safeBody}${BEL}`),
|
||||
);
|
||||
}
|
||||
|
||||
function emitBellNotification(): void {
|
||||
writeToStdout(BEL);
|
||||
}
|
||||
|
||||
export async function notifyViaTerminal(
|
||||
notificationsEnabled: boolean,
|
||||
content: RunEventNotificationContent,
|
||||
method: TerminalNotificationMethod = TerminalNotificationMethod.Auto,
|
||||
): Promise<boolean> {
|
||||
if (!notificationsEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
emitOsc9Notification(sanitizeNotificationContent(content));
|
||||
if (method === TerminalNotificationMethod.Osc9) {
|
||||
emitOsc9Notification(content);
|
||||
} else if (method === TerminalNotificationMethod.Osc777) {
|
||||
emitOsc777Notification(content);
|
||||
} else if (method === TerminalNotificationMethod.Bell) {
|
||||
emitBellNotification();
|
||||
} else {
|
||||
// auto
|
||||
const capabilityManager = TerminalCapabilityManager.getInstance();
|
||||
if (capabilityManager.isITerm2()) {
|
||||
emitOsc9Notification(content);
|
||||
} else if (
|
||||
capabilityManager.isAlacritty() ||
|
||||
capabilityManager.isAppleTerminal() ||
|
||||
capabilityManager.isVSCodeTerminal() ||
|
||||
capabilityManager.isWindowsTerminal()
|
||||
) {
|
||||
emitBellNotification();
|
||||
} else {
|
||||
emitOsc777Notification(content);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
debugLogger.debug('Failed to emit terminal notification:', error);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@google/gemini-cli-core",
|
||||
"version": "0.39.0-nightly.20260408.e77b22e63",
|
||||
"version": "0.40.0-nightly.20260414.g5b1f7375a",
|
||||
"description": "Gemini CLI Core",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
@@ -20,7 +20,8 @@
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
"dist",
|
||||
"vendor"
|
||||
],
|
||||
"dependencies": {
|
||||
"@a2a-js/sdk": "0.3.11",
|
||||
@@ -31,7 +32,6 @@
|
||||
"@google/genai": "1.30.0",
|
||||
"@grpc/grpc-js": "^1.14.3",
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@joshua.litt/get-ripgrep": "^0.0.3",
|
||||
"@modelcontextprotocol/sdk": "^1.23.0",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@opentelemetry/api-logs": "^0.211.0",
|
||||
@@ -59,6 +59,7 @@
|
||||
"diff": "^8.0.3",
|
||||
"dotenv": "^17.2.4",
|
||||
"dotenv-expand": "^12.0.3",
|
||||
"execa": "^9.6.1",
|
||||
"fast-levenshtein": "^2.0.6",
|
||||
"fdir": "^6.4.6",
|
||||
"fzf": "^0.5.2",
|
||||
|
||||
@@ -55,8 +55,9 @@ export const GeneralistAgent = (
|
||||
return {
|
||||
systemPrompt: getCoreSystemPrompt(
|
||||
context.config,
|
||||
/*useMemory=*/ undefined,
|
||||
/*userMemory=*/ undefined,
|
||||
/*interactiveOverride=*/ false,
|
||||
/*topicUpdateNarrationOverride=*/ false,
|
||||
),
|
||||
query: '${request}',
|
||||
};
|
||||
|
||||
@@ -82,6 +82,7 @@ import { CompleteTaskTool } from '../tools/complete-task.js';
|
||||
import {
|
||||
COMPLETE_TASK_TOOL_NAME,
|
||||
ACTIVATE_SKILL_TOOL_NAME,
|
||||
UPDATE_TOPIC_TOOL_NAME,
|
||||
} from '../tools/definitions/base-declarations.js';
|
||||
|
||||
/** A callback function to report on agent activity. */
|
||||
@@ -189,6 +190,10 @@ export class LocalAgentExecutor<TOutput extends z.ZodTypeAny> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tool.name === UPDATE_TOPIC_TOOL_NAME) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clone the tool, so it gets its own state and subagent messageBus
|
||||
const clonedTool = tool.clone(subagentMessageBus);
|
||||
agentToolRegistry.registerTool(clonedTool);
|
||||
|
||||