// Pré-trust programmatique (spike S3) : écrit projects[""].hasTrustDialogAccepted = true // dans ~/.claude.json pour éviter le dialogue Trust au 1er lancement de `claude` dans un worktree neuf. // Écriture ATOMIQUE (tmp + rename). Le chemin est injectable pour les tests (jamais le vrai HOME). import { readFileSync, writeFileSync, renameSync } from 'node:fs'; import { homedir } from 'node:os'; import { join } from 'node:path'; export function claudeConfigPath(): string { return join(homedir(), '.claude.json'); } /** * Marque un worktree comme déjà approuvé. Tolérant : fichier absent → on le crée ; fichier corrompu * → on ABANDONNE le pré-trust (on ne l'écrase pas, pour ne pas perdre la config existante). Retourne * true si le pré-trust a été écrit, false sinon (l'appelant continue : ce n'est pas bloquant). */ export function preTrustProject(worktreePath: string, filePath = claudeConfigPath()): boolean { let data: Record = {}; try { const parsed = JSON.parse(readFileSync(filePath, 'utf8')) as unknown; if (typeof parsed !== 'object' || parsed === null) return false; // contenu inattendu : on n'écrase pas data = parsed as Record; } catch (err) { if ((err as NodeJS.ErrnoException).code !== 'ENOENT') return false; // corrompu/illisible : abandon data = {}; // fichier absent : on part d'un objet vide } const projects = typeof data.projects === 'object' && data.projects !== null ? (data.projects as Record>) : {}; projects[worktreePath] = { ...(projects[worktreePath] ?? {}), hasTrustDialogAccepted: true }; data.projects = projects; try { const tmp = `${filePath}.arb-tmp`; writeFileSync(tmp, JSON.stringify(data, null, 2)); renameSync(tmp, filePath); // rename atomique : jamais de fichier à moitié écrit return true; } catch { return false; } }