Files
vibe-kanban/shared/types.ts
Alex Netsch 036dd802d8 Force push (vibe-kanban) (#1350)
* Excellent! All tasks completed successfully. Here's a summary of the changes:

I've successfully added typed error handling to the push method following the same pattern as `CreatePrError`. Here's what was implemented:

1. **Created `PushError` enum** in `crates/server/src/routes/task_attempts.rs:608-613`
   - Single variant: `ForcePushRequired`
   - Uses proper derives for TypeScript generation

2. **Updated push handler signature** in `crates/server/src/routes/task_attempts.rs:596`
   - Changed return type to `Result<ResponseJson<ApiResponse<(), PushError>>, ApiError>`

3. **Registered error type** in `crates/server/src/bin/generate_types.rs:140`
   - Added `PushError::decl()` to the type declarations

4. **Generated TypeScript type** in `shared/types.ts:301`
   - Type: `export type PushError = { "type": "force_push_required" }`

5. **Updated frontend API** in `frontend/src/lib/api.ts`
   - Imported `PushError` type
   - Changed `push` method to return `Result<void, PushError>`
   - Uses `handleApiResponseAsResult` for proper error handling

6. **Updated `usePush` hook** in `frontend/src/hooks/usePush.ts`
   - Created custom `PushErrorWithData` class to properly pass error data
   - Updated signature to pass `errorData` to `onError` callback

7. **Updated component error handling** in `frontend/src/hooks/useGitOperations.ts:47-52`
   - Added handling for `force_push_required` error type
   - Displays user-friendly message: "Force push required. The remote branch has diverged."

All checks pass successfully! The implementation is ready for future force push functionality.

Cleanup script changes for task attempt 982f21cc-f0a3-455d-8b30-3a9911c2889f

Excellent! All tasks completed successfully. Here's a summary of the force push implementation:

I've successfully implemented a complete force push feature with user confirmation. Here's what was done:

1. **Updated Git CLI** (`crates/services/src/services/git/cli.rs:318`)
   - Added `force: bool` parameter to `push()` method
   - Uses `+refs/heads/{branch}` refspec when force is true

2. **Updated Git Service** (`crates/services/src/services/git.rs:1615`)
   - Added `force: bool` parameter to `push_to_github()` method
   - Passes force flag to Git CLI

3. **Added Force Push Endpoint** (`crates/server/src/routes/task_attempts.rs:608`)
   - New handler: `force_push_task_attempt_branch`
   - Calls `push_to_github()` with `force: true`
   - Regular push endpoint now passes `force: false`

4. **Added Route** (`crates/server/src/routes/task_attempts.rs:1581`)
   - Route: `POST /api/task-attempts/:id/push/force`

5. **API Client** (`frontend/src/lib/api.ts:561`)
   - Added `forcePush()` method
   - Returns `Result<void, PushError>`

6. **Created useForcePush Hook** (`frontend/src/hooks/useForcePush.ts`)
   - React Query mutation for force push
   - Handles typed errors
   - Invalidates branch status on success

7. **Created ForcePushDialog** (`frontend/src/components/dialogs/git/ForcePushDialog.tsx`)
   - Destructive variant with warning icon
   - Clear warning about overwriting remote changes
   - Buttons: "Cancel" and "Force Push"

8. **Integrated Dialog Flow** (`frontend/src/hooks/useGitOperations.ts:58-85`)
   - When regular push fails with `force_push_required` error:
     - Shows ForcePushDialog to confirm
     - If user confirms, executes force push
     - Handles errors from force push operation

1. User attempts to push
2. If remote has diverged, backend returns `force_push_required` error
3. Frontend shows confirmation dialog explaining the consequences
4. User can cancel or confirm force push
5. If confirmed, force push is executed
6. Success/error feedback is shown

All checks pass successfully! The feature is ready to use.

Cleanup script changes for task attempt 982f21cc-f0a3-455d-8b30-3a9911c2889f

Perfect! The fix is complete and all checks pass. Here's what was changed:

**Problem:** The `push_task_attempt_branch` endpoint was using the `?` operator which converted `GitServiceError::GitCLI(GitCliError::PushRejected(_))` into a generic `ApiError`, preventing the frontend from receiving the typed `PushError::ForcePushRequired` error.

**Solution:** Updated the endpoint in `crates/server/src/routes/task_attempts.rs:602-613` to use a `match` statement that:
1. Returns success on `Ok(_)`
2. Detects `GitServiceError::GitCLI(GitCliError::PushRejected(_))` and returns the typed error `ApiResponse::error_with_data(PushError::ForcePushRequired)`
3. Returns generic `ApiError::GitService(e)` for other errors

Now when a push is rejected due to non-fast-forward, the backend will return:
```json
{
  "success": false,
  "error_data": {
    "type": "force_push_required"
  }
}
```

This will trigger the force push confirmation dialog in the frontend, allowing the user to choose whether to force push or cancel.

Cleanup script changes for task attempt 982f21cc-f0a3-455d-8b30-3a9911c2889f

Perfect! The fix is complete and all checks pass. Here's what was changed:

**Problem:** The ForcePushDialog was not closing after the user clicked "Force Push" or "Cancel" because it only called `modal.resolve()` without calling `modal.hide()`.

**Solution:** Added `modal.hide()` calls to both handlers in `frontend/src/components/dialogs/git/ForcePushDialog.tsx`:

- **Line 24:** Added `modal.hide()` after `modal.resolve('confirmed')` in `handleConfirm`
- **Line 29:** Added `modal.hide()` after `modal.resolve('canceled')` in `handleCancel`

Now the dialog will properly close when the user clicks either button. This follows the correct NiceModal pattern where you need both:
1. `modal.resolve()` - to resolve the promise with a result
2. `modal.hide()` - to actually hide the dialog

The force push feature should now work end-to-end: push rejection → confirmation dialog → force push → dialog closes.

Perfect! All checks pass. Here's what was fixed:

The force push dialog now follows the same pattern as all other async dialogs in the codebase.

**Added:**
- `attemptId` prop (required) to identify which task attempt to force push
- `useForcePush` hook usage internally
- Loading state with `forcePush.isPending`
- Error state displayed in the dialog
- Loader spinner and "Force Pushing..." button text during operation
- Disabled buttons during operation
- Dialog stays open until operation completes

**Behavior:**
- User clicks "Force Push" → button shows spinner and "Force Pushing..."
- On success → dialog closes automatically
- On error → error shown in dialog, stays open, user can retry or cancel

**Changed:**
- Removed the manual force push call after dialog confirmation
- Now passes `attemptId` to the dialog: `ForcePushDialog.show({ attemptId })`
- Dialog handles the entire force push operation internally

1. User attempts push
2. Push rejected with `force_push_required` error
3. Dialog appears with warning
4. User clicks "Force Push"
5. **Button shows spinner and "Force Pushing..."** ← New!
6. **Buttons disabled during operation** ← New!
7. On success: dialog closes
8. On error: error displayed in dialog, user can retry

This matches the pattern used by CreatePRDialog, GhCliSetupDialog, and other async dialogs in the codebase.

* Force push i18n (vibe-kanban 5519a7db)

Run @scripts/check-i18n.sh until it passes. Make sure to check the script and set GITHUB_BASE_REF to vk/607c-add-pre-flight-c

Force push i18n (vibe-kanban 5519a7db)

Run @scripts/check-i18n.sh until it passes. Make sure to check the script and set GITHUB_BASE_REF to vk/607c-add-pre-flight-c

* fix tests
2025-11-24 15:52:05 +00:00

399 lines
24 KiB
TypeScript

// This file was generated by `crates/core/src/bin/generate_types.rs`.
// Do not edit this file manually.
// If you are an AI, and you absolutely have to edit this file, please confirm with the user first.
export type DirectoryEntry = { name: string, path: string, is_directory: boolean, is_git_repo: boolean, last_modified: bigint | null, };
export type DirectoryListResponse = { entries: Array<DirectoryEntry>, current_path: string, };
export type Project = { id: string, name: string, git_repo_path: string, setup_script: string | null, dev_script: string | null, cleanup_script: string | null, copy_files: string | null, remote_project_id: string | null, created_at: Date, updated_at: Date, };
export type CreateProject = { name: string, git_repo_path: string, use_existing_repo: boolean, setup_script: string | null, dev_script: string | null, cleanup_script: string | null, copy_files: string | null, };
export type UpdateProject = { name: string | null, git_repo_path: string | null, setup_script: string | null, dev_script: string | null, cleanup_script: string | null, copy_files: string | null, };
export type SearchResult = { path: string, is_file: boolean, match_type: SearchMatchType, };
export type SearchMatchType = "FileName" | "DirectoryName" | "FullPath";
export type CreateRemoteProjectRequest = { organization_id: string, name: string, };
export type LinkToExistingRequest = { remote_project_id: string, };
export type ExecutorAction = { typ: ExecutorActionType, next_action: ExecutorAction | null, };
export type McpConfig = { servers: { [key in string]?: JsonValue }, servers_path: Array<string>, template: JsonValue, preconfigured: JsonValue, is_toml_config: boolean, };
export type ExecutorActionType = { "type": "CodingAgentInitialRequest" } & CodingAgentInitialRequest | { "type": "CodingAgentFollowUpRequest" } & CodingAgentFollowUpRequest | { "type": "ScriptRequest" } & ScriptRequest;
export type ScriptContext = "SetupScript" | "CleanupScript" | "DevServer" | "GithubCliSetupScript";
export type ScriptRequest = { script: string, language: ScriptRequestLanguage, context: ScriptContext, };
export type ScriptRequestLanguage = "Bash";
export enum BaseCodingAgent { CLAUDE_CODE = "CLAUDE_CODE", AMP = "AMP", GEMINI = "GEMINI", CODEX = "CODEX", OPENCODE = "OPENCODE", CURSOR_AGENT = "CURSOR_AGENT", QWEN_CODE = "QWEN_CODE", COPILOT = "COPILOT", DROID = "DROID" }
export type CodingAgent = { "CLAUDE_CODE": ClaudeCode } | { "AMP": Amp } | { "GEMINI": Gemini } | { "CODEX": Codex } | { "OPENCODE": Opencode } | { "CURSOR_AGENT": CursorAgent } | { "QWEN_CODE": QwenCode } | { "COPILOT": Copilot } | { "DROID": Droid };
export type Tag = { id: string, tag_name: string, content: string, created_at: string, updated_at: string, };
export type CreateTag = { tag_name: string, content: string, };
export type UpdateTag = { tag_name: string | null, content: string | null, };
export type TagSearchParams = { search: string | null, };
export type TaskStatus = "todo" | "inprogress" | "inreview" | "done" | "cancelled";
export type Task = { id: string, project_id: string, title: string, description: string | null, status: TaskStatus, parent_task_attempt: string | null, shared_task_id: string | null, created_at: string, updated_at: string, };
export type TaskWithAttemptStatus = { has_in_progress_attempt: boolean, has_merged_attempt: boolean, last_attempt_failed: boolean, executor: string, id: string, project_id: string, title: string, description: string | null, status: TaskStatus, parent_task_attempt: string | null, shared_task_id: string | null, created_at: string, updated_at: string, };
export type TaskRelationships = { parent_task: Task | null, current_attempt: TaskAttempt, children: Array<Task>, };
export type CreateTask = { project_id: string, title: string, description: string | null, status: TaskStatus | null, parent_task_attempt: string | null, image_ids: Array<string> | null, shared_task_id: string | null, };
export type UpdateTask = { title: string | null, description: string | null, status: TaskStatus | null, parent_task_attempt: string | null, image_ids: Array<string> | null, };
export type SharedTask = { id: string, remote_project_id: string, title: string, description: string | null, status: TaskStatus, assignee_user_id: string | null, assignee_first_name: string | null, assignee_last_name: string | null, assignee_username: string | null, version: bigint, last_event_seq: bigint | null, created_at: Date, updated_at: Date, };
export type Image = { id: string, file_path: string, original_name: string, mime_type: string | null, size_bytes: bigint, hash: string, created_at: string, updated_at: string, };
export type CreateImage = { file_path: string, original_name: string, mime_type: string | null, size_bytes: bigint, hash: string, };
export type ApiResponse<T, E = T> = { success: boolean, data: T | null, error_data: E | null, message: string | null, };
export type LoginStatus = { "status": "loggedout" } | { "status": "loggedin", profile: ProfileResponse, };
export type ProfileResponse = { user_id: string, username: string | null, email: string, providers: Array<ProviderProfile>, };
export type ProviderProfile = { provider: string, username: string | null, display_name: string | null, email: string | null, avatar_url: string | null, };
export type StatusResponse = { logged_in: boolean, profile: ProfileResponse | null, degraded: boolean | null, };
export enum MemberRole { ADMIN = "ADMIN", MEMBER = "MEMBER" }
export enum InvitationStatus { PENDING = "PENDING", ACCEPTED = "ACCEPTED", DECLINED = "DECLINED", EXPIRED = "EXPIRED" }
export type Organization = { id: string, name: string, slug: string, is_personal: boolean, created_at: string, updated_at: string, };
export type OrganizationWithRole = { id: string, name: string, slug: string, is_personal: boolean, created_at: string, updated_at: string, user_role: MemberRole, };
export type ListOrganizationsResponse = { organizations: Array<OrganizationWithRole>, };
export type GetOrganizationResponse = { organization: Organization, user_role: string, };
export type CreateOrganizationRequest = { name: string, slug: string, };
export type CreateOrganizationResponse = { organization: OrganizationWithRole, };
export type UpdateOrganizationRequest = { name: string, };
export type Invitation = { id: string, organization_id: string, invited_by_user_id: string | null, email: string, role: MemberRole, status: InvitationStatus, token: string, created_at: string, expires_at: string, };
export type CreateInvitationRequest = { email: string, role: MemberRole, };
export type CreateInvitationResponse = { invitation: Invitation, };
export type ListInvitationsResponse = { invitations: Array<Invitation>, };
export type GetInvitationResponse = { id: string, organization_slug: string, role: MemberRole, expires_at: string, };
export type AcceptInvitationResponse = { organization_id: string, organization_slug: string, role: MemberRole, };
export type RevokeInvitationRequest = { invitation_id: string, };
export type OrganizationMember = { user_id: string, role: MemberRole, joined_at: string, };
export type OrganizationMemberWithProfile = { user_id: string, role: MemberRole, joined_at: string, first_name: string | null, last_name: string | null, username: string | null, email: string | null, avatar_url: string | null, };
export type ListMembersResponse = { members: Array<OrganizationMemberWithProfile>, };
export type UpdateMemberRoleRequest = { role: MemberRole, };
export type UpdateMemberRoleResponse = { user_id: string, role: MemberRole, };
export type RemoteProject = { id: string, organization_id: string, name: string, metadata: Record<string, unknown>, created_at: string, };
export type ListProjectsResponse = { projects: Array<RemoteProject>, };
export type RemoteProjectMembersResponse = { organization_id: string, members: Array<OrganizationMemberWithProfile>, };
export type UserSystemInfo = { config: Config, analytics_user_id: string, login_status: LoginStatus, environment: Environment,
/**
* Capabilities supported per executor (e.g., { "CLAUDE_CODE": ["SESSION_FORK"] })
*/
capabilities: { [key in string]?: Array<BaseAgentCapability> }, executors: { [key in BaseCodingAgent]?: ExecutorConfig }, };
export type Environment = { os_type: string, os_version: string, os_architecture: string, bitness: string, };
export type McpServerQuery = { executor: BaseCodingAgent, };
export type UpdateMcpServersBody = { servers: { [key in string]?: JsonValue }, };
export type GetMcpServerResponse = { mcp_config: McpConfig, config_path: string, };
export type CheckEditorAvailabilityQuery = { editor_type: EditorType, };
export type CheckEditorAvailabilityResponse = { available: boolean, };
export type CreateFollowUpAttempt = { prompt: string, variant: string | null, image_ids: Array<string> | null, retry_process_id: string | null, force_when_dirty: boolean | null, perform_git_reset: boolean | null, };
export type DraftResponse = { task_attempt_id: string, draft_type: DraftType, retry_process_id: string | null, prompt: string, queued: boolean, variant: string | null, image_ids: Array<string> | null, version: bigint, };
export type UpdateFollowUpDraftRequest = { prompt: string | null, variant: string | null | null, image_ids: Array<string> | null, version: bigint | null, };
export type UpdateRetryFollowUpDraftRequest = { retry_process_id: string, prompt: string | null, variant: string | null | null, image_ids: Array<string> | null, version: bigint | null, };
export type ChangeTargetBranchRequest = { new_target_branch: string, };
export type ChangeTargetBranchResponse = { new_target_branch: string, status: [number, number], };
export type RenameBranchRequest = { new_branch_name: string, };
export type RenameBranchResponse = { branch: string, };
export type CommitCompareResult = { head_oid: string, target_oid: string, ahead_from_head: number, behind_from_head: number, is_linear: boolean, };
export type OpenEditorRequest = { editor_type: string | null, file_path: string | null, };
export type OpenEditorResponse = { url: string | null, };
export type AssignSharedTaskRequest = { new_assignee_user_id: string | null, version: bigint | null, };
export type AssignSharedTaskResponse = { shared_task: SharedTask, };
export type ShareTaskResponse = { shared_task_id: string, };
export type CreateAndStartTaskRequest = { task: CreateTask, executor_profile_id: ExecutorProfileId, base_branch: string, };
export type CreateGitHubPrRequest = { title: string, body: string | null, target_branch: string | null, };
export type ImageResponse = { id: string, file_path: string, original_name: string, mime_type: string | null, size_bytes: bigint, hash: string, created_at: string, updated_at: string, };
export type Config = { config_version: string, theme: ThemeMode, executor_profile: ExecutorProfileId, disclaimer_acknowledged: boolean, onboarding_acknowledged: boolean, notifications: NotificationConfig, editor: EditorConfig, github: GitHubConfig, analytics_enabled: boolean, workspace_dir: string | null, last_app_version: string | null, show_release_notes: boolean, language: UiLanguage, git_branch_prefix: string, showcases: ShowcaseState, };
export type NotificationConfig = { sound_enabled: boolean, push_enabled: boolean, sound_file: SoundFile, };
export enum ThemeMode { LIGHT = "LIGHT", DARK = "DARK", SYSTEM = "SYSTEM" }
export type EditorConfig = { editor_type: EditorType, custom_command: string | null, remote_ssh_host: string | null, remote_ssh_user: string | null, };
export enum EditorType { VS_CODE = "VS_CODE", CURSOR = "CURSOR", WINDSURF = "WINDSURF", INTELLI_J = "INTELLI_J", ZED = "ZED", XCODE = "XCODE", CUSTOM = "CUSTOM" }
export type EditorOpenError = { "type": "executable_not_found", executable: string, editor_type: EditorType, } | { "type": "invalid_command", details: string, editor_type: EditorType, } | { "type": "launch_failed", executable: string, details: string, editor_type: EditorType, };
export type GitHubConfig = { pat: string | null, oauth_token: string | null, username: string | null, primary_email: string | null, default_pr_base: string | null, };
export enum SoundFile { ABSTRACT_SOUND1 = "ABSTRACT_SOUND1", ABSTRACT_SOUND2 = "ABSTRACT_SOUND2", ABSTRACT_SOUND3 = "ABSTRACT_SOUND3", ABSTRACT_SOUND4 = "ABSTRACT_SOUND4", COW_MOOING = "COW_MOOING", PHONE_VIBRATION = "PHONE_VIBRATION", ROOSTER = "ROOSTER" }
export type UiLanguage = "BROWSER" | "EN" | "JA" | "ES" | "KO";
export type ShowcaseState = { seen_features: Array<string>, };
export type GitBranch = { name: string, is_current: boolean, is_remote: boolean, last_commit_date: Date, };
export type Diff = { change: DiffChangeKind, oldPath: string | null, newPath: string | null, oldContent: string | null, newContent: string | null,
/**
* True when file contents are intentionally omitted (e.g., too large)
*/
contentOmitted: boolean,
/**
* Optional precomputed stats for omitted content
*/
additions: number | null, deletions: number | null, };
export type DiffChangeKind = "added" | "deleted" | "modified" | "renamed" | "copied" | "permissionChange";
export type CommandBuilder = {
/**
* Base executable command (e.g., "npx -y @anthropic-ai/claude-code@latest")
*/
base: string,
/**
* Optional parameters to append to the base command
*/
params: Array<string> | null, };
export type ExecutorProfileId = {
/**
* The executor type (e.g., "CLAUDE_CODE", "AMP")
*/
executor: BaseCodingAgent,
/**
* Optional variant name (e.g., "PLAN", "ROUTER")
*/
variant: string | null, };
export type ExecutorConfig = { [key in string]?: { "CLAUDE_CODE": ClaudeCode } | { "AMP": Amp } | { "GEMINI": Gemini } | { "CODEX": Codex } | { "OPENCODE": Opencode } | { "CURSOR_AGENT": CursorAgent } | { "QWEN_CODE": QwenCode } | { "COPILOT": Copilot } | { "DROID": Droid } };
export type ExecutorConfigs = { executors: { [key in BaseCodingAgent]?: ExecutorConfig }, };
export enum BaseAgentCapability { SESSION_FORK = "SESSION_FORK", SETUP_HELPER = "SETUP_HELPER" }
export type ClaudeCode = { append_prompt: AppendPrompt, claude_code_router?: boolean | null, plan?: boolean | null, approvals?: boolean | null, model?: string | null, dangerously_skip_permissions?: boolean | null, base_command_override?: string | null, additional_params?: Array<string> | null, };
export type Gemini = { append_prompt: AppendPrompt, model?: string | null, yolo?: boolean | null, base_command_override?: string | null, additional_params?: Array<string> | null, };
export type Amp = { append_prompt: AppendPrompt, dangerously_allow_all?: boolean | null, base_command_override?: string | null, additional_params?: Array<string> | null, };
export type Codex = { append_prompt: AppendPrompt, sandbox?: SandboxMode | null, ask_for_approval?: AskForApproval | null, oss?: boolean | null, model?: string | null, model_reasoning_effort?: ReasoningEffort | null, model_reasoning_summary?: ReasoningSummary | null, model_reasoning_summary_format?: ReasoningSummaryFormat | null, profile?: string | null, base_instructions?: string | null, include_plan_tool?: boolean | null, include_apply_patch_tool?: boolean | null, base_command_override?: string | null, additional_params?: Array<string> | null, };
export type SandboxMode = "auto" | "read-only" | "workspace-write" | "danger-full-access";
export type AskForApproval = "unless-trusted" | "on-failure" | "on-request" | "never";
export type ReasoningEffort = "low" | "medium" | "high";
export type ReasoningSummary = "auto" | "concise" | "detailed" | "none";
export type ReasoningSummaryFormat = "none" | "experimental";
export type CursorAgent = { append_prompt: AppendPrompt, force?: boolean | null, model?: string | null, base_command_override?: string | null, additional_params?: Array<string> | null, };
export type Copilot = { append_prompt: AppendPrompt, model?: string | null, allow_all_tools?: boolean | null, allow_tool?: string | null, deny_tool?: string | null, add_dir?: Array<string> | null, disable_mcp_server?: Array<string> | null, base_command_override?: string | null, additional_params?: Array<string> | null, };
export type Opencode = { append_prompt: AppendPrompt, model?: string | null, agent?: string | null, base_command_override?: string | null, additional_params?: Array<string> | null, };
export type QwenCode = { append_prompt: AppendPrompt, yolo?: boolean | null, base_command_override?: string | null, additional_params?: Array<string> | null, };
export type Droid = { append_prompt: AppendPrompt, autonomy: Autonomy, model?: string | null, reasoning_effort?: DroidReasoningEffort | null, base_command_override?: string | null, additional_params?: Array<string> | null, };
export type Autonomy = "normal" | "low" | "medium" | "high" | "skip-permissions-unsafe";
export type DroidReasoningEffort = "none" | "dynamic" | "off" | "low" | "medium" | "high";
export type AppendPrompt = string | null;
export type CodingAgentInitialRequest = { prompt: string,
/**
* Executor profile specification
*/
executor_profile_id: ExecutorProfileId, };
export type CodingAgentFollowUpRequest = { prompt: string, session_id: string,
/**
* Executor profile specification
*/
executor_profile_id: ExecutorProfileId, };
export type CreateTaskAttemptBody = { task_id: string,
/**
* Executor profile specification
*/
executor_profile_id: ExecutorProfileId, base_branch: string, };
export type RunAgentSetupRequest = { executor_profile_id: ExecutorProfileId, };
export type RunAgentSetupResponse = Record<string, never>;
export type GhCliSetupError = "BREW_MISSING" | "SETUP_HELPER_NOT_SUPPORTED" | { "OTHER": { message: string, } };
export type RebaseTaskAttemptRequest = { old_base_branch: string | null, new_base_branch: string | null, };
export type GitOperationError = { "type": "merge_conflicts", message: string, op: ConflictOp, } | { "type": "rebase_in_progress" };
export type PushError = { "type": "force_push_required" };
export type CreatePrError = { "type": "github_cli_not_installed" } | { "type": "github_cli_not_logged_in" } | { "type": "git_cli_not_logged_in" } | { "type": "git_cli_not_installed" } | { "type": "target_branch_not_found", branch: string, };
export type CommitInfo = { sha: string, subject: string, };
export type BranchStatus = { commits_behind: number | null, commits_ahead: number | null, has_uncommitted_changes: boolean | null, head_oid: string | null, uncommitted_count: number | null, untracked_count: number | null, target_branch_name: string, remote_commits_behind: number | null, remote_commits_ahead: number | null, merges: Array<Merge>,
/**
* True if a `git rebase` is currently in progress in this worktree
*/
is_rebase_in_progress: boolean,
/**
* Current conflict operation if any
*/
conflict_op: ConflictOp | null,
/**
* List of files currently in conflicted (unmerged) state
*/
conflicted_files: Array<string>, };
export type ConflictOp = "rebase" | "merge" | "cherry_pick" | "revert";
export type TaskAttempt = { id: string, task_id: string, container_ref: string | null, branch: string, target_branch: string, executor: string, worktree_deleted: boolean, setup_completed_at: string | null, created_at: string, updated_at: string, };
export type ExecutionProcess = { id: string, task_attempt_id: string, run_reason: ExecutionProcessRunReason, executor_action: ExecutorAction,
/**
* Git HEAD commit OID captured before the process starts
*/
before_head_commit: string | null,
/**
* Git HEAD commit OID captured after the process ends
*/
after_head_commit: string | null, status: ExecutionProcessStatus, exit_code: bigint | null,
/**
* dropped: true if this process is excluded from the current
* history view (due to restore/trimming). Hidden from logs/timeline;
* still listed in the Processes tab.
*/
dropped: boolean, started_at: string, completed_at: string | null, created_at: string, updated_at: string, };
export enum ExecutionProcessStatus { running = "running", completed = "completed", failed = "failed", killed = "killed" }
export type ExecutionProcessRunReason = "setupscript" | "cleanupscript" | "codingagent" | "devserver";
export type Merge = { "type": "direct" } & DirectMerge | { "type": "pr" } & PrMerge;
export type DirectMerge = { id: string, task_attempt_id: string, merge_commit: string, target_branch_name: string, created_at: string, };
export type PrMerge = { id: string, task_attempt_id: string, created_at: string, target_branch_name: string, pr_info: PullRequestInfo, };
export type MergeStatus = "open" | "merged" | "closed" | "unknown";
export type PullRequestInfo = { number: bigint, url: string, status: MergeStatus, merged_at: string | null, merge_commit_sha: string | null, };
export type Draft = { id: string, task_attempt_id: string, draft_type: DraftType, retry_process_id: string | null, prompt: string, queued: boolean, sending: boolean, variant: string | null, image_ids: Array<string> | null, created_at: string, updated_at: string, version: bigint, };
export type DraftType = "follow_up" | "retry";
export type CommandExitStatus = { "type": "exit_code", code: number, } | { "type": "success", success: boolean, };
export type CommandRunResult = { exit_status: CommandExitStatus | null, output: string | null, };
export type NormalizedEntry = { timestamp: string | null, entry_type: NormalizedEntryType, content: string, };
export type NormalizedEntryType = { "type": "user_message" } | { "type": "user_feedback", denied_tool: string, } | { "type": "assistant_message" } | { "type": "tool_use", tool_name: string, action_type: ActionType, status: ToolStatus, } | { "type": "system_message" } | { "type": "error_message", error_type: NormalizedEntryError, } | { "type": "thinking" } | { "type": "loading" } | { "type": "next_action", failed: boolean, execution_processes: number, needs_setup: boolean, };
export type FileChange = { "action": "write", content: string, } | { "action": "delete" } | { "action": "rename", new_path: string, } | { "action": "edit",
/**
* Unified diff containing file header and hunks.
*/
unified_diff: string,
/**
* Whether line number in the hunks are reliable.
*/
has_line_numbers: boolean, };
export type ActionType = { "action": "file_read", path: string, } | { "action": "file_edit", path: string, changes: Array<FileChange>, } | { "action": "command_run", command: string, result: CommandRunResult | null, } | { "action": "search", query: string, } | { "action": "web_fetch", url: string, } | { "action": "tool", tool_name: string, arguments: JsonValue | null, result: ToolResult | null, } | { "action": "task_create", description: string, } | { "action": "plan_presentation", plan: string, } | { "action": "todo_management", todos: Array<TodoItem>, operation: string, } | { "action": "other", description: string, };
export type TodoItem = { content: string, status: string, priority: string | null, };
export type NormalizedEntryError = { "type": "setup_required" } | { "type": "other" };
export type ToolResult = { type: ToolResultValueType,
/**
* For Markdown, this will be a JSON string; for JSON, a structured value
*/
value: JsonValue, };
export type ToolResultValueType = { "type": "markdown" } | { "type": "json" };
export type ToolStatus = { "status": "created" } | { "status": "success" } | { "status": "failed" } | { "status": "denied", reason: string | null, } | { "status": "pending_approval", approval_id: string, requested_at: string, timeout_at: string, } | { "status": "timed_out" };
export type PatchType = { "type": "NORMALIZED_ENTRY", "content": NormalizedEntry } | { "type": "STDOUT", "content": string } | { "type": "STDERR", "content": string } | { "type": "DIFF", "content": Diff };
export type ApprovalStatus = { "status": "pending" } | { "status": "approved" } | { "status": "denied", reason?: string, } | { "status": "timed_out" };
export type CreateApprovalRequest = { tool_name: string, tool_input: JsonValue, tool_call_id: string, };
export type ApprovalResponse = { execution_process_id: string, status: ApprovalStatus, };
export type JsonValue = number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null;