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 { 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';
@@ -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';
/**
@@ -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';
/**
-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.
// 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 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();
+12 -6
View File
@@ -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<Recipe | null> {
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();
+2
View File
@@ -78,6 +78,7 @@ type ElectronAPI = {
getDockIconState: () => Promise<boolean>;
getSettings: () => Promise<unknown | null>;
getSecretKey: () => Promise<string>;
getGoosedHostPort: () => Promise<string | null>;
setSchedulingEngine: (engine: string) => Promise<boolean>;
setWakelock: (enable: boolean) => Promise<boolean>;
getWakelockState: () => Promise<boolean>;
@@ -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'),
+8 -1
View File
@@ -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(),