( sessionId: string, ingressUrl: string, )
| 1586 | } |
| 1587 | |
| 1588 | export async function hydrateRemoteSession( |
| 1589 | sessionId: string, |
| 1590 | ingressUrl: string, |
| 1591 | ): Promise<boolean> { |
| 1592 | switchSession(asSessionId(sessionId)) |
| 1593 | |
| 1594 | const project = getProject() |
| 1595 | |
| 1596 | try { |
| 1597 | const remoteLogs = |
| 1598 | (await sessionIngress.getSessionLogs(sessionId, ingressUrl)) || [] |
| 1599 | |
| 1600 | // Ensure the project directory and session file exist |
| 1601 | const projectDir = getProjectDir(getOriginalCwd()) |
| 1602 | await mkdir(projectDir, { recursive: true, mode: 0o700 }) |
| 1603 | |
| 1604 | const sessionFile = getTranscriptPathForSession(sessionId) |
| 1605 | |
| 1606 | // Replace local logs with remote logs. writeFile truncates, so no |
| 1607 | // unlink is needed; an empty remoteLogs array produces an empty file. |
| 1608 | const content = remoteLogs.map(e => jsonStringify(e) + '\n').join('') |
| 1609 | await writeFile(sessionFile, content, { encoding: 'utf8', mode: 0o600 }) |
| 1610 | |
| 1611 | logForDebugging(`Hydrated ${remoteLogs.length} entries from remote`) |
| 1612 | return remoteLogs.length > 0 |
| 1613 | } catch (error) { |
| 1614 | logForDebugging(`Error hydrating session from remote: ${error}`) |
| 1615 | logForDiagnosticsNoPII('error', 'hydrate_remote_session_fail') |
| 1616 | return false |
| 1617 | } finally { |
| 1618 | // Set remote ingress URL after hydrating the remote session |
| 1619 | // to ensure we've always synced with the remote session |
| 1620 | // prior to enabling persistence |
| 1621 | project.setRemoteIngressUrl(ingressUrl) |
| 1622 | } |
| 1623 | } |
| 1624 | |
| 1625 | /** |
| 1626 | * Hydrate session state from CCR v2 internal events. |
no test coverage detected