syntax = "proto3";

package globalstacks.agent.v1;

option go_package = "globalstacks/proto/gen/go/globalstacks/agent/v1;agentv1";

service AgentControlService {
  rpc Enroll(EnrollRequest) returns (EnrollResponse);
  rpc Connect(stream ConnectRequest) returns (stream ConnectResponse);
  rpc ClaimJob(ClaimJobRequest) returns (ClaimJobResponse);
  rpc UpdateJobState(UpdateJobStateRequest) returns (UpdateJobStateResponse);
  rpc StreamLogs(stream StreamLogsRequest) returns (StreamLogsResponse);
  rpc OpenShell(OpenShellRequest) returns (OpenShellResponse);
  rpc PortForward(stream PortForwardRequest) returns (stream PortForwardResponse);
  rpc SyncEnvironmentNetwork(SyncEnvironmentNetworkRequest) returns (SyncEnvironmentNetworkResponse);
}

enum AgentStatus {
  AGENT_STATUS_UNSPECIFIED = 0;
  AGENT_STATUS_REGISTERING = 1;
  AGENT_STATUS_ONLINE = 2;
  AGENT_STATUS_OFFLINE = 3;
  AGENT_STATUS_UNHEALTHY = 4;
}

enum JobState {
  JOB_STATE_UNSPECIFIED = 0;
  JOB_STATE_QUEUED = 1;
  JOB_STATE_ASSIGNED = 2;
  JOB_STATE_PREPARING = 3;
  JOB_STATE_FETCHING_SOURCE = 4;
  JOB_STATE_DETECTING_STACK = 5;
  JOB_STATE_BUILDING = 6;
  JOB_STATE_DEPLOYING = 7;
  JOB_STATE_VERIFYING = 8;
  JOB_STATE_SUCCEEDED = 9;
  JOB_STATE_FAILED = 10;
  JOB_STATE_ROLLBACK_IN_PROGRESS = 11;
  JOB_STATE_ROLLED_BACK = 12;
}

enum MeshPolicyAction {
  MESH_POLICY_ACTION_UNSPECIFIED = 0;
  MESH_POLICY_ACTION_ALLOW = 1;
  MESH_POLICY_ACTION_DENY = 2;
}

enum MeshRuntimeStatus {
  MESH_RUNTIME_STATUS_UNSPECIFIED = 0;
  MESH_RUNTIME_STATUS_UNSUPPORTED = 1;
  MESH_RUNTIME_STATUS_PENDING = 2;
  MESH_RUNTIME_STATUS_READY = 3;
  MESH_RUNTIME_STATUS_DEGRADED = 4;
  MESH_RUNTIME_STATUS_DISABLED = 5;
}

enum MeshScope {
  MESH_SCOPE_UNSPECIFIED = 0;
  MESH_SCOPE_SANDBOX = 1;
  MESH_SCOPE_INFRA = 2;
}

message AgentMetadata {
  optional string tenant_id = 1;
  optional string environment_id = 2;
  optional string agent_id = 3;
  optional string display_name = 4;
  optional string version = 5;
  repeated string capabilities = 6;
  map<string, string> labels = 7;
  optional string host_guid = 8;
}

message EnrollRequest {
  optional string bootstrap_token = 1;
  AgentMetadata metadata = 2;
}

message EnrollResponse {
  optional string agent_id = 1;
  optional string control_endpoint = 2;
  optional string stream_token = 3;
  optional AgentStatus status = 4;
}

message Heartbeat {
  optional string agent_id = 1;
  optional int64 sent_at_unix_ms = 2;
  optional AgentStatus status = 3;
  AgentRuntimeOverview overview = 4;
  optional string host_guid = 5;
}

message AgentRuntimeOverview {
  optional string hostname = 1;
  optional string platform = 2;
  optional uint32 cpu_cores = 3;
  optional double load_average_1m = 4;
  optional double load_average_5m = 5;
  optional double load_average_15m = 6;
  optional int64 uptime_seconds = 7;
  optional uint64 memory_total_bytes = 8;
  optional uint64 memory_available_bytes = 9;
  optional uint64 root_total_bytes = 10;
  optional uint64 root_available_bytes = 11;
  optional string agent_service_name = 12;
  optional string agent_service_status = 13;
  optional int64 sampled_at_unix_ms = 14;
  optional string agent_version = 15;
  optional string docker_status = 16;
  optional string docker_version = 17;
  optional string docker_status_detail = 18;
  repeated string traits = 19;
  optional uint32 max_concurrent_operations = 20;
}

