syntax = "proto3";

package heddle.v1;

// Agent timeline object store. This service is the local daemon bridge used by
// harnesses like OpenCode: clients submit typed operations, while the daemon
// stores canonical versioned Heddle timeline operation objects and returns
// their content-addressed ids.
service TimelineService {
  rpc RecordOperation(RecordTimelineOperationRequest) returns (AgentTimelineOperationRecord);
  rpc GetOperation(GetTimelineOperationRequest) returns (AgentTimelineOperationRecord);
  rpc GetTimelineStatus(GetTimelineStatusRequest) returns (AgentTimelineStatus);
  rpc GetTimelineNavigation(GetTimelineNavigationRequest) returns (TimelineNavigationSnapshot);
  rpc ListTimelineSteps(ListTimelineStepsRequest) returns (ListTimelineStepsResponse);
  rpc ResolveNativeToolCall(ResolveNativeToolCallRequest) returns (AgentTimelineStepSummary);
  rpc SeekToStep(SeekTimelineToStepRequest) returns (TimelineCursorMoveResponse);
  rpc SeekToNativeToolCall(SeekTimelineToNativeToolCallRequest) returns (TimelineCursorMoveResponse);
  rpc UndoToolCall(TimelineCursorRequest) returns (TimelineCursorMoveResponse);
  rpc RedoToolCall(TimelineCursorRequest) returns (TimelineCursorMoveResponse);
  rpc CreateTimelineBranch(CreateTimelineBranchRequest) returns (CreateTimelineBranchResponse);
  rpc PreviewTimelineSeek(PreviewTimelineSeekRequest) returns (TimelineSeekPreview);
  rpc MaterializeTimelineCursor(MaterializeTimelineCursorRequest) returns (TimelineMaterializeResponse);
  rpc ForkTimelineFromSelector(ForkTimelineFromSelectorRequest) returns (ForkTimelineFromSelectorResponse);
  rpc ResetTimelineCursor(ResetTimelineCursorRequest) returns (ResetTimelineCursorResponse);
  rpc RecoverTimelineMaterialization(RecoverTimelineMaterializationRequest) returns (RecoverTimelineMaterializationResponse);
}

message RecordTimelineOperationRequest {
  string repo_path = 1;
  AgentTimelineOperationDraft operation = 2;
  string client_operation_id = 15;
}

message GetTimelineOperationRequest {
  string repo_path = 1;
  bytes operation_id = 2;
}

message GetTimelineStatusRequest {
  string repo_path = 1;
  string thread = 2;
}

message GetTimelineNavigationRequest {
  string repo_path = 1;
  string thread = 2;
}

message ListTimelineStepsRequest {
  string repo_path = 1;
  string thread = 2;
  string branch_id = 3;
  uint32 limit = 4;
}

message ListTimelineStepsResponse {
  repeated AgentTimelineStepSummary steps = 1;
  AgentTimelineStatus status = 2;
}

message ResolveNativeToolCallRequest {
  string repo_path = 1;
  string thread = 2;
  string harness = 3;
  string session_id = 4;
  string message_id = 5;
  string tool_call_id = 6;
}

message SeekTimelineToStepRequest {
  string repo_path = 1;
  string thread = 2;
  string branch_id = 3;
  string step_id = 4;
  string reason = 5;
  string client_operation_id = 15;
}

message SeekTimelineToNativeToolCallRequest {
  string repo_path = 1;
  string thread = 2;
  string harness = 3;
  string session_id = 4;
  string message_id = 5;
  string tool_call_id = 6;
  string reason = 7;
  string client_operation_id = 15;
}

message TimelineCursorRequest {
  string repo_path = 1;
  string thread = 2;
  string branch_id = 3;
  string client_operation_id = 15;
}

message TimelineCursorMoveResponse {
  AgentTimelineStatus status = 1;
  AgentTimelineOperationRecord operation = 2;
}

message CreateTimelineBranchRequest {
  string repo_path = 1;
  string thread = 2;
  string from_step_id = 3;
  string branch_id = 4;
  string reason = 5;
  string client_operation_id = 15;
}

message CreateTimelineBranchResponse {
  AgentTimelineStatus status = 1;
  string branch_id = 2;
  string parent_branch_id = 3;
  string from_step_id = 4;
  AgentTimelineOperationRecord operation = 5;
}

