MCPcopy Index your code
hub / github.com/codeaashu/claude-code / registerMacos

Function registerMacos

src/utils/deepLink/registerProtocol.ts:75–138  ·  view source on GitHub ↗

* Register the protocol handler on macOS. * * Creates a .app bundle where the CFBundleExecutable is a symlink to the * already-installed (and signed) `claude` binary. When macOS opens a * `claude-cli://` URL, it launches `claude` through this app bundle. * Claude then uses the url-handler NAPI

(claudePath: string)

Source from the content-addressed store, hash-verified

73 * to be signed and allowlisted by endpoint security tools like Santa).
74 */
75async function registerMacos(claudePath: string): Promise<void> {
76 const contentsDir = path.join(MACOS_APP_DIR, 'Contents')
77
78 // Remove any existing app bundle to start clean
79 try {
80 await fs.rm(MACOS_APP_DIR, { recursive: true })
81 } catch (e: unknown) {
82 const code = getErrnoCode(e)
83 if (code !== 'ENOENT') {
84 throw e
85 }
86 }
87
88 await fs.mkdir(path.dirname(MACOS_SYMLINK_PATH), { recursive: true })
89
90 // Info.plist — registers the URL scheme with claude as the executable
91 const infoPlist = `<?xml version="1.0" encoding="UTF-8"?>
92<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
93<plist version="1.0">
94<dict>
95 <key>CFBundleIdentifier</key>
96 <string>${MACOS_BUNDLE_ID}</string>
97 <key>CFBundleName</key>
98 <string>${APP_NAME}</string>
99 <key>CFBundleExecutable</key>
100 <string>claude</string>
101 <key>CFBundleVersion</key>
102 <string>1.0</string>
103 <key>CFBundlePackageType</key>
104 <string>APPL</string>
105 <key>LSBackgroundOnly</key>
106 <true/>
107 <key>CFBundleURLTypes</key>
108 <array>
109 <dict>
110 <key>CFBundleURLName</key>
111 <string>Claude Code Deep Link</string>
112 <key>CFBundleURLSchemes</key>
113 <array>
114 <string>${DEEP_LINK_PROTOCOL}</string>
115 </array>
116 </dict>
117 </array>
118</dict>
119</plist>`
120
121 await fs.writeFile(path.join(contentsDir, 'Info.plist'), infoPlist)
122
123 // Symlink to the already-signed claude binary — avoids a new executable
124 // that would need signing and endpoint-security allowlisting.
125 // Written LAST among the throwing fs calls: isProtocolHandlerCurrent reads
126 // this symlink, so it acts as the commit marker. If Info.plist write
127 // failed above, no symlink → next session retries.
128 await fs.symlink(claudePath, MACOS_SYMLINK_PATH)
129
130 // Re-register the app with LaunchServices so macOS picks up the URL scheme.
131 const lsregister =
132 '/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister'

Callers 1

registerProtocolHandlerFunction · 0.85

Calls 3

getErrnoCodeFunction · 0.85
execFileNoThrowFunction · 0.85
logForDebuggingFunction · 0.85

Tested by

no test coverage detected