Commit Graph

83 Commits

Author SHA1 Message Date
Carlos Florêncio 3e2aba45ed fix(agentctl): sticky-max context window size with reset on model switch (#1254) 2026-06-02 22:58:31 +01:00
João Salavisa 6a684211fc fix(agentctl): reap disconnected ACP sessions + MCP child trees (#1249)
* fix(agentctl): reap disconnected ACP sessions + MCP child trees (#1247)

Two independent leaks let opencode acp sessions accumulate indefinitely:

1. instance.Manager never reaped disconnected sessions. StopInstance
   only ran via the kandev DELETE route, so any session whose backend
   went away (UI closed mid-run, WS dropped, opencode failed to emit
   complete) was orphaned forever.
2. Even when DELETE fired, the ACP adapter unconditionally returned
   RequiresProcessKill=false. opencode acp keeps an HTTP server + MCP
   child tree alive after stdin EOF, so closing stdin was a no-op and
   the children re-parented to init.

Fix both:

- Plumb RuntimeConfig.RequiresProcessKill from agents.OpenCodeACP
  through the ExecutorCreateRequest -> CreateInstanceRequest ->
  InstanceConfig -> adapter.Config -> shared.Config chain. acp.Adapter
  now reads cfg.RequiresProcessKill instead of hardcoding false.
- Belt-and-braces: process.Manager.waitForProcessExit timeout fallback
  now killProcessGroup first (only falls back to single-process kill
  if that errors), so any future ACP CLI that ignores stdin EOF still
  gets reaped.
- Add an idle-instance reaper to instance.Manager. Per-instance
  activity middleware tracks inflight HTTP requests + lastActivity;
  a background goroutine sweeps every minute and StopInstance's any
  instance idle past KANDEV_ACP_IDLE_TIMEOUT (default 1h, set to 0
  to disable). Long-lived /agent/stream WS connections keep the
  inflight counter above zero so active sessions are never reaped.
- Validate stdio MCP commands at CreateInstance time via
  exec.LookPath; missing entries are dropped with a warn instead of
  spawning a permanently broken child every session (fixes the
  stale /snap/bin/brave MCP repro in the issue).

Regression tests: process-group kill (parent+child fixture), idle
reaper end-to-end, MCP validation, opencode-acp opt-in vs other
ACP agents' default.

* fix: address PR review feedback on #1247 fix

- idle_reaper: extract reapSingleIdleInstance helper with defer cancel(),
  add reaperStop polling between sweep iterations so Shutdown drains in
  one StopInstance window instead of N * timeout (cubic, claude, greptile).
- instance.Manager: use sync.Once instead of m.mu to gate reaper-stop
  channel close (claude).
- mcpStdioValidationError: tolerate compound Command strings by
  resolving only the first whitespace-delimited token; reject entries
  with neither URL nor Command outright; document agentctl-vs-agent
  PATH skew in Docker/SSH executor modes (claude, greptile, cubic).
- manager_killgroup_test: treat zombie state as dead via /proc/<pid>/stat
  on Linux + bump Eventually window to 15s — CI containers' PID 1 can
  delay harvesting orphans long enough to flake signal(0) probes.
- instance package: add goleak TestMain for the new reaper goroutine
  (coderabbit).
- AGENTS.md: correct SIGKILL vs SIGTERM wording; clarify the timeout
  fallback only fires on ctx.Done (coderabbit, cubic).

---------

Co-authored-by: Kandev Agent <agent@kandev.dev>
2026-06-02 21:46:49 +01:00
Carlos Florêncio fac2ad5039 fix(backend): stabilize ACP session resume and workspace git poll under contention (#1242) 2026-06-02 21:22:45 +01:00
João Salavisa a1143aa525 fix(acp): handle claude-acp async_launched subagents end-to-end (#1244)
* fix(acp): handle claude-acp async_launched subagents end-to-end

Claude Agent SDK's Task tool with run_in_background=true returns
session/prompt with stop_reason=end_turn while subagents stay alive
in the background, reporting `_meta.claudeCode.toolResponse.status =
"async_launched"` instead of a terminal top-level status. kandev
previously treated stop_reason as authoritative, cancelled the
subagent card on prompt return, and fired an "agent finished without
producing any output" notice — even though the dispatch did produce
work and the subagent's child events would arrive seconds later.

Backend:
- `SubagentTaskPayload` gains `IsAsync` / `OutputFile` /
  `CanReadOutputFile` so the async-launched envelope is preserved.
- `convertToolCallResultUpdate` recognizes async_launched as terminal
  for the Task tool itself (dispatch is the completion).
- `cancelActiveToolCalls` preserves subagent_task tool calls through
  the prompt-return sweep so a late terminal tool_call_update from
  the SDK still lands correctly (covers the in-turn-complete case).

Frontend:
- `subagentMetaChips` emits a "background" chip when `is_async` or
  `status == "async_launched"` so the card is visually distinct.
- `computeEmptyTurnNotice` suppresses the notice when any subagent
  task message exists for the turn (the dispatch IS output).

Reproduced via `acpdbg prompt` against `claude-acp` 0.31.1; captured
frames in acp-debug/claude-acp-prompt-20260602-110119.jsonl drive the
backend test fixtures verbatim.

* fix(acp): harden async_launched override against future SDK frames

Address PR review feedback (greptile #1244, claude review):

- Move the async_launched override inside the mutex lock so it can
  inspect the stored payload kind before flipping the status.
- Drop the `status == ""` precondition. The earlier in_progress
  synthesis (Title/RawInput/Content/Locations) was implicitly trumping
  the override; a future SDK frame that combines async_launched with
  any of those fields would have left the card stuck in_progress
  forever. The override is now unconditional for async_launched
  subagent_task frames.
- Gate the override on `payload.Kind() == ToolKindSubagentTask`. A
  hypothetical future claude-acp tool that reuses the `async_launched`
  literal in its own `_meta.claudeCode.toolResponse.status` would have
  been incorrectly marked complete by the prior unscoped check.

Pinned by two new tests:
- TestConvertToolCallResultUpdate_AsyncLaunched_OverridesInProgress
- TestConvertToolCallResultUpdate_AsyncLaunched_NonSubagentNotTerminated

---------

Co-authored-by: Kandev Agent <agent@kandev.dev>
2026-06-02 14:30:36 +01:00
Carlos Florêncio 0f87f7a56b fix(acp): enrich tool call metadata per agent with structured ACP fields (#1212) 2026-06-01 19:12:32 +01:00
Carlos Florêncio 13e6e2d89b fix(acp): serialize wakeup prompts to prevent turn misalignment (#1202) 2026-05-31 21:12:36 +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 700ff4199c fix(agentctl): write ACP debug logs under KANDEV_HOME_DIR (#1196) 2026-05-31 17:10:08 +01:00
Carlos Florêncio a10e81c0d7 fix: preserve whitespace in acp message chunks (#1190) 2026-05-31 12:31:56 +01:00
Carlos Florêncio 4da076c43e feat(backend): per-session ACP debug logs with rotation and retention (#1172) 2026-05-30 19:10:09 +01:00
João Salavisa cab7b28ed9 chore: round 4 dead-code cleanup (transport helpers, detect, orphan methods) (#1156)
* chore(agentctl): delete duplicate procattr files in adapter package

setProcGroup and killProcessGroup are defined in both
agentctl/server/adapter/ and agentctl/server/process/. The process/
copies are the live ones (called by process/runner.go, manager.go,
vscode.go); the adapter/ copies have zero callers and are removed.

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

* chore(agentctl): remove orphan helpers from transport/shared

Left over from the ACP refactor. All had zero callers:
- DebugEnabled(): internal debugMode var is checked directly by
  LogRawEvent/LogNormalizedEvent — the exported wrapper was unused.
- GetBool, GetMap, GetSlice: only GetString/GetInt are called in acp/normalize.go.
- NormalizeShellResult, NormalizeReadResult, NormalizeCodeSearchResult,
  NormalizeModifyResult: normalization moved to acp/normalize.go.
- TruncateIfNeeded, MaxContentLength, MaxFileCount: only used by the
  four Normalize* helpers above; removed transitively.
- TraceControlMessage: zero callers in the adapter transport layer.

GenerateUnifiedDiff, SplitLines, DetectLanguage, Tracer, ShutdownTracing,
TraceProtocolEvent, TraceProtocolRequest are alive and kept.

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

* chore(agentctl): remove unused tool_payload constructors

NewHttpRequest, NewCreateTask, NewSubagentTask, NewShowPlan,
NewManageTodos, and NewMisc have zero callers — ACP normalization
builds NormalizedPayload via struct literals and JSON unmarshaling,
not these factory functions. NewReadFile, NewModifyFile, NewShellExec,
NewCodeSearch, and NewGeneric are kept (live callers in acp/normalize.go).

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

* chore(agents/detect): remove dead fluent options and OSPaths type

WithFileExists, WithCommandOutput, WithEnvVar, expandHomePath (their
transitive helper), and OSPaths (struct + Resolve + Expanded) have
zero callers. Only WithCommand and WithNpxRunnable are used by agent
IsInstalled implementations. Imports trimmed to context and os/exec.

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

* chore(office): remove dead channel methods superseded by service/

ListComments, DeleteComment, and UpdateChannelStatus on ChannelService
have zero callers — the live implementations live in
internal/office/service/comments.go and service/channels.go.
CreateComment is kept: it is called by HandleChannelInbound.

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

* chore: remove scattered orphan helpers

Remove dead single-symbol exports verified to have zero callers:
- ParseCronExpression (office/shared/cron.go): NextCronTime covers
  all live usages; the validator wrapper was unused.
- IsValidPathComponent, MustJSON (office/shared/helpers.go): zero
  callers; GenerateSlug is kept.
- DiscoverUserSkillsAt (office/skills/userhome_discovery.go): exported
  wrapper over the private discoverUserSkillsAt; only the internal
  DiscoverUserSkills method is wired up.
- Manager.Get (agent/loginpty/manager.go): zero callers; GetByID and
  Stop are kept (Stop is tested in manager_test.go).
- DetachedWithValues (common/appctx/appctx.go): zero callers; Detached
  is kept.
- Repository.Close no-ops (task/share, terminal/repository): both are
  documented no-ops with zero callers.
- TaskBranchName (worktree/config.go): zero callers; the deterministic
  TaskBranchNameWithSuffix is kept.

Note: dialect.Now was initially targeted but is tested in
dialect_test.go (same-package call — missed by package-qualified grep).
It remains unchanged.

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

* chore(share): remove stale Close reference from provider.go comment

Repository.Close() was removed as a no-op in the round-4 cleanup.
The comment in provider.go still referenced it by name; updated to
reflect that the repo simply doesn't own its DB connections.

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

* chore(office/shared): delete helpers.go — GenerateSlug had zero callers

The triage step mistakenly identified skills/service.go as a caller,
but that package defines its own local GenerateSlug (different regex,
adds TrimSpace and a 'skill' fallback default). shared.GenerateSlug
was never called anywhere. helpers.go is now empty; delete the file.

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

* chore(worktree): fix stale TaskBranchName reference in TaskBranchNameWithSuffix doc

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

---------

Co-authored-by: Kandev Agent <agent@kandev.dev>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:18:10 +01:00
José Almeida b109c84e4e fix(backend): pass HTTP MCP servers to ACP agents via AssumeMcpHttp (#1152)
* fix(backend): pass HTTP MCP servers to ACP agents via AssumeMcpHttp

* test(backend): cover AssumeMcpHttp override path with effectiveMcpCapabilities helper
2026-05-29 12:58:51 +01:00
João Salavisa 7b75d4c39d refactor(acp): split adapter.go into per-concern files (#1054)
* refactor(acp): split adapter.go into per-concern files

Pure file split of the 2,083-line transport/acp/adapter.go into sibling
files inside the same package — no behavior change, no new types, no
signature changes. The struct, constructor, lifecycle, and locking-
sensitive helpers (sendUpdate, trace ctx, Close) stay co-located in
adapter.go (422 lines); session/mcp/auth, prompt/cancel/wakeup, update
dispatch, tool-call conversion, permission flow, and cross-file helpers
each move to their own file, all under the 800-line lint cap.

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

* refactor(acp): restore struct doc wording on availableAuthMethods

independent-review fix: the file split should have been byte-identical for
comments. Restore "surface a picker" (matches origin/main) — accidentally
rewritten as "drive a picker" during the adapter.go rewrite in ccfad56d.

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

* ci(acp): extract toolStatusInProgress / toolStatusCancelled constants

CI golangci-lint flagged 'in_progress' (9 occurrences) and 'cancelled'
(4 occurrences) as goconst violations after the file split surfaced them
as "new" lines. Extend the existing toolStatus* constant set in
normalize.go and use the new constants at every production call site
(adapter_tools.go, adapter_prompt.go, monitor.go). Behavior unchanged.

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

---------

Co-authored-by: Kandev Agent <agent@kandev.dev>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 23:22:21 +01:00
Carlos Florêncio 21db57bdfd fix(orchestrator): repair worktree state and prompt persistence on resume (#1121) 2026-05-28 21:48:12 +01:00
João Salavisa 76143f8159 fix(acp): restore ScheduleWakeup wire string broken by Wakeup→Run rename (#998)
PR #914 globally renamed Wakeup→Run in the ACP transport, including the
wire-level tool name check (`name != "ScheduleRun"`). That string is
hardcoded by the Claude Code SDK binary as `ScheduleWakeup`, so the
bridge's tool-call frames stopped matching and every Claude wakeup
silently never fired: kandev never armed the timer, never sent the
synthetic session/prompt, and the SDK's buffered wakeup turn only
drained when the user typed a new message.

Commit 0b2c59a2's lifecycle fix (publish AgentReady on wakeup turns)
relied on the wakeup turn actually firing — which it wasn't — so the
fix appeared not to work in production.

Restore the wire string to `"ScheduleWakeup"` and rename the surrounding
Go symbols back to wakeup-naming (`wakeupScheduler`, `pendingWakeup`,
`handleWakeupEvent`, `fireWakeup`, `wakeupPromptTimeout`) so the next
contributor can't repeat the rename. Add a comment at the match site
warning that the string is externally hardcoded, plus a negative
regression test asserting `"ScheduleRun"` is NOT recognised as a wakeup.

Co-authored-by: Kandev Agent <agent@kandev.dev>
2026-05-21 21:29:30 +01:00
João Salavisa 0b2c59a2dd fix(lifecycle): publish AgentReady on wakeup-driven turns (#875)
* fix(lifecycle): publish AgentReady on wakeup-driven turns

Wakeup turns flow Adapter.Prompt → bridge → events, bypassing
SessionManager.SendPrompt. The execution status stayed Ready across
the wakeup turn, so MarkReady's duplicate-suppression guard dropped
the second AgentReady — the orchestrator never closed the turn,
never evaluated on_turn_complete, and never dispatched queued
messages. Detect this in recordActivity and flip Ready → Running on
the first non-terminal event, re-emitting AgentRunning so the rest
of the pipeline behaves like any other turn.

* fix(lifecycle): gate wakeup flip on turn-content events and handle empty turns

Three follow-ups on the wakeup AgentReady fix:

1. Restrict the Ready → Running flip in `recordActivity` to events that
   unambiguously indicate turn-in-progress activity (message_chunk,
   reasoning, tool_call/update, plan, agent_plan, permission_request).
   The original whole-event-type flip caused a regression: claude-agent-acp
   emits available_commands_update asynchronously ~50ms after session/new,
   well after dispatchInitialPrompt fires MarkBootReady for a no-prompt
   task. The Ready → Running flip on that delayed metadata event was
   putting newly-created tasks back into Running and breaking the chat-
   input UI (changes-panel-focus E2E tests).

2. Handle the empty-wakeup edge case: a wakeup turn that emits only a
   `complete` event (empty model response) is still excluded from the
   flip whitelist, so the Ready guard in MarkReady would suppress
   AgentReady. `handleCompleteEventMarkState` now publishes AgentReady
   directly when Status is already Ready on a successful complete —
   the orchestrator still closes the turn for empty wakeup responses.

3. Fold the `executionStore != nil` check into the early-return so the
   AgentRunning publish only fires when the status flip actually succeeded.

Test-file cleanup from review feedback: dead loop, redundant
`var _ = io.MultiReader`, and `teeReader.src any` → `io.Reader`.

New regression tests:
- TestWakeup_PostBootMetadataEventsDoNotFlipToRunning — locks in the
  whitelist behavior so future events can't accidentally re-arm a
  boot-ready session.
- TestWakeup_EmptyTurnStillPublishesAgentReady — covers the
  empty-wakeup-complete fallback.

* fix(lifecycle): publish AgentRunning before AgentReady on empty wakeup turns

Follow-up on the previous wakeup fixes — addresses three issues raised in
review:

1. **Empty-wakeup AgentReady was ignored by the orchestrator.** The fallback
   in `handleCompleteEventMarkState` published AgentReady when Status was
   already Ready, but `handleAgentReady` at the orchestrator early-returns
   when `session.State != Running/Starting`. After the previous turn ended
   the session is in WaitingForInput, so the AgentReady got silently
   dropped — same suppression the wakeup fix was meant to prevent. Now the
   fallback flips Ready → Running + publishes AgentRunning first (mirroring
   `recordActivity` for the non-empty case), then falls through to MarkReady.

2. **firstActivityOnce could still publish AgentRunning on a late
   metadata event.** Gate it on `Status != Ready` so a delayed
   `available_commands_update` arriving after MarkBootReady (the original
   regression scenario) can't slip through via the once-per-execution path.
   In practice the adapter always emits `agent_capabilities` during
   Initialize before MarkBootReady, so firstActivityOnce still fires there
   with Status==Running — this is defensive hardening.

3. **Tighter test assertions.** The post-boot-metadata test now primes
   firstActivityOnce in setup and asserts strict `runningCount == 0`.
   The second-turn test verifies AgentRunning precedes each AgentReady in
   bus order so the orchestrator's session-state guard isn't violated.
   Same ordering check added to the empty-wakeup test.

* test(lifecycle): rename exec to agentExec to avoid os/exec shadow

The test variable `exec` in wakeup_e2e_test.go shadowed the imported
`os/exec` package — harmless today because all `exec.Command`/`LookPath`
calls happen before the local binding, but a future call added below
would silently fail. Rename to `agentExec` to remove the shadow.

* ci: retrigger CodeQL after transient Ruby analyze flake

The default-setup CodeQL run on PR #875 produced a flaky 'CodeQL could
not process any code written in Ruby' failure on the Ruby analyze job
(github.com/kdlbs/kandev/actions/runs/26124163769). The repo has no
Ruby code and main's CodeQL only analyzes javascript-typescript +
actions; the Ruby job was added dynamically and failed on the empty
diff. Sibling run 26124163815 on the same SHA passed. Cannot rerun
default-setup workflows via the API (403 'cannot be retried'), so
push an empty commit to retrigger the analysis.

* test(lifecycle): tighten wakeup test assertions

- wakeup_simulated_test.go: assert exact readyCount==2 instead of <2 so
  any over-emission (e.g. duplicate AgentReady on the wakeup turn) is
  also caught.
- wakeup_e2e_test.go: fail with t.Fatalf when the adapter surfaces no
  WAKEUP text instead of logging a warning. Otherwise the bus-level
  assertions below pass vacuously if the wakeup never fires.

Both fixes address review comments from cubic-dev-ai / claude[bot] on
PR #875.

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

* test(lifecycle): remove unsynchronised SessionID write in forwarder goroutine

The forwarding goroutine wrote to agentExec.SessionID without holding
the executionStore mutex, racing with the main goroutine's authoritative
assignment after NewSession returns. The forwarder's write is redundant
— line 264 sets the canonical value — and benign in practice, but
`go test -race` would flag it. Drop the write to keep the race detector
clean.

Addresses review comment from claude[bot] on PR #875.

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

---------

Co-authored-by: Kandev Agent <agent@kandev.dev>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 01:37:03 +01:00
José Almeida 7115ee08d5 fix(acp): stop inventing currentModelId from AvailableModels[0] (#947)
* fix(acp): stop inventing currentModelId from AvailableModels[0]

When session/new returned an empty currentModelId, the adapter fell back
to AvailableModels[0]. Auggie returns an alphabetically-sorted list whose
[0] is a pseudo-agent ("Build Analyzer"), so the UI showed the wrong
model on every fresh load and session resume.

Drop that fallback (the configOption-based fallback stays — that one is
legitimate). When neither CurrentModelId nor a model-shaped configOption
provides a value, emit empty and let the frontend resolve to the profile
or snapshot model.

Also emit a session_models convergence event after SetModel succeeds,
so the UI updates after the lifecycle manager applies the profile model
at session init and after user-driven /session/set_model calls. Cache
configOptions alongside availableModels for inclusion in that event.

* fix(acp): tighten SetModel convergence event semantics

Address PR #947 review feedback:

- Bind the convergence event to the session captured under the same
  RLock used to read the connection. `SetModel` now snapshots
  `sessionID`, `available`, and `cachedConfig` together and passes
  them into `emitSetModelEvent`, so a concurrent session switch can
  no longer route the event to the wrong target.

- Rewrite the model-shaped configOption's `CurrentValue` to the new
  `modelID` before emitting. Without this the event carried
  `CurrentModelID = <new>` alongside `ConfigOptions[model].CurrentValue
  = <old>` — a latent inconsistency for codex-style consumers that
  read the option value. The cached slice is copied first so the
  caller's snapshot is not mutated.

- Refresh `availableConfigOptions` under `Lock` from inbound
  `ConfigOptionUpdate` notifications, so a subsequent `SetModel`
  convergence event uses the latest options instead of the
  session/new snapshot.

- Log the convergence event with `session_id` and `model_id`, matching
  the logging already on `emitSessionModels`.

- Extract a `configOptionIDModel` constant for the well-known "model"
  ID (silences goconst on the new helper).

Tests: extend `TestEmitSetModelEvent_EmitsSessionModelsWithCachedState`
to assert the `CurrentValue` rewrite and the caller-slice
no-mutation guarantee; add `TestConfigOptionUpdate_RefreshesCachedConfig`
to pin the cache refresh.

* test(acp): tighten ConfigOptionUpdate cache-refresh assertions

Address two minor follow-up suggestions from Claude on PR #947:

- Add a comment to emitSetModelEvent noting that the cachedConfig
  copy is shallow (Options shares the caller's backing array) — safe
  today because only CurrentValue is mutated, but worth flagging in
  case a future caller mutates Options in place.

- Have TestConfigOptionUpdate_RefreshesCachedConfig assert that the
  returned event's CurrentModelID resolves to the fresh value from
  the refreshed configOption, so the test pins both the cache update
  and the event payload in one place.

* test(acp): cover Category-based model option rewrite path

Address Claude's follow-up suggestion on PR #947: the previous test
only exercised the ID == "model" branch of emitSetModelEvent's
CurrentValue rewrite, so an accidental drop of the
Category == "model" branch would have passed. Add a third entry
with Category: "model" (and a non-matching ID) and assert both
matched options are rewritten while the unmatched one is untouched.
2026-05-19 14:18:51 +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 0b2085688b feat(office): autonomous agent management layer (#914) 2026-05-16 20:07:57 +01:00
Carlos Florêncio 7ce2e24150 feat(backend): add 10 ACP agents, set_config_option, auth_required flow (#807) 2026-05-04 07:46:56 +01:00
João Salavisa 8948ebdb25 fix(acp): flush ScheduleWakeup output via synthetic prompt (#706) 2026-04-26 21:07:22 +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
João Salavisa 519de03da5 fix(agentctl): inject HTTP MCP server for Codex ACP support (#641)
* fix(agentctl): inject HTTP MCP server for Codex ACP support

Codex ACP only supports HTTP-based MCP servers (not SSE). The kandev
MCP server was only injected with SSE transport, causing it to be
filtered out by Codex ACP's capability check.

Now inject both SSE and HTTP variants of the kandev MCP server:
- SSE at /sse (for Claude Code)
- HTTP at /mcp (for Codex ACP)

The agent's capability filtering automatically selects the appropriate
transport based on what the agent supports.

* refactor(agentctl): address code review feedback

- Add name deduplication to filterMcpServersByCapabilities to prevent
  duplicate MCP server entries if an agent supports both transports
- Extract injectKandevMcpServers helper to centralize dual-transport
  injection logic in agent.go
- Add constants for MCP server name and transport types
- Add test for duplicate name deduplication

* fix(agentctl): add MCP injection to handleWSResetSession

Apply injectKandevMcpServers to session reset handler, ensuring MCP
tools remain available after context window reset.
2026-04-18 18:37:09 +01:00
Carlos Florêncio 204fac1cca feat: acp-first profiles, models, and modes (#566) 2026-04-15 13:22:32 +01:00
Carlos Florêncio 8c6f16337d fix(acp): suppress stale events during session resume history replay (#527) 2026-04-03 15:15:02 +01:00
Carlos Florêncio 663919a52b fix(agents): update gemini ACP flag and claude-agent-acp package org (#482) 2026-03-28 23:11:21 +00:00
José Almeida 5b7e54f5da fix: pass MCP servers through LoadSession so tools survive session resume (#450)
* fix: pass MCP servers through LoadSession so tools survive session resume

* fix: pass MCP servers to Copilot ResumeSession (address CR feedback)
2026-03-22 23:19:37 +00:00
Carlos Florêncio 684ea1f98e fix(mcp): carry env and headers through MCP server config pipeline (#439) 2026-03-14 21:59:41 +00:00
Carlos Florêncio 083b2b5bb0 fix(acp): improve claude acp tool messages and model selector flow (#442) 2026-03-14 21:58:31 +00:00
Carlos Florêncio 9af1b05bfb fix: resolve acp chat ux issues with permissions, plans, and tool states (#428) 2026-03-12 23:22:26 +00:00
Carlos Florêncio 37e6b1bd6d fix: recover from agent MCP timeout during clarification wait (#413) 2026-03-10 22:48:30 +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 a2d04a9573 fix: resolve ACP model ID mismatch and promote ACP agents as default (#404) 2026-03-10 18:58:29 +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 c70e97c104 fix: prevent duplicate messages when resuming ACP sessions (#392) 2026-03-08 18:13:11 +00:00
João Salavisa 07b39efde2 feat(auggie): enable native session resume with ACP session/load (#380) 2026-03-06 10:41:05 +00:00
Carlos Florêncio cd96c6f699 feat: install agents on env preparation remote executors (#352) 2026-03-02 22:47:21 +00:00
Carlos Florêncio fb50b726df fix: copy markdown to clipboard and codex error handling (#348) 2026-03-02 18:37:13 +00:00
Carlos Florêncio 22c0fd2a57 fix: improve claude plan mode reliability and cleanup (#346) 2026-03-02 14:29:34 +00:00
Carlos Florêncio 4e2e59b1ec feat: opencode acp 2026-02-21 22:05:25 +00:00
Carlos Florêncio f0d84b32b8 feat: opencode improve sse 2026-02-21 22:05:25 +00:00
Carlos Florêncio 1556dfeda8 feat: improve amp 2026-02-21 22:05:25 +00:00
Carlos Florêncio 122094fa5d feat: e2e tests 2026-02-21 22:05:24 +00:00
Carlos Florêncio a2e9390e66 feat: improve claude code 2026-02-21 22:05:24 +00:00
Carlos Florêncio 01b0e9edf1 feat: improve acp + tracing (#258) 2026-02-20 17:30:14 +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
João Salavisa e2ba35b3bd feat: migrate agent operations from HTTP to WebSocket (#218) 2026-02-13 09:05:40 +00:00
Carlos Florêncio ff96b4ed2d fix: copilot mcp (#217) 2026-02-10 22:37:50 +00:00