Merge pull request #3205: feat(eval): isolated/apply/merge options for agent() helper
Resolves conflict in test/task/worktree.test.ts by keeping both the getRepoRoot (main) and applyNestedPatches (PR) describe blocks. Extends the PR's Python/JS work to the remaining workflow runtimes: - eval/rb/prelude.rb, eval/jl/prelude.jl: agent() now accepts and forwards isolated/apply/merge (as booleans) plus returnHandle, and the return_handle node carries isolated/patch_path/branch_name/ nested_patches/changes_applied/isolation_summary. Post-merge fixups: - task/index.ts: drop dead commitStyle var (the dedup refactor reads task.isolation.commits inside makeIsolationCommitMessage). - CHANGELOG: move the misplaced Added entry under [Unreleased], correct the stale "defaults track task.isolation.mode" wording to the final strict opt-in behavior, and note all four runtimes. Fixes #3196
This commit is contained in:
@@ -194,6 +194,14 @@ export async function captureDeltaPatch(isolationDir: string, baseline: Worktree
|
||||
|
||||
/**
|
||||
* Apply nested repo patches directly to their working directories after parent merge.
|
||||
*
|
||||
* Pre-existing dirty state in a nested repo is stashed before the patch is
|
||||
* applied and popped back after the commit, so unrelated user edits never get
|
||||
* folded into the agent's commit. A failing `git stash pop` (e.g. user edits
|
||||
* collide with the patched lines) leaves the stash entry intact and emits a
|
||||
* `logger.warn` — the caller's catch handler turns the broader nested-apply
|
||||
* failure into a non-fatal system notification.
|
||||
*
|
||||
* @param commitMessage Optional async function to generate a commit message from the combined diff.
|
||||
* If omitted or returns null, falls back to a generic message.
|
||||
*/
|
||||
@@ -220,15 +228,33 @@ export async function applyNestedPatches(
|
||||
}
|
||||
|
||||
const combinedDiff = repoPatches.map(p => p.patch).join("\n");
|
||||
for (const { patch } of repoPatches) {
|
||||
await git.patch.applyText(nestedDir, patch);
|
||||
}
|
||||
|
||||
// Commit so nested repo history reflects the task changes
|
||||
if ((await git.status(nestedDir)).trim().length > 0) {
|
||||
const msg = (await commitMessage?.(combinedDiff)) ?? "changes from isolated task(s)";
|
||||
await git.stage.files(nestedDir);
|
||||
await git.commit(nestedDir, msg);
|
||||
// Preserve any pre-existing dirty state (tracked + untracked) so we
|
||||
// commit only the agent delta, not the user's in-flight work.
|
||||
const stashed =
|
||||
(await git.status(nestedDir)).trim().length > 0
|
||||
? await git.stash.push(nestedDir, `omp-isolation-${Snowflake.next()}`)
|
||||
: false;
|
||||
try {
|
||||
for (const { patch } of repoPatches) {
|
||||
await git.patch.applyText(nestedDir, patch);
|
||||
}
|
||||
if ((await git.status(nestedDir)).trim().length > 0) {
|
||||
const msg = (await commitMessage?.(combinedDiff)) ?? "changes from isolated task(s)";
|
||||
await git.stage.files(nestedDir);
|
||||
await git.commit(nestedDir, msg);
|
||||
}
|
||||
} finally {
|
||||
if (stashed) {
|
||||
try {
|
||||
await git.stash.pop(nestedDir, { index: true });
|
||||
} catch (popErr) {
|
||||
logger.warn("Pre-existing nested-repo dirty state could not be auto-restored", {
|
||||
nestedDir,
|
||||
error: popErr instanceof Error ? popErr.message : String(popErr),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user