( sessionId: string, ingressUrl: string, )
| 1743 | } |
| 1744 | |
| 1745 | export async function hydrateRemoteSession( |
| 1746 | sessionId: string, |
| 1747 | ingressUrl: string, |
| 1748 | ): Promise<boolean> { |
| 1749 | switchSession(asSessionId(sessionId)) |
| 1750 | |
| 1751 | const project = getProject() |
| 1752 | |
| 1753 | try { |
| 1754 | const remoteLogs = |
| 1755 | (await sessionIngress.getSessionLogs(sessionId, ingressUrl)) || [] |
| 1756 | |
| 1757 | // Ensure the project directory and session file exist |
| 1758 | const projectDir = getProjectDir(getOriginalCwd()) |
| 1759 | await mkdir(projectDir, { recursive: true, mode: 0o700 }) |
| 1760 | |
| 1761 | const sessionFile = getTranscriptPathForSession(sessionId) |
| 1762 | |
| 1763 | // Replace local logs with remote logs. writeFile truncates, so no |
| 1764 | // unlink is needed; an empty remoteLogs array produces an empty file. |
| 1765 | const content = remoteLogs.map(e => jsonStringify(e) + '\n').join('') |
| 1766 | await writeFile(sessionFile, content, { encoding: 'utf8', mode: 0o600 }) |
| 1767 | |
| 1768 | logForDebugging(`Hydrated ${remoteLogs.length} entries from remote`) |
| 1769 | return remoteLogs.length > 0 |
| 1770 | } catch (error) { |
| 1771 | logForDebugging(`Error hydrating session from remote: ${error}`) |
| 1772 | logForDiagnosticsNoPII('error', 'hydrate_remote_session_fail') |
| 1773 | return false |
| 1774 | } finally { |
| 1775 | // Set remote ingress URL after hydrating the remote session |
| 1776 | // to ensure we've always synced with the remote session |
| 1777 | // prior to enabling persistence |
| 1778 | project.setRemoteIngressUrl(ingressUrl) |
| 1779 | } |
| 1780 | } |
| 1781 | |
| 1782 | /** |
| 1783 | * Hydrate session state from CCR v2 internal events. |
no test coverage detected