feat(vscode): add copy-to-clipboard button for permission ruleset JSON

Adds a copy icon button in the Calculated Permissions header that copies
the agent name and full permission ruleset as formatted JSON to the
clipboard, making it easy to share in issues or discussions.
This commit is contained in:
Mark IJbema
2026-04-08 14:17:58 +02:00
parent cb7058c2dd
commit 7dc4399010
20 changed files with 46 additions and 1 deletions
@@ -233,7 +233,14 @@ const ModeEditView: Component<Props> = (props) => {
{/* Calculated permissions (read-only, collapsible) */}
<Show when={agent()?.permission} keyed>
{(rules) => <PermissionRuleset rules={rules} expanded={expanded()} onToggle={() => setExpanded((v) => !v)} />}
{(rules) => (
<PermissionRuleset
agent={props.name}
rules={rules}
expanded={expanded()}
onToggle={() => setExpanded((v) => !v)}
/>
)}
</Show>
<div style={{ display: "flex", "justify-content": "flex-end" }}>
@@ -257,6 +264,7 @@ const ACTION_COLORS: Record<string, { bg: string; fg: string }> = {
}
interface RulesetProps {
agent: string
rules: PermissionRuleItem[]
expanded: boolean
onToggle: () => void
@@ -264,6 +272,7 @@ interface RulesetProps {
const PermissionRuleset: Component<RulesetProps> = (props) => {
const language = useLanguage()
const [copied, setCopied] = createSignal(false)
// Compute effective action per unique tool by finding the last rule with pattern "*"
// NOTE: This assumes the CLI uses "*" as the wildcard pattern for catch-all rules.
@@ -278,6 +287,14 @@ const PermissionRuleset: Component<RulesetProps> = (props) => {
return [...tools.entries()].sort((a, b) => a[0].localeCompare(b[0]))
})
const copy = (e: MouseEvent) => {
e.stopPropagation()
const data = { agent: props.agent, rules: props.rules }
navigator.clipboard.writeText(JSON.stringify(data, null, 2))
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<Card style={{ "margin-bottom": "12px" }}>
<div
@@ -305,6 +322,15 @@ const PermissionRuleset: Component<RulesetProps> = (props) => {
>
{language.t("settings.agentBehaviour.permissions.count", { count: String(props.rules.length) })}
</span>
<div style={{ "margin-left": "auto" }}>
<IconButton
size="small"
variant="ghost"
icon={copied() ? "check" : "copy"}
title={language.t("settings.agentBehaviour.permissions.copy")}
onClick={copy}
/>
</div>
</div>
<Show when={props.expanded}>
+1
View File
@@ -1124,6 +1124,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "الأداة",
"settings.agentBehaviour.permissions.col.pattern": "النمط",
"settings.agentBehaviour.permissions.col.action": "الإجراء",
"settings.agentBehaviour.permissions.copy": "نسخ الأذونات كـ JSON",
"settings.agentBehaviour.permissions.hint":
"يتم تقييم القواعد بالترتيب — القاعدة المطابقة الأخيرة هي التي تُطبق. هذه هي مجموعة القواعد المحلولة من خلفية CLI.",
"settings.agentBehaviour.removeMode.title": "إزالة الوضع",
+1
View File
@@ -1143,6 +1143,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Ferramenta",
"settings.agentBehaviour.permissions.col.pattern": "Padrão",
"settings.agentBehaviour.permissions.col.action": "Ação",
"settings.agentBehaviour.permissions.copy": "Copiar permissões como JSON",
"settings.agentBehaviour.permissions.hint":
"As regras são avaliadas em ordem — a última regra correspondente vence. Este é o conjunto de regras resolvido do backend da CLI.",
"settings.agentBehaviour.removeMode.title": "Remover modo",
+1
View File
@@ -1141,6 +1141,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Alat",
"settings.agentBehaviour.permissions.col.pattern": "Uzorak",
"settings.agentBehaviour.permissions.col.action": "Akcija",
"settings.agentBehaviour.permissions.copy": "Kopiraj dozvole kao JSON",
"settings.agentBehaviour.permissions.hint":
"Pravila se evaluiraju po redoslijedu — zadnje pravilo koje se podudara pobjeđuje. Ovo je riješeni skup pravila iz CLI backenda.",
"settings.agentBehaviour.removeMode.title": "Ukloni mod",
+1
View File
@@ -1134,6 +1134,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Værktøj",
"settings.agentBehaviour.permissions.col.pattern": "Mønster",
"settings.agentBehaviour.permissions.col.action": "Handling",
"settings.agentBehaviour.permissions.copy": "Kopiér tilladelser som JSON",
"settings.agentBehaviour.permissions.hint":
"Reglerne evalueres i rækkefølge — den sidst matchende regel vinder. Dette er det endelige regelsæt fra CLI-backenden.",
"settings.agentBehaviour.removeMode.title": "Fjern tilstand",
+1
View File
@@ -1156,6 +1156,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Werkzeug",
"settings.agentBehaviour.permissions.col.pattern": "Muster",
"settings.agentBehaviour.permissions.col.action": "Aktion",
"settings.agentBehaviour.permissions.copy": "Berechtigungen als JSON kopieren",
"settings.agentBehaviour.permissions.hint":
"Regeln werden der Reihe nach ausgewertet — die letzte übereinstimmende Regel gewinnt. Dies ist das aufgelöste Regelwerk vom CLI-Backend.",
"settings.agentBehaviour.removeMode.title": "Modus entfernen",
@@ -1185,6 +1185,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Tool",
"settings.agentBehaviour.permissions.col.pattern": "Pattern",
"settings.agentBehaviour.permissions.col.action": "Action",
"settings.agentBehaviour.permissions.copy": "Copy permissions as JSON",
"settings.agentBehaviour.permissions.hint":
"Rules are evaluated in order — last matching rule wins. This is the resolved ruleset from the CLI backend.",
+1
View File
@@ -1148,6 +1148,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Herramienta",
"settings.agentBehaviour.permissions.col.pattern": "Patrón",
"settings.agentBehaviour.permissions.col.action": "Acción",
"settings.agentBehaviour.permissions.copy": "Copiar permisos como JSON",
"settings.agentBehaviour.permissions.hint":
"Las reglas se evalúan en orden — gana la última regla coincidente. Este es el conjunto de reglas resuelto desde el backend de la CLI.",
"settings.agentBehaviour.removeMode.title": "Eliminar modo",
+1
View File
@@ -1160,6 +1160,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Outil",
"settings.agentBehaviour.permissions.col.pattern": "Motif",
"settings.agentBehaviour.permissions.col.action": "Action",
"settings.agentBehaviour.permissions.copy": "Copier les permissions en JSON",
"settings.agentBehaviour.permissions.hint":
"Les règles sont évaluées dans l'ordre — la dernière règle correspondante l'emporte. Il s'agit de l'ensemble de règles résolu depuis le backend CLI.",
"settings.agentBehaviour.removeMode.title": "Supprimer le mode",
+1
View File
@@ -1136,6 +1136,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "ツール",
"settings.agentBehaviour.permissions.col.pattern": "パターン",
"settings.agentBehaviour.permissions.col.action": "アクション",
"settings.agentBehaviour.permissions.copy": "権限をJSONとしてコピー",
"settings.agentBehaviour.permissions.hint":
"ルールは順番に評価され、最後に一致したルールが適用されます。これはCLIバックエンドから解決されたルールセットです。",
"settings.agentBehaviour.removeMode.title": "モードを削除",
+1
View File
@@ -1130,6 +1130,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "도구",
"settings.agentBehaviour.permissions.col.pattern": "패턴",
"settings.agentBehaviour.permissions.col.action": "작업",
"settings.agentBehaviour.permissions.copy": "권한을 JSON으로 복사",
"settings.agentBehaviour.permissions.hint":
"규칙은 순서대로 평가되며, 마지막에 일치하는 규칙이 적용됩니다. 이것은 CLI 백엔드에서 확인된 규칙 세트입니다.",
"settings.agentBehaviour.removeMode.title": "모드 제거",
+1
View File
@@ -1389,6 +1389,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Tool",
"settings.agentBehaviour.permissions.col.pattern": "Patroon",
"settings.agentBehaviour.permissions.col.action": "Actie",
"settings.agentBehaviour.permissions.copy": "Machtigingen kopiëren als JSON",
"settings.agentBehaviour.permissions.hint":
"Regels worden op volgorde geëvalueerd — de laatst overeenkomende regel wint. Dit is de opgeloste regelset van de CLI backend.",
"settings.agentBehaviour.editMode.save": "Klaar",
+1
View File
@@ -1137,6 +1137,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Verktøy",
"settings.agentBehaviour.permissions.col.pattern": "Mønster",
"settings.agentBehaviour.permissions.col.action": "Handling",
"settings.agentBehaviour.permissions.copy": "Kopier tillatelser som JSON",
"settings.agentBehaviour.permissions.hint":
"Reglene evalueres i rekkefølge — siste matchende regel vinner. Dette er det gjeldende regelsettet fra CLI-backenden.",
"settings.agentBehaviour.removeMode.title": "Fjern modus",
+1
View File
@@ -1140,6 +1140,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Narzędzie",
"settings.agentBehaviour.permissions.col.pattern": "Wzorzec",
"settings.agentBehaviour.permissions.col.action": "Akcja",
"settings.agentBehaviour.permissions.copy": "Kopiuj uprawnienia jako JSON",
"settings.agentBehaviour.permissions.hint":
"Reguły są sprawdzane po kolei — ostatnia pasująca reguła wygrywa. To jest wynikowy zestaw reguł z backendu CLI.",
"settings.agentBehaviour.removeMode.title": "Usuń tryb",
+1
View File
@@ -1143,6 +1143,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Инструмент",
"settings.agentBehaviour.permissions.col.pattern": "Шаблон",
"settings.agentBehaviour.permissions.col.action": "Действие",
"settings.agentBehaviour.permissions.copy": "Скопировать разрешения как JSON",
"settings.agentBehaviour.permissions.hint":
"Правила оцениваются по порядку — побеждает последнее совпавшее правило. Это разрешенный набор правил из бэкенда CLI.",
"settings.agentBehaviour.removeMode.title": "Удалить режим",
+1
View File
@@ -1125,6 +1125,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "เครื่องมือ",
"settings.agentBehaviour.permissions.col.pattern": "รูปแบบ",
"settings.agentBehaviour.permissions.col.action": "การดำเนินการ",
"settings.agentBehaviour.permissions.copy": "คัดลอกสิทธิ์เป็น JSON",
"settings.agentBehaviour.permissions.hint":
"กฎจะถูกประเมินตามลำดับ — กฎที่ตรงกันล่าสุดจะมีผล นี่คือชุดกฎที่ประมวลผลแล้วจากแบ็กเอนด์ CLI",
"settings.agentBehaviour.removeMode.title": "ลบโหมด",
+1
View File
@@ -1382,6 +1382,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Araç",
"settings.agentBehaviour.permissions.col.pattern": "Desen",
"settings.agentBehaviour.permissions.col.action": "Eylem",
"settings.agentBehaviour.permissions.copy": "İzinleri JSON olarak kopyala",
"settings.agentBehaviour.permissions.hint":
"Kurallar sırayla değerlendirilir — son eşleşen kural kazanır. Bu, CLI arka ucundan çözümlenen kural kümesidir.",
"settings.agentBehaviour.editMode.save": "Tamam",
+1
View File
@@ -1384,6 +1384,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "Інструмент",
"settings.agentBehaviour.permissions.col.pattern": "Шаблон",
"settings.agentBehaviour.permissions.col.action": "Дія",
"settings.agentBehaviour.permissions.copy": "Копіювати дозволи як JSON",
"settings.agentBehaviour.permissions.hint":
"Правила оцінюються по порядку — останнє відповідне правило має пріоритет. Це розрахований набір правил з CLI бекенду.",
"settings.agentBehaviour.editMode.save": "Готово",
+1
View File
@@ -1112,6 +1112,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "工具",
"settings.agentBehaviour.permissions.col.pattern": "模式",
"settings.agentBehaviour.permissions.col.action": "操作",
"settings.agentBehaviour.permissions.copy": "复制权限为 JSON",
"settings.agentBehaviour.permissions.hint": "规则按顺序评估 — 最后匹配的规则生效。这是从 CLI 后端解析出的规则集。",
"settings.agentBehaviour.removeMode.title": "移除模式",
"settings.agentBehaviour.removeMode.confirm": '移除模式 "{{name}}" 吗?这将通过更新配置来禁用该模式。',
+1
View File
@@ -1115,6 +1115,7 @@ export const dict = {
"settings.agentBehaviour.permissions.col.tool": "工具",
"settings.agentBehaviour.permissions.col.pattern": "模式",
"settings.agentBehaviour.permissions.col.action": "動作",
"settings.agentBehaviour.permissions.copy": "複製權限為 JSON",
"settings.agentBehaviour.permissions.hint":
"規則會按順序評估 — 最後符合的規則為準。這是來自 CLI 後端的已解析規則集。",
"settings.agentBehaviour.removeMode.title": "移除模式",