diff --git a/.github/DISCUSSION_TEMPLATE/feature-requests.yml b/.github/DISCUSSION_TEMPLATE/feature-requests.yml
index 183a3de934eccc8baa8428e822176e31d1d11782..e8a695063c34771ac6120b1e477b7494a17aa3c9 100644
--- a/.github/DISCUSSION_TEMPLATE/feature-requests.yml
+++ b/.github/DISCUSSION_TEMPLATE/feature-requests.yml
@@ -40,4 +40,4 @@ body:
attributes:
value: |
Learn more about how feature requests work in our
- [Feature Request Guidelines](https://github.com/zed-industries/zed/discussions/47963).
+ [Feature Request Guidelines](https://github.com/zed-industries/zed/discussions/51422).
diff --git a/.github/workflows/assign-reviewers.yml b/.github/workflows/assign-reviewers.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a77f1812d06330b4635fe173583f0f1ce93e4e17
--- /dev/null
+++ b/.github/workflows/assign-reviewers.yml
@@ -0,0 +1,81 @@
+# Assign Reviewers — Smart team assignment based on diff weight
+#
+# Triggers on PR open and ready_for_review events. Checks out the coordinator
+# repo (zed-industries/codeowner-coordinator) to access the assignment script and rules,
+# then assigns the 1-2 most relevant teams as reviewers.
+#
+# NOTE: This file is stored in the codeowner-coordinator repo but must be deployed to
+# the zed repo at .github/workflows/assign-reviewers.yml. See INSTALL.md.
+#
+# AUTH NOTE: Uses a GitHub App (COORDINATOR_APP_ID + COORDINATOR_APP_PRIVATE_KEY)
+# for all API operations: cloning the private coordinator repo, requesting team
+# reviewers, and setting PR assignees. GITHUB_TOKEN is not used.
+
+name: Assign Reviewers
+
+on:
+ pull_request:
+ types: [opened, ready_for_review]
+
+# GITHUB_TOKEN is not used — all operations use the GitHub App token.
+# Declare minimal permissions so the default token has no write access.
+permissions: {}
+
+# Only run for PRs from within the org (not forks) — fork PRs don't have
+# write access to request team reviewers.
+jobs:
+ assign-reviewers:
+ if: >-
+ github.event.pull_request.head.repo.full_name == github.repository &&
+ github.event.pull_request.draft == false &&
+ contains(fromJSON('["MEMBER", "OWNER"]'), github.event.pull_request.author_association)
+ runs-on: ubuntu-latest
+ steps:
+ - name: Generate app token
+ id: app-token
+ uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
+ with:
+ app-id: ${{ vars.COORDINATOR_APP_ID }}
+ private-key: ${{ secrets.COORDINATOR_APP_PRIVATE_KEY }}
+ repositories: codeowner-coordinator,zed
+
+ - name: Checkout coordinator repo
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
+ with:
+ repository: zed-industries/codeowner-coordinator
+ ref: main
+ path: codeowner-coordinator
+ token: ${{ steps.app-token.outputs.token }}
+ persist-credentials: false
+
+ - name: Setup Python
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
+ with:
+ python-version: "3.11"
+
+ - name: Install dependencies
+ run: pip install pyyaml==6.0.3
+
+ - name: Assign reviewers
+ env:
+ GH_TOKEN: ${{ steps.app-token.outputs.token }}
+ PR_URL: ${{ github.event.pull_request.html_url }}
+ TARGET_REPO: ${{ github.repository }}
+ run: |
+ cd codeowner-coordinator
+ python .github/scripts/assign-reviewers.py \
+ --pr "$PR_URL" \
+ --apply \
+ --rules-file team-membership-rules.yml \
+ --repo "$TARGET_REPO" \
+ --org zed-industries \
+ --min-association member \
+ 2>&1 | tee /tmp/assign-reviewers-output.txt
+
+ - name: Upload output
+ if: always()
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ with:
+ name: assign-reviewers-output
+ path: /tmp/assign-reviewers-output.txt
+ retention-days: 30
diff --git a/.github/workflows/bump_patch_version.yml b/.github/workflows/bump_patch_version.yml
index 480d8b0ada98e859d2e72b49a39805ffe8f72b25..62540321ed755f2fd3879a7ddfc3a37237d8e7de 100644
--- a/.github/workflows/bump_patch_version.yml
+++ b/.github/workflows/bump_patch_version.yml
@@ -23,8 +23,8 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
- token: ${{ steps.get-app-token.outputs.token }}
ref: ${{ inputs.branch }}
+ token: ${{ steps.get-app-token.outputs.token }}
- name: bump_patch_version::run_bump_patch_version::bump_patch_version
run: |
channel="$(cat crates/zed/RELEASE_CHANNEL)"
diff --git a/.github/workflows/deploy_collab.yml b/.github/workflows/deploy_collab.yml
index 89fb6980b65f2d09a6571f140ab016a710be230f..0d98438c9e3029f85cc37cb4e57f6c9e24df43b0 100644
--- a/.github/workflows/deploy_collab.yml
+++ b/.github/workflows/deploy_collab.yml
@@ -12,6 +12,9 @@ jobs:
if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions')
name: Check formatting and Clippy lints
runs-on: namespace-profile-16x32-ubuntu-2204
+ env:
+ CC: clang
+ CXX: clang++
steps:
- name: steps::checkout_repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
@@ -42,6 +45,9 @@ jobs:
- style
name: Run tests
runs-on: namespace-profile-16x32-ubuntu-2204
+ env:
+ CC: clang
+ CXX: clang++
steps:
- name: steps::checkout_repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
diff --git a/.github/workflows/extension_auto_bump.yml b/.github/workflows/extension_auto_bump.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f5203800958c51ee0c6bc0f0ee0fb76da826def5
--- /dev/null
+++ b/.github/workflows/extension_auto_bump.yml
@@ -0,0 +1,72 @@
+# Generated from xtask::workflows::extension_auto_bump
+# Rebuild with `cargo xtask workflows`.
+name: extension_auto_bump
+on:
+ push:
+ branches:
+ - main
+ paths:
+ - extensions/**
+ - '!extensions/workflows/**'
+ - '!extensions/*.md'
+jobs:
+ detect_changed_extensions:
+ if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions')
+ runs-on: namespace-profile-2x4-ubuntu-2404
+ steps:
+ - name: steps::checkout_repo
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ with:
+ clean: false
+ fetch-depth: 2
+ - id: detect
+ name: extension_auto_bump::detect_changed_extensions
+ run: |
+ COMPARE_REV="$(git rev-parse HEAD~1)"
+ CHANGED_FILES="$(git diff --name-only "$COMPARE_REV" "$GITHUB_SHA")"
+ # Detect changed extension directories (excluding extensions/workflows)
+ CHANGED_EXTENSIONS=$(echo "$CHANGED_FILES" | grep -oP '^extensions/[^/]+(?=/)' | sort -u | grep -v '^extensions/workflows$' || true)
+ if [ -n "$CHANGED_EXTENSIONS" ]; then
+ EXTENSIONS_JSON=$(echo "$CHANGED_EXTENSIONS" | jq -R -s -c 'split("\n") | map(select(length > 0))')
+ else
+ EXTENSIONS_JSON="[]"
+ fi
+ # Filter out newly added or entirely removed extensions
+ FILTERED="[]"
+ for ext in $(echo "$EXTENSIONS_JSON" | jq -r '.[]'); do
+ if git show HEAD~1:"$ext/extension.toml" >/dev/null 2>&1 && \
+ [ -f "$ext/extension.toml" ]; then
+ FILTERED=$(echo "$FILTERED" | jq -c --arg e "$ext" '. + [$e]')
+ fi
+ done
+ echo "changed_extensions=$FILTERED" >> "$GITHUB_OUTPUT"
+ outputs:
+ changed_extensions: ${{ steps.detect.outputs.changed_extensions }}
+ timeout-minutes: 5
+ bump_extension_versions:
+ needs:
+ - detect_changed_extensions
+ if: needs.detect_changed_extensions.outputs.changed_extensions != '[]'
+ permissions:
+ actions: write
+ contents: write
+ issues: write
+ pull-requests: write
+ strategy:
+ matrix:
+ extension: ${{ fromJson(needs.detect_changed_extensions.outputs.changed_extensions) }}
+ fail-fast: false
+ max-parallel: 1
+ uses: ./.github/workflows/extension_bump.yml
+ secrets:
+ app-id: ${{ secrets.ZED_ZIPPY_APP_ID }}
+ app-secret: ${{ secrets.ZED_ZIPPY_APP_PRIVATE_KEY }}
+ with:
+ working-directory: ${{ matrix.extension }}
+ force-bump: false
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
+ cancel-in-progress: true
+defaults:
+ run:
+ shell: bash -euxo pipefail {0}
diff --git a/.github/workflows/extension_bump.yml b/.github/workflows/extension_bump.yml
index 9cc53741e8007a1b3ddd02ad07b191b3ce171cc8..31f34c9299cee8b464162d501aecaa2bb70035d6 100644
--- a/.github/workflows/extension_bump.yml
+++ b/.github/workflows/extension_bump.yml
@@ -17,6 +17,10 @@ on:
description: force-bump
required: true
type: boolean
+ working-directory:
+ description: working-directory
+ type: string
+ default: .
secrets:
app-id:
description: The app ID used to create the PR
@@ -42,8 +46,6 @@ jobs:
if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
PR_FORK_POINT="$(git merge-base origin/main HEAD)"
git checkout "$PR_FORK_POINT"
- elif BRANCH_PARENT_SHA="$(git merge-base origin/main origin/zed-zippy-autobump)"; then
- git checkout "$BRANCH_PARENT_SHA"
else
git checkout "$(git log -1 --format=%H)"~1
fi
@@ -59,6 +61,10 @@ jobs:
version_changed: ${{ steps.compare-versions-check.outputs.version_changed }}
current_version: ${{ steps.compare-versions-check.outputs.current_version }}
timeout-minutes: 1
+ defaults:
+ run:
+ shell: bash -euxo pipefail {0}
+ working-directory: ${{ inputs.working-directory }}
bump_extension_version:
needs:
- check_version_changed
@@ -98,18 +104,35 @@ jobs:
fi
NEW_VERSION="$(sed -n 's/^version = \"\(.*\)\"/\1/p' < extension.toml | tr -d '[:space:]')"
+ EXTENSION_ID="$(sed -n 's/^id = "\(.*\)"/\1/p' < extension.toml | head -1 | tr -d '[:space:]')"
+ EXTENSION_NAME="$(sed -n 's/^name = "\(.*\)"/\1/p' < extension.toml | head -1 | tr -d '[:space:]')"
+
+ if [[ "$WORKING_DIR" == "." || -z "$WORKING_DIR" ]]; then
+ {
+ echo "title=Bump version to ${NEW_VERSION}";
+ echo "body=This PR bumps the version of this extension to v${NEW_VERSION}";
+ echo "branch_name=zed-zippy-autobump";
+ } >> "$GITHUB_OUTPUT"
+ else
+ {
+ echo "title=${EXTENSION_ID}: Bump to v${NEW_VERSION}";
+ echo "body=This PR bumps the version of the ${EXTENSION_NAME} extension to v${NEW_VERSION}";
+ echo "branch_name=zed-zippy-${EXTENSION_ID}-autobump";
+ } >> "$GITHUB_OUTPUT"
+ fi
echo "new_version=${NEW_VERSION}" >> "$GITHUB_OUTPUT"
env:
OLD_VERSION: ${{ needs.check_version_changed.outputs.current_version }}
BUMP_TYPE: ${{ inputs.bump-type }}
+ WORKING_DIR: ${{ inputs.working-directory }}
- name: extension_bump::create_pull_request
uses: peter-evans/create-pull-request@v7
with:
- title: Bump version to ${{ steps.bump-version.outputs.new_version }}
- body: This PR bumps the version of this extension to v${{ steps.bump-version.outputs.new_version }}
- commit-message: Bump version to v${{ steps.bump-version.outputs.new_version }}
- branch: zed-zippy-autobump
+ title: ${{ steps.bump-version.outputs.title }}
+ body: ${{ steps.bump-version.outputs.body }}
+ commit-message: ${{ steps.bump-version.outputs.title }}
+ branch: ${{ steps.bump-version.outputs.branch_name }}
committer: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
base: main
delete-branch: true
@@ -117,6 +140,10 @@ jobs:
sign-commits: true
assignees: ${{ github.actor }}
timeout-minutes: 3
+ defaults:
+ run:
+ shell: bash -euxo pipefail {0}
+ working-directory: ${{ inputs.working-directory }}
create_version_label:
needs:
- check_version_changed
@@ -145,6 +172,10 @@ jobs:
})
github-token: ${{ steps.generate-token.outputs.token }}
timeout-minutes: 1
+ defaults:
+ run:
+ shell: bash -euxo pipefail {0}
+ working-directory: ${{ inputs.working-directory }}
trigger_release:
needs:
- check_version_changed
@@ -178,8 +209,12 @@ jobs:
tag: v${{ needs.check_version_changed.outputs.current_version }}
env:
COMMITTER_TOKEN: ${{ steps.generate-token.outputs.token }}
+ defaults:
+ run:
+ shell: bash -euxo pipefail {0}
+ working-directory: ${{ inputs.working-directory }}
concurrency:
- group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
+ group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}extension-bump
cancel-in-progress: true
defaults:
run:
diff --git a/.github/workflows/extension_tests.yml b/.github/workflows/extension_tests.yml
index 53de373c1b79dc3ca9a3637642e10998c781580a..89668c028a6d1fa4baddd417687226dd55a52426 100644
--- a/.github/workflows/extension_tests.yml
+++ b/.github/workflows/extension_tests.yml
@@ -9,7 +9,12 @@ env:
RUSTUP_TOOLCHAIN: stable
CARGO_BUILD_TARGET: wasm32-wasip2
on:
- workflow_call: {}
+ workflow_call:
+ inputs:
+ working-directory:
+ description: working-directory
+ type: string
+ default: .
jobs:
orchestrate:
if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions')
@@ -34,6 +39,14 @@ jobs:
fi
CHANGED_FILES="$(git diff --name-only "$COMPARE_REV" "$GITHUB_SHA")"
+ # When running from a subdirectory, git diff returns repo-root-relative paths.
+ # Filter to only files within the current working directory and strip the prefix.
+ REPO_SUBDIR="$(git rev-parse --show-prefix)"
+ REPO_SUBDIR="${REPO_SUBDIR%/}"
+ if [ -n "$REPO_SUBDIR" ]; then
+ CHANGED_FILES="$(echo "$CHANGED_FILES" | grep "^${REPO_SUBDIR}/" | sed "s|^${REPO_SUBDIR}/||" || true)"
+ fi
+
check_pattern() {
local output_name="$1"
local pattern="$2"
@@ -49,6 +62,10 @@ jobs:
outputs:
check_rust: ${{ steps.filter.outputs.check_rust }}
check_extension: ${{ steps.filter.outputs.check_extension }}
+ defaults:
+ run:
+ shell: bash -euxo pipefail {0}
+ working-directory: ${{ inputs.working-directory }}
check_rust:
needs:
- orchestrate
@@ -66,17 +83,31 @@ jobs:
path: ~/.rustup
- name: extension_tests::install_rust_target
run: rustup target add wasm32-wasip2
- - name: steps::cargo_fmt
- run: cargo fmt --all -- --check
+ - id: get-package-name
+ name: extension_tests::get_package_name
+ run: |
+ PACKAGE_NAME="$(sed -n 's/^name = "\(.*\)"/\1/p' < Cargo.toml | head -1 | tr -d '[:space:]')"
+ echo "package_name=${PACKAGE_NAME}" >> "$GITHUB_OUTPUT"
+ - name: extension_tests::cargo_fmt_package
+ run: cargo fmt -p "$PACKAGE_NAME" -- --check
+ env:
+ PACKAGE_NAME: ${{ steps.get-package-name.outputs.package_name }}
- name: extension_tests::run_clippy
- run: cargo clippy --release --all-features -- --deny warnings
+ run: cargo clippy -p "$PACKAGE_NAME" --release --all-features -- --deny warnings
+ env:
+ PACKAGE_NAME: ${{ steps.get-package-name.outputs.package_name }}
- name: steps::cargo_install_nextest
uses: taiki-e/install-action@nextest
- - name: steps::cargo_nextest
- run: 'cargo nextest run --workspace --no-fail-fast --no-tests=warn --target "$(rustc -vV | sed -n ''s|host: ||p'')"'
+ - name: extension_tests::run_nextest
+ run: 'cargo nextest run -p "$PACKAGE_NAME" --no-fail-fast --no-tests=warn --target "$(rustc -vV | sed -n ''s|host: ||p'')"'
env:
+ PACKAGE_NAME: ${{ steps.get-package-name.outputs.package_name }}
NEXTEST_NO_TESTS: warn
timeout-minutes: 6
+ defaults:
+ run:
+ shell: bash -euxo pipefail {0}
+ working-directory: ${{ inputs.working-directory }}
check_extension:
needs:
- orchestrate
@@ -97,8 +128,8 @@ jobs:
- name: extension_tests::download_zed_extension_cli
if: steps.cache-zed-extension-cli.outputs.cache-hit != 'true'
run: |
- wget --quiet "https://zed-extension-cli.nyc3.digitaloceanspaces.com/$ZED_EXTENSION_CLI_SHA/x86_64-unknown-linux-gnu/zed-extension"
- chmod +x zed-extension
+ wget --quiet "https://zed-extension-cli.nyc3.digitaloceanspaces.com/$ZED_EXTENSION_CLI_SHA/x86_64-unknown-linux-gnu/zed-extension" -O "$GITHUB_WORKSPACE/zed-extension"
+ chmod +x "$GITHUB_WORKSPACE/zed-extension"
- name: steps::cache_rust_dependencies_namespace
uses: namespacelabs/nscloud-cache-action@v1
with:
@@ -108,7 +139,7 @@ jobs:
run: |
mkdir -p /tmp/ext-scratch
mkdir -p /tmp/ext-output
- ./zed-extension --source-dir . --scratch-dir /tmp/ext-scratch --output-dir /tmp/ext-output
+ "$GITHUB_WORKSPACE/zed-extension" --source-dir . --scratch-dir /tmp/ext-scratch --output-dir /tmp/ext-output
- name: run_tests::fetch_ts_query_ls
uses: dsaltares/fetch-gh-release-asset@aa37ae5c44d3c9820bc12fe675e8670ecd93bd1c
with:
@@ -117,8 +148,8 @@ jobs:
file: ts_query_ls-x86_64-unknown-linux-gnu.tar.gz
- name: run_tests::run_ts_query_ls
run: |-
- tar -xf ts_query_ls-x86_64-unknown-linux-gnu.tar.gz
- ./ts_query_ls format --check . || {
+ tar -xf "$GITHUB_WORKSPACE/ts_query_ls-x86_64-unknown-linux-gnu.tar.gz" -C "$GITHUB_WORKSPACE"
+ "$GITHUB_WORKSPACE/ts_query_ls" format --check . || {
echo "Found unformatted queries, please format them with ts_query_ls."
echo "For easy use, install the Tree-sitter query extension:"
echo "zed://extension/tree-sitter-query"
@@ -132,8 +163,6 @@ jobs:
if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
PR_FORK_POINT="$(git merge-base origin/main HEAD)"
git checkout "$PR_FORK_POINT"
- elif BRANCH_PARENT_SHA="$(git merge-base origin/main origin/zed-zippy-autobump)"; then
- git checkout "$BRANCH_PARENT_SHA"
else
git checkout "$(git log -1 --format=%H)"~1
fi
@@ -156,6 +185,10 @@ jobs:
VERSION_CHANGED: ${{ steps.compare-versions-check.outputs.version_changed }}
PR_USER_LOGIN: ${{ github.event.pull_request.user.login }}
timeout-minutes: 6
+ defaults:
+ run:
+ shell: bash -euxo pipefail {0}
+ working-directory: ${{ inputs.working-directory }}
tests_pass:
needs:
- orchestrate
@@ -184,7 +217,7 @@ jobs:
RESULT_CHECK_RUST: ${{ needs.check_rust.result }}
RESULT_CHECK_EXTENSION: ${{ needs.check_extension.result }}
concurrency:
- group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
+ group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}extension-tests
cancel-in-progress: true
defaults:
run:
diff --git a/.github/workflows/extension_workflow_rollout.yml b/.github/workflows/extension_workflow_rollout.yml
index 9bfac06d4527985553ba3d04e64c656ee5bf85e4..f695b43ecac47a221bbc795d03e6ddd6259d7014 100644
--- a/.github/workflows/extension_workflow_rollout.yml
+++ b/.github/workflows/extension_workflow_rollout.yml
@@ -4,12 +4,57 @@ name: extension_workflow_rollout
env:
CARGO_TERM_COLOR: always
on:
- workflow_dispatch: {}
+ workflow_dispatch:
+ inputs:
+ filter-repos:
+ description: Comma-separated list of repository names to rollout to. Leave empty for all repos.
+ type: string
+ default: ''
+ change-description:
+ description: Description for the changes to be expected with this rollout
+ type: string
+ default: ''
jobs:
fetch_extension_repos:
if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') && github.ref == 'refs/heads/main'
runs-on: namespace-profile-2x4-ubuntu-2404
steps:
+ - name: checkout_zed_repo
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ with:
+ clean: false
+ fetch-depth: 0
+ - id: prev-tag
+ name: extension_workflow_rollout::fetch_extension_repos::get_previous_tag_commit
+ run: |
+ PREV_COMMIT=$(git rev-parse "extension-workflows^{commit}" 2>/dev/null || echo "")
+ if [ -z "$PREV_COMMIT" ]; then
+ echo "::error::No previous rollout tag 'extension-workflows' found. Cannot determine file changes."
+ exit 1
+ fi
+ echo "Found previous rollout at commit: $PREV_COMMIT"
+ echo "prev_commit=$PREV_COMMIT" >> "$GITHUB_OUTPUT"
+ - id: calc-changes
+ name: extension_workflow_rollout::fetch_extension_repos::get_removed_files
+ run: |
+ for workflow_type in "ci" "shared"; do
+ if [ "$workflow_type" = "ci" ]; then
+ WORKFLOW_DIR="extensions/workflows"
+ else
+ WORKFLOW_DIR="extensions/workflows/shared"
+ fi
+
+ REMOVED=$(git diff --name-status -M "$PREV_COMMIT" HEAD -- "$WORKFLOW_DIR" | \
+ awk '/^D/ { print $2 } /^R/ { print $2 }' | \
+ xargs -I{} basename {} 2>/dev/null | \
+ tr '\n' ' ' || echo "")
+ REMOVED=$(echo "$REMOVED" | xargs)
+
+ echo "Removed files for $workflow_type: $REMOVED"
+ echo "removed_${workflow_type}=$REMOVED" >> "$GITHUB_OUTPUT"
+ done
+ env:
+ PREV_COMMIT: ${{ steps.prev-tag.outputs.prev_commit }}
- id: list-repos
name: extension_workflow_rollout::fetch_extension_repos::get_repositories
uses: actions/github-script@v7
@@ -21,16 +66,42 @@ jobs:
per_page: 100,
});
- const filteredRepos = repos
+ let filteredRepos = repos
.filter(repo => !repo.archived)
.map(repo => repo.name);
+ const filterInput = `${{ inputs.filter-repos }}`.trim();
+ if (filterInput.length > 0) {
+ const allowedNames = filterInput.split(',').map(s => s.trim()).filter(s => s.length > 0);
+ filteredRepos = filteredRepos.filter(name => allowedNames.includes(name));
+ console.log(`Filter applied. Matched ${filteredRepos.length} repos from ${allowedNames.length} requested.`);
+ }
+
console.log(`Found ${filteredRepos.length} extension repos`);
return filteredRepos;
result-encoding: json
+ - name: steps::cache_rust_dependencies_namespace
+ uses: namespacelabs/nscloud-cache-action@v1
+ with:
+ cache: rust
+ path: ~/.rustup
+ - name: extension_workflow_rollout::fetch_extension_repos::generate_workflow_files
+ run: |
+ cargo xtask workflows "$COMMIT_SHA"
+ env:
+ COMMIT_SHA: ${{ github.sha }}
+ - name: extension_workflow_rollout::fetch_extension_repos::upload_workflow_files
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
+ with:
+ name: extension-workflow-files
+ path: extensions/workflows/**/*.yml
+ if-no-files-found: error
outputs:
repos: ${{ steps.list-repos.outputs.result }}
- timeout-minutes: 5
+ prev_commit: ${{ steps.prev-tag.outputs.prev_commit }}
+ removed_ci: ${{ steps.calc-changes.outputs.removed_ci }}
+ removed_shared: ${{ steps.calc-changes.outputs.removed_shared }}
+ timeout-minutes: 10
rollout_workflows_to_extension:
needs:
- fetch_extension_repos
@@ -53,59 +124,28 @@ jobs:
permission-pull-requests: write
permission-contents: write
permission-workflows: write
- - name: checkout_zed_repo
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- with:
- clean: false
- fetch-depth: 0
- path: zed
- name: checkout_extension_repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
- token: ${{ steps.generate-token.outputs.token }}
path: extension
repository: zed-extensions/${{ matrix.repo }}
- - id: prev-tag
- name: extension_workflow_rollout::rollout_workflows_to_extension::get_previous_tag_commit
- run: |
- PREV_COMMIT=$(git rev-parse "extension-workflows^{commit}" 2>/dev/null || echo "")
- if [ -z "$PREV_COMMIT" ]; then
- echo "::error::No previous rollout tag 'extension-workflows' found. Cannot determine file changes."
- exit 1
- fi
- echo "Found previous rollout at commit: $PREV_COMMIT"
- echo "prev_commit=$PREV_COMMIT" >> "$GITHUB_OUTPUT"
- working-directory: zed
- - id: calc-changes
- name: extension_workflow_rollout::rollout_workflows_to_extension::get_removed_files
+ token: ${{ steps.generate-token.outputs.token }}
+ - name: extension_workflow_rollout::rollout_workflows_to_extension::download_workflow_files
+ uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
+ with:
+ name: extension-workflow-files
+ path: workflow-files
+ - name: extension_workflow_rollout::rollout_workflows_to_extension::sync_workflow_files
run: |
+ mkdir -p extension/.github/workflows
+
if [ "$MATRIX_REPO" = "workflows" ]; then
- WORKFLOW_DIR="extensions/workflows"
+ REMOVED_FILES="$REMOVED_CI"
else
- WORKFLOW_DIR="extensions/workflows/shared"
+ REMOVED_FILES="$REMOVED_SHARED"
fi
- echo "Calculating changes from $PREV_COMMIT to HEAD for $WORKFLOW_DIR"
-
- # Get deleted files (status D) and renamed files (status R - old name needs removal)
- # Using -M to detect renames, then extracting files that are gone from their original location
- REMOVED_FILES=$(git diff --name-status -M "$PREV_COMMIT" HEAD -- "$WORKFLOW_DIR" | \
- awk '/^D/ { print $2 } /^R/ { print $2 }' | \
- xargs -I{} basename {} 2>/dev/null | \
- tr '\n' ' ' || echo "")
-
- REMOVED_FILES=$(echo "$REMOVED_FILES" | xargs)
-
- echo "Files to remove: $REMOVED_FILES"
- echo "removed_files=$REMOVED_FILES" >> "$GITHUB_OUTPUT"
- env:
- PREV_COMMIT: ${{ steps.prev-tag.outputs.prev_commit }}
- MATRIX_REPO: ${{ matrix.repo }}
- working-directory: zed
- - name: extension_workflow_rollout::rollout_workflows_to_extension::sync_workflow_files
- run: |
- mkdir -p extension/.github/workflows
cd extension/.github/workflows
if [ -n "$REMOVED_FILES" ]; then
@@ -119,18 +159,18 @@ jobs:
cd - > /dev/null
if [ "$MATRIX_REPO" = "workflows" ]; then
- cp zed/extensions/workflows/*.yml extension/.github/workflows/
+ cp workflow-files/*.yml extension/.github/workflows/
else
- cp zed/extensions/workflows/shared/*.yml extension/.github/workflows/
+ cp workflow-files/shared/*.yml extension/.github/workflows/
fi
env:
- REMOVED_FILES: ${{ steps.calc-changes.outputs.removed_files }}
+ REMOVED_CI: ${{ needs.fetch_extension_repos.outputs.removed_ci }}
+ REMOVED_SHARED: ${{ needs.fetch_extension_repos.outputs.removed_shared }}
MATRIX_REPO: ${{ matrix.repo }}
- id: short-sha
name: extension_workflow_rollout::rollout_workflows_to_extension::get_short_sha
run: |
- echo "sha_short=$(git rev-parse --short=7 HEAD)" >> "$GITHUB_OUTPUT"
- working-directory: zed
+ echo "sha_short=$(echo "$GITHUB_SHA" | cut -c1-7)" >> "$GITHUB_OUTPUT"
- id: create-pr
name: extension_workflow_rollout::rollout_workflows_to_extension::create_pull_request
uses: peter-evans/create-pull-request@v7
@@ -140,6 +180,8 @@ jobs:
body: |
This PR updates the CI workflow files from the main Zed repository
based on the commit zed-industries/zed@${{ github.sha }}
+
+ ${{ inputs.change-description }}
commit-message: Update CI workflows to `${{ steps.short-sha.outputs.sha_short }}`
branch: update-workflows
committer: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
@@ -151,16 +193,17 @@ jobs:
- name: extension_workflow_rollout::rollout_workflows_to_extension::enable_auto_merge
run: |
if [ -n "$PR_NUMBER" ]; then
- cd extension
gh pr merge "$PR_NUMBER" --auto --squash
fi
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
PR_NUMBER: ${{ steps.create-pr.outputs.pull-request-number }}
+ working-directory: extension
timeout-minutes: 10
create_rollout_tag:
needs:
- rollout_workflows_to_extension
+ if: inputs.filter-repos == ''
runs-on: namespace-profile-2x4-ubuntu-2404
steps:
- id: generate-token
diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml
index 00d69639a53868386157e67aeab5ce7383d32426..fed05e00459b3c688c4244ddb9ea29ec1dbfd564 100644
--- a/.github/workflows/run_tests.yml
+++ b/.github/workflows/run_tests.yml
@@ -103,13 +103,22 @@ jobs:
check_pattern "run_action_checks" '^\.github/(workflows/|actions/|actionlint.yml)|tooling/xtask|script/' -qP
check_pattern "run_docs" '^(docs/|crates/.*\.rs)' -qP
check_pattern "run_licenses" '^(Cargo.lock|script/.*licenses)' -qP
- check_pattern "run_tests" '^(docs/|script/update_top_ranking_issues/|\.github/(ISSUE_TEMPLATE|workflows/(?!run_tests)))' -qvP
+ check_pattern "run_tests" '^(docs/|script/update_top_ranking_issues/|\.github/(ISSUE_TEMPLATE|workflows/(?!run_tests))|extensions/)' -qvP
+ # Detect changed extension directories (excluding extensions/workflows)
+ CHANGED_EXTENSIONS=$(echo "$CHANGED_FILES" | grep -oP '^extensions/[^/]+(?=/)' | sort -u | grep -v '^extensions/workflows$' || true)
+ if [ -n "$CHANGED_EXTENSIONS" ]; then
+ EXTENSIONS_JSON=$(echo "$CHANGED_EXTENSIONS" | jq -R -s -c 'split("\n") | map(select(length > 0))')
+ else
+ EXTENSIONS_JSON="[]"
+ fi
+ echo "changed_extensions=$EXTENSIONS_JSON" >> "$GITHUB_OUTPUT"
outputs:
changed_packages: ${{ steps.filter.outputs.changed_packages }}
run_action_checks: ${{ steps.filter.outputs.run_action_checks }}
run_docs: ${{ steps.filter.outputs.run_docs }}
run_licenses: ${{ steps.filter.outputs.run_licenses }}
run_tests: ${{ steps.filter.outputs.run_tests }}
+ changed_extensions: ${{ steps.filter.outputs.changed_extensions }}
check_style:
if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions')
runs-on: namespace-profile-4x8-ubuntu-2204
@@ -147,8 +156,8 @@ jobs:
file: ts_query_ls-x86_64-unknown-linux-gnu.tar.gz
- name: run_tests::run_ts_query_ls
run: |-
- tar -xf ts_query_ls-x86_64-unknown-linux-gnu.tar.gz
- ./ts_query_ls format --check . || {
+ tar -xf "$GITHUB_WORKSPACE/ts_query_ls-x86_64-unknown-linux-gnu.tar.gz" -C "$GITHUB_WORKSPACE"
+ "$GITHUB_WORKSPACE/ts_query_ls" format --check . || {
echo "Found unformatted queries, please format them with ts_query_ls."
echo "For easy use, install the Tree-sitter query extension:"
echo "zed://extension/tree-sitter-query"
@@ -711,6 +720,20 @@ jobs:
- name: run_tests::check_postgres_and_protobuf_migrations::check_protobuf_formatting
run: buf format --diff --exit-code crates/proto/proto
timeout-minutes: 60
+ extension_tests:
+ needs:
+ - orchestrate
+ if: needs.orchestrate.outputs.changed_extensions != '[]'
+ permissions:
+ contents: read
+ strategy:
+ matrix:
+ extension: ${{ fromJson(needs.orchestrate.outputs.changed_extensions) }}
+ fail-fast: false
+ max-parallel: 1
+ uses: ./.github/workflows/extension_tests.yml
+ with:
+ working-directory: ${{ matrix.extension }}
tests_pass:
needs:
- orchestrate
@@ -728,6 +751,7 @@ jobs:
- check_docs
- check_licenses
- check_scripts
+ - extension_tests
if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') && always()
runs-on: namespace-profile-2x4-ubuntu-2404
steps:
@@ -756,6 +780,7 @@ jobs:
check_result "check_docs" "$RESULT_CHECK_DOCS"
check_result "check_licenses" "$RESULT_CHECK_LICENSES"
check_result "check_scripts" "$RESULT_CHECK_SCRIPTS"
+ check_result "extension_tests" "$RESULT_EXTENSION_TESTS"
exit $EXIT_CODE
env:
@@ -774,6 +799,7 @@ jobs:
RESULT_CHECK_DOCS: ${{ needs.check_docs.result }}
RESULT_CHECK_LICENSES: ${{ needs.check_licenses.result }}
RESULT_CHECK_SCRIPTS: ${{ needs.check_scripts.result }}
+ RESULT_EXTENSION_TESTS: ${{ needs.extension_tests.result }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
cancel-in-progress: true
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 740b33dd55790bd3cabfc75146d71854eca6375d..e7e7629825b5f487a3b00af525d36458eb91956c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -26,6 +26,8 @@ If you're looking for concrete ideas:
- [Triaged bugs with confirmed steps to reproduce](https://github.com/zed-industries/zed/issues?q=is%3Aissue%20state%3Aopen%20type%3ABug%20label%3Astate%3Areproducible).
- [Area labels](https://github.com/zed-industries/zed/labels?q=area%3A*) to browse bugs in a specific part of the product you care about (after clicking on an area label, add type:Bug to the search).
+If you're thinking about proposing or building a larger feature, read the [Zed Feature Process](./docs/src/development/feature-process.md) for how we think about feature design — what context to provide, what integration points to consider, and how to put together a strong proposal.
+
## Sending changes
The Zed culture values working code and synchronous conversations over long
diff --git a/Cargo.lock b/Cargo.lock
index 4dbd905beb51bda4f5ff061179d144d9cd255e9a..65d7f7ccb5ae148e337257d52f71ac2cc4aeebc0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -36,7 +36,6 @@ dependencies = [
"smol",
"task",
"telemetry",
- "tempfile",
"terminal",
"text",
"ui",
@@ -45,7 +44,6 @@ dependencies = [
"util",
"uuid",
"watch",
- "zlog",
]
[[package]]
@@ -79,7 +77,6 @@ dependencies = [
"fs",
"futures 0.3.31",
"gpui",
- "indoc",
"language",
"log",
"pretty_assertions",
@@ -108,7 +105,6 @@ dependencies = [
"language",
"project",
"proto",
- "release_channel",
"smallvec",
"ui",
"util",
@@ -214,11 +210,9 @@ dependencies = [
"task",
"telemetry",
"tempfile",
- "terminal",
"text",
"theme",
"thiserror 2.0.17",
- "tree-sitter-rust",
"ui",
"unindent",
"url",
@@ -226,7 +220,6 @@ dependencies = [
"uuid",
"watch",
"web_search",
- "worktree",
"zed_env_vars",
"zlog",
"zstd",
@@ -234,9 +227,9 @@ dependencies = [
[[package]]
name = "agent-client-protocol"
-version = "0.9.4"
+version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2659b1089101b15db31137710159421cb44785ecdb5ba784be3b4a6f8cb8a475"
+checksum = "9c56a59cf6315e99f874d2c1f96c69d2da5ffe0087d211297fc4a41f849770a2"
dependencies = [
"agent-client-protocol-schema",
"anyhow",
@@ -251,16 +244,16 @@ dependencies = [
[[package]]
name = "agent-client-protocol-schema"
-version = "0.10.8"
+version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44bc1fef9c32f03bce2ab44af35b6f483bfd169bf55cc59beeb2e3b1a00ae4d1"
+checksum = "e0497b9a95a404e35799904835c57c6f8c69b9d08ccfd3cb5b7d746425cd6789"
dependencies = [
"anyhow",
"derive_more",
"schemars",
"serde",
"serde_json",
- "strum 0.27.2",
+ "strum 0.28.0",
]
[[package]]
@@ -285,7 +278,6 @@ dependencies = [
"gpui_tokio",
"http_client",
"indoc",
- "language",
"language_model",
"libc",
"log",
@@ -319,7 +311,6 @@ dependencies = [
"gpui",
"language_model",
"log",
- "paths",
"project",
"regex",
"schemars",
@@ -352,7 +343,6 @@ dependencies = [
"buffer_diff",
"chrono",
"client",
- "clock",
"cloud_api_types",
"cloud_llm_client",
"collections",
@@ -398,9 +388,7 @@ dependencies = [
"prompt_store",
"proto",
"rand 0.9.2",
- "recent_projects",
"release_channel",
- "remote_connection",
"reqwest_client",
"rope",
"rules_library",
@@ -415,14 +403,12 @@ dependencies = [
"streaming_diff",
"task",
"telemetry",
- "tempfile",
"terminal",
"terminal_view",
"text",
"theme",
"time",
"time_format",
- "title_bar",
"tree-sitter-md",
"ui",
"ui_input",
@@ -671,17 +657,13 @@ dependencies = [
"anyhow",
"chrono",
"futures 0.3.31",
- "gpui",
- "gpui_tokio",
"http_client",
- "reqwest_client",
"schemars",
"serde",
"serde_json",
"settings",
"strum 0.27.2",
"thiserror 2.0.17",
- "tokio",
]
[[package]]
@@ -731,7 +713,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -893,7 +875,6 @@ dependencies = [
"futures 0.3.31",
"fuzzy",
"gpui",
- "indoc",
"itertools 0.14.0",
"language",
"language_model",
@@ -1128,7 +1109,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -1196,7 +1177,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -1226,7 +1207,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -2065,7 +2046,7 @@ dependencies = [
"regex",
"rustc-hash 2.1.1",
"shlex",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -2083,7 +2064,7 @@ dependencies = [
"regex",
"rustc-hash 2.1.1",
"shlex",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -2212,13 +2193,13 @@ version = "3.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ec27229c38ed0eb3c0feee3d2c1d6a4379ae44f418a29a658890e062d8f365"
dependencies = [
- "darling",
+ "darling 0.20.11",
"ident_case",
"prettyplease",
"proc-macro2",
"quote",
"rustversion",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -2247,7 +2228,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -2320,7 +2301,6 @@ dependencies = [
"pretty_assertions",
"rand 0.9.2",
"rope",
- "serde_json",
"settings",
"sum_tree",
"text",
@@ -2397,7 +2377,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -2479,10 +2459,10 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9225bdcf4e4a9a4c08bf16607908eb2fbf746828d5e0b5e019726dbf6571f201"
dependencies = [
- "darling",
+ "darling 0.20.11",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -2504,7 +2484,6 @@ dependencies = [
"futures 0.3.31",
"gpui",
"gpui_tokio",
- "http_client",
"language",
"livekit_client",
"log",
@@ -2736,7 +2715,7 @@ dependencies = [
"quote",
"serde",
"serde_json",
- "syn 2.0.106",
+ "syn 2.0.117",
"tempfile",
"toml 0.8.23",
]
@@ -2965,7 +2944,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -3099,8 +3078,6 @@ name = "cloud_llm_client"
version = "0.1.0"
dependencies = [
"anyhow",
- "indoc",
- "pretty_assertions",
"serde",
"serde_json",
"strum 0.27.2",
@@ -3225,6 +3202,7 @@ dependencies = [
"serde",
"serde_json",
"text",
+ "zeta_prompt",
]
[[package]]
@@ -3232,15 +3210,11 @@ name = "collab"
version = "0.44.0"
dependencies = [
"agent",
- "agent-client-protocol",
- "agent_settings",
- "agent_ui",
"anyhow",
"assistant_slash_command",
"assistant_text_thread",
"async-trait",
"async-tungstenite",
- "audio",
"aws-config",
"aws-sdk-kinesis",
"aws-sdk-s3",
@@ -3256,10 +3230,8 @@ dependencies = [
"collab_ui",
"collections",
"command_palette_hooks",
- "context_server",
"ctor",
"dap",
- "dap-types",
"dap_adapters",
"dashmap",
"debugger_ui",
@@ -3276,7 +3248,6 @@ dependencies = [
"gpui_tokio",
"hex",
"http_client",
- "hyper 0.14.32",
"indoc",
"language",
"language_model",
@@ -3318,7 +3289,6 @@ dependencies = [
"text",
"theme",
"time",
- "title_bar",
"tokio",
"toml 0.8.23",
"tower 0.4.13",
@@ -3349,12 +3319,10 @@ dependencies = [
"futures 0.3.31",
"fuzzy",
"gpui",
- "http_client",
"log",
"menu",
"notifications",
"picker",
- "pretty_assertions",
"project",
"release_channel",
"rpc",
@@ -3367,7 +3335,6 @@ dependencies = [
"time",
"time_format",
"title_bar",
- "tree-sitter-md",
"ui",
"util",
"workspace",
@@ -3421,10 +3388,8 @@ dependencies = [
"client",
"collections",
"command_palette_hooks",
- "ctor",
"db",
"editor",
- "env_logger 0.11.8",
"fuzzy",
"go_to_line",
"gpui",
@@ -3435,7 +3400,6 @@ dependencies = [
"postage",
"project",
"serde",
- "serde_json",
"settings",
"telemetry",
"theme",
@@ -3643,24 +3607,29 @@ dependencies = [
"unicode-segmentation",
]
+[[package]]
+name = "convert_case"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49"
+dependencies = [
+ "unicode-segmentation",
+]
+
[[package]]
name = "copilot"
version = "0.1.0"
dependencies = [
"anyhow",
"async-std",
- "client",
- "clock",
"collections",
"command_palette_hooks",
"copilot_chat",
- "ctor",
"edit_prediction_types",
"editor",
"fs",
"futures 0.3.31",
"gpui",
- "http_client",
"icons",
"indoc",
"language",
@@ -3687,6 +3656,7 @@ dependencies = [
name = "copilot_chat"
version = "0.1.0"
dependencies = [
+ "anthropic",
"anyhow",
"collections",
"dirs 4.0.0",
@@ -4354,7 +4324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -4431,7 +4401,7 @@ dependencies = [
"proc-macro2",
"quote",
"scratch",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -4445,7 +4415,7 @@ dependencies = [
"indexmap",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -4463,7 +4433,7 @@ dependencies = [
"indexmap",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -4497,8 +4467,6 @@ dependencies = [
"smol",
"task",
"telemetry",
- "tree-sitter",
- "tree-sitter-go",
"util",
"zlog",
]
@@ -4545,8 +4513,18 @@ version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
dependencies = [
- "darling_core",
- "darling_macro",
+ "darling_core 0.20.11",
+ "darling_macro 0.20.11",
+]
+
+[[package]]
+name = "darling"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
+dependencies = [
+ "darling_core 0.21.3",
+ "darling_macro 0.21.3",
]
[[package]]
@@ -4560,7 +4538,21 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
- "syn 2.0.106",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.117",
]
[[package]]
@@ -4569,9 +4561,20 @@ version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
- "darling_core",
+ "darling_core 0.20.11",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
+dependencies = [
+ "darling_core 0.21.3",
+ "quote",
+ "syn 2.0.117",
]
[[package]]
@@ -4803,7 +4806,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -4825,7 +4828,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustc_version",
- "syn 2.0.106",
+ "syn 2.0.117",
"unicode-xid",
]
@@ -4835,19 +4838,19 @@ version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
name = "derive_setters"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae5c625eda104c228c06ecaf988d1c60e542176bd7a490e60eeda3493244c0c9"
+checksum = "b7e6f6fa1f03c14ae082120b84b3c7fbd7b8588d924cf2d7c3daf9afd49df8b9"
dependencies = [
- "darling",
+ "darling 0.21.3",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -4869,7 +4872,6 @@ dependencies = [
"serde_json",
"settings",
"smol",
- "theme",
"ui",
"util",
"workspace",
@@ -4881,7 +4883,6 @@ name = "diagnostics"
version = "0.1.0"
dependencies = [
"anyhow",
- "client",
"collections",
"component",
"ctor",
@@ -5038,7 +5039,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -5101,7 +5102,7 @@ dependencies = [
"proc-macro2",
"quote",
"strum 0.27.2",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -5274,7 +5275,6 @@ dependencies = [
"thiserror 2.0.17",
"time",
"toml 0.8.23",
- "tree-sitter-rust",
"ui",
"util",
"uuid",
@@ -5372,7 +5372,6 @@ dependencies = [
"tree-sitter",
"util",
"zeta_prompt",
- "zlog",
]
[[package]]
@@ -5393,7 +5392,6 @@ dependencies = [
"anyhow",
"buffer_diff",
"client",
- "clock",
"cloud_llm_client",
"codestral",
"collections",
@@ -5410,18 +5408,12 @@ dependencies = [
"gpui",
"indoc",
"language",
- "language_model",
- "lsp",
"markdown",
"menu",
"multi_buffer",
"paths",
- "pretty_assertions",
"project",
"regex",
- "release_channel",
- "semver",
- "serde_json",
"settings",
"telemetry",
"text",
@@ -5432,7 +5424,6 @@ dependencies = [
"workspace",
"zed_actions",
"zeta_prompt",
- "zlog",
]
[[package]]
@@ -5461,7 +5452,6 @@ dependencies = [
"fuzzy",
"git",
"gpui",
- "http_client",
"indoc",
"itertools 0.14.0",
"language",
@@ -5476,6 +5466,8 @@ dependencies = [
"parking_lot",
"pretty_assertions",
"project",
+ "proptest",
+ "proptest-derive",
"rand 0.9.2",
"regex",
"release_channel",
@@ -5492,7 +5484,6 @@ dependencies = [
"sum_tree",
"task",
"telemetry",
- "tempfile",
"text",
"theme",
"time",
@@ -5652,7 +5643,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -5673,7 +5664,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -5738,7 +5729,7 @@ checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -5789,6 +5780,15 @@ dependencies = [
"libc",
]
+[[package]]
+name = "error-graph"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b920e777967421aa5f9bf34f842c0ab6ba19b3bdb4a082946093860f5858879"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "etagere"
version = "0.2.15"
@@ -5892,6 +5892,47 @@ dependencies = [
"watch",
]
+[[package]]
+name = "eval_cli"
+version = "0.1.0"
+dependencies = [
+ "acp_thread",
+ "agent",
+ "agent-client-protocol",
+ "agent_ui",
+ "anyhow",
+ "clap",
+ "client",
+ "ctrlc",
+ "debug_adapter_extension",
+ "env_logger 0.11.8",
+ "extension",
+ "feature_flags",
+ "fs",
+ "futures 0.3.31",
+ "gpui",
+ "gpui_platform",
+ "gpui_tokio",
+ "language",
+ "language_extension",
+ "language_model",
+ "language_models",
+ "languages",
+ "node_runtime",
+ "paths",
+ "project",
+ "prompt_store",
+ "release_channel",
+ "reqwest_client",
+ "serde",
+ "serde_json",
+ "settings",
+ "shellexpand 2.1.2",
+ "terminal_view",
+ "util",
+ "watch",
+]
+
[[package]]
name = "eval_utils"
version = "0.1.0"
@@ -6020,7 +6061,9 @@ dependencies = [
"serde",
"serde_json",
"serde_json_lenient",
+ "settings_content",
"snippet_provider",
+ "task",
"theme",
"tokio",
"toml 0.8.23",
@@ -6057,7 +6100,6 @@ dependencies = [
"parking_lot",
"paths",
"project",
- "rand 0.9.2",
"release_channel",
"remote",
"reqwest_client",
@@ -6117,6 +6159,12 @@ dependencies = [
"zed_actions",
]
+[[package]]
+name = "failspot"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c942e64b20ecd39933d5ff938ca4fdb6ef0d298cc3855b231179a5ef0b24948d"
+
[[package]]
name = "fallible-iterator"
version = "0.3.0"
@@ -6172,7 +6220,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -6199,7 +6247,6 @@ dependencies = [
name = "feature_flags"
version = "0.1.0"
dependencies = [
- "futures 0.3.31",
"gpui",
]
@@ -6207,7 +6254,6 @@ dependencies = [
name = "feedback"
version = "0.1.0"
dependencies = [
- "editor",
"gpui",
"system_specs",
"urlencoding",
@@ -6231,6 +6277,8 @@ name = "file_finder"
version = "0.1.0"
dependencies = [
"anyhow",
+ "channel",
+ "client",
"collections",
"ctor",
"editor",
@@ -6238,13 +6286,13 @@ dependencies = [
"futures 0.3.31",
"fuzzy",
"gpui",
- "language",
"menu",
"open_path_prompt",
"picker",
"pretty_assertions",
"project",
"project_panel",
+ "remote_connection",
"serde",
"serde_json",
"settings",
@@ -6471,7 +6519,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -6740,7 +6788,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -7130,7 +7178,7 @@ dependencies = [
[[package]]
name = "gh-workflow"
version = "0.8.0"
-source = "git+https://github.com/zed-industries/gh-workflow?rev=c9eac0ed361583e1072860d96776fa52775b82ac#c9eac0ed361583e1072860d96776fa52775b82ac"
+source = "git+https://github.com/zed-industries/gh-workflow?rev=37f3c0575d379c218a9c455ee67585184e40d43f#37f3c0575d379c218a9c455ee67585184e40d43f"
dependencies = [
"async-trait",
"derive_more",
@@ -7141,17 +7189,17 @@ dependencies = [
"serde",
"serde_json",
"serde_yaml",
- "strum_macros",
+ "strum_macros 0.27.2",
]
[[package]]
name = "gh-workflow-macros"
version = "0.8.0"
-source = "git+https://github.com/zed-industries/gh-workflow?rev=c9eac0ed361583e1072860d96776fa52775b82ac#c9eac0ed361583e1072860d96776fa52775b82ac"
+source = "git+https://github.com/zed-industries/gh-workflow?rev=37f3c0575d379c218a9c455ee67585184e40d43f#37f3c0575d379c218a9c455ee67585184e40d43f"
dependencies = [
"heck 0.5.0",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -7224,7 +7272,6 @@ dependencies = [
"text",
"thiserror 2.0.17",
"time",
- "unindent",
"url",
"urlencoding",
"util",
@@ -7261,7 +7308,6 @@ dependencies = [
"menu",
"project",
"rand 0.9.2",
- "recent_projects",
"serde_json",
"settings",
"smallvec",
@@ -7312,7 +7358,6 @@ dependencies = [
"futures 0.3.31",
"fuzzy",
"git",
- "git_hosting_providers",
"gpui",
"indoc",
"itertools 0.14.0",
@@ -7400,7 +7445,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -7481,8 +7526,6 @@ dependencies = [
"settings",
"text",
"theme",
- "tree-sitter-rust",
- "tree-sitter-typescript",
"ui",
"util",
"workspace",
@@ -7501,9 +7544,9 @@ dependencies = [
[[package]]
name = "goblin"
-version = "0.8.2"
+version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47"
+checksum = "daa0a64d21a7eb230583b4c5f4e23b7e4e57974f96620f42a7e75e08ae66d745"
dependencies = [
"log",
"plain",
@@ -7613,8 +7656,8 @@ dependencies = [
"pin-project",
"pollster 0.4.0",
"postage",
- "pretty_assertions",
"profiling",
+ "proptest",
"rand 0.9.2",
"raw-window-handle",
"refineable",
@@ -7742,7 +7785,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -8170,7 +8213,7 @@ dependencies = [
"markup5ever 0.12.1",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -8628,7 +8671,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
dependencies = [
"byteorder-lite",
- "quick-error",
+ "quick-error 2.0.1",
]
[[package]]
@@ -8704,7 +8747,7 @@ checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -8799,7 +8842,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -8991,7 +9034,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -9413,7 +9456,6 @@ dependencies = [
"copilot_ui",
"credentials_provider",
"deepseek",
- "editor",
"extension",
"extension_host",
"fs",
@@ -9433,7 +9475,6 @@ dependencies = [
"open_router",
"partial-json-fixer",
"pretty_assertions",
- "project",
"release_channel",
"schemars",
"semver",
@@ -9561,7 +9602,6 @@ dependencies = [
"snippet",
"task",
"terminal",
- "text",
"theme",
"toml 0.8.23",
"tree-sitter",
@@ -9585,7 +9625,6 @@ dependencies = [
"unindent",
"url",
"util",
- "workspace",
]
[[package]]
@@ -9632,9 +9671,9 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
[[package]]
name = "libc"
-version = "0.2.177"
+version = "0.2.182"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
+checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
[[package]]
name = "libdbus-sys"
@@ -9939,7 +9978,6 @@ dependencies = [
"serde_json",
"serde_urlencoded",
"settings",
- "sha2",
"simplelog",
"smallvec",
"ui",
@@ -10262,7 +10300,7 @@ checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -10496,9 +10534,9 @@ dependencies = [
[[package]]
name = "minidump-common"
-version = "0.21.2"
+version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c4d14bcca0fd3ed165a03000480aaa364c6860c34e900cb2dafdf3b95340e77"
+checksum = "2e16d10087ae9e375bad7a40e8ef5504bc08e808ccc6019067ff9de42a84570f"
dependencies = [
"bitflags 2.10.0",
"debugid",
@@ -10511,14 +10549,16 @@ dependencies = [
[[package]]
name = "minidump-writer"
-version = "0.8.9"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abcd9c8a1e6e1e9d56ce3627851f39a17ea83e17c96bc510f29d7e43d78a7d"
+checksum = "0e1fc14d6ded915b8e850801465e7096f77ed60bf87e4e85878d463720d9dc4d"
dependencies = [
"bitflags 2.10.0",
"byteorder",
"cfg-if",
"crash-context",
+ "error-graph",
+ "failspot",
"goblin",
"libc",
"log",
@@ -10526,18 +10566,20 @@ dependencies = [
"memmap2",
"memoffset",
"minidump-common",
- "nix 0.28.0",
+ "nix 0.29.0",
"procfs-core",
"scroll",
+ "serde",
+ "serde_json",
"tempfile",
- "thiserror 1.0.69",
+ "thiserror 2.0.17",
]
[[package]]
name = "minidumper"
-version = "0.8.3"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b4ebc9d1f8847ec1d078f78b35ed598e0ebefa1f242d5f83cd8d7f03960a7d1"
+checksum = "10d9254e42a48098d045472a5c0cb892007a42e25342eddbf2642f6978bf381a"
dependencies = [
"cfg-if",
"crash-context",
@@ -10547,7 +10589,7 @@ dependencies = [
"parking_lot",
"polling",
"scroll",
- "thiserror 1.0.69",
+ "thiserror 2.0.17",
"uds",
]
@@ -10680,7 +10722,6 @@ dependencies = [
"log",
"parking_lot",
"pretty_assertions",
- "project",
"rand 0.9.2",
"rope",
"serde",
@@ -10731,7 +10772,7 @@ dependencies = [
[[package]]
name = "naga"
version = "28.0.1"
-source = "git+https://github.com/zed-industries/wgpu?rev=9459e95113c5bd116b2cc2c87e8424b28059e17c#9459e95113c5bd116b2cc2c87e8424b28059e17c"
+source = "git+https://github.com/zed-industries/wgpu?rev=465557eccfe77c840a9b4936f1408da9503372c4#465557eccfe77c840a9b4936f1408da9503372c4"
dependencies = [
"arrayvec",
"bit-set",
@@ -10958,12 +10999,10 @@ dependencies = [
"anyhow",
"channel",
"client",
- "collections",
"component",
"db",
"gpui",
"rpc",
- "settings",
"sum_tree",
"time",
"ui",
@@ -11129,7 +11168,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -11212,7 +11251,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -11605,7 +11644,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -11634,7 +11673,7 @@ checksum = "969ccca8ffc4fb105bd131a228107d5c9dd89d9d627edf3295cbe979156f9712"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -11692,7 +11731,7 @@ dependencies = [
"proc-macro2",
"proc-macro2-diagnostics",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -11714,8 +11753,6 @@ dependencies = [
"settings",
"smol",
"theme",
- "tree-sitter-rust",
- "tree-sitter-typescript",
"ui",
"util",
"workspace",
@@ -11802,7 +11839,7 @@ dependencies = [
"by_address",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -12065,7 +12102,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -12544,7 +12581,7 @@ dependencies = [
"phf_shared 0.11.3",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -12557,7 +12594,7 @@ dependencies = [
"phf_shared 0.12.1",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -12619,7 +12656,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -12943,7 +12980,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -13007,7 +13044,7 @@ dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -13027,19 +13064,20 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"version_check",
"yansi",
]
[[package]]
name = "procfs-core"
-version = "0.16.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29"
+checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec"
dependencies = [
"bitflags 2.10.0",
"hex",
+ "serde",
]
[[package]]
@@ -13058,7 +13096,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
dependencies = [
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -13077,8 +13115,6 @@ dependencies = [
"collections",
"context_server",
"dap",
- "dap_adapters",
- "db",
"encoding_rs",
"extension",
"fancy-regex",
@@ -13185,7 +13221,6 @@ dependencies = [
"pretty_assertions",
"project",
"rayon",
- "remote_connection",
"schemars",
"search",
"serde",
@@ -13267,6 +13302,47 @@ dependencies = [
"uuid",
]
+[[package]]
+name = "proptest"
+version = "1.10.0"
+source = "git+https://github.com/proptest-rs/proptest?rev=3dca198a8fef1b32e3a66f1e1897c955b4dc5b5b#3dca198a8fef1b32e3a66f1e1897c955b4dc5b5b"
+dependencies = [
+ "bit-set",
+ "bit-vec",
+ "bitflags 2.10.0",
+ "num-traits",
+ "proptest-macro",
+ "rand 0.9.2",
+ "rand_chacha 0.9.0",
+ "rand_xorshift",
+ "regex-syntax",
+ "rusty-fork",
+ "tempfile",
+ "unarray",
+]
+
+[[package]]
+name = "proptest-derive"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c57924a81864dddafba92e1bf92f9bf82f97096c44489548a60e888e1547549b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "proptest-macro"
+version = "0.5.0"
+source = "git+https://github.com/proptest-rs/proptest?rev=3dca198a8fef1b32e3a66f1e1897c955b4dc5b5b#3dca198a8fef1b32e3a66f1e1897c955b4dc5b5b"
+dependencies = [
+ "convert_case 0.11.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
[[package]]
name = "prost"
version = "0.9.0"
@@ -13324,7 +13400,7 @@ dependencies = [
"prost 0.12.6",
"prost-types 0.12.6",
"regex",
- "syn 2.0.106",
+ "syn 2.0.117",
"tempfile",
]
@@ -13351,7 +13427,7 @@ dependencies = [
"itertools 0.12.1",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -13378,11 +13454,9 @@ name = "proto"
version = "0.1.0"
dependencies = [
"anyhow",
- "collections",
"prost 0.9.0",
"prost-build 0.9.0",
"serde",
- "typed-path",
]
[[package]]
@@ -13519,6 +13593,12 @@ dependencies = [
"bytemuck",
]
+[[package]]
+name = "quick-error"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+
[[package]]
name = "quick-error"
version = "2.0.1"
@@ -13744,6 +13824,15 @@ dependencies = [
"rand_core 0.6.4",
]
+[[package]]
+name = "rand_xorshift"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
+dependencies = [
+ "rand_core 0.9.3",
+]
+
[[package]]
name = "random_choice"
version = "0.3.2"
@@ -13818,7 +13907,7 @@ dependencies = [
"avif-serialize",
"imgref",
"loop9",
- "quick-error",
+ "quick-error 2.0.1",
"rav1e",
"rayon",
"rgb",
@@ -13920,7 +14009,6 @@ dependencies = [
"anyhow",
"askpass",
"chrono",
- "dap",
"db",
"dev_container",
"editor",
@@ -14018,7 +14106,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -14169,7 +14257,6 @@ dependencies = [
"collections",
"crash-handler",
"crashes",
- "dap",
"dap_adapters",
"debug_adapter_extension",
"editor",
@@ -14201,7 +14288,6 @@ dependencies = [
"paths",
"pretty_assertions",
"project",
- "prompt_store",
"proto",
"rayon",
"release_channel",
@@ -14225,7 +14311,6 @@ dependencies = [
"uuid",
"watch",
"windows 0.61.3",
- "workspace",
"worktree",
"zlog",
]
@@ -14259,7 +14344,6 @@ dependencies = [
"collections",
"command_palette_hooks",
"editor",
- "env_logger 0.11.8",
"feature_flags",
"file_icons",
"futures 0.3.31",
@@ -14387,7 +14471,6 @@ dependencies = [
"anyhow",
"bytes 1.11.1",
"futures 0.3.31",
- "gpui",
"gpui_util",
"http_client",
"http_client_tls",
@@ -14432,20 +14515,6 @@ dependencies = [
"bytemuck",
]
-[[package]]
-name = "rich_text"
-version = "0.1.0"
-dependencies = [
- "futures 0.3.31",
- "gpui",
- "language",
- "linkify",
- "pulldown-cmark 0.13.0",
- "theme",
- "ui",
- "util",
-]
-
[[package]]
name = "ring"
version = "0.17.14"
@@ -14695,7 +14764,7 @@ dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
- "syn 2.0.106",
+ "syn 2.0.117",
"walkdir",
]
@@ -14949,6 +15018,18 @@ version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+[[package]]
+name = "rusty-fork"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2"
+dependencies = [
+ "fnv",
+ "quick-error 1.2.3",
+ "tempfile",
+ "wait-timeout",
+]
+
[[package]]
name = "rustybuzz"
version = "0.20.1"
@@ -15068,7 +15149,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -15129,7 +15210,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -15158,7 +15239,7 @@ dependencies = [
"proc-macro-error2",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -15200,7 +15281,7 @@ dependencies = [
"proc-macro2",
"quote",
"sea-bae",
- "syn 2.0.106",
+ "syn 2.0.117",
"unicode-ident",
]
@@ -15249,7 +15330,6 @@ dependencies = [
"any_vec",
"anyhow",
"bitflags 2.10.0",
- "client",
"collections",
"editor",
"fs",
@@ -15385,7 +15465,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -15396,7 +15476,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -15454,7 +15534,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -15594,18 +15674,16 @@ version = "0.1.0"
dependencies = [
"quote",
"settings",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
name = "settings_profile_selector"
version = "0.1.0"
dependencies = [
- "client",
"editor",
"fuzzy",
"gpui",
- "language",
"menu",
"picker",
"project",
@@ -15624,9 +15702,7 @@ dependencies = [
"agent",
"agent_settings",
"anyhow",
- "assets",
"audio",
- "client",
"codestral",
"component",
"copilot",
@@ -15644,13 +15720,11 @@ dependencies = [
"language",
"log",
"menu",
- "node_runtime",
"paths",
"picker",
"platform_title_bar",
"pretty_assertions",
"project",
- "recent_projects",
"regex",
"release_channel",
"rodio",
@@ -15658,7 +15732,6 @@ dependencies = [
"search",
"serde",
"serde_json",
- "session",
"settings",
"shell_command_parser",
"strum 0.27.2",
@@ -15669,7 +15742,6 @@ dependencies = [
"util",
"workspace",
"zed_actions",
- "zlog",
]
[[package]]
@@ -15773,33 +15845,6 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
-[[package]]
-name = "sidebar"
-version = "0.1.0"
-dependencies = [
- "acp_thread",
- "agent",
- "agent-client-protocol",
- "agent_ui",
- "assistant_text_thread",
- "chrono",
- "editor",
- "feature_flags",
- "fs",
- "gpui",
- "language_model",
- "menu",
- "project",
- "recent_projects",
- "serde_json",
- "settings",
- "theme",
- "ui",
- "util",
- "workspace",
- "zed_actions",
-]
-
[[package]]
name = "signal-hook"
version = "0.3.18"
@@ -15969,7 +16014,7 @@ checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -16147,7 +16192,7 @@ version = "0.1.0"
dependencies = [
"sqlez",
"sqlformat",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -16224,7 +16269,7 @@ dependencies = [
"quote",
"sqlx-core",
"sqlx-macros-core",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -16247,7 +16292,7 @@ dependencies = [
"sqlx-mysql",
"sqlx-postgres",
"sqlx-sqlite",
- "syn 2.0.106",
+ "syn 2.0.117",
"tokio",
"url",
]
@@ -16406,7 +16451,7 @@ checksum = "172175341049678163e979d9107ca3508046d4d2a7c6682bee46ac541b17db69"
dependencies = [
"proc-macro-error2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -16537,7 +16582,16 @@ version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
dependencies = [
- "strum_macros",
+ "strum_macros 0.27.2",
+]
+
+[[package]]
+name = "strum"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd"
+dependencies = [
+ "strum_macros 0.28.0",
]
[[package]]
@@ -16549,7 +16603,19 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664"
+dependencies = [
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
]
[[package]]
@@ -16565,6 +16631,7 @@ dependencies = [
"arrayvec",
"ctor",
"log",
+ "proptest",
"rand 0.9.2",
"rayon",
"tracing",
@@ -16850,9 +16917,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.106"
+version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
@@ -16891,7 +16958,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -17062,13 +17129,11 @@ dependencies = [
name = "tab_switcher"
version = "0.1.0"
dependencies = [
- "anyhow",
"collections",
"ctor",
"editor",
"fuzzy",
"gpui",
- "language",
"menu",
"picker",
"project",
@@ -17257,7 +17322,6 @@ dependencies = [
"release_channel",
"schemars",
"serde",
- "serde_json",
"settings",
"smol",
"sysinfo 0.37.2",
@@ -17289,7 +17353,6 @@ dependencies = [
"assistant_slash_command",
"async-recursion",
"breadcrumbs",
- "client",
"collections",
"db",
"dirs 4.0.0",
@@ -17302,7 +17365,6 @@ dependencies = [
"menu",
"pretty_assertions",
"project",
- "rand 0.9.2",
"regex",
"schemars",
"serde",
@@ -17327,7 +17389,6 @@ dependencies = [
"collections",
"ctor",
"gpui",
- "http_client",
"log",
"parking_lot",
"postage",
@@ -17441,7 +17502,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -17452,7 +17513,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -17473,7 +17534,7 @@ dependencies = [
"fax",
"flate2",
"half",
- "quick-error",
+ "quick-error 2.0.1",
"weezl",
"zune-jpeg",
]
@@ -17630,15 +17691,11 @@ dependencies = [
"chrono",
"client",
"cloud_api_types",
- "collections",
"db",
- "feature_flags",
"git_ui",
"gpui",
- "http_client",
"notifications",
"platform_title_bar",
- "pretty_assertions",
"project",
"recent_projects",
"release_channel",
@@ -17652,7 +17709,6 @@ dependencies = [
"story",
"telemetry",
"theme",
- "tree-sitter-md",
"ui",
"util",
"windows 0.61.3",
@@ -17696,7 +17752,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -18034,7 +18090,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -18129,7 +18185,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -18482,12 +18538,6 @@ dependencies = [
"utf-8",
]
-[[package]]
-name = "typed-path"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c462d18470a2857aa657d338af5fa67170bb48bcc80a296710ce3b0802a32566"
-
[[package]]
name = "typeid"
version = "1.0.3"
@@ -18586,7 +18636,7 @@ version = "0.1.0"
dependencies = [
"component",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"ui",
]
@@ -18603,6 +18653,12 @@ dependencies = [
"workspace",
]
+[[package]]
+name = "unarray"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
+
[[package]]
name = "unicase"
version = "2.8.1"
@@ -18808,7 +18864,6 @@ dependencies = [
"git2",
"globset",
"gpui_util",
- "indoc",
"itertools 0.14.0",
"libc",
"log",
@@ -18841,7 +18896,7 @@ version = "0.1.0"
dependencies = [
"perf",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -18953,7 +19008,6 @@ name = "vim"
version = "0.1.0"
dependencies = [
"anyhow",
- "assets",
"async-compat",
"async-trait",
"collections",
@@ -18993,7 +19047,6 @@ dependencies = [
"task",
"text",
"theme",
- "title_bar",
"tokio",
"ui",
"util",
@@ -19059,6 +19112,15 @@ dependencies = [
"serde",
]
+[[package]]
+name = "wait-timeout"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "waker-fn"
version = "1.2.0"
@@ -19188,7 +19250,7 @@ dependencies = [
"bumpalo",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"wasm-bindgen-shared",
]
@@ -19484,7 +19546,7 @@ dependencies = [
"anyhow",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"wasmtime-component-util",
"wasmtime-wit-bindgen",
"wit-parser 0.229.0",
@@ -19599,7 +19661,7 @@ checksum = "d0963c1438357a3d8c0efe152b4ef5259846c1cf8b864340270744fe5b3bae5e"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -19692,7 +19754,6 @@ dependencies = [
"futures 0.3.31",
"gpui",
"parking_lot",
- "rand 0.9.2",
"zlog",
]
@@ -19924,7 +19985,7 @@ checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3"
[[package]]
name = "wgpu"
version = "28.0.1"
-source = "git+https://github.com/zed-industries/wgpu?rev=9459e95113c5bd116b2cc2c87e8424b28059e17c#9459e95113c5bd116b2cc2c87e8424b28059e17c"
+source = "git+https://github.com/zed-industries/wgpu?rev=465557eccfe77c840a9b4936f1408da9503372c4#465557eccfe77c840a9b4936f1408da9503372c4"
dependencies = [
"arrayvec",
"bitflags 2.10.0",
@@ -19953,7 +20014,7 @@ dependencies = [
[[package]]
name = "wgpu-core"
version = "28.0.1"
-source = "git+https://github.com/zed-industries/wgpu?rev=9459e95113c5bd116b2cc2c87e8424b28059e17c#9459e95113c5bd116b2cc2c87e8424b28059e17c"
+source = "git+https://github.com/zed-industries/wgpu?rev=465557eccfe77c840a9b4936f1408da9503372c4#465557eccfe77c840a9b4936f1408da9503372c4"
dependencies = [
"arrayvec",
"bit-set",
@@ -19984,7 +20045,7 @@ dependencies = [
[[package]]
name = "wgpu-core-deps-apple"
version = "28.0.1"
-source = "git+https://github.com/zed-industries/wgpu?rev=9459e95113c5bd116b2cc2c87e8424b28059e17c#9459e95113c5bd116b2cc2c87e8424b28059e17c"
+source = "git+https://github.com/zed-industries/wgpu?rev=465557eccfe77c840a9b4936f1408da9503372c4#465557eccfe77c840a9b4936f1408da9503372c4"
dependencies = [
"wgpu-hal",
]
@@ -19992,7 +20053,7 @@ dependencies = [
[[package]]
name = "wgpu-core-deps-emscripten"
version = "28.0.1"
-source = "git+https://github.com/zed-industries/wgpu?rev=9459e95113c5bd116b2cc2c87e8424b28059e17c#9459e95113c5bd116b2cc2c87e8424b28059e17c"
+source = "git+https://github.com/zed-industries/wgpu?rev=465557eccfe77c840a9b4936f1408da9503372c4#465557eccfe77c840a9b4936f1408da9503372c4"
dependencies = [
"wgpu-hal",
]
@@ -20000,7 +20061,7 @@ dependencies = [
[[package]]
name = "wgpu-core-deps-windows-linux-android"
version = "28.0.1"
-source = "git+https://github.com/zed-industries/wgpu?rev=9459e95113c5bd116b2cc2c87e8424b28059e17c#9459e95113c5bd116b2cc2c87e8424b28059e17c"
+source = "git+https://github.com/zed-industries/wgpu?rev=465557eccfe77c840a9b4936f1408da9503372c4#465557eccfe77c840a9b4936f1408da9503372c4"
dependencies = [
"wgpu-hal",
]
@@ -20008,7 +20069,7 @@ dependencies = [
[[package]]
name = "wgpu-hal"
version = "28.0.1"
-source = "git+https://github.com/zed-industries/wgpu?rev=9459e95113c5bd116b2cc2c87e8424b28059e17c#9459e95113c5bd116b2cc2c87e8424b28059e17c"
+source = "git+https://github.com/zed-industries/wgpu?rev=465557eccfe77c840a9b4936f1408da9503372c4#465557eccfe77c840a9b4936f1408da9503372c4"
dependencies = [
"android_system_properties",
"arrayvec",
@@ -20055,7 +20116,7 @@ dependencies = [
[[package]]
name = "wgpu-types"
version = "28.0.1"
-source = "git+https://github.com/zed-industries/wgpu?rev=9459e95113c5bd116b2cc2c87e8424b28059e17c#9459e95113c5bd116b2cc2c87e8424b28059e17c"
+source = "git+https://github.com/zed-industries/wgpu?rev=465557eccfe77c840a9b4936f1408da9503372c4#465557eccfe77c840a9b4936f1408da9503372c4"
dependencies = [
"bitflags 2.10.0",
"bytemuck",
@@ -20137,7 +20198,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"witx",
]
@@ -20149,7 +20210,7 @@ checksum = "d873bb5b59ca703b5e41562e96a4796d1af61bf4cf80bf8a7abda755a380ec1c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"wiggle-generate",
]
@@ -20372,7 +20433,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -20383,7 +20444,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -20394,7 +20455,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -20405,7 +20466,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -20416,7 +20477,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -20427,7 +20488,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -21065,7 +21126,7 @@ dependencies = [
"heck 0.5.0",
"indexmap",
"prettyplease",
- "syn 2.0.106",
+ "syn 2.0.117",
"wasm-metadata 0.227.1",
"wit-bindgen-core 0.41.0",
"wit-component 0.227.1",
@@ -21081,7 +21142,7 @@ dependencies = [
"heck 0.5.0",
"indexmap",
"prettyplease",
- "syn 2.0.106",
+ "syn 2.0.117",
"wasm-metadata 0.244.0",
"wit-bindgen-core 0.51.0",
"wit-component 0.244.0",
@@ -21096,7 +21157,7 @@ dependencies = [
"anyhow",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"wit-bindgen-core 0.22.0",
"wit-bindgen-rust 0.22.0",
]
@@ -21111,7 +21172,7 @@ dependencies = [
"prettyplease",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"wit-bindgen-core 0.41.0",
"wit-bindgen-rust 0.41.0",
]
@@ -21126,7 +21187,7 @@ dependencies = [
"prettyplease",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"wit-bindgen-core 0.51.0",
"wit-bindgen-rust 0.51.0",
]
@@ -21284,7 +21345,6 @@ dependencies = [
"clock",
"collections",
"component",
- "dap",
"db",
"feature_flags",
"fs",
@@ -21337,9 +21397,7 @@ dependencies = [
"futures 0.3.31",
"fuzzy",
"git",
- "git2",
"gpui",
- "http_client",
"ignore",
"language",
"log",
@@ -21657,7 +21715,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"synstructure",
]
@@ -21669,7 +21727,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"synstructure",
]
@@ -21717,7 +21775,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"zbus_names",
"zvariant",
"zvariant_utils",
@@ -21736,7 +21794,7 @@ dependencies = [
[[package]]
name = "zed"
-version = "0.228.0"
+version = "0.229.0"
dependencies = [
"acp_thread",
"acp_tools",
@@ -21773,7 +21831,6 @@ dependencies = [
"copilot_ui",
"crashes",
"csv_preview",
- "dap",
"dap_adapters",
"db",
"debug_adapter_extension",
@@ -21861,7 +21918,6 @@ dependencies = [
"settings_profile_selector",
"settings_ui",
"shellexpand 2.1.2",
- "sidebar",
"smol",
"snippet_provider",
"snippets_ui",
@@ -21883,8 +21939,6 @@ dependencies = [
"title_bar",
"toolchain_selector",
"tracing",
- "tree-sitter-md",
- "tree-sitter-rust",
"ui",
"ui_prompt",
"url",
@@ -22115,7 +22169,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -22135,7 +22189,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"synstructure",
]
@@ -22156,7 +22210,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -22213,7 +22267,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
]
[[package]]
@@ -22375,7 +22429,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.117",
"zvariant_utils",
]
@@ -22388,6 +22442,6 @@ dependencies = [
"proc-macro2",
"quote",
"serde",
- "syn 2.0.106",
+ "syn 2.0.117",
"winnow",
]
diff --git a/Cargo.toml b/Cargo.toml
index b8e57bda7e46ea45451fedd6759268235c7d71ab..754860cc43f5b841e45316a0434b37886e901a0f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -66,6 +66,7 @@ members = [
"crates/encoding_selector",
"crates/etw_tracing",
"crates/eval",
+ "crates/eval_cli",
"crates/eval_utils",
"crates/explorer_command_injector",
"crates/extension",
@@ -158,7 +159,6 @@ members = [
"crates/remote_server",
"crates/repl",
"crates/reqwest_client",
- "crates/rich_text",
"crates/rope",
"crates/rpc",
"crates/rules_library",
@@ -173,7 +173,6 @@ members = [
"crates/settings_profile_selector",
"crates/settings_ui",
"crates/shell_command_parser",
- "crates/sidebar",
"crates/snippet",
"crates/snippet_provider",
"crates/snippets_ui",
@@ -412,7 +411,6 @@ rules_library = { path = "crates/rules_library" }
scheduler = { path = "crates/scheduler" }
search = { path = "crates/search" }
session = { path = "crates/session" }
-sidebar = { path = "crates/sidebar" }
settings = { path = "crates/settings" }
settings_content = { path = "crates/settings_content" }
settings_json = { path = "crates/settings_json" }
@@ -475,7 +473,7 @@ ztracing_macro = { path = "crates/ztracing_macro" }
# External crates
#
-agent-client-protocol = { version = "=0.9.4", features = ["unstable"] }
+agent-client-protocol = { version = "=0.10.2", features = ["unstable"] }
aho-corasick = "1.1"
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "9d9640d4" }
any_vec = "0.14"
@@ -513,7 +511,6 @@ aws-smithy-runtime-api = { version = "1.9.2", features = ["http-1x", "client"] }
aws-smithy-types = { version = "1.3.4", features = ["http-body-1-x"] }
backtrace = "0.3"
base64 = "0.22"
-bincode = "1.2.1"
bitflags = "2.6.0"
brotli = "8.0.2"
bytes = "1.0"
@@ -561,7 +558,7 @@ fork = "0.4.0"
futures = "0.3"
futures-concurrency = "7.7.1"
futures-lite = "1.13"
-gh-workflow = { git = "https://github.com/zed-industries/gh-workflow", rev = "c9eac0ed361583e1072860d96776fa52775b82ac" }
+gh-workflow = { git = "https://github.com/zed-industries/gh-workflow", rev = "37f3c0575d379c218a9c455ee67585184e40d43f" }
git2 = { version = "0.20.1", default-features = false, features = ["vendored-libgit2"] }
globset = "0.4"
handlebars = "4.3"
@@ -572,7 +569,6 @@ human_bytes = "0.4.1"
html5ever = "0.27.0"
http = "1.1"
http-body = "1.0"
-hyper = "0.14"
ignore = "0.4.22"
image = "0.25.1"
imara-diff = "0.1.8"
@@ -595,7 +591,7 @@ lsp-types = { git = "https://github.com/zed-industries/lsp-types", rev = "a4f410
mach2 = "0.5"
markup5ever_rcdom = "0.3.0"
metal = "0.33"
-minidumper = "0.8"
+minidumper = "0.9"
moka = { version = "0.12.10", features = ["sync"] }
naga = { version = "28.0", features = ["wgsl-in"] }
nanoid = "0.4"
@@ -649,6 +645,9 @@ postage = { version = "0.5", features = ["futures-traits"] }
pretty_assertions = { version = "1.3.0", features = ["unstable"] }
proc-macro2 = "1.0.93"
profiling = "1"
+# replace this with main when #635 is merged
+proptest = { git = "https://github.com/proptest-rs/proptest", rev = "3dca198a8fef1b32e3a66f1e1897c955b4dc5b5b", features = ["attr-macro"] }
+proptest-derive = "0.8.0"
prost = "0.9"
prost-build = "0.9"
prost-types = "0.9"
@@ -687,7 +686,6 @@ serde_json_lenient = { version = "0.2", features = [
"raw_value",
] }
serde_path_to_error = "0.1.17"
-serde_repr = "0.1"
serde_urlencoded = "0.7"
sha2 = "0.10"
shellexpand = "2.1.0"
@@ -718,7 +716,6 @@ time = { version = "0.3", features = [
] }
tiny_http = "0.8"
tokio = { version = "1" }
-tokio-tungstenite = { version = "0.26", features = ["__rustls-tls"] }
tokio-socks = { version = "0.5.2", default-features = false, features = [
"futures-io",
"tokio",
@@ -779,7 +776,7 @@ wax = "0.7"
which = "6.0.0"
wasm-bindgen = "0.2.113"
web-time = "1.1.0"
-wgpu = { git = "https://github.com/zed-industries/wgpu", rev = "9459e95113c5bd116b2cc2c87e8424b28059e17c" }
+wgpu = { git = "https://github.com/zed-industries/wgpu", rev = "465557eccfe77c840a9b4936f1408da9503372c4" }
windows-core = "0.61"
yawc = "0.2.5"
zeroize = "1.8"
@@ -904,7 +901,6 @@ refineable = { codegen-units = 1 }
release_channel = { codegen-units = 1 }
reqwest_client = { codegen-units = 1 }
session = { codegen-units = 1 }
-sidebar = { codegen-units = 1 }
snippet = { codegen-units = 1 }
snippets_ui = { codegen-units = 1 }
story = { codegen-units = 1 }
diff --git a/Dockerfile-collab b/Dockerfile-collab
index 63359334906b58c560c0ed6acc6378259ccbd5c5..50af874200a6ef3bc3c882b7d08257ec41f944de 100644
--- a/Dockerfile-collab
+++ b/Dockerfile-collab
@@ -14,8 +14,12 @@ ARG GITHUB_SHA
ENV GITHUB_SHA=$GITHUB_SHA
# Also add `cmake`, since we need it to build `wasmtime`.
+# clang is needed because `webrtc-sys` uses Clang-specific compiler flags.
RUN apt-get update; \
- apt-get install -y --no-install-recommends cmake
+ apt-get install -y --no-install-recommends cmake clang
+
+ENV CC=clang
+ENV CXX=clang++
RUN --mount=type=cache,target=./script/node_modules \
--mount=type=cache,target=/usr/local/cargo/registry \
diff --git a/assets/icons/archive.svg b/assets/icons/archive.svg
new file mode 100644
index 0000000000000000000000000000000000000000..9ffe3f39d27c7fe5cbb532a4f263c8800398e96f
--- /dev/null
+++ b/assets/icons/archive.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/git_merge_conflict.svg b/assets/icons/git_merge_conflict.svg
new file mode 100644
index 0000000000000000000000000000000000000000..10bc2c04fc9877112723273b0d60351c3a4c56bc
--- /dev/null
+++ b/assets/icons/git_merge_conflict.svg
@@ -0,0 +1,7 @@
+
diff --git a/assets/icons/list_collapse.svg b/assets/icons/list_collapse.svg
index f18bc550b90228c2f689848b86cfc5bea3d6ff50..dbdb2aaa4537c25ba1867d4957c23819af425835 100644
--- a/assets/icons/list_collapse.svg
+++ b/assets/icons/list_collapse.svg
@@ -1 +1,7 @@
-
+
diff --git a/assets/icons/thread.svg b/assets/icons/thread.svg
index 496cf42e3a3ee1439f36b8e2479d05564362e628..569a6f3aec7e3b8742d3d7d23fe11db5aea199ba 100644
--- a/assets/icons/thread.svg
+++ b/assets/icons/thread.svg
@@ -1,3 +1,4 @@
diff --git a/assets/icons/threads_sidebar_left_closed.svg b/assets/icons/threads_sidebar_left_closed.svg
new file mode 100644
index 0000000000000000000000000000000000000000..feb1015254635ef65f90f2c9ea38efab74d01d60
--- /dev/null
+++ b/assets/icons/threads_sidebar_left_closed.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/threads_sidebar_left_open.svg b/assets/icons/threads_sidebar_left_open.svg
new file mode 100644
index 0000000000000000000000000000000000000000..8057b060a84d7d7ffcf29aff1c0c79a8764edc22
--- /dev/null
+++ b/assets/icons/threads_sidebar_left_open.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/threads_sidebar_right_closed.svg b/assets/icons/threads_sidebar_right_closed.svg
new file mode 100644
index 0000000000000000000000000000000000000000..10fa4b792fd65b5875dcf2cadab1fc12a123ab47
--- /dev/null
+++ b/assets/icons/threads_sidebar_right_closed.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/threads_sidebar_right_open.svg b/assets/icons/threads_sidebar_right_open.svg
new file mode 100644
index 0000000000000000000000000000000000000000..23a01eb3f82a5866157220172c868ed9ded46033
--- /dev/null
+++ b/assets/icons/threads_sidebar_right_open.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/workspace_nav_closed.svg b/assets/icons/workspace_nav_closed.svg
deleted file mode 100644
index ed1fce52d6826a4d10299f331358ff84e4caa973..0000000000000000000000000000000000000000
--- a/assets/icons/workspace_nav_closed.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/assets/icons/workspace_nav_open.svg b/assets/icons/workspace_nav_open.svg
deleted file mode 100644
index 464b6aac73c2aeaa9463a805aabc4559377bbfd3..0000000000000000000000000000000000000000
--- a/assets/icons/workspace_nav_open.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json
index 0b354ef1c039c2fe7dde2f20bb30ef71f067e84d..56a51843ca9da052e39450ba38d8afcda9d1166d 100644
--- a/assets/keymaps/default-linux.json
+++ b/assets/keymaps/default-linux.json
@@ -226,8 +226,8 @@
"context": "ContextEditor > Editor",
"bindings": {
"ctrl-enter": "assistant::Assist",
- "ctrl-s": "workspace::Save",
"save": "workspace::Save",
+ "ctrl-s": "workspace::Save",
"ctrl-<": "assistant::InsertIntoEditor",
"shift-enter": "assistant::Split",
"ctrl-r": "assistant::CycleMessageRole",
@@ -258,6 +258,7 @@
"ctrl-shift-j": "agent::ToggleNavigationMenu",
"ctrl-alt-i": "agent::ToggleOptionsMenu",
"ctrl-alt-shift-n": "agent::ToggleNewThreadMenu",
+ "ctrl-shift-t": "agent::CycleStartThreadIn",
"shift-alt-escape": "agent::ExpandMessageEditor",
"ctrl->": "agent::AddSelectionToThread",
"ctrl-shift-e": "project_panel::ToggleFocus",
@@ -623,6 +624,7 @@
"ctrl-shift-t": "pane::ReopenClosedItem",
"ctrl-k ctrl-s": "zed::OpenKeymap",
"ctrl-k ctrl-t": "theme_selector::Toggle",
+ "ctrl-k ctrl-shift-t": "theme::ToggleMode",
"ctrl-alt-super-p": "settings_profile_selector::Toggle",
"ctrl-t": "project_symbols::Toggle",
"ctrl-p": "file_finder::Toggle",
@@ -818,7 +820,7 @@
},
},
{
- "context": "!ContextEditor > Editor && mode == full",
+ "context": "!ContextEditor && !AcpThread > Editor && mode == full",
"bindings": {
"alt-enter": "editor::OpenExcerpts",
"shift-enter": "editor::ExpandExcerpts",
@@ -982,6 +984,7 @@
"ctrl-shift-enter": "git::Amend",
"ctrl-space": "git::StageAll",
"ctrl-shift-space": "git::UnstageAll",
+ "ctrl-k ctrl-r": "git::RestoreAndNext",
},
},
{
diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json
index 052475ddb981c4db5495914096ffd72dee54d80f..a4aec7cfe8053f3f23b43652f7e58f319c9691f6 100644
--- a/assets/keymaps/default-macos.json
+++ b/assets/keymaps/default-macos.json
@@ -297,6 +297,7 @@
"cmd-shift-j": "agent::ToggleNavigationMenu",
"cmd-alt-m": "agent::ToggleOptionsMenu",
"cmd-alt-shift-n": "agent::ToggleNewThreadMenu",
+ "cmd-shift-t": "agent::CycleStartThreadIn",
"shift-alt-escape": "agent::ExpandMessageEditor",
"cmd->": "agent::AddSelectionToThread",
"cmd-shift-e": "project_panel::ToggleFocus",
@@ -690,6 +691,7 @@
"cmd-shift-t": "pane::ReopenClosedItem",
"cmd-k cmd-s": "zed::OpenKeymap",
"cmd-k cmd-t": "theme_selector::Toggle",
+ "cmd-k cmd-shift-t": "theme::ToggleMode",
"ctrl-alt-cmd-p": "settings_profile_selector::Toggle",
"cmd-t": "project_symbols::Toggle",
"cmd-p": "file_finder::Toggle",
@@ -881,7 +883,7 @@
},
},
{
- "context": "!ContextEditor > Editor && mode == full",
+ "context": "!ContextEditor && !AcpThread > Editor && mode == full",
"use_key_equivalents": true,
"bindings": {
"alt-enter": "editor::OpenExcerpts",
@@ -1033,6 +1035,7 @@
"cmd-shift-enter": "git::Amend",
"cmd-ctrl-y": "git::StageAll",
"cmd-ctrl-shift-y": "git::UnstageAll",
+ "cmd-alt-z": "git::RestoreAndNext",
},
},
{
diff --git a/assets/keymaps/default-windows.json b/assets/keymaps/default-windows.json
index ef2b339951382a44433372b34e7e62b082428362..c10054d5813c6deae33b7a790b3639e7f2c802aa 100644
--- a/assets/keymaps/default-windows.json
+++ b/assets/keymaps/default-windows.json
@@ -259,6 +259,7 @@
"shift-alt-j": "agent::ToggleNavigationMenu",
"shift-alt-i": "agent::ToggleOptionsMenu",
"ctrl-shift-alt-n": "agent::ToggleNewThreadMenu",
+ "ctrl-shift-t": "agent::CycleStartThreadIn",
"shift-alt-escape": "agent::ExpandMessageEditor",
"ctrl-shift-.": "agent::AddSelectionToThread",
"ctrl-shift-e": "project_panel::ToggleFocus",
@@ -615,6 +616,7 @@
"ctrl-shift-t": "pane::ReopenClosedItem",
"ctrl-k ctrl-s": "zed::OpenKeymap",
"ctrl-k ctrl-t": "theme_selector::Toggle",
+ "ctrl-k ctrl-shift-t": "theme::ToggleMode",
"ctrl-alt-super-p": "settings_profile_selector::Toggle",
"ctrl-t": "project_symbols::Toggle",
"ctrl-p": "file_finder::Toggle",
@@ -820,7 +822,7 @@
},
},
{
- "context": "!ContextEditor > Editor && mode == full",
+ "context": "!ContextEditor && !AcpThread > Editor && mode == full",
"use_key_equivalents": true,
"bindings": {
"alt-enter": "editor::OpenExcerpts",
@@ -983,6 +985,7 @@
"ctrl-shift-enter": "git::Amend",
"ctrl-space": "git::StageAll",
"ctrl-shift-space": "git::UnstageAll",
+ "ctrl-k ctrl-r": "git::RestoreAndNext",
},
},
{
diff --git a/assets/keymaps/linux/jetbrains.json b/assets/keymaps/linux/jetbrains.json
index bdf3949b3f9203220978ff599e0187513d6a976f..98d5cf93106f35e488ab70a60468fa2239cb08c0 100644
--- a/assets/keymaps/linux/jetbrains.json
+++ b/assets/keymaps/linux/jetbrains.json
@@ -81,6 +81,13 @@
"ctrl-\\": "assistant::InlineAssist",
},
},
+ {
+ "context": "Editor && mode == auto_height",
+ "bindings": {
+ "shift-enter": "editor::Newline",
+ "ctrl-shift-enter": "editor::NewlineBelow",
+ },
+ },
{
"context": "BufferSearchBar",
"bindings": {
diff --git a/assets/keymaps/macos/jetbrains.json b/assets/keymaps/macos/jetbrains.json
index c9106e4d49671f16917b1322824c2edfcd0e7700..304ffb86e8c2fd08fb756b015490f8c4ac424f58 100644
--- a/assets/keymaps/macos/jetbrains.json
+++ b/assets/keymaps/macos/jetbrains.json
@@ -33,6 +33,7 @@
"cmd-+": "editor::UnfoldLines",
"alt-shift-g": "editor::SplitSelectionIntoLines",
"ctrl-g": ["editor::SelectNext", { "replace_newest": false }],
+ "ctrl-shift-g": "editor::UndoSelection",
"ctrl-cmd-g": ["editor::SelectPrevious", { "replace_newest": false }],
"cmd-/": ["editor::ToggleComments", { "advance_downwards": true }],
"alt-up": "editor::SelectLargerSyntaxNode",
@@ -79,6 +80,13 @@
"cmd-\\": "assistant::InlineAssist",
},
},
+ {
+ "context": "Editor && mode == auto_height",
+ "bindings": {
+ "shift-enter": "editor::Newline",
+ "ctrl-shift-enter": "editor::NewlineBelow",
+ },
+ },
{
"context": "BufferSearchBar",
"bindings": {
diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json
index 1f2742f982bc2165181a797e577b350f5630def9..66693ab0a153a73af1dccb101e0ed36259b774fa 100644
--- a/assets/keymaps/vim.json
+++ b/assets/keymaps/vim.json
@@ -427,6 +427,7 @@
"escape": "vim::SwitchToHelixNormalMode",
"i": "vim::HelixInsert",
"a": "vim::HelixAppend",
+ "shift-a": "vim::HelixInsertEndOfLine",
"ctrl-[": "editor::Cancel",
},
},
diff --git a/assets/settings/default.json b/assets/settings/default.json
index 0a824bbe93a0d68a23d934a63eb1fdab1e2f1b02..7af6ce7e44d9abde7b29c80bb170cd13f3c2e786 100644
--- a/assets/settings/default.json
+++ b/assets/settings/default.json
@@ -768,6 +768,9 @@
// 5. Never show the scrollbar:
// "never"
"show": null,
+ // Whether to allow horizontal scrolling in the project panel.
+ // When false, the view is locked to the leftmost position and long file names are clipped.
+ "horizontal_scroll": true,
},
// Which files containing diagnostic errors/warnings to mark in the project panel.
// This setting can take the following three values:
@@ -920,8 +923,8 @@
},
// Whether to show the addition/deletion change count next to each file in the Git panel.
//
- // Default: false
- "diff_stats": false,
+ // Default: true
+ "diff_stats": true,
},
"message_editor": {
// Whether to automatically replace emoji shortcodes with emoji characters.
@@ -1282,6 +1285,8 @@
// * "indexed": Use only the files Zed had indexed
// * "smart": Be smart and search for ignored when called from a gitignored worktree
"include_ignored": "smart",
+ // Whether to include text channels in file finder results.
+ "include_channels": false,
},
// Whether or not to remove any trailing whitespace from lines of a buffer
// before saving it.
diff --git a/crates/acp_thread/Cargo.toml b/crates/acp_thread/Cargo.toml
index 83cf86bfafc33e4d1b520ca5af04da626831aed7..7ef53bc522708680e64cfcc9ce2860990bfd7d13 100644
--- a/crates/acp_thread/Cargo.toml
+++ b/crates/acp_thread/Cargo.toml
@@ -59,7 +59,5 @@ indoc.workspace = true
parking_lot.workspace = true
project = { workspace = true, "features" = ["test-support"] }
rand.workspace = true
-tempfile.workspace = true
util.workspace = true
settings.workspace = true
-zlog.workspace = true
diff --git a/crates/acp_thread/src/acp_thread.rs b/crates/acp_thread/src/acp_thread.rs
index 1b9271918884dc020986577926d9578e3a6f049c..95030443f642b019b27758f53fd413c5146857b1 100644
--- a/crates/acp_thread/src/acp_thread.rs
+++ b/crates/acp_thread/src/acp_thread.rs
@@ -952,8 +952,11 @@ struct RunningTurn {
}
pub struct AcpThread {
+ session_id: acp::SessionId,
+ cwd: Option,
parent_session_id: Option,
title: SharedString,
+ provisional_title: Option,
entries: Vec,
plan: Plan,
project: Entity,
@@ -962,7 +965,6 @@ pub struct AcpThread {
turn_id: u32,
running_turn: Option,
connection: Rc,
- session_id: acp::SessionId,
token_usage: Option,
prompt_capabilities: acp::PromptCapabilities,
_observe_prompt_capabilities: Task>,
@@ -1047,87 +1049,6 @@ pub enum TerminalProviderCommand {
},
}
-impl AcpThread {
- pub fn on_terminal_provider_event(
- &mut self,
- event: TerminalProviderEvent,
- cx: &mut Context,
- ) {
- match event {
- TerminalProviderEvent::Created {
- terminal_id,
- label,
- cwd,
- output_byte_limit,
- terminal,
- } => {
- let entity = self.register_terminal_created(
- terminal_id.clone(),
- label,
- cwd,
- output_byte_limit,
- terminal,
- cx,
- );
-
- if let Some(mut chunks) = self.pending_terminal_output.remove(&terminal_id) {
- for data in chunks.drain(..) {
- entity.update(cx, |term, cx| {
- term.inner().update(cx, |inner, cx| {
- inner.write_output(&data, cx);
- })
- });
- }
- }
-
- if let Some(_status) = self.pending_terminal_exit.remove(&terminal_id) {
- entity.update(cx, |_term, cx| {
- cx.notify();
- });
- }
-
- cx.notify();
- }
- TerminalProviderEvent::Output { terminal_id, data } => {
- if let Some(entity) = self.terminals.get(&terminal_id) {
- entity.update(cx, |term, cx| {
- term.inner().update(cx, |inner, cx| {
- inner.write_output(&data, cx);
- })
- });
- } else {
- self.pending_terminal_output
- .entry(terminal_id)
- .or_default()
- .push(data);
- }
- }
- TerminalProviderEvent::TitleChanged { terminal_id, title } => {
- if let Some(entity) = self.terminals.get(&terminal_id) {
- entity.update(cx, |term, cx| {
- term.inner().update(cx, |inner, cx| {
- inner.breadcrumb_text = title;
- cx.emit(::terminal::Event::BreadcrumbsChanged);
- })
- });
- }
- }
- TerminalProviderEvent::Exit {
- terminal_id,
- status,
- } => {
- if let Some(entity) = self.terminals.get(&terminal_id) {
- entity.update(cx, |_term, cx| {
- cx.notify();
- });
- } else {
- self.pending_terminal_exit.insert(terminal_id, status);
- }
- }
- }
- }
-}
-
#[derive(PartialEq, Eq, Debug)]
pub enum ThreadStatus {
Idle,
@@ -1174,6 +1095,7 @@ impl AcpThread {
pub fn new(
parent_session_id: Option,
title: impl Into,
+ cwd: Option,
connection: Rc,
project: Entity,
action_log: Entity,
@@ -1194,11 +1116,13 @@ impl AcpThread {
Self {
parent_session_id,
+ cwd,
action_log,
shared_buffers: Default::default(),
entries: Default::default(),
plan: Default::default(),
title: title.into(),
+ provisional_title: None,
project,
running_turn: None,
turn_id: 0,
@@ -1253,7 +1177,9 @@ impl AcpThread {
}
pub fn title(&self) -> SharedString {
- self.title.clone()
+ self.provisional_title
+ .clone()
+ .unwrap_or_else(|| self.title.clone())
}
pub fn entries(&self) -> &[AgentThreadEntry] {
@@ -1264,6 +1190,10 @@ impl AcpThread {
&self.session_id
}
+ pub fn cwd(&self) -> Option<&PathBuf> {
+ self.cwd.as_ref()
+ }
+
pub fn status(&self) -> ThreadStatus {
if self.running_turn.is_some() {
ThreadStatus::Generating
@@ -1505,16 +1435,29 @@ impl AcpThread {
}
pub fn set_title(&mut self, title: SharedString, cx: &mut Context) -> Task> {
+ let had_provisional = self.provisional_title.take().is_some();
if title != self.title {
self.title = title.clone();
cx.emit(AcpThreadEvent::TitleUpdated);
if let Some(set_title) = self.connection.set_title(&self.session_id, cx) {
return set_title.run(title, cx);
}
+ } else if had_provisional {
+ cx.emit(AcpThreadEvent::TitleUpdated);
}
Task::ready(Ok(()))
}
+ /// Sets a provisional display title without propagating back to the
+ /// underlying agent connection. This is used for quick preview titles
+ /// (e.g. first 20 chars of the user message) that should be shown
+ /// immediately but replaced once the LLM generates a proper title via
+ /// `set_title`.
+ pub fn set_provisional_title(&mut self, title: SharedString, cx: &mut Context) {
+ self.provisional_title = Some(title);
+ cx.emit(AcpThreadEvent::TitleUpdated);
+ }
+
pub fn subagent_spawned(&mut self, session_id: acp::SessionId, cx: &mut Context) {
cx.emit(AcpThreadEvent::SubagentSpawned(session_id));
}
@@ -2607,6 +2550,85 @@ impl AcpThread {
}
}
}
+
+ pub fn on_terminal_provider_event(
+ &mut self,
+ event: TerminalProviderEvent,
+ cx: &mut Context,
+ ) {
+ match event {
+ TerminalProviderEvent::Created {
+ terminal_id,
+ label,
+ cwd,
+ output_byte_limit,
+ terminal,
+ } => {
+ let entity = self.register_terminal_created(
+ terminal_id.clone(),
+ label,
+ cwd,
+ output_byte_limit,
+ terminal,
+ cx,
+ );
+
+ if let Some(mut chunks) = self.pending_terminal_output.remove(&terminal_id) {
+ for data in chunks.drain(..) {
+ entity.update(cx, |term, cx| {
+ term.inner().update(cx, |inner, cx| {
+ inner.write_output(&data, cx);
+ })
+ });
+ }
+ }
+
+ if let Some(_status) = self.pending_terminal_exit.remove(&terminal_id) {
+ entity.update(cx, |_term, cx| {
+ cx.notify();
+ });
+ }
+
+ cx.notify();
+ }
+ TerminalProviderEvent::Output { terminal_id, data } => {
+ if let Some(entity) = self.terminals.get(&terminal_id) {
+ entity.update(cx, |term, cx| {
+ term.inner().update(cx, |inner, cx| {
+ inner.write_output(&data, cx);
+ })
+ });
+ } else {
+ self.pending_terminal_output
+ .entry(terminal_id)
+ .or_default()
+ .push(data);
+ }
+ }
+ TerminalProviderEvent::TitleChanged { terminal_id, title } => {
+ if let Some(entity) = self.terminals.get(&terminal_id) {
+ entity.update(cx, |term, cx| {
+ term.inner().update(cx, |inner, cx| {
+ inner.breadcrumb_text = title;
+ cx.emit(::terminal::Event::BreadcrumbsChanged);
+ })
+ });
+ }
+ }
+ TerminalProviderEvent::Exit {
+ terminal_id,
+ status,
+ } => {
+ if let Some(entity) = self.terminals.get(&terminal_id) {
+ entity.update(cx, |_term, cx| {
+ cx.notify();
+ });
+ } else {
+ self.pending_terminal_exit.insert(terminal_id, status);
+ }
+ }
+ }
+ }
}
fn markdown_for_raw_output(
@@ -3916,6 +3938,7 @@ mod tests {
struct FakeAgentConnection {
auth_methods: Vec,
sessions: Arc>>>,
+ set_title_calls: Rc>>,
on_user_message: Option<
Rc<
dyn Fn(
@@ -3934,6 +3957,7 @@ mod tests {
auth_methods: Vec::new(),
on_user_message: None,
sessions: Arc::default(),
+ set_title_calls: Default::default(),
}
}
@@ -3969,7 +3993,7 @@ mod tests {
fn new_session(
self: Rc,
project: Entity,
- _cwd: &Path,
+ cwd: &Path,
cx: &mut App,
) -> Task>> {
let session_id = acp::SessionId::new(
@@ -3984,6 +4008,7 @@ mod tests {
AcpThread::new(
None,
"Test",
+ Some(cwd.to_path_buf()),
self.clone(),
project,
action_log,
@@ -4002,7 +4027,7 @@ mod tests {
}
fn authenticate(&self, method: acp::AuthMethodId, _cx: &mut App) -> Task> {
- if self.auth_methods().iter().any(|m| m.id == method) {
+ if self.auth_methods().iter().any(|m| m.id() == &method) {
Task::ready(Ok(()))
} else {
Task::ready(Err(anyhow!("Invalid Auth Method")))
@@ -4038,11 +4063,32 @@ mod tests {
}))
}
+ fn set_title(
+ &self,
+ _session_id: &acp::SessionId,
+ _cx: &App,
+ ) -> Option> {
+ Some(Rc::new(FakeAgentSessionSetTitle {
+ calls: self.set_title_calls.clone(),
+ }))
+ }
+
fn into_any(self: Rc) -> Rc {
self
}
}
+ struct FakeAgentSessionSetTitle {
+ calls: Rc>>,
+ }
+
+ impl AgentSessionSetTitle for FakeAgentSessionSetTitle {
+ fn run(&self, title: SharedString, _cx: &mut App) -> Task> {
+ self.calls.borrow_mut().push(title);
+ Task::ready(Ok(()))
+ }
+ }
+
struct FakeAgentSessionEditor {
_session_id: acp::SessionId,
}
@@ -4634,4 +4680,54 @@ mod tests {
);
});
}
+
+ #[gpui::test]
+ async fn test_provisional_title_replaced_by_real_title(cx: &mut TestAppContext) {
+ init_test(cx);
+
+ let fs = FakeFs::new(cx.executor());
+ let project = Project::test(fs, [], cx).await;
+ let connection = Rc::new(FakeAgentConnection::new());
+ let set_title_calls = connection.set_title_calls.clone();
+
+ let thread = cx
+ .update(|cx| connection.new_session(project, Path::new(path!("/test")), cx))
+ .await
+ .unwrap();
+
+ // Initial title is the default.
+ thread.read_with(cx, |thread, _| {
+ assert_eq!(thread.title().as_ref(), "Test");
+ });
+
+ // Setting a provisional title updates the display title.
+ thread.update(cx, |thread, cx| {
+ thread.set_provisional_title("Hello, can you help…".into(), cx);
+ });
+ thread.read_with(cx, |thread, _| {
+ assert_eq!(thread.title().as_ref(), "Hello, can you help…");
+ });
+
+ // The provisional title should NOT have propagated to the connection.
+ assert_eq!(
+ set_title_calls.borrow().len(),
+ 0,
+ "provisional title should not propagate to the connection"
+ );
+
+ // When the real title arrives via set_title, it replaces the
+ // provisional title and propagates to the connection.
+ let task = thread.update(cx, |thread, cx| {
+ thread.set_title("Helping with Rust question".into(), cx)
+ });
+ task.await.expect("set_title should succeed");
+ thread.read_with(cx, |thread, _| {
+ assert_eq!(thread.title().as_ref(), "Helping with Rust question");
+ });
+ assert_eq!(
+ set_title_calls.borrow().as_slice(),
+ &[SharedString::from("Helping with Rust question")],
+ "real title should propagate to the connection"
+ );
+ }
}
diff --git a/crates/acp_thread/src/connection.rs b/crates/acp_thread/src/connection.rs
index 773508f1c898c39d713d5779c82384caf8f190ec..4f6aaf86bad68f919c2c5de30214b21ff851c3dd 100644
--- a/crates/acp_thread/src/connection.rs
+++ b/crates/acp_thread/src/connection.rs
@@ -45,9 +45,10 @@ pub trait AgentConnection {
/// Load an existing session by ID.
fn load_session(
self: Rc,
- _session: AgentSessionInfo,
+ _session_id: acp::SessionId,
_project: Entity,
_cwd: &Path,
+ _title: Option,
_cx: &mut App,
) -> Task>> {
Task::ready(Err(anyhow::Error::msg("Loading sessions is not supported")))
@@ -59,7 +60,11 @@ pub trait AgentConnection {
}
/// Close an existing session. Allows the agent to free the session from memory.
- fn close_session(&self, _session_id: &acp::SessionId, _cx: &mut App) -> Task> {
+ fn close_session(
+ self: Rc,
+ _session_id: &acp::SessionId,
+ _cx: &mut App,
+ ) -> Task> {
Task::ready(Err(anyhow::Error::msg("Closing sessions is not supported")))
}
@@ -71,9 +76,10 @@ pub trait AgentConnection {
/// Resume an existing session by ID without replaying previous messages.
fn resume_session(
self: Rc,
- _session: AgentSessionInfo,
+ _session_id: acp::SessionId,
_project: Entity,
_cwd: &Path,
+ _title: Option,
_cx: &mut App,
) -> Task>> {
Task::ready(Err(anyhow::Error::msg(
@@ -240,6 +246,7 @@ pub struct AgentSessionInfo {
pub cwd: Option,
pub title: Option,
pub updated_at: Option>,
+ pub created_at: Option>,
pub meta: Option,
}
@@ -250,6 +257,7 @@ impl AgentSessionInfo {
cwd: None,
title: None,
updated_at: None,
+ created_at: None,
meta: None,
}
}
@@ -619,7 +627,7 @@ mod test_support {
fn new_session(
self: Rc,
project: Entity,
- _cwd: &Path,
+ cwd: &Path,
cx: &mut gpui::App,
) -> Task>> {
static NEXT_SESSION_ID: AtomicUsize = AtomicUsize::new(0);
@@ -630,6 +638,7 @@ mod test_support {
AcpThread::new(
None,
"Test",
+ Some(cwd.to_path_buf()),
self.clone(),
project,
action_log,
diff --git a/crates/acp_thread/src/mention.rs b/crates/acp_thread/src/mention.rs
index b63eec154a40de8909d13de2a4e1bd3e9d1e06f3..43dfe7610e34a0399a27a1d28858b938acfc2e0f 100644
--- a/crates/acp_thread/src/mention.rs
+++ b/crates/acp_thread/src/mention.rs
@@ -60,6 +60,9 @@ pub enum MentionUri {
GitDiff {
base_ref: String,
},
+ MergeConflict {
+ file_path: String,
+ },
}
impl MentionUri {
@@ -215,6 +218,9 @@ impl MentionUri {
let base_ref =
single_query_param(&url, "base")?.unwrap_or_else(|| "main".to_string());
Ok(Self::GitDiff { base_ref })
+ } else if path.starts_with("/agent/merge-conflict") {
+ let file_path = single_query_param(&url, "path")?.unwrap_or_default();
+ Ok(Self::MergeConflict { file_path })
} else {
bail!("invalid zed url: {:?}", input);
}
@@ -245,6 +251,13 @@ impl MentionUri {
}
}
MentionUri::GitDiff { base_ref } => format!("Branch Diff ({})", base_ref),
+ MentionUri::MergeConflict { file_path } => {
+ let name = Path::new(file_path)
+ .file_name()
+ .unwrap_or_default()
+ .to_string_lossy();
+ format!("Merge Conflict ({name})")
+ }
MentionUri::Selection {
abs_path: path,
line_range,
@@ -306,6 +319,7 @@ impl MentionUri {
MentionUri::Selection { .. } => IconName::Reader.path().into(),
MentionUri::Fetch { .. } => IconName::ToolWeb.path().into(),
MentionUri::GitDiff { .. } => IconName::GitBranch.path().into(),
+ MentionUri::MergeConflict { .. } => IconName::GitMergeConflict.path().into(),
}
}
@@ -409,6 +423,11 @@ impl MentionUri {
url.query_pairs_mut().append_pair("base", base_ref);
url
}
+ MentionUri::MergeConflict { file_path } => {
+ let mut url = Url::parse("zed:///agent/merge-conflict").unwrap();
+ url.query_pairs_mut().append_pair("path", file_path);
+ url
+ }
}
}
}
diff --git a/crates/action_log/Cargo.toml b/crates/action_log/Cargo.toml
index b1a1bf824fb770b8378e596fd0c799a7cf98b13d..5227a61651012279e83a3b6e3e68b1484acb0f66 100644
--- a/crates/action_log/Cargo.toml
+++ b/crates/action_log/Cargo.toml
@@ -37,7 +37,7 @@ collections = { workspace = true, features = ["test-support"] }
clock = { workspace = true, features = ["test-support"] }
ctor.workspace = true
gpui = { workspace = true, features = ["test-support"] }
-indoc.workspace = true
+
language = { workspace = true, features = ["test-support"] }
log.workspace = true
pretty_assertions.workspace = true
diff --git a/crates/action_log/src/action_log.rs b/crates/action_log/src/action_log.rs
index 5679f3c58fe52057f7a4a0faa24d5b5db2b5e497..3faf767c7020763eadc7db6c93af42f650a07434 100644
--- a/crates/action_log/src/action_log.rs
+++ b/crates/action_log/src/action_log.rs
@@ -209,7 +209,7 @@ impl ActionLog {
cx: &mut Context,
) {
match event {
- BufferEvent::Edited => {
+ BufferEvent::Edited { .. } => {
let Some(tracked_buffer) = self.tracked_buffers.get_mut(&buffer) else {
return;
};
@@ -1028,6 +1028,11 @@ impl ActionLog {
.collect()
}
+ /// Returns the total number of lines added and removed across all unreviewed buffers.
+ pub fn diff_stats(&self, cx: &App) -> DiffStats {
+ DiffStats::all_files(&self.changed_buffers(cx), cx)
+ }
+
/// Iterate over buffers changed since last read or edited by the model
pub fn stale_buffers<'a>(&'a self, cx: &'a App) -> impl Iterator- > {
self.tracked_buffers
@@ -1044,6 +1049,46 @@ impl ActionLog {
}
}
+#[derive(Default, Debug, Clone, Copy)]
+pub struct DiffStats {
+ pub lines_added: u32,
+ pub lines_removed: u32,
+}
+
+impl DiffStats {
+ pub fn single_file(buffer: &Buffer, diff: &BufferDiff, cx: &App) -> Self {
+ let mut stats = DiffStats::default();
+ let diff_snapshot = diff.snapshot(cx);
+ let buffer_snapshot = buffer.snapshot();
+ let base_text = diff_snapshot.base_text();
+
+ for hunk in diff_snapshot.hunks(&buffer_snapshot) {
+ let added_rows = hunk.range.end.row.saturating_sub(hunk.range.start.row);
+ stats.lines_added += added_rows;
+
+ let base_start = hunk.diff_base_byte_range.start.to_point(base_text).row;
+ let base_end = hunk.diff_base_byte_range.end.to_point(base_text).row;
+ let removed_rows = base_end.saturating_sub(base_start);
+ stats.lines_removed += removed_rows;
+ }
+
+ stats
+ }
+
+ pub fn all_files(
+ changed_buffers: &BTreeMap, Entity>,
+ cx: &App,
+ ) -> Self {
+ let mut total = DiffStats::default();
+ for (buffer, diff) in changed_buffers {
+ let stats = DiffStats::single_file(buffer.read(cx), diff.read(cx), cx);
+ total.lines_added += stats.lines_added;
+ total.lines_removed += stats.lines_removed;
+ }
+ total
+ }
+}
+
#[derive(Clone)]
pub struct ActionLogTelemetry {
pub agent_telemetry_id: SharedString,
diff --git a/crates/activity_indicator/Cargo.toml b/crates/activity_indicator/Cargo.toml
index 99ae5b5b077a14c0909737d64935220698a007c7..ce53f23365d57666e25cac434935514fc4bd7e3f 100644
--- a/crates/activity_indicator/Cargo.toml
+++ b/crates/activity_indicator/Cargo.toml
@@ -30,4 +30,4 @@ workspace.workspace = true
[dev-dependencies]
editor = { workspace = true, features = ["test-support"] }
-release_channel.workspace = true
+
diff --git a/crates/agent/Cargo.toml b/crates/agent/Cargo.toml
index 9f563cf0b1b009a496d36a6f090b0f4b476433a7..fe2089d94dc2e3fc812f6cbe39c16c5cadc1a1f5 100644
--- a/crates/agent/Cargo.toml
+++ b/crates/agent/Cargo.toml
@@ -100,9 +100,9 @@ rand.workspace = true
reqwest_client.workspace = true
settings = { workspace = true, "features" = ["test-support"] }
tempfile.workspace = true
-terminal = { workspace = true, "features" = ["test-support"] }
+
theme = { workspace = true, "features" = ["test-support"] }
-tree-sitter-rust.workspace = true
+
unindent = { workspace = true }
-worktree = { workspace = true, "features" = ["test-support"] }
+
zlog.workspace = true
diff --git a/crates/agent/src/agent.rs b/crates/agent/src/agent.rs
index a93c2d2062b7472f8ed94a6ea0947a685edd204f..2ac341dc997b016f3e723fad99a4a57007510c52 100644
--- a/crates/agent/src/agent.rs
+++ b/crates/agent/src/agent.rs
@@ -37,7 +37,8 @@ use futures::channel::{mpsc, oneshot};
use futures::future::Shared;
use futures::{FutureExt as _, StreamExt as _, future};
use gpui::{
- App, AppContext, AsyncApp, Context, Entity, SharedString, Subscription, Task, WeakEntity,
+ App, AppContext, AsyncApp, Context, Entity, EntityId, SharedString, Subscription, Task,
+ WeakEntity,
};
use language_model::{IconOrSvg, LanguageModel, LanguageModelProvider, LanguageModelRegistry};
use project::{Project, ProjectItem, ProjectPath, Worktree};
@@ -65,12 +66,22 @@ pub struct RulesLoadingError {
pub message: SharedString,
}
+struct ProjectState {
+ project: Entity,
+ project_context: Entity,
+ project_context_needs_refresh: watch::Sender<()>,
+ _maintain_project_context: Task>,
+ context_server_registry: Entity,
+ _subscriptions: Vec,
+}
+
/// Holds both the internal Thread and the AcpThread for a session
struct Session {
/// The internal thread that processes messages
thread: Entity,
/// The ACP thread that handles protocol communication
acp_thread: Entity,
+ project_id: EntityId,
pending_save: Task<()>,
_subscriptions: Vec,
}
@@ -235,79 +246,47 @@ pub struct NativeAgent {
/// Session ID -> Session mapping
sessions: HashMap,
thread_store: Entity,
- /// Shared project context for all threads
- project_context: Entity,
- project_context_needs_refresh: watch::Sender<()>,
- _maintain_project_context: Task>,
- context_server_registry: Entity,
+ /// Project-specific state keyed by project EntityId
+ projects: HashMap,
/// Shared templates for all threads
templates: Arc,
/// Cached model information
models: LanguageModels,
- project: Entity,
prompt_store: Option>,
fs: Arc,
_subscriptions: Vec,
}
impl NativeAgent {
- pub async fn new(
- project: Entity,
+ pub fn new(
thread_store: Entity,
templates: Arc,
prompt_store: Option>,
fs: Arc,
- cx: &mut AsyncApp,
- ) -> Result> {
+ cx: &mut App,
+ ) -> Entity {
log::debug!("Creating new NativeAgent");
- let project_context = cx
- .update(|cx| Self::build_project_context(&project, prompt_store.as_ref(), cx))
- .await;
-
- Ok(cx.new(|cx| {
- let context_server_store = project.read(cx).context_server_store();
- let context_server_registry =
- cx.new(|cx| ContextServerRegistry::new(context_server_store.clone(), cx));
-
- let mut subscriptions = vec![
- cx.subscribe(&project, Self::handle_project_event),
- cx.subscribe(
- &LanguageModelRegistry::global(cx),
- Self::handle_models_updated_event,
- ),
- cx.subscribe(
- &context_server_store,
- Self::handle_context_server_store_updated,
- ),
- cx.subscribe(
- &context_server_registry,
- Self::handle_context_server_registry_event,
- ),
- ];
+ cx.new(|cx| {
+ let mut subscriptions = vec![cx.subscribe(
+ &LanguageModelRegistry::global(cx),
+ Self::handle_models_updated_event,
+ )];
if let Some(prompt_store) = prompt_store.as_ref() {
subscriptions.push(cx.subscribe(prompt_store, Self::handle_prompts_updated_event))
}
- let (project_context_needs_refresh_tx, project_context_needs_refresh_rx) =
- watch::channel(());
Self {
sessions: HashMap::default(),
thread_store,
- project_context: cx.new(|_| project_context),
- project_context_needs_refresh: project_context_needs_refresh_tx,
- _maintain_project_context: cx.spawn(async move |this, cx| {
- Self::maintain_project_context(this, project_context_needs_refresh_rx, cx).await
- }),
- context_server_registry,
+ projects: HashMap::default(),
templates,
models: LanguageModels::new(cx),
- project,
prompt_store,
fs,
_subscriptions: subscriptions,
}
- }))
+ })
}
fn new_session(
@@ -315,10 +294,10 @@ impl NativeAgent {
project: Entity,
cx: &mut Context,
) -> Entity {
- // Create Thread
- // Fetch default model from registry settings
+ let project_id = self.get_or_create_project_state(&project, cx);
+ let project_state = &self.projects[&project_id];
+
let registry = LanguageModelRegistry::read_global(cx);
- // Log available models for debugging
let available_count = registry.available_models(cx).count();
log::debug!("Total available models: {}", available_count);
@@ -328,21 +307,22 @@ impl NativeAgent {
});
let thread = cx.new(|cx| {
Thread::new(
- project.clone(),
- self.project_context.clone(),
- self.context_server_registry.clone(),
+ project,
+ project_state.project_context.clone(),
+ project_state.context_server_registry.clone(),
self.templates.clone(),
default_model,
cx,
)
});
- self.register_session(thread, cx)
+ self.register_session(thread, project_id, cx)
}
fn register_session(
&mut self,
thread_handle: Entity,
+ project_id: EntityId,
cx: &mut Context,
) -> Entity {
let connection = Rc::new(NativeAgentConnection(cx.entity()));
@@ -361,6 +341,7 @@ impl NativeAgent {
let mut acp_thread = acp_thread::AcpThread::new(
parent_session_id,
title,
+ None,
connection,
project.clone(),
action_log.clone(),
@@ -404,12 +385,13 @@ impl NativeAgent {
Session {
thread: thread_handle,
acp_thread: acp_thread.clone(),
+ project_id,
_subscriptions: subscriptions,
pending_save: Task::ready(()),
},
);
- self.update_available_commands(cx);
+ self.update_available_commands_for_project(project_id, cx);
acp_thread
}
@@ -418,19 +400,102 @@ impl NativeAgent {
&self.models
}
+ fn get_or_create_project_state(
+ &mut self,
+ project: &Entity,
+ cx: &mut Context,
+ ) -> EntityId {
+ let project_id = project.entity_id();
+ if self.projects.contains_key(&project_id) {
+ return project_id;
+ }
+
+ let project_context = cx.new(|_| ProjectContext::new(vec![], vec![]));
+ self.register_project_with_initial_context(project.clone(), project_context, cx);
+ if let Some(state) = self.projects.get_mut(&project_id) {
+ state.project_context_needs_refresh.send(()).ok();
+ }
+ project_id
+ }
+
+ fn register_project_with_initial_context(
+ &mut self,
+ project: Entity,
+ project_context: Entity,
+ cx: &mut Context,
+ ) {
+ let project_id = project.entity_id();
+
+ let context_server_store = project.read(cx).context_server_store();
+ let context_server_registry =
+ cx.new(|cx| ContextServerRegistry::new(context_server_store.clone(), cx));
+
+ let subscriptions = vec![
+ cx.subscribe(&project, Self::handle_project_event),
+ cx.subscribe(
+ &context_server_store,
+ Self::handle_context_server_store_updated,
+ ),
+ cx.subscribe(
+ &context_server_registry,
+ Self::handle_context_server_registry_event,
+ ),
+ ];
+
+ let (project_context_needs_refresh_tx, project_context_needs_refresh_rx) =
+ watch::channel(());
+
+ self.projects.insert(
+ project_id,
+ ProjectState {
+ project,
+ project_context,
+ project_context_needs_refresh: project_context_needs_refresh_tx,
+ _maintain_project_context: cx.spawn(async move |this, cx| {
+ Self::maintain_project_context(
+ this,
+ project_id,
+ project_context_needs_refresh_rx,
+ cx,
+ )
+ .await
+ }),
+ context_server_registry,
+ _subscriptions: subscriptions,
+ },
+ );
+ }
+
+ fn session_project_state(&self, session_id: &acp::SessionId) -> Option<&ProjectState> {
+ self.sessions
+ .get(session_id)
+ .and_then(|session| self.projects.get(&session.project_id))
+ }
+
async fn maintain_project_context(
this: WeakEntity,
+ project_id: EntityId,
mut needs_refresh: watch::Receiver<()>,
cx: &mut AsyncApp,
) -> Result<()> {
while needs_refresh.changed().await.is_ok() {
let project_context = this
.update(cx, |this, cx| {
- Self::build_project_context(&this.project, this.prompt_store.as_ref(), cx)
- })?
+ let state = this
+ .projects
+ .get(&project_id)
+ .context("project state not found")?;
+ anyhow::Ok(Self::build_project_context(
+ &state.project,
+ this.prompt_store.as_ref(),
+ cx,
+ ))
+ })??
.await;
this.update(cx, |this, cx| {
- this.project_context = cx.new(|_| project_context);
+ if let Some(state) = this.projects.get_mut(&project_id) {
+ state.project_context = cx.new(|_| project_context);
+ }
})?;
}
@@ -619,13 +684,17 @@ impl NativeAgent {
fn handle_project_event(
&mut self,
- _project: Entity,
+ project: Entity,
event: &project::Event,
_cx: &mut Context,
) {
+ let project_id = project.entity_id();
+ let Some(state) = self.projects.get_mut(&project_id) else {
+ return;
+ };
match event {
project::Event::WorktreeAdded(_) | project::Event::WorktreeRemoved(_) => {
- self.project_context_needs_refresh.send(()).ok();
+ state.project_context_needs_refresh.send(()).ok();
}
project::Event::WorktreeUpdatedEntries(_, items) => {
if items.iter().any(|(path, _, _)| {
@@ -633,7 +702,7 @@ impl NativeAgent {
.iter()
.any(|name| path.as_ref() == RelPath::unix(name).unwrap())
}) {
- self.project_context_needs_refresh.send(()).ok();
+ state.project_context_needs_refresh.send(()).ok();
}
}
_ => {}
@@ -646,7 +715,9 @@ impl NativeAgent {
_event: &prompt_store::PromptsUpdatedEvent,
_cx: &mut Context,
) {
- self.project_context_needs_refresh.send(()).ok();
+ for state in self.projects.values_mut() {
+ state.project_context_needs_refresh.send(()).ok();
+ }
}
fn handle_models_updated_event(
@@ -676,30 +747,52 @@ impl NativeAgent {
fn handle_context_server_store_updated(
&mut self,
- _store: Entity,
+ store: Entity,
_event: &project::context_server_store::ServerStatusChangedEvent,
cx: &mut Context,
) {
- self.update_available_commands(cx);
+ let project_id = self.projects.iter().find_map(|(id, state)| {
+ if *state.context_server_registry.read(cx).server_store() == store {
+ Some(*id)
+ } else {
+ None
+ }
+ });
+ if let Some(project_id) = project_id {
+ self.update_available_commands_for_project(project_id, cx);
+ }
}
fn handle_context_server_registry_event(
&mut self,
- _registry: Entity,
+ registry: Entity,
event: &ContextServerRegistryEvent,
cx: &mut Context,
) {
match event {
ContextServerRegistryEvent::ToolsChanged => {}
ContextServerRegistryEvent::PromptsChanged => {
- self.update_available_commands(cx);
+ let project_id = self.projects.iter().find_map(|(id, state)| {
+ if state.context_server_registry == registry {
+ Some(*id)
+ } else {
+ None
+ }
+ });
+ if let Some(project_id) = project_id {
+ self.update_available_commands_for_project(project_id, cx);
+ }
}
}
}
- fn update_available_commands(&self, cx: &mut Context) {
- let available_commands = self.build_available_commands(cx);
+ fn update_available_commands_for_project(&self, project_id: EntityId, cx: &mut Context) {
+ let available_commands =
+ Self::build_available_commands_for_project(self.projects.get(&project_id), cx);
for session in self.sessions.values() {
+ if session.project_id != project_id {
+ continue;
+ }
session.acp_thread.update(cx, |thread, cx| {
thread
.handle_session_update(
@@ -713,8 +806,14 @@ impl NativeAgent {
}
}
- fn build_available_commands(&self, cx: &App) -> Vec {
- let registry = self.context_server_registry.read(cx);
+ fn build_available_commands_for_project(
+ project_state: Option<&ProjectState>,
+ cx: &App,
+ ) -> Vec {
+ let Some(state) = project_state else {
+ return vec![];
+ };
+ let registry = state.context_server_registry.read(cx);
let mut prompt_name_counts: HashMap<&str, usize> = HashMap::default();
for context_server_prompt in registry.prompts() {
@@ -768,6 +867,7 @@ impl NativeAgent {
pub fn load_thread(
&mut self,
id: acp::SessionId,
+ project: Entity,
cx: &mut Context,
) -> Task>> {
let database_future = ThreadsDatabase::connect(cx);
@@ -779,41 +879,49 @@ impl NativeAgent {
.with_context(|| format!("no thread found with ID: {id:?}"))?;
this.update(cx, |this, cx| {
+ let project_id = this.get_or_create_project_state(&project, cx);
+ let project_state = this
+ .projects
+ .get(&project_id)
+ .context("project state not found")?;
let summarization_model = LanguageModelRegistry::read_global(cx)
.thread_summary_model()
.map(|c| c.model);
- cx.new(|cx| {
+ Ok(cx.new(|cx| {
let mut thread = Thread::from_db(
id.clone(),
db_thread,
- this.project.clone(),
- this.project_context.clone(),
- this.context_server_registry.clone(),
+ project_state.project.clone(),
+ project_state.project_context.clone(),
+ project_state.context_server_registry.clone(),
this.templates.clone(),
cx,
);
thread.set_summarization_model(summarization_model, cx);
thread
- })
- })
+ }))
+ })?
})
}
pub fn open_thread(
&mut self,
id: acp::SessionId,
+ project: Entity,
cx: &mut Context,
) -> Task>> {
if let Some(session) = self.sessions.get(&id) {
return Task::ready(Ok(session.acp_thread.clone()));
}
- let task = self.load_thread(id, cx);
+ let task = self.load_thread(id, project.clone(), cx);
cx.spawn(async move |this, cx| {
let thread = task.await?;
- let acp_thread =
- this.update(cx, |this, cx| this.register_session(thread.clone(), cx))?;
+ let acp_thread = this.update(cx, |this, cx| {
+ let project_id = this.get_or_create_project_state(&project, cx);
+ this.register_session(thread.clone(), project_id, cx)
+ })?;
let events = thread.update(cx, |thread, cx| thread.replay(cx));
cx.update(|cx| {
NativeAgentConnection::handle_thread_events(events, acp_thread.downgrade(), cx)
@@ -826,9 +934,10 @@ impl NativeAgent {
pub fn thread_summary(
&mut self,
id: acp::SessionId,
+ project: Entity,
cx: &mut Context,
) -> Task> {
- let thread = self.open_thread(id.clone(), cx);
+ let thread = self.open_thread(id.clone(), project, cx);
cx.spawn(async move |this, cx| {
let acp_thread = thread.await?;
let result = this
@@ -856,8 +965,13 @@ impl NativeAgent {
return;
};
+ let project_id = session.project_id;
+ let Some(state) = self.projects.get(&project_id) else {
+ return;
+ };
+
let folder_paths = PathList::new(
- &self
+ &state
.project
.read(cx)
.visible_worktrees(cx)
@@ -888,15 +1002,22 @@ impl NativeAgent {
fn send_mcp_prompt(
&self,
message_id: UserMessageId,
- session_id: agent_client_protocol::SessionId,
+ session_id: acp::SessionId,
prompt_name: String,
server_id: ContextServerId,
arguments: HashMap,
original_content: Vec,
cx: &mut Context,
) -> Task> {
- let server_store = self.context_server_registry.read(cx).server_store().clone();
- let path_style = self.project.read(cx).path_style(cx);
+ let Some(state) = self.session_project_state(&session_id) else {
+ return Task::ready(Err(anyhow!("Project state not found for session")));
+ };
+ let server_store = state
+ .context_server_registry
+ .read(cx)
+ .server_store()
+ .clone();
+ let path_style = state.project.read(cx).path_style(cx);
cx.spawn(async move |this, cx| {
let prompt =
@@ -995,8 +1116,14 @@ impl NativeAgentConnection {
.map(|session| session.thread.clone())
}
- pub fn load_thread(&self, id: acp::SessionId, cx: &mut App) -> Task>> {
- self.0.update(cx, |this, cx| this.load_thread(id, cx))
+ pub fn load_thread(
+ &self,
+ id: acp::SessionId,
+ project: Entity,
+ cx: &mut App,
+ ) -> Task>> {
+ self.0
+ .update(cx, |this, cx| this.load_thread(id, project, cx))
}
fn run_turn(
@@ -1277,22 +1404,35 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
fn load_session(
self: Rc,
- session: AgentSessionInfo,
- _project: Entity,
+ session_id: acp::SessionId,
+ project: Entity,
_cwd: &Path,
+ _title: Option,
cx: &mut App,
) -> Task>> {
self.0
- .update(cx, |agent, cx| agent.open_thread(session.session_id, cx))
+ .update(cx, |agent, cx| agent.open_thread(session_id, project, cx))
}
fn supports_close_session(&self) -> bool {
true
}
- fn close_session(&self, session_id: &acp::SessionId, cx: &mut App) -> Task> {
+ fn close_session(
+ self: Rc,
+ session_id: &acp::SessionId,
+ cx: &mut App,
+ ) -> Task> {
self.0.update(cx, |agent, _cx| {
+ let project_id = agent.sessions.get(session_id).map(|s| s.project_id);
agent.sessions.remove(session_id);
+
+ if let Some(project_id) = project_id {
+ let has_remaining = agent.sessions.values().any(|s| s.project_id == project_id);
+ if !has_remaining {
+ agent.projects.remove(&project_id);
+ }
+ }
});
Task::ready(Ok(()))
}
@@ -1323,8 +1463,12 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
log::info!("Received prompt request for session: {}", session_id);
log::debug!("Prompt blocks count: {}", params.prompt.len());
+ let Some(project_state) = self.0.read(cx).session_project_state(&session_id) else {
+ return Task::ready(Err(anyhow::anyhow!("Session not found")));
+ };
+
if let Some(parsed_command) = Command::parse(¶ms.prompt) {
- let registry = self.0.read(cx).context_server_registry.read(cx);
+ let registry = project_state.context_server_registry.read(cx);
let explicit_server_id = parsed_command
.explicit_server_id
@@ -1360,10 +1504,10 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
cx,
)
});
- };
+ }
};
- let path_style = self.0.read(cx).project.read(cx).path_style(cx);
+ let path_style = project_state.project.read(cx).path_style(cx);
self.run_turn(session_id, cx, move |thread, cx| {
let content: Vec = params
@@ -1404,7 +1548,7 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
fn truncate(
&self,
- session_id: &agent_client_protocol::SessionId,
+ session_id: &acp::SessionId,
cx: &App,
) -> Option> {
self.0.read_with(cx, |agent, _cx| {
@@ -1609,6 +1753,7 @@ impl NativeThreadEnvironment {
};
let parent_thread = parent_thread_entity.read(cx);
let current_depth = parent_thread.depth();
+ let parent_session_id = parent_thread.id().clone();
if current_depth >= MAX_SUBAGENT_DEPTH {
return Err(anyhow!(
@@ -1625,9 +1770,16 @@ impl NativeThreadEnvironment {
let session_id = subagent_thread.read(cx).id().clone();
- let acp_thread = self.agent.update(cx, |agent, cx| {
- agent.register_session(subagent_thread.clone(), cx)
- })?;
+ let acp_thread = self
+ .agent
+ .update(cx, |agent, cx| -> Result> {
+ let project_id = agent
+ .sessions
+ .get(&parent_session_id)
+ .map(|s| s.project_id)
+ .context("parent session not found")?;
+ Ok(agent.register_session(subagent_thread.clone(), project_id, cx))
+ })??;
let depth = current_depth + 1;
@@ -1953,18 +2105,21 @@ mod internal_tests {
.await;
let project = Project::test(fs.clone(), [], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let agent = NativeAgent::new(
- project.clone(),
- thread_store,
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent =
+ cx.update(|cx| NativeAgent::new(thread_store, Templates::new(), None, fs.clone(), cx));
+
+ // Creating a session registers the project and triggers context building.
+ let connection = NativeAgentConnection(agent.clone());
+ let _acp_thread = cx
+ .update(|cx| Rc::new(connection).new_session(project.clone(), Path::new("/"), cx))
+ .await
+ .unwrap();
+ cx.run_until_parked();
+
agent.read_with(cx, |agent, cx| {
- assert_eq!(agent.project_context.read(cx).worktrees, vec![])
+ let project_id = project.entity_id();
+ let state = agent.projects.get(&project_id).unwrap();
+ assert_eq!(state.project_context.read(cx).worktrees, vec![])
});
let worktree = project
@@ -1973,8 +2128,10 @@ mod internal_tests {
.unwrap();
cx.run_until_parked();
agent.read_with(cx, |agent, cx| {
+ let project_id = project.entity_id();
+ let state = agent.projects.get(&project_id).unwrap();
assert_eq!(
- agent.project_context.read(cx).worktrees,
+ state.project_context.read(cx).worktrees,
vec![WorktreeContext {
root_name: "a".into(),
abs_path: Path::new("/a").into(),
@@ -1987,12 +2144,14 @@ mod internal_tests {
fs.insert_file("/a/.rules", Vec::new()).await;
cx.run_until_parked();
agent.read_with(cx, |agent, cx| {
+ let project_id = project.entity_id();
+ let state = agent.projects.get(&project_id).unwrap();
let rules_entry = worktree
.read(cx)
.entry_for_path(rel_path(".rules"))
.unwrap();
assert_eq!(
- agent.project_context.read(cx).worktrees,
+ state.project_context.read(cx).worktrees,
vec![WorktreeContext {
root_name: "a".into(),
abs_path: Path::new("/a").into(),
@@ -2013,18 +2172,10 @@ mod internal_tests {
fs.insert_tree("/", json!({ "a": {} })).await;
let project = Project::test(fs.clone(), [], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let connection = NativeAgentConnection(
- NativeAgent::new(
- project.clone(),
- thread_store,
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap(),
- );
+ let connection =
+ NativeAgentConnection(cx.update(|cx| {
+ NativeAgent::new(thread_store, Templates::new(), None, fs.clone(), cx)
+ }));
// Create a thread/session
let acp_thread = cx
@@ -2093,16 +2244,8 @@ mod internal_tests {
let thread_store = cx.new(|cx| ThreadStore::new(cx));
// Create the agent and connection
- let agent = NativeAgent::new(
- project.clone(),
- thread_store,
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent =
+ cx.update(|cx| NativeAgent::new(thread_store, Templates::new(), None, fs.clone(), cx));
let connection = NativeAgentConnection(agent.clone());
// Create a thread/session
@@ -2194,16 +2337,8 @@ mod internal_tests {
let project = Project::test(fs.clone(), [], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let agent = NativeAgent::new(
- project.clone(),
- thread_store,
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent =
+ cx.update(|cx| NativeAgent::new(thread_store, Templates::new(), None, fs.clone(), cx));
let connection = NativeAgentConnection(agent.clone());
let acp_thread = cx
@@ -2286,16 +2421,9 @@ mod internal_tests {
fs.insert_tree("/", json!({ "a": {} })).await;
let project = Project::test(fs.clone(), [path!("/a").as_ref()], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let agent = NativeAgent::new(
- project.clone(),
- thread_store.clone(),
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent = cx.update(|cx| {
+ NativeAgent::new(thread_store.clone(), Templates::new(), None, fs.clone(), cx)
+ });
let connection = Rc::new(NativeAgentConnection(agent.clone()));
// Register a thinking model.
@@ -2369,7 +2497,9 @@ mod internal_tests {
// Reload the thread and verify thinking_enabled is still true.
let reloaded_acp_thread = agent
- .update(cx, |agent, cx| agent.open_thread(session_id.clone(), cx))
+ .update(cx, |agent, cx| {
+ agent.open_thread(session_id.clone(), project.clone(), cx)
+ })
.await
.unwrap();
let reloaded_thread = agent.read_with(cx, |agent, _| {
@@ -2392,16 +2522,9 @@ mod internal_tests {
fs.insert_tree("/", json!({ "a": {} })).await;
let project = Project::test(fs.clone(), [path!("/a").as_ref()], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let agent = NativeAgent::new(
- project.clone(),
- thread_store.clone(),
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent = cx.update(|cx| {
+ NativeAgent::new(thread_store.clone(), Templates::new(), None, fs.clone(), cx)
+ });
let connection = Rc::new(NativeAgentConnection(agent.clone()));
// Register a model where id() != name(), like real Anthropic models
@@ -2476,7 +2599,9 @@ mod internal_tests {
// Reload the thread and verify the model was preserved.
let reloaded_acp_thread = agent
- .update(cx, |agent, cx| agent.open_thread(session_id.clone(), cx))
+ .update(cx, |agent, cx| {
+ agent.open_thread(session_id.clone(), project.clone(), cx)
+ })
.await
.unwrap();
let reloaded_thread = agent.read_with(cx, |agent, _| {
@@ -2511,16 +2636,9 @@ mod internal_tests {
.await;
let project = Project::test(fs.clone(), [path!("/a").as_ref()], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let agent = NativeAgent::new(
- project.clone(),
- thread_store.clone(),
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent = cx.update(|cx| {
+ NativeAgent::new(thread_store.clone(), Templates::new(), None, fs.clone(), cx)
+ });
let connection = Rc::new(NativeAgentConnection(agent.clone()));
let acp_thread = cx
@@ -2640,7 +2758,9 @@ mod internal_tests {
)]
);
let acp_thread = agent
- .update(cx, |agent, cx| agent.open_thread(session_id.clone(), cx))
+ .update(cx, |agent, cx| {
+ agent.open_thread(session_id.clone(), project.clone(), cx)
+ })
.await
.unwrap();
acp_thread.read_with(cx, |thread, cx| {
diff --git a/crates/agent/src/db.rs b/crates/agent/src/db.rs
index 2c9b33e4efc4f22059e2914589ca6c635b51c0e5..43ab9c3c1826ea7d81fed2c934b96f3bb05dd519 100644
--- a/crates/agent/src/db.rs
+++ b/crates/agent/src/db.rs
@@ -45,6 +45,7 @@ impl From<&DbThreadMetadata> for acp_thread::AgentSessionInfo {
cwd: None,
title: Some(meta.title.clone()),
updated_at: Some(meta.updated_at),
+ created_at: meta.created_at,
meta: None,
}
}
@@ -482,7 +483,10 @@ impl ThreadsDatabase {
let data_type = DataType::Zstd;
let data = compressed;
- let created_at = Utc::now().to_rfc3339();
+ // Use the thread's updated_at as created_at for new threads.
+ // This ensures the creation time reflects when the thread was conceptually
+ // created, not when it was saved to the database.
+ let created_at = updated_at.clone();
let mut insert = connection.exec_bound::<(Arc, Option>, Option, Option, String, String, DataType, Vec, String)>(indoc! {"
INSERT INTO threads (id, parent_id, folder_paths, folder_paths_order, summary, updated_at, data_type, data, created_at)
diff --git a/crates/agent/src/edit_agent/evals.rs b/crates/agent/src/edit_agent/evals.rs
index 2e8818b101995b374cf8172547c45b55c27c6f26..e7b67e37bf4a8b71664a78b99b757c6985794ec6 100644
--- a/crates/agent/src/edit_agent/evals.rs
+++ b/crates/agent/src/edit_agent/evals.rs
@@ -1423,7 +1423,7 @@ impl EditAgentTest {
let client = Client::production(cx);
let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
settings::init(cx);
- language_model::init(client.clone(), cx);
+ language_model::init(user_store.clone(), client.clone(), cx);
language_models::init(user_store, client.clone(), cx);
});
diff --git a/crates/agent/src/native_agent_server.rs b/crates/agent/src/native_agent_server.rs
index 18c41670ac4b4ba3146fb207992a7020a44fbd5f..ca5128fc80d49df0f165ab065a510585400f55d9 100644
--- a/crates/agent/src/native_agent_server.rs
+++ b/crates/agent/src/native_agent_server.rs
@@ -35,11 +35,10 @@ impl AgentServer for NativeAgentServer {
fn connect(
&self,
- delegate: AgentServerDelegate,
+ _delegate: AgentServerDelegate,
cx: &mut App,
) -> Task>> {
log::debug!("NativeAgentServer::connect");
- let project = delegate.project().clone();
let fs = self.fs.clone();
let thread_store = self.thread_store.clone();
let prompt_store = PromptStore::global(cx);
@@ -49,9 +48,8 @@ impl AgentServer for NativeAgentServer {
let prompt_store = prompt_store.await?;
log::debug!("Creating native agent entity");
- let agent =
- NativeAgent::new(project, thread_store, templates, Some(prompt_store), fs, cx)
- .await?;
+ let agent = cx
+ .update(|cx| NativeAgent::new(thread_store, templates, Some(prompt_store), fs, cx));
// Create the connection wrapper
let connection = NativeAgentConnection(agent);
diff --git a/crates/agent/src/tests/mod.rs b/crates/agent/src/tests/mod.rs
index 0993b43a13ced62000692bf2b0b35d3ab7fb68e7..db3fa7c56ebc8ba7a94850d9d38b07c65a7ef4ba 100644
--- a/crates/agent/src/tests/mod.rs
+++ b/crates/agent/src/tests/mod.rs
@@ -3167,7 +3167,7 @@ async fn test_agent_connection(cx: &mut TestAppContext) {
let clock = Arc::new(clock::FakeSystemClock::new());
let client = Client::new(clock, http_client, cx);
let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
- language_model::init(client.clone(), cx);
+ language_model::init(user_store.clone(), client.clone(), cx);
language_models::init(user_store, client.clone(), cx);
LanguageModelRegistry::test(cx);
});
@@ -3181,16 +3181,8 @@ async fn test_agent_connection(cx: &mut TestAppContext) {
let thread_store = cx.new(|cx| ThreadStore::new(cx));
// Create agent and connection
- let agent = NativeAgent::new(
- project.clone(),
- thread_store,
- templates.clone(),
- None,
- fake_fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent = cx
+ .update(|cx| NativeAgent::new(thread_store, templates.clone(), None, fake_fs.clone(), cx));
let connection = NativeAgentConnection(agent.clone());
// Create a thread using new_thread
@@ -3616,7 +3608,7 @@ async fn test_streaming_tool_completes_when_llm_stream_ends_without_final_input(
let fake_model = model.as_fake();
thread.update(cx, |thread, _cx| {
- thread.add_tool(StreamingEchoTool);
+ thread.add_tool(StreamingEchoTool::new());
});
let _events = thread
@@ -3768,7 +3760,8 @@ async fn setup(cx: &mut TestAppContext, model: TestModel) -> ThreadTest {
InfiniteTool::NAME: true,
CancellationAwareTool::NAME: true,
StreamingEchoTool::NAME: true,
- (TerminalTool::NAME): true,
+ StreamingFailingEchoTool::NAME: true,
+ TerminalTool::NAME: true,
}
}
}
@@ -3790,7 +3783,7 @@ async fn setup(cx: &mut TestAppContext, model: TestModel) -> ThreadTest {
cx.set_http_client(Arc::new(http_client));
let client = Client::production(cx);
let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
- language_model::init(client.clone(), cx);
+ language_model::init(user_store.clone(), client.clone(), cx);
language_models::init(user_store, client.clone(), cx);
}
};
@@ -4387,16 +4380,9 @@ async fn test_subagent_tool_call_end_to_end(cx: &mut TestAppContext) {
.await;
let project = Project::test(fs.clone(), [path!("/a").as_ref()], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let agent = NativeAgent::new(
- project.clone(),
- thread_store.clone(),
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent = cx.update(|cx| {
+ NativeAgent::new(thread_store.clone(), Templates::new(), None, fs.clone(), cx)
+ });
let connection = Rc::new(NativeAgentConnection(agent.clone()));
let acp_thread = cx
@@ -4529,16 +4515,9 @@ async fn test_subagent_tool_output_does_not_include_thinking(cx: &mut TestAppCon
.await;
let project = Project::test(fs.clone(), [path!("/a").as_ref()], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let agent = NativeAgent::new(
- project.clone(),
- thread_store.clone(),
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent = cx.update(|cx| {
+ NativeAgent::new(thread_store.clone(), Templates::new(), None, fs.clone(), cx)
+ });
let connection = Rc::new(NativeAgentConnection(agent.clone()));
let acp_thread = cx
@@ -4684,16 +4663,9 @@ async fn test_subagent_tool_call_cancellation_during_task_prompt(cx: &mut TestAp
.await;
let project = Project::test(fs.clone(), [path!("/a").as_ref()], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let agent = NativeAgent::new(
- project.clone(),
- thread_store.clone(),
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent = cx.update(|cx| {
+ NativeAgent::new(thread_store.clone(), Templates::new(), None, fs.clone(), cx)
+ });
let connection = Rc::new(NativeAgentConnection(agent.clone()));
let acp_thread = cx
@@ -4821,16 +4793,9 @@ async fn test_subagent_tool_resume_session(cx: &mut TestAppContext) {
.await;
let project = Project::test(fs.clone(), [path!("/a").as_ref()], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let agent = NativeAgent::new(
- project.clone(),
- thread_store.clone(),
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent = cx.update(|cx| {
+ NativeAgent::new(thread_store.clone(), Templates::new(), None, fs.clone(), cx)
+ });
let connection = Rc::new(NativeAgentConnection(agent.clone()));
let acp_thread = cx
@@ -5200,16 +5165,9 @@ async fn test_subagent_context_window_warning(cx: &mut TestAppContext) {
.await;
let project = Project::test(fs.clone(), [path!("/a").as_ref()], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let agent = NativeAgent::new(
- project.clone(),
- thread_store.clone(),
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent = cx.update(|cx| {
+ NativeAgent::new(thread_store.clone(), Templates::new(), None, fs.clone(), cx)
+ });
let connection = Rc::new(NativeAgentConnection(agent.clone()));
let acp_thread = cx
@@ -5333,16 +5291,9 @@ async fn test_subagent_no_context_window_warning_when_already_at_warning(cx: &mu
.await;
let project = Project::test(fs.clone(), [path!("/a").as_ref()], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let agent = NativeAgent::new(
- project.clone(),
- thread_store.clone(),
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent = cx.update(|cx| {
+ NativeAgent::new(thread_store.clone(), Templates::new(), None, fs.clone(), cx)
+ });
let connection = Rc::new(NativeAgentConnection(agent.clone()));
let acp_thread = cx
@@ -5514,16 +5465,9 @@ async fn test_subagent_error_propagation(cx: &mut TestAppContext) {
.await;
let project = Project::test(fs.clone(), [path!("/a").as_ref()], cx).await;
let thread_store = cx.new(|cx| ThreadStore::new(cx));
- let agent = NativeAgent::new(
- project.clone(),
- thread_store.clone(),
- Templates::new(),
- None,
- fs.clone(),
- &mut cx.to_async(),
- )
- .await
- .unwrap();
+ let agent = cx.update(|cx| {
+ NativeAgent::new(thread_store.clone(), Templates::new(), None, fs.clone(), cx)
+ });
let connection = Rc::new(NativeAgentConnection(agent.clone()));
let acp_thread = cx
@@ -6335,3 +6279,196 @@ async fn test_queued_message_ends_turn_at_boundary(cx: &mut TestAppContext) {
);
});
}
+
+#[gpui::test]
+async fn test_streaming_tool_error_breaks_stream_loop_immediately(cx: &mut TestAppContext) {
+ init_test(cx);
+ always_allow_tools(cx);
+
+ let ThreadTest { model, thread, .. } = setup(cx, TestModel::Fake).await;
+ let fake_model = model.as_fake();
+
+ thread.update(cx, |thread, _cx| {
+ thread.add_tool(StreamingFailingEchoTool {
+ receive_chunks_until_failure: 1,
+ });
+ });
+
+ let _events = thread
+ .update(cx, |thread, cx| {
+ thread.send(
+ UserMessageId::new(),
+ ["Use the streaming_failing_echo tool"],
+ cx,
+ )
+ })
+ .unwrap();
+ cx.run_until_parked();
+
+ let tool_use = LanguageModelToolUse {
+ id: "call_1".into(),
+ name: StreamingFailingEchoTool::NAME.into(),
+ raw_input: "hello".into(),
+ input: json!({}),
+ is_input_complete: false,
+ thought_signature: None,
+ };
+
+ fake_model
+ .send_last_completion_stream_event(LanguageModelCompletionEvent::ToolUse(tool_use.clone()));
+
+ cx.run_until_parked();
+
+ let completions = fake_model.pending_completions();
+ let last_completion = completions.last().unwrap();
+
+ assert_eq!(
+ last_completion.messages[1..],
+ vec![
+ LanguageModelRequestMessage {
+ role: Role::User,
+ content: vec!["Use the streaming_failing_echo tool".into()],
+ cache: false,
+ reasoning_details: None,
+ },
+ LanguageModelRequestMessage {
+ role: Role::Assistant,
+ content: vec![language_model::MessageContent::ToolUse(tool_use.clone())],
+ cache: false,
+ reasoning_details: None,
+ },
+ LanguageModelRequestMessage {
+ role: Role::User,
+ content: vec![language_model::MessageContent::ToolResult(
+ LanguageModelToolResult {
+ tool_use_id: tool_use.id.clone(),
+ tool_name: tool_use.name,
+ is_error: true,
+ content: "failed".into(),
+ output: Some("failed".into()),
+ }
+ )],
+ cache: true,
+ reasoning_details: None,
+ },
+ ]
+ );
+}
+
+#[gpui::test]
+async fn test_streaming_tool_error_waits_for_prior_tools_to_complete(cx: &mut TestAppContext) {
+ init_test(cx);
+ always_allow_tools(cx);
+
+ let ThreadTest { model, thread, .. } = setup(cx, TestModel::Fake).await;
+ let fake_model = model.as_fake();
+
+ let (complete_streaming_echo_tool_call_tx, complete_streaming_echo_tool_call_rx) =
+ oneshot::channel();
+
+ thread.update(cx, |thread, _cx| {
+ thread.add_tool(
+ StreamingEchoTool::new().with_wait_until_complete(complete_streaming_echo_tool_call_rx),
+ );
+ thread.add_tool(StreamingFailingEchoTool {
+ receive_chunks_until_failure: 1,
+ });
+ });
+
+ let _events = thread
+ .update(cx, |thread, cx| {
+ thread.send(
+ UserMessageId::new(),
+ ["Use the streaming_echo tool and the streaming_failing_echo tool"],
+ cx,
+ )
+ })
+ .unwrap();
+ cx.run_until_parked();
+
+ fake_model.send_last_completion_stream_event(LanguageModelCompletionEvent::ToolUse(
+ LanguageModelToolUse {
+ id: "call_1".into(),
+ name: StreamingEchoTool::NAME.into(),
+ raw_input: "hello".into(),
+ input: json!({ "text": "hello" }),
+ is_input_complete: false,
+ thought_signature: None,
+ },
+ ));
+ let first_tool_use = LanguageModelToolUse {
+ id: "call_1".into(),
+ name: StreamingEchoTool::NAME.into(),
+ raw_input: "hello world".into(),
+ input: json!({ "text": "hello world" }),
+ is_input_complete: true,
+ thought_signature: None,
+ };
+ fake_model.send_last_completion_stream_event(LanguageModelCompletionEvent::ToolUse(
+ first_tool_use.clone(),
+ ));
+ let second_tool_use = LanguageModelToolUse {
+ name: StreamingFailingEchoTool::NAME.into(),
+ raw_input: "hello".into(),
+ input: json!({ "text": "hello" }),
+ is_input_complete: false,
+ thought_signature: None,
+ id: "call_2".into(),
+ };
+ fake_model.send_last_completion_stream_event(LanguageModelCompletionEvent::ToolUse(
+ second_tool_use.clone(),
+ ));
+
+ cx.run_until_parked();
+
+ complete_streaming_echo_tool_call_tx.send(()).unwrap();
+
+ cx.run_until_parked();
+
+ let completions = fake_model.pending_completions();
+ let last_completion = completions.last().unwrap();
+
+ assert_eq!(
+ last_completion.messages[1..],
+ vec![
+ LanguageModelRequestMessage {
+ role: Role::User,
+ content: vec![
+ "Use the streaming_echo tool and the streaming_failing_echo tool".into()
+ ],
+ cache: false,
+ reasoning_details: None,
+ },
+ LanguageModelRequestMessage {
+ role: Role::Assistant,
+ content: vec![
+ language_model::MessageContent::ToolUse(first_tool_use.clone()),
+ language_model::MessageContent::ToolUse(second_tool_use.clone())
+ ],
+ cache: false,
+ reasoning_details: None,
+ },
+ LanguageModelRequestMessage {
+ role: Role::User,
+ content: vec![
+ language_model::MessageContent::ToolResult(LanguageModelToolResult {
+ tool_use_id: second_tool_use.id.clone(),
+ tool_name: second_tool_use.name,
+ is_error: true,
+ content: "failed".into(),
+ output: Some("failed".into()),
+ }),
+ language_model::MessageContent::ToolResult(LanguageModelToolResult {
+ tool_use_id: first_tool_use.id.clone(),
+ tool_name: first_tool_use.name,
+ is_error: false,
+ content: "hello world".into(),
+ output: Some("hello world".into()),
+ }),
+ ],
+ cache: true,
+ reasoning_details: None,
+ },
+ ]
+ );
+}
diff --git a/crates/agent/src/tests/test_tools.rs b/crates/agent/src/tests/test_tools.rs
index ac179c590a93824813afa338d9deed16b4d00ebd..f36549a6c42f9e810c7794d8ec683613b6ae6933 100644
--- a/crates/agent/src/tests/test_tools.rs
+++ b/crates/agent/src/tests/test_tools.rs
@@ -2,6 +2,7 @@ use super::*;
use agent_settings::AgentSettings;
use gpui::{App, SharedString, Task};
use std::future;
+use std::sync::Mutex;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
@@ -14,7 +15,22 @@ pub struct StreamingEchoToolInput {
pub text: String,
}
-pub struct StreamingEchoTool;
+pub struct StreamingEchoTool {
+ wait_until_complete_rx: Mutex