diff --git a/src-tauri/crates/agent-cli/src/session_provenance.rs b/src-tauri/crates/agent-cli/src/session_provenance.rs index a7ef34d6a..c611a4d80 100644 --- a/src-tauri/crates/agent-cli/src/session_provenance.rs +++ b/src-tauri/crates/agent-cli/src/session_provenance.rs @@ -54,10 +54,14 @@ const CLAUDE_CODE_LIFECYCLE_EVENTS: &[(&str, Option<&str>)] = &[ ("PreToolUse", Some("*")), ("PostToolUseFailure", Some("*")), ]; -// Codex lifecycle events (all matcher-less; SessionStart doubles as the -// resume signal and PreToolUse is the per-tool working heartbeat). +// Codex events required whenever provenance capture is enabled. SessionStart +// proves that Codex accepted and executed the current managed definitions; +// the subagent events preserve exact actor attribution. +const CODEX_REQUIRED_EVENTS: &[&str] = &["SessionStart", "SubagentStart", "SubagentStop"]; +// Optional Codex lifecycle events (all matcher-less). SessionStart remains +// installed when live status is off because it also drives hook activation; +// PreToolUse is the per-tool working heartbeat when live status is on. const CODEX_LIFECYCLE_EVENTS: &[&str] = &[ - "SessionStart", "UserPromptSubmit", "PreToolUse", "PermissionRequest", @@ -358,7 +362,7 @@ pub struct SessionProvenanceHookStatus { #[serde(rename_all = "snake_case")] pub enum SessionProvenanceHookActivationState { Inactive, - AwaitingApproval, + AwaitingVerification, Active, } @@ -597,7 +601,7 @@ fn update_codex_platform( unix_command, windows_command, )?; - for event_name in ["SubagentStart", "SubagentStop"] { + for event_name in CODEX_REQUIRED_EVENTS { update_nested_event( config, event_name, @@ -1473,8 +1477,9 @@ fn config_has_complete_managed_hooks( platform, "PostToolUse", Some(CODEX_POST_TOOL_USE_MATCHER), - ) && nested_event_has_managed_hook(config, platform, "SubagentStart", None) - && nested_event_has_managed_hook(config, platform, "SubagentStop", None) + ) && CODEX_REQUIRED_EVENTS + .iter() + .all(|event_name| nested_event_has_managed_hook(config, platform, event_name, None)) && (!live_status || CODEX_LIFECYCLE_EVENTS.iter().all(|event_name| { nested_event_has_managed_hook(config, platform, event_name, None) @@ -1642,7 +1647,10 @@ fn codex_activation_from_receipt( Some(receipt.activated_at), ) } else { - (SessionProvenanceHookActivationState::AwaitingApproval, None) + ( + SessionProvenanceHookActivationState::AwaitingVerification, + None, + ) } } @@ -1709,7 +1717,7 @@ fn build_hook_status( /// Record proof that Codex invoked the current ORG2-managed hook definition. /// A matching receipt is the only state that upgrades the UI from -/// `awaiting_approval` to `active`. +/// `awaiting_verification` to `active`. pub fn record_session_provenance_hook_activation(source: &str) -> Result { if source != SessionProvenanceHookPlatform::Codex.source_arg() { return Ok(false); @@ -2057,7 +2065,7 @@ mod tests { } #[test] - fn codex_config_installs_and_removes_actor_lifecycle_hooks() { + fn codex_config_installs_and_removes_required_hooks() { let mut config = json!({ "hooks": { "SubagentStop": [{ @@ -2076,6 +2084,7 @@ mod tests { .expect("enable Codex hooks"); assert_eq!(config["hooks"]["PostToolUse"].as_array().unwrap().len(), 1); + assert_eq!(config["hooks"]["SessionStart"].as_array().unwrap().len(), 1); assert_eq!( config["hooks"]["SubagentStart"].as_array().unwrap().len(), 1 @@ -2087,7 +2096,7 @@ mod tests { false )); - config["hooks"]["SubagentStart"] = json!([]); + config["hooks"]["SessionStart"] = json!([]); assert!(!config_has_complete_managed_hooks( &config, SessionProvenanceHookPlatform::Codex, @@ -2169,11 +2178,17 @@ mod tests { }; assert_eq!( codex_activation_from_receipt("current", None), - (SessionProvenanceHookActivationState::AwaitingApproval, None) + ( + SessionProvenanceHookActivationState::AwaitingVerification, + None + ) ); assert_eq!( codex_activation_from_receipt("stale", Some(receipt.clone())), - (SessionProvenanceHookActivationState::AwaitingApproval, None) + ( + SessionProvenanceHookActivationState::AwaitingVerification, + None + ) ); assert_eq!( codex_activation_from_receipt("current", Some(receipt)), diff --git a/src/api/tauri/rpc/__tests__/sessionProvenanceSchemas.test.ts b/src/api/tauri/rpc/__tests__/sessionProvenanceSchemas.test.ts index 85be7838a..dd26caaab 100644 --- a/src/api/tauri/rpc/__tests__/sessionProvenanceSchemas.test.ts +++ b/src/api/tauri/rpc/__tests__/sessionProvenanceSchemas.test.ts @@ -42,13 +42,13 @@ describe("session provenance RPC schemas", () => { platform: "codex", enabled: true, desiredEnabled: true, - activationState: "awaiting_approval", + activationState: "awaiting_verification", lastActivatedAt: null, configPath: "/Users/test/.codex/hooks.json", error: null, }); expect(parsed.enabled).toBe(true); - expect(parsed.activationState).toBe("awaiting_approval"); + expect(parsed.activationState).toBe("awaiting_verification"); }); it("parses a recent hook signal from the Rust camelCase payload", () => { diff --git a/src/api/tauri/rpc/schemas/agentOrgs.ts b/src/api/tauri/rpc/schemas/agentOrgs.ts index a328f26b8..d1c4d899f 100644 --- a/src/api/tauri/rpc/schemas/agentOrgs.ts +++ b/src/api/tauri/rpc/schemas/agentOrgs.ts @@ -34,7 +34,7 @@ export const SessionProvenanceHookPlatformSchema = z.enum([ export const SessionProvenanceHookActivationStateSchema = z.enum([ "inactive", - "awaiting_approval", + "awaiting_verification", "active", ]); diff --git a/src/i18n/locales/de/integrations.json b/src/i18n/locales/de/integrations.json index 68011308d..f916951be 100644 --- a/src/i18n/locales/de/integrations.json +++ b/src/i18n/locales/de/integrations.json @@ -1688,6 +1688,8 @@ "emptyConfigPreview": "Kein Konfigurationsinhalt" }, "sessionProvenance": { + "masterToggle": "Provenienz-Hooks", + "masterToggleDesc": "Wenn deaktiviert, werden alle verwalteten Hooks deinstalliert und keine Signale erfasst; die Auswahl pro Plattform bleibt erhalten und wird beim erneuten Aktivieren wiederhergestellt.", "title": "Sitzungsherkunft", "capture": "Dateiinteraktionen erfassen", "description": "Erfasst Lese- und Schreibzugriffe auf Dateien als Metadaten. Prompts, Werkzeugausgaben und Dateiinhalte werden nicht gespeichert.", @@ -1704,16 +1706,16 @@ "on": "Ein", "off": "Aus", "repair": "Reparieren", - "needsApproval": "Genehmigung erforderlich", + "awaitingVerification": "Warten auf Verifizierung", "checking": "Wird geprüft…", "error": "Fehler" }, "codexApproval": { - "title": "Approve ORG2 hooks in Codex", - "description": "Codex has the ORG2 hooks installed, but Codex still needs your approval before it can run them.", - "instructions": "Open Codex, review the 3 ORG2 hooks, then choose Trust all and continue. ORG2 marks this active after the first real hook signal.", - "review": "Review in Codex", - "verified": "Verified by a real Codex hook signal {{time}}." + "title": "ORG2-Hooks in Codex verifizieren", + "description": "Es wird darauf gewartet, dass Codex die aktuellen ORG2-Hooks genehmigt und ausführt.", + "instructions": "Öffne Codex, prüfe die ORG2-Hooks und wähle dann Trust all and continue. Der SessionStart-Hook bestätigt die Aktivierung automatisch, sobald die Sitzung startet.", + "review": "In Codex prüfen", + "verified": "Durch ein echtes Codex-Hook-Signal verifiziert ({{time}})." }, "signals": { "title": "Aktuelle Signale", diff --git a/src/i18n/locales/en/integrations.json b/src/i18n/locales/en/integrations.json index b76888e36..e2fb6b31a 100644 --- a/src/i18n/locales/en/integrations.json +++ b/src/i18n/locales/en/integrations.json @@ -2400,14 +2400,14 @@ "on": "On", "off": "Off", "repair": "Repair", - "needsApproval": "Needs approval", + "awaitingVerification": "Awaiting verification", "checking": "Checking…", "error": "Error" }, "codexApproval": { - "title": "Approve ORG2 hooks in Codex", - "description": "Codex has the ORG2 hooks installed, but Codex still needs your approval before it can run them.", - "instructions": "Open Codex, review the 3 ORG2 hooks, then choose Trust all and continue. ORG2 marks this active after the first real hook signal.", + "title": "Verify ORG2 hooks in Codex", + "description": "Waiting for Codex to approve and execute the current ORG2 hooks.", + "instructions": "Open Codex, review the ORG2 hooks, then choose Trust all and continue. The SessionStart hook verifies activation automatically when the session starts.", "review": "Review in Codex", "verified": "Verified by a real Codex hook signal {{time}}." }, diff --git a/src/i18n/locales/es/integrations.json b/src/i18n/locales/es/integrations.json index 492742d96..426534eaa 100644 --- a/src/i18n/locales/es/integrations.json +++ b/src/i18n/locales/es/integrations.json @@ -1685,6 +1685,8 @@ "emptyConfigPreview": "Sin contenido de configuración" }, "sessionProvenance": { + "masterToggle": "Hooks de procedencia", + "masterToggleDesc": "Al desactivarlos, se desinstalan todos los hooks administrados y no se captura ninguna señal; las selecciones por plataforma se conservan y se restauran al volver a activarlos.", "title": "Procedencia de sesiones", "capture": "Registrar interacciones con archivos", "description": "Registra lecturas y escrituras de archivos como metadatos. No se guardan prompts, salidas de herramientas ni contenido de archivos.", @@ -1701,16 +1703,16 @@ "on": "Activado", "off": "Desactivado", "repair": "Reparar", - "needsApproval": "Requiere aprobación", + "awaitingVerification": "Esperando verificación", "checking": "Comprobando…", "error": "Error" }, "codexApproval": { - "title": "Approve ORG2 hooks in Codex", - "description": "Codex has the ORG2 hooks installed, but Codex still needs your approval before it can run them.", - "instructions": "Open Codex, review the 3 ORG2 hooks, then choose Trust all and continue. ORG2 marks this active after the first real hook signal.", - "review": "Review in Codex", - "verified": "Verified by a real Codex hook signal {{time}}." + "title": "Verificar los hooks de ORG2 en Codex", + "description": "Esperando a que Codex apruebe y ejecute los hooks actuales de ORG2.", + "instructions": "Abre Codex, revisa los hooks de ORG2 y elige Trust all and continue. El hook SessionStart verifica la activación automáticamente al iniciar la sesión.", + "review": "Revisar en Codex", + "verified": "Verificado mediante una señal real de un hook de Codex ({{time}})." }, "signals": { "title": "Señales recientes", diff --git a/src/i18n/locales/fr/integrations.json b/src/i18n/locales/fr/integrations.json index 079624132..65d1b9658 100644 --- a/src/i18n/locales/fr/integrations.json +++ b/src/i18n/locales/fr/integrations.json @@ -1688,6 +1688,8 @@ "emptyConfigPreview": "Aucun contenu de configuration" }, "sessionProvenance": { + "masterToggle": "Hooks de provenance", + "masterToggleDesc": "Lorsque cette option est désactivée, tous les hooks gérés sont désinstallés et aucun signal n’est collecté ; les choix par plateforme sont conservés et restaurés à la réactivation.", "title": "Traçabilité des sessions", "capture": "Enregistrer les interactions avec les fichiers", "description": "Enregistre les lectures et écritures de fichiers sous forme de métadonnées. Les prompts, les sorties d’outils et le contenu des fichiers ne sont pas stockés.", @@ -1704,16 +1706,16 @@ "on": "Activé", "off": "Désactivé", "repair": "Réparer", - "needsApproval": "Approbation requise", + "awaitingVerification": "En attente de vérification", "checking": "Vérification…", "error": "Erreur" }, "codexApproval": { - "title": "Approve ORG2 hooks in Codex", - "description": "Codex has the ORG2 hooks installed, but Codex still needs your approval before it can run them.", - "instructions": "Open Codex, review the 3 ORG2 hooks, then choose Trust all and continue. ORG2 marks this active after the first real hook signal.", - "review": "Review in Codex", - "verified": "Verified by a real Codex hook signal {{time}}." + "title": "Vérifier les hooks ORG2 dans Codex", + "description": "En attente de l’approbation et de l’exécution des hooks ORG2 actuels par Codex.", + "instructions": "Ouvrez Codex, vérifiez les hooks ORG2, puis choisissez Trust all and continue. Le hook SessionStart vérifie automatiquement l’activation au démarrage de la session.", + "review": "Vérifier dans Codex", + "verified": "Vérifié par un signal réel de hook Codex ({{time}})." }, "signals": { "title": "Signaux récents", diff --git a/src/i18n/locales/ja/integrations.json b/src/i18n/locales/ja/integrations.json index c56f6114f..f50f29f53 100644 --- a/src/i18n/locales/ja/integrations.json +++ b/src/i18n/locales/ja/integrations.json @@ -1688,6 +1688,8 @@ "emptyConfigPreview": "設定内容がありません" }, "sessionProvenance": { + "masterToggle": "プロベナンス hooks", + "masterToggleDesc": "オフにすると、管理対象の hooks がすべてアンインストールされ、シグナルは取得されません。プラットフォームごとの選択は保持され、再度オンにすると復元されます。", "title": "セッションの来歴", "capture": "ファイル操作を記録", "description": "ファイルの読み取りと書き込みをメタデータとして記録します。プロンプト、ツール出力、ファイル内容は保存されません。", @@ -1704,16 +1706,16 @@ "on": "オン", "off": "オフ", "repair": "修復", - "needsApproval": "承認が必要", + "awaitingVerification": "検証待ち", "checking": "確認中…", "error": "エラー" }, "codexApproval": { - "title": "Approve ORG2 hooks in Codex", - "description": "Codex has the ORG2 hooks installed, but Codex still needs your approval before it can run them.", - "instructions": "Open Codex, review the 3 ORG2 hooks, then choose Trust all and continue. ORG2 marks this active after the first real hook signal.", - "review": "Review in Codex", - "verified": "Verified by a real Codex hook signal {{time}}." + "title": "Codex で ORG2 hooks を検証", + "description": "Codex が現在の ORG2 hooks を承認して実行するのを待っています。", + "instructions": "Codex を開いて ORG2 hooks を確認し、Trust all and continue を選択してください。セッションの開始時に SessionStart hook が有効化を自動検証します。", + "review": "Codex で確認", + "verified": "実際の Codex hook シグナルで検証済み({{time}})。" }, "signals": { "title": "最近のシグナル", diff --git a/src/i18n/locales/ko/integrations.json b/src/i18n/locales/ko/integrations.json index 976f070e2..f2d34bddb 100644 --- a/src/i18n/locales/ko/integrations.json +++ b/src/i18n/locales/ko/integrations.json @@ -1685,6 +1685,8 @@ "emptyConfigPreview": "설정 내용이 없습니다" }, "sessionProvenance": { + "masterToggle": "출처 추적 hooks", + "masterToggleDesc": "끄면 관리되는 모든 hooks가 제거되고 신호를 수집하지 않습니다. 플랫폼별 선택은 유지되며 다시 켜면 복원됩니다.", "title": "세션 출처", "capture": "파일 상호작용 기록", "description": "파일 읽기와 쓰기를 메타데이터로 기록합니다. 프롬프트, 도구 출력 및 파일 내용은 저장하지 않습니다.", @@ -1701,16 +1703,16 @@ "on": "켜짐", "off": "꺼짐", "repair": "복구", - "needsApproval": "승인 필요", + "awaitingVerification": "확인 대기 중", "checking": "확인 중…", "error": "오류" }, "codexApproval": { - "title": "Approve ORG2 hooks in Codex", - "description": "Codex has the ORG2 hooks installed, but Codex still needs your approval before it can run them.", - "instructions": "Open Codex, review the 3 ORG2 hooks, then choose Trust all and continue. ORG2 marks this active after the first real hook signal.", - "review": "Review in Codex", - "verified": "Verified by a real Codex hook signal {{time}}." + "title": "Codex에서 ORG2 hooks 확인", + "description": "Codex가 현재 ORG2 hooks를 승인하고 실행하기를 기다리는 중입니다.", + "instructions": "Codex를 열고 ORG2 hooks를 검토한 다음 Trust all and continue를 선택하세요. 세션이 시작되면 SessionStart hook이 활성화를 자동으로 확인합니다.", + "review": "Codex에서 검토", + "verified": "실제 Codex hook 신호로 확인됨({{time}})." }, "signals": { "title": "최근 신호", diff --git a/src/i18n/locales/pl/integrations.json b/src/i18n/locales/pl/integrations.json index 2e8f020cc..71929ceab 100644 --- a/src/i18n/locales/pl/integrations.json +++ b/src/i18n/locales/pl/integrations.json @@ -1685,6 +1685,8 @@ "emptyConfigPreview": "Brak treści konfiguracji" }, "sessionProvenance": { + "masterToggle": "Hooki pochodzenia", + "masterToggleDesc": "Po wyłączeniu wszystkie zarządzane hooki zostaną odinstalowane i żadne sygnały nie będą zbierane; wybory dla poszczególnych platform zostaną zachowane i przywrócone po ponownym włączeniu.", "title": "Pochodzenie sesji", "capture": "Rejestruj interakcje z plikami", "description": "Rejestruje odczyty i zapisy plików jako metadane. Prompty, wyniki narzędzi i zawartość plików nie są przechowywane.", @@ -1701,16 +1703,16 @@ "on": "Wł.", "off": "Wył.", "repair": "Napraw", - "needsApproval": "Wymaga zatwierdzenia", + "awaitingVerification": "Oczekiwanie na weryfikację", "checking": "Sprawdzanie…", "error": "Błąd" }, "codexApproval": { - "title": "Approve ORG2 hooks in Codex", - "description": "Codex has the ORG2 hooks installed, but Codex still needs your approval before it can run them.", - "instructions": "Open Codex, review the 3 ORG2 hooks, then choose Trust all and continue. ORG2 marks this active after the first real hook signal.", - "review": "Review in Codex", - "verified": "Verified by a real Codex hook signal {{time}}." + "title": "Weryfikacja hooków ORG2 w Codex", + "description": "Oczekiwanie, aż Codex zatwierdzi i uruchomi bieżące hooki ORG2.", + "instructions": "Otwórz Codex, sprawdź hooki ORG2, a następnie wybierz Trust all and continue. Hook SessionStart automatycznie zweryfikuje aktywację po rozpoczęciu sesji.", + "review": "Sprawdź w Codex", + "verified": "Zweryfikowano prawdziwym sygnałem hooka Codex ({{time}})." }, "signals": { "title": "Ostatnie sygnały", diff --git a/src/i18n/locales/pt/integrations.json b/src/i18n/locales/pt/integrations.json index 84bcee4b1..c48afe84a 100644 --- a/src/i18n/locales/pt/integrations.json +++ b/src/i18n/locales/pt/integrations.json @@ -1688,6 +1688,8 @@ "emptyConfigPreview": "Sem conteúdo de configuração" }, "sessionProvenance": { + "masterToggle": "Hooks de proveniência", + "masterToggleDesc": "Quando desativado, todos os hooks gerenciados são desinstalados e nenhum sinal é capturado; as escolhas de cada plataforma são mantidas e restauradas ao reativar.", "title": "Proveniência da sessão", "capture": "Registrar interações com arquivos", "description": "Registra leituras e gravações de arquivos como metadados. Prompts, saídas de ferramentas e conteúdo dos arquivos não são armazenados.", @@ -1704,16 +1706,16 @@ "on": "Ativado", "off": "Desativado", "repair": "Reparar", - "needsApproval": "Requer aprovação", + "awaitingVerification": "Aguardando verificação", "checking": "Verificando…", "error": "Erro" }, "codexApproval": { - "title": "Approve ORG2 hooks in Codex", - "description": "Codex has the ORG2 hooks installed, but Codex still needs your approval before it can run them.", - "instructions": "Open Codex, review the 3 ORG2 hooks, then choose Trust all and continue. ORG2 marks this active after the first real hook signal.", - "review": "Review in Codex", - "verified": "Verified by a real Codex hook signal {{time}}." + "title": "Verificar hooks do ORG2 no Codex", + "description": "Aguardando o Codex aprovar e executar os hooks atuais do ORG2.", + "instructions": "Abra o Codex, revise os hooks do ORG2 e escolha Trust all and continue. O hook SessionStart verifica a ativação automaticamente quando a sessão começa.", + "review": "Revisar no Codex", + "verified": "Verificado por um sinal real de hook do Codex ({{time}})." }, "signals": { "title": "Sinais recentes", diff --git a/src/i18n/locales/ru/integrations.json b/src/i18n/locales/ru/integrations.json index 2239a23bc..c22e242ee 100644 --- a/src/i18n/locales/ru/integrations.json +++ b/src/i18n/locales/ru/integrations.json @@ -1688,6 +1688,8 @@ "emptyConfigPreview": "Нет содержимого конфигурации" }, "sessionProvenance": { + "masterToggle": "Хуки происхождения", + "masterToggleDesc": "При отключении все управляемые хуки удаляются и сигналы не собираются; выбор для каждой платформы сохраняется и восстанавливается при повторном включении.", "title": "Происхождение сессий", "capture": "Записывать взаимодействия с файлами", "description": "Записывает чтение и запись файлов как метаданные. Запросы, вывод инструментов и содержимое файлов не сохраняются.", @@ -1704,16 +1706,16 @@ "on": "Вкл.", "off": "Выкл.", "repair": "Восстановить", - "needsApproval": "Требуется одобрение", + "awaitingVerification": "Ожидание проверки", "checking": "Проверка…", "error": "Ошибка" }, "codexApproval": { - "title": "Approve ORG2 hooks in Codex", - "description": "Codex has the ORG2 hooks installed, but Codex still needs your approval before it can run them.", - "instructions": "Open Codex, review the 3 ORG2 hooks, then choose Trust all and continue. ORG2 marks this active after the first real hook signal.", - "review": "Review in Codex", - "verified": "Verified by a real Codex hook signal {{time}}." + "title": "Проверить хуки ORG2 в Codex", + "description": "Ожидание, пока Codex одобрит и выполнит текущие хуки ORG2.", + "instructions": "Откройте Codex, проверьте хуки ORG2 и выберите Trust all and continue. Хук SessionStart автоматически подтвердит активацию при запуске сессии.", + "review": "Проверить в Codex", + "verified": "Проверено реальным сигналом хука Codex ({{time}})." }, "signals": { "title": "Недавние сигналы", diff --git a/src/i18n/locales/tr/integrations.json b/src/i18n/locales/tr/integrations.json index 56fdb60fa..92c82f808 100644 --- a/src/i18n/locales/tr/integrations.json +++ b/src/i18n/locales/tr/integrations.json @@ -1685,6 +1685,8 @@ "emptyConfigPreview": "Yapılandırma içeriği yok" }, "sessionProvenance": { + "masterToggle": "Kaynak izleme hook'ları", + "masterToggleDesc": "Kapatıldığında tüm yönetilen hook'lar kaldırılır ve hiçbir sinyal yakalanmaz; platform seçimleri korunur ve yeniden açıldığında geri yüklenir.", "title": "Oturum kaynağı", "capture": "Dosya etkileşimlerini kaydet", "description": "Dosya okuma ve yazma işlemlerini meta veri olarak kaydeder. İstemler, araç çıktıları ve dosya içerikleri saklanmaz.", @@ -1701,16 +1703,16 @@ "on": "Açık", "off": "Kapalı", "repair": "Onar", - "needsApproval": "Onay gerekli", + "awaitingVerification": "Doğrulama bekleniyor", "checking": "Kontrol ediliyor…", "error": "Hata" }, "codexApproval": { - "title": "Approve ORG2 hooks in Codex", - "description": "Codex has the ORG2 hooks installed, but Codex still needs your approval before it can run them.", - "instructions": "Open Codex, review the 3 ORG2 hooks, then choose Trust all and continue. ORG2 marks this active after the first real hook signal.", - "review": "Review in Codex", - "verified": "Verified by a real Codex hook signal {{time}}." + "title": "ORG2 hook'larını Codex'te doğrula", + "description": "Codex'in mevcut ORG2 hook'larını onaylayıp çalıştırması bekleniyor.", + "instructions": "Codex'i açın, ORG2 hook'larını inceleyin ve Trust all and continue seçeneğini seçin. SessionStart hook'u, oturum başladığında etkinleştirmeyi otomatik olarak doğrular.", + "review": "Codex'te incele", + "verified": "Gerçek bir Codex hook sinyaliyle doğrulandı ({{time}})." }, "signals": { "title": "Son sinyaller", diff --git a/src/i18n/locales/vi/integrations.json b/src/i18n/locales/vi/integrations.json index c79135e45..a2701374f 100644 --- a/src/i18n/locales/vi/integrations.json +++ b/src/i18n/locales/vi/integrations.json @@ -1688,6 +1688,8 @@ "emptyConfigPreview": "Không có nội dung cấu hình" }, "sessionProvenance": { + "masterToggle": "Hook truy xuất nguồn gốc", + "masterToggleDesc": "Khi tắt, tất cả hook được quản lý sẽ bị gỡ và không có tín hiệu nào được thu thập; lựa chọn của từng nền tảng được giữ lại và khôi phục khi bật lại.", "title": "Nguồn gốc phiên", "capture": "Ghi lại tương tác với tệp", "description": "Ghi các thao tác đọc và ghi tệp dưới dạng siêu dữ liệu. Không lưu câu lệnh, đầu ra công cụ hoặc nội dung tệp.", @@ -1704,16 +1706,16 @@ "on": "Bật", "off": "Tắt", "repair": "Sửa", - "needsApproval": "Cần phê duyệt", + "awaitingVerification": "Đang chờ xác minh", "checking": "Đang kiểm tra…", "error": "Lỗi" }, "codexApproval": { - "title": "Approve ORG2 hooks in Codex", - "description": "Codex has the ORG2 hooks installed, but Codex still needs your approval before it can run them.", - "instructions": "Open Codex, review the 3 ORG2 hooks, then choose Trust all and continue. ORG2 marks this active after the first real hook signal.", - "review": "Review in Codex", - "verified": "Verified by a real Codex hook signal {{time}}." + "title": "Xác minh hook ORG2 trong Codex", + "description": "Đang chờ Codex phê duyệt và chạy các hook ORG2 hiện tại.", + "instructions": "Mở Codex, xem lại các hook ORG2, rồi chọn Trust all and continue. Hook SessionStart sẽ tự động xác minh việc kích hoạt khi phiên bắt đầu.", + "review": "Xem lại trong Codex", + "verified": "Đã xác minh bằng tín hiệu hook Codex thực ({{time}})." }, "signals": { "title": "Tín hiệu gần đây", diff --git a/src/i18n/locales/zh-Hant/integrations.json b/src/i18n/locales/zh-Hant/integrations.json index d7cea37e9..9a7eeb31b 100644 --- a/src/i18n/locales/zh-Hant/integrations.json +++ b/src/i18n/locales/zh-Hant/integrations.json @@ -1688,6 +1688,8 @@ "emptyConfigPreview": "沒有配置內容" }, "sessionProvenance": { + "masterToggle": "溯源 Hooks", + "masterToggleDesc": "關閉後將解除安裝所有受管理的 hook,並停止擷取任何訊號;各平台的選擇會保留,重新開啟時恢復。", "title": "Session 來源追蹤", "capture": "擷取檔案互動", "description": "以中繼資料記錄檔案讀取與寫入。不會儲存提示詞、工具輸出或檔案內容。", @@ -1704,14 +1706,14 @@ "on": "開啟", "off": "關閉", "repair": "修復", - "needsApproval": "需要授權", + "awaitingVerification": "等待驗證", "checking": "檢查中…", "error": "錯誤" }, "codexApproval": { - "title": "在 Codex 中授權 ORG2 hooks", - "description": "ORG2 hooks 已安裝,但 Codex 仍需要你的明確授權才能執行。", - "instructions": "開啟 Codex,檢查 3 條 ORG2 hooks,然後選擇 Trust all and continue。收到第一條真實 hook 訊號後,ORG2 會自動標記為已啟用。", + "title": "在 Codex 中驗證 ORG2 hooks", + "description": "正在等待 Codex 授權並執行目前的 ORG2 hooks。", + "instructions": "開啟 Codex,檢查 ORG2 hooks,然後選擇 Trust all and continue。工作階段啟動時,SessionStart hook 會自動驗證是否已啟用。", "review": "在 Codex 中檢查", "verified": "已透過真實 Codex hook 訊號驗證({{time}})。" }, diff --git a/src/i18n/locales/zh/integrations.json b/src/i18n/locales/zh/integrations.json index 4d958b82c..5bada926f 100644 --- a/src/i18n/locales/zh/integrations.json +++ b/src/i18n/locales/zh/integrations.json @@ -1759,14 +1759,14 @@ "on": "开启", "off": "关闭", "repair": "修复", - "needsApproval": "需要授权", + "awaitingVerification": "等待验证", "checking": "检查中…", "error": "错误" }, "codexApproval": { - "title": "在 Codex 中授权 ORG2 hooks", - "description": "ORG2 hooks 已安装,但 Codex 需要你的明确授权才能运行它们。", - "instructions": "打开 Codex,检查 3 条 ORG2 hooks,然后选择 Trust all and continue。收到第一条真实 hook 信号后,ORG2 会自动标记为已启用。", + "title": "在 Codex 中验证 ORG2 hooks", + "description": "正在等待 Codex 授权并执行当前的 ORG2 hooks。", + "instructions": "打开 Codex,检查 ORG2 hooks,然后选择 Trust all and continue。会话启动时,SessionStart hook 会自动验证是否已启用。", "review": "在 Codex 中检查", "verified": "已通过真实 Codex hook 信号验证({{time}})。" }, diff --git a/src/modules/shared/dataSource/SessionProvenanceHooksPanel.tsx b/src/modules/shared/dataSource/SessionProvenanceHooksPanel.tsx index 9b0a97a17..10f027b79 100644 --- a/src/modules/shared/dataSource/SessionProvenanceHooksPanel.tsx +++ b/src/modules/shared/dataSource/SessionProvenanceHooksPanel.tsx @@ -237,22 +237,25 @@ const HookPlatformsTable: React.FC = () => { }, [loadStatuses]); useEffect(() => { - if (statuses.codex?.activationState !== "awaiting_approval") return; + if (statuses.codex?.activationState !== "awaiting_verification") return; const interval = window.setInterval(() => void loadStatuses(true), 2_000); return () => window.clearInterval(interval); }, [loadStatuses, statuses.codex?.activationState]); useEffect(() => { for (const platform of PLATFORMS) { - const awaitingApproval = + const awaitingVerification = platform.id === "codex" && - statuses[platform.id]?.activationState === "awaiting_approval"; - if (awaitingApproval && !approvalAutoExpanded.current.has(platform.id)) { + statuses[platform.id]?.activationState === "awaiting_verification"; + if ( + awaitingVerification && + !approvalAutoExpanded.current.has(platform.id) + ) { approvalAutoExpanded.current.add(platform.id); setExpandedRowKeys((current) => current.includes(platform.id) ? current : [...current, platform.id] ); - } else if (!awaitingApproval) { + } else if (!awaitingVerification) { approvalAutoExpanded.current.delete(platform.id); } } @@ -337,8 +340,8 @@ const HookPlatformsTable: React.FC = () => { if (status && status.desiredEnabled && !status.enabled) { return { color: "warning", labelKey: "repair" }; } - if (status?.activationState === "awaiting_approval") { - return { color: "warning", labelKey: "needsApproval" }; + if (status?.activationState === "awaiting_verification") { + return { color: "warning", labelKey: "awaitingVerification" }; } return status?.enabled ? { color: "success", labelKey: "on" } @@ -429,10 +432,10 @@ const HookPlatformsTable: React.FC = () => { path: status.configPath, }); } - if (status?.activationState === "awaiting_approval") { + if (status?.activationState === "awaiting_verification") { return t("agentOrgs.sessionProvenance.codexApproval.description", { defaultValue: - "Codex has the ORG2 hooks installed, but Codex still needs your approval before it can run them.", + "Waiting for Codex to approve and execute the current ORG2 hooks.", }); } if (status?.activationState === "active" && status.lastActivatedAt) { @@ -565,7 +568,7 @@ const HookPlatformsTable: React.FC = () => { {description(row)}

