Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,58 @@ test('browser routing wording keys have parity across all ten settings locales',
for (const [key, text] of Object.entries(actual)) assert.ok(text.trim().length > 0, `${locale}${key}`);
}
});

/*
* The app overrides `mcp.discoveryMode`, `mcp.enableProjectConfig`,
* `tools.discoveryMode` and `astEdit.enabled` for every session. The overrides
* are the right call; saying nothing about them was not. "Works in the CLI,
* missing in the app, no error message" is an unanswerable support question.
*/

test('the withheld runtime features are reported with a reason for each', async () => {
fakeApi();
await mount();
await waitFor(() => assert.equal(backendSelect().disabled, false));

assert.ok(screen.getByText(english.automation.withheld));
assert.ok(screen.getByText(english.automation.withheldDescription));

for (const [label, reason] of [
[english.automation.withheldMcp, english.automation.withheldMcpReason],
[english.automation.withheldToolDiscovery, english.automation.withheldToolDiscoveryReason],
[english.automation.withheldAstEdit, english.automation.withheldAstEditReason],
]) {
assert.ok(screen.getByText(label), label);
assert.ok(screen.getByText(reason), reason);
}
});

test('the withheld block offers nothing to switch on', async () => {
fakeApi();
await mount();
await waitFor(() => assert.equal(backendSelect().disabled, false));

// A session cannot turn these on either, so a control here would be a lie.
const row = screen.getByText(english.automation.withheldMcp).closest('div')?.parentElement;
assert.ok(row);
assert.equal(row.querySelector('button, input, select'), null);
});

test('withheld-feature wording keys have parity across all ten settings locales', () => {
const keys = [
'withheld', 'withheldDescription',
'withheldMcp', 'withheldMcpReason',
'withheldToolDiscovery', 'withheldToolDiscoveryReason',
'withheldAstEdit', 'withheldAstEditReason',
] as const;

for (const locale of ['en', 'ko', 'de', 'fr', 'it', 'ja', 'ru', 'tr', 'zh-CN', 'zh-TW']) {
const file = new URL(`../../../../i18n/locales/${locale}/settings.json`, import.meta.url);
const translated = JSON.parse(readFileSync(file, 'utf8')) as { automation?: Record<string, unknown> };
for (const key of keys) {
const text = translated.automation?.[key];
assert.equal(typeof text, 'string', `${locale}.automation.${key}`);
assert.ok(String(text).trim().length > 0, `${locale}.automation.${key}`);
}
}
});
30 changes: 29 additions & 1 deletion src/components/settings/view/tabs/AutomationSettingsTab.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from 'react';
import { ExternalLink, RefreshCw, ShieldCheck, Trash2 } from 'lucide-react';
import { ExternalLink, RefreshCw, ShieldCheck, SquareSlash, Trash2 } from 'lucide-react';
import { useTranslation } from 'react-i18next';

import { useAppShellStore } from '../../../../stores/useAppShellStore';
Expand Down Expand Up @@ -306,6 +306,34 @@ export default function AutomationSettingsTab() {
))}
</SettingsCard>
</SettingsSection>

