diff --git a/src/blackboard/db.py b/src/blackboard/db.py index a61d663..090087f 100644 --- a/src/blackboard/db.py +++ b/src/blackboard/db.py @@ -64,53 +64,54 @@ def _migrate_v28(conn: sqlite3.Connection) -> None: conn.execute("DROP TABLE IF EXISTS tasks_v28") # 迁移期间禁用 FK 检查(DROP TABLE tasks 会触发 events FK 约束) fk_was_on = conn.execute("PRAGMA foreign_keys").fetchone()[0] - conn.execute("PRAGMA foreign_keys = OFF") - conn.executescript(""" - CREATE TABLE tasks_v28 ( - id TEXT PRIMARY KEY, - title TEXT NOT NULL, - description TEXT, - status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','claimed','working','review','paused','escalated','waiting_human','done','failed','blocked','cancelled')), - assignee TEXT, - assigned_by TEXT, - depends_on TEXT, - parent_task TEXT, - priority INTEGER NOT NULL DEFAULT 5, - task_type TEXT, - created_at TEXT NOT NULL DEFAULT (datetime('now')), - updated_at TEXT NOT NULL DEFAULT (datetime('now')), - claimed_at TEXT, - started_at TEXT, - completed_at TEXT, - deadline TEXT, - retry_count INTEGER NOT NULL DEFAULT 0, - max_retries INTEGER NOT NULL DEFAULT 2, - must_haves TEXT, - risk_level TEXT DEFAULT 'standard', - estimated_duration_minutes INTEGER, - escalated INTEGER DEFAULT 0, - current_agent TEXT, - previous_agent TEXT, - next_capability TEXT, - stage TEXT, - stages_json TEXT DEFAULT '[]', - archived INTEGER DEFAULT 0, - archived_at TEXT - ); - INSERT INTO tasks_v28 SELECT * FROM tasks; - DROP TABLE tasks; - ALTER TABLE tasks_v28 RENAME TO tasks; - """) - # 重建索引 - conn.executescript(""" - CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); - CREATE INDEX IF NOT EXISTS idx_tasks_assignee ON tasks(assignee); - CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks(parent_task); - CREATE INDEX IF NOT EXISTS idx_tasks_current_agent ON tasks(current_agent); - """) - # 恢复 FK 检查 - if fk_was_on: - conn.execute("PRAGMA foreign_keys = ON") + try: + conn.execute("PRAGMA foreign_keys = OFF") + conn.executescript(""" + CREATE TABLE tasks_v28 ( + id TEXT PRIMARY KEY, + title TEXT NOT NULL, + description TEXT, + status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','claimed','working','review','paused','escalated','waiting_human','done','failed','blocked','cancelled')), + assignee TEXT, + assigned_by TEXT, + depends_on TEXT, + parent_task TEXT, + priority INTEGER NOT NULL DEFAULT 5, + task_type TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + claimed_at TEXT, + started_at TEXT, + completed_at TEXT, + deadline TEXT, + retry_count INTEGER NOT NULL DEFAULT 0, + max_retries INTEGER NOT NULL DEFAULT 2, + must_haves TEXT, + risk_level TEXT DEFAULT 'standard', + estimated_duration_minutes INTEGER, + escalated INTEGER DEFAULT 0, + current_agent TEXT, + previous_agent TEXT, + next_capability TEXT, + stage TEXT, + stages_json TEXT DEFAULT '[]', + archived INTEGER DEFAULT 0, + archived_at TEXT + ); + INSERT INTO tasks_v28 SELECT * FROM tasks; + DROP TABLE tasks; + ALTER TABLE tasks_v28 RENAME TO tasks; + """) + # 重建索引 + conn.executescript(""" + CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); + CREATE INDEX IF NOT EXISTS idx_tasks_assignee ON tasks(assignee); + CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks(parent_task); + CREATE INDEX IF NOT EXISTS idx_tasks_current_agent ON tasks(current_agent); + """) + finally: + if fk_was_on: + conn.execute("PRAGMA foreign_keys = ON") # 3. checkpoints 表(M3) conn.execute("""CREATE TABLE IF NOT EXISTS checkpoints (