mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
fix(hapi): consolidate approved web and Codex recovery fixes (#578)
This commit is contained in:
@@ -59,7 +59,7 @@ export class SyncEngine {
|
||||
private inactivityTimer: NodeJS.Timeout | null = null
|
||||
|
||||
constructor(
|
||||
store: Store,
|
||||
private readonly store: Store,
|
||||
io: Server,
|
||||
rpcRegistry: RpcRegistry,
|
||||
sseManager: SSEManager
|
||||
@@ -458,7 +458,7 @@ export class SyncEngine {
|
||||
? metadata.opencodeSessionId
|
||||
: flavor === 'cursor'
|
||||
? metadata.cursorSessionId
|
||||
: metadata.claudeSessionId
|
||||
: (metadata.claudeSessionId ?? this.recoverClaudeSessionIdFromMessages(access.sessionId, namespace))
|
||||
|
||||
if (!resumeToken) {
|
||||
return { type: 'error', message: 'Resume session ID unavailable', code: 'resume_unavailable' }
|
||||
@@ -527,6 +527,78 @@ export class SyncEngine {
|
||||
return { type: 'success', sessionId: spawnResult.sessionId }
|
||||
}
|
||||
|
||||
private recoverClaudeSessionIdFromMessages(sessionId: string, namespace: string): string | null {
|
||||
const messages = this.messageService.getMessages(sessionId, 200)
|
||||
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
||||
const found = this.extractClaudeSessionId(messages[i].content)
|
||||
if (!found) continue
|
||||
|
||||
this.persistRecoveredClaudeSessionId(sessionId, namespace, found)
|
||||
return found
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private extractClaudeSessionId(value: unknown): string | null {
|
||||
if (!value || typeof value !== 'object') {
|
||||
return null
|
||||
}
|
||||
|
||||
const obj = value as Record<string, unknown>
|
||||
const direct = this.normalizeClaudeSessionId(obj.session_id) ?? this.normalizeClaudeSessionId(obj.sessionId)
|
||||
if (direct) {
|
||||
return direct
|
||||
}
|
||||
|
||||
const content = obj.content
|
||||
if (content && typeof content === 'object') {
|
||||
const found = this.extractClaudeSessionId(content)
|
||||
if (found) return found
|
||||
}
|
||||
|
||||
const data = obj.data
|
||||
if (data && typeof data === 'object') {
|
||||
const found = this.extractClaudeSessionId(data)
|
||||
if (found) return found
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private normalizeClaudeSessionId(value: unknown): string | null {
|
||||
if (typeof value !== 'string') {
|
||||
return null
|
||||
}
|
||||
const trimmed = value.trim()
|
||||
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(trimmed)
|
||||
? trimmed
|
||||
: null
|
||||
}
|
||||
|
||||
private persistRecoveredClaudeSessionId(sessionId: string, namespace: string, claudeSessionId: string): void {
|
||||
for (let attempt = 0; attempt < 2; attempt += 1) {
|
||||
const latest = this.sessionCache.getSessionByNamespace(sessionId, namespace)
|
||||
?? this.sessionCache.refreshSession(sessionId)
|
||||
if (!latest?.metadata) return
|
||||
if (latest.metadata.claudeSessionId === claudeSessionId) return
|
||||
|
||||
const result = this.store.sessions.updateSessionMetadata(
|
||||
sessionId,
|
||||
{ ...latest.metadata, claudeSessionId },
|
||||
latest.metadataVersion,
|
||||
namespace,
|
||||
{ touchUpdatedAt: false }
|
||||
)
|
||||
if (result.result === 'success') {
|
||||
this.sessionCache.refreshSession(sessionId)
|
||||
return
|
||||
}
|
||||
if (result.result !== 'version-mismatch') {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private hasSameAgentSessionIds(
|
||||
prev: Session['metadata'] | null,
|
||||
next: NonNullable<Session['metadata']>
|
||||
|
||||
Reference in New Issue
Block a user