message DeploymentJob {
  optional string job_id = 1;
  optional string deployment_id = 2;
  optional string tenant_id = 3;
  optional string project_id = 4;
  optional string environment_id = 5;
  optional string repository_id = 6;
  optional string requested_ref = 7;
  optional string requested_sha = 8;
  optional JobState state = 9;
  optional string repository_url = 10;
}

message ShellSessionNotice {
  optional string session_id = 1;
  optional string service_id = 2;
  optional string token = 3;
  optional int64 expires_at_unix_ms = 4;
}

message PortForwardSessionNotice {
  optional string session_id = 1;
  optional string service_id = 2;
  optional string token = 3;
  optional uint32 remote_port = 4;
  optional int64 expires_at_unix_ms = 5;
}

message EnvironmentNetworkNotice {
  optional string environment_id = 1;
  optional string network_name = 2;
  repeated string service_names = 3;
  map<string, string> metadata = 4;
}

message MeshUserJoinRequest {
  optional string user_id = 1;
  optional string network_id = 2;
  optional string device_name = 3;
}

message MeshUserJoinResponse {
  optional string control_url = 1;
  optional string auth_key = 2;
  optional string dns_domain = 3;
  optional int64 expires_at_unix_ms = 4;
}

message MeshJoinRequest {
  optional string agent_id = 1;
  optional string network_id = 2;
}

message MeshJoinResponse {
  optional string control_url = 1;
  optional string auth_key = 2;
  optional string dns_domain = 3;
  optional int64 expires_at_unix_ms = 4;
  repeated string assigned_addresses = 5;
}

message MeshService {
  optional string network_id = 1;
  optional string service_id = 2;
  optional string sandbox_id = 3;
  repeated string aliases = 4;
  repeated uint32 ports = 5;
  optional string agent_id = 6;
}

message MeshPolicy {
  optional string policy_id = 1;
  optional string source_selector = 2;
  optional string target_selector = 3;
  repeated uint32 ports = 4;
  optional MeshPolicyAction action = 5;
}

message MeshTopologyNotice {
  optional string network_id = 1;
  optional string dns_domain = 2;
  repeated MeshService services = 3;
  repeated MeshPolicy policies = 4;
  optional uint64 version = 5;
  optional MeshScope scope = 6;
  repeated string peer_agent_ids = 7;
  repeated MeshPeerEndpoint peer_endpoints = 8;
}

message MeshPeerEndpoint {
  optional string agent_id = 1;
  repeated string addresses = 2;
}

message MeshPeerLatency {
  optional string agent_id = 1;
  optional int64 latency_ms = 2;
  optional string status = 3;
  optional string error = 4;
  optional string target_address = 5;
}

message MeshStatusNotice {
  optional string network_id = 1;
  optional string agent_id = 2;
  optional MeshRuntimeStatus status = 3;
  repeated string addresses = 4;
  optional string error = 5;
  optional uint64 applied_version = 6;
  repeated MeshPeerLatency peer_latencies = 7;
}

message MeshDiagnosticsRequest {
  optional string network_id = 1;
  optional string source_selector = 2;
  optional string target_alias = 3;
  optional uint32 target_port = 4;
}

message MeshDiagnosticsCheck {
  optional string name = 1;
  optional string status = 2;
  optional string message = 3;
}

message MeshDiagnosticsResponse {
  optional string network_id = 1;
  optional string agent_id = 2;
  repeated MeshDiagnosticsCheck checks = 3;
  optional bool ready = 4;
  optional string error = 5;
}

message BlueprintCaptureRequest {
  optional string blueprint_id = 1;
  optional string blueprint_name = 2;
  optional string sandbox_id = 3;
  optional string source_container_id = 4;
  optional string mode = 5;
  optional string image_ref = 6;
}

message BlueprintCaptureResponse {
  optional string blueprint_id = 1;
  optional string sandbox_id = 2;
  optional string artifact_ref = 3;
  optional string image_ref = 4;
  optional string mode = 5;
  optional bool paused = 6;
  optional string error = 7;
}

message RegistryPullCredentialRequest {
  optional string repository_id = 1;
  optional string artifact_id = 2;
  optional string artifact_ref = 3;
}

