mirror of
https://github.com/different-ai/openwork
synced 2026-04-25 17:15:34 +02:00
feat(desktop): default to control-chrome executable without npx (#534)
This commit is contained in:
@@ -24,7 +24,7 @@ description: Guide users through browser automation setup using Chrome DevTools
|
|||||||
4. If DevTools MCP calls fail:
|
4. If DevTools MCP calls fail:
|
||||||
- Ask the user to open Chrome and keep it running.
|
- Ask the user to open Chrome and keep it running.
|
||||||
- Retry `chrome-devtools_list_pages`.
|
- Retry `chrome-devtools_list_pages`.
|
||||||
- If it still fails, ensure `opencode.jsonc` includes `mcp.chrome-devtools` with command `['npx','-y','chrome-devtools-mcp@latest']` and ask the user to restart OpenWork/OpenCode.
|
- If it still fails, ensure `opencode.jsonc` includes `mcp.control-chrome` with command `['chrome-devtools-mcp']` and ask the user to restart OpenWork/OpenCode.
|
||||||
- Retry the DevTools MCP check.
|
- Retry the DevTools MCP check.
|
||||||
5. If DevTools MCP is ready:
|
5. If DevTools MCP is ready:
|
||||||
- Offer a first task ("Let's try opening a webpage").
|
- Offer a first task ("Let's try opening a webpage").
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://opencode.ai/config.json",
|
"$schema": "https://opencode.ai/config.json",
|
||||||
"mcp": {
|
"mcp": {
|
||||||
"chrome-devtools": {
|
"control-chrome": {
|
||||||
"type": "local",
|
"type": "local",
|
||||||
"command": [
|
"command": [
|
||||||
"npx",
|
"chrome-devtools-mcp"
|
||||||
"-y",
|
|
||||||
"chrome-devtools-mcp@latest"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -75,10 +75,10 @@ export const MCP_QUICK_CONNECT: McpDirectoryInfo[] = [
|
|||||||
oauth: false,
|
oauth: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Chrome DevTools",
|
name: "Control Chrome",
|
||||||
description: "Drive Chrome tabs with browser automation.",
|
description: "Drive Chrome tabs with browser automation.",
|
||||||
type: "local",
|
type: "local",
|
||||||
command: ["npx", "-y", "chrome-devtools-mcp@latest"],
|
command: ["chrome-devtools-mcp"],
|
||||||
oauth: false,
|
oauth: false,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use tauri::async_runtime::Receiver;
|
use tauri::async_runtime::Receiver;
|
||||||
use tauri::AppHandle;
|
use tauri::{AppHandle, Manager};
|
||||||
use tauri_plugin_shell::process::{CommandChild, CommandEvent};
|
use tauri_plugin_shell::process::{CommandChild, CommandEvent};
|
||||||
use tauri_plugin_shell::ShellExt;
|
use tauri_plugin_shell::ShellExt;
|
||||||
|
|
||||||
use crate::paths::{candidate_xdg_config_dirs, candidate_xdg_data_dirs, maybe_infer_xdg_home};
|
use crate::paths::{candidate_xdg_config_dirs, candidate_xdg_data_dirs, maybe_infer_xdg_home};
|
||||||
|
use crate::paths::{prepended_path_env, sidecar_path_candidates};
|
||||||
|
|
||||||
pub fn find_free_port() -> Result<u16, String> {
|
pub fn find_free_port() -> Result<u16, String> {
|
||||||
let listener = std::net::TcpListener::bind(("127.0.0.1", 0)).map_err(|e| e.to_string())?;
|
let listener = std::net::TcpListener::bind(("127.0.0.1", 0)).map_err(|e| e.to_string())?;
|
||||||
@@ -77,6 +78,16 @@ pub fn spawn_engine(
|
|||||||
command = command.env("OPENCODE_CLIENT", "openwork");
|
command = command.env("OPENCODE_CLIENT", "openwork");
|
||||||
command = command.env("OPENWORK", "1");
|
command = command.env("OPENWORK", "1");
|
||||||
|
|
||||||
|
let resource_dir = app.path().resource_dir().ok();
|
||||||
|
let current_bin_dir = tauri::process::current_binary(&app.env())
|
||||||
|
.ok()
|
||||||
|
.and_then(|path| path.parent().map(|parent| parent.to_path_buf()));
|
||||||
|
let sidecar_paths =
|
||||||
|
sidecar_path_candidates(resource_dir.as_deref(), current_bin_dir.as_deref());
|
||||||
|
if let Some(path_env) = prepended_path_env(&sidecar_paths) {
|
||||||
|
command = command.env("PATH", path_env);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(username) = opencode_username {
|
if let Some(username) = opencode_username {
|
||||||
if !username.trim().is_empty() {
|
if !username.trim().is_empty() {
|
||||||
command = command.env("OPENCODE_SERVER_USERNAME", username);
|
command = command.env("OPENCODE_SERVER_USERNAME", username);
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ use std::path::{Path, PathBuf};
|
|||||||
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::AppHandle;
|
use tauri::{AppHandle, Manager};
|
||||||
use tauri_plugin_shell::process::{CommandChild, CommandEvent};
|
use tauri_plugin_shell::process::{CommandChild, CommandEvent};
|
||||||
use tauri_plugin_shell::ShellExt;
|
use tauri_plugin_shell::ShellExt;
|
||||||
|
|
||||||
use crate::paths::home_dir;
|
use crate::paths::home_dir;
|
||||||
|
use crate::paths::{prepended_path_env, sidecar_path_candidates};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
OpenwrkBinaryState, OpenwrkDaemonState, OpenwrkOpencodeState, OpenwrkSidecarInfo,
|
OpenwrkBinaryState, OpenwrkDaemonState, OpenwrkOpencodeState, OpenwrkSidecarInfo,
|
||||||
OpenwrkStatus, OpenwrkWorkspace,
|
OpenwrkStatus, OpenwrkWorkspace,
|
||||||
@@ -237,8 +238,19 @@ pub fn spawn_openwrk_daemon(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut command = command.args(args);
|
||||||
|
|
||||||
|
let resource_dir = app.path().resource_dir().ok();
|
||||||
|
let current_bin_dir = tauri::process::current_binary(&app.env())
|
||||||
|
.ok()
|
||||||
|
.and_then(|path| path.parent().map(|parent| parent.to_path_buf()));
|
||||||
|
let sidecar_paths =
|
||||||
|
sidecar_path_candidates(resource_dir.as_deref(), current_bin_dir.as_deref());
|
||||||
|
if let Some(path_env) = prepended_path_env(&sidecar_paths) {
|
||||||
|
command = command.env("PATH", path_env);
|
||||||
|
}
|
||||||
|
|
||||||
command
|
command
|
||||||
.args(args)
|
|
||||||
.spawn()
|
.spawn()
|
||||||
.map_err(|e| format!("Failed to start openwrk: {e}"))
|
.map_err(|e| format!("Failed to start openwrk: {e}"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,3 +90,57 @@ pub fn resolve_in_path(name: &str) -> Option<PathBuf> {
|
|||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sidecar_path_candidates(
|
||||||
|
resource_dir: Option<&Path>,
|
||||||
|
current_bin_dir: Option<&Path>,
|
||||||
|
) -> Vec<PathBuf> {
|
||||||
|
let mut candidates = Vec::new();
|
||||||
|
|
||||||
|
if let Some(current_bin_dir) = current_bin_dir {
|
||||||
|
candidates.push(current_bin_dir.to_path_buf());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(resource_dir) = resource_dir {
|
||||||
|
candidates.push(resource_dir.join("sidecars"));
|
||||||
|
candidates.push(resource_dir.to_path_buf());
|
||||||
|
}
|
||||||
|
|
||||||
|
candidates.push(PathBuf::from("src-tauri/sidecars"));
|
||||||
|
|
||||||
|
let mut unique = Vec::new();
|
||||||
|
for candidate in candidates {
|
||||||
|
if !candidate.is_dir() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if unique
|
||||||
|
.iter()
|
||||||
|
.any(|existing: &PathBuf| existing == &candidate)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
unique.push(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
unique
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prepended_path_env(prefixes: &[PathBuf]) -> Option<std::ffi::OsString> {
|
||||||
|
let mut entries = Vec::<PathBuf>::new();
|
||||||
|
|
||||||
|
for prefix in prefixes {
|
||||||
|
if prefix.is_dir() {
|
||||||
|
entries.push(prefix.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(existing) = env::var_os("PATH") {
|
||||||
|
entries.extend(env::split_paths(&existing));
|
||||||
|
}
|
||||||
|
|
||||||
|
if entries.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
env::join_paths(entries).ok()
|
||||||
|
}
|
||||||
|
|||||||
@@ -460,12 +460,12 @@ pub fn ensure_workspace_files(workspace_path: &str, preset: &str) -> Result<(),
|
|||||||
_ => serde_json::Map::new(),
|
_ => serde_json::Map::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if !mcp_obj.contains_key("chrome-devtools") {
|
if !mcp_obj.contains_key("control-chrome") {
|
||||||
mcp_obj.insert(
|
mcp_obj.insert(
|
||||||
"chrome-devtools".to_string(),
|
"control-chrome".to_string(),
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "local",
|
"type": "local",
|
||||||
"command": ["npx", "-y", "chrome-devtools-mcp@latest"]
|
"command": ["chrome-devtools-mcp"]
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
config_changed = true;
|
config_changed = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user