From ad045bc94c2ead086144f0686982594dcc461c9b Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Wed, 24 Sep 2025 13:42:19 -0400 Subject: [PATCH] shave and code split (#4630) --- ui/desktop/src/components/ChatInput.tsx | 2 +- .../src/components/conversation/SearchBar.tsx | 2 +- .../components/conversation/SearchView.tsx | 2 +- ui/desktop/src/components/ui/Greeting.tsx | 57 ------------------- ui/desktop/src/goosed.ts | 13 +---- ui/desktop/src/main.ts | 18 ++++-- ui/desktop/src/preload.ts | 2 + ui/desktop/src/renderer.tsx | 9 ++- 8 files changed, 26 insertions(+), 79 deletions(-) delete mode 100644 ui/desktop/src/components/ui/Greeting.tsx diff --git a/ui/desktop/src/components/ChatInput.tsx b/ui/desktop/src/components/ChatInput.tsx index 60d8982c..b19c32be 100644 --- a/ui/desktop/src/components/ChatInput.tsx +++ b/ui/desktop/src/components/ChatInput.tsx @@ -6,7 +6,7 @@ import type { View } from '../utils/navigationUtils'; import Stop from './ui/Stop'; import { Attach, Send, Close, Microphone } from './icons'; import { ChatState } from '../types/chatState'; -import { debounce } from 'lodash'; +import debounce from 'lodash/debounce'; import { LocalMessageStorage } from '../utils/localMessageStorage'; import { Message } from '../types/message'; import { DirSwitcher } from './bottom_menu/DirSwitcher'; diff --git a/ui/desktop/src/components/conversation/SearchBar.tsx b/ui/desktop/src/components/conversation/SearchBar.tsx index 756c55f7..db83442d 100644 --- a/ui/desktop/src/components/conversation/SearchBar.tsx +++ b/ui/desktop/src/components/conversation/SearchBar.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState, useRef, KeyboardEvent } from 'react'; import { Search as SearchIcon } from 'lucide-react'; import { ArrowDown, ArrowUp, Close } from '../icons'; -import { debounce } from 'lodash'; +import debounce from 'lodash/debounce'; import { Button } from '../ui/button'; /** diff --git a/ui/desktop/src/components/conversation/SearchView.tsx b/ui/desktop/src/components/conversation/SearchView.tsx index b2d35f77..051ee0a5 100644 --- a/ui/desktop/src/components/conversation/SearchView.tsx +++ b/ui/desktop/src/components/conversation/SearchView.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, PropsWithChildren, useCallback, useRef } from 'react'; import SearchBar from './SearchBar'; import { SearchHighlighter } from '../../utils/searchHighlighter'; -import { debounce } from 'lodash'; +import debounce from 'lodash/debounce'; import '../../styles/search.css'; /** diff --git a/ui/desktop/src/components/ui/Greeting.tsx b/ui/desktop/src/components/ui/Greeting.tsx deleted file mode 100644 index c117c842..00000000 --- a/ui/desktop/src/components/ui/Greeting.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { useState } from 'react'; -import { useTextAnimator } from '../../hooks/use-text-animator'; - -interface GreetingProps { - className?: string; - forceRefresh?: boolean; -} - -export function Greeting({ - className = 'mb-12 mt-8 text-4xl font-light animate-in fade-in slide-in-from-right-8 duration-300', - forceRefresh = false, -}: GreetingProps) { - const prefixes = ['Hello.', 'Welcome.', 'Greetings.', 'Welcome back.', 'Hello there.']; - const messages = [ - ' Ready to get started?', - ' What would you like to work on?', - ' Ready to build something amazing?', - ' What would you like to explore?', - " What's on your mind?", - ' What shall we create today?', - ' What project needs attention?', - ' What would you like to tackle?', - ' What would you like to explore?', - ' What needs to be done?', - " What's the plan for today?", - ' Ready to create something great?', - ' What can be built today?', - " What's the next challenge?", - ' What progress can be made?', - ' What would you like to accomplish?', - ' What task awaits?', - " What's the mission today?", - ' What can be achieved?', - ' What project is ready to begin?', - ]; - - const greeting = useState(() => { - const randomPrefixIndex = Math.floor(Math.random() * prefixes.length); - const randomMessageIndex = Math.floor(Math.random() * messages.length); - - return { - prefix: prefixes[randomPrefixIndex], - message: messages[randomMessageIndex], - }; - })[0]; - - const messageRef = useTextAnimator({ text: greeting.message }); - - return ( -

- {greeting.prefix} - - {greeting.message} - -

- ); -} diff --git a/ui/desktop/src/goosed.ts b/ui/desktop/src/goosed.ts index acdb6188..6cff75f4 100644 --- a/ui/desktop/src/goosed.ts +++ b/ui/desktop/src/goosed.ts @@ -28,7 +28,7 @@ export const findAvailablePort = (): Promise => { // Goose process manager. Take in the app, port, and directory to start goosed in. // Check if goosed server is ready by polling the status endpoint -const checkServerStatus = async (): Promise => { +export const checkServerStatus = async (): Promise => { const interval = 100; const maxAttempts = 200; for (let attempt = 1; attempt <= maxAttempts; attempt++) { @@ -270,10 +270,6 @@ export const startGoosed = async ( }, }); - // Wait for the server to be ready - const isReady = await checkServerStatus(); - log.info(`Goosed isReady ${isReady}`); - const try_kill_goose = () => { try { if (isWindows) { @@ -287,14 +283,7 @@ export const startGoosed = async ( } }; - if (!isReady) { - log.error(`Goosed server failed to start on port ${port}`); - try_kill_goose(); - throw new Error(`Goosed server failed to start on port ${port}`); - } - // Ensure goosed is terminated when the app quits - // TODO will need to do it at tab level next app.on('will-quit', () => { log.info('App quitting, terminating goosed server'); try_kill_goose(); diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index dacbb22b..9ebba638 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -23,7 +23,7 @@ import path from 'node:path'; import os from 'node:os'; import { spawn } from 'child_process'; import 'dotenv/config'; -import { startGoosed } from './goosed'; +import { checkServerStatus, startGoosed } from './goosed'; import { expandTilde, getBinaryPath } from './utils/pathUtils'; import log from './utils/logger'; import { ensureWinShims } from './utils/winShims'; @@ -51,6 +51,7 @@ import { UPDATES_ENABLED } from './updates'; import { Recipe } from './recipe'; import './utils/recipeHash'; import { decodeRecipe } from './api/sdk.gen'; +import { client } from './api/client.gen'; async function decodeRecipeMain(deeplink: string): Promise { try { @@ -697,7 +698,7 @@ const createChat = async ( // Goose's react app uses HashRouter, so the path + search params follow a #/ url.hash = `${appPath}?${searchParams.toString()}`; let formattedUrl = formatUrl(url); - console.log('Opening URL: ', formattedUrl); + log.info('Opening URL: ', formattedUrl); mainWindow.loadURL(formattedUrl); // Set up local keyboard shortcuts that only work when the window is focused @@ -1016,18 +1017,18 @@ process.on('unhandledRejection', (error) => { }); ipcMain.on('react-ready', () => { - console.log('React ready event received'); + log.info('React ready event received'); if (pendingDeepLink) { - console.log('Processing pending deep link:', pendingDeepLink); + log.info('Processing pending deep link:', pendingDeepLink); handleProtocolUrl(pendingDeepLink); } else { - console.log('No pending deep link to process'); + log.info('No pending deep link to process'); } // We don't need to handle pending deep links here anymore // since we're handling them in the window creation flow - console.log('[main] React ready - window is prepared for deep links'); + log.info('React ready - window is prepared for deep links'); }); // Handle external URL opening @@ -1060,6 +1061,11 @@ ipcMain.handle('get-secret-key', () => { return SERVER_SECRET; }); +ipcMain.handle('get-goosed-host-port', async () => { + await checkServerStatus(); + return client.getConfig().baseUrl || null; +}); + ipcMain.handle('set-scheduling-engine', async (_event, engine: string) => { try { const settings = loadSettings(); diff --git a/ui/desktop/src/preload.ts b/ui/desktop/src/preload.ts index b6ce7a9d..50fceda3 100644 --- a/ui/desktop/src/preload.ts +++ b/ui/desktop/src/preload.ts @@ -78,6 +78,7 @@ type ElectronAPI = { getDockIconState: () => Promise; getSettings: () => Promise; getSecretKey: () => Promise; + getGoosedHostPort: () => Promise; setSchedulingEngine: (engine: string) => Promise; setWakelock: (enable: boolean) => Promise; getWakelockState: () => Promise; @@ -168,6 +169,7 @@ const electronAPI: ElectronAPI = { getDockIconState: () => ipcRenderer.invoke('get-dock-icon-state'), getSettings: () => ipcRenderer.invoke('get-settings'), getSecretKey: () => ipcRenderer.invoke('get-secret-key'), + getGoosedHostPort: () => ipcRenderer.invoke('get-goosed-host-port'), setSchedulingEngine: (engine: string) => ipcRenderer.invoke('set-scheduling-engine', engine), setWakelock: (enable: boolean) => ipcRenderer.invoke('set-wakelock', enable), getWakelockState: () => ipcRenderer.invoke('get-wakelock-state'), diff --git a/ui/desktop/src/renderer.tsx b/ui/desktop/src/renderer.tsx index 75047dc9..067e1495 100644 --- a/ui/desktop/src/renderer.tsx +++ b/ui/desktop/src/renderer.tsx @@ -8,8 +8,15 @@ import { client } from './api/client.gen'; const App = lazy(() => import('./App')); (async () => { + console.log('window created, getting goosed connection info'); + const baseUrl = await window.electron.getGoosedHostPort(); + if (baseUrl === null) { + window.alert('failed to start goose backend process'); + return; + } + console.log('connecting at', baseUrl); client.setConfig({ - baseUrl: window.appConfig.get('GOOSE_API_HOST') + ':' + window.appConfig.get('GOOSE_PORT'), + baseUrl, headers: { 'Content-Type': 'application/json', 'X-Secret-Key': await window.electron.getSecretKey(),