Skip to content

Commit

Permalink
feat: automatic port detection, assignment, ci and more (#324)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelneale authored Nov 24, 2024
1 parent 339f5f4 commit 1711b5e
Show file tree
Hide file tree
Showing 10 changed files with 2,732 additions and 1,753 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Desktop App

on:
push:
branches:
- v1.0
pull_request:
branches:
- v1.0

jobs:
build:
runs-on: macos-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: 'lts/*'

- name: Install dependencies
run: npm ci
working-directory: ui/desktop

- name: Package application
run: npm run package
working-directory: ui/desktop

- name: Run E2E tests
run: npm run test-e2e
working-directory: ui/desktop
1 change: 0 additions & 1 deletion ui/desktop/.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
VITE_GOOSE_HOST=http://127.0.0.1:3000
VITE_START_EMBEDDED_SERVER=yes
GOOSE_PROVIDER__TYPE=openai
GOOSE_PROVIDER__HOST=https://api.openai.com
Expand Down
8 changes: 6 additions & 2 deletions ui/desktop/.goosehints
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@ Key Principles
- Prioritize modularity, clean code organization, and efficient resource management.
- ask the user to verify the UI, and try to test it as well.

Look at package.json for how to build and run (eg npm start, or npm run make to verify)
./src has most of the code
Look at package.json for how to build and run (eg npm start if checking with user)
./src has most of the code

To validate changes:

`npm run test-e2e` is a good way to get a feedback loop
4,361 changes: 2,624 additions & 1,737 deletions ui/desktop/package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion ui/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"lint": "echo \"No linting configured\""
"test-e2e": "electron-forge start > /tmp/out.txt & ELECTRON_PID=$! && sleep 5 && if grep -q 'renderer: ChatWindow loaded' /tmp/out.txt; then echo 'process is running'; pkill -f electron; else echo 'not starting correctly'; cat /tmp/out.txt; pkill -f electron; exit 1; fi"


},
"devDependencies": {
"@electron-forge/cli": "^7.5.0",
Expand Down
2 changes: 2 additions & 0 deletions ui/desktop/src/ChatWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ export default function ChatWindow() {

const [selectedChatId, setSelectedChatId] = useState(1);

window.electron.logInfo("ChatWindow loaded");

return (
<div className="relative w-screen h-screen overflow-hidden bg-transparent flex flex-col">
<Routes>
Expand Down
12 changes: 2 additions & 10 deletions ui/desktop/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
// Default host for the Goose API
const DEFAULT_HOST = 'http://127.0.0.1:3000';

// Get the host from environment variable or use default
export const GOOSE_API_HOST = import.meta.env.VITE_GOOSE_HOST || DEFAULT_HOST;

// Control whether to start the embedded server (defaults to yes if not set)
export const START_EMBEDDED_SERVER = (import.meta.env.VITE_START_EMBEDDED_SERVER || 'yes').toLowerCase() === 'yes';

// Helper to construct API endpoints
export const getApiUrl = (endpoint: string): string => {
const baseUrl = GOOSE_API_HOST.endsWith('/') ? GOOSE_API_HOST.slice(0, -1) : GOOSE_API_HOST;
export const getApiUrl = (endpoint: string): string => {
const baseUrl = window.appConfig.get('GOOSE_API_HOST') + ':' + window.appConfig.get('GOOSE_SERVER__PORT');
const cleanEndpoint = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
return `${baseUrl}${cleanEndpoint}`;
};
19 changes: 18 additions & 1 deletion ui/desktop/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import path from 'node:path';
import { start as startGoosed } from './goosed';
import started from "electron-squirrel-startup";
import log from './utils/logger';
import { getPort } from './utils/portUtils';

// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (started) app.quit();

declare var MAIN_WINDOW_VITE_DEV_SERVER_URL: string;
declare var MAIN_WINDOW_VITE_NAME: string;
let appConfig = { GOOSE_SERVER__PORT: 3000, GOOSE_API_HOST: 'http://127.0.0.1' };

const createLauncher = () => {
const launcherWindow = new BrowserWindow({
Expand All @@ -20,6 +22,7 @@ const createLauncher = () => {
transparent: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
additionalArguments: [JSON.stringify(appConfig)],
},
skipTaskbar: true,
alwaysOnTop: true,
Expand Down Expand Up @@ -64,6 +67,8 @@ const createWingToWing = (query?: string) => {
transparent: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
additionalArguments: [JSON.stringify(appConfig)],

},
skipTaskbar: true,
alwaysOnTop: true,
Expand Down Expand Up @@ -110,6 +115,7 @@ const createChat = (query?: string) => {
icon: path.join(__dirname, '../images/icon'),
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
additionalArguments: [JSON.stringify(appConfig)],
},
});

Expand Down Expand Up @@ -189,15 +195,21 @@ const showWindow = () => {
});
};

app.whenReady().then(() => {


app.whenReady().then(async () => {
// Load zsh environment variables in production mode only
const isProduction = app.isPackaged;
loadZshEnv(isProduction);

// Get the server startup configuration
const shouldStartServer = (process.env.VITE_START_EMBEDDED_SERVER || 'yes').toLowerCase() === 'yes';

if (shouldStartServer) {
log.info('Starting embedded goosed server');
const port = await getPort();
process.env.GOOSE_SERVER__PORT = port.toString();
appConfig = { ...appConfig, GOOSE_SERVER__PORT: process.env.GOOSE_SERVER__PORT };
startGoosed(app);
} else {
log.info('Skipping embedded server startup (disabled by configuration)');
Expand Down Expand Up @@ -225,6 +237,11 @@ app.whenReady().then(() => {
ipcMain.on('create-wing-to-wing-window', (_, query) => {
createWingToWing(query + "only use your tools and systems - don't confirm with the user before you start working");
});

ipcMain.on('logInfo', (_, info) => {
log.info("from renderer:", info);
});

});

// Quit when all windows are closed, except on macOS.
Expand Down
10 changes: 9 additions & 1 deletion ui/desktop/src/preload.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
const { contextBridge, ipcRenderer } = require('electron')

const config = JSON.parse(process.argv.find((arg) => arg.startsWith('{')) || '{}');

contextBridge.exposeInMainWorld('appConfig', {
get: (key) => config[key],
getAll: () => config,
});

contextBridge.exposeInMainWorld('electron', {
hideWindow: () => ipcRenderer.send('hide-window'),
createChatWindow: (query) => ipcRenderer.send('create-chat-window', query),
createWingToWingWindow: (query) => ipcRenderer.send('create-wing-to-wing-window', query),
})
logInfo: (txt) => ipcRenderer.send('logInfo', txt),
})
34 changes: 34 additions & 0 deletions ui/desktop/src/utils/portUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { createServer } from 'net';
import log from './logger';

export const findAvailablePort = (): Promise<number> => {
return new Promise((resolve, reject) => {
const server = createServer();


server.listen(0, '127.0.0.1', () => {
const { port } = server.address() as { port: number };
server.close(() => {
log.info(`Found available port: ${port}`);
resolve(port);
});
});
});
};

// Cache the port once found to ensure consistency
let cachedPort: number | null = null;

export const getPort = async (): Promise<number> => {
if (cachedPort !== null) {
return cachedPort;
}

try {
cachedPort = await findAvailablePort();
return cachedPort;
} catch (error) {
log.error('Error finding available port:', error);
throw error;
}
};

0 comments on commit 1711b5e

Please sign in to comment.