From 5bf6e571cbd48cc992d2cfc7bf3a2bdb2f4b9011 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Mon, 16 Mar 2026 23:12:30 +0100 Subject: [PATCH 1/3] agent_ui: Fix non-compiling tests (#51715) Release Notes: - N/A --- crates/agent_ui/src/agent_panel.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 592a8b9e24277d4679a05c02acb68d0b3da4b6a6..e6dc1b8148067503554fbdf71a414782f805b850 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -6411,7 +6411,7 @@ mod tests { // open_external_thread_with_server overrides selected_agent_type. panel.update(cx, |panel, cx| { panel.selected_agent_type = AgentType::Custom { - name: CODEX_NAME.into(), + id: CODEX_ID.into(), }; panel.set_start_thread_in(&StartThreadIn::NewWorktree, cx); }); @@ -6421,7 +6421,7 @@ mod tests { assert_eq!( panel.selected_agent_type, AgentType::Custom { - name: CODEX_NAME.into() + id: CODEX_ID.into() }, ); }); @@ -6466,7 +6466,7 @@ mod tests { assert_eq!( found_codex, AgentType::Custom { - name: CODEX_NAME.into() + id: CODEX_ID.into() }, "the new worktree workspace should use the same agent (Codex) that was selected in the original panel", ); From 9c3aa4b9fa5ad49ed3455de83ed772ef4a25aa20 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Mon, 16 Mar 2026 23:25:04 +0100 Subject: [PATCH 2/3] agent_ui: Remove special casing for previous built in agents (#51713) Now that the migration has happened, we can stop making these ever present Release Notes: - N/A --- crates/agent_servers/src/acp.rs | 2 +- crates/agent_servers/src/custom.rs | 33 +--- crates/agent_ui/src/agent_panel.rs | 245 ++--------------------------- crates/agent_ui/src/agent_ui.rs | 87 +--------- 4 files changed, 18 insertions(+), 349 deletions(-) diff --git a/crates/agent_servers/src/acp.rs b/crates/agent_servers/src/acp.rs index 54166f1d553b4ed1ef0f3642517125b30bc5fda8..a8c8e2f6ebf2b7efeb264aa412131881564ce3b3 100644 --- a/crates/agent_servers/src/acp.rs +++ b/crates/agent_servers/src/acp.rs @@ -324,7 +324,7 @@ impl AcpConnection { // TODO: Remove this override once Google team releases their official auth methods let auth_methods = if agent_id.0.as_ref() == GEMINI_ID { let mut args = command.args.clone(); - args.retain(|a| a != "--experimental-acp"); + args.retain(|a| a != "--experimental-acp" && a != "--acp"); let value = serde_json::json!({ "label": "gemini /auth", "command": command.path.to_string_lossy().into_owned(), diff --git a/crates/agent_servers/src/custom.rs b/crates/agent_servers/src/custom.rs index d9a4469aefa957033a583a1061656dcb090eeec1..30bfae3a34049116a523d971952f40b3f2269cbf 100644 --- a/crates/agent_servers/src/custom.rs +++ b/crates/agent_servers/src/custom.rs @@ -405,8 +405,6 @@ fn api_key_for_gemini_cli(cx: &mut App) -> Task> { fn is_registry_agent(agent_id: impl Into, cx: &App) -> bool { let agent_id = agent_id.into(); - let is_previous_built_in = - matches!(agent_id.0.as_ref(), CLAUDE_AGENT_ID | CODEX_ID | GEMINI_ID); let is_in_registry = project::AgentRegistryStore::try_global(cx) .map(|store| store.read(cx).agent(&agent_id).is_some()) .unwrap_or(false); @@ -421,7 +419,7 @@ fn is_registry_agent(agent_id: impl Into, cx: &App) -> bool { ) }) }); - is_previous_built_in || is_in_registry || is_settings_registry + is_in_registry || is_settings_registry } fn default_settings_for_agent( @@ -509,16 +507,6 @@ mod tests { }); } - #[gpui::test] - fn test_previous_builtins_are_registry(cx: &mut TestAppContext) { - init_test(cx); - cx.update(|cx| { - assert!(is_registry_agent(CLAUDE_AGENT_ID, cx)); - assert!(is_registry_agent(CODEX_ID, cx)); - assert!(is_registry_agent(GEMINI_ID, cx)); - }); - } - #[gpui::test] fn test_unknown_agent_is_not_registry(cx: &mut TestAppContext) { init_test(cx); @@ -581,25 +569,6 @@ mod tests { }); } - #[gpui::test] - fn test_default_settings_for_builtin_agent(cx: &mut TestAppContext) { - init_test(cx); - cx.update(|cx| { - assert!(matches!( - default_settings_for_agent(CODEX_ID, cx), - settings::CustomAgentServerSettings::Registry { .. } - )); - assert!(matches!( - default_settings_for_agent(CLAUDE_AGENT_ID, cx), - settings::CustomAgentServerSettings::Registry { .. } - )); - assert!(matches!( - default_settings_for_agent(GEMINI_ID, cx), - settings::CustomAgentServerSettings::Registry { .. } - )); - }); - } - #[gpui::test] fn test_default_settings_for_extension_agent(cx: &mut TestAppContext) { init_test(cx); diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index e6dc1b8148067503554fbdf71a414782f805b850..4a40f3303b8aab6f7ad5794e564d79e2c4943d98 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -16,10 +16,7 @@ use agent_servers::AgentServer; use collections::HashSet; use db::kvp::{Dismissable, KEY_VALUE_STORE}; use itertools::Itertools; -use project::{ - AgentId, - agent_server_store::{CLAUDE_AGENT_ID, CODEX_ID, GEMINI_ID}, -}; +use project::AgentId; use serde::{Deserialize, Serialize}; use settings::{LanguageModelProviderSetting, LanguageModelSelection}; @@ -645,7 +642,7 @@ enum WhichFontSize { } // TODO unify this with ExternalAgent -#[derive(Debug, Default, Clone, PartialEq, Serialize)] +#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] pub enum AgentType { #[default] NativeAgent, @@ -656,65 +653,6 @@ pub enum AgentType { }, } -// Custom impl handles legacy variant names from before the built-in agents were moved to -// the registry: "ClaudeAgent" -> Custom { name: "claude-acp" }, "Codex" -> Custom { name: -// "codex-acp" }, "Gemini" -> Custom { name: "gemini" }. -// Can be removed at some point in the future and go back to #[derive(Deserialize)]. -impl<'de> Deserialize<'de> for AgentType { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let value = serde_json::Value::deserialize(deserializer)?; - - if let Some(s) = value.as_str() { - return match s { - "NativeAgent" => Ok(Self::NativeAgent), - "TextThread" => Ok(Self::TextThread), - "ClaudeAgent" | "ClaudeCode" => Ok(Self::Custom { - id: CLAUDE_AGENT_ID.into(), - }), - "Codex" => Ok(Self::Custom { - id: CODEX_ID.into(), - }), - "Gemini" => Ok(Self::Custom { - id: GEMINI_ID.into(), - }), - other => Err(serde::de::Error::unknown_variant( - other, - &[ - "NativeAgent", - "TextThread", - "Custom", - "ClaudeAgent", - "ClaudeCode", - "Codex", - "Gemini", - ], - )), - }; - } - - if let Some(obj) = value.as_object() { - if let Some(inner) = obj.get("Custom") { - #[derive(Deserialize)] - struct CustomFields { - name: SharedString, - } - let fields: CustomFields = - serde_json::from_value(inner.clone()).map_err(serde::de::Error::custom)?; - return Ok(Self::Custom { - id: AgentId::new(fields.name), - }); - } - } - - Err(serde::de::Error::custom( - "expected a string variant or {\"Custom\": {\"name\": ...}}", - )) - } -} - impl AgentType { pub fn is_native(&self) -> bool { matches!(self, Self::NativeAgent) @@ -4045,10 +3983,8 @@ impl AgentPanel { .header("External Agents") .map(|mut menu| { let agent_server_store = agent_server_store.read(cx); - let registry_store = - project::AgentRegistryStore::try_global(cx); - let registry_store_ref = - registry_store.as_ref().map(|s| s.read(cx)); + let registry_store = project::AgentRegistryStore::try_global(cx); + let registry_store_ref = registry_store.as_ref().map(|s| s.read(cx)); struct AgentMenuItem { id: AgentId, @@ -4076,12 +4012,10 @@ impl AgentPanel { .collect::>(); for item in &agent_items { - let mut entry = - ContextMenuEntry::new(item.display_name.clone()); + let mut entry = ContextMenuEntry::new(item.display_name.clone()); - let icon_path = agent_server_store - .agent_icon(&item.id) - .or_else(|| { + let icon_path = + agent_server_store.agent_icon(&item.id).or_else(|| { registry_store_ref .as_ref() .and_then(|store| store.agent(&item.id)) @@ -4100,9 +4034,9 @@ impl AgentPanel { id: item.id.clone(), }), |this| { - this.action(Box::new( - NewExternalAgentThread { agent: None }, - )) + this.action(Box::new(NewExternalAgentThread { + agent: None, + })) }, ) .icon_color(Color::Muted) @@ -4137,111 +4071,14 @@ impl AgentPanel { menu }) .separator() - .map(|mut menu| { - let agent_server_store = agent_server_store.read(cx); - let registry_store = - project::AgentRegistryStore::try_global(cx); - let registry_store_ref = - registry_store.as_ref().map(|s| s.read(cx)); - - let previous_built_in_ids: &[AgentId] = - &[CLAUDE_AGENT_ID.into(), CODEX_ID.into(), GEMINI_ID.into()]; - - let promoted_items = previous_built_in_ids - .iter() - .filter(|id| { - !agent_server_store.external_agents.contains_key(*id) - }) - .filter_map(|id| { - let display_name = registry_store_ref - .as_ref() - .and_then(|store| store.agent(&id)) - .map(|a| a.name().clone())?; - Some((id.clone(), display_name)) - }) - .sorted_unstable_by_key(|(_, display_name)| display_name.to_lowercase()) - .collect::>(); - - for (agent_id, display_name) in &promoted_items { - let mut entry = - ContextMenuEntry::new(display_name.clone()); - - let icon_path = registry_store_ref - .as_ref() - .and_then(|store| store.agent(agent_id)) - .and_then(|a| a.icon_path().cloned()); - - if let Some(icon_path) = icon_path { - entry = entry.custom_icon_svg(icon_path); - } else { - entry = entry.icon(IconName::Sparkle); - } - - entry = entry - .icon_color(Color::Muted) - .disabled(is_via_collab) - .handler({ - let workspace = workspace.clone(); - let agent_id = agent_id.clone(); - move |window, cx| { - let fs = ::global(cx); - let agent_id_string = - agent_id.to_string(); - settings::update_settings_file( - fs, - cx, - move |settings, _| { - let agent_servers = settings - .agent_servers - .get_or_insert_default(); - agent_servers.entry(agent_id_string).or_insert_with(|| { - settings::CustomAgentServerSettings::Registry { - default_mode: None, - default_model: None, - env: Default::default(), - favorite_models: Vec::new(), - default_config_options: Default::default(), - favorite_config_option_values: Default::default(), - } - }); - }, - ); - - if let Some(workspace) = workspace.upgrade() { - workspace.update(cx, |workspace, cx| { - if let Some(panel) = - workspace.panel::(cx) - { - panel.update(cx, |panel, cx| { - panel.new_agent_thread( - AgentType::Custom { - id: agent_id.clone(), - }, - window, - cx, - ); - }); - } - }); - } - } - }); - - menu = menu.item(entry); - } - - menu - }) .item( ContextMenuEntry::new("Add More Agents") .icon(IconName::Plus) .icon_color(Color::Muted) .handler({ move |window, cx| { - window.dispatch_action( - Box::new(zed_actions::AcpRegistry), - cx, - ) + window + .dispatch_action(Box::new(zed_actions::AcpRegistry), cx) } }), ) @@ -5348,6 +5185,7 @@ mod tests { use fs::FakeFs; use gpui::{TestAppContext, VisualTestContext}; use project::Project; + use project::agent_server_store::CODEX_ID; use serde_json::json; use workspace::MultiWorkspace; @@ -6273,35 +6111,7 @@ mod tests { } #[test] - fn test_deserialize_legacy_agent_type_variants() { - assert_eq!( - serde_json::from_str::(r#""ClaudeAgent""#).unwrap(), - AgentType::Custom { - id: CLAUDE_AGENT_ID.into(), - }, - ); - assert_eq!( - serde_json::from_str::(r#""ClaudeCode""#).unwrap(), - AgentType::Custom { - id: CLAUDE_AGENT_ID.into(), - }, - ); - assert_eq!( - serde_json::from_str::(r#""Codex""#).unwrap(), - AgentType::Custom { - id: CODEX_ID.into(), - }, - ); - assert_eq!( - serde_json::from_str::(r#""Gemini""#).unwrap(), - AgentType::Custom { - id: GEMINI_ID.into(), - }, - ); - } - - #[test] - fn test_deserialize_current_agent_type_variants() { + fn test_deserialize_agent_type_variants() { assert_eq!( serde_json::from_str::(r#""NativeAgent""#).unwrap(), AgentType::NativeAgent, @@ -6471,31 +6281,4 @@ mod tests { "the new worktree workspace should use the same agent (Codex) that was selected in the original panel", ); } - - #[test] - fn test_deserialize_legacy_serialized_panel() { - let json = serde_json::json!({ - "width": 300.0, - "selected_agent": "ClaudeAgent", - "last_active_thread": { - "session_id": "test-session", - "agent_type": "Codex", - }, - }); - - let panel: SerializedAgentPanel = serde_json::from_value(json).unwrap(); - assert_eq!( - panel.selected_agent, - Some(AgentType::Custom { - id: CLAUDE_AGENT_ID.into(), - }), - ); - let thread = panel.last_active_thread.unwrap(); - assert_eq!( - thread.agent_type, - AgentType::Custom { - id: CODEX_ID.into(), - }, - ); - } } diff --git a/crates/agent_ui/src/agent_ui.rs b/crates/agent_ui/src/agent_ui.rs index dde70f15e8084144d9beb1d4fb9563cf12fb942e..2488bc1687cc01af47e1939a5feff8b49cce64dd 100644 --- a/crates/agent_ui/src/agent_ui.rs +++ b/crates/agent_ui/src/agent_ui.rs @@ -218,7 +218,7 @@ pub struct NewNativeAgentThreadFromSummary { } // TODO unify this with AgentType -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, JsonSchema)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum Agent { NativeAgent, @@ -228,65 +228,6 @@ pub enum Agent { }, } -// Custom impl handles legacy variant names from before the built-in agents were moved to -// the registry: "claude_code" -> Custom { name: "claude-acp" }, "codex" -> Custom { name: -// "codex-acp" }, "gemini" -> Custom { name: "gemini" }. -// Can be removed at some point in the future and go back to #[derive(Deserialize)]. -impl<'de> serde::Deserialize<'de> for Agent { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - use project::agent_server_store::{CLAUDE_AGENT_ID, CODEX_ID, GEMINI_ID}; - - let value = serde_json::Value::deserialize(deserializer)?; - - if let Some(s) = value.as_str() { - return match s { - "native_agent" => Ok(Self::NativeAgent), - "claude_code" | "claude_agent" => Ok(Self::Custom { - id: CLAUDE_AGENT_ID.into(), - }), - "codex" => Ok(Self::Custom { - id: CODEX_ID.into(), - }), - "gemini" => Ok(Self::Custom { - id: GEMINI_ID.into(), - }), - other => Err(serde::de::Error::unknown_variant( - other, - &[ - "native_agent", - "custom", - "claude_agent", - "claude_code", - "codex", - "gemini", - ], - )), - }; - } - - if let Some(obj) = value.as_object() { - if let Some(inner) = obj.get("custom") { - #[derive(serde::Deserialize)] - struct CustomFields { - name: SharedString, - } - let fields: CustomFields = - serde_json::from_value(inner.clone()).map_err(serde::de::Error::custom)?; - return Ok(Self::Custom { - id: AgentId::new(fields.name), - }); - } - } - - Err(serde::de::Error::custom( - "expected a string variant or {\"custom\": {\"name\": ...}}", - )) - } -} - impl Agent { pub fn server( &self, @@ -759,31 +700,7 @@ mod tests { } #[test] - fn test_deserialize_legacy_external_agent_variants() { - use project::agent_server_store::{CLAUDE_AGENT_ID, CODEX_ID, GEMINI_ID}; - - assert_eq!( - serde_json::from_str::(r#""claude_code""#).unwrap(), - Agent::Custom { - id: CLAUDE_AGENT_ID.into(), - }, - ); - assert_eq!( - serde_json::from_str::(r#""codex""#).unwrap(), - Agent::Custom { - id: CODEX_ID.into(), - }, - ); - assert_eq!( - serde_json::from_str::(r#""gemini""#).unwrap(), - Agent::Custom { - id: GEMINI_ID.into(), - }, - ); - } - - #[test] - fn test_deserialize_current_external_agent_variants() { + fn test_deserialize_external_agent_variants() { assert_eq!( serde_json::from_str::(r#""native_agent""#).unwrap(), Agent::NativeAgent, From 6a06f72f18ab1401618d8128c034de10c1105efb Mon Sep 17 00:00:00 2001 From: Finn Evers Date: Mon, 16 Mar 2026 23:26:56 +0100 Subject: [PATCH 3/3] extension_ci: Bump update action and fix cache issues (#51716) This PR bumps the update action again. It also fixes a bug where a cache issue could occur during the extension auto bump and adds update auto-merge for PRs from staff-members in zed-industries/extensions. Release Notes: - N/A --- .github/workflows/extension_bump.yml | 61 ++++++++++++- .../src/tasks/workflows/extension_bump.rs | 85 +++++++++++++++++-- 2 files changed, 136 insertions(+), 10 deletions(-) diff --git a/.github/workflows/extension_bump.yml b/.github/workflows/extension_bump.yml index c971bc2ab096cd54089558a6a19875cb66f03918..a8598f3693bec3bb5b46860315276c69608ae070 100644 --- a/.github/workflows/extension_bump.yml +++ b/.github/workflows/extension_bump.yml @@ -105,7 +105,7 @@ jobs: --no-configured-files "$BUMP_TYPE" "${BUMP_FILES[@]}" if [[ -f "Cargo.toml" ]]; then - cargo update --workspace + cargo +stable update --workspace fi NEW_VERSION="$(sed -n 's/^version = \"\(.*\)\"/\1/p' < extension.toml | tr -d '[:space:]')" @@ -229,14 +229,69 @@ jobs: EXTENSION_ID="$(sed -n 's/id = \"\(.*\)\"/\1/p' < extension.toml)" echo "extension_id=${EXTENSION_ID}" >> "$GITHUB_OUTPUT" - - name: extension_bump::release_action - uses: zed-extensions/update-action@1ef53b23be40fe2549be0baffaa98e9f51838fef + - id: extension-update + name: extension_bump::release_action + uses: zed-extensions/update-action@72da482880c2f32ec8aa6e0a0427ab92d52ae32d with: extension-name: ${{ steps.get-extension-id.outputs.extension_id }} push-to: zed-industries/extensions tag: ${{ needs.create_version_label.outputs.tag }} env: COMMITTER_TOKEN: ${{ steps.generate-token.outputs.token }} + - name: extension_bump::enable_automerge_if_staff + uses: actions/github-script@v7 + with: + github-token: ${{ steps.generate-token.outputs.token }} + script: | + const prNumber = process.env.PR_NUMBER; + if (!prNumber) { + console.log('No pull request number set, skipping automerge.'); + return; + } + + const author = process.env.GITHUB_ACTOR; + let isStaff = false; + try { + const response = await github.rest.teams.getMembershipForUserInOrg({ + org: 'zed-industries', + team_slug: 'staff', + username: author + }); + isStaff = response.data.state === 'active'; + } catch (error) { + if (error.status !== 404) { + throw error; + } + } + + if (!isStaff) { + console.log(`Actor ${author} is not a staff member, skipping automerge.`); + return; + } + + + // Get the GraphQL node ID + const { data: pr } = await github.rest.pulls.get({ + owner: 'zed-industries', + repo: 'extensions', + pull_number: parseInt(prNumber) + }); + + await github.graphql(` + mutation($pullRequestId: ID!) { + enablePullRequestAutoMerge(input: { pullRequestId: $pullRequestId, mergeMethod: SQUASH }) { + pullRequest { + autoMergeRequest { + enabledAt + } + } + } + } + `, { pullRequestId: pr.node_id }); + + console.log(`Automerge enabled for PR #${prNumber} in zed-industries/extensions`); + env: + PR_NUMBER: ${{ steps.extension-update.outputs.pull-request-number }} defaults: run: shell: bash -euxo pipefail {0} diff --git a/tooling/xtask/src/tasks/workflows/extension_bump.rs b/tooling/xtask/src/tasks/workflows/extension_bump.rs index 3097611e079195d2d6244f3ab2b15d8f99e8c8a4..50bbab0372ad8f73d0e1b45e27e681eb1d50cf28 100644 --- a/tooling/xtask/src/tasks/workflows/extension_bump.rs +++ b/tooling/xtask/src/tasks/workflows/extension_bump.rs @@ -316,7 +316,7 @@ fn bump_version( --no-configured-files "$BUMP_TYPE" "${{BUMP_FILES[@]}}" if [[ -f "Cargo.toml" ]]; then - cargo update --workspace + cargo +stable update --workspace fi NEW_VERSION="$({VERSION_CHECK})" @@ -395,6 +395,7 @@ fn trigger_release( Some(extension_registry), ); let (get_extension_id, extension_id) = get_extension_id(); + let (release_action, pull_request_number) = release_action(extension_id, tag, &generated_token); let job = dependant_job(dependencies) .defaults(extension_job_defaults()) @@ -403,7 +404,11 @@ fn trigger_release( .add_step(generate_token) .add_step(checkout_repo()) .add_step(get_extension_id) - .add_step(release_action(extension_id, tag, generated_token)); + .add_step(release_action) + .add_step(enable_automerge_if_staff( + pull_request_number, + generated_token, + )); named::job(job) } @@ -425,17 +430,83 @@ fn get_extension_id() -> (Step, StepOutput) { fn release_action( extension_id: StepOutput, tag: JobOutput, - generated_token: StepOutput, -) -> Step { - named::uses( + generated_token: &StepOutput, +) -> (Step, StepOutput) { + let step = named::uses( "zed-extensions", "update-action", - "1ef53b23be40fe2549be0baffaa98e9f51838fef", + "72da482880c2f32ec8aa6e0a0427ab92d52ae32d", ) + .id("extension-update") .add_with(("extension-name", extension_id.to_string())) .add_with(("push-to", "zed-industries/extensions")) .add_with(("tag", tag.to_string())) - .add_env(("COMMITTER_TOKEN", generated_token.to_string())) + .add_env(("COMMITTER_TOKEN", generated_token.to_string())); + + let pull_request_number = StepOutput::new(&step, "pull-request-number"); + + (step, pull_request_number) +} + +fn enable_automerge_if_staff( + pull_request_number: StepOutput, + generated_token: StepOutput, +) -> Step { + named::uses("actions", "github-script", "v7") + .add_with(("github-token", generated_token.to_string())) + .add_with(( + "script", + indoc! {r#" + const prNumber = process.env.PR_NUMBER; + if (!prNumber) { + console.log('No pull request number set, skipping automerge.'); + return; + } + + const author = process.env.GITHUB_ACTOR; + let isStaff = false; + try { + const response = await github.rest.teams.getMembershipForUserInOrg({ + org: 'zed-industries', + team_slug: 'staff', + username: author + }); + isStaff = response.data.state === 'active'; + } catch (error) { + if (error.status !== 404) { + throw error; + } + } + + if (!isStaff) { + console.log(`Actor ${author} is not a staff member, skipping automerge.`); + return; + } + + + // Get the GraphQL node ID + const { data: pr } = await github.rest.pulls.get({ + owner: 'zed-industries', + repo: 'extensions', + pull_number: parseInt(prNumber) + }); + + await github.graphql(` + mutation($pullRequestId: ID!) { + enablePullRequestAutoMerge(input: { pullRequestId: $pullRequestId, mergeMethod: SQUASH }) { + pullRequest { + autoMergeRequest { + enabledAt + } + } + } + } + `, { pullRequestId: pr.node_id }); + + console.log(`Automerge enabled for PR #${prNumber} in zed-industries/extensions`); + "#}, + )) + .add_env(("PR_NUMBER", pull_request_number.to_string())) } fn extension_workflow_secrets() -> (WorkflowSecret, WorkflowSecret) {