diff --git a/packages/electron-app/.codenomad-data/mjnz73yi/sessions.json b/packages/electron-app/.codenomad-data/mjnz73yi/sessions.json new file mode 100644 index 0000000..5702983 --- /dev/null +++ b/packages/electron-app/.codenomad-data/mjnz73yi/sessions.json @@ -0,0 +1,19 @@ +{ + "sessions": { + "01KDFB53053F09XN5CJ3S7PQWH": { + "id": "01KDFB53053F09XN5CJ3S7PQWH", + "workspaceId": "mjnz73yi", + "title": "New Session", + "parentId": null, + "createdAt": 1766820318213, + "updatedAt": 1766820318213, + "messageIds": [], + "model": { + "providerId": "opencode-zen", + "modelId": "grok-code" + }, + "agent": "Assistant" + } + }, + "messages": {} +} \ No newline at end of file diff --git a/packages/server/src/server/routes/antigravity.ts b/packages/server/src/server/routes/antigravity.ts index 1fc7087..1abda20 100644 --- a/packages/server/src/server/routes/antigravity.ts +++ b/packages/server/src/server/routes/antigravity.ts @@ -110,9 +110,12 @@ export async function registerAntigravityRoutes( }) if (!response.ok) { - const error = await response.text() - logger.error({ error, status: response.status }, "Device auth request failed") - return reply.status(500).send({ error: "Failed to start device authorization" }) + const errorText = await response.text() + logger.error({ error: errorText, status: response.status }, "Device auth request failed") + return reply.status(500).send({ + error: `Device authorization failed: ${response.status}`, + details: errorText + }) } const data = await response.json() as { @@ -142,7 +145,7 @@ export async function registerAntigravityRoutes( } } - logger.info({ sessionId, userCode: data.user_code }, "Device auth session created") + logger.info({ sessionId, userCode: data.user_code, verificationUrl: data.verification_url }, "Device auth session created") return { sessionId, @@ -151,9 +154,12 @@ export async function registerAntigravityRoutes( expiresIn: data.expires_in, interval: data.interval } - } catch (error) { - logger.error({ error }, "Failed to start device authorization") - return reply.status(500).send({ error: "Failed to start device authorization" }) + } catch (error: any) { + logger.error({ error: error.message, stack: error.stack }, "Failed to start device authorization") + return reply.status(500).send({ + error: "Failed to start device authorization", + details: error.message + }) } }) diff --git a/packages/server/src/workspaces/manager.ts b/packages/server/src/workspaces/manager.ts index 951e9ed..b535c56 100644 --- a/packages/server/src/workspaces/manager.ts +++ b/packages/server/src/workspaces/manager.ts @@ -45,6 +45,31 @@ export class WorkspaceManager { return this.workspaces.get(id)?.port } + /** + * Generate a deterministic workspace ID based on folder path + * This ensures the same folder always gets the same workspace ID, + * allowing sessions to persist across app restarts + */ + private generateDeterministicId(folderPath: string): string { + // Normalize the path for consistent hashing across platforms + const normalizedPath = folderPath.replace(/\\/g, '/').toLowerCase() + + // Simple hash function to create a short, deterministic ID + let hash = 0 + for (let i = 0; i < normalizedPath.length; i++) { + const char = normalizedPath.charCodeAt(i) + hash = ((hash << 5) - hash) + char + hash = hash & hash // Convert to 32bit integer + } + + // Convert to base36 and ensure positive + const hashStr = Math.abs(hash).toString(36) + + // Return a short but unique ID + return hashStr.padStart(8, '0') + } + + listFiles(workspaceId: string, relativePath = "."): FileSystemEntry[] { const workspace = this.requireWorkspace(workspaceId) const browser = new FileSystemBrowser({ rootDir: workspace.path }) @@ -71,10 +96,21 @@ export class WorkspaceManager { // Special constant for Native mode (no OpenCode binary) const NATIVE_MODE_PATH = "__nomadarch_native__" - const id = `${Date.now().toString(36)}` const binary = this.options.binaryRegistry.resolveDefault() const resolvedBinaryPath = this.resolveBinaryPath(binary.path) const workspacePath = path.isAbsolute(folder) ? folder : path.resolve(this.options.rootDir, folder) + + // Generate a deterministic workspace ID based on the folder path + // This ensures the same folder always gets the same ID, allowing sessions to persist + const id = this.generateDeterministicId(workspacePath) + + // Check if workspace already exists - if so, return the existing one + const existingWorkspace = this.workspaces.get(id) + if (existingWorkspace && existingWorkspace.status === "ready") { + this.options.logger.info({ workspaceId: id }, "Reusing existing workspace") + return existingWorkspace + } + clearWorkspaceSearchCache(workspacePath) // Check if we're in native mode diff --git a/packages/ui/src/components/settings/AntigravitySettings.tsx b/packages/ui/src/components/settings/AntigravitySettings.tsx index 18ba39c..852a9a8 100644 --- a/packages/ui/src/components/settings/AntigravitySettings.tsx +++ b/packages/ui/src/components/settings/AntigravitySettings.tsx @@ -154,7 +154,12 @@ const AntigravitySettings: Component = () => { } catch (err: any) { console.error('Device auth error:', err) - setError(err.message || 'Authentication failed') + // Try to get detailed error message + let errorMessage = err.message || 'Authentication failed' + if (err.details) { + errorMessage += ` - ${err.details}` + } + setError(errorMessage) setIsAuthenticating(false) } }