mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 08:47:44 +00:00
Extensibility: Gemini.md files (#944)
This commit is contained in:
@@ -58,8 +58,11 @@ vi.mock('@gemini-cli/core', async () => {
|
||||
setUserMemory: vi.fn(),
|
||||
setGeminiMdFileCount: vi.fn(),
|
||||
})),
|
||||
loadServerHierarchicalMemory: vi.fn(() =>
|
||||
Promise.resolve({ memoryContent: '', fileCount: 0 }),
|
||||
loadServerHierarchicalMemory: vi.fn((cwd, debug, extensionPaths) =>
|
||||
Promise.resolve({
|
||||
memoryContent: extensionPaths?.join(',') || '',
|
||||
fileCount: extensionPaths?.length || 0,
|
||||
}),
|
||||
),
|
||||
};
|
||||
});
|
||||
@@ -228,15 +231,31 @@ describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('should have a placeholder test to ensure test file validity', () => {
|
||||
// This test suite is currently a placeholder.
|
||||
// Tests for loadHierarchicalGeminiMemory were removed due to persistent
|
||||
// and complex mocking issues with Node.js built-in modules (like 'os')
|
||||
// in the Vitest environment. These issues prevented consistent and reliable
|
||||
// testing of file system interactions dependent on os.homedir().
|
||||
// The core logic was implemented as per specification, but the tests
|
||||
// could not be stabilized.
|
||||
expect(true).toBe(true);
|
||||
it('should pass extension context file paths to loadServerHierarchicalMemory', async () => {
|
||||
process.argv = ['node', 'script.js'];
|
||||
const settings: Settings = {};
|
||||
const extensions = [
|
||||
{
|
||||
name: 'ext1',
|
||||
version: '1.0.0',
|
||||
contextFileName: '/path/to/ext1/gemini.md',
|
||||
},
|
||||
{
|
||||
name: 'ext2',
|
||||
version: '1.0.0',
|
||||
},
|
||||
{
|
||||
name: 'ext3',
|
||||
version: '1.0.0',
|
||||
contextFileName: '/path/to/ext3/gemini.md',
|
||||
},
|
||||
];
|
||||
await loadCliConfig(settings, extensions, [], 'session-id');
|
||||
expect(ServerConfig.loadServerHierarchicalMemory).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
false,
|
||||
['/path/to/ext1/gemini.md', '/path/to/ext3/gemini.md'],
|
||||
);
|
||||
});
|
||||
|
||||
// NOTE TO FUTURE DEVELOPERS:
|
||||
|
||||
@@ -112,6 +112,7 @@ async function parseArguments(): Promise<CliArgs> {
|
||||
export async function loadHierarchicalGeminiMemory(
|
||||
currentWorkingDirectory: string,
|
||||
debugMode: boolean,
|
||||
extensionContextFilePaths: string[] = [],
|
||||
): Promise<{ memoryContent: string; fileCount: number }> {
|
||||
if (debugMode) {
|
||||
logger.debug(
|
||||
@@ -120,7 +121,11 @@ export async function loadHierarchicalGeminiMemory(
|
||||
}
|
||||
// Directly call the server function.
|
||||
// The server function will use its own homedir() for the global path.
|
||||
return loadServerHierarchicalMemory(currentWorkingDirectory, debugMode);
|
||||
return loadServerHierarchicalMemory(
|
||||
currentWorkingDirectory,
|
||||
debugMode,
|
||||
extensionContextFilePaths,
|
||||
);
|
||||
}
|
||||
|
||||
export async function loadCliConfig(
|
||||
@@ -145,10 +150,15 @@ export async function loadCliConfig(
|
||||
setServerGeminiMdFilename(getCurrentGeminiMdFilename());
|
||||
}
|
||||
|
||||
const extensionContextFilePaths = extensions
|
||||
.map((e) => e.contextFileName)
|
||||
.filter((p): p is string => !!p);
|
||||
|
||||
// Call the (now wrapper) loadHierarchicalGeminiMemory which calls the server's version
|
||||
const { memoryContent, fileCount } = await loadHierarchicalGeminiMemory(
|
||||
process.cwd(),
|
||||
debugMode,
|
||||
extensionContextFilePaths,
|
||||
);
|
||||
|
||||
const contentGeneratorConfig = await createContentGeneratorConfig(argv);
|
||||
|
||||
@@ -41,28 +41,47 @@ describe('loadExtensions', () => {
|
||||
fs.rmSync(tempHomeDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('should deduplicate extensions, prioritizing the workspace directory', () => {
|
||||
// Create extensions in the workspace
|
||||
it('should load context file path when gemini.md is present', () => {
|
||||
const workspaceExtensionsDir = path.join(
|
||||
tempWorkspaceDir,
|
||||
EXTENSIONS_DIRECTORY_NAME,
|
||||
);
|
||||
fs.mkdirSync(workspaceExtensionsDir, { recursive: true });
|
||||
createExtension(workspaceExtensionsDir, 'ext1', '1.0.0');
|
||||
createExtension(workspaceExtensionsDir, 'ext1', '1.0.0', true);
|
||||
createExtension(workspaceExtensionsDir, 'ext2', '2.0.0');
|
||||
|
||||
// Create extensions in the home directory
|
||||
const homeExtensionsDir = path.join(tempHomeDir, EXTENSIONS_DIRECTORY_NAME);
|
||||
fs.mkdirSync(homeExtensionsDir, { recursive: true });
|
||||
createExtension(homeExtensionsDir, 'ext1', '1.1.0'); // Duplicate that should be ignored
|
||||
createExtension(homeExtensionsDir, 'ext3', '3.0.0');
|
||||
|
||||
const extensions = loadExtensions(tempWorkspaceDir);
|
||||
|
||||
expect(extensions).toHaveLength(3);
|
||||
expect(extensions.find((e) => e.name === 'ext1')?.version).toBe('1.0.0'); // Workspace version should be kept
|
||||
expect(extensions.find((e) => e.name === 'ext2')?.version).toBe('2.0.0');
|
||||
expect(extensions.find((e) => e.name === 'ext3')?.version).toBe('3.0.0');
|
||||
expect(extensions).toHaveLength(2);
|
||||
const ext1 = extensions.find((e) => e.name === 'ext1');
|
||||
const ext2 = extensions.find((e) => e.name === 'ext2');
|
||||
expect(ext1?.contextFileName).toBe(
|
||||
path.join(workspaceExtensionsDir, 'ext1', 'gemini.md'),
|
||||
);
|
||||
expect(ext2?.contextFileName).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should load context file path from the extension config', () => {
|
||||
const workspaceExtensionsDir = path.join(
|
||||
tempWorkspaceDir,
|
||||
EXTENSIONS_DIRECTORY_NAME,
|
||||
);
|
||||
fs.mkdirSync(workspaceExtensionsDir, { recursive: true });
|
||||
createExtension(
|
||||
workspaceExtensionsDir,
|
||||
'ext1',
|
||||
'1.0.0',
|
||||
false,
|
||||
'my-context.md',
|
||||
);
|
||||
|
||||
const extensions = loadExtensions(tempWorkspaceDir);
|
||||
|
||||
expect(extensions).toHaveLength(1);
|
||||
const ext1 = extensions.find((e) => e.name === 'ext1');
|
||||
expect(ext1?.contextFileName).toBe(
|
||||
path.join(workspaceExtensionsDir, 'ext1', 'my-context.md'),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -70,11 +89,21 @@ function createExtension(
|
||||
extensionsDir: string,
|
||||
name: string,
|
||||
version: string,
|
||||
addContextFile = false,
|
||||
contextFileName?: string,
|
||||
): void {
|
||||
const extDir = path.join(extensionsDir, name);
|
||||
fs.mkdirSync(extDir);
|
||||
fs.writeFileSync(
|
||||
path.join(extDir, EXTENSIONS_CONFIG_FILENAME),
|
||||
JSON.stringify({ name, version }),
|
||||
JSON.stringify({ name, version, contextFileName }),
|
||||
);
|
||||
|
||||
if (addContextFile) {
|
||||
fs.writeFileSync(path.join(extDir, 'gemini.md'), 'context');
|
||||
}
|
||||
|
||||
if (contextFileName) {
|
||||
fs.writeFileSync(path.join(extDir, contextFileName), 'context');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,22 @@ function loadExtensionsFromDir(dir: string): ExtensionConfig[] {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (extensionConfig.contextFileName) {
|
||||
const contextFilePath = path.join(
|
||||
extensionDir,
|
||||
extensionConfig.contextFileName,
|
||||
);
|
||||
if (fs.existsSync(contextFilePath)) {
|
||||
extensionConfig.contextFileName = contextFilePath;
|
||||
}
|
||||
} else {
|
||||
const contextFilePath = path.join(extensionDir, 'gemini.md');
|
||||
if (fs.existsSync(contextFilePath)) {
|
||||
extensionConfig.contextFileName = contextFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
extensions.push(extensionConfig);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
|
||||
Reference in New Issue
Block a user