diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 998823a5a..dc329ae3e 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -10,7 +10,7 @@ - Added `fuse-overlay` isolation mode for subagents using `fuse-overlayfs` (copy-on-write overlay, no baseline patch apply needed) - Added `task.isolation.merge` setting (`patch` or `branch`) to control how isolated task changes are integrated back. `branch` mode commits each task to a temp branch and cherry-picks for clean commit history -- Added `task.isolation.commits` setting (`generic` or `ai`) for nested repo commit messages. `ai` mode uses a smol model to generate conventional commit messages from diffs +- Added `task.isolation.commits` setting (`generic` or `ai`) for commit messages on isolated task branches and nested repos. `ai` mode uses a smol model to generate conventional commit messages from diffs - Nested non-submodule git repos are now discovered and handled during task isolation (changes captured and applied independently from parent repo) - Added `task.eager` setting to encourage the agent to delegate work to subagents by default @@ -20,6 +20,9 @@ - Fixed nested repo patches conflicting when multiple tasks contribute to the same repo (baseline untracked files no longer leak into patches) - Nested repo changes are now committed after patch application (previously left as untracked files) - Failed tasks no longer create stale branches or capture garbage patches (gated on exit code) +- Merge failures (e.g. conflicting patches) are now non-fatal — agent output is preserved with `merge failed` status instead of `failed` +- Stale branches are cleaned up when `commitToBranch` fails +- Commit message generator filters lock files from diffs before AI summarization ## [13.2.0] - 2026-02-23 ### Breaking Changes diff --git a/packages/coding-agent/DEVELOPMENT.md b/packages/coding-agent/DEVELOPMENT.md index cff1843f5..a9384b85d 100644 --- a/packages/coding-agent/DEVELOPMENT.md +++ b/packages/coding-agent/DEVELOPMENT.md @@ -907,11 +907,13 @@ Despite the name `runSubprocess`, `packages/coding-agent/src/task/executor.ts` c What _is_ isolated is execution context and artifacts, not process memory: - Optional filesystem isolation is controlled by the `task.isolation.mode` setting (`"none"`, `"worktree"`, or `"fuse-overlay"`). - - **worktree**: `ensureWorktree(...)`, `applyBaseline(...)`, `captureDeltaPatch(...)`, `cleanupWorktree(...)`. - - **fuse-overlay**: `ensureFuseOverlay(...)` (mounts a copy-on-write overlay via `fuse-overlayfs`), `captureDeltaPatch(...)`, `cleanupFuseOverlay(...)`. No baseline apply step needed since the overlay reflects the full working tree. + - **worktree**: `ensureWorktree(...)`, `applyBaseline(...)`, `captureDeltaPatch(...)`, `cleanupWorktree(...)`. Nested non-submodule git repos are discovered and handled independently. + - **fuse-overlay**: `ensureFuseOverlay(...)` (mounts a copy-on-write overlay via `fuse-overlayfs`), `captureDeltaPatch(...)`, `cleanupFuseOverlay(...)`. No baseline apply needed since the overlay reflects the full working tree. Fails outright if mount fails. - The `task.isolation.merge` setting controls how isolated changes are integrated back: - **patch** (default): captures a diff via `captureDeltaPatch(...)`, combines patches, and applies with `git apply`. - - **branch**: each task commits to a temp branch (`omp/task/`) via `commitToBranch(...)`, then `mergeTaskBranches(...)` merges them sequentially with `--no-ff` merge commits. + - **branch**: each task commits to a temp branch (`omp/task/`) via `commitToBranch(...)`, then `mergeTaskBranches(...)` cherry-picks them sequentially onto HEAD. If `git apply` fails inside `commitToBranch`, the error is non-fatal — the agent result is preserved with a `merge failed` status. +- The `task.isolation.commits` setting (`generic` or `ai`) controls commit messages for branch commits and nested repo patches. `ai` mode uses a smol model to generate conventional commit messages from diffs. +- Nested repo patches are applied via `applyNestedPatches(...)` after the parent merge, grouped by repo with one commit per repo. - Child session JSONL/markdown outputs are written under the task artifacts directory (`.jsonl`, `.md`, and in isolated mode `.patch`). ### Tooling Surface in Child Sessions diff --git a/packages/coding-agent/src/task/index.ts b/packages/coding-agent/src/task/index.ts index 73e272913..824e4fa62 100644 --- a/packages/coding-agent/src/task/index.ts +++ b/packages/coding-agent/src/task/index.ts @@ -806,7 +806,6 @@ export class TaskTool implements AgentTool { if (isolationMode === "fuse-overlay") { isolationDir = await ensureFuseOverlay(repoRoot, task.id); - // Overlay already reflects the full working tree state — no baseline apply needed } else { isolationDir = await ensureWorktree(repoRoot, task.id); await applyBaseline(isolationDir, baseline); diff --git a/packages/coding-agent/src/utils/commit-message-generator.ts b/packages/coding-agent/src/utils/commit-message-generator.ts index 5691bcf26..726ceca20 100644 --- a/packages/coding-agent/src/utils/commit-message-generator.ts +++ b/packages/coding-agent/src/utils/commit-message-generator.ts @@ -14,19 +14,18 @@ import commitSystemPrompt from "../prompts/system/commit-message-system.md" with const COMMIT_SYSTEM_PROMPT = renderPromptTemplate(commitSystemPrompt); const MAX_DIFF_CHARS = 4000; -/** Paths that should be excluded from commit message generation diffs. */ -const NOISE_PATH_PREFIXES = ["node_modules/", ".yarn/", ".pnp.", "dist/", "build/", ".next/", "coverage/"]; +/** File patterns that should be excluded from commit message generation diffs. */ +const NOISE_SUFFIXES = [".lock", ".lockb", "-lock.json", "-lock.yaml"]; -/** Strip diff hunks for noisy paths that drown out real changes. */ +/** Strip diff hunks for noisy files that drown out real changes. */ function filterDiffNoise(diff: string): string { const lines = diff.split("\n"); const filtered: string[] = []; let skip = false; for (const line of lines) { if (line.startsWith("diff --git ")) { - // Extract b/ path from "diff --git a/... b/..." const bPath = line.split(" b/")[1]; - skip = bPath != null && NOISE_PATH_PREFIXES.some(p => bPath.startsWith(p)); + skip = bPath != null && NOISE_SUFFIXES.some(s => bPath.endsWith(s)); } if (!skip) filtered.push(line); }