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) {
|
if (!response.ok) {
|
||||||
const error = await response.text()
|
const errorText = await response.text()
|
||||||
logger.error({ error, status: response.status }, "Device auth request failed")
|
logger.error({ error: errorText, status: response.status }, "Device auth request failed")
|
||||||
return reply.status(500).send({ error: "Failed to start device authorization" })
|
return reply.status(500).send({
|
||||||
|
error: `Device authorization failed: ${response.status}`,
|
||||||
|
details: errorText
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json() as {
|
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 {
|
return {
|
||||||
sessionId,
|
sessionId,
|
||||||
@@ -151,9 +154,12 @@ export async function registerAntigravityRoutes(
|
|||||||
expiresIn: data.expires_in,
|
expiresIn: data.expires_in,
|
||||||
interval: data.interval
|
interval: data.interval
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
logger.error({ error }, "Failed to start device authorization")
|
logger.error({ error: error.message, stack: error.stack }, "Failed to start device authorization")
|
||||||
return reply.status(500).send({ error: "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
|
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[] {
|
listFiles(workspaceId: string, relativePath = "."): FileSystemEntry[] {
|
||||||
const workspace = this.requireWorkspace(workspaceId)
|
const workspace = this.requireWorkspace(workspaceId)
|
||||||
const browser = new FileSystemBrowser({ rootDir: workspace.path })
|
const browser = new FileSystemBrowser({ rootDir: workspace.path })
|
||||||
@@ -71,10 +96,21 @@ export class WorkspaceManager {
|
|||||||
// Special constant for Native mode (no OpenCode binary)
|
// Special constant for Native mode (no OpenCode binary)
|
||||||
const NATIVE_MODE_PATH = "__nomadarch_native__"
|
const NATIVE_MODE_PATH = "__nomadarch_native__"
|
||||||
|
|
||||||
const id = `${Date.now().toString(36)}`
|
|
||||||
const binary = this.options.binaryRegistry.resolveDefault()
|
const binary = this.options.binaryRegistry.resolveDefault()
|
||||||
const resolvedBinaryPath = this.resolveBinaryPath(binary.path)
|
const resolvedBinaryPath = this.resolveBinaryPath(binary.path)
|
||||||
const workspacePath = path.isAbsolute(folder) ? folder : path.resolve(this.options.rootDir, folder)
|
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)
|
clearWorkspaceSearchCache(workspacePath)
|
||||||
|
|
||||||
// Check if we're in native mode
|
// Check if we're in native mode
|
||||||
|
|||||||
@@ -154,7 +154,12 @@ const AntigravitySettings: Component = () => {
|
|||||||
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error('Device auth error:', err)
|
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)
|
setIsAuthenticating(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user