Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 62 additions & 1 deletion packages/desktop/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ edition = "2021"
tauri-build = { version = "2", features = [] }

[dependencies]
json5 = "0.4"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tauri = { version = "2", features = [] }
Expand Down
22 changes: 19 additions & 3 deletions packages/desktop/src-tauri/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ use std::path::PathBuf;

use crate::types::{ExecResult, OpencodeConfigFile};

pub fn resolve_opencode_config_path(scope: &str, project_dir: &str) -> Result<PathBuf, String> {
fn opencode_config_candidates(scope: &str, project_dir: &str) -> Result<(PathBuf, PathBuf), String> {
match scope {
"project" => {
if project_dir.trim().is_empty() {
return Err("projectDir is required".to_string());
}
Ok(PathBuf::from(project_dir).join("opencode.json"))
let root = PathBuf::from(project_dir);
Ok((root.join("opencode.jsonc"), root.join("opencode.json")))
}
"global" => {
let base = if let Ok(dir) = env::var("XDG_CONFIG_HOME") {
Expand All @@ -21,12 +22,27 @@ pub fn resolve_opencode_config_path(scope: &str, project_dir: &str) -> Result<Pa
return Err("Unable to resolve config directory".to_string());
};

Ok(base.join("opencode").join("opencode.json"))
let root = base.join("opencode");
Ok((root.join("opencode.jsonc"), root.join("opencode.json")))
}
_ => Err("scope must be 'project' or 'global'".to_string()),
}
}

pub fn resolve_opencode_config_path(scope: &str, project_dir: &str) -> Result<PathBuf, String> {
let (jsonc_path, json_path) = opencode_config_candidates(scope, project_dir)?;

if jsonc_path.exists() {
return Ok(jsonc_path);
}

if json_path.exists() {
return Ok(json_path);
}

Ok(jsonc_path)
}

pub fn read_opencode_config(scope: &str, project_dir: &str) -> Result<OpencodeConfigFile, String> {
let path = resolve_opencode_config_path(scope.trim(), project_dir)?;
let exists = path.exists();
Expand Down
15 changes: 12 additions & 3 deletions packages/desktop/src-tauri/src/engine/spawn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,20 @@ pub fn build_engine_command(program: &Path, hostname: &str, port: u16, project_d
command.env("XDG_DATA_HOME", xdg_data_home);
}

if let Some(xdg_config_home) = maybe_infer_xdg_home(
let xdg_config_home = maybe_infer_xdg_home(
"XDG_CONFIG_HOME",
candidate_xdg_config_dirs(),
Path::new("opencode/opencode.json"),
) {
Path::new("opencode/opencode.jsonc"),
)
.or_else(|| {
maybe_infer_xdg_home(
"XDG_CONFIG_HOME",
candidate_xdg_config_dirs(),
Path::new("opencode/opencode.json"),
)
});

if let Some(xdg_config_home) = xdg_config_home {
command.env("XDG_CONFIG_HOME", xdg_config_home);
}

Expand Down
29 changes: 23 additions & 6 deletions packages/desktop/src-tauri/src/workspace/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,22 @@ pub fn ensure_workspace_files(workspace_path: &str, preset: &str) -> Result<(),
.map_err(|e| format!("Failed to create .openwork/templates: {e}"))?;
seed_templates(&templates_dir)?;

let config_path = root.join("opencode.json");
let mut config: serde_json::Value = if config_path.exists() {
let config_path_jsonc = root.join("opencode.jsonc");
let config_path_json = root.join("opencode.json");
let config_path = if config_path_jsonc.exists() {
config_path_jsonc
} else if config_path_json.exists() {
config_path_json
} else {
config_path_jsonc
};

let config_exists = config_path.exists();
let mut config_changed = !config_exists;
let mut config: serde_json::Value = if config_exists {
let raw = fs::read_to_string(&config_path)
.map_err(|e| format!("Failed to read {}: {e}", config_path.display()))?;
serde_json::from_str(&raw).unwrap_or_else(|_| serde_json::json!({}))
json5::from_str(&raw).unwrap_or_else(|_| serde_json::json!({}))
} else {
serde_json::json!({
"$schema": "https://opencode.ai/config.json"
Expand All @@ -173,6 +184,7 @@ pub fn ensure_workspace_files(workspace_path: &str, preset: &str) -> Result<(),
config = serde_json::json!({
"$schema": "https://opencode.ai/config.json"
});
config_changed = true;
}

let required_plugins: Vec<&str> = match preset {
Expand All @@ -196,7 +208,10 @@ pub fn ensure_workspace_files(workspace_path: &str, preset: &str) -> Result<(),
_ => vec![],
};

let merged = merge_plugins(existing_plugins, &required_plugins);
let merged = merge_plugins(existing_plugins.clone(), &required_plugins);
if merged != existing_plugins {
config_changed = true;
}
if let Some(obj) = config.as_object_mut() {
obj.insert(
"plugin".to_string(),
Expand All @@ -205,8 +220,10 @@ pub fn ensure_workspace_files(workspace_path: &str, preset: &str) -> Result<(),
}
}

fs::write(&config_path, serde_json::to_string_pretty(&config).map_err(|e| e.to_string())?)
.map_err(|e| format!("Failed to write {}: {e}", config_path.display()))?;
if config_changed {
fs::write(&config_path, serde_json::to_string_pretty(&config).map_err(|e| e.to_string())?)
.map_err(|e| format!("Failed to write {}: {e}", config_path.display()))?;
}

let openwork_path = root.join(".opencode").join("openwork.json");
if !openwork_path.exists() {
Expand Down