Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions ui/desktop/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
// Apply single instance lock on Windows and Linux where it's needed for deep links
// macOS uses the 'open-url' event instead
let gotTheLock = true;
let openUrlHandledLaunch = false;
if (process.platform !== 'darwin') {
gotTheLock = app.requestSingleInstanceLock();

Expand Down Expand Up @@ -430,7 +431,7 @@ if (process.platform !== 'darwin') {
}

// For non-bot URLs, continue with normal handling
handleProtocolUrl(protocolUrl);
handleProtocolUrl(protocolUrl, parsedUrl);
}

// Only focus existing windows for non-bot/recipe URLs
Expand All @@ -448,14 +449,30 @@ if (process.platform !== 'darwin') {
// Handle protocol URLs on Windows and Linux startup
const protocolUrl = process.argv.find((arg) => arg.startsWith('goose://'));
if (protocolUrl) {
app.whenReady().then(() => {
handleProtocolUrl(protocolUrl);
app.whenReady().then(async () => {
let parsedUrl: URL;
try {
parsedUrl = new URL(protocolUrl);
} catch (error) {
log.warn('[Main] Ignoring invalid startup protocol URL:', errorMessage(error));
return;
}

openUrlHandledLaunch = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Only mark startup deep links handled after resume succeeds

For Windows/Linux cold starts with a parseable but invalid resume URL such as goose://resume or goose://resume/%ZZ, this sets openUrlHandledLaunch before handleProtocolUrl calls createResumeChatWindow, which returns false without throwing when no session id can be extracted. Because no window is created and appMain later skips its fallback window, the app can start with no visible window; use the resume handler's success result (as the macOS path does) or fall back when it returns false.

Useful? React with 👍 / 👎.

try {
await handleProtocolUrl(protocolUrl, parsedUrl);
} catch (error) {
log.error('[Main] Failed to handle startup protocol URL:', errorMessage(error));
if (BrowserWindow.getAllWindows().length === 0) {
const { dirPath } = parseArgs();
await createNewWindow(app, dirPath);
}
}
});
}
}

const pendingDeepLinks = new Map<number, string>(); // windowId -> deep link URL
let openUrlHandledLaunch = false;

function getResumeSessionId(parsedUrl: URL): string | null {
try {
Expand All @@ -477,10 +494,9 @@ async function createResumeChatWindow(parsedUrl: URL, dir?: string): Promise<boo
return true;
}

async function handleProtocolUrl(url: string) {
async function handleProtocolUrl(url: string, parsedUrl: URL) {
if (!url) return;

const parsedUrl = new URL(url);
const recentDirs = loadRecentDirs();
const openDir = recentDirs.length > 0 ? recentDirs[0] : null;

Expand Down