Fix session persistence: deterministic workspace IDs based on folder path, improve Antigravity auth error handling
Some checks failed
Release Binaries / release (push) Has been cancelled
Some checks failed
Release Binaries / release (push) Has been cancelled
This commit is contained in:
19
packages/electron-app/.codenomad-data/mjnz73yi/sessions.json
Normal file
19
packages/electron-app/.codenomad-data/mjnz73yi/sessions.json
Normal file
@@ -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": {}
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user