message PreviewTimelineSeekRequest {
  string repo_path = 1;
  TimelineSeekSelector selector = 2;
  TimelineMaterializeMode mode = 3;
}

message MaterializeTimelineCursorRequest {
  string repo_path = 1;
  TimelineSeekSelector selector = 2;
  TimelineMaterializeMode mode = 3;
  string client_operation_id = 15;
}

message ForkTimelineFromSelectorRequest {
  string repo_path = 1;
  TimelineSeekSelector selector = 2;
  string branch_id = 3;
  string reason = 4;
  string client_operation_id = 15;
}

message ForkTimelineFromSelectorResponse {
  TimelineNavigationSnapshot navigation = 1;
  AgentTimelineOperationRecord operation = 2;
  string branch_id = 3;
  string parent_branch_id = 4;
  string from_step_id = 5;
}

message ResetTimelineCursorRequest {
  string repo_path = 1;
  TimelineSeekSelector selector = 2;
  TimelineMaterializeMode mode = 3;
  bool materialize_checkout = 4;
  string client_operation_id = 15;
}

message ResetTimelineCursorResponse {
  TimelineNavigationSnapshot navigation = 1;
  AgentTimelineOperationRecord cursor_operation = 2;
  TimelineMaterializeResponse materialization = 3;
}

message RecoverTimelineMaterializationRequest {
  string repo_path = 1;
  string thread = 2;
  string client_operation_id = 15;
}

message RecoverTimelineMaterializationResponse {
  TimelineNavigationSnapshot navigation = 1;
  AgentTimelineOperationRecord recovered_cursor_operation = 2;
  TimelineMaterializationRecoveryStatus recovery_status = 3;
  repeated TimelineMaterializationRecoveryBlocker recovery_blockers = 4;
}

message TimelineSeekSelector {
  oneof target {
    TimelineSeekStepSelector step = 1;
    TimelineSeekNativeToolCallSelector native_tool_call = 2;
    TimelineCursorSelector undo = 3;
    TimelineCursorSelector redo = 4;
    TimelineCursorSelector current_cursor = 5;
  }
}

message TimelineSeekStepSelector {
  string thread = 1;
  string branch_id = 2;
  string step_id = 3;
}

message TimelineSeekNativeToolCallSelector {
  string thread = 1;
  string harness = 2;
  string session_id = 3;
  string message_id = 4;
  string tool_call_id = 5;
}

message TimelineCursorSelector {
  string thread = 1;
  string branch_id = 2;
}

enum TimelineMaterializeMode {
  TIMELINE_MATERIALIZE_MODE_UNSPECIFIED = 0;
  TIMELINE_MATERIALIZE_MODE_FAIL_IF_DIRTY = 1;
  TIMELINE_MATERIALIZE_MODE_CAPTURE_CURRENT_THEN_SEEK = 2;
}

enum TimelineMaterializeStatus {
  TIMELINE_MATERIALIZE_STATUS_UNSPECIFIED = 0;
  TIMELINE_MATERIALIZE_STATUS_MATERIALIZED = 1;
  TIMELINE_MATERIALIZE_STATUS_ALREADY_AT_TARGET = 2;
  TIMELINE_MATERIALIZE_STATUS_REFUSED = 3;
  TIMELINE_MATERIALIZE_STATUS_UNSUPPORTED = 4;
  TIMELINE_MATERIALIZE_STATUS_RECOVERY_BLOCKED = 5;
}

enum TimelineMaterializationRecoveryStatus {
  TIMELINE_MATERIALIZATION_RECOVERY_STATUS_UNSPECIFIED = 0;
  TIMELINE_MATERIALIZATION_RECOVERY_STATUS_NO_PENDING = 1;
  TIMELINE_MATERIALIZATION_RECOVERY_STATUS_CURSOR_RECORDED = 2;
  TIMELINE_MATERIALIZATION_RECOVERY_STATUS_ALREADY_APPLIED = 3;
  TIMELINE_MATERIALIZATION_RECOVERY_STATUS_BLOCKED = 4;
}

enum TimelineMaterializationBlockerKind {
  TIMELINE_MATERIALIZATION_BLOCKER_KIND_UNSPECIFIED = 0;
  TIMELINE_MATERIALIZATION_BLOCKER_KIND_UNSUPPORTED_MODE = 1;
  TIMELINE_MATERIALIZATION_BLOCKER_KIND_DIRTY_WORKTREE = 2;
  TIMELINE_MATERIALIZATION_BLOCKER_KIND_CHECKOUT_STATE_UNKNOWN = 3;
  TIMELINE_MATERIALIZATION_BLOCKER_KIND_MISSING_TREE = 4;
}

