feat(core): add .agents/skills directory alias for skill discovery (#18151)

This commit is contained in:
N. Taylor Mullen
2026-02-02 22:07:36 -08:00
committed by GitHub
parent e7bfd2bf83
commit ad8796b02d
4 changed files with 236 additions and 1 deletions
+25 -1
View File
@@ -17,7 +17,15 @@ vi.mock('fs', async (importOriginal) => {
});
import { Storage } from './storage.js';
import { GEMINI_DIR } from '../utils/paths.js';
import { GEMINI_DIR, homedir } from '../utils/paths.js';
vi.mock('../utils/paths.js', async (importOriginal) => {
const actual = await importOriginal<typeof import('../utils/paths.js')>();
return {
...actual,
homedir: vi.fn(actual.homedir),
};
});
describe('Storage getGlobalSettingsPath', () => {
it('returns path to ~/.gemini/settings.json', () => {
@@ -26,6 +34,22 @@ describe('Storage getGlobalSettingsPath', () => {
});
});
describe('Storage - Security', () => {
it('falls back to tmp for gemini but returns empty for agents if the home directory cannot be determined', () => {
vi.mocked(homedir).mockReturnValue('');
// .gemini falls back for backward compatibility
expect(Storage.getGlobalGeminiDir()).toBe(
path.join(os.tmpdir(), GEMINI_DIR),
);
// .agents returns empty to avoid insecure fallback WITHOUT throwing error
expect(Storage.getGlobalAgentsDir()).toBe('');
vi.mocked(homedir).mockReturnValue(os.homedir());
});
});
describe('Storage additional helpers', () => {
const projectRoot = '/tmp/project';
const storage = new Storage(projectRoot);
+21
View File
@@ -14,6 +14,7 @@ export const GOOGLE_ACCOUNTS_FILENAME = 'google_accounts.json';
export const OAUTH_FILE = 'oauth_creds.json';
const TMP_DIR_NAME = 'tmp';
const BIN_DIR_NAME = 'bin';
const AGENTS_DIR_NAME = '.agents';
export class Storage {
private readonly targetDir: string;
@@ -30,6 +31,14 @@ export class Storage {
return path.join(homeDir, GEMINI_DIR);
}
static getGlobalAgentsDir(): string {
const homeDir = homedir();
if (!homeDir) {
return '';
}
return path.join(homeDir, AGENTS_DIR_NAME);
}
static getMcpOAuthTokensPath(): string {
return path.join(Storage.getGlobalGeminiDir(), 'mcp-oauth-tokens.json');
}
@@ -54,6 +63,10 @@ export class Storage {
return path.join(Storage.getGlobalGeminiDir(), 'skills');
}
static getUserAgentSkillsDir(): string {
return path.join(Storage.getGlobalAgentsDir(), 'skills');
}
static getGlobalMemoryFilePath(): string {
return path.join(Storage.getGlobalGeminiDir(), 'memory.md');
}
@@ -107,6 +120,10 @@ export class Storage {
return path.join(this.targetDir, GEMINI_DIR);
}
getAgentsDir(): string {
return path.join(this.targetDir, AGENTS_DIR_NAME);
}
getProjectTempDir(): string {
const hash = this.getFilePathHash(this.getProjectRoot());
const tempDir = Storage.getGlobalTempDir();
@@ -147,6 +164,10 @@ export class Storage {
return path.join(this.getGeminiDir(), 'skills');
}
getProjectAgentSkillsDir(): string {
return path.join(this.getAgentsDir(), 'skills');
}
getProjectAgentsDir(): string {
return path.join(this.getGeminiDir(), 'agents');
}