daemon: agent-driven workspace images — repo→image registry (GET/PUT/DELETE /api/repos), spawn resolves custom image, self-healing lvmh-ops control container with docker.sock; 132 tests, e2e 87/87

This commit is contained in:
Raphael Westphal
2026-08-18 23:54:09 +02:00
parent 8fcaeb7c03
commit 7287b831e4
15 changed files with 1216 additions and 38 deletions
+52
View File
@@ -47,6 +47,12 @@ type ContainerRow struct {
Repo string
}
// RepoImageRow maps a repo path to its registered custom worker image.
type RepoImageRow struct {
Repo string `json:"repo"`
Image string `json:"image"`
}
const dsnParams string = "?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)&_pragma=synchronous(NORMAL)"
const schema string = `
@@ -59,6 +65,8 @@ CREATE TABLE IF NOT EXISTS sessions(
CREATE TABLE IF NOT EXISTS settings(key TEXT PRIMARY KEY, value TEXT NOT NULL);
CREATE TABLE IF NOT EXISTS containers(
sessionId TEXT PRIMARY KEY, containerId TEXT NOT NULL, repo TEXT NOT NULL);
CREATE TABLE IF NOT EXISTS repo_images(
repo TEXT PRIMARY KEY, image TEXT NOT NULL);
CREATE INDEX IF NOT EXISTS idx_events_session ON events(sessionId, seq);
`
@@ -278,3 +286,47 @@ func (s *Store) DeleteContainer(sessionID string) error {
_, err := s.db.Exec(`DELETE FROM containers WHERE sessionId=?`, sessionID)
return err
}
// GetRepoImage returns the custom image registered for a repo, if any.
func (s *Store) GetRepoImage(repo string) (string, bool, error) {
var image string
err := s.db.QueryRow(`SELECT image FROM repo_images WHERE repo=?`, repo).Scan(&image)
if err == sql.ErrNoRows {
return "", false, nil
}
if err != nil {
return "", false, err
}
return image, true, nil
}
// SetRepoImage upserts the custom image for a repo.
func (s *Store) SetRepoImage(repo, image string) error {
_, err := s.db.Exec(`INSERT INTO repo_images(repo, image) VALUES(?,?)
ON CONFLICT(repo) DO UPDATE SET image=excluded.image`, repo, image)
return err
}
// DeleteRepoImage removes a repo's custom image registration (idempotent).
func (s *Store) DeleteRepoImage(repo string) error {
_, err := s.db.Exec(`DELETE FROM repo_images WHERE repo=?`, repo)
return err
}
// ListRepoImages returns every repo→image registration, sorted by repo.
func (s *Store) ListRepoImages() ([]RepoImageRow, error) {
rows, err := s.db.Query(`SELECT repo, image FROM repo_images ORDER BY repo`)
if err != nil {
return nil, err
}
defer rows.Close()
var out []RepoImageRow
for rows.Next() {
var row RepoImageRow
if err := rows.Scan(&row.Repo, &row.Image); err != nil {
return nil, err
}
out = append(out, row)
}
return out, rows.Err()
}