shave and code split (#4630)

This commit is contained in:
Jack Amadeo
2025-09-24 13:42:19 -04:00
committed by GitHub
parent 5acaca4301
commit ad045bc94c
8 changed files with 26 additions and 79 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ import type { View } from '../utils/navigationUtils';
import Stop from './ui/Stop'; import Stop from './ui/Stop';
import { Attach, Send, Close, Microphone } from './icons'; import { Attach, Send, Close, Microphone } from './icons';
import { ChatState } from '../types/chatState'; import { ChatState } from '../types/chatState';
import { debounce } from 'lodash'; import debounce from 'lodash/debounce';
import { LocalMessageStorage } from '../utils/localMessageStorage'; import { LocalMessageStorage } from '../utils/localMessageStorage';
import { Message } from '../types/message'; import { Message } from '../types/message';
import { DirSwitcher } from './bottom_menu/DirSwitcher'; import { DirSwitcher } from './bottom_menu/DirSwitcher';
@@ -1,7 +1,7 @@
import React, { useEffect, useState, useRef, KeyboardEvent } from 'react'; import React, { useEffect, useState, useRef, KeyboardEvent } from 'react';
import { Search as SearchIcon } from 'lucide-react'; import { Search as SearchIcon } from 'lucide-react';
import { ArrowDown, ArrowUp, Close } from '../icons'; import { ArrowDown, ArrowUp, Close } from '../icons';
import { debounce } from 'lodash'; import debounce from 'lodash/debounce';
import { Button } from '../ui/button'; import { Button } from '../ui/button';
/** /**
@@ -1,7 +1,7 @@
import React, { useState, useEffect, PropsWithChildren, useCallback, useRef } from 'react'; import React, { useState, useEffect, PropsWithChildren, useCallback, useRef } from 'react';
import SearchBar from './SearchBar'; import SearchBar from './SearchBar';
import { SearchHighlighter } from '../../utils/searchHighlighter'; import { SearchHighlighter } from '../../utils/searchHighlighter';
import { debounce } from 'lodash'; import debounce from 'lodash/debounce';
import '../../styles/search.css'; import '../../styles/search.css';
/** /**
-57
View File
@@ -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 (
<h1 className={className} key={forceRefresh ? Date.now() : undefined}>
<span>{greeting.prefix}</span>
<span className="text-text-muted" ref={messageRef}>
{greeting.message}
</span>
</h1>
);
}
+1 -12
View File
@@ -28,7 +28,7 @@ export const findAvailablePort = (): Promise<number> => {
// Goose process manager. Take in the app, port, and directory to start goosed in. // 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 // Check if goosed server is ready by polling the status endpoint
const checkServerStatus = async (): Promise<boolean> => { export const checkServerStatus = async (): Promise<boolean> => {
const interval = 100; const interval = 100;
const maxAttempts = 200; const maxAttempts = 200;
for (let attempt = 1; attempt <= maxAttempts; attempt++) { 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 = () => { const try_kill_goose = () => {
try { try {
if (isWindows) { 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 // Ensure goosed is terminated when the app quits
// TODO will need to do it at tab level next
app.on('will-quit', () => { app.on('will-quit', () => {
log.info('App quitting, terminating goosed server'); log.info('App quitting, terminating goosed server');
try_kill_goose(); try_kill_goose();
+12 -6
View File
@@ -23,7 +23,7 @@ import path from 'node:path';
import os from 'node:os'; import os from 'node:os';
import { spawn } from 'child_process'; import { spawn } from 'child_process';
import 'dotenv/config'; import 'dotenv/config';
import { startGoosed } from './goosed'; import { checkServerStatus, startGoosed } from './goosed';
import { expandTilde, getBinaryPath } from './utils/pathUtils'; import { expandTilde, getBinaryPath } from './utils/pathUtils';
import log from './utils/logger'; import log from './utils/logger';
import { ensureWinShims } from './utils/winShims'; import { ensureWinShims } from './utils/winShims';
@@ -51,6 +51,7 @@ import { UPDATES_ENABLED } from './updates';
import { Recipe } from './recipe'; import { Recipe } from './recipe';
import './utils/recipeHash'; import './utils/recipeHash';
import { decodeRecipe } from './api/sdk.gen'; import { decodeRecipe } from './api/sdk.gen';
import { client } from './api/client.gen';
async function decodeRecipeMain(deeplink: string): Promise<Recipe | null> { async function decodeRecipeMain(deeplink: string): Promise<Recipe | null> {
try { try {
@@ -697,7 +698,7 @@ const createChat = async (
// Goose's react app uses HashRouter, so the path + search params follow a #/ // Goose's react app uses HashRouter, so the path + search params follow a #/
url.hash = `${appPath}?${searchParams.toString()}`; url.hash = `${appPath}?${searchParams.toString()}`;
let formattedUrl = formatUrl(url); let formattedUrl = formatUrl(url);
console.log('Opening URL: ', formattedUrl); log.info('Opening URL: ', formattedUrl);
mainWindow.loadURL(formattedUrl); mainWindow.loadURL(formattedUrl);
// Set up local keyboard shortcuts that only work when the window is focused // 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', () => { ipcMain.on('react-ready', () => {
console.log('React ready event received'); log.info('React ready event received');
if (pendingDeepLink) { if (pendingDeepLink) {
console.log('Processing pending deep link:', pendingDeepLink); log.info('Processing pending deep link:', pendingDeepLink);
handleProtocolUrl(pendingDeepLink); handleProtocolUrl(pendingDeepLink);
} else { } 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 // We don't need to handle pending deep links here anymore
// since we're handling them in the window creation flow // 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 // Handle external URL opening
@@ -1060,6 +1061,11 @@ ipcMain.handle('get-secret-key', () => {
return SERVER_SECRET; 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) => { ipcMain.handle('set-scheduling-engine', async (_event, engine: string) => {
try { try {
const settings = loadSettings(); const settings = loadSettings();
+2
View File
@@ -78,6 +78,7 @@ type ElectronAPI = {
getDockIconState: () => Promise<boolean>; getDockIconState: () => Promise<boolean>;
getSettings: () => Promise<unknown | null>; getSettings: () => Promise<unknown | null>;
getSecretKey: () => Promise<string>; getSecretKey: () => Promise<string>;
getGoosedHostPort: () => Promise<string | null>;
setSchedulingEngine: (engine: string) => Promise<boolean>; setSchedulingEngine: (engine: string) => Promise<boolean>;
setWakelock: (enable: boolean) => Promise<boolean>; setWakelock: (enable: boolean) => Promise<boolean>;
getWakelockState: () => Promise<boolean>; getWakelockState: () => Promise<boolean>;
@@ -168,6 +169,7 @@ const electronAPI: ElectronAPI = {
getDockIconState: () => ipcRenderer.invoke('get-dock-icon-state'), getDockIconState: () => ipcRenderer.invoke('get-dock-icon-state'),
getSettings: () => ipcRenderer.invoke('get-settings'), getSettings: () => ipcRenderer.invoke('get-settings'),
getSecretKey: () => ipcRenderer.invoke('get-secret-key'), getSecretKey: () => ipcRenderer.invoke('get-secret-key'),
getGoosedHostPort: () => ipcRenderer.invoke('get-goosed-host-port'),
setSchedulingEngine: (engine: string) => ipcRenderer.invoke('set-scheduling-engine', engine), setSchedulingEngine: (engine: string) => ipcRenderer.invoke('set-scheduling-engine', engine),
setWakelock: (enable: boolean) => ipcRenderer.invoke('set-wakelock', enable), setWakelock: (enable: boolean) => ipcRenderer.invoke('set-wakelock', enable),
getWakelockState: () => ipcRenderer.invoke('get-wakelock-state'), getWakelockState: () => ipcRenderer.invoke('get-wakelock-state'),
+8 -1
View File
@@ -8,8 +8,15 @@ import { client } from './api/client.gen';
const App = lazy(() => import('./App')); const App = lazy(() => import('./App'));
(async () => { (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({ client.setConfig({
baseUrl: window.appConfig.get('GOOSE_API_HOST') + ':' + window.appConfig.get('GOOSE_PORT'), baseUrl,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Secret-Key': await window.electron.getSecretKey(), 'X-Secret-Key': await window.electron.getSecretKey(),