diff --git a/apps/boss-agent-mac/Sources/BossAgentApp.swift b/apps/boss-agent-mac/Sources/BossAgentApp.swift
index 35a0896..90c7cb4 100644
--- a/apps/boss-agent-mac/Sources/BossAgentApp.swift
+++ b/apps/boss-agent-mac/Sources/BossAgentApp.swift
@@ -68,6 +68,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate, WKNavigationDelegate {
loadAgentPanel(tab: activeTab)
}
+ func application(_ application: NSApplication, open urls: [URL]) {
+ for url in urls where isBossAgentDeepLink(url) {
+ handleBossAgentDeepLink(url)
+ }
+ }
+
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
loadFallback()
}
@@ -109,6 +115,24 @@ final class AppDelegate: NSObject, NSApplicationDelegate, WKNavigationDelegate {
url.path == "/api/v1/boss-agent/permissions/open"
}
+ private func isBossAgentDeepLink(_ url: URL) -> Bool {
+ url.scheme == "boss-agent"
+ }
+
+ private func handleBossAgentDeepLink(_ url: URL) {
+ if url.host == "permissions" && url.path == "/open" {
+ handlePermissionTarget(
+ queryValue("target", in: url) ?? "all",
+ returnTab: queryValue("returnTab", in: url) ?? "permissions"
+ )
+ return
+ }
+
+ if url.host == "tab" {
+ loadAgentPanel(tab: String(url.path.dropFirst()))
+ }
+ }
+
private func isAgentPanelUrl(_ url: URL) -> Bool {
let host = url.host ?? ""
return (host == "127.0.0.1" || host == "localhost") && url.port == 4317 && (url.path == "/boss-agent" || url.path == "/")
@@ -137,9 +161,14 @@ final class AppDelegate: NSObject, NSApplicationDelegate, WKNavigationDelegate {
}
private func handlePermissionSetupNavigation(_ url: URL) {
- let target =
- queryValue("target", in: url) ?? "all"
- let returnTab = normalizedTab(queryValue("returnTab", in: url) ?? activeTab)
+ handlePermissionTarget(
+ queryValue("target", in: url) ?? "all",
+ returnTab: queryValue("returnTab", in: url) ?? activeTab
+ )
+ }
+
+ private func handlePermissionTarget(_ target: String, returnTab rawReturnTab: String) {
+ let returnTab = normalizedTab(rawReturnTab)
activeTab = returnTab
requestNativePermission(for: target)
diff --git a/scripts/build-boss-agent-mac-app.sh b/scripts/build-boss-agent-mac-app.sh
index e4d049e..fd9bb4e 100644
--- a/scripts/build-boss-agent-mac-app.sh
+++ b/scripts/build-boss-agent-mac-app.sh
@@ -132,6 +132,17 @@ cat > "$CONTENTS_DIR/Info.plist" <<'PLIST'
boss-agent
CFBundleIconFile
BossAgent.icns
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ com.hyzq.boss.agent
+ CFBundleURLSchemes
+
+ boss-agent
+
+
+
CFBundlePackageType
APPL
CFBundleShortVersionString
@@ -162,4 +173,5 @@ cat > "$CONTENTS_DIR/Info.plist" <<'PLIST'
PLIST
plutil -lint "$CONTENTS_DIR/Info.plist" >/dev/null
+codesign --force --deep --sign - "$APP_DIR" >/dev/null
echo "$APP_DIR"
diff --git a/tests/boss-agent-status.test.mjs b/tests/boss-agent-status.test.mjs
index 6879746..fd61837 100644
--- a/tests/boss-agent-status.test.mjs
+++ b/tests/boss-agent-status.test.mjs
@@ -248,6 +248,8 @@ test("boss-agent mac app intercepts permission links and triggers native app per
assert.match(swiftSource, /nativePermissionQueryItems/);
assert.match(swiftSource, /nativeCamera/);
assert.match(swiftSource, /nativeMicrophone/);
+ assert.match(swiftSource, /func application\(_ application: NSApplication, open urls: \[URL\]\)/);
+ assert.match(swiftSource, /isBossAgentDeepLink/);
assert.match(swiftSource, /AVCaptureDevice\.authorizationStatus\(for: \.video/);
assert.match(swiftSource, /AVCaptureDevice\.authorizationStatus\(for: \.audio/);
assert.match(swiftSource, /NSApplication\.didBecomeActiveNotification/);
@@ -255,7 +257,10 @@ test("boss-agent mac app intercepts permission links and triggers native app per
assert.match(buildScript, /NSCameraUsageDescription/);
assert.match(buildScript, /NSAppleEventsUsageDescription/);
assert.match(buildScript, /NSLocalNetworkUsageDescription/);
+ assert.match(buildScript, /CFBundleURLTypes/);
+ assert.match(buildScript, /boss-agent/);
assert.match(buildScript, /CFBundleIconFile/);
assert.match(buildScript, /BossAgent\.icns/);
assert.match(buildScript, /iconutil -c icns/);
+ assert.match(buildScript, /codesign --force --deep --sign - "\$APP_DIR"/);
});