Skip to content
Merged
Show file tree
Hide file tree
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
8 changes: 8 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ run-ui-only:
@echo "Running UI..."
cd ui/desktop && npm install && npm run start-gui

debug-ui:
@echo "🚀 Starting Goose frontend in external backend mode"
cd ui/desktop && \
export GOOSE_EXTERNAL_BACKEND=true && \
export GOOSE_EXTERNAL_PORT=3000 && \
npm install && \
npm run start-gui

# Run UI with alpha changes
run-ui-alpha temporal="true":
Expand Down Expand Up @@ -453,3 +460,4 @@ kotlin-example:
-Djna.library.path=$HOME/Development/goose/target/debug \
-classpath "example.jar:libs/kotlin-stdlib-1.9.0.jar:libs/kotlinx-coroutines-core-jvm-1.7.3.jar:libs/jna-5.13.0.jar" \
UsageKt

29 changes: 26 additions & 3 deletions ui/desktop/src/goosed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,30 @@ const checkServerStatus = async (
return false;
};

const connectToExternalBackend = async (
workingDir: string,
port: number = 3000
): Promise<[number, string, ChildProcess]> => {
log.info(`Using external goosed backend on port ${port}`);

const isReady = await checkServerStatus(port);
if (!isReady) {
throw new Error(`External goosed server not accessible on port ${port}`);
}

const mockProcess = {
pid: undefined,
kill: () => {
log.info(`Not killing external process that is managed externally`);
},
} as ChildProcess;

return [port, workingDir, mockProcess];
};

interface GooseProcessEnv {
[key: string]: string | undefined;

HOME: string;
USERPROFILE: string;
APPDATA: string;
Expand All @@ -75,18 +97,19 @@ export const startGoosed = async (
dir: string | null = null,
env: Partial<GooseProcessEnv> = {}
): Promise<[number, string, ChildProcess]> => {
// we default to running goosed in home dir - if not specified
const homeDir = os.homedir();
const isWindows = process.platform === 'win32';

// Ensure dir is properly normalized for the platform and validate it
if (!dir) {
dir = homeDir;
}

// Sanitize and validate the directory path
dir = path.resolve(path.normalize(dir));

if (process.env.GOOSE_EXTERNAL_BACKEND) {
return connectToExternalBackend(dir, 3000);
}

// Validate that the directory actually exists and is a directory
try {
const stats = fs.lstatSync(dir);
Expand Down
4 changes: 2 additions & 2 deletions ui/desktop/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ const getGooseProvider = () => {
};

const generateSecretKey = () => {
const key = crypto.randomBytes(32).toString('hex');
const key = process.env.GOOSE_EXTERNAL_BACKEND ? 'test' : crypto.randomBytes(32).toString('hex');
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe here you could just check if GOOSE_SERVER__SECRET_KEY is already set, and if so, use that instead of generating one. Then in the Justfile set it

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes, but then you put the burden on the user to set that in their RustRover started backend to the same value - that thing currently sets it to test, so this is lower maintaince maybe?

process.env.GOOSE_SERVER__SECRET_KEY = key;
return key;
};
Expand Down Expand Up @@ -2066,7 +2066,7 @@ app.whenReady().then(async () => {
command: uvx mcp_slack
- id: knowledge_graph_memory
command: npx -y @modelcontextprotocol/server-memory
```
```
Copy link
Collaborator

Choose a reason for hiding this comment

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

You probably didnt' mean to remove this leading whitespace

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

hmm, that's weird, it looks like my autoformatter is doing that

*
* @returns A promise that resolves to an array of extension commands that are allowed.
*/
Expand Down
Loading