import * as vscode from "vscode"; interface GitExtension { getAPI(version: number): GitAPI; } interface GitAPI { repositories: Repository[]; } interface Repository { root: string; rootUri: vscode.Uri; state: RepositoryState; inputBox: { value: string }; diffWithHEAD(path?: string): Promise; diffIndexWithHEAD(path?: string): Promise; status(): Promise; } interface RepositoryState { indexChanges: Change[]; workingTreeChanges: Change[]; } interface Change { uri: vscode.Uri; status: number; } export interface GitChange { path: string; status: "added" | "modified" | "deleted" | "renamed" | "untracked"; diff?: string; } export async function getGitChanges(): Promise { const repository = await getActiveGitRepository(); if (!repository) { throw new Error("No Git repository found"); } const state = repository.state; const changes: GitChange[] = []; const stagedChanges = state.indexChanges || []; const unstagedChanges = state.workingTreeChanges || []; if (stagedChanges.length > 0) { for (const change of stagedChanges) { changes.push({ path: change.uri.fsPath, status: getChangeStatus(change.status), }); } } else if (unstagedChanges.length > 0) { const config = vscode.workspace.getConfiguration("aiCommitExt"); const includeUnstaged = config.get("includeUnstaged", false); if (includeUnstaged) { for (const change of unstagedChanges) { changes.push({ path: change.uri.fsPath, status: getChangeStatus(change.status), }); } } } return changes; } export async function getGitDiff(): Promise { const repository = await getActiveGitRepository(); if (!repository) { throw new Error("No Git repository found"); } const state = repository.state; let diffOutput = ""; const stagedChanges = state.indexChanges || []; const unstagedChanges = state.workingTreeChanges || []; const config = vscode.workspace.getConfiguration("aiCommitExt"); const includeUnstaged = config.get("includeUnstaged", false); if (stagedChanges.length > 0) { for (const change of stagedChanges) { const fileName = change.uri.fsPath.split("/").pop() || ""; diffOutput += `## ${fileName} (staged)\n`; try { const diff = await repository.diffIndexWithHEAD( change.uri.fsPath, ); if (diff) { diffOutput += diff + "\n"; } } catch { diffOutput += "(Unable to get diff)\n"; } } } else if (unstagedChanges.length > 0 && includeUnstaged) { for (const change of unstagedChanges) { const fileName = change.uri.fsPath.split("/").pop() || ""; diffOutput += `## ${fileName} (unstaged)\n`; try { const diff = await repository.diffWithHEAD(change.uri.fsPath); if (diff) { diffOutput += diff + "\n"; } } catch { diffOutput += "(Unable to get diff)\n"; } } } if (!diffOutput) { throw new Error("No changes to commit"); } return diffOutput; } async function getActiveGitRepository(): Promise { const gitExtension = vscode.extensions.getExtension("vscode.git"); if (!gitExtension) { throw new Error("Git extension not found"); } const api = gitExtension.exports.getAPI(1); if (api.repositories.length === 0) { return null; } return api.repositories[0]; } function getChangeStatus(status: number): GitChange["status"] { const Status = { INDEX_MODIFIED: 0, INDEX_ADDED: 1, INDEX_DELETED: 2, INDEX_RENAMED: 3, MODIFIED: 4, DELETED: 5, UNTRACKED: 6, }; if (status === Status.INDEX_ADDED || status === Status.UNTRACKED) { return "added"; } if (status === Status.INDEX_DELETED || status === Status.DELETED) { return "deleted"; } if (status === Status.INDEX_RENAMED) { return "renamed"; } return "modified"; } export async function getRepositoryRoot(): Promise { const repository = await getActiveGitRepository(); if (!repository) { return null; } if (typeof repository.root === "string") { return repository.root; } return repository.rootUri.fsPath; }