message TimelineMaterializationBlocker {
  TimelineMaterializationBlockerKind kind = 1;
  string message = 2;
  TimelineMaterializeMode unsupported_mode = 3;
  repeated string paths = 4;
  bytes state = 5;
  string state_display_id = 6;
}

enum TimelineMaterializationRecoveryBlockerKind {
  TIMELINE_MATERIALIZATION_RECOVERY_BLOCKER_KIND_UNSPECIFIED = 0;
  TIMELINE_MATERIALIZATION_RECOVERY_BLOCKER_KIND_CHECKOUT_NOT_AT_TARGET = 1;
}

message TimelineMaterializationRecoveryBlocker {
  TimelineMaterializationRecoveryBlockerKind kind = 1;
  string message = 2;
  bytes checkout_state = 3;
  string checkout_state_display_id = 4;
  bool checkout_state_known = 5;
  bytes target_state = 6;
  string target_state_display_id = 7;
}

message TimelineSeekPreview {
  AgentTimelineStatus current_status = 1;
  AgentTimelineStepSummary current_step = 2;
  string target_branch_id = 3;
  string target_step_id = 4;
  bytes target_state = 5;
  string target_state_display_id = 6;
  AgentTimelineStepSummary target_step = 7;
  bytes current_state = 8;
  string current_state_display_id = 9;
  repeated string changed_paths = 10;
  bool worktree_dirty = 11;
  bool worktree_dirty_known = 12;
  repeated TimelineMaterializationBlocker blockers = 13;
  bool materialization_supported = 14;
  bytes checkout_state = 15;
  string checkout_state_display_id = 16;
  bool can_materialize = 17;
}

message TimelineMaterializeResponse {
  TimelineSeekPreview preview = 1;
  AgentTimelineOperationRecord cursor_operation = 2;
  AgentTimelineStatus updated_status = 3;
  bool materialized = 4;
  repeated TimelineMaterializationBlocker blockers = 5;
  TimelineMaterializeStatus status = 6;
  AgentTimelineOperationRecord recovered_cursor_operation = 7;
  TimelineMaterializationRecoveryStatus recovery_status = 8;
  repeated TimelineMaterializationRecoveryBlocker recovery_blockers = 9;
}

enum TimelineNavigationRecoveryStatus {
  TIMELINE_NAVIGATION_RECOVERY_STATUS_UNSPECIFIED = 0;
  TIMELINE_NAVIGATION_RECOVERY_STATUS_PENDING_CURSOR_RECORD = 1;
  TIMELINE_NAVIGATION_RECOVERY_STATUS_BLOCKED = 2;
  TIMELINE_NAVIGATION_RECOVERY_STATUS_ALREADY_APPLIED = 3;
}

message TimelineNavigationSnapshot {
  string thread = 1;
  TimelineNavigationCursor cursor = 2;
  repeated TimelineNavigationBranch branches = 3;
  repeated TimelineNavigationStep steps = 4;
  repeated string active_branch_path = 5;
  TimelineNavigationActionAvailability actions = 6;
  TimelineNavigationRecovery recovery = 7;
  AgentTimelineStatus status = 8;
}

message TimelineNavigationCursor {
  string branch_id = 1;
  string step_id = 2;
  bytes state = 3;
  string state_display_id = 4;
}

message TimelineNavigationBranch {
  string branch_id = 1;
  string parent_branch_id = 2;
  string forked_from_step_id = 3;
  bytes forked_from_state = 4;
  string forked_from_state_display_id = 5;
  string reason = 6;
  int64 created_at_ms = 7;
  repeated bytes operation_ids = 8;
  repeated string operation_display_ids = 9;
  repeated string step_ids = 10;
  bool is_active = 11;
  bool is_on_active_path = 12;
}

message TimelineNavigationStep {
  AgentTimelineStepSummary step = 1;
  bytes cursor_state = 2;
  string cursor_state_display_id = 3;
  bool is_current = 4;
  bool is_on_active_branch_path = 5;
  bool can_seek = 6;
  bool can_fork = 7;
  bool can_reset = 8;
  bool can_materialize = 9;
  bool has_boundary_warning = 10;
}

