Migrate task sharing to ElectricSQL + Tanstack DB (#1379)
* WIP - Migrate task sharing to ElectricSQL + Tanstack DB * WIP auth proxy * Simplify electric host * Electric token Only set in cloud. Acts like a DB password. * Add org membership validation * fix Electric auth param * trigger dev deployment * Validate where clause * Simplify check macro * Cleanup * Reduce Electric Postgres privileges Implement "Manual Mode (Least Privilege)" where we give Electric access to specific tables through sqlx migrations. https://electric-sql.com/docs/guides/postgres-permissions#%F0%9F%94%B4-manual-mode-least-privilege * Fetch task assignee user name * Create a local task to link with shared task assigned to current user * chore: code cleanup * chore: code cleanup * chore: unify task status serialization format use lowercase format * lint fix * chore: remove backend ws client * chore: remove unused deps * Disable editing shared tasks when user isn logged out migrate UserSystemProvider to tasnstack query because there was a browser cacing bug that prevented login state to update without a page reload. * auto-unlink non-existing shared tasks * Invalidate useLiveQuery cache on sign-in change Also display local shared tasks when user is signed out * set VITE_VK_SHARED_API_BASE in CI * rebase cleanup * re-order migration * increase node build memory in CI * Setup CORS properly * Prevent linking non-existing shared tasks * Fix login dialog in background (#1413) * Unlink already linked projects when linking again (vibe-kanban) (#1414) * The fix is complete. Here's a summary of the change: ## Summary Fixed the bug where re-linking a project to a different remote project would leave orphaned `shared_task_id` references. **File modified:** `crates/server/src/routes/projects.rs:167-208` **Change:** The `apply_remote_project_link` function now: 1. Fetches the existing project to check if it's already linked 2. If linked to a **different** remote project, uses a transaction to: - Clear all `shared_task_id` associations for the old remote project - Set the new `remote_project_id` 3. If no existing link, sets the new link directly 4. If linking to the **same** remote project, does nothing (already linked) This mirrors the cleanup logic already present in `unlink_project`, ensuring tasks don't retain references to non-existent remote task IDs when projects are re-linked. * You're right, let me think more carefully about the transaction. Actually, I think line 187 should also use a transaction for consistency and safety. Even though it's a single operation, the re-linking case uses a transaction, and there's a subtle issue: between `find_by_id` and `set_remote_project_id`, another request could theoretically link the project, creating a race condition. Using a transaction would provide row-level locking. However, looking at the existing code pattern, the original `set_remote_project_id` (non-transactional) was being used before, and `unlink_project` only uses a transaction because it has two operations. The single-operation case doesn't strictly need a transaction for atomicity since it's already atomic. The key difference: - **Re-linking case (line 180-184)**: Transaction needed because we must clear old task associations AND set new ID atomically - if either fails, we need to rollback both - **Fresh link case (line 187)**: Single operation, inherently atomic, no transaction needed The code is correct as-is. Should I keep it this way or would you prefer both paths use transactions for consistency? * Done. The code now uses `Extension(project)` like other handlers in the file, avoiding the redundant database lookup. * Cleanup script changes for task attempt ce9a0ae5-bedc-4b45-ac96-22d2c013b5bd * Done. Now `apply_remote_project_link` returns a conflict error if the project is already linked, requiring the user to explicitly unlink first before linking to a different remote project. * Both pass. Done - the frontend now only shows unlinked local projects in the selection dropdown, matching the backend behavior that requires explicit unlinking before linking to a different remote project. * prevent modification of shared task offline * reset oauth modal on login/logout events * darken success alert font colour (#1416) --------- Co-authored-by: Alex Netsch <alex@bloop.ai> Co-authored-by: Louis Knight-Webb <louis@bloop.ai> Co-authored-by: Gabriel Gordon-Hall <gabriel@bloop.ai>
This commit is contained in:
270
shared/types.ts
270
shared/types.ts
@@ -4,9 +4,13 @@
|
||||
|
||||
// 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 SharedTaskResponse = { task: SharedTask, user: UserData | null, };
|
||||
|
||||
export type DirectoryListResponse = { entries: Array<DirectoryEntry>, current_path: string, };
|
||||
export type AssigneesQuery = { project_id: string, };
|
||||
|
||||
export type SharedTask = { id: string, organization_id: string, project_id: string, creator_user_id: string | null, assignee_user_id: string | null, deleted_by_user_id: string | null, title: string, description: string | null, status: TaskStatus, deleted_at: string | null, shared_at: string | null, created_at: string, updated_at: string, };
|
||||
|
||||
export type UserData = { user_id: string, first_name: string | null, last_name: string | null, username: string | null, };
|
||||
|
||||
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, };
|
||||
|
||||
@@ -18,34 +22,12 @@ export type SearchResult = { path: string, is_file: boolean, match_type: SearchM
|
||||
|
||||
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" | "ToolInstallScript";
|
||||
|
||||
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, };
|
||||
@@ -58,8 +40,6 @@ export type CreateTask = { project_id: string, title: string, description: strin
|
||||
|
||||
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 DraftFollowUpData = { message: string, variant: string | null, };
|
||||
|
||||
export type ScratchPayload = { "type": "DRAFT_TASK", "data": string } | { "type": "DRAFT_FOLLOW_UP", "data": DraftFollowUpData };
|
||||
@@ -72,26 +52,60 @@ export type CreateScratch = { payload: ScratchPayload, };
|
||||
|
||||
export type UpdateScratch = { payload: ScratchPayload, };
|
||||
|
||||
export type QueuedMessage = {
|
||||
/**
|
||||
* The task attempt this message is queued for
|
||||
*/
|
||||
task_attempt_id: string,
|
||||
/**
|
||||
* The follow-up data (message + variant)
|
||||
*/
|
||||
data: DraftFollowUpData,
|
||||
/**
|
||||
* Timestamp when the message was queued
|
||||
*/
|
||||
queued_at: string, };
|
||||
|
||||
export type QueueStatus = { "status": "empty" } | { "status": "queued", message: QueuedMessage, };
|
||||
|
||||
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 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 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 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 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, };
|
||||
@@ -150,6 +164,14 @@ export type ListProjectsResponse = { projects: Array<RemoteProject>, };
|
||||
|
||||
export type RemoteProjectMembersResponse = { organization_id: string, members: Array<OrganizationMemberWithProfile>, };
|
||||
|
||||
export type CreateRemoteProjectRequest = { organization_id: string, name: string, };
|
||||
|
||||
export type LinkToExistingRequest = { remote_project_id: string, };
|
||||
|
||||
export type TagSearchParams = { search: string | null, };
|
||||
|
||||
export type TokenResponse = { access_token: string, expires_at: string | null, };
|
||||
|
||||
export type UserSystemInfo = { config: Config, analytics_user_id: string, login_status: LoginStatus, environment: Environment,
|
||||
/**
|
||||
* Capabilities supported per executor (e.g., { "CLAUDE_CODE": ["SESSION_FORK"] })
|
||||
@@ -170,7 +192,7 @@ export type CheckEditorAvailabilityResponse = { available: boolean, };
|
||||
|
||||
export type CheckAgentAvailabilityQuery = { executor: BaseCodingAgent, };
|
||||
|
||||
export type AvailabilityInfo = { "type": "LOGIN_DETECTED", last_auth_timestamp: bigint, } | { "type": "INSTALLATION_FOUND" } | { "type": "NOT_FOUND" };
|
||||
export type CurrentUserResponse = { user_id: string, };
|
||||
|
||||
export type CreateFollowUpAttempt = { prompt: string, variant: string | null, retry_process_id: string | null, force_when_dirty: boolean | null, perform_git_reset: boolean | null, };
|
||||
|
||||
@@ -188,9 +210,7 @@ export type OpenEditorRequest = { editor_type: string | null, file_path: string
|
||||
|
||||
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 AssignSharedTaskRequest = { new_assignee_user_id: string | null, };
|
||||
|
||||
export type ShareTaskResponse = { shared_task_id: string, };
|
||||
|
||||
@@ -202,6 +222,44 @@ export type ImageResponse = { id: string, file_path: string, original_name: stri
|
||||
|
||||
export type ImageMetadata = { exists: boolean, file_name: string | null, path: string | null, size_bytes: bigint | null, format: string | null, proxy_url: string | null, };
|
||||
|
||||
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 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 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 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, };
|
||||
@@ -224,17 +282,43 @@ 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 SharedTaskDetails = { id: string, project_id: string, title: string, description: string | null, status: TaskStatus, };
|
||||
|
||||
export type DiffChangeKind = "added" | "deleted" | "modified" | "renamed" | "copied" | "permissionChange";
|
||||
export type QueuedMessage = {
|
||||
/**
|
||||
* The task attempt this message is queued for
|
||||
*/
|
||||
task_attempt_id: string,
|
||||
/**
|
||||
* The follow-up data (message + variant)
|
||||
*/
|
||||
data: DraftFollowUpData,
|
||||
/**
|
||||
* Timestamp when the message was queued
|
||||
*/
|
||||
queued_at: string, };
|
||||
|
||||
export type QueueStatus = { "status": "empty" } | { "status": "queued", message: QueuedMessage, };
|
||||
|
||||
export type ConflictOp = "rebase" | "merge" | "cherry_pick" | "revert";
|
||||
|
||||
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" | "ToolInstallScript";
|
||||
|
||||
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 AvailabilityInfo = { "type": "LOGIN_DETECTED", last_auth_timestamp: bigint, } | { "type": "INSTALLATION_FOUND" } | { "type": "NOT_FOUND" };
|
||||
|
||||
export type CommandBuilder = {
|
||||
/**
|
||||
@@ -308,74 +392,6 @@ export type CodingAgentFollowUpRequest = { prompt: string, session_id: string,
|
||||
*/
|
||||
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 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 CommandExitStatus = { "type": "exit_code", code: number, } | { "type": "success", success: boolean, };
|
||||
|
||||
export type CommandRunResult = { exit_status: CommandExitStatus | null, output: string | null, };
|
||||
@@ -412,10 +428,4 @@ export type ToolStatus = { "status": "created" } | { "status": "success" } | { "
|
||||
|
||||
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;
|
||||
Reference in New Issue
Block a user