Loads all config sources synchronously (without remote wellknown). Merge order (TS parity): 1. Global config (~/.config/opencode/opencode.json{,c}) 2. Custom config (OPENCODE_CONFIG) 3. Project config (opencode.json{,c}) 4. .opencode directories (agents, commands, plugins, modes, config) 5. Inline config (OPENCODE_CONFIG_CONTENT) 6. Managed config directory (enterprise, highest priority) Then: leg
(&mut self, project_dir: P)
| 141 | /// 6. Managed config directory (enterprise, highest priority) |
| 142 | /// Then: legacy migrations, flag overrides, plugin dedup |
| 143 | pub fn load_all<P: AsRef<Path>>(&mut self, project_dir: P) -> Result<Config> { |
| 144 | let project_dir = project_dir.as_ref(); |
| 145 | |
| 146 | self.load_global()?; |
| 147 | self.load_from_env()?; |
| 148 | self.load_project(project_dir)?; |
| 149 | |
| 150 | // Scan .opencode directories |
| 151 | let directories = collect_opencode_directories(project_dir); |
| 152 | for dir in &directories { |
| 153 | // Load config files from .opencode dirs |
| 154 | for ext in &["opencode.jsonc", "opencode.json"] { |
| 155 | let path = dir.join(ext); |
| 156 | self.load_from_file(&path)?; |
| 157 | } |
| 158 | |
| 159 | // Load commands, agents, modes from markdown files |
| 160 | let commands = load_commands_from_dir(dir); |
| 161 | if !commands.is_empty() { |
| 162 | let mut cmd_map = self.config.command.take().unwrap_or_default(); |
| 163 | for (name, cmd) in commands { |
| 164 | cmd_map.insert(name, cmd); |
| 165 | } |
| 166 | self.config.command = Some(cmd_map); |
| 167 | } |
| 168 | |
| 169 | let agents = load_agents_from_dir(dir); |
| 170 | if !agents.is_empty() { |
| 171 | let mut agent_configs = self.config.agent.take().unwrap_or_default(); |
| 172 | for (name, agent) in agents { |
| 173 | if let Some(existing) = agent_configs.entries.get_mut(&name) { |
| 174 | // Deep merge |
| 175 | merge_agent_config(existing, agent); |
| 176 | } else { |
| 177 | agent_configs.entries.insert(name, agent); |
| 178 | } |
| 179 | } |
| 180 | self.config.agent = Some(agent_configs); |
| 181 | } |
| 182 | |
| 183 | let modes = load_modes_from_dir(dir); |
| 184 | if !modes.is_empty() { |
| 185 | let mut agent_configs = self.config.agent.take().unwrap_or_default(); |
| 186 | for (name, agent) in modes { |
| 187 | if let Some(existing) = agent_configs.entries.get_mut(&name) { |
| 188 | merge_agent_config(existing, agent); |
| 189 | } else { |
| 190 | agent_configs.entries.insert(name, agent); |
| 191 | } |
| 192 | } |
| 193 | self.config.agent = Some(agent_configs); |
| 194 | } |
| 195 | |
| 196 | // Load plugins from .ts/.js files |
| 197 | let plugins = load_plugins_from_dir(dir); |
| 198 | for plugin in plugins { |
| 199 | if !self.config.plugin.contains(&plugin) { |
| 200 | self.config.plugin.push(plugin); |