diff --git a/packages/opencode/src/snapshot/index.ts b/packages/opencode/src/snapshot/index.ts index 4da9bc3ca864..f7b2e5608466 100644 --- a/packages/opencode/src/snapshot/index.ts +++ b/packages/opencode/src/snapshot/index.ts @@ -92,7 +92,10 @@ const layer: Layer.Layer Effect.succeed({ - code: ChildProcessSpawner.ExitCode(1), + // -1 is a sentinel for "git failed to run at all". Callers that give + // exit code 1 a meaning (check-ignore: "none ignored") must not see + // spawn failures as code 1, otherwise fail-closed paths get bypassed. + code: ChildProcessSpawner.ExitCode(-1), text: "", stderr: err instanceof Error ? err.message : String(err), }), @@ -120,7 +123,16 @@ const layer: Layer.Layer() + // git check-ignore: 0 = some ignored, 1 = none ignored; any other code is an error. + // Fail closed: treat every candidate as ignored so gitignored files cannot leak into + // snapshot patches and later be restored or deleted by /undo (see #28033). + if (check.code !== 0 && check.code !== 1) { + yield* Effect.logWarning("git check-ignore failed; treating all candidates as ignored", { + code: check.code, + stderr: check.stderr, + }) + return new Set(files) + } return new Set( check.text .split("\0")