import 'dart:io'; class OpencodeConfigBridge { OpencodeConfigBridge({String? opencodeHome}) : opencodeHome = opencodeHome ?? '${Platform.environment['HOME'] ?? ''}/.opencode'; static const String _managedMcpBlockStart = '# BEGIN XWORKMATE MANAGED MCP BLOCK'; static const String _managedMcpBlockEnd = '# END XWORKMATE MANAGED MCP BLOCK'; final String opencodeHome; Future configureManagedMcpServers({ required List servers, }) async { final configDir = Directory(opencodeHome); if (!await configDir.exists()) { await configDir.create(recursive: true); } final configFile = File('$opencodeHome/config.toml'); final existingConfig = await configFile.exists() ? await configFile.readAsString() : ''; final preserved = _stripManagedMcpBlock(existingConfig).trimRight(); final managedBlock = _buildManagedMcpBlock(servers); final merged = preserved.isEmpty ? '$managedBlock\n' : '$preserved\n\n$managedBlock\n'; await configFile.writeAsString(merged); } Future readConfig() async { final configFile = File('$opencodeHome/config.toml'); if (!await configFile.exists()) { return ''; } return configFile.readAsString(); } String _stripManagedMcpBlock(String content) { if (content.isEmpty) { return content; } var remaining = content; while (true) { final start = remaining.indexOf(_managedMcpBlockStart); if (start < 0) { break; } final end = remaining.indexOf(_managedMcpBlockEnd, start); if (end < 0) { remaining = remaining.substring(0, start); break; } remaining = remaining.substring(0, start) + remaining.substring(end + _managedMcpBlockEnd.length); } return remaining; } String _buildManagedMcpBlock(List servers) { final buffer = StringBuffer() ..writeln(_managedMcpBlockStart) ..writeln('# Generated by XWorkmate - Managed MCP Server Configuration') ..writeln('# Last updated: ${DateTime.now().toIso8601String()}') ..writeln(); for (final server in servers) { buffer.writeln('[mcp_servers.${server.name}]'); if (server.url.trim().isNotEmpty) { buffer.writeln('url = "${server.url.trim()}"'); } else { buffer.writeln('type = "stdio"'); buffer.writeln('command = "${server.command}"'); if (server.args.isNotEmpty) { buffer.writeln('args = ${_formatTomlArray(server.args)}'); } } if (server.env.isNotEmpty) { final entries = server.env.entries .map((entry) => '${entry.key} = "${entry.value}"') .join(', '); buffer.writeln('env = { $entries }'); } buffer.writeln(); } buffer.writeln(_managedMcpBlockEnd); return buffer.toString().trimRight(); } String _formatTomlArray(List items) { if (items.isEmpty) { return '[]'; } return '[${items.map((item) => '"$item"').join(', ')}]'; } } class OpencodeMcpServer { const OpencodeMcpServer({ required this.name, this.command = '', this.url = '', this.args = const [], this.env = const {}, }); final String name; final String command; final String url; final List args; final Map env; }