message RegistryPullCredentialResponse {
  optional string repository_id = 1;
  optional string artifact_id = 2;
  optional string artifact_ref = 3;
  optional string registry_url = 4;
  optional string username = 5;
  optional string token = 6;
  optional string scope = 7;
  optional int64 expires_at_unix_ms = 8;
  optional string error = 9;
}

message BlueprintImageCacheWarmRequest {
  optional string job_id = 1;
  optional string blueprint_id = 2;
  optional string repository_id = 3;
  optional string artifact_id = 4;
  optional string artifact_ref = 5;
  optional string digest = 6;
  optional uint64 max_cache_bytes = 7;
  optional string registry_url = 8;
  optional string registry_username = 9;
  optional string registry_token = 10;
  optional string registry_scope = 11;
  optional int64 registry_credential_expires_at_unix_ms = 12;
}

message BlueprintImageCacheWarmResponse {
  optional string job_id = 1;
  optional string blueprint_id = 2;
  optional string repository_id = 3;
  optional string artifact_id = 4;
  optional string artifact_ref = 5;
  optional string digest = 6;
  optional string status = 7;
  optional uint64 size_bytes = 8;
  optional int64 completed_at_unix_ms = 9;
  optional string error = 10;
  optional string phase = 11;
  optional uint64 progress_bytes = 12;
  optional uint64 total_bytes = 13;
  optional int64 started_at_unix_ms = 14;
  optional string runtime = 15;
  optional string local_ref = 16;
}

message BlueprintBuildRequest {
  optional string build_id = 1;
  optional string blueprint_id = 2;
  optional string blueprint_name = 3;
  optional string repository_url = 4;
  optional string requested_ref = 5;
  optional string context_path = 6;
  optional string dockerfile_path = 7;
  optional string image_ref = 8;
  optional string registry_url = 9;
  optional string registry_username = 10;
  optional string registry_token = 11;
  optional string registry_scope = 12;
  optional int64 registry_credential_expires_at_unix_ms = 13;
  repeated string egress_hosts = 14;
  optional string builder_sandbox_id = 15;
  repeated BlueprintBuildBrokerRule broker_rules = 16;
  optional string repository_connection_id = 17;
}

message BlueprintBuildBrokerRule {
  optional string name = 1;
  repeated string hosts = 2;
  repeated string paths = 3;
  repeated string methods = 4;
  map<string, string> headers = 5;
}

message BlueprintBuildResponse {
  optional string build_id = 1;
  optional string blueprint_id = 2;
  optional string status = 3;
  optional string phase = 4;
  optional string message = 5;
  optional string artifact_ref = 6;
  optional string artifact_digest = 7;
  optional string resolved_commit = 8;
  optional string error = 9;
  optional int64 started_at_unix_ms = 10;
  optional int64 completed_at_unix_ms = 11;
  optional string local_ref = 12;
}

message BlueprintImageCacheEntry {
  optional string blueprint_id = 1;
  optional string repository_id = 2;
  optional string artifact_id = 3;
  optional string artifact_ref = 4;
  optional string digest = 5;
  optional string status = 6;
  optional uint64 size_bytes = 7;
  optional int64 last_seen_at_unix_ms = 8;
  optional int64 warmed_at_unix_ms = 9;
  optional int64 expires_at_unix_ms = 10;
}

message BlueprintImageCacheInventoryReport {
  optional string agent_id = 1;
  repeated BlueprintImageCacheEntry entries = 2;
  optional uint64 total_size_bytes = 3;
  optional uint64 max_cache_bytes = 4;
  repeated BlueprintImageCacheEntry evicted_entries = 5;
  optional int64 collected_at_unix_ms = 6;
}

message HostShellFrame {
  optional string session_id = 1;
  optional bytes stdin = 2;
  optional bytes stdout = 3;
  optional uint32 cols = 4;
  optional uint32 rows = 5;
  optional bool open = 6;
  optional bool close = 7;
  optional bool exited = 8;
  optional int32 exit_code = 9;
  optional string error = 10;
}

message SandboxTCPFrame {
  optional string session_id = 1;
  optional string sandbox_id = 2;
  optional uint32 port = 3;
  optional bool open = 4;
  optional bool close = 5;
  optional bytes data = 6;
  optional string error = 7;
}

