feat: implement persistent agent execution logs storage and retrieval

- Add task_agent_execution_logs table schema in SQLite with indexes
- Create SQLiteMessageStore implementing MessageStore interface for persistent ACP message storage
- Add task.logs WebSocket action for retrieving historical logs
- Implement historical log replay on task.subscribe
- Add HistoricalLogsProvider callback to WebSocket Hub

Tests:
- Add comprehensive unit tests for SQLiteMessageStore (29 tests)
- Add integration tests for task.logs and historical replay (3 test suites)
- Enhance e2e-test.sh with historical logs test scenarios (Steps 14-16)

Files:
- apps/backend/internal/orchestrator/acp/sqlite_store.go (new)
- apps/backend/internal/orchestrator/acp/sqlite_store_test.go (new)
- apps/backend/internal/task/repository/sqlite.go (schema)
- apps/backend/internal/gateway/websocket/hub.go (provider)
- apps/backend/internal/gateway/websocket/client.go (replay)
- apps/backend/internal/orchestrator/wshandlers/handlers.go (task.logs)
- apps/backend/cmd/kandev/main.go (wiring)
- scripts/e2e-test.sh (test scenarios)
This commit is contained in:
jcfs
2026-01-11 01:24:54 +00:00
parent 0f0c8edfd2
commit 6a46eb5a54
13 changed files with 3027 additions and 15 deletions
@@ -90,6 +90,22 @@ func (r *SQLiteRepository) initSchema() error {
CREATE INDEX IF NOT EXISTS idx_tasks_board_id ON tasks(board_id);
CREATE INDEX IF NOT EXISTS idx_tasks_column_id ON tasks(column_id);
CREATE INDEX IF NOT EXISTS idx_columns_board_id ON columns(board_id);
CREATE TABLE IF NOT EXISTS task_agent_execution_logs (
id TEXT PRIMARY KEY,
task_id TEXT NOT NULL,
agent_instance_id TEXT NOT NULL DEFAULT '',
log_level TEXT NOT NULL DEFAULT 'info',
message_type TEXT NOT NULL,
message TEXT NOT NULL DEFAULT '',
metadata TEXT DEFAULT '{}',
timestamp DATETIME NOT NULL,
FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_execution_logs_task_id ON task_agent_execution_logs(task_id);
CREATE INDEX IF NOT EXISTS idx_execution_logs_timestamp ON task_agent_execution_logs(timestamp);
CREATE INDEX IF NOT EXISTS idx_execution_logs_task_timestamp ON task_agent_execution_logs(task_id, timestamp);
`
_, err := r.db.Exec(schema)
@@ -101,6 +117,11 @@ func (r *SQLiteRepository) Close() error {
return r.db.Close()
}
// DB returns the underlying sql.DB instance for shared access
func (r *SQLiteRepository) DB() *sql.DB {
return r.db
}
// Task operations
// CreateTask creates a new task