diff --git a/Resources/Info.plist b/Resources/Info.plist
index 3f0cc6b569..6f92332f82 100644
--- a/Resources/Info.plist
+++ b/Resources/Info.plist
@@ -69,6 +69,8 @@
NSMicrophoneUsageDescription
A program running within cmux would like to use your microphone.
+ NSSpeechRecognitionUsageDescription
+ A program running within cmux would like to use speech recognition.
NSCameraUsageDescription
A program running within cmux would like to use your camera.
NSBluetoothAlwaysUsageDescription
diff --git a/Resources/InfoPlist.xcstrings b/Resources/InfoPlist.xcstrings
index 9e50f7d4b9..937eb953db 100644
--- a/Resources/InfoPlist.xcstrings
+++ b/Resources/InfoPlist.xcstrings
@@ -149,6 +149,119 @@
}
}
},
+ "NSSpeechRecognitionUsageDescription": {
+ "extractionState": "manual",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "A program running within cmux would like to use speech recognition."
+ }
+ },
+ "ja": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "cmux 内で実行中のプログラムが音声認識の使用を求めています。"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "在 cmux 中运行的程序想要使用语音识别。"
+ }
+ },
+ "zh-Hant": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "在 cmux 中執行的程式想要使用語音辨識。"
+ }
+ },
+ "ko": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "cmux 내에서 실행 중인 프로그램이 음성 인식을 사용하려고 합니다."
+ }
+ },
+ "de": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Ein in cmux ausgeführtes Programm möchte Spracherkennung verwenden."
+ }
+ },
+ "es": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Un programa en ejecución dentro de cmux desea usar el reconocimiento de voz."
+ }
+ },
+ "fr": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Un programme s'exécutant dans cmux souhaite utiliser la reconnaissance vocale."
+ }
+ },
+ "it": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Un programma in esecuzione in cmux desidera utilizzare il riconoscimento vocale."
+ }
+ },
+ "da": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Et program, der kører i cmux, vil gerne bruge talegenkendelse."
+ }
+ },
+ "pl": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Program działający w cmux chciałby użyć rozpoznawania mowy."
+ }
+ },
+ "ru": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Программа, запущенная в cmux, хотела бы использовать распознавание речи."
+ }
+ },
+ "bs": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Program koji se izvršava unutar cmux želi koristiti prepoznavanje govora."
+ }
+ },
+ "ar": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "يرغب برنامج يعمل داخل cmux في استخدام التعرف على الكلام."
+ }
+ },
+ "nb": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Et program som kjører i cmux ønsker å bruke talegjenkjenning."
+ }
+ },
+ "pt-BR": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Um programa em execução no cmux gostaria de usar reconhecimento de fala."
+ }
+ },
+ "th": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "โปรแกรมที่ทำงานภายใน cmux ต้องการใช้การรู้จำเสียงพูด"
+ }
+ },
+ "tr": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "cmux içinde çalışan bir program konuşma tanımayı kullanmak istiyor."
+ }
+ }
+ }
+ },
"New $(PRODUCT_NAME) Workspace Here": {
"extractionState": "manual",
"localizations": {
diff --git a/cmux.xcodeproj/project.pbxproj b/cmux.xcodeproj/project.pbxproj
index 29e65084c7..c0e19b6162 100644
--- a/cmux.xcodeproj/project.pbxproj
+++ b/cmux.xcodeproj/project.pbxproj
@@ -341,6 +341,7 @@
F4100000A1B2C3D4E5F60718 /* PortScannerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4100001A1B2C3D4E5F60718 /* PortScannerTests.swift */; };
A5001270 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = A5001271 /* PostHog */; };
A5001521 /* PostHogAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5001520 /* PostHogAnalytics.swift */; };
+ C0DEF5000000000000000001 /* PrivacyUsageDescriptionBundleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0DEF5000000000000000002 /* PrivacyUsageDescriptionBundleTests.swift */; };
C47110010000000000000001 /* ProcessPipeReadCrashRegressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47110010000000000000002 /* ProcessPipeReadCrashRegressionTests.swift */; };
C47110020000000000000001 /* ProcessPipeReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47110020000000000000002 /* ProcessPipeReader.swift */; };
C47110020000000000000003 /* ProcessPipeReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47110020000000000000002 /* ProcessPipeReader.swift */; };
@@ -977,6 +978,7 @@
A5001541 /* PortScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PortScanner.swift; sourceTree = ""; };
F4100001A1B2C3D4E5F60718 /* PortScannerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PortScannerTests.swift; sourceTree = ""; };
A5001520 /* PostHogAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogAnalytics.swift; sourceTree = ""; };
+ C0DEF5000000000000000002 /* PrivacyUsageDescriptionBundleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyUsageDescriptionBundleTests.swift; sourceTree = ""; };
C47110010000000000000002 /* ProcessPipeReadCrashRegressionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessPipeReadCrashRegressionTests.swift; sourceTree = ""; };
C47110020000000000000002 /* ProcessPipeReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessPipeReader.swift; sourceTree = ""; };
A5C0DE0000000000000000B9 /* ProjectBuildSettingsTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Panels/ProjectBuildSettingsTabView.swift; sourceTree = ""; };
@@ -1815,6 +1817,7 @@
D7AB00000000000000000012 /* WorkspaceAdjacentPaneMoveTests.swift */,
D7AB3605C10DEF0000000002 /* WorkspaceCloseTabsContextMenuTests.swift */,
D0B10009A1B2C3D4E5F60001 /* PortalTabDragRoutingTests.swift */,
+ C0DEF5000000000000000002 /* PrivacyUsageDescriptionBundleTests.swift */,
71F8ED91A4B55D34BE6A0668 /* WorkspaceUnitTests.swift */,
71F8ED92A4B55D34BE6A0668 /* WorkspaceSplitStartupCommandTests.swift */,
EF7347934AB1BD387686EE43 /* WorkspaceActionDispatcherTests.swift */,
@@ -2699,6 +2702,7 @@
B3575000000000000000000A /* PiVaultAgentPersistenceTests.swift in Sources */,
D0B10008A1B2C3D4E5F60001 /* PortalTabDragRoutingTests.swift in Sources */,
F4100000A1B2C3D4E5F60718 /* PortScannerTests.swift in Sources */,
+ C0DEF5000000000000000001 /* PrivacyUsageDescriptionBundleTests.swift in Sources */,
C47110010000000000000001 /* ProcessPipeReadCrashRegressionTests.swift in Sources */,
F5410004A1B2C3D4E5F60718 /* RestorableAgentHookProviderHermesTests.swift in Sources */,
F5410000A1B2C3D4E5F60718 /* RestorableAgentHookProviderResumeTests.swift in Sources */,
diff --git a/cmuxTests/PrivacyUsageDescriptionBundleTests.swift b/cmuxTests/PrivacyUsageDescriptionBundleTests.swift
new file mode 100644
index 0000000000..3ea72892e3
--- /dev/null
+++ b/cmuxTests/PrivacyUsageDescriptionBundleTests.swift
@@ -0,0 +1,21 @@
+import Foundation
+import Testing
+
+#if canImport(cmux_DEV)
+@testable import cmux_DEV
+#elseif canImport(cmux)
+@testable import cmux
+#endif
+
+@MainActor
+@Suite
+struct PrivacyUsageDescriptionBundleTests {
+ @Test
+ func appBundleDeclaresSpeechRecognitionUsageDescription() throws {
+ let usageDescription = try #require(Bundle(for: AppDelegate.self)
+ .infoDictionary?["NSSpeechRecognitionUsageDescription"] as? String
+ )
+
+ #expect(usageDescription == "A program running within cmux would like to use speech recognition.")
+ }
+}