The default Docker API version was hardcoded to 1.41, which fails on
newer Docker daemons that require at least API version 1.44.
Change the default to empty string so the Docker client uses the
existing WithAPIVersionNegotiation() option to auto-negotiate a
compatible version with the daemon.
Long file paths could overflow the AlertDialog horizontally, pushing
the action buttons outside the visible area. Add break-words on the
description and overflow-wrap:anywhere on the filename span so paths
wrap mid-string instead of forcing the dialog wider than its max-w.
* fix: prevent agentctl OOM from unbounded diff generation in workspace tracker
Add per-file size cap (10MB), binary detection (null-byte in 8KB),
diff output cap (256KB), and total budget (2MB) to workspace tracker
diff enrichment. Strip diff content from event bus path. Surface skip
reasons in frontend. Add pprof endpoints to agentctl.
* fix: address PR review feedback
Close stdout pipe on cmd.Start failure to prevent fd leak.
Limit untracked file read to maxDiffOutputSize (256KB) instead of
maxDiffFileSize (10MB) to reduce peak allocation from ~20MB to ~512KB.
* fix: add filepath.Clean to os.Stat call to satisfy CodeQL path-injection check
* fix: address second round of PR review feedback
Extract all DiffSkipReason strings as named constants. Add diff_skip_reason
to UncommittedFile type removing unsafe cast. Add unit tests for
isBinaryContent, totalDiffBytes, capDiffOutput truncation, and all
enrichUntrackedFileDiffs skip-reason paths.
* fix: use bytes.IndexByte for null-byte check clarity
* fix: show truncation banner when diff has partial content
* fix: revert diff stripping from event bus — frontend needs diffs from this path
E2E tests confirmed the frontend receives git status diffs through the
event bus (agentctl → backend WS → event bus → gateway → frontend).
Stripping diffs broke the changes panel. The per-file size caps in
workspace_git_diff.go already bound the data.
* fix: extract renderDiffContent to keep FileDiffSection under 100-line lint limit
* fix: correct onCommentRun type in renderDiffContent helper
* fix: format long destructuring line for prettier
* fix: move diffSkipReasonLabel to types.ts to keep review-diff-list under 600 lines
Co-authored-by: José Almeida <undefined@users.noreply.github.com>
* fix: coerce optional forceLoad to boolean for renderDiffContent
* fix: shorten className and comment to stay within prettier printWidth
* fix: apply prettier formatting to review-diff-list
* fix: correct off-by-one in untracked file line count
---------
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: José Almeida <undefined@users.noreply.github.com>
* fix: improve plan comment formatting to match code review style
- Update formatPlanCommentsAsMarkdown to use code blocks and blockquotes
- Remove duplicate header in chat-input-area.tsx
- Update buildDocumentContext to use consistent formatting
- Fixes duplicate '### Plan Comments' headers and extra separators
* fix: add tests and fix multiline blockquote handling
- Add format.test.ts for formatPlanCommentsAsMarkdown and related functions
- Fix multiline comment text to properly prefix each line with >
- Addresses review feedback about missing tests and broken blockquotes
* fix: export and reuse toBlockquote helper to avoid duplication
* fix: update E2E test to match new plan comment format
The test was expecting 'Comment 1:' which was the old bullet-style format.
Now looks for 'Plan Comments' header instead.
* fix(web): replace mermaid bomb-icon error flood with toast notifications
mermaid.render() called without a container leaves orphaned error
elements (with bomb icons) in document.body on parse failures. Clean up
these orphans after every render and show an error toast instead.
* fix(web): address PR review — prevent toast flooding, include error detail, add hook tests
- Add latestRenderId guard in TipTap MermaidNodeView to skip stale
renders, preventing toast spam on every keystroke
- Include mermaid error message in toast description via CustomEvent detail
- Add useMermaidErrorToast hook tests (event listener + cleanup)
* style(web): format mermaid-error-toast test with prettier
* fix(web): include error message in MermaidBlock toast description
* fix(web): fix dock view task-switching regressions
Three bugs caused broken UI when switching tasks in the dock view:
1. Environment key migration was dead code — data stored under fallback
sessionId keys became invisible when the environmentIdBySessionId
mapping was later set, because migrateEnvKeyedData was never called
in production (only in tests via registerSessionEnvironment).
2. Orphaned portals leaked on every fast-path session switch — the
isRestoringLayout guard in setupPortalCleanup blocked portal release
for panels removed during the fast path, accumulating invisible React
trees with live WS subscriptions.
3. Chat panel gap during fast-path transition — old session tab was
removed synchronously but new tab was deferred to a useEffect,
leaving a brief layout gap.
* fix(web): remove superfluous args in test helper
Address CodeQL finding — createSessionSlice only takes `set`, not
`get` and `api`.
* fix(web): add addPanel test assertions and doc comment
Address claude-review blocker: assert that fast-path creates the
session panel with correct id/params, and skips creation when it
already exists. Add doc comment noting syncEnvironmentMapping
requires the combined store draft.
* test(web): add PanelPortalManager.reconcile tests
Export PanelPortalManager class for testability and add tests covering
reconcile removal, no-op, and listener notification paths.
* fix: use dynamic merge-base for git commits to filter main branch commits
When a feature branch is rebased on main, the stored base_commit_sha
becomes outdated. Using git log base_commit..HEAD would include main
branch commits that were merged after the stored base commit.
This fix adds dynamic merge-base calculation using the session's
base_branch (target branch like origin/main). When fetching commits:
- The backend computes git merge-base HEAD target_branch
- This returns only commits not yet merged into the target branch
- Works correctly even after rebases
Changes:
- Extended SessionReader interface with GetSessionBaseBranch method
- Added GetMergeBase to GitOperator for computing merge-base
- Updated git log API to accept target_branch parameter
- Modified wsGitCommits handler to pass target branch for filtering
* fix: update executor_test mock to match new GetGitLog signature
* fix: update remaining mocks to match new GetGitLog signature
* fix: update integration test mock for GetGitLog signature
* fix: address code review feedback
- Use GetOrEnsureExecution in wsGitCommits to recover workspaces after backend restarts
- Fix archive snapshot to use baseBranch for merge-base when baseCommit is empty
- Extended ExecutionLookup interface with GetOrEnsureExecution method
* fix: distinguish not-ready errors from unexpected errors in wsGitCommits
Address CodeRabbit review feedback:
- Use errors.Is() to detect ErrSessionWorkspaceNotReady sentinel error
- Return ready:false gracefully for workspace-not-ready and session-not-ready errors
- Return actual errors for unexpected failures (database errors, etc.)
- Add comprehensive tests for error handling paths
* feat(mcp): add start_agent and local_path params to create_task
Add control over task creation behavior in MCP create_task tool:
- Add start_agent boolean param (default true) to optionally skip
auto-starting an agent when creating tasks
- Add local_path param for specifying local repository folder path
when creating top-level tasks (worktree flow)
- Add repository_id and base_branch params for explicit repo config
- Improve tool description with clear guidance on when to use
parent_id='self' vs creating top-level tasks
- Update backend handler to respect start_agent flag
- Relax description requirement for subtasks when start_agent=false
This fixes the issue where agents creating tasks from plans would
always auto-start immediately and couldn't specify repositories
for top-level tasks.
* test(mcp): add integration tests for source_task_id inheritance paths
Cover the source-task path in resolveTaskRepositories that had no test
coverage at any layer: valid source_task_id inherits repos and missing
source_task_id silently falls through rather than failing.
Co-authored-by: João Salavisa <undefined@users.noreply.github.com>
---------
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: João Salavisa <undefined@users.noreply.github.com>
* fix(worktree): handle submodules in worktree creation
Repos with git submodules failed during worktree creation when git-crypt
was also present. The `git checkout HEAD -- .` command in
unlockGitCryptAndCheckout() tried to process submodule gitlink entries,
but git resolved their git dirs relative to the worktree-specific git
dir instead of the common dir, causing "not a git repository" errors.
- Detect submodule paths via `git ls-tree -r HEAD` (mode 160000)
- Exclude submodule paths from git-crypt checkout using :(exclude) pathspecs
- Initialize submodules after worktree creation via `git submodule update --init`
(non-fatal — unreachable URLs are logged as warnings)
- Add submodule init to all worktree creation paths (git-crypt and non-git-crypt)
* fix(worktree): address review — recursive submodule init, consistent call sites
- Add --recursive to git submodule update --init for nested submodules
- Call initSubmodules unconditionally in git-crypt path (matching manager.go)
* fix(worktree): restore submodule index entries after git-crypt checkout
The :(exclude) pathspec used to skip submodules during git checkout also
prevents their gitlink entries from being written to the index. This
leaves git status showing them as staged deletions.
After checkout, run git reset HEAD for each excluded submodule path to
copy the gitlink entry from HEAD back into the index.
* test(worktree): add git status assertion to submodule unlock test
Validate that the index reset after :(exclude) checkout leaves no
staged deletions for submodule paths.
* fix(worktree): use literal pathspec for submodule exclusion
Use :(literal,exclude) instead of :(exclude) to prevent glob
metacharacters in submodule paths from being interpreted as patterns.
* fix(worktree): fix initSubmodules docstring to match --recursive flag