refactor(monorepo): extract coord-core
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"embed"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
//go:embed schema/*.sql
|
||||
var schemaFS embed.FS
|
||||
|
||||
func ApplyMigrations(ctx context.Context, db *sql.DB) error {
|
||||
files, err := schemaFS.ReadDir("schema")
|
||||
if err != nil {
|
||||
return fmt.Errorf("read embedded schema directory: %w", err)
|
||||
}
|
||||
|
||||
names := make([]string, 0, len(files))
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
names = append(names, file.Name())
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("begin schema transaction: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
for _, name := range names {
|
||||
content, err := schemaFS.ReadFile("schema/" + name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read embedded schema file %q: %w", name, err)
|
||||
}
|
||||
if _, err := tx.ExecContext(ctx, string(content)); err != nil {
|
||||
return fmt.Errorf("apply schema file %q: %w", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf("commit schema transaction: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
func Open(ctx context.Context, dbPath string) (*sql.DB, error) {
|
||||
if err := ensureParentDir(dbPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db, err := sql.Open("sqlite", dbPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open sqlite database: %w", err)
|
||||
}
|
||||
|
||||
if err := applyPragmas(ctx, db); err != nil {
|
||||
_ = db.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func ensureParentDir(dbPath string) error {
|
||||
parent := filepath.Dir(dbPath)
|
||||
if parent == "." || parent == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return os.MkdirAll(parent, 0o755)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func applyPragmas(ctx context.Context, db *sql.DB) error {
|
||||
pragmas := []string{
|
||||
"PRAGMA foreign_keys = ON;",
|
||||
"PRAGMA journal_mode = WAL;",
|
||||
"PRAGMA busy_timeout = 5000;",
|
||||
}
|
||||
|
||||
for _, pragma := range pragmas {
|
||||
if _, err := db.ExecContext(ctx, pragma); err != nil {
|
||||
return fmt.Errorf("apply pragma %q: %w", pragma, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
CREATE TABLE IF NOT EXISTS threads (
|
||||
thread_id TEXT PRIMARY KEY,
|
||||
run_id TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
subject TEXT NOT NULL,
|
||||
created_by TEXT NOT NULL,
|
||||
assigned_to TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
priority TEXT NOT NULL DEFAULT 'normal',
|
||||
latest_message_id TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS messages (
|
||||
message_id TEXT PRIMARY KEY,
|
||||
thread_id TEXT NOT NULL,
|
||||
from_agent TEXT NOT NULL,
|
||||
to_agent TEXT NOT NULL,
|
||||
kind TEXT NOT NULL,
|
||||
summary TEXT NOT NULL,
|
||||
body TEXT NOT NULL DEFAULT '',
|
||||
payload_json TEXT NOT NULL DEFAULT '{}',
|
||||
created_at TEXT NOT NULL,
|
||||
FOREIGN KEY(thread_id) REFERENCES threads(thread_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS leases (
|
||||
thread_id TEXT PRIMARY KEY,
|
||||
agent_id TEXT NOT NULL,
|
||||
lease_token TEXT NOT NULL,
|
||||
claimed_at TEXT NOT NULL,
|
||||
expires_at TEXT NOT NULL,
|
||||
released_at TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS artifacts (
|
||||
artifact_id TEXT PRIMARY KEY,
|
||||
message_id TEXT NOT NULL,
|
||||
path TEXT NOT NULL,
|
||||
kind TEXT NOT NULL,
|
||||
metadata_json TEXT NOT NULL DEFAULT '{}',
|
||||
created_at TEXT NOT NULL,
|
||||
FOREIGN KEY(message_id) REFERENCES messages(message_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_threads_status_assigned
|
||||
ON threads(status, assigned_to, updated_at);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_thread_created
|
||||
ON messages(thread_id, created_at);
|
||||
@@ -0,0 +1,52 @@
|
||||
CREATE TABLE IF NOT EXISTS runs (
|
||||
run_id TEXT PRIMARY KEY,
|
||||
goal TEXT NOT NULL,
|
||||
summary TEXT NOT NULL DEFAULT '',
|
||||
status TEXT NOT NULL DEFAULT 'active',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tasks (
|
||||
run_id TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
summary TEXT NOT NULL DEFAULT '',
|
||||
status TEXT NOT NULL,
|
||||
default_to TEXT,
|
||||
priority TEXT NOT NULL DEFAULT 'normal',
|
||||
acceptance_json TEXT NOT NULL DEFAULT '[]',
|
||||
latest_attempt_no INTEGER,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
PRIMARY KEY (run_id, task_id),
|
||||
FOREIGN KEY(run_id) REFERENCES runs(run_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS task_dependencies (
|
||||
run_id TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
depends_on_task_id TEXT NOT NULL,
|
||||
PRIMARY KEY (run_id, task_id, depends_on_task_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS task_attempts (
|
||||
run_id TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
attempt_no INTEGER NOT NULL,
|
||||
assigned_to TEXT NOT NULL,
|
||||
thread_id TEXT NOT NULL,
|
||||
base_ref TEXT,
|
||||
base_commit TEXT,
|
||||
branch_name TEXT,
|
||||
worktree_path TEXT,
|
||||
workspace_status TEXT,
|
||||
result_commit TEXT,
|
||||
status TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
PRIMARY KEY (run_id, task_id, attempt_no)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_run_status
|
||||
ON tasks(run_id, status, priority, updated_at);
|
||||
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE IF NOT EXISTS events (
|
||||
event_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
run_id TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
thread_id TEXT,
|
||||
source TEXT NOT NULL,
|
||||
event_type TEXT NOT NULL,
|
||||
message_id TEXT,
|
||||
summary TEXT NOT NULL DEFAULT '',
|
||||
payload_json TEXT NOT NULL DEFAULT '{}',
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_events_run_event
|
||||
ON events(run_id, event_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_events_thread_event
|
||||
ON events(thread_id, event_id);
|
||||
@@ -0,0 +1,45 @@
|
||||
CREATE TABLE IF NOT EXISTS council_runs (
|
||||
run_id TEXT PRIMARY KEY,
|
||||
mode TEXT NOT NULL,
|
||||
target_type TEXT NOT NULL,
|
||||
output_mode TEXT NOT NULL,
|
||||
only_unanimous INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS council_reviewers (
|
||||
run_id TEXT NOT NULL,
|
||||
reviewer_role TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
PRIMARY KEY (run_id, reviewer_role)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS council_findings (
|
||||
run_id TEXT NOT NULL,
|
||||
reviewer_role TEXT NOT NULL,
|
||||
finding_id TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
summary TEXT NOT NULL,
|
||||
proposal TEXT NOT NULL,
|
||||
rationale TEXT NOT NULL,
|
||||
confidence TEXT NOT NULL,
|
||||
tags_json TEXT NOT NULL DEFAULT '[]',
|
||||
target_refs_json TEXT NOT NULL DEFAULT '{}',
|
||||
PRIMARY KEY (run_id, reviewer_role, finding_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS council_groups (
|
||||
run_id TEXT NOT NULL,
|
||||
group_id TEXT NOT NULL,
|
||||
proposal TEXT NOT NULL,
|
||||
bucket TEXT NOT NULL,
|
||||
support_count INTEGER NOT NULL,
|
||||
supporters_json TEXT NOT NULL DEFAULT '[]',
|
||||
dissenters_json TEXT NOT NULL DEFAULT '[]',
|
||||
rationale_summary TEXT NOT NULL DEFAULT '',
|
||||
tags_json TEXT NOT NULL DEFAULT '[]',
|
||||
source_finding_ids_json TEXT NOT NULL DEFAULT '[]',
|
||||
PRIMARY KEY (run_id, group_id)
|
||||
);
|
||||
@@ -0,0 +1,12 @@
|
||||
CREATE TABLE IF NOT EXISTS thread_reads (
|
||||
thread_id TEXT NOT NULL,
|
||||
agent_id TEXT NOT NULL,
|
||||
last_read_message_id TEXT NOT NULL,
|
||||
last_read_at TEXT NOT NULL,
|
||||
PRIMARY KEY(thread_id, agent_id),
|
||||
FOREIGN KEY(thread_id) REFERENCES threads(thread_id),
|
||||
FOREIGN KEY(last_read_message_id) REFERENCES messages(message_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_thread_reads_agent
|
||||
ON thread_reads(agent_id, last_read_at);
|
||||
@@ -0,0 +1,9 @@
|
||||
CREATE TABLE IF NOT EXISTS council_inputs (
|
||||
run_id TEXT PRIMARY KEY,
|
||||
prompt TEXT NOT NULL DEFAULT '',
|
||||
target_file TEXT NOT NULL DEFAULT '',
|
||||
repo_path TEXT NOT NULL DEFAULT '',
|
||||
target_task_id TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
@@ -0,0 +1,8 @@
|
||||
CREATE TABLE IF NOT EXISTS council_reports (
|
||||
run_id TEXT PRIMARY KEY,
|
||||
show_json TEXT NOT NULL DEFAULT '[]',
|
||||
summary_json TEXT NOT NULL DEFAULT '{}',
|
||||
markdown_path TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
Reference in New Issue
Block a user