Commit Graph

40 Commits

Author SHA1 Message Date
Carlos Florêncio 5591cdc0bf fix(web): add button to load older chat messages reliably (#1223) 2026-06-01 19:12:49 +01:00
Carlos Florêncio d1c73d2f2c feat: surface subagent task tool calls as cards in task chat (#1132) 2026-05-31 17:53:21 +01:00
Carlos Florêncio dcde3da74c feat: surface an inline notice when an agent turn produces no output (#1179) 2026-05-31 11:14:23 +01:00
Carlos Florêncio ec289c799b feat: retry transient provider 529 errors with visible backoff (#1173) 2026-05-30 19:16:49 +01:00
Carlos Florêncio 43977ca570 fix(web): keep markdown table headers readable on narrow content (#1122) 2026-05-30 13:38:21 +01:00
Luan Martins 1a467b969f fix(web): wire permission approval UI for Kandev MCP tools (#1037)
* fix(web): wire permission approval UI for Kandev MCP tools

KandevToolMessage adapter ignored the permissionMessage prop, so MCP tools
that block on a permission request rendered the result row but no Approve/
Deny buttons — users could not unblock the agent. Extract the shared
permission handlers into use-permission-handlers.ts and reuse them from
both ToolCallMessage and KandevToolMessage. KandevRow now also shows an
amber pending clock icon and hides the result-count summary while waiting
for approval so the row reads correctly before the result arrives.

Adds a mock-agent scenarioKandevMCPPermission emitting
mcp__kandev__list_workspaces_kandev plus a Playwright e2e and unit tests
covering the pending UI and the absence of "0 workspaces" while pending.

* fix(web): collapse tool + permission status into resolved Kandev row

After approve/reject the orchestrator stamps the decision onto the
permission_request message immediately, but the tool_call's own
meta.status stays "pending" until the next tool_call update lands.
KandevToolMessage previously passed meta.status straight to the renderer,
so the row kept the amber pending clock and the hidden-summary state for
the brief window between the two events. resolveKandevStatus now prefers
the permission decision once present, mapping approved -> complete and
rejected -> error.

Drops a redundant Playwright `.first()` after a toHaveCount(1) assertion
on the same locator. Adds unit coverage for the resolved-decision state.

* fix(web): keep Kandev tool status independent of permission decision

The previous fix collapsed an approved permission into tool status
"complete" and a rejected permission into "error". That was wrong on two
counts: an approved tool that's still running rendered as already done
(green check + visible result summary built from an empty payload), and
any later tool_call error was silently masked because the status had
already been forced to "complete".

Replace the status override with a separate display overlay. KandevRow
now reads a `KandevPermissionUIContext` ("pending" | "rejected" |
undefined) and uses it only to drive the waiting-on-user affordances —
amber clock, hidden summary — and a rejection mark that wins over the
tool's own success state. The renderer always receives the real
tool_call status, so a tool that's approved-but-pending still reads as
pending and a tool that errors after approval still renders the red X.

Adds explicit regression tests for the two race-window failure modes
plus the new rejected overlay.

* test(web): tolerate duplicate-render backend race in Kandev MCP e2e

CI shard 1 sometimes renders two approve buttons for the same Kandev MCP
permission because the orchestrator can create a second generic tool_call
message for the same tool_call_id alongside the kandev-routed one. Both
buttons resolve the same pending_id, so clicking the first unblocks the
agent either way.

The bug the test guards against is "no approve button at all" — the
strict toHaveCount(1) assertion was tying the test to that separate
backend issue. Relax to at-least-one and click the first.

* fix: persist Deny clicks as rejected, not approved

Backend RespondToPermission previously derived status purely from cancelled:
cancelled=true -> "rejected", otherwise "approved". Deny clicks sent
cancelled=false with a reject_* option_id, so they were recorded as
"approved". Add an explicit rejected flag from the WS request so the
backend can record "rejected" without taking the cancellation path (which
races against permission_cancelled -> "expired").

Also refactor permission-request-message.tsx to consume the shared
usePermissionResponseHandlers hook (the duplicated inline handler had the
same bug) and introduce a typed models.PermissionStatus enum on the
backend so status strings are not scattered literals.

* test(web): scope Kandev MCP permission e2e to the Kandev row

Previously the test clicked the first matching permission-approve button,
which could be a duplicate generic ToolCallMessage fallback rendered for
the same pending_id by a backend race -- a green test no longer proved the
custom Kandev approval UI rendered.

Add a `data-testid="kandev-tool-permission"` wrapper around the Kandev
action row and a `kandevPermissionApproveButtons` page-object locator that
scopes through it, then assert `toHaveCount(1)` so the test only passes
when the Kandev custom row actually mounts.

* chore(orchestrator): log rejected flag in RespondToPermission

Debug log was missing the new rejected param, making it impossible to
distinguish explicit Deny from dialog cancellation when triaging
permission-flow issues.
2026-05-26 00:22:45 +01:00
Carlos Florêncio a2b4fc0c6d fix(web): keep sidebar 3-dot menu from overlapping the subtask toggle (#1012) 2026-05-22 15:36:46 +01:00
Carlos Florêncio a74409af3c fix(web): cap clarification overlay height and add mock agent ask commands (#956) 2026-05-19 22:27:24 +01:00
Carlos Florêncio 2bfdd518b6 fix(web): improve inline code chip visibility in markdown (#948) 2026-05-19 17:56:35 +01:00
Carlos Florêncio e346572371 chore(deps): migrate ACP SDK from agentcooper fork to upstream v0.13.0 (#921) 2026-05-17 19:51:24 +01:00
Carlos Florêncio d7e183847c fix(web): hide stuck Resume session button after click + cover with e2e (#890) 2026-05-13 18:39:59 +01:00
Carlos Florêncio 40c89cd380 fix(web): preserve dockview state across task and plan-mode switches (#855) 2026-05-09 11:59:16 +01:00
José Almeida bce9fd266a feat: multi-question support for ask_user_question_kandev (#828)
* feat(backend): multi-question support for ask_user_question_kandev

Reshape the MCP tool from a single prompt+options pair to a questions[]
array (1-4 entries, single-choice each, custom text fallback). The
clarification HTTP handler gates the response until every question has an
answer, fans out one chat message per question (sharing pending_id, with
question_index/question_total in metadata), and returns a JSON map keyed
by question id back to the agent. The orchestrator resume prompt now
formats multi-line Q1/A1, Q2/A2 summaries when the bundle has more than
one question. Mock-agent gets a clarification-multi scenario and
ask_user_question_test.go covers the new schema + map response. No
back-compat shim — local-first tool, single-PR breaking change.

* feat(web): refresh clarification overlay with multi-question + modern UI

Each per-question chat message gets its own card with a "Question N of M"
progress chip, a ✓ Answered badge once committed, and shadcn-aligned
option buttons with kbd hints. A new useClarificationGroup hook coordinates
the per-question commits (decision A) and posts every answer in a single
batch once the user finishes the bundle; X rejects the whole group. The
single-question case keeps the 1-9 / Esc keyboard shortcuts. Playwright
e2e adds 6 multi-question scenarios (rendering, full happy path, partial
state, mixed option/custom, skip-rejects-bundle, sibling-state) on top of
the existing single-question regression suite.

* fix(web): clarification carousel UX with stepper navigation + race fix

Replaces the vertically stacked card layout with a horizontal stepper:
numbered circle dots up top show step state (active/answered/pending),
the single active question card sits in the middle, and Back / Next /
Submit buttons sit at the bottom. Picking an option auto-advances to the
next step (single-question case auto-submits, no explicit Submit button).
The stepper steps are clickable so users can revise prior answers.
Keyboard shortcuts: 1-9 for option pick, ArrowLeft/Right for navigation,
Esc for skip.

Also fixes a race that surfaced as a 400 BadRequest on the
/api/v1/clarification/:id/respond endpoint when the user clicked an
option before all N messages of a multi-question bundle had streamed in:
findPendingClarificationGroup now gates on metadata.question_total and
returns an empty array until the full bundle has arrived.

Playwright suite expanded from 6 to 12 multi-question scenarios:
stepper rendering, auto-advance, Back, stepper jump, Submit gating,
happy path, mixed custom-text, revise-via-jump, skip-from-mid-step,
number-key shortcuts, Esc skip, first-step Back disabled.

* fix(clarification): address CodeRabbit/Greptile/Claude review comments

Backend:
- Single source of truth for question validation: rename/export
  NormalizeAndValidateQuestions and call it from both the HTTP and the
  WebSocket-side MCP handlers, so duplicate question ids and bad option
  counts can't slip through either path.
- httpRespond now validates that every answer references a real question
  id from the bundle and that no id is answered twice (regression tests
  added).
- questionsFromMessages reorders by metadata.question_index so the
  reconstructed bundle preserves the original question order.
- adapters.CreateClarificationRequestMessages rolls back already-created
  messages when a later write in the bundle fails.
- extractQuestionAnswers always returns a JSON map (even on rejection,
  with an envelope { rejected, reject_reason }) and simplifyAnswer
  preserves both selected_option and custom_text when both are present.
- MCP tool description: rewrite the response example to match the actual
  output shape; add minItems / maxItems to the questions and options
  arrays in the JSON Schema.
- Test helper: drop the local contains() shim, use strings.Contains.

Frontend:
- useMemo([props]) was a no-op (props is always a fresh ref); split into
  [message, messages] so it actually memoizes.
- Drop the dead "expired" SubmitState branch — the backend never returns
  410 from this endpoint.
- Remove the asymmetric option-list dimming: the agent now receives both
  selected_option and custom_text together, so a half-grey state was
  misleading.
- New tests: pending-clarification.test.ts covers
  findPendingClarificationGroup including the question_total gate, and
  use-clarification-group.test.ts covers the hook's record/submit/skip
  flows and the override-merge path used by the single-question case.

* fix(web): treat clarification 409 as success so duplicate submit doesn't stick the overlay

* fix(clarification): unblock agent on persistence failure + nil-guard rejected branch

- Add Store.CancelRequest(pendingID) and call it from both the WebSocket
  MCP handler and the HTTP create-request handler when message creation
  fails. Without it, the agent's WaitForResponse parked for the full
  2-hour MCP timeout while no clarification cards ever reached the user.
  Both handlers now return an explicit error response on failure.
- applyAnswersToMessages now guards h.repo == nil in the rejected branch
  (parity with sibling expectedQuestionIDs).
- extractQuestionAnswers stubs for unanswered questions in a rejected
  bundle now carry { answered: false, rejected: true } so agents reading
  per-question payloads see the rejection without inspecting the
  envelope.
- Hook test: added 409-as-ok regression coverage for both submit and
  skip paths so the previous fix can't drift.
- Store test: covers CancelRequest unblocking a parked WaitForResponse.

* fix: drop unused e2e helper + use channel sync in CancelRequest test

* refactor(web): drop dead 'message' prop from clarification overlay

Both call sites pass 'messages' (the bundle group), so the legacy
single-message prop was unused. Tightening the prop type also lets the
useMemo depend on a single value.

* fix(web): ignore modifier-keyed events in clarification carousel shortcuts

Bare 1..9 / ArrowLeft / ArrowRight / Esc still drive the carousel, but
Cmd/Ctrl+1..9 (browser tab switch) and Alt+ArrowLeft (browser back) now
pass through as the user expects.
2026-05-05 19:14:57 +01:00
Carlos Florêncio b01e6abc06 fix: retry CLI passthrough launch without resume flag after fast-fail (#810) 2026-05-04 08:45:20 +01:00
José Almeida fcc7ceb8b6 fix(approvals): drop stuck pending permission_request messages (#723)
* fix(web): exclude permission_request from turn-complete safety net

The session.turn.completed handler iterated over messages and forced
metadata.status="complete" on anything carrying tool_call_id. Permission
prompts also carry tool_call_id (for FE pairing with their tool_call),
so this loop overwrote the user's "approved" decision on every prompt
in the turn — and the FE component re-rendered the Approve/Deny buttons.

* fix(backend): protect permission_request rows from tool_call sweeps

Three permission_request invariants the prior code violated, mirroring
the FE bug fix:

- CompletePendingToolCallsForTurn: SQL UPDATE filtered by tool_call_id
  presence, also catching permission_request rows. Add type filter so
  the safety net only touches actual tool messages.
- GetMessageByToolCallID: returned the oldest row carrying that
  tool_call_id, which races to the permission_request when timing
  shifts. Exclude permission_request type so a tool_update can never
  land on the user's approve/reject row.
- applyToolCallMessageUpdate: defensive guard that refuses to overwrite
  a permission_request, making the invariant explicit at the layer that
  does the writing.

Adds a regression test for CompletePendingToolCallsForTurn covering
approved/rejected/pending permission rows.

* test(e2e): cover approval-reappear regression with mock-agent scenario

Adds a multi-permission mock-agent scenario (three sequential bash
tools, each requiring approval) and an E2E test that approves all
three and asserts no permission action row remains visible after
the agent's turn ends, and that the resolved state survives a reload.

Supporting test infrastructure:
- data-testid hooks on PermissionActionRow.
- permissionActionRows() / permissionApproveButtons() on SessionPage.
- backend fixture force-disables AGENTCTL_AUTO_APPROVE_PERMISSIONS=false
  so a developer's local AUTO_APPROVE=true env doesn't silently bypass
  the permission UI in tests that exercise the approve/reject flow.

* test(backend): cover GetMessageByToolCallID permission_request exclusion

Addresses claude-review feedback on the approvals fix:
- Adds a regression test that seeds both a permission_request and a
  tool_call with the same tool_call_id (permission_request created
  first, so an ORDER BY created_at ASC sweep without the type filter
  would race to it) and asserts the lookup returns the tool_call row.
- Bumps the applyToolCallMessageUpdate invariant guard from Warn to
  Error: reaching that branch means a caller bug, not a transient
  condition, and Warn would silently swallow the violation.

* fix(e2e): scope auto-approve override to permission-approval test only

The previous fixture force-disabled AGENTCTL_AUTO_APPROVE_PERMISSIONS
globally, which broke session-isolation.spec.ts and other tests that
use scenarios with permission-required tools (e.g. /e2e:read-and-edit)
and rely on auto-approve to let the agent finish without UI clicks.

Default the env to "true" in the fixture; let permission-approval.spec
flip it to "false" via a backend.restart() override in beforeAll, then
restore in afterAll. Adds an envOverrides parameter to backend.restart.
2026-05-01 00:25:51 +01:00
José Almeida 7e8b4bb30e feat(quick-chat): eager-init agent on profile selection (#747)
* feat(quick-chat): eager-init agent on profile selection

Switch quick-chat backend from `IntentPrepare` to `IntentStart` so the
agent process boots immediately when the user picks a profile, instead
of waiting for the first prompt. The ACP `session/new` handshake fires
before the user types anything, so the slash menu, mode dropdown, and
model selector are populated up-front. Fixes the empty-slash-menu UX
in quick chat for ACP agents (OpenCode, Claude, Codex, etc.).

Frontend picker shows a per-card spinner + disables sibling cards
during boot. Rapid profile switches (and other picker-bypassing
actions like opening a new tab, switching tabs, or closing the modal)
supersede the in-flight start via a monotonic request id; the
resolved task is cleaned up via `deleteQuickChatTask` so we never
orphan an ephemeral task or its agent process.

Backend rollback uses a fresh background context so `DeleteTask`
runs even when the request context has already been cancelled by
the client.

`mock-agent` now emits `available_commands_update` from `NewSession`
and `LoadSession` (matching real OpenCode/Claude) so the eager-init
pipeline is exercised in e2e. Existing prompt-time emit kept as an
idempotent fallback.

* test+cleanup(quick-chat): unit tests for useAgentSelection; minor cleanups

- Add 5 unit tests for useAgentSelection covering happy path, rapid-pick
  supersession, reset() during in-flight, and error toast vs silent-on-superseded.
  Exercises the orphan-task cleanup that the eager-init flow depends on.
  (claude bot review)
- Drop redundant isDisabled alias in AgentPickerView. (claude bot review)
- Drop unused ctx parameter from emitAvailableCommandsAfterDelay — it was
  always called with context.Background() so the Done() branch was dead
  code. (claude bot review)
- Re-format with prettier after the rebase.

* fix(quick-chat): use constants.TaskDeleteTimeout for rollback ctx

Match the other DeleteTask call sites in task_http_handlers.go (line 851)
instead of an ad-hoc 10s timeout. (claude bot review)
2026-05-01 00:21:53 +01:00
Carlos Florêncio 74d44bd26b feat(acp): support claude-acp Monitor tool and fix incremental tool_call updates (#698) 2026-04-25 16:26:20 +01:00
Carlos Florêncio 66f0cc2a16 fix(web): persist agent profile mode through bulk-edit save (#626) 2026-04-19 11:34:43 +01:00
Carlos Florêncio 181a64a5fb fix: prevent utility agents settings page crash on null models (#602) 2026-04-17 14:22:34 +01:00
Carlos Florêncio 2ae996a2c1 fix(agentctl): register MCP tools with _kandev suffix to match sysprompt (#572) 2026-04-10 17:17:42 +01:00
Carlos Florêncio e519d182fb chore: add dedicated sub-agents for skill delegation (#497) 2026-03-30 10:17:22 +01:00
Carlos Florêncio 3a50cf42e5 fix(web): show both send and cancel buttons when agent is busy (#487) 2026-03-29 22:13:39 +01:00
Carlos Florêncio 116895b4ff fix: resolve symlinks in file tree so symlink-to-directory entries show as folders (#467) 2026-03-25 23:00:05 +00:00
Carlos Florêncio df70eee749 fix(web): merge chat status bar into single row and switch task on archive (#460) 2026-03-24 23:22:20 +00:00
José Almeida f06577e989 fix: include uncommitted changes in review dialog cumulative diff (#447)
* fix: include uncommitted changes in review dialog cumulative diff

The review dialog only showed uncommitted changes instead of the full
diff from the task's base commit. Two issues combined:

1. Backend used `git diff base..HEAD` (committed only); changed to
   `git diff base` which compares against the working tree.
2. Frontend gave priority to git status over cumulative diff; reversed
   the merge order so cumulative diff takes precedence.

Adds E2E test with a mock-agent scenario that commits changes then
leaves uncommitted modifications, verifying the review dialog shows
the complete base→working-tree diff.

* fix(e2e): remove incorrect BASE_CONTENT assertion in review cumulative diff test

The file is created after the base commit, so the entire file shows as
added in the cumulative diff. BASE_CONTENT was replaced and doesn't
appear. The key assertion is that COMMITTED_CHANGE is visible — proving
the diff includes committed changes (not just the uncommitted portion).

* fix: address CodeRabbit review feedback

- Update 3 docstrings to reflect working-tree diff (not HEAD)
- Generate scenario list dynamically in error message
- Use data-testid selector in E2E test for resilience

* style: format E2E test file

* fix(e2e): use toContainText and click file to ensure diff is scrollable

Pierre diff viewer content inside a scroll container may not be
considered "visible" by Playwright. Switch to toContainText which
checks text presence without element-level visibility. Also click
the file in the tree to ensure its diff section is scrolled into view.
2026-03-18 00:24:10 +00:00
Carlos Florêncio bb0c63e73b fix: resolve model selector mismatch for ACP agents (#410) 2026-03-10 22:13:28 +00:00
Carlos Florêncio bb1caaba11 feat: add ACP agent variants for Claude, Codex, Copilot, and Amp (#387) 2026-03-10 17:30:04 +00:00
João Salavisa 815fb5b24e fix: refresh diff view when untracked files change (#372) 2026-03-05 15:18:30 +00:00
Carlos Florêncio a34693e993 feat: improve session recovery and context reset (#369) 2026-03-05 00:30:50 +00:00
Carlos Florêncio c73fa7471b fix: resolve clarification MCP timeout with cancel-and-resume flow (#362) 2026-03-05 00:18:57 +00:00
Carlos Florêncio 124fe588f8 feat: improve TUI agents session resume on restart (#367) 2026-03-04 23:34:26 +00:00
João Salavisa b0a85e6471 fix: restore git status update in workspace polling loop (#364) 2026-03-04 12:22:50 +00:00
José Almeida c79d138c45 feat(web): add diff expansion with expand-all in review panel (#340)
* feat(backend): add support for fetching file content at git ref

Add GetFileContentAtRef method to WorkspaceTracker for retrieving file content
at specific git refs (branches, commits, HEAD). This enables diff expansion by
fetching old file versions without checking out.

Changes:
- Extract maxFileSize constant to package level (10MB)
- Add GetFileContentAtRef to workspace_files.go using git show
- Add workspace.file.get_at_ref WebSocket action and handler
- Add agentctl client method for the new endpoint
- Register handler in workspace file handlers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(web): add diff expansion support for code review

Add lazy-loaded diff expansion to show more context in code reviews. When expansion
is enabled, users can expand hunks to see more surrounding code by clicking expand
buttons. Full file content is fetched on-demand via WebSocket.

Changes:
- Add useExpandableDiff hook for lazy-loading old/new file content
- Add requestFileContentAtRef to workspace-files.ts
- Integrate expansion into diff viewer components
- Add enableExpansion and baseRef props to DiffViewer
- Auto-load expansion content when enabled
- Pass expansion state through diff viewer hierarchy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(web): gracefully handle expansion props for Monaco diff viewer

Monaco diff viewer has built-in expansion that doesn't require fetching
old file content. Strip pierre-diffs-only expansion props (enableExpansion,
baseRef) when Monaco is selected to avoid passing unsupported props.

This ensures the feature works correctly regardless of which diff viewer
the user selects in settings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(backend): add diff expansion e2e scenario and fix unstaged diff base ref

- Add scenarioDiffExpansionSetup mock-agent scenario that creates a
  200-line file, commits it, then modifies lines 50 and 150 to produce
  a two-hunk uncommitted diff for testing diff expansion in the UI
- Add workspace_file_handlers for workspace.file.get_at_ref WS action
- Fix enrichWithDiffData to always diff against HEAD for unstaged/staged
  content so locally committed files show correct diffs
- Add unit tests for GetFileContentAtRef (6 sub-tests)

* feat(web): add diff expansion UI and e2e test

- Wire useExpandableDiff hook into FileDiffViewer and ReviewDiffList
  with enableExpansion and baseRef props
- Gracefully handle expansion props for Monaco diff viewer fallback
- Add e2e Playwright test for diff expansion between hunks

* fix(web): fix diff expansion by correcting hunk separators and line splitting

Three bugs prevented @pierre/diffs expand buttons from rendering:
- hunkSeparators was "simple" (no expand UI); changed to "line-info" when expansion enabled
- expandUnchanged:true showed all lines expanded (no separators); removed the option
- .split("\n") stripped trailing newlines; now uses SPLIT_WITH_NEWLINES regex to match library

* feat(web): add editor provider settings UI

Add an "Editor Providers" section to the Editors settings page with
Select dropdowns for each configurable context (Code Editor, Diff Viewer,
Chat Code Blocks, Chat Diff Blocks). Reads from and writes to the
existing localStorage-backed editor resolver store. Changes apply
immediately without requiring a save action.

* test(web): add e2e tests for editor provider settings

Verify that the editor provider dropdowns render with correct defaults,
update on selection, and persist changes across page reloads via
localStorage.

* feat(web): add expand/collapse unchanged regions toggle to diff toolbar

Refactor diff header toolbar into composable ToolbarButtons component and
add a toggle button to expand or collapse unchanged regions in both
Pierre Diffs and Monaco diff viewers. Pass enableExpansion through to
Monaco to control hideUnchangedRegions.

* fix(web): handle deleted files in diff expansion

Treat "file not found" / "no such file" errors as empty content instead
of throwing, so diff expansion works correctly for deleted files.

* chore(web): add diff expansion debug e2e helpers

* test(web): split diff expansion tests by provider (Pierre Diffs + Monaco)

Restructure diff-expansion e2e tests into two describe blocks, one per
diff viewer provider. Each block sets the provider via localStorage
before navigation and verifies the correct viewer renders:

- Pierre Diffs: checks for diffs-container element and shadow DOM
  expand buttons between hunks
- Monaco: checks for .monaco-diff-viewer wrapper and the built-in
  hideUnchangedRegions widget with "Show Unchanged Region" link

Both suites verify that clicking expand reveals collapsed middle lines.

* fix(web): fix Pierre Diffs expand button selectors in e2e tests

Use shadow DOM data attributes ([data-expand-button], [data-expand-up])
instead of XPath parent traversal which doesn't work inside shadow DOM.
Wait for expand buttons to load asynchronously before clicking.

* fix(e2e): make diff-expansion-setup scenario idempotent

The mock-agent scenario now removes and re-commits the test file before
each run, so subsequent tests in the same repo don't fail with "git
commit failed" when the file already exists. Also increase test timeouts
to match other heavy e2e tests.

* refactor(web): remove editor provider settings UI, enable expand-all in review

Remove the editor provider switching UI and its tests — Monaco's diff
expansion doesn't work and exposing provider switching adds confusion.
Show Pierre Diffs header toolbar in the review panel (remove hideHeader)
so the expand-all button is accessible. Add e2e test for expand-all.

* style(web): fix prettier formatting and lint warnings

Run prettier on files with formatting drift. Extract ToolbarBtn helper
in diff-header-toolbar to stay within max-lines-per-function limit.
Consolidate useMonacoDiffViewerState to reduce line count.

* chore(web): remove debug scaffolding, revert Monaco changes, drop stray console.log

Revert Monaco diff-viewer-toolbar and monaco-diff-viewer to main
(expansion not functional with Monaco). Remove debug-expansion
screenshot scripts and spec. Strip console.log from commit-detail-panel.
Strip enableExpansion from Monaco path in diff-viewer-resolver.

* fix(web): use commit-relative base ref for diff expansion

Use `${commitSha}^` instead of hardcoded `HEAD~1` so expansion fetches
the correct old content when viewing non-HEAD commits.

* fix(web,backend): address CodeRabbit review feedback

- Add aria-label to icon-only toolbar buttons for screen reader access
- Guard auto-load expansion effect against error state to prevent retry
  loops when WebSocket fetch fails
- Invalidate expansion cache on file/ref change with request versioning
  to prevent stale content
- Preflight blob size with git cat-file -s before git show to avoid
  memory spikes on large files

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 00:05:39 +00:00
Carlos Florêncio ee59ccdfbb feat: tui agents with workflows and code quality improvements (#360) 2026-03-03 22:59:22 +00:00
Carlos Florêncio 2aab682cd8 fix: sidebar task switcher shows outdated session state (#349) 2026-03-02 20:15:48 +00:00
Carlos Florêncio 44811da702 feat: web e2e tests (#304) 2026-03-02 08:54:58 +00:00
Carlos Florêncio b3f1eaa037 feat: mermaid support (#293) 2026-02-26 13:24:40 +00:00
Carlos Florêncio 61ef224ec7 style: fix format issues (#255) 2026-02-19 22:18:01 +00:00
Carlos Florêncio fd4ae1eb54 fix: resolve all backend golangci-lint violations (#245) 2026-02-18 18:24:24 +00:00
Carlos Florêncio 4d41155158 feat: mock agent (#208) 2026-02-07 17:48:04 +00:00