Initial commit: Triple-C app, container, and CI

Tauri v2 desktop app (React/TypeScript + Rust) for managing
containerized Claude Code environments. Includes Gitea Actions
workflow for building and pushing the sandbox container image,
and a BUILDING.md guide for manual app builds on Linux and Windows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-27 04:29:51 +00:00
commit 97a0745ead
65 changed files with 17202 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppSettings {
pub default_ssh_key_path: Option<String>,
pub default_git_user_name: Option<String>,
pub default_git_user_email: Option<String>,
pub docker_socket_path: Option<String>,
}
impl Default for AppSettings {
fn default() -> Self {
Self {
default_ssh_key_path: None,
default_git_user_name: None,
default_git_user_email: None,
docker_socket_path: None,
}
}
}

View File

@@ -0,0 +1,16 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContainerInfo {
pub container_id: String,
pub project_id: String,
pub status: String,
pub image: String,
}
pub const IMAGE_NAME: &str = "triple-c";
pub const IMAGE_TAG: &str = "latest";
pub fn full_image_name() -> String {
format!("{IMAGE_NAME}:{IMAGE_TAG}")
}

View File

@@ -0,0 +1,7 @@
pub mod project;
pub mod container_config;
pub mod app_settings;
pub use project::*;
pub use container_config::*;
pub use app_settings::*;

View File

@@ -0,0 +1,69 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Project {
pub id: String,
pub name: String,
pub path: String,
pub container_id: Option<String>,
pub status: ProjectStatus,
pub auth_mode: AuthMode,
pub allow_docker_access: bool,
pub ssh_key_path: Option<String>,
pub git_token: Option<String>,
pub git_user_name: Option<String>,
pub git_user_email: Option<String>,
pub created_at: String,
pub updated_at: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ProjectStatus {
Stopped,
Starting,
Running,
Stopping,
Error,
}
/// How the project authenticates with Claude.
/// - `Login`: User runs `claude login` inside the container (OAuth, persisted via config volume)
/// - `ApiKey`: Uses the API key stored in the OS keychain
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum AuthMode {
Login,
ApiKey,
}
impl Default for AuthMode {
fn default() -> Self {
Self::Login
}
}
impl Project {
pub fn new(name: String, path: String) -> Self {
let now = chrono::Utc::now().to_rfc3339();
Self {
id: uuid::Uuid::new_v4().to_string(),
name,
path,
container_id: None,
status: ProjectStatus::Stopped,
auth_mode: AuthMode::default(),
allow_docker_access: false,
ssh_key_path: None,
git_token: None,
git_user_name: None,
git_user_email: None,
created_at: now.clone(),
updated_at: now,
}
}
pub fn container_name(&self) -> String {
format!("triple-c-{}", self.id)
}
}