* Apply remote entries to local files (CCR pull pattern). * Only writes files that match expected keys. * * After writing, invalidates relevant caches: * - resetSettingsCache() for settings files * - clearMemoryFileCaches() for memory files (CLAUDE.md)
( entries: Record<string, string>, projectId: string | null, )
| 486 | * - clearMemoryFileCaches() for memory files (CLAUDE.md) |
| 487 | */ |
| 488 | async function applyRemoteEntriesToLocal( |
| 489 | entries: Record<string, string>, |
| 490 | projectId: string | null, |
| 491 | ): Promise<void> { |
| 492 | let appliedCount = 0 |
| 493 | let settingsWritten = false |
| 494 | let memoryWritten = false |
| 495 | |
| 496 | // Helper to check size limit (defense-in-depth, matches backend limit) |
| 497 | const exceedsSizeLimit = (content: string, _path: string): boolean => { |
| 498 | const sizeBytes = Buffer.byteLength(content, 'utf8') |
| 499 | if (sizeBytes > MAX_FILE_SIZE_BYTES) { |
| 500 | logForDiagnosticsNoPII('info', 'settings_sync_file_too_large', { |
| 501 | sizeBytes, |
| 502 | maxBytes: MAX_FILE_SIZE_BYTES, |
| 503 | }) |
| 504 | return true |
| 505 | } |
| 506 | return false |
| 507 | } |
| 508 | |
| 509 | // Apply global user settings |
| 510 | const userSettingsContent = entries[SYNC_KEYS.USER_SETTINGS] |
| 511 | if (userSettingsContent) { |
| 512 | const userSettingsPath = getSettingsFilePathForSource('userSettings') |
| 513 | if ( |
| 514 | userSettingsPath && |
| 515 | !exceedsSizeLimit(userSettingsContent, userSettingsPath) |
| 516 | ) { |
| 517 | // Mark as internal write to prevent spurious change detection |
| 518 | markInternalWrite(userSettingsPath) |
| 519 | if (await writeFileForSync(userSettingsPath, userSettingsContent)) { |
| 520 | appliedCount++ |
| 521 | settingsWritten = true |
| 522 | } |
| 523 | } |
| 524 | } |
| 525 | |
| 526 | // Apply global user memory |
| 527 | const userMemoryContent = entries[SYNC_KEYS.USER_MEMORY] |
| 528 | if (userMemoryContent) { |
| 529 | const userMemoryPath = getMemoryPath('User') |
| 530 | if (!exceedsSizeLimit(userMemoryContent, userMemoryPath)) { |
| 531 | if (await writeFileForSync(userMemoryPath, userMemoryContent)) { |
| 532 | appliedCount++ |
| 533 | memoryWritten = true |
| 534 | } |
| 535 | } |
| 536 | } |
| 537 | |
| 538 | // Apply project-specific files (only if project ID matches) |
| 539 | if (projectId) { |
| 540 | const projectSettingsKey = SYNC_KEYS.projectSettings(projectId) |
| 541 | const projectSettingsContent = entries[projectSettingsKey] |
| 542 | if (projectSettingsContent) { |
| 543 | const localSettingsPath = getSettingsFilePathForSource('localSettings') |
| 544 | if ( |
| 545 | localSettingsPath && |
no test coverage detected