message TimelineNavigationActionAvailability {
  bool can_undo = 1;
  bool can_redo = 2;
}

message TimelineNavigationRecovery {
  TimelineNavigationRecoveryStatus status = 1;
  string thread = 2;
  string branch_id = 3;
  string from_step_id = 4;
  string to_step_id = 5;
  bytes from_state = 6;
  string from_state_display_id = 7;
  bytes to_state = 8;
  string to_state_display_id = 9;
  string reason = 10;
  int64 moved_at_ms = 11;
  bytes checkout_state = 12;
  string checkout_state_display_id = 13;
  bool checkout_state_known = 14;
}

message AgentTimelineOperationDraft {
  repeated string labels = 1;
  oneof body {
    AgentTimelineToolCallStarted tool_call_started = 10;
    AgentTimelineToolCallFinished tool_call_finished = 11;
    AgentTimelineCursorMoved cursor_moved = 12;
    AgentTimelineBranchCreated branch_created = 13;
  }
}

message AgentTimelineOperationRecord {
  bytes operation_id = 1;
  string display_id = 2;
  uint32 schema_version = 3;
  string kind = 4;
  repeated string labels = 5;
  oneof body {
    AgentTimelineToolCallStarted tool_call_started = 10;
    AgentTimelineToolCallFinished tool_call_finished = 11;
    AgentTimelineCursorMoved cursor_moved = 12;
    AgentTimelineBranchCreated branch_created = 13;
  }
  bytes envelope = 20;
}

message AgentTimelineStatus {
  string thread = 1;
  string current_branch_id = 2;
  string current_step_id = 3;
  AgentTimelineStateSummary current_state = 4;
  uint32 branch_count = 5;
  uint32 step_count = 6;
}

message AgentTimelineStateSummary {
  bytes state_id = 1;
  string display_id = 2;
  string source_step_id = 3;
  AgentTimelineToolPayload payload = 4;
}

message AgentTimelineStepSummary {
  string thread = 1;
  string step_id = 2;
  string branch_id = 3;
  string parent_step_id = 4;
  AgentTimelineNativeToolCall native = 5;
  string tool_name = 6;
  string status = 7;
  bool changed = 8;
  repeated string touched_paths = 9;
  bytes before_state = 10;
  bytes after_state = 11;
  bytes capture_state = 12;
  AgentTimelineToolPayload payload = 13;
  repeated string labels = 14;
  int64 started_at_ms = 15;
  int64 finished_at_ms = 16;
  repeated bytes operation_ids = 17;
  repeated string operation_display_ids = 18;
  optional uint64 capture_oplog_batch_id = 19;
}

message AgentTimelineToolPayload {
  string summary = 1;
  bytes hash = 2;
}

message AgentTimelineNativeToolCall {
  string harness = 1;
  string session_id = 2;
  string message_id = 3;
  string tool_call_id = 4;
}

message AgentTimelineToolCallStarted {
  string thread = 1;
  string step_id = 2;
  string branch_id = 3;
  string parent_step_id = 4;
  AgentTimelineNativeToolCall native = 5;
  string tool_name = 6;
  bytes before_state = 7;
  AgentTimelineToolPayload payload = 8;
  int64 started_at_ms = 9;
}

message AgentTimelineToolCallFinished {
  string thread = 1;
  string step_id = 2;
  string branch_id = 3;
  AgentTimelineNativeToolCall native = 4;
  string status = 5;
  bytes before_state = 6;
  bytes after_state = 7;
  bytes capture_state = 8;
  optional uint64 capture_oplog_batch_id = 9;
  bool changed = 10;
  repeated string touched_paths = 11;
  AgentTimelineToolPayload payload = 12;
  int64 finished_at_ms = 13;
}

message AgentTimelineCursorMoved {
  string thread = 1;
  string branch_id = 2;
  string from_step_id = 3;
  string to_step_id = 4;
  bytes from_state = 5;
  bytes to_state = 6;
  string reason = 7;
  int64 moved_at_ms = 8;
}

message AgentTimelineBranchCreated {
  string thread = 1;
  string branch_id = 2;
  string parent_branch_id = 3;
  string from_step_id = 4;
  bytes from_state = 5;
  string reason = 6;
  int64 created_at_ms = 7;
}
