-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdb.py
More file actions
342 lines (304 loc) · 12.9 KB
/
Copy pathdb.py
File metadata and controls
342 lines (304 loc) · 12.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
"""
SentinelForge Database Layer
Task tracking, sprint management, agent activity log, and benchmark history.
SQLite with WAL mode for concurrent agent access.
"""
import sqlite3
import json
from datetime import datetime, timezone
from pathlib import Path
from config import DB_PATH, TASK_STATES, PRIORITIES
def get_conn():
"""Thread-safe connection with WAL mode."""
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
conn = sqlite3.connect(str(DB_PATH), timeout=10)
conn.execute("PRAGMA journal_mode=WAL")
conn.execute("PRAGMA foreign_keys=ON")
conn.row_factory = sqlite3.Row
return conn
def init_db():
"""Create all tables if they don't exist."""
conn = get_conn()
conn.executescript("""
-- Sprints: 2-week planning cycles
CREATE TABLE IF NOT EXISTS sprints (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
goal TEXT,
start_date TEXT NOT NULL,
end_date TEXT NOT NULL,
status TEXT DEFAULT 'ACTIVE',
created_at TEXT DEFAULT (datetime('now'))
);
-- Tasks: individual work items assigned to agents
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sprint_id INTEGER REFERENCES sprints(id),
title TEXT NOT NULL,
description TEXT,
agent_id INTEGER NOT NULL,
priority TEXT DEFAULT 'P2_MEDIUM',
state TEXT DEFAULT 'BACKLOG',
deliverables TEXT, -- JSON list of file paths
depends_on TEXT, -- JSON list of task IDs
estimated_hours REAL,
actual_hours REAL,
created_at TEXT DEFAULT (datetime('now')),
started_at TEXT,
completed_at TEXT,
review_status TEXT, -- PENDING, APPROVED, REJECTED
review_notes TEXT
);
-- Agent activity log: every action every agent takes
CREATE TABLE IF NOT EXISTS agent_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
agent_id INTEGER NOT NULL,
task_id INTEGER REFERENCES tasks(id),
action TEXT NOT NULL,
details TEXT, -- JSON payload
files_modified TEXT, -- JSON list of file paths
duration_sec REAL,
status TEXT DEFAULT 'SUCCESS', -- SUCCESS, FAILED, SKIPPED
timestamp TEXT DEFAULT (datetime('now'))
);
-- Code artifacts: files produced by agents
CREATE TABLE IF NOT EXISTS artifacts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id INTEGER REFERENCES tasks(id),
agent_id INTEGER NOT NULL,
file_path TEXT NOT NULL,
language TEXT, -- cuda, cpp, python, docker, yaml
lines_of_code INTEGER,
version TEXT,
checksum TEXT,
review_status TEXT DEFAULT 'PENDING',
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT
);
-- Benchmarks: performance measurements over time
CREATE TABLE IF NOT EXISTS benchmarks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
build_version TEXT NOT NULL,
metric TEXT NOT NULL,
value REAL NOT NULL,
unit TEXT,
site_id TEXT,
passed INTEGER, -- 1=pass, 0=fail
measured_at TEXT DEFAULT (datetime('now'))
);
-- Site deployments: what version is running where
CREATE TABLE IF NOT EXISTS deployments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
site_id TEXT NOT NULL,
image_version TEXT NOT NULL,
status TEXT DEFAULT 'DEPLOYING', -- DEPLOYING, ACTIVE, ROLLED_BACK, FAILED
deployed_at TEXT DEFAULT (datetime('now')),
health_check_at TEXT,
health_status TEXT -- JSON health telemetry
);
-- Indexes
CREATE INDEX IF NOT EXISTS idx_tasks_agent ON tasks(agent_id);
CREATE INDEX IF NOT EXISTS idx_tasks_state ON tasks(state);
CREATE INDEX IF NOT EXISTS idx_tasks_sprint ON tasks(sprint_id);
CREATE INDEX IF NOT EXISTS idx_log_agent ON agent_log(agent_id);
CREATE INDEX IF NOT EXISTS idx_log_task ON agent_log(task_id);
CREATE INDEX IF NOT EXISTS idx_benchmarks_metric ON benchmarks(metric);
CREATE INDEX IF NOT EXISTS idx_deployments_site ON deployments(site_id);
""")
conn.commit()
conn.close()
print(f"[DB] Initialized at {DB_PATH}")
# ─── Task Operations ────────────────────────────────────────────
def create_task(sprint_id, title, description, agent_id, priority="P2_MEDIUM",
deliverables=None, depends_on=None, estimated_hours=None):
conn = get_conn()
conn.execute("""
INSERT INTO tasks (sprint_id, title, description, agent_id, priority,
deliverables, depends_on, estimated_hours)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""", (sprint_id, title, description, agent_id, priority,
json.dumps(deliverables or []),
json.dumps(depends_on or []),
estimated_hours))
conn.commit()
task_id = conn.execute("SELECT last_insert_rowid()").fetchone()[0]
conn.close()
return task_id
def update_task_state(task_id, new_state):
conn = get_conn()
updates = {"state": new_state}
if new_state == "IN_PROGRESS":
updates["started_at"] = datetime.now(timezone.utc).isoformat()
elif new_state == "DONE":
updates["completed_at"] = datetime.now(timezone.utc).isoformat()
set_clause = ", ".join(f"{k} = ?" for k in updates)
conn.execute(f"UPDATE tasks SET {set_clause} WHERE id = ?",
list(updates.values()) + [task_id])
conn.commit()
conn.close()
def get_tasks_for_agent(agent_id, state=None):
conn = get_conn()
if state:
rows = conn.execute(
"SELECT * FROM tasks WHERE agent_id = ? AND state = ? ORDER BY priority",
(agent_id, state)
).fetchall()
else:
rows = conn.execute(
"SELECT * FROM tasks WHERE agent_id = ? ORDER BY priority, state",
(agent_id,)
).fetchall()
conn.close()
return [dict(r) for r in rows]
def get_blocked_tasks():
"""Find tasks whose dependencies aren't DONE yet."""
conn = get_conn()
tasks = conn.execute(
"SELECT * FROM tasks WHERE state != 'DONE' AND depends_on != '[]'"
).fetchall()
result = []
for t in tasks:
deps = json.loads(t["depends_on"])
for dep_id in deps:
dep = conn.execute("SELECT state FROM tasks WHERE id = ?", (dep_id,)).fetchone()
if dep and dep["state"] != "DONE":
result.append(dict(t))
break
conn.close()
return result
# ─── Agent Log Operations ───────────────────────────────────────
def log_action(agent_id, action, task_id=None, details=None,
files_modified=None, duration_sec=None, status="SUCCESS"):
conn = get_conn()
conn.execute("""
INSERT INTO agent_log (agent_id, task_id, action, details,
files_modified, duration_sec, status)
VALUES (?, ?, ?, ?, ?, ?, ?)
""", (agent_id, task_id, action, json.dumps(details) if details else None,
json.dumps(files_modified) if files_modified else None,
duration_sec, status))
conn.commit()
conn.close()
# ─── Artifact Operations ────────────────────────────────────────
def register_artifact(task_id, agent_id, file_path, language, lines_of_code, version):
conn = get_conn()
conn.execute("""
INSERT OR REPLACE INTO artifacts (task_id, agent_id, file_path, language,
lines_of_code, version, updated_at)
VALUES (?, ?, ?, ?, ?, ?, datetime('now'))
""", (task_id, agent_id, file_path, language, lines_of_code, version))
conn.commit()
conn.close()
# ─── Benchmark Operations ───────────────────────────────────────
def record_benchmark(build_version, metric, value, unit=None, site_id=None, passed=True):
conn = get_conn()
conn.execute("""
INSERT INTO benchmarks (build_version, metric, value, unit, site_id, passed)
VALUES (?, ?, ?, ?, ?, ?)
""", (build_version, metric, value, unit, site_id, 1 if passed else 0))
conn.commit()
conn.close()
def get_latest_benchmarks(build_version=None):
conn = get_conn()
if build_version:
rows = conn.execute(
"SELECT * FROM benchmarks WHERE build_version = ? ORDER BY measured_at DESC",
(build_version,)
).fetchall()
else:
rows = conn.execute("""
SELECT * FROM benchmarks WHERE id IN (
SELECT MAX(id) FROM benchmarks GROUP BY metric
) ORDER BY metric
""").fetchall()
conn.close()
return [dict(r) for r in rows]
# ─── Deployment Operations ──────────────────────────────────────
def record_deployment(site_id, image_version):
conn = get_conn()
conn.execute("""
INSERT INTO deployments (site_id, image_version) VALUES (?, ?)
""", (site_id, image_version))
conn.commit()
conn.close()
def get_fleet_status():
"""Current deployment version at each site."""
conn = get_conn()
rows = conn.execute("""
SELECT d.* FROM deployments d
INNER JOIN (
SELECT site_id, MAX(id) as max_id FROM deployments GROUP BY site_id
) latest ON d.id = latest.max_id
ORDER BY d.site_id
""").fetchall()
conn.close()
return [dict(r) for r in rows]
# ─── Sprint Operations ──────────────────────────────────────────
def create_sprint(name, goal, start_date, end_date):
conn = get_conn()
conn.execute("""
INSERT INTO sprints (name, goal, start_date, end_date) VALUES (?, ?, ?, ?)
""", (name, goal, start_date, end_date))
conn.commit()
sprint_id = conn.execute("SELECT last_insert_rowid()").fetchone()[0]
conn.close()
return sprint_id
def get_sprint_summary(sprint_id):
conn = get_conn()
sprint = dict(conn.execute("SELECT * FROM sprints WHERE id = ?", (sprint_id,)).fetchone())
tasks = conn.execute("SELECT state, COUNT(*) as cnt FROM tasks WHERE sprint_id = ? GROUP BY state",
(sprint_id,)).fetchall()
sprint["task_counts"] = {r["state"]: r["cnt"] for r in tasks}
conn.close()
return sprint
# ─── Reporting ──────────────────────────────────────────────────
def get_agent_stats():
"""Summary of each agent's activity."""
conn = get_conn()
rows = conn.execute("""
SELECT agent_id,
COUNT(*) as total_actions,
SUM(CASE WHEN status='SUCCESS' THEN 1 ELSE 0 END) as successes,
SUM(CASE WHEN status='FAILED' THEN 1 ELSE 0 END) as failures,
ROUND(SUM(duration_sec), 1) as total_seconds
FROM agent_log
GROUP BY agent_id
ORDER BY agent_id
""").fetchall()
conn.close()
return [dict(r) for r in rows]
def dashboard():
"""Print full system status."""
conn = get_conn()
task_states = conn.execute(
"SELECT state, COUNT(*) as cnt FROM tasks GROUP BY state"
).fetchall()
total_tasks = sum(r["cnt"] for r in task_states)
done_tasks = next((r["cnt"] for r in task_states if r["state"] == "DONE"), 0)
agent_stats = get_agent_stats()
fleet = get_fleet_status()
benchmarks = get_latest_benchmarks()
conn.close()
print("\n" + "="*60)
print(" SENTINELFORGE DASHBOARD")
print("="*60)
print(f"\n Tasks: {done_tasks}/{total_tasks} complete")
for r in task_states:
print(f" {r['state']:15s} {r['cnt']}")
print(f"\n Agent Activity:")
for a in agent_stats:
print(f" Agent {a['agent_id']:2d}: {a['total_actions']} actions, "
f"{a['successes']} ok, {a['failures']} fail, "
f"{a['total_seconds'] or 0:.0f}s total")
print(f"\n Fleet ({len(fleet)} sites deployed):")
for f in fleet:
print(f" {f['site_id']:8s} -> {f['image_version']:20s} [{f['status']}]")
if benchmarks:
print(f"\n Latest Benchmarks:")
for b in benchmarks:
status = "PASS" if b["passed"] else "FAIL"
print(f" {b['metric']:30s} {b['value']:.4f} {b.get('unit',''):10s} [{status}]")
print("="*60 + "\n")
if __name__ == "__main__":
init_db()
dashboard()