mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-19 01:30:42 -07:00
125 lines
3.5 KiB
TypeScript
125 lines
3.5 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { ApprovalMode, type PolicyRule } from '@google/gemini-cli-core';
|
|
import { CommandKind, type SlashCommand } from './types.js';
|
|
import { MessageType } from '../types.js';
|
|
|
|
interface CategorizedRules {
|
|
normal: PolicyRule[];
|
|
autoEdit: PolicyRule[];
|
|
yolo: PolicyRule[];
|
|
plan: PolicyRule[];
|
|
}
|
|
|
|
const categorizeRulesByMode = (
|
|
rules: readonly PolicyRule[],
|
|
): CategorizedRules => {
|
|
const result: CategorizedRules = {
|
|
normal: [],
|
|
autoEdit: [],
|
|
yolo: [],
|
|
plan: [],
|
|
};
|
|
const ALL_MODES = Object.values(ApprovalMode);
|
|
rules.forEach((rule) => {
|
|
const modes = rule.modes?.length ? rule.modes : ALL_MODES;
|
|
const modeSet = new Set(modes);
|
|
if (modeSet.has(ApprovalMode.DEFAULT)) result.normal.push(rule);
|
|
if (modeSet.has(ApprovalMode.AUTO_EDIT)) result.autoEdit.push(rule);
|
|
if (modeSet.has(ApprovalMode.YOLO)) result.yolo.push(rule);
|
|
if (modeSet.has(ApprovalMode.PLAN)) result.plan.push(rule);
|
|
});
|
|
return result;
|
|
};
|
|
|
|
const formatRule = (rule: PolicyRule, i: number) =>
|
|
`${i + 1}. **${rule.decision.toUpperCase()}** ${rule.toolName ? `tool: \`${rule.toolName}\`` : 'all tools'}` +
|
|
(rule.argsPattern ? ` (args match: \`${rule.argsPattern.source}\`)` : '') +
|
|
(rule.priority !== undefined ? ` [Priority: ${rule.priority}]` : '') +
|
|
(rule.source ? ` [Source: ${rule.source}]` : '');
|
|
|
|
const formatSection = (title: string, rules: PolicyRule[]) =>
|
|
`### ${title}\n${rules.length ? rules.map(formatRule).join('\n') : '_No policies._'}\n\n`;
|
|
|
|
const listPoliciesCommand: SlashCommand = {
|
|
name: 'list',
|
|
description: 'List all active policies grouped by mode',
|
|
kind: CommandKind.BUILT_IN,
|
|
autoExecute: true,
|
|
action: async (context) => {
|
|
const agentContext = context.services.agentContext;
|
|
const config = agentContext?.config;
|
|
if (!config) {
|
|
context.ui.addItem(
|
|
{
|
|
type: MessageType.ERROR,
|
|
text: 'Error: Config not available.',
|
|
},
|
|
Date.now(),
|
|
);
|
|
return;
|
|
}
|
|
|
|
const policyEngine = config.getPolicyEngine();
|
|
const rules = policyEngine.getRules();
|
|
|
|
if (rules.length === 0) {
|
|
context.ui.addItem(
|
|
{
|
|
type: MessageType.INFO,
|
|
text: 'No active policies.',
|
|
},
|
|
Date.now(),
|
|
);
|
|
return;
|
|
}
|
|
|
|
const categorized = categorizeRulesByMode(rules);
|
|
const normalRulesSet = new Set(categorized.normal);
|
|
const uniqueAutoEdit = categorized.autoEdit.filter(
|
|
(rule) => !normalRulesSet.has(rule),
|
|
);
|
|
const uniqueYolo = categorized.yolo.filter(
|
|
(rule) => !normalRulesSet.has(rule),
|
|
);
|
|
const uniquePlan = categorized.plan.filter(
|
|
(rule) => !normalRulesSet.has(rule),
|
|
);
|
|
|
|
let content = '**Active Policies**\n\n';
|
|
content += formatSection('Normal Mode Policies', categorized.normal);
|
|
content += formatSection(
|
|
'Auto Edit Mode Policies (combined with normal mode policies)',
|
|
uniqueAutoEdit,
|
|
);
|
|
content += formatSection(
|
|
'Yolo Mode Policies (combined with normal mode policies)',
|
|
uniqueYolo,
|
|
);
|
|
content += formatSection(
|
|
'Plan Mode Policies (combined with normal mode policies)',
|
|
uniquePlan,
|
|
);
|
|
|
|
context.ui.addItem(
|
|
{
|
|
type: MessageType.INFO,
|
|
text: content,
|
|
},
|
|
Date.now(),
|
|
);
|
|
},
|
|
};
|
|
|
|
export const policiesCommand: SlashCommand = {
|
|
name: 'policies',
|
|
description: 'Manage policies',
|
|
kind: CommandKind.BUILT_IN,
|
|
autoExecute: false,
|
|
subCommands: [listPoliciesCommand],
|
|
};
|