Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
6.8 kB · 233 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234import { readdir } from 'fs/promises'import { homedir } from 'os'import { join } from 'path'import { isFsInaccessible } from '../errors.js'
export const CHROME_EXTENSION_URL = 'https://claude.ai/chrome'
// Production extension IDconst PROD_EXTENSION_ID = 'fcoeoabgfenejglbffodgkkbkcdhcgfn'// Dev extension IDs (for internal use)const DEV_EXTENSION_ID = 'dihbgbndebgnbjfmelmegjepbnkhlgni'const ANT_EXTENSION_ID = 'dngcpimnedloihjnnfngkgjoidhnaolf'
function getExtensionIds(): string[] { return process.env.USER_TYPE === 'ant' ? [PROD_EXTENSION_ID, DEV_EXTENSION_ID, ANT_EXTENSION_ID] : [PROD_EXTENSION_ID]}
// Must match ChromiumBrowser from common.tsexport type ChromiumBrowser = | 'chrome' | 'brave' | 'arc' | 'chromium' | 'edge' | 'vivaldi' | 'opera'
export type BrowserPath = { browser: ChromiumBrowser path: string}
type Logger = (message: string) => void
// Browser detection order - must match BROWSER_DETECTION_ORDER from common.tsconst BROWSER_DETECTION_ORDER: ChromiumBrowser[] = [ 'chrome', 'brave', 'arc', 'edge', 'chromium', 'vivaldi', 'opera',]
type BrowserDataConfig = { macos: string[] linux: string[] windows: { path: string[]; useRoaming?: boolean }}
// Must match CHROMIUM_BROWSERS dataPath from common.tsconst CHROMIUM_BROWSERS: Record<ChromiumBrowser, BrowserDataConfig> = { chrome: { macos: ['Library', 'Application Support', 'Google', 'Chrome'], linux: ['.config', 'google-chrome'], windows: { path: ['Google', 'Chrome', 'User Data'] }, }, brave: { macos: ['Library', 'Application Support', 'BraveSoftware', 'Brave-Browser'], linux: ['.config', 'BraveSoftware', 'Brave-Browser'], windows: { path: ['BraveSoftware', 'Brave-Browser', 'User Data'] }, }, arc: { macos: ['Library', 'Application Support', 'Arc', 'User Data'], linux: [], windows: { path: ['Arc', 'User Data'] }, }, chromium: { macos: ['Library', 'Application Support', 'Chromium'], linux: ['.config', 'chromium'], windows: { path: ['Chromium', 'User Data'] }, }, edge: { macos: ['Library', 'Application Support', 'Microsoft Edge'], linux: ['.config', 'microsoft-edge'], windows: { path: ['Microsoft', 'Edge', 'User Data'] }, }, vivaldi: { macos: ['Library', 'Application Support', 'Vivaldi'], linux: ['.config', 'vivaldi'], windows: { path: ['Vivaldi', 'User Data'] }, }, opera: { macos: ['Library', 'Application Support', 'com.operasoftware.Opera'], linux: ['.config', 'opera'], windows: { path: ['Opera Software', 'Opera Stable'], useRoaming: true }, },}
/** * Get all browser data paths to check for extension installation. * Portable version that uses process.platform directly. */export function getAllBrowserDataPathsPortable(): BrowserPath[] { const home = homedir() const paths: BrowserPath[] = []
for (const browserId of BROWSER_DETECTION_ORDER) { const config = CHROMIUM_BROWSERS[browserId] let dataPath: string[] | undefined
switch (process.platform) { case 'darwin': dataPath = config.macos break case 'linux': dataPath = config.linux break case 'win32': { if (config.windows.path.length > 0) { const appDataBase = config.windows.useRoaming ? join(home, 'AppData', 'Roaming') : join(home, 'AppData', 'Local') paths.push({ browser: browserId, path: join(appDataBase, ...config.windows.path), }) } continue } }
if (dataPath && dataPath.length > 0) { paths.push({ browser: browserId, path: join(home, ...dataPath), }) } }
return paths}
/** * Detects if the Claude in Chrome extension is installed by checking the Extensions * directory across all supported Chromium-based browsers and their profiles. * * This is a portable version that can be used by both TUI and VS Code extension. * * @param browserPaths - Array of browser data paths to check (from getAllBrowserDataPaths) * @param log - Optional logging callback for debug messages * @returns Object with isInstalled boolean and the browser where the extension was found */export async function detectExtensionInstallationPortable( browserPaths: BrowserPath[], log?: Logger,): Promise<{ isInstalled: boolean browser: ChromiumBrowser | null}> { if (browserPaths.length === 0) { log?.(`[Claude in Chrome] No browser paths to check`) return { isInstalled: false, browser: null } }
const extensionIds = getExtensionIds()
// Check each browser for the extension for (const { browser, path: browserBasePath } of browserPaths) { let browserProfileEntries = []
try { browserProfileEntries = await readdir(browserBasePath, { withFileTypes: true, }) } catch (e) { // Browser not installed or path doesn't exist, continue to next browser if (isFsInaccessible(e)) continue throw e }
const profileDirs = browserProfileEntries .filter(entry => entry.isDirectory()) .filter( entry => entry.name === 'Default' || entry.name.startsWith('Profile '), ) .map(entry => entry.name)
if (profileDirs.length > 0) { log?.( `[Claude in Chrome] Found ${browser} profiles: ${profileDirs.join(', ')}`, ) }
// Check each profile for any of the extension IDs for (const profile of profileDirs) { for (const extensionId of extensionIds) { const extensionPath = join( browserBasePath, profile, 'Extensions', extensionId, )
try { await readdir(extensionPath) log?.( `[Claude in Chrome] Extension ${extensionId} found in ${browser} ${profile}`, ) return { isInstalled: true, browser } } catch { // Extension not found in this profile, continue checking } } } }
log?.(`[Claude in Chrome] Extension not found in any browser`) return { isInstalled: false, browser: null }}
/** * Simple wrapper that returns just the boolean result */export async function isChromeExtensionInstalledPortable( browserPaths: BrowserPath[], log?: Logger,): Promise<boolean> { const result = await detectExtensionInstallationPortable(browserPaths, log) return result.isInstalled}
/** * Convenience function that gets browser paths automatically. * Use this when you don't need to provide custom browser paths. */export function isChromeExtensionInstalled(log?: Logger): Promise<boolean> { const browserPaths = getAllBrowserDataPathsPortable() return isChromeExtensionInstalledPortable(browserPaths, log)}