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
32 changes: 15 additions & 17 deletions ui/desktop/src/components/settings/app/ExternalBackendSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Switch } from '../../ui/switch';
import { Input } from '../../ui/input';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../../ui/card';
import { AlertCircle } from 'lucide-react';
import { ExternalGoosedConfig, defaultSettings } from '../../../utils/settings';
import { ExternalBackendConfig, defaultSettings } from '../../../utils/settings';
import { defineMessages, useIntl } from '../../../i18n';
import { normalizeAcpHttpBaseUrl } from '../../../acp/url';

Expand Down Expand Up @@ -56,12 +56,12 @@ const i18n = defineMessages({
},
certFingerprintHelp: {
id: 'externalBackendSection.certFingerprintHelp',
defaultMessage: 'Pin a specific TLS certificate fingerprint. If omitted, the certificate is trusted on first use (TOFU).',
defaultMessage:
'Pin a specific TLS certificate fingerprint. If omitted, the certificate is trusted on first use (TOFU).',
},
restartNote: {
id: 'externalBackendSection.restartNote',
defaultMessage:
'Changes apply to new chat windows. Restart Goose to update existing windows.',
defaultMessage: 'Changes apply to new chat windows. Restart Goose to update existing windows.',
},
urlProtocolError: {
id: 'externalBackendSection.urlProtocolError',
Expand All @@ -77,13 +77,14 @@ const i18n = defineMessages({
},
urlBaseError: {
id: 'externalBackendSection.urlBaseError',
defaultMessage: 'URL must be the backend base URL before /acp, without query parameters or fragments',
defaultMessage:
'URL must be the backend base URL before /acp, without query parameters or fragments',
},
});

export default function ExternalBackendSection() {
const intl = useIntl();
const [config, setConfig] = useState<ExternalGoosedConfig>(defaultSettings.externalGoosed);
const [config, setConfig] = useState<ExternalBackendConfig>(defaultSettings.externalGoosed);
const [isSaving, setIsSaving] = useState(false);
const [urlError, setUrlError] = useState<string | null>(null);

Expand All @@ -95,10 +96,7 @@ export default function ExternalBackendSection() {
loadSettings();
}, []);

const validateUrl = (
value: string,
certFingerprint = config.certFingerprint
): boolean => {
const validateUrl = (value: string, certFingerprint = config.certFingerprint): boolean => {
if (!value) {
setUrlError(null);
return true;
Expand Down Expand Up @@ -128,7 +126,7 @@ export default function ExternalBackendSection() {
}
};

const saveConfig = async (newConfig: ExternalGoosedConfig): Promise<void> => {
const saveConfig = async (newConfig: ExternalBackendConfig): Promise<void> => {
setIsSaving(true);
try {
await window.electron.setSetting('externalGoosed', newConfig);
Expand All @@ -139,9 +137,9 @@ export default function ExternalBackendSection() {
}
};

const updateField = <K extends keyof ExternalGoosedConfig>(
const updateField = <K extends keyof ExternalBackendConfig>(
field: K,
value: ExternalGoosedConfig[K]
value: ExternalBackendConfig[K]
) => {
const newConfig = { ...config, [field]: value };
setConfig(newConfig);
Expand Down Expand Up @@ -175,14 +173,14 @@ export default function ExternalBackendSection() {
<Card className="pb-2">
<CardHeader className="pb-0">
<CardTitle>{intl.formatMessage(i18n.title)}</CardTitle>
<CardDescription>
{intl.formatMessage(i18n.description)}
</CardDescription>
<CardDescription>{intl.formatMessage(i18n.description)}</CardDescription>
</CardHeader>
<CardContent className="pt-4 space-y-4 px-4">
<div className="flex items-center justify-between">
<div>
<h3 className="text-text-primary text-xs">{intl.formatMessage(i18n.useExternalServer)}</h3>
<h3 className="text-text-primary text-xs">
{intl.formatMessage(i18n.useExternalServer)}
</h3>
<p className="text-xs text-text-secondary max-w-md mt-[2px]">
{intl.formatMessage(i18n.useExternalServerDescription)}
</p>
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "Geheimer Schlüssel"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "Der auf dem goosed-Server konfigurierte geheime Schlüssel (GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "Der auf dem Goose-Server konfigurierte geheime Schlüssel (GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "Geben Sie den geheimen Schlüssel des Servers ein"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "Secret Key"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "La secret key configurada en el servidor goosed (GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "La clave secreta configurada en el servidor Goose (GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "Introduce la secret key del servidor"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "Clé secrète"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "La clé secrète configurée sur le serveur goosed (GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "La clé secrète configurée sur le serveur Goose (GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "Saisissez la clé secrète du serveur"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/id.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "Kunci Rahasia"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "Kunci rahasia yang dikonfigurasi pada server goosed (GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "Kunci rahasia yang dikonfigurasi pada server Goose (GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "Masukkan kunci rahasia server"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "Chiave segreta"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "La chiave segreta configurata sul server goosed (GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "La chiave segreta configurata sul server Goose (GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "Inserisci la chiave segreta del server"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "シークレットキー"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "goosed サーバーに設定されたシークレットキー(GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "Goose サーバーに設定されたシークレットキー(GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "サーバーのシークレットキーを入力"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "비밀 키"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "goosed 서버에 설정된 비밀 키 (GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "Goose 서버에 설정된 비밀 키 (GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "서버의 비밀 키를 입력하세요"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/ms.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "Kunci Rahsia"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "Kunci rahsia yang dikonfigurasikan pada pelayan goosed (GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "Kunci rahsia yang dikonfigurasikan pada pelayan Goose (GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "Masukkan kunci rahsia pelayan"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "Chave secreta"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "A chave secreta configurada no servidor goosed (GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "A chave secreta configurada no servidor Goose (GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "Insira a chave secreta do servidor"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "Секретный ключ"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "Секретный ключ, настроенный на сервере goosed (GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "Секретный ключ, настроенный на сервере Goose (GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "Введите секретный ключ сервера"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/tr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "Gizli Anahtar"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "goosed sunucusunda yapılandırılan gizli anahtar (GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "Goose sunucusunda yapılandırılan gizli anahtar (GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "Sunucunun gizli anahtarını girin"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/vi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "Khóa bí mật"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "Khóa bí mật được cấu hình trên máy chủ goosed (GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "Khóa bí mật được cấu hình trên máy chủ Goose (GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "Nhập khóa bí mật của máy chủ"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "密钥"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "在 goosed 服务器上配置的密钥(GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "在 Goose 服务器上配置的密钥(GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "输入服务器的密钥"
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/i18n/messages/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@
"defaultMessage": "密鑰"
},
"externalBackendSection.secretKeyHelp": {
"defaultMessage": "在 goosed 伺服器上設定的密鑰 (GOOSE_SERVER__SECRET_KEY)"
"defaultMessage": "在 Goose 伺服器上設定的密鑰 (GOOSE_SERVER__SECRET_KEY)"
},
"externalBackendSection.secretKeyPlaceholder": {
"defaultMessage": "輸入伺服器的密鑰"
Expand Down
32 changes: 1 addition & 31 deletions ui/desktop/src/startupDiagnostics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { afterEach, describe, expect, it } from 'vitest';
import { createGooseServeStartupDiagnostics, createStartupDiagnostics } from './startupDiagnostics';
import { createGooseServeStartupDiagnostics } from './startupDiagnostics';

const tempDirs: string[] = [];

Expand All @@ -22,36 +22,6 @@ describe('startup diagnostics', () => {
}
});

it('keeps goosed startup diagnostics shape and file prefix', () => {
const diagnosticsDir = makeTempDir();
const trace = createStartupDiagnostics(diagnosticsDir, '/tmp/project');
const expectedKeys = [
'attemptId',
'startedAt',
'goosedPath',
'workingDir',
'baseUrl',
'pid',
'certFingerprintSeen',
'healthCheckSucceeded',
'childExitCode',
'childExitSignal',
'stderrTail',
'events',
];

expect(trace).not.toBeNull();
expect(path.basename(trace!.diagnosticsPath)).toMatch(/^goosed-startup-.*\.json$/);
expect(Object.keys(trace!.diagnostics)).toEqual(expectedKeys);
expect(trace!.diagnostics).toMatchObject({
goosedPath: null,
baseUrl: null,
certFingerprintSeen: false,
});
const saved = JSON.parse(fs.readFileSync(trace!.diagnosticsPath, 'utf8'));
expect(Object.keys(saved)).toEqual(expectedKeys);
});

it('writes serve startup diagnostics with serve-specific fields', () => {
const diagnosticsDir = makeTempDir();
const trace = createGooseServeStartupDiagnostics(diagnosticsDir, '/tmp/project');
Expand Down
100 changes: 0 additions & 100 deletions ui/desktop/src/startupDiagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,6 @@ export interface StartupTraceEvent {
details?: Record<string, unknown>;
}

export interface StartupDiagnostics {
attemptId: string;
startedAt: string;
goosedPath: string | null;
workingDir: string;
baseUrl: string | null;
pid: number | null;
certFingerprintSeen: boolean;
healthCheckSucceeded: boolean;
childExitCode: number | null;
childExitSignal: string | null;
stderrTail: string[];
events: StartupTraceEvent[];
}

export interface GooseServeStartupDiagnostics {
attemptId: string;
startedAt: string;
Expand All @@ -41,13 +26,6 @@ export interface GooseServeStartupDiagnostics {
events: StartupTraceEvent[];
}

export interface StartupTrace {
diagnosticsPath: string;
diagnostics: StartupDiagnostics;
record: (name: string, details?: Record<string, unknown>) => void;
flush: () => void;
}

export interface GooseServeStartupTrace {
diagnosticsPath: string;
diagnostics: GooseServeStartupDiagnostics;
Expand All @@ -65,27 +43,6 @@ export const appendTail = (target: string[], lines: string[]) => {
}
};

const cleanupStartupDiagnostics = (diagnosticsDir: string) => {
const startupLogs = fs
.readdirSync(diagnosticsDir, { withFileTypes: true })
.filter(
(entry) =>
entry.isFile() && entry.name.startsWith('goosed-startup-') && entry.name.endsWith('.json')
)
.map((entry) => {
const filePath = path.join(diagnosticsDir, entry.name);
return {
filePath,
modifiedMs: fs.statSync(filePath).mtimeMs,
};
})
.sort((a, b) => b.modifiedMs - a.modifiedMs);

for (const startupLog of startupLogs.slice(STARTUP_LOGS_TO_KEEP)) {
fs.unlinkSync(startupLog.filePath);
}
};

const cleanupGooseServeStartupDiagnostics = (diagnosticsDir: string) => {
const startupLogs = fs
.readdirSync(diagnosticsDir, { withFileTypes: true })
Expand All @@ -109,63 +66,6 @@ const cleanupGooseServeStartupDiagnostics = (diagnosticsDir: string) => {
}
};

export const createStartupDiagnostics = (
diagnosticsDir: string | undefined,
workingDir: string
): StartupTrace | null => {
if (!diagnosticsDir) {
return null;
}

fs.mkdirSync(diagnosticsDir, { recursive: true });
cleanupStartupDiagnostics(diagnosticsDir);
const startedAt = new Date();
const attemptId = `goosed-startup-${startedAt.toISOString().replace(/:/g, '-')}-${process.pid}.json`;
const diagnosticsPath = path.join(diagnosticsDir, attemptId);
const monotonicStart = Date.now();

const diagnostics: StartupDiagnostics = {
attemptId,
startedAt: startedAt.toISOString(),
goosedPath: null,
workingDir,
baseUrl: null,
pid: null,
certFingerprintSeen: false,
healthCheckSucceeded: false,
childExitCode: null,
childExitSignal: null,
stderrTail: [],
events: [],
};

const flush = () => {
fs.writeFileSync(diagnosticsPath, `${JSON.stringify(diagnostics, null, 2)}\n`);
};

const record = (name: string, details?: Record<string, unknown>) => {
if (name === 'healthcheck_success') {
diagnostics.healthCheckSucceeded = true;
}
diagnostics.events.push({
name,
at: new Date().toISOString(),
elapsedMs: Date.now() - monotonicStart,
...(details ? { details } : {}),
});
flush();
};

flush();

return {
diagnosticsPath,
diagnostics,
record,
flush,
};
};

export const createGooseServeStartupDiagnostics = (
diagnosticsDir: string | undefined,
workingDir: string
Expand Down
Loading
Loading