@@ -389,6 +389,18 @@ export function buildNativeHostManifest(options: {
389389 } ;
390390}
391391
392+ function extensionIdFromAllowedOrigin ( origin : string ) : string | null {
393+ const match = / ^ c h r o m e - e x t e n s i o n : \/ \/ ( [ ^ / ] + ) \/ $ / . exec ( origin ) ;
394+ return match ?. [ 1 ] ?? null ;
395+ }
396+
397+ function mergeExtensionIds ( extensionIds : string [ ] , allowedOrigins : string [ ] | undefined ) : string [ ] {
398+ const existingIds = ( allowedOrigins ?? [ ] )
399+ . map ( extensionIdFromAllowedOrigin )
400+ . filter ( ( id ) : id is string => Boolean ( id ) ) ;
401+ return Array . from ( new Set ( [ ...existingIds , ...extensionIds ] . filter ( Boolean ) ) ) ;
402+ }
403+
392404function resolveNodePath ( ) : string {
393405 // Don't use bun or the compiled autohand binary as the shebang —
394406 // Chrome native messaging host scripts must use Node.js because they
@@ -623,13 +635,15 @@ export async function ensureNativeHostInstalled(options?: {
623635 const expectedExtensionIds = [ options ?. extensionId ] . filter ( ( id ) : id is string => Boolean ( id ) ) ;
624636 const expectedAllowedOrigins = expectedExtensionIds . map ( ( extensionId ) => `chrome-extension://${ extensionId } /` ) ;
625637 const hostScriptPath = path . join ( getBrowserDataRoot ( homeDir ) , 'host.js' ) ;
638+ let installExtensionIds = expectedExtensionIds ;
626639
627640 // If the Chrome manifest already exists and its host script is reachable
628641 // with a valid shebang and it is paired with the current extension id,
629642 // don't overwrite.
630643 if ( await pathExists ( chromeManifest . manifestPath ) ) {
631644 try {
632645 const manifest = await readJson ( chromeManifest . manifestPath ) as { path ?: string ; allowed_origins ?: string [ ] } ;
646+ installExtensionIds = mergeExtensionIds ( expectedExtensionIds , manifest . allowed_origins ) ;
633647 if ( manifest . path && await pathExists ( manifest . path ) ) {
634648 // Check shebang is a valid Node.js interpreter (not bun, not the autohand binary itself)
635649 const firstLine = ( await readFile ( manifest . path , 'utf8' ) ) . split ( '\n' ) [ 0 ] ?? '' ;
@@ -656,7 +670,7 @@ export async function ensureNativeHostInstalled(options?: {
656670 const { command, args } = resolveCliLaunchSpec ( ) ;
657671
658672 await installNativeHost ( {
659- extensionIds : expectedExtensionIds ,
673+ extensionIds : installExtensionIds ,
660674 cliCommand : command ,
661675 cliArgPrefix : args . length ? args : undefined ,
662676 } ) ;
0 commit comments