message SourceSSHFrame {
  optional string session_id = 1;
  optional string repository_connection_id = 2;
  optional string sandbox_id = 3;
  optional string user = 4;
  optional string host = 5;
  optional uint32 port = 6;
  optional string repo_path = 7;
  optional string operation = 8;
  optional bool open = 9;
  optional bool close = 10;
  optional bytes data = 11;
  optional string error = 12;
}

message Ack {
  optional string correlation_id = 1;
}

message ControlStreamMessage {
  optional string correlation_id = 1;
  oneof body {
    Heartbeat heartbeat = 2;
    DeploymentJob job = 3;
    ShellSessionNotice shell_session = 4;
    PortForwardSessionNotice port_forward_session = 5;
    EnvironmentNetworkNotice environment_network = 6;
    Ack ack = 7;
    HostShellFrame host_shell = 8;
    ManagedContainerDiscovery managed_container_discovery = 9;
    MeshTopologyNotice mesh_topology = 10;
    MeshStatusNotice mesh_status = 11;
    MeshDiagnosticsRequest mesh_diagnostics_request = 12;
    MeshDiagnosticsResponse mesh_diagnostics_response = 13;
    BlueprintCaptureRequest blueprint_capture_request = 14;
    BlueprintCaptureResponse blueprint_capture_response = 15;
    RegistryPullCredentialRequest registry_pull_credential_request = 16;
    RegistryPullCredentialResponse registry_pull_credential_response = 17;
    BlueprintImageCacheWarmRequest blueprint_image_cache_warm_request = 18;
    BlueprintImageCacheWarmResponse blueprint_image_cache_warm_response = 19;
    BlueprintImageCacheInventoryReport blueprint_image_cache_inventory_report = 20;
    SandboxTCPFrame sandbox_tcp = 21;
    BlueprintBuildRequest blueprint_build_request = 22;
    BlueprintBuildResponse blueprint_build_response = 23;
    SourceSSHFrame source_ssh = 24;
  }
}

message ManagedContainerDiscovery {
  optional string container_id = 1;
  optional string container_name = 2;
  optional string runtime_status = 3;
  optional string deployment_id = 4;
  optional string sandbox_id = 5;
  optional string service_name = 6;
  optional string environment_id = 7;
  optional int64 runtime_started_at_unix_ms = 8;
  optional int64 runtime_finished_at_unix_ms = 9;
  optional int64 runtime_duration_ms = 10;
}

message ConnectRequest {
  ControlStreamMessage message = 1;
}

message ConnectResponse {
  ControlStreamMessage message = 1;
}

message ClaimJobRequest {
  optional string agent_id = 1;
  optional string job_id = 2;
}

message ClaimJobResponse {
  optional bool claimed = 1;
  DeploymentJob job = 2;
}

message UpdateJobStateRequest {
  optional string agent_id = 1;
  optional string job_id = 2;
  optional JobState state = 3;
  optional string message = 4;
  map<string, string> metadata = 5;
}

message UpdateJobStateResponse {
  optional JobState state = 1;
  optional bool accepted = 2;
}

message LogChunk {
  optional string agent_id = 1;
  optional string deployment_id = 2;
  optional string job_id = 3;
  optional string cursor = 4;
  optional string level = 5;
  optional string stage = 6;
  optional string message = 7;
  optional int64 timestamp_unix_ms = 8;
  map<string, string> fields = 9;
}

message StreamLogsRequest {
  LogChunk chunk = 1;
}

message StreamLogsResponse {
  optional uint64 accepted_entries = 1;
}

message OpenShellRequest {
  optional string session_id = 1;
  optional string service_id = 2;
  optional string token = 3;
  repeated string command = 4;
}

message OpenShellResponse {
  optional string session_id = 1;
  optional bool accepted = 2;
}

message PortForwardFrame {
  optional string session_id = 1;
  optional string token = 2;
  optional bytes payload = 3;
  optional bool eof = 4;
}

message PortForwardRequest {
  PortForwardFrame frame = 1;
}

message PortForwardResponse {
  PortForwardFrame frame = 1;
}

message SyncEnvironmentNetworkRequest {
  optional string environment_id = 1;
  optional string agent_id = 2;
  optional string desired_network_name = 3;
  repeated string service_names = 4;
}

message SyncEnvironmentNetworkResponse {
  optional string environment_id = 1;
  optional string network_name = 2;
  repeated string service_names = 3;
}
