|
@@ -8,11 +8,15 @@
|
|
|
* logic), since the end-to-end hook is validated by a live agent run, not a
|
|
* logic), since the end-to-end hook is validated by a live agent run, not a
|
|
|
* unit test.
|
|
* unit test.
|
|
|
*/
|
|
*/
|
|
|
-import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
|
|
|
|
|
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
|
import * as fs from 'fs';
|
|
import * as fs from 'fs';
|
|
|
import * as os from 'os';
|
|
import * as os from 'os';
|
|
|
import * as path from 'path';
|
|
import * as path from 'path';
|
|
|
-import { planFrontload, findIndexedSubprojectRoots, isStructuralPrompt, hasStructuralKeyword, extractCodeTokens, PROMPT_HOOK_INJECTION_MAX, CLAUDE_CODE_INLINE_HOOK_OUTPUT_LIMIT, capPromptHookInjection } from '../src/directory';
|
|
|
|
|
|
|
+import { planFrontload, findIndexedSubprojectRoots, unsafeIndexRootReason, isStructuralPrompt, hasStructuralKeyword, extractCodeTokens, PROMPT_HOOK_INJECTION_MAX, CLAUDE_CODE_INLINE_HOOK_OUTPUT_LIMIT, capPromptHookInjection } from '../src/directory';
|
|
|
|
|
+
|
|
|
|
|
+// Make the built-in exports configurable so HOME can point at a real temp
|
|
|
|
|
+// fixture without changing the process environment or the user's home files.
|
|
|
|
|
+vi.mock('os', async (importOriginal) => ({ ...await importOriginal<typeof import('os')>() }));
|
|
|
|
|
|
|
|
/** Make `dir` look indexed (isInitialized needs `.codegraph/codegraph.db`). */
|
|
/** Make `dir` look indexed (isInitialized needs `.codegraph/codegraph.db`). */
|
|
|
function mkIndexed(dir: string): string {
|
|
function mkIndexed(dir: string): string {
|
|
@@ -30,7 +34,10 @@ function mkWorkspaceRoot(dir: string): string {
|
|
|
describe('planFrontload — front-load hook project resolution (#964)', () => {
|
|
describe('planFrontload — front-load hook project resolution (#964)', () => {
|
|
|
let tmp: string;
|
|
let tmp: string;
|
|
|
beforeEach(() => { tmp = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'cg-frontload-'))); });
|
|
beforeEach(() => { tmp = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'cg-frontload-'))); });
|
|
|
- afterEach(() => { fs.rmSync(tmp, { recursive: true, force: true }); });
|
|
|
|
|
|
|
+ afterEach(() => {
|
|
|
|
|
+ vi.restoreAllMocks();
|
|
|
|
|
+ fs.rmSync(tmp, { recursive: true, force: true });
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
it('cwd is itself indexed → front-load cwd (the common single-project case)', () => {
|
|
it('cwd is itself indexed → front-load cwd (the common single-project case)', () => {
|
|
|
mkIndexed(tmp);
|
|
mkIndexed(tmp);
|
|
@@ -92,6 +99,29 @@ describe('planFrontload — front-load hook project resolution (#964)', () => {
|
|
|
expect(plan.nudgeProjects).toEqual([]);
|
|
expect(plan.nudgeProjects).toEqual([]);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
+ it.each([
|
|
|
|
|
+ { root: 'home', manifest: 'package.json', children: 1 },
|
|
|
|
|
+ { root: 'home', manifest: 'package.json', children: 2 },
|
|
|
|
|
+ { root: 'home', manifest: 'WORKSPACE', children: 1 },
|
|
|
|
|
+ { root: 'parent of home', manifest: 'package.json', children: 1 },
|
|
|
|
|
+ ])('$root with stray $manifest and $children indexed children → no-op (#1454)', ({ root, manifest, children }) => {
|
|
|
|
|
+ const homeDir = root === 'home' ? tmp : path.join(tmp, 'user');
|
|
|
|
|
+ fs.mkdirSync(homeDir, { recursive: true });
|
|
|
|
|
+ vi.spyOn(os, 'homedir').mockReturnValue(homeDir);
|
|
|
|
|
+ if (manifest === 'package.json') mkWorkspaceRoot(tmp);
|
|
|
|
|
+ else fs.mkdirSync(path.join(tmp, manifest)); // Even a WORKSPACE directory opens the manifest gate.
|
|
|
|
|
+ mkIndexed(path.join(tmp, 'packages', 'api'));
|
|
|
|
|
+ if (children === 2) mkIndexed(path.join(tmp, 'packages', 'web'));
|
|
|
|
|
+ expect(unsafeIndexRootReason(tmp)).toBe(root === 'home' ? 'your home directory' : 'a parent of your home directory');
|
|
|
|
|
+
|
|
|
|
|
+ expect(planFrontload(tmp, 'how does authentication work end to end?')).toEqual({
|
|
|
|
|
+ exploreRoot: null,
|
|
|
|
|
+ nudgeProjects: [],
|
|
|
|
|
+ viaSubScan: false,
|
|
|
|
|
+ });
|
|
|
|
|
+ expect(findIndexedSubprojectRoots(tmp)).toEqual([]);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
it('nothing indexed anywhere → no-op', () => {
|
|
it('nothing indexed anywhere → no-op', () => {
|
|
|
mkWorkspaceRoot(tmp);
|
|
mkWorkspaceRoot(tmp);
|
|
|
fs.mkdirSync(path.join(tmp, 'packages', 'api'), { recursive: true });
|
|
fs.mkdirSync(path.join(tmp, 'packages', 'api'), { recursive: true });
|