Initial commit: Captain Claude Mobile App

- Flutter app with chat and terminal screens
- WebSocket integration for real-time chat
- xterm integration for screen sessions
- Markdown rendering with code blocks
- JWT authentication

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
ARCHITECT
2026-01-16 18:34:02 +00:00
commit 3663e4c622
31 changed files with 2343 additions and 0 deletions

65
lib/models/message.dart Normal file
View File

@@ -0,0 +1,65 @@
import 'package:uuid/uuid.dart';
class Message {
final String id;
final String role; // 'user' or 'assistant'
final String content;
final DateTime timestamp;
final bool isStreaming;
final List<String>? attachments;
Message({
String? id,
required this.role,
required this.content,
DateTime? timestamp,
this.isStreaming = false,
this.attachments,
}) : id = id ?? const Uuid().v4(),
timestamp = timestamp ?? DateTime.now();
Message copyWith({
String? id,
String? role,
String? content,
DateTime? timestamp,
bool? isStreaming,
List<String>? attachments,
}) {
return Message(
id: id ?? this.id,
role: role ?? this.role,
content: content ?? this.content,
timestamp: timestamp ?? this.timestamp,
isStreaming: isStreaming ?? this.isStreaming,
attachments: attachments ?? this.attachments,
);
}
factory Message.fromJson(Map<String, dynamic> json) {
return Message(
id: json['id'],
role: json['role'],
content: json['content'],
timestamp: json['timestamp'] != null
? DateTime.parse(json['timestamp'])
: DateTime.now(),
attachments: json['attachments'] != null
? List<String>.from(json['attachments'])
: null,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'role': role,
'content': content,
'timestamp': timestamp.toIso8601String(),
'attachments': attachments,
};
}
bool get isUser => role == 'user';
bool get isAssistant => role == 'assistant';
}

50
lib/models/session.dart Normal file
View File

@@ -0,0 +1,50 @@
class ScreenSession {
final String name;
final String pid;
final bool attached;
ScreenSession({
required this.name,
required this.pid,
required this.attached,
});
factory ScreenSession.fromJson(Map<String, dynamic> json) {
return ScreenSession(
name: json['name'] ?? '',
pid: json['pid'] ?? '',
attached: json['attached'] ?? false,
);
}
Map<String, dynamic> toJson() {
return {
'name': name,
'pid': pid,
'attached': attached,
};
}
}
class Conversation {
final String id;
final String title;
final DateTime createdAt;
final int messageCount;
Conversation({
required this.id,
required this.title,
required this.createdAt,
required this.messageCount,
});
factory Conversation.fromJson(Map<String, dynamic> json) {
return Conversation(
id: json['id'],
title: json['title'] ?? 'Untitled',
createdAt: DateTime.parse(json['created_at']),
messageCount: json['message_count'] ?? 0,
);
}
}

29
lib/models/user.dart Normal file
View File

@@ -0,0 +1,29 @@
class User {
final String username;
final String token;
final DateTime expiresAt;
User({
required this.username,
required this.token,
required this.expiresAt,
});
bool get isExpired => DateTime.now().isAfter(expiresAt);
factory User.fromJson(Map<String, dynamic> json) {
return User(
username: json['username'],
token: json['token'],
expiresAt: DateTime.parse(json['expires_at']),
);
}
Map<String, dynamic> toJson() {
return {
'username': username,
'token': token,
'expires_at': expiresAt.toIso8601String(),
};
}
}