119 lines
3.4 KiB
Dart
119 lines
3.4 KiB
Dart
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<void> configureManagedMcpServers({
|
|
required List<OpencodeMcpServer> 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<String> 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<OpencodeMcpServer> 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<String> 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 <String>[],
|
|
this.env = const <String, String>{},
|
|
});
|
|
|
|
final String name;
|
|
final String command;
|
|
final String url;
|
|
final List<String> args;
|
|
final Map<String, String> env;
|
|
}
|