import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:dartssh2/dartssh2.dart'; import 'package:flutter/foundation.dart'; /// Opencode API 响应模型 class OpencodeResponse { final String id; final String? content; final String? error; final Map? toolCalls; final bool isComplete; final DateTime timestamp; OpencodeResponse({ required this.id, this.content, this.error, this.toolCalls, this.isComplete = false, DateTime? timestamp, }) : timestamp = timestamp ?? DateTime.now(); factory OpencodeResponse.fromJson(Map json) { return OpencodeResponse( id: json['id'] ?? '', content: json['content'], error: json['error'], toolCalls: json['tool_calls'], isComplete: json['is_complete'] ?? false, timestamp: json['timestamp'] != null ? DateTime.parse(json['timestamp']) : DateTime.now(), ); } Map toJson() => { 'id': id, 'content': content, 'error': error, 'tool_calls': toolCalls, 'is_complete': isComplete, 'timestamp': timestamp.toIso8601String(), }; } /// Opencode 消息模型 class OpencodeMessage { final String id; final String role; // 'user', 'assistant', 'system' final String content; final DateTime timestamp; final List>? toolCalls; final Map? toolResults; OpencodeMessage({ required this.id, required this.role, required this.content, DateTime? timestamp, this.toolCalls, this.toolResults, }) : timestamp = timestamp ?? DateTime.now(); factory OpencodeMessage.user(String content) { return OpencodeMessage( id: _generateId(), role: 'user', content: content, ); } factory OpencodeMessage.assistant(String content) { return OpencodeMessage( id: _generateId(), role: 'assistant', content: content, ); } factory OpencodeMessage.system(String content) { return OpencodeMessage( id: _generateId(), role: 'system', content: content, ); } factory OpencodeMessage.fromJson(Map json) { return OpencodeMessage( id: json['id'] ?? _generateId(), role: json['role'] ?? 'user', content: json['content'] ?? '', timestamp: json['timestamp'] != null ? DateTime.parse(json['timestamp']) : DateTime.now(), toolCalls: json['tool_calls'] != null ? List>.from(json['tool_calls']) : null, toolResults: json['tool_results'], ); } Map toJson() => { 'id': id, 'role': role, 'content': content, 'timestamp': timestamp.toIso8601String(), 'tool_calls': toolCalls, 'tool_results': toolResults, }; static String _generateId() { return DateTime.now().millisecondsSinceEpoch.toString(); } } /// Opencode 会话配置 class OpencodeSession { final String id; final String serverId; final String serverName; final List messages; final DateTime createdAt; DateTime updatedAt; String? title; OpencodeSession({ required this.id, required this.serverId, required this.serverName, this.messages = const [], DateTime? createdAt, DateTime? updatedAt, this.title, }) : createdAt = createdAt ?? DateTime.now(), updatedAt = updatedAt ?? DateTime.now(); factory OpencodeSession.create({ required String serverId, required String serverName, String? title, }) { return OpencodeSession( id: _generateId(), serverId: serverId, serverName: serverName, title: title, messages: [ OpencodeMessage.system( 'You are Opencode, a helpful AI assistant running inside an SSH session. ' 'You have access to the server filesystem and can execute commands via tools.', ), ], ); } void addMessage(OpencodeMessage message) { messages.add(message); updatedAt = DateTime.now(); } Map toJson() => { 'id': id, 'server_id': serverId, 'server_name': serverName, 'messages': messages.map((m) => m.toJson()).toList(), 'created_at': createdAt.toIso8601String(), 'updated_at': updatedAt.toIso8601String(), 'title': title, }; factory OpencodeSession.fromJson(Map json) { return OpencodeSession( id: json['id'] ?? _generateId(), serverId: json['server_id'] ?? '', serverName: json['server_name'] ?? '', messages: (json['messages'] as List?) ?.map((m) => OpencodeMessage.fromJson(m)) .toList() ?? [], createdAt: json['created_at'] != null ? DateTime.parse(json['created_at']) : DateTime.now(), updatedAt: json['updated_at'] != null ? DateTime.parse(json['updated_at']) : DateTime.now(), title: json['title'], ); } static String _generateId() { return DateTime.now().millisecondsSinceEpoch.toString(); } } /// Opencode 安装状态 enum OpencodeInstallStatus { notInstalled, installing, installed, error, } /// Opencode 服务器配置 class OpencodeServerConfig { final String serverId; String opencodePath; String configPath; String apiPort; bool autoStart; Map envVars; String? apiKey; // Opencode API Key OpencodeServerConfig({ required this.serverId, this.opencodePath = '/usr/local/bin/opencode', this.configPath = '~/.config/opencode', this.apiPort = '8080', this.autoStart = true, this.envVars = const {}, this.apiKey, }); Map toJson() => { 'server_id': serverId, 'opencode_path': opencodePath, 'config_path': configPath, 'api_port': apiPort, 'auto_start': autoStart, 'env_vars': envVars, 'api_key': apiKey, }; factory OpencodeServerConfig.fromJson(Map json) { return OpencodeServerConfig( serverId: json['server_id'] ?? '', opencodePath: json['opencode_path'] ?? '/usr/local/bin/opencode', configPath: json['config_path'] ?? '~/.config/opencode', apiPort: json['api_port'] ?? '8080', autoStart: json['auto_start'] ?? true, envVars: Map.from(json['env_vars'] ?? {}), apiKey: json['api_key'], ); } }