When the indexed root is a directory an enclosing git repo ignores,
`git ls-files --directory` collapses the whole cwd to a single literal
`./` entry. That sentinel reached the `ignore` matcher, which rejects it
("path should be a `path.relative()`d string, but got "./""), aborting
buildScopeIgnore — the one ignore-building call in FileWatcher.start().
So the MCP daemon's startWatching() threw, was caught as "Failed to open
project", and auto-sync never started: the index silently went stale
until a manual `codegraph sync` (CODEGRAPH_NO_DAEMON=1 was the only
workaround).
Filter the `./`/`.` self-entry wherever we consume `--directory` output
(listIgnoredDirs + the untracked-dir loop in discoverEmbeddedRepoRoots).
Semantically correct, not just a crash guard: `./` means "the whole cwd",
never a nested repo to recurse into.
Not platform-specific (reported on Codex/Windows, reproduced on macOS):
the trigger is git state, not the OS.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e43ac82cdf
commit
03666584ed
@@ -203,6 +203,27 @@ describe('multi-repo workspaces (#514)', () => {
|
||||
expect(scope.ignores('src/app.ts')).toBe(false);
|
||||
});
|
||||
|
||||
it('buildScopeIgnore: indexed root is itself a gitignored subdir of an enclosing repo (#936)', () => {
|
||||
// `child/` is NOT its own repo, so `git` resolves the ENCLOSING repo from
|
||||
// inside it — and `git ls-files --directory`, whose cwd is then a wholly
|
||||
// ignored directory, emits the literal `./` ("this entire directory").
|
||||
// That sentinel used to reach the `ignore` matcher and throw
|
||||
// ("path should be a `path.relative()`d string, but got "./""), aborting
|
||||
// buildScopeIgnore → the MCP daemon's watcher never started and auto-sync
|
||||
// silently stalled until a manual `codegraph sync`.
|
||||
write(path.join(ws, 'child/src/a.ts'), 'export const x = 1;\n');
|
||||
write(path.join(ws, '.gitignore'), '/child/\n');
|
||||
makeRepo(ws);
|
||||
|
||||
const child = path.join(ws, 'child');
|
||||
// The crux: building scope for the ignored subdir must not throw.
|
||||
const scope = buildScopeIgnore(child);
|
||||
// The subdir's own source is watchable/indexable, not ignored.
|
||||
expect(scope.ignores('src/a.ts')).toBe(false);
|
||||
// And the `./` self entry must not be mistaken for a nested embedded repo.
|
||||
expect(discoverEmbeddedRepoRoots(child)).toEqual([]);
|
||||
});
|
||||
|
||||
it('sync picks up a change inside a gitignored embedded repo', async () => {
|
||||
write(path.join(ws, 'packages/proj-a/src/auth.ts'), 'export function login() { return 1; }\n');
|
||||
makeRepo(path.join(ws, 'packages/proj-a'));
|
||||
|
||||
Reference in New Issue
Block a user