* Back up the current bytes at `abs` next to it without clobbering any existing * backup or writing through a symlink. Exclusive create (`wx`) fails with * EEXIST on an existing regular file OR symlink, so we walk `.bak`, `.bak.1`, * `.bak.2`, … until a free slot is found. Returns the absolute pa
(agentFs: AgentFs, abs: string, existing: string)
| 124 | * `.bak.2`, … until a free slot is found. Returns the absolute path used. |
| 125 | */ |
| 126 | async function writeBackup(agentFs: AgentFs, abs: string, existing: string): Promise<string> { |
| 127 | for (let n = 0; n < 100; n++) { |
| 128 | const candidate = n === 0 ? `${abs}.bak` : `${abs}.bak.${n}`; |
| 129 | try { |
| 130 | await agentFs.writeFile(candidate, existing, { exclusive: true }); |
| 131 | return candidate; |
| 132 | } catch (err) { |
| 133 | if (err instanceof Error && (err as NodeJS.ErrnoException).code === 'EEXIST') { |
| 134 | continue; |
| 135 | } |
| 136 | throw err; |
| 137 | } |
| 138 | } |
| 139 | throw new CLIError( |
| 140 | `refusing to back up ${path.basename(abs)}: too many existing .bak files — clean them up and re-run.`, |
| 141 | 6, |
| 142 | ); |
| 143 | } |
| 144 | |
| 145 | // --------------------------------------------------------------------------- |
| 146 | // Managed-section helpers (codex target) |