{/*
* The app overrides four runtime settings for every session:
* `mcp.discoveryMode`, `mcp.enableProjectConfig`, `tools.discoveryMode`
* and `astEdit.enabled`. Those overrides are a deliberate boundary and
* they stay - but until now nothing said so. A user whose MCP servers
* work in the GJC CLI found them simply absent here, with no error and
* no explanation, which is an unanswerable support question.
*
* Reports, not controls: there is nothing to toggle, because the point
* is that a session cannot toggle them either.
*/}
<SettingsSection title={t('automation.withheld')} description={t('automation.withheldDescription')}>
<SettingsCard>
{([
['mcp', 'automation.withheldMcp', 'automation.withheldMcpReason'],
['toolDiscovery', 'automation.withheldToolDiscovery', 'automation.withheldToolDiscoveryReason'],
['astEdit', 'automation.withheldAstEdit', 'automation.withheldAstEditReason'],
] as const).map(([key, label, reason]) => (
<SettingsRow key={key} label={t(label)} description={t(reason)}>
<span className="flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground">
<SquareSlash className="h-3.5 w-3.5" aria-hidden />
{t('automation.notInstalled')}
</span>
</SettingsRow>
))}
</SettingsCard>
</SettingsSection>
</div>
);
}
10 changes: 9 additions & 1 deletion src/i18n/locales/de/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,15 @@
"noGrants": "Keine gespeicherten Automatisierungsgenehmigungen.",
"origin": "Herkunft der Website",
"application": "Desktop-Anwendung",
"revoke": "Genehmigung entfernen"
"revoke": "Genehmigung entfernen",
"withheld": "In der App deaktivierte Laufzeitfunktionen",
"withheldDescription": "Die App bestimmt ihren eigenen Werkzeugsatz. Unabhängig von Ihrer GJC-Konfiguration bleiben diese Laufzeitfunktionen in jeder Sitzung aus.",
"withheldMcp": "MCP-Server",
"withheldMcpReason": "Server aus Ihren GJC-Einstellungen und eine .mcp.json im Projekt werden nicht geladen, damit keine Werkzeuge in eine Sitzung gelangen, die die App nie gewählt hat.",
"withheldToolDiscovery": "Werkzeugsuche",
"withheldToolDiscoveryReason": "Sitzungen können zur Laufzeit keine weiteren Werkzeuge aktivieren; der von der App gewählte Satz ist der gesamte Satz.",
"withheldAstEdit": "AST-Bearbeitung",
"withheldAstEditReason": "Sie zeigt Änderungen nur als Vorschau und wendet sie über ein Werkzeug an, das die App nicht bereitstellt — sie würde also Änderungen anbieten, die eine Sitzung nie übernehmen könnte."
},
"notifications": {
"title": "Hinweise",
Expand Down
10 changes: 9 additions & 1 deletion src/i18n/locales/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,15 @@
"noGrants": "No saved automation approvals.",
"origin": "Site origin",
"application": "Desktop application",
"revoke": "Remove approval"
"revoke": "Remove approval",
"withheld": "Withheld runtime features",
"withheldDescription": "The app decides its own tool set. These runtime features stay off for every session, whatever your GJC configuration says.",
"withheldMcp": "MCP servers",
"withheldMcpReason": "Servers from your GJC settings and a project .mcp.json are not loaded, so tools the app never chose cannot reach a session.",
"withheldToolDiscovery": "Tool discovery",
"withheldToolDiscoveryReason": "Sessions cannot activate additional tools at runtime; the app-selected set is the whole set.",
"withheldAstEdit": "AST edit",
"withheldAstEditReason": "It only previews rewrites and applies them through a tool the app does not expose, so it would advertise edits a session could never commit."
},
"notifications": {
"title": "Notifications",
Expand Down
10 changes: 9 additions & 1 deletion src/i18n/locales/fr/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,15 @@
"noGrants": "Aucune approbation d’automatisation enregistrée.",
"origin": "Origine du site",
"application": "Application de bureau",
"revoke": "Supprimer l'approbation"
"revoke": "Supprimer l'approbation",
"withheld": "Fonctions du runtime désactivées dans l'application",
"withheldDescription": "L'application décide de son propre jeu d'outils. Quelle que soit votre configuration GJC, ces fonctions du runtime restent désactivées dans toutes les sessions.",
"withheldMcp": "Serveurs MCP",
"withheldMcpReason": "Les serveurs de vos réglages GJC et un .mcp.json de projet ne sont pas chargés, afin qu'aucun outil que l'application n'a pas choisi n'atteigne une session.",
"withheldToolDiscovery": "Découverte d'outils",
"withheldToolDiscoveryReason": "Une session ne peut pas activer d'outils supplémentaires en cours d'exécution ; le jeu choisi par l'application est le jeu complet.",
"withheldAstEdit": "Édition AST",
"withheldAstEditReason": "Elle ne fait que prévisualiser les réécritures et les applique via un outil que l'application n'expose pas : elle annoncerait donc des modifications qu'une session ne pourrait jamais valider."
},
"notifications": {
"title": "Alertes",
Expand Down
10 changes: 9 additions & 1 deletion src/i18n/locales/it/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,15 @@
"noGrants": "Nessuna approvazione di automazione salvata.",
"origin": "Origine del sito",
"application": "Applicazione desktop",
"revoke": "Rimuovi l'approvazione"
"revoke": "Rimuovi l'approvazione",
"withheld": "Funzioni del runtime disattivate nell'app",
"withheldDescription": "L'app decide il proprio insieme di strumenti. Qualunque sia la tua configurazione GJC, queste funzioni del runtime restano disattivate in ogni sessione.",
"withheldMcp": "Server MCP",
"withheldMcpReason": "I server dalle tue impostazioni GJC e un .mcp.json di progetto non vengono caricati, così nessuno strumento che l'app non ha scelto raggiunge una sessione.",
"withheldToolDiscovery": "Rilevamento strumenti",
"withheldToolDiscoveryReason": "Le sessioni non possono attivare altri strumenti in esecuzione; l'insieme scelto dall'app è l'insieme completo.",
"withheldAstEdit": "Modifica AST",
"withheldAstEditReason": "Si limita ad anteprimare le riscritture e le applica tramite uno strumento che l'app non espone, quindi proporrebbe modifiche che una sessione non potrebbe mai confermare."
},
"notifications": {
"title": "Avvisi",
Expand Down
10 changes: 9 additions & 1 deletion src/i18n/locales/ja/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,15 @@
"noGrants": "保存された自動化の承認はありません。",
"origin": "サイトのオリジン",
"application": "デスクトップアプリケーション",
"revoke": "承認を削除"
"revoke": "承認を削除",
"withheld": "アプリで無効なランタイム機能",
"withheldDescription": "ツールセットはアプリが決定します。GJC の設定にかかわらず、以下のランタイム機能はすべてのセッションで無効です。",
"withheldMcp": "MCP サーバー",
"withheldMcpReason": "GJC 設定のサーバーとプロジェクトの .mcp.json は読み込まれません。アプリが選んでいないツールがセッションに届かないようにします。",
"withheldToolDiscovery": "ツール探索",
"withheldToolDiscoveryReason": "セッションは実行中に追加のツールを有効化できません。アプリが選んだ集合がすべてです。",
"withheldAstEdit": "AST 編集",
"withheldAstEditReason": "書き換えをプレビューするだけで、適用にはアプリが公開していないツールを使うため、セッションが決して確定できない編集を提示することになります。"
},
"notifications": {
"title": "通知",
Expand Down
10 changes: 9 additions & 1 deletion src/i18n/locales/ko/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,15 @@
"noGrants": "저장된 자동화 승인 없음.",
"origin": "사이트 원본",
"application": "데스크톱 애플리케이션",
"revoke": "승인 취소"
"revoke": "승인 취소",
"withheld": "앱에서 비활성화된 런타임 기능",
"withheldDescription": "앱이 자체 도구 집합을 결정합니다. GJC 설정과 무관하게 아래 런타임 기능은 모든 세션에서 꺼져 있습니다.",
"withheldMcp": "MCP 서버",
"withheldMcpReason": "GJC 설정의 서버와 프로젝트의 .mcp.json을 불러오지 않습니다. 앱이 선택하지 않은 도구가 세션에 닿지 못하게 합니다.",
"withheldToolDiscovery": "도구 탐색",
"withheldToolDiscoveryReason": "세션이 실행 중에 도구를 추가로 활성화할 수 없습니다. 앱이 선택한 집합이 전부입니다.",
"withheldAstEdit": "AST 편집",
"withheldAstEditReason": "수정안을 미리 보여주기만 하고 적용은 앱이 노출하지 않는 도구로 합니다. 세션이 절대 커밋할 수 없는 편집을 광고하게 됩니다."
},
"notifications": {
"title": "알림 메시지",
Expand Down
10 changes: 9 additions & 1 deletion src/i18n/locales/ru/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,15 @@
"noGrants": "Нет сохраненных разрешений на автоматизацию.",
"origin": "Происхождение сайта",
"application": "Настольное приложение",
"revoke": "Удалить одобрение"
"revoke": "Удалить одобрение",
"withheld": "Отключённые в приложении возможности среды",
"withheldDescription": "Приложение само определяет набор инструментов. Независимо от вашей конфигурации GJC эти возможности среды отключены во всех сессиях.",
"withheldMcp": "Серверы MCP",
"withheldMcpReason": "Серверы из ваших настроек GJC и файл .mcp.json проекта не загружаются, чтобы в сессию не попали инструменты, которых приложение не выбирало.",
"withheldToolDiscovery": "Поиск инструментов",
"withheldToolDiscoveryReason": "Сессия не может включать дополнительные инструменты во время работы: выбранный приложением набор — это весь набор.",
"withheldAstEdit": "Редактирование AST",
"withheldAstEditReason": "Оно лишь показывает предпросмотр правок и применяет их инструментом, которого приложение не предоставляет, — то есть предлагало бы правки, которые сессия никогда не смогла бы применить."
},
"notifications": {
"title": "Центр уведомлений",
Expand Down
10 changes: 9 additions & 1 deletion src/i18n/locales/tr/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,15 @@
"noGrants": "Kaydedilmiş otomasyon onayı yok.",
"origin": "Sitenin kökeni",
"application": "Masaüstü uygulaması",
"revoke": "Onayı kaldır"
"revoke": "Onayı kaldır",
"withheld": "Uygulamada devre dışı çalışma zamanı özellikleri",
"withheldDescription": "Araç kümesine uygulama karar verir. GJC yapılandırmanız ne olursa olsun bu çalışma zamanı özellikleri her oturumda kapalıdır.",
"withheldMcp": "MCP sunucuları",
"withheldMcpReason": "GJC ayarlarınızdaki sunucular ve projedeki .mcp.json yüklenmez; böylece uygulamanın seçmediği araçlar bir oturuma ulaşamaz.",
"withheldToolDiscovery": "Araç keşfi",
"withheldToolDiscoveryReason": "Oturumlar çalışırken ek araç etkinleştiremez; uygulamanın seçtiği küme kümenin tamamıdır.",
"withheldAstEdit": "AST düzenleme",
"withheldAstEditReason": "Yalnızca yeniden yazımları önizler ve bunları uygulamanın sunmadığı bir araçla uygular; yani oturumun asla işleyemeyeceği düzenlemeleri duyurur."
},
"notifications": {
"title": "Uygulama bildirimleri",
Expand Down
10 changes: 9 additions & 1 deletion src/i18n/locales/zh-CN/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,15 @@
"noGrants": "没有保存的自动化批准。",
"origin": "站点来源",
"application": "桌面应用",
"revoke": "移除批准"
"revoke": "移除批准",
"withheld": "应用中停用的运行时功能",
"withheldDescription": "工具集由应用决定。无论你的 GJC 配置如何,以下运行时功能在所有会话中都保持关闭。",
"withheldMcp": "MCP 服务器",
"withheldMcpReason": "不会加载你 GJC 设置中的服务器和项目里的 .mcp.json,以免应用从未选择的工具进入会话。",
"withheldToolDiscovery": "工具发现",
"withheldToolDiscoveryReason": "会话无法在运行时激活额外工具;应用选定的集合就是全部集合。",
"withheldAstEdit": "AST 编辑",
"withheldAstEditReason": "它只预览改写,并通过应用未开放的工具来应用,因此会展示会话永远无法提交的编辑。"
},
"notifications": {
"title": "通知",
Expand Down
10 changes: 9 additions & 1 deletion src/i18n/locales/zh-TW/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,15 @@
"noGrants": "無存儲自動化批准。",
"origin": "網站原始碼",
"application": "桌面應用程式",
"revoke": "移除批准"
"revoke": "移除批准",
"withheld": "應用程式中停用的執行階段功能",
"withheldDescription": "工具集由應用程式決定。無論你的 GJC 設定為何,以下執行階段功能在所有工作階段中都保持關閉。",
"withheldMcp": "MCP 伺服器",
"withheldMcpReason": "不會載入你 GJC 設定中的伺服器與專案中的 .mcp.json,以免應用程式從未選擇的工具進入工作階段。",
"withheldToolDiscovery": "工具探索",
"withheldToolDiscoveryReason": "工作階段無法在執行期間啟用額外工具;應用程式選定的集合就是全部集合。",
"withheldAstEdit": "AST 編輯",
"withheldAstEditReason": "它只預覽改寫,並透過應用程式未開放的工具套用,因此會展示工作階段永遠無法提交的編輯。"
},
"notifications": {
"title": "通知",
Expand Down