* feat: session resumption with ACP session ID support
- Add useSessionResumption hook for automatic session recovery on page reload
- Fix ACPSessionID not being set on AgentInstance in Launch() and createInstance()
- Add task.session.status and task.session.resume WebSocket actions
- Fix shell terminal retry logic for resumed sessions
- Fix taskSessionState reading from Zustand store instead of local state
- Remove dead code: unused stream handling functions in lifecycle/manager.go
- Fix test mock interfaces (CleanupStaleInstanceByTaskID, NewManager signature)
- Add enhanced logging for session resumption debugging
- Simplify page-client.tsx state merging logic
* refactor: remove unused AgentController (dead code)
- Delete agent_controller.go - entirely unused duplicate of Manager methods
- Remove agentController field from Manager struct
- Remove AgentController initialization in NewManager
The AgentController duplicated StartAgentProcess, initializeACPSession, and
PromptAgent from Manager but was never called. All agent control operations
go through Manager's own methods.
* refactor: remove unused MemoryRepository (dead code)
- Delete memory.go - entire MemoryRepository implementation unused
(replaced by SQLite repository)
- Delete memory_test.go - tests for removed MemoryRepository
Found via 'deadcode' tool analysis.
* refactor: consolidate agentctl packages into server/client structure
Reorganize the confusing dual agentctl packages:
- internal/agentctl/* → internal/agentctl/server/
- internal/agent/agentctl/* → internal/agentctl/client/
Structure is now:
internal/agentctl/
├── client/ - HTTP client for talking to agentctl servers
│ ├── client.go
│ ├── standalone.go
│ ├── acp.go
│ └── launcher/
├── server/ - agentctl server implementation (runs in containers)
│ ├── api/
│ ├── adapter/
│ ├── acp/
│ ├── config/
│ ├── instance/
│ ├── process/
│ └── shell/
└── types/ - Shared types used by both client and server
Also consolidated shared types (GitStatusUpdate, FileInfo, etc.) from
process/types.go into the shared types/ package.
* refactor: rename AgentInstance to AgentExecution for clarity
Rename AgentInstance -> AgentExecution across the entire codebase to better
reflect what it represents: an agent actively working on a task, not just
a generic 'instance'.
Changes:
- AgentInstance struct -> AgentExecution
- InstanceStore -> ExecutionStore (new file: execution_store.go)
- RecoveredInstance -> RecoveredExecution
- All method names: GetInstance* -> GetExecution*, ListInstances -> ListExecutions, etc.
- All parameters: instanceID -> executionID
- All local variables: instance -> execution
- DTOs and JSON tags: agent_instance_id -> agent_execution_id
- Database columns: agent_instance_id -> agent_execution_id
Also consolidates duplicate prompt logic:
- Merge sendInitialPrompt and SendPrompt into single SendPrompt method
- Add validateStatus parameter to differentiate initial vs follow-up prompts
Also extracts ACP session management to session.go:
- Move initializeACPSession logic to SessionManager.InitializeAndPrompt
- Move PromptAgent logic to SessionManager.SendPrompt
- Manager now delegates to SessionManager for all prompt operations
Also removes duplicate event publishing:
- Remove 9 duplicate m.publish*() methods from manager.go
- Use existing EventPublisher methods via m.eventPublisher.Publish*()
Also extracts types to dedicated file:
- Move AgentExecution, LaunchRequest, PromptResult, etc. to types.go
Net reduction: ~600 lines removed from manager.go through deduplication
and better separation of concerns.
* fix(backend): Docker runtime now creates instance via ControlServer
The Docker runtime was incorrectly creating an agentctl.Client pointing
directly to port 9999 (the ControlServer port), then trying to call
instance-specific APIs like /api/v1/agent/configure which only exist
on per-instance servers.
Fixed by making Docker runtime follow the same flow as standalone mode:
- LaunchContainer now uses StandaloneCtl to create an instance via the
control API, then creates Client pointing to the instance port
- RecoverInstances queries the ControlServer to get the instance port
- Added waitForHealth helper to wait for agentctl to be ready
Also improved HTTP error handling in agentctl client:
- All client methods now check HTTP status codes before JSON decoding
- Better error messages include status code and response body
* fix: restore session resumption imports and variables
* fix: add sessionId prop back to TaskLayout
* feat: replace agent_type with agent_profile_id
- Replace agent_type field with agent_profile_id across backend and frontend
- Add ProfileResolver interface and StoreProfileResolver implementation
- Update task creation/update to use agent_profile_id
- Change default agent runtime from docker to standalone
- Fix workspace state types to include all required fields
- Fix websocket handlers type mismatches for environments, executors, workspaces
- Update integration tests to use agent_profile_id
* feat: pass model as CLI argument to agents
- Add ModelFlag field to AgentTypeConfig for specifying the CLI flag
- Set ModelFlag to '--model' for all agents (auggie, claude, codex, gemini, opencode, copilot)
- Update launchStandalone to append model flag to agent command
- Update launchDocker/buildContainerConfig to append model flag to container command
- Model is passed when both agent supports ModelFlag and profile has Model configured
* fix: make WebSocket message handling async to prevent blocking
When a long-running handler like orchestrator.prompt was executing,
it blocked the ReadPump loop, preventing other requests (like
workspace.tree.get) from being processed until the handler completed.
Now each message is handled in its own goroutine, allowing concurrent
message handling so file tree requests work while the agent is working.
* feat: show task description as first message in chat
- Add 'Task' label with distinct styling (lighter background, border)
- Pass taskDescription from page to TaskChatPanel component
- Differentiate from regular user messages visually
- Add AgentSession database entity with SQLite persistence
- Implement AgentSession CRUD operations in repository layer
- Update executor to use hybrid cache + database approach
- Add session restoration on startup (LoadActiveSessionsFromDB)
- Link comments to agent sessions via agent_session_id
- Fix SQLite NULL handling for nullable task fields
- Add dev database setup with seed data (make dev, make dev-db-reset)
- Update Makefile with dev targets for development mode
This enables agent sessions to persist across backend restarts,
solving the 'execution not found' error for resumed conversations.
- Add permission stream support to backend agentctl client
- StreamPermissions() connects to permission WebSocket
- RespondToPermission() sends responses via HTTP POST
- PermissionNotification type for permission request data
- Connect lifecycle manager to permission stream
- handlePermissionStream() receives permission requests
- publishPermissionRequest() forwards to event bus
- RespondToPermission() and RespondToPermissionByTaskID() methods
- Add WebSocket handler for permission.respond action
- Validates task_id, pending_id, option_id
- Routes response through orchestrator → executor → lifecycle manager
- Add permission WebSocket actions
- ActionPermissionRequested for notifications
- ActionPermissionRespond for user responses
- Update executor interface with RespondToPermissionByTaskID()
- Update mock implementations in tests
- Add permission response test to e2e-test.sh
- Fix e2e-test.sh ID extraction (strip newlines)
The full permission flow is now wired up:
agent → agentctl → backend → frontend → user → backend → agentctl → agent
Auto-approve mode is still enabled by default until frontend is ready.
- Add Comment model and CRUD operations (repository, service layers)
- Add WAITING_FOR_INPUT task state for agent input requests
- Add WebSocket actions for comment.add, comment.get, comment.list
- Add ActionCommentAdded and ActionInputRequested notifications
- Update PromptAgent to return PromptResult with stop reason
- Add e2e test for agent input request flow
- Add PR template for the repository
This enables agents to request input from users by returning
stopReason 'needs_input' which transitions the task to
WAITING_FOR_INPUT state and creates an agent comment.
- Add AgentStatusReady status for when agent finishes a prompt
- Add AgentReady event published when prompt completes
- PromptAgent accepts RUNNING/READY states, marks READY when done
- Add /complete endpoint to explicitly complete a task
- E2E test polls for READY status instead of file creation
- E2E test validates multi-turn conversation flow
- Use acp-go-sdk for all ACP communication in agentctl
- Mark agent as completed when Prompt() returns successfully
- Update task state to COMPLETED when agent completes
- Update task state to FAILED when agent fails and retries exhausted
- Enhanced E2E test to verify agent actually creates files
- E2E test now validates full flow: task creation -> agent work -> file creation -> task completion