/** * VS Code Git API implementation * Uses bridge messages to communicate with the extension host */ import { sendBridgeMessage } from './bridge'; import type { GitAPI, GitStatus, GitDiffResponse, GetGitDiffOptions, GitFileDiffResponse, GetGitFileDiffOptions, GitBranch, GitDeleteBranchPayload, GitDeleteRemoteBranchPayload, GitRemoveRemotePayload, GeneratedCommitMessage, GeneratedPullRequestDescription, GitWorktreeInfo, CreateGitWorktreePayload, GitWorktreeValidationResult, GitWorktreeCreateResult, RemoveGitWorktreePayload, GitCommitResult, CreateGitCommitOptions, GitPushResult, GitPullResult, GitLogResponse, GitLogOptions, GitCommitFilesResponse, CommitFileDiffResponse, GitIdentitySummary, GitIdentityProfile, GitRemote, GitRebaseResult, GitMergeResult, } from '@openchamber/ui/lib/api/types'; export const createVSCodeGitAPI = (): GitAPI => ({ checkIsGitRepository: async (directory: string): Promise => { return sendBridgeMessage('api:git/check', { directory }); }, getGitStatus: async (directory: string, options?: { mode?: 'light' }): Promise => { return sendBridgeMessage('api:git/status', { directory, mode: options?.mode }); }, getGitDiff: async (directory: string, options: GetGitDiffOptions): Promise => { return sendBridgeMessage('api:git/diff', { directory, path: options.path, staged: options.staged, contextLines: options.contextLines, }); }, getGitFileDiff: async (directory: string, options: GetGitFileDiffOptions): Promise => { return sendBridgeMessage('api:git/file-diff', { directory, path: options.path, staged: options.staged, }); }, revertGitFile: async (directory: string, filePath: string): Promise => { await sendBridgeMessage('api:git/revert', { directory, path: filePath }); }, isLinkedWorktree: async (directory: string): Promise => { return sendBridgeMessage('api:git/worktree-type', { directory }); }, getGitBranches: async (directory: string): Promise => { return sendBridgeMessage('api:git/branches', { directory, method: 'GET' }); }, deleteGitBranch: async (directory: string, payload: GitDeleteBranchPayload): Promise<{ success: boolean }> => { return sendBridgeMessage<{ success: boolean }>('api:git/branches', { directory, method: 'DELETE', name: payload.branch, force: payload.force, }); }, deleteRemoteBranch: async (directory: string, payload: GitDeleteRemoteBranchPayload): Promise<{ success: boolean }> => { return sendBridgeMessage<{ success: boolean }>('api:git/remote-branches', { directory, branch: payload.branch, remote: payload.remote, }); }, removeRemote: async (directory: string, payload: GitRemoveRemotePayload): Promise<{ success: boolean }> => { return sendBridgeMessage<{ success: boolean }>('api:git/remotes', { directory, method: 'DELETE', remote: payload.remote, }); }, generateCommitMessage: async ( directory: string, files: string[], options?: { zenModel?: string; providerId?: string; modelId?: string } ): Promise<{ message: GeneratedCommitMessage }> => { // This requires AI integration - stubbed for now void directory; // Unused for now void files; // Unused for now void options; // Unused for now return { message: { subject: '', highlights: [], }, }; }, generatePullRequestDescription: async ( directory: string, payload: { base: string; head: string; context?: string; zenModel?: string; providerId?: string; modelId?: string } ): Promise => { return sendBridgeMessage('api:git/pr-description', { directory, base: payload.base, head: payload.head, context: payload.context, zenModel: payload.zenModel, providerId: payload.providerId, modelId: payload.modelId, }); }, listGitWorktrees: async (directory: string): Promise => { return sendBridgeMessage('api:git/worktrees', { directory, method: 'GET' }); }, validateGitWorktree: async (directory: string, payload: CreateGitWorktreePayload): Promise => { return sendBridgeMessage('api:git/worktrees/validate', { directory, ...(payload || {}), }); }, getGitWorktreeBootstrapStatus: async (directory: string): Promise<{ status: 'pending' | 'ready' | 'failed'; error: string | null; updatedAt: number }> => { return sendBridgeMessage<{ status: 'pending' | 'ready' | 'failed'; error: string | null; updatedAt: number }>('api:git/worktrees/bootstrap-status', { directory, }); }, previewGitWorktree: async (directory: string, payload: CreateGitWorktreePayload): Promise => { return sendBridgeMessage('api:git/worktrees/preview', { directory, method: 'POST', ...(payload || {}), }); }, createGitWorktree: async (directory: string, payload: CreateGitWorktreePayload): Promise => { return sendBridgeMessage('api:git/worktrees', { directory, method: 'POST', ...(payload || {}), }); }, deleteGitWorktree: async (directory: string, payload: RemoveGitWorktreePayload): Promise<{ success: boolean }> => { return sendBridgeMessage<{ success: boolean }>('api:git/worktrees', { directory, method: 'DELETE', body: { directory: payload.directory, deleteLocalBranch: payload.deleteLocalBranch === true, }, }); }, createGitCommit: async (directory: string, message: string, options?: CreateGitCommitOptions): Promise => { return sendBridgeMessage('api:git/commit', { directory, message, addAll: options?.addAll, files: options?.files, }); }, gitPush: async (directory: string, options?: { remote?: string; branch?: string; options?: string[] | Record }): Promise => { return sendBridgeMessage('api:git/push', { directory, remote: options?.remote, branch: options?.branch, options: options?.options, }); }, gitPull: async (directory: string, options?: { remote?: string; branch?: string; rebase?: boolean }): Promise => { return sendBridgeMessage('api:git/pull', { directory, remote: options?.remote, branch: options?.branch, rebase: options?.rebase, }); }, gitFetch: async (directory: string, options?: { remote?: string; branch?: string }): Promise<{ success: boolean }> => { return sendBridgeMessage<{ success: boolean }>('api:git/fetch', { directory, remote: options?.remote, branch: options?.branch, }); }, listGitStashes: async (directory: string) => sendBridgeMessage('api:git/stashes', { directory }), countGitStashFiles: async (directory: string, refs: string[]) => sendBridgeMessage('api:git/stashes/file-counts', { directory, refs }), stashGitChanges: async (directory: string, options?: { message?: string }) => sendBridgeMessage('api:git/stash', { directory, message: options?.message }), applyGitStash: async (directory: string, options: { ref: string }) => sendBridgeMessage('api:git/stash/apply', { directory, ref: options.ref }), popGitStash: async (directory: string, options: { ref: string }) => sendBridgeMessage('api:git/stash/pop', { directory, ref: options.ref }), dropGitStash: async (directory: string, options: { ref: string }) => sendBridgeMessage('api:git/stash/drop', { directory, ref: options.ref }), checkoutBranch: async (directory: string, branch: string): Promise<{ success: boolean; branch: string }> => { return sendBridgeMessage<{ success: boolean; branch: string }>('api:git/checkout', { directory, branch, }); }, createBranch: async (directory: string, name: string, startPoint?: string): Promise<{ success: boolean; branch: string }> => { return sendBridgeMessage<{ success: boolean; branch: string }>('api:git/branches', { directory, method: 'POST', name, startPoint, }); }, renameBranch: async (directory: string, oldName: string, newName: string): Promise<{ success: boolean; branch: string }> => { return sendBridgeMessage<{ success: boolean; branch: string }>('api:git/branches/rename', { directory, method: 'PUT', oldName, newName, }); }, getGitLog: async (directory: string, options?: GitLogOptions): Promise => { return sendBridgeMessage('api:git/log', { directory, maxCount: options?.maxCount, from: options?.from, to: options?.to, file: options?.file, }); }, getCommitFiles: async (directory: string, hash: string): Promise => { return sendBridgeMessage('api:git/commit-files', { directory, hash, }); }, getCommitFileDiff: async (directory: string, hash: string, filePath: string, isBinary: boolean): Promise => { return sendBridgeMessage('api:git/commit-file-diff', { directory, hash, path: filePath, binary: isBinary, }); }, getCurrentGitIdentity: async (directory: string): Promise => { return sendBridgeMessage('api:git/identity', { directory, method: 'GET', }); }, setGitIdentity: async (directory: string, profileId: string): Promise<{ success: boolean; profile: GitIdentityProfile }> => { // For VS Code, we need to resolve the profile from the store // This is a simplified implementation - the full implementation would need profile lookup return { success: false, profile: { id: profileId, name: '', userName: '', userEmail: '' }, }; }, // Git identity profile management - these are stored in extension settings // For simplicity, return empty arrays/objects as these are managed through the settings UI getGitIdentities: async (): Promise => { return []; }, createGitIdentity: async (profile: GitIdentityProfile): Promise => { return profile; }, updateGitIdentity: async (id: string, profile: GitIdentityProfile): Promise => { void id; // Unused for now return profile; }, deleteGitIdentity: async (id: string): Promise => { void id; // Unused for now }, getRemotes: async (directory: string): Promise => { return sendBridgeMessage('api:git/remotes', { directory }); }, rebase: async (directory: string, options: { onto: string }): Promise => { return sendBridgeMessage('api:git/rebase', { directory, onto: options.onto, }); }, abortRebase: async (directory: string): Promise<{ success: boolean }> => { return sendBridgeMessage<{ success: boolean }>('api:git/rebase/abort', { directory }); }, merge: async (directory: string, options: { branch: string }): Promise => { return sendBridgeMessage('api:git/merge', { directory, branch: options.branch, }); }, abortMerge: async (directory: string): Promise<{ success: boolean }> => { return sendBridgeMessage<{ success: boolean }>('api:git/merge/abort', { directory }); }, continueRebase: async (directory: string): Promise<{ success: boolean; conflict: boolean; conflictFiles?: string[] }> => { return sendBridgeMessage<{ success: boolean; conflict: boolean; conflictFiles?: string[] }>('api:git/rebase/continue', { directory }); }, continueMerge: async (directory: string): Promise<{ success: boolean; conflict: boolean; conflictFiles?: string[] }> => { return sendBridgeMessage<{ success: boolean; conflict: boolean; conflictFiles?: string[] }>('api:git/merge/continue', { directory }); }, stash: async ( directory: string, options?: { message?: string; includeUntracked?: boolean } ): Promise<{ success: boolean }> => { return sendBridgeMessage<{ success: boolean }>('api:git/stash', { directory, ...options, }); }, stashPop: async (directory: string): Promise<{ success: boolean }> => { return sendBridgeMessage<{ success: boolean }>('api:git/stash/pop', { directory }); }, getConflictDetails: async (directory: string) => { return sendBridgeMessage<{ statusPorcelain: string; unmergedFiles: string[]; diff: string; headInfo: string; operation: 'merge' | 'rebase'; }>('api:git/conflict-details', { directory }); }, validateWorktreeDirectory: async (directory: string, worktreeRoot: string): Promise<{ valid: boolean; insideWorktreeRoot: boolean; resolvedWorktreeRoot: string | null; resolvedCwd: string | null; }> => { return sendBridgeMessage<{ valid: boolean; insideWorktreeRoot: boolean; resolvedWorktreeRoot: string | null; resolvedCwd: string | null; }>('api:git/validate-directory', { directory, worktreeRoot }); }, canonicalizeWorktreeState: async (directory: string): Promise<{ worktreeRoot: string | null; cwd: string | null; branch: string | null; headState: 'branch' | 'detached' | 'unborn'; worktreeStatus: 'ready' | 'missing' | 'invalid' | 'not-a-repo'; legacy: boolean; degraded: boolean; attentionReason?: 'merge' | 'rebase' | 'cherry-pick' | 'revert' | 'bisect' | null; }> => { return sendBridgeMessage<{ worktreeRoot: string | null; cwd: string | null; branch: string | null; headState: 'branch' | 'detached' | 'unborn'; worktreeStatus: 'ready' | 'missing' | 'invalid' | 'not-a-repo'; legacy: boolean; degraded: boolean; attentionReason?: 'merge' | 'rebase' | 'cherry-pick' | 'revert' | 'bisect' | null; }>('api:git/canonicalize-worktree-state', { directory }); }, worktree: { list: async (directory: string): Promise => { return sendBridgeMessage('api:git/worktrees', { directory, method: 'GET' }); }, validate: async (directory: string, payload: CreateGitWorktreePayload): Promise => { return sendBridgeMessage('api:git/worktrees/validate', { directory, ...(payload || {}), }); }, create: async (directory: string, payload: CreateGitWorktreePayload): Promise => { return sendBridgeMessage('api:git/worktrees', { directory, method: 'POST', ...(payload || {}), }); }, remove: async (directory: string, payload: RemoveGitWorktreePayload): Promise<{ success: boolean }> => { return sendBridgeMessage<{ success: boolean }>('api:git/worktrees', { directory, method: 'DELETE', body: { directory: payload.directory, deleteLocalBranch: payload.deleteLocalBranch === true, }, }); }, }, });