fix(coding-agent/task): treated stash cleanup paths literally

Failed stash-pop cleanup now invokes git clean with literal pathspecs for
stash-derived untracked paths. Filenames such as `:(glob)*` are valid POSIX
filenames and valid Git pathspec magic; passing them as ordinary pathspecs with
`-x` could delete unrelated ignored artifacts that were never stashed and are
not recoverable from the preserved stash.

Extend the fallback regression with a literal `:(glob)*` stash file and an
ignored `build.log` that must survive cleanup.

Fixes #4175
This commit is contained in:
roboomp
2026-07-01 22:03:23 +00:00
parent 4d471b1aa4
commit e109883ee2
2 changed files with 32 additions and 14 deletions
+12 -3
View File
@@ -1635,7 +1635,7 @@ export const stash = {
}
if (restoredUntracked.length > 0) {
try {
await clean(cwd, { includeIgnored: true, paths: restoredUntracked });
await clean(cwd, { includeIgnored: true, literalPathspecs: true, paths: restoredUntracked });
} catch {
/* best-effort cleanup — do not mask the primary conflict */
}
@@ -1709,9 +1709,18 @@ export async function reset(
export async function clean(
cwd: string,
options: { ignoredOnly?: boolean; includeIgnored?: boolean; paths?: readonly string[]; signal?: AbortSignal } = {},
options: {
ignoredOnly?: boolean;
includeIgnored?: boolean;
literalPathspecs?: boolean;
paths?: readonly string[];
signal?: AbortSignal;
} = {},
): Promise<void> {
const args = ["clean", options.ignoredOnly ? "-fdX" : options.includeIgnored ? "-fdx" : "-fd"];
const args = [options.literalPathspecs ? "--literal-pathspecs" : undefined, "clean"].filter(
(arg): arg is string => arg !== undefined,
);
args.push(options.ignoredOnly ? "-fdX" : options.includeIgnored ? "-fdx" : "-fd");
if (options.paths?.length) args.push("--", ...options.paths);
await runEffect(cwd, args, { signal: options.signal });
}