fix(git): pin simple-git to project path for session discovery

simple-git without baseDir inherits process.cwd(), so launching
OpenChamber from a neutral directory (e.g. $HOME) and opening a git
project elsewhere produced repeated "not a git repository" status
errors and could abort project/session enumeration. Always require an
explicit baseDir, soft-handle non-repo GitErrors on status/check
routes, and cover non-git, foreign-cwd, and nested-repo cases.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
Cursor Agent
2026-07-31 09:53:09 +00:00
co-authored by Serhii Dziupin
parent 09f0c64839
commit d839c8b0f8
5 changed files with 239 additions and 26 deletions
+42 -16
View File
@@ -7,6 +7,36 @@ export function registerGitRoutes(app) {
return gitLibraries;
};
const resolveDirectoryQuery = (value) => {
const raw = Array.isArray(value) ? value[0] : value;
if (typeof raw !== 'string') {
return null;
}
const trimmed = raw.trim();
return trimmed || null;
};
const extractGitErrorText = (error) => {
const message = typeof error?.message === 'string' ? error.message : '';
const stderr = typeof error?.stderr === 'string' ? error.stderr : '';
const stdout = typeof error?.stdout === 'string' ? error.stdout : '';
const fallback = !message && error != null ? String(error) : '';
return [message, stderr, stdout, fallback]
.map((value) => String(value || '').trim())
.filter(Boolean)
.join('\n');
};
const isNonRepoGitError = (error) => /not a git repository/i.test(extractGitErrorText(error));
const nonRepoStatusPayload = () => ({
isGitRepository: false,
files: [],
branch: null,
ahead: 0,
behind: 0,
});
app.get('/api/git/identities', async (req, res) => {
const { getProfiles } = await getGitLibraries();
try {
@@ -79,7 +109,7 @@ export function registerGitRoutes(app) {
app.get('/api/git/check', async (req, res) => {
const { isGitRepository } = await getGitLibraries();
try {
const directory = req.query.directory;
const directory = resolveDirectoryQuery(req.query.directory);
if (!directory) {
return res.status(400).json({ error: 'directory parameter is required' });
}
@@ -87,6 +117,10 @@ export function registerGitRoutes(app) {
const isRepo = await isGitRepository(directory);
res.json({ isGitRepository: isRepo });
} catch (error) {
if (isNonRepoGitError(error)) {
console.warn('Git check treated non-repository path as not a git repo:', extractGitErrorText(error));
return res.json({ isGitRepository: false });
}
console.error('Failed to check git repository:', error);
res.status(500).json({ error: 'Failed to check git repository' });
}
@@ -188,34 +222,26 @@ export function registerGitRoutes(app) {
app.get('/api/git/status', async (req, res) => {
const { getStatus, isGitRepository } = await getGitLibraries();
const extractGitErrorText = (error) => {
const message = typeof error?.message === 'string' ? error.message : '';
const stderr = typeof error?.stderr === 'string' ? error.stderr : '';
const stdout = typeof error?.stdout === 'string' ? error.stdout : '';
return [message, stderr, stdout]
.map((value) => String(value || '').trim())
.filter(Boolean)
.join('\n');
};
try {
const directory = req.query.directory;
const directory = resolveDirectoryQuery(req.query.directory);
if (!directory) {
return res.status(400).json({ error: 'directory parameter is required' });
}
const isRepo = await isGitRepository(directory);
if (!isRepo) {
return res.json({ isGitRepository: false, files: [], branch: null, ahead: 0, behind: 0 });
return res.json(nonRepoStatusPayload());
}
const mode = req.query.mode === 'light' ? 'light' : undefined;
const status = await getStatus(directory, { mode });
res.json(status);
} catch (error) {
const errorText = extractGitErrorText(error);
if (/not a git repository/i.test(errorText)) {
return res.json({ isGitRepository: false, files: [], branch: null, ahead: 0, behind: 0 });
// Non-repo / GitError must not abort callers that enumerate projects or
// sessions (e.g. sidebar discovery). Log a warning and continue.
if (isNonRepoGitError(error)) {
console.warn('Git status skipped for non-repository path:', extractGitErrorText(error));
return res.json(nonRepoStatusPayload());
}
console.error('Failed to get git status:', error);
res.status(500).json({ error: error.message || 'Failed to get git status' });