From 8757d26387b35a616b6e3315613d1a01b328bc52 Mon Sep 17 00:00:00 2001 From: Atish Patel Date: Mon, 1 Sep 2025 16:59:49 -0500 Subject: [PATCH 1/4] fix: enhance recipe deeplink parsing to handle "+" characters --- ui/desktop/src/main.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index 9ed1f91c9d86..f3af07aafb27 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -329,7 +329,22 @@ app.on('open-url', async (_event, url) => { console.log('[Main] Received open-url event:', url); if (parsedUrl.hostname === 'bot' || parsedUrl.hostname === 'recipe') { console.log('[Main] Detected bot/recipe URL, creating new chat window'); - const recipeDeeplink = parsedUrl.searchParams.get('config'); + let recipeDeeplink = parsedUrl.searchParams.get('config'); + if (recipeDeeplink?.includes(' ')) { + // Parse raw query to preserve "+" characters in values like config + const search = parsedUrl.search || ''; + // parse recipe deeplink from search params + const configMatch = search.match(/(?:[?&])config=([^&]*)/); + // get recipe deeplink from config match + let recipeDeeplinkTmp = configMatch ? configMatch[1] : null; + if (recipeDeeplinkTmp) { + try { + recipeDeeplink = decodeURIComponent(recipeDeeplinkTmp); + } catch { + // Leave as-is if decoding fails + } + } + } const scheduledJobId = parsedUrl.searchParams.get('scheduledJob'); // Create a new window directly From fa76760b5cdccbfd4dcb727c3f08e2ea6b520f59 Mon Sep 17 00:00:00 2001 From: Atish Patel Date: Mon, 1 Sep 2025 17:24:43 -0500 Subject: [PATCH 2/4] make check more generic --- ui/desktop/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index f3af07aafb27..29938f686a6f 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -330,7 +330,7 @@ app.on('open-url', async (_event, url) => { if (parsedUrl.hostname === 'bot' || parsedUrl.hostname === 'recipe') { console.log('[Main] Detected bot/recipe URL, creating new chat window'); let recipeDeeplink = parsedUrl.searchParams.get('config'); - if (recipeDeeplink?.includes(' ')) { + if (recipeDeeplink && !url.includes(recipeDeeplink)) { // Parse raw query to preserve "+" characters in values like config const search = parsedUrl.search || ''; // parse recipe deeplink from search params From 86b11d2b33796ec6eae6be3bf10c464005c20917 Mon Sep 17 00:00:00 2001 From: Atish Patel Date: Tue, 2 Sep 2025 17:52:33 -0500 Subject: [PATCH 3/4] Fix deeplink behavior with opening new folder --- ui/desktop/src/main.ts | 63 ++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index 29938f686a6f..98eb09050a6e 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -202,7 +202,7 @@ if (process.platform === 'win32') { const recentDirs = loadRecentDirs(); const openDir = recentDirs.length > 0 ? recentDirs[0] : null; - const recipeDeeplink = parsedUrl.searchParams.get('config'); + const recipeDeeplink = parseRecipeDeeplink(protocolUrl); const scheduledJobId = parsedUrl.searchParams.get('scheduledJob'); createChat( @@ -319,6 +319,8 @@ async function processProtocolUrl(parsedUrl: URL, window: BrowserWindow) { pendingDeepLink = null; } +let windowDeeplinkURL: string | null = null; + app.on('open-url', async (_event, url) => { if (process.platform !== 'win32') { const parsedUrl = new URL(url); @@ -329,21 +331,9 @@ app.on('open-url', async (_event, url) => { console.log('[Main] Received open-url event:', url); if (parsedUrl.hostname === 'bot' || parsedUrl.hostname === 'recipe') { console.log('[Main] Detected bot/recipe URL, creating new chat window'); - let recipeDeeplink = parsedUrl.searchParams.get('config'); - if (recipeDeeplink && !url.includes(recipeDeeplink)) { - // Parse raw query to preserve "+" characters in values like config - const search = parsedUrl.search || ''; - // parse recipe deeplink from search params - const configMatch = search.match(/(?:[?&])config=([^&]*)/); - // get recipe deeplink from config match - let recipeDeeplinkTmp = configMatch ? configMatch[1] : null; - if (recipeDeeplinkTmp) { - try { - recipeDeeplink = decodeURIComponent(recipeDeeplinkTmp); - } catch { - // Leave as-is if decoding fails - } - } + let recipeDeeplink = parseRecipeDeeplink(url); + if (recipeDeeplink) { + windowDeeplinkURL = url; } const scheduledJobId = parsedUrl.searchParams.get('scheduledJob'); @@ -1052,12 +1042,51 @@ const openDirectoryDialog = async (): Promise => { } addRecentDir(dirToAdd); + + let recipeDeeplink: string | undefined = undefined; + if (windowDeeplinkURL) { + recipeDeeplink = parseRecipeDeeplink(windowDeeplinkURL); + } // Create a new window with the selected directory - await createChat(app, undefined, dirToAdd); + await createChat( + app, + undefined, + dirToAdd, + undefined, + undefined, + undefined, + undefined, + recipeDeeplink + ); } return result; }; +function parseRecipeDeeplink(url: string): string | undefined { + const parsedUrl = new URL(url); + let recipeDeeplink = parsedUrl.searchParams.get('config'); + if (recipeDeeplink && !url.includes(recipeDeeplink)) { + // Parse raw query to preserve "+" characters in values like config + const search = parsedUrl.search || ''; + // parse recipe deeplink from search params + const configMatch = search.match(/(?:[?&])config=([^&]*)/); + // get recipe deeplink from config match + let recipeDeeplinkTmp = configMatch ? configMatch[1] : null; + if (recipeDeeplinkTmp) { + try { + recipeDeeplink = decodeURIComponent(recipeDeeplinkTmp); + } catch { + // Leave as-is if decoding fails + return undefined; + } + } + } + if (recipeDeeplink) { + return recipeDeeplink; + } + return undefined; +} + // Global error handler const handleFatalError = (error: Error) => { const windows = BrowserWindow.getAllWindows(); From 6b56aa96933fe9ad59fec1c1b733760af4c274eb Mon Sep 17 00:00:00 2001 From: Atish Patel Date: Tue, 2 Sep 2025 17:54:52 -0500 Subject: [PATCH 4/4] Add suggested comment --- ui/desktop/src/main.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index 98eb09050a6e..d76945471d1e 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -1066,6 +1066,7 @@ function parseRecipeDeeplink(url: string): string | undefined { const parsedUrl = new URL(url); let recipeDeeplink = parsedUrl.searchParams.get('config'); if (recipeDeeplink && !url.includes(recipeDeeplink)) { + // URLSearchParams decodes + as space, which can break encoded configs // Parse raw query to preserve "+" characters in values like config const search = parsedUrl.search || ''; // parse recipe deeplink from search params