Extract shell_command_parser into shared crate (#48660)

Richard Feldman created

Move shell command parsing logic (`extract_commands` and supporting
code) from the agent crate into a new `shell_command_parser` crate so it
can be reused by `agent_servers` for ACP permission checking.

Release Notes:

- N/A

Change summary

Cargo.lock                                              |  9 +++++
Cargo.toml                                              |  2 +
crates/agent/Cargo.toml                                 |  2 
crates/agent/src/agent.rs                               |  1 
crates/agent/src/pattern_extraction.rs                  |  2 
crates/agent/src/tool_permissions.rs                    |  2 
crates/shell_command_parser/Cargo.toml                  | 17 +++++++++++
crates/shell_command_parser/LICENSE-GPL                 |  1 
crates/shell_command_parser/src/shell_command_parser.rs |  0 
9 files changed, 31 insertions(+), 5 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -161,7 +161,6 @@ dependencies = [
  "agent_servers",
  "agent_settings",
  "anyhow",
- "brush-parser",
  "chrono",
  "client",
  "clock",
@@ -205,6 +204,7 @@ dependencies = [
  "serde",
  "serde_json",
  "settings",
+ "shell_command_parser",
  "smallvec",
  "smol",
  "sqlez",
@@ -15318,6 +15318,13 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
 
+[[package]]
+name = "shell_command_parser"
+version = "0.1.0"
+dependencies = [
+ "brush-parser",
+]
+
 [[package]]
 name = "shellexpand"
 version = "2.1.2"

Cargo.toml 🔗

@@ -162,6 +162,7 @@ members = [
     "crates/settings_macros",
     "crates/settings_profile_selector",
     "crates/settings_ui",
+    "crates/shell_command_parser",
     "crates/snippet",
     "crates/snippet_provider",
     "crates/snippets_ui",
@@ -402,6 +403,7 @@ settings_content = { path = "crates/settings_content" }
 settings_json = { path = "crates/settings_json" }
 settings_macros = { path = "crates/settings_macros" }
 settings_ui = { path = "crates/settings_ui" }
+shell_command_parser = { path = "crates/shell_command_parser" }
 snippet = { path = "crates/snippet" }
 snippet_provider = { path = "crates/snippet_provider" }
 snippets_ui = { path = "crates/snippets_ui" }

crates/agent/Cargo.toml 🔗

@@ -19,7 +19,6 @@ workspace = true
 
 [dependencies]
 acp_thread.workspace = true
-brush-parser.workspace = true
 action_log.workspace = true
 agent-client-protocol.workspace = true
 agent_servers.workspace = true
@@ -58,6 +57,7 @@ schemars.workspace = true
 serde.workspace = true
 serde_json.workspace = true
 settings.workspace = true
+shell_command_parser.workspace = true
 smallvec.workspace = true
 smol.workspace = true
 sqlez.workspace = true

crates/agent/src/agent.rs 🔗

@@ -4,7 +4,6 @@ mod legacy_thread;
 mod native_agent_server;
 pub mod outline;
 mod pattern_extraction;
-mod shell_parser;
 mod templates;
 #[cfg(test)]
 mod tests;

crates/agent/src/tool_permissions.rs 🔗

@@ -1,8 +1,8 @@
 use crate::AgentTool;
-use crate::shell_parser::extract_commands;
 use crate::tools::TerminalTool;
 use agent_settings::{AgentSettings, CompiledRegex, ToolPermissions, ToolRules};
 use settings::ToolPermissionMode;
+use shell_command_parser::extract_commands;
 use std::path::{Component, Path};
 use std::sync::LazyLock;
 use util::shell::ShellKind;

crates/shell_command_parser/Cargo.toml 🔗

@@ -0,0 +1,17 @@
+[package]
+name = "shell_command_parser"
+version = "0.1.0"
+edition.workspace = true
+publish.workspace = true
+license = "GPL-3.0-or-later"
+
+[lints]
+workspace = true
+
+[lib]
+path = "src/shell_command_parser.rs"
+
+[dependencies]
+brush-parser.workspace = true
+
+[dev-dependencies]