{row.id === "codex" && - row.status?.activationState === "awaiting_approval" && ( + row.status?.activationState === "awaiting_verification" && (
{

{t( "agentOrgs.sessionProvenance.codexApproval.title", - { defaultValue: "Approve ORG2 hooks in Codex" } + { defaultValue: "Verify ORG2 hooks in Codex" } )}

@@ -587,7 +590,7 @@ const HookPlatformsTable: React.FC = () => { "agentOrgs.sessionProvenance.codexApproval.instructions", { defaultValue: - "Open Codex, review the 3 ORG2 hooks, then choose Trust all and continue. ORG2 marks this active after the first real hook signal.", + "Open Codex, review the ORG2 hooks, then choose Trust all and continue. The SessionStart hook verifies activation automatically when the session starts.", } )}

diff --git a/tests/e2e/specs/core/session-launch-wiring-ui.spec.mjs b/tests/e2e/specs/core/session-launch-wiring-ui.spec.mjs index 61eed18fa..04cf81cc5 100644 --- a/tests/e2e/specs/core/session-launch-wiring-ui.spec.mjs +++ b/tests/e2e/specs/core/session-launch-wiring-ui.spec.mjs @@ -1258,7 +1258,7 @@ describe("Session launch wiring rendered UI invariants", function () { .trim() .replace(/\s+/g, " "); return ( - activationState === "awaiting_approval" && + activationState === "awaiting_verification" && cardText.includes("ORG2 hooks") && cardText.includes("Trust all and continue") && approvalState?.[2] === true @@ -1323,7 +1323,7 @@ describe("Session launch wiring rendered UI invariants", function () { return false; } return ( - approvalOutput.includes("3 hooks are new or changed") && + /\d+ hooks? (?:are|is) new or changed/.test(approvalOutput) && approvalOutput.includes("Trust") && approvalOutput.includes("continue") ); @@ -1353,21 +1353,15 @@ describe("Session launch wiring rendered UI invariants", function () { ); } - // Deterministically emulate the first post-approval callback by invoking - // the real installed hook binary and adapter path. This establishes the - // activation receipt without automating the user's security decision. + // Deterministically emulate the post-approval SessionStart callback by + // invoking the real installed hook binary and adapter path. This proves + // the activation receipt no longer waits for a later tool interaction, + // without automating the user's security decision. execFileSync(APP_BINARY, ["--session-provenance-hook", "codex"], { input: JSON.stringify({ session_id: `e2e-codex-trust-${RUN_ID}`, - turn_id: `turn-${RUN_ID}`, cwd: E2E_REPO_PATH, - hook_event_name: "PostToolUse", - tool_name: "apply_patch", - tool_use_id: `tool-${RUN_ID}`, - tool_input: { - command: - "*** Begin Patch\n*** Add File: e2e-trust-proof.txt\n+proof\n*** End Patch", - }, + hook_event_name: "SessionStart", }), env: process.env, stdio: ["pipe", "ignore", "pipe"],