refactoring the api endpoints to be separate files to reduce context usage

This commit is contained in:
Cody Seibert
2025-12-14 17:53:21 -05:00
parent cdc8334d82
commit 6b30271441
121 changed files with 4281 additions and 2927 deletions

View File

@@ -0,0 +1,21 @@
/**
* Common utilities for git routes
*/
import { createLogger } from "../../lib/logger.js";
const logger = createLogger("Git");
/**
* Get error message from error object
*/
export function getErrorMessage(error: unknown): string {
return error instanceof Error ? error.message : "Unknown error";
}
/**
* Log error details consistently
*/
export function logError(error: unknown, context: string): void {
logger.error(`${context}:`, error);
}

View File

@@ -0,0 +1,16 @@
/**
* Git routes - HTTP API for git operations (non-worktree)
*/
import { Router } from "express";
import { createDiffsHandler } from "./routes/diffs.js";
import { createFileDiffHandler } from "./routes/file-diff.js";
export function createGitRoutes(): Router {
const router = Router();
router.post("/diffs", createDiffsHandler());
router.post("/file-diff", createFileDiffHandler());
return router;
}

View File

@@ -0,0 +1,67 @@
/**
* POST /diffs endpoint - Get diffs for the main project
*/
import type { Request, Response } from "express";
import { exec } from "child_process";
import { promisify } from "util";
import { getErrorMessage, logError } from "../common.js";
const execAsync = promisify(exec);
export function createDiffsHandler() {
return async (req: Request, res: Response): Promise<void> => {
try {
const { projectPath } = req.body as { projectPath: string };
if (!projectPath) {
res.status(400).json({ success: false, error: "projectPath required" });
return;
}
try {
const { stdout: diff } = await execAsync("git diff HEAD", {
cwd: projectPath,
maxBuffer: 10 * 1024 * 1024,
});
const { stdout: status } = await execAsync("git status --porcelain", {
cwd: projectPath,
});
const files = status
.split("\n")
.filter(Boolean)
.map((line) => {
const statusChar = line[0];
const filePath = line.slice(3);
const statusMap: Record<string, string> = {
M: "Modified",
A: "Added",
D: "Deleted",
R: "Renamed",
C: "Copied",
U: "Updated",
"?": "Untracked",
};
return {
status: statusChar,
path: filePath,
statusText: statusMap[statusChar] || "Unknown",
};
});
res.json({
success: true,
diff,
files,
hasChanges: files.length > 0,
});
} catch {
res.json({ success: true, diff: "", files: [], hasChanges: false });
}
} catch (error) {
logError(error, "Get diffs failed");
res.status(500).json({ success: false, error: getErrorMessage(error) });
}
};
}

View File

@@ -0,0 +1,45 @@
/**
* POST /file-diff endpoint - Get diff for a specific file
*/
import type { Request, Response } from "express";
import { exec } from "child_process";
import { promisify } from "util";
import { getErrorMessage, logError } from "../common.js";
const execAsync = promisify(exec);
export function createFileDiffHandler() {
return async (req: Request, res: Response): Promise<void> => {
try {
const { projectPath, filePath } = req.body as {
projectPath: string;
filePath: string;
};
if (!projectPath || !filePath) {
res
.status(400)
.json({ success: false, error: "projectPath and filePath required" });
return;
}
try {
const { stdout: diff } = await execAsync(
`git diff HEAD -- "${filePath}"`,
{
cwd: projectPath,
maxBuffer: 10 * 1024 * 1024,
}
);
res.json({ success: true, diff, filePath });
} catch {
res.json({ success: true, diff: "", filePath });
}
} catch (error) {
logError(error, "Get file diff failed");
res.status(500).json({ success: false, error: getErrorMessage(error) });
}
};
}