mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-19 17:50:37 -07:00
feat(admin): support admin-enforced settings for Agent Skills (#16406)
This commit is contained in:
@@ -16,6 +16,9 @@ import {
|
||||
refreshServerHierarchicalMemory,
|
||||
SimpleExtensionLoader,
|
||||
type FileDiscoveryService,
|
||||
showMemory,
|
||||
addMemory,
|
||||
listMemoryFiles,
|
||||
} from '@google/gemini-cli-core';
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
@@ -44,6 +47,9 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
content: 'Memory refreshed successfully.',
|
||||
};
|
||||
}),
|
||||
showMemory: vi.fn(),
|
||||
addMemory: vi.fn(),
|
||||
listMemoryFiles: vi.fn(),
|
||||
refreshServerHierarchicalMemory: vi.fn(),
|
||||
};
|
||||
});
|
||||
@@ -78,6 +84,22 @@ describe('memoryCommand', () => {
|
||||
mockGetUserMemory = vi.fn();
|
||||
mockGetGeminiMdFileCount = vi.fn();
|
||||
|
||||
vi.mocked(showMemory).mockImplementation((config) => {
|
||||
const memoryContent = config.getUserMemory() || '';
|
||||
const fileCount = config.getGeminiMdFileCount() || 0;
|
||||
let content;
|
||||
if (memoryContent.length > 0) {
|
||||
content = `Current memory content from ${fileCount} file(s):\n\n---\n${memoryContent}\n---`;
|
||||
} else {
|
||||
content = 'Memory is currently empty.';
|
||||
}
|
||||
return {
|
||||
type: 'message',
|
||||
messageType: 'info',
|
||||
content,
|
||||
};
|
||||
});
|
||||
|
||||
mockContext = createMockCommandContext({
|
||||
services: {
|
||||
config: {
|
||||
@@ -131,6 +153,20 @@ describe('memoryCommand', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
addCommand = getSubCommand('add');
|
||||
vi.mocked(addMemory).mockImplementation((args) => {
|
||||
if (!args || args.trim() === '') {
|
||||
return {
|
||||
type: 'message',
|
||||
messageType: 'error',
|
||||
content: 'Usage: /memory add <text to remember>',
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: 'tool',
|
||||
toolName: 'save_memory',
|
||||
toolArgs: { fact: args.trim() },
|
||||
};
|
||||
});
|
||||
mockContext = createMockCommandContext();
|
||||
});
|
||||
|
||||
@@ -360,6 +396,21 @@ describe('memoryCommand', () => {
|
||||
beforeEach(() => {
|
||||
listCommand = getSubCommand('list');
|
||||
mockGetGeminiMdfilePaths = vi.fn();
|
||||
vi.mocked(listMemoryFiles).mockImplementation((config) => {
|
||||
const filePaths = config.getGeminiMdFilePaths() || [];
|
||||
const fileCount = filePaths.length;
|
||||
let content;
|
||||
if (fileCount > 0) {
|
||||
content = `There are ${fileCount} GEMINI.md file(s) in use:\n\n${filePaths.join('\n')}`;
|
||||
} else {
|
||||
content = 'No GEMINI.md files in use.';
|
||||
}
|
||||
return {
|
||||
type: 'message',
|
||||
messageType: 'info',
|
||||
content,
|
||||
};
|
||||
});
|
||||
mockContext = createMockCommandContext({
|
||||
services: {
|
||||
config: {
|
||||
|
||||
@@ -46,6 +46,7 @@ describe('skillsCommand', () => {
|
||||
getSkillManager: vi.fn().mockReturnValue({
|
||||
getAllSkills: vi.fn().mockReturnValue(skills),
|
||||
getSkills: vi.fn().mockReturnValue(skills),
|
||||
isAdminEnabled: vi.fn().mockReturnValue(true),
|
||||
getSkill: vi
|
||||
.fn()
|
||||
.mockImplementation(
|
||||
@@ -307,6 +308,43 @@ describe('skillsCommand', () => {
|
||||
type: MessageType.ERROR,
|
||||
text: 'Skill "non-existent" not found.',
|
||||
}),
|
||||
expect.any(Number),
|
||||
);
|
||||
});
|
||||
|
||||
it('should show error if skills are disabled by admin during disable', async () => {
|
||||
const skillManager = context.services.config!.getSkillManager();
|
||||
vi.mocked(skillManager.isAdminEnabled).mockReturnValue(false);
|
||||
|
||||
const disableCmd = skillsCommand.subCommands!.find(
|
||||
(s) => s.name === 'disable',
|
||||
)!;
|
||||
await disableCmd.action!(context, 'skill1');
|
||||
|
||||
expect(context.ui.addItem).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
type: MessageType.ERROR,
|
||||
text: 'Agent skills are disabled by your admin.',
|
||||
}),
|
||||
expect.any(Number),
|
||||
);
|
||||
});
|
||||
|
||||
it('should show error if skills are disabled by admin during enable', async () => {
|
||||
const skillManager = context.services.config!.getSkillManager();
|
||||
vi.mocked(skillManager.isAdminEnabled).mockReturnValue(false);
|
||||
|
||||
const enableCmd = skillsCommand.subCommands!.find(
|
||||
(s) => s.name === 'enable',
|
||||
)!;
|
||||
await enableCmd.action!(context, 'skill1');
|
||||
|
||||
expect(context.ui.addItem).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
type: MessageType.ERROR,
|
||||
text: 'Agent skills are disabled by your admin.',
|
||||
}),
|
||||
expect.any(Number),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -79,12 +79,26 @@ async function disableAction(
|
||||
return;
|
||||
}
|
||||
const skillManager = context.services.config?.getSkillManager();
|
||||
if (skillManager?.isAdminEnabled() === false) {
|
||||
context.ui.addItem(
|
||||
{
|
||||
type: MessageType.ERROR,
|
||||
text: 'Agent skills are disabled by your admin.',
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const skill = skillManager?.getSkill(skillName);
|
||||
if (!skill) {
|
||||
context.ui.addItem({
|
||||
type: MessageType.ERROR,
|
||||
text: `Skill "${skillName}" not found.`,
|
||||
});
|
||||
context.ui.addItem(
|
||||
{
|
||||
type: MessageType.ERROR,
|
||||
text: `Skill "${skillName}" not found.`,
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,6 +135,18 @@ async function enableAction(
|
||||
return;
|
||||
}
|
||||
|
||||
const skillManager = context.services.config?.getSkillManager();
|
||||
if (skillManager?.isAdminEnabled() === false) {
|
||||
context.ui.addItem(
|
||||
{
|
||||
type: MessageType.ERROR,
|
||||
text: 'Agent skills are disabled by your admin.',
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = enableSkill(context.services.settings, skillName);
|
||||
|
||||
let feedback = renderSkillActionFeedback(
|
||||
|
||||
Reference in New Issue
Block a user