auto-sync: 2026-05-18 11:36:11

This commit is contained in:
cfdaily
2026-05-18 11:36:11 +08:00
parent e645fc2483
commit ae8b85df1d
+10 -90
View File
@@ -14,11 +14,9 @@ def init_db(db_path: Path) -> None:
try:
for stmt in _SCHEMA_STATEMENTS:
conn.execute(stmt)
for stmt in _CARDS_SCHEMA:
conn.execute(stmt)
# v2.6.1 迁移:旧 DB 可能缺少新字段
_migrate_v261(conn)
# v2.7 迁移:cards 表 + card_id + stage
# v2.7 迁移:stages_json
_migrate_v27(conn)
conn.commit()
finally:
@@ -41,70 +39,11 @@ def _migrate_v261(conn: sqlite3.Connection) -> None:
def _migrate_v27(conn: sqlite3.Connection) -> None:
"""v2.7 数据迁移:cards 表 + 所有表加 card_id/stage"""
# 1. cards 表(CREATE IF NOT EXISTS 已处理)
for stmt in _CARDS_SCHEMA:
try:
conn.execute(stmt)
except sqlite3.OperationalError:
pass
# 2. 所有表加 card_id
for table in ("tasks", "outputs", "reviews", "comments", "events",
"task_attempts", "routing_decisions"):
_safe_add_column(conn, table, "card_id", "TEXT")
# 3. tasks 加 stage
"""v2.7 数据迁移:stages_json 字段(动态 Stage 定义)"""
_safe_add_column(conn, "tasks", "stages_json", "TEXT DEFAULT '[]'")
# 确保 stage 列存在(旧 v2.7 迁移可能已添加)
_safe_add_column(conn, "tasks", "stage", "TEXT")
# 4. card_id 索引
for table in ("tasks", "events"):
try:
conn.execute(
f"CREATE INDEX IF NOT EXISTS idx_{table}_card ON {table}(card_id)")
except sqlite3.OperationalError:
pass
# 5. 回填 card_id = 'default'(分批,避免大表锁太久)
for table in ("tasks", "outputs", "reviews", "comments", "events",
"task_attempts", "routing_decisions"):
try:
row = conn.execute(
f"SELECT COUNT(*) as cnt FROM {table} WHERE card_id IS NULL"
).fetchone()
if row and row["cnt"] > 0:
# 分批更新,每批 500 行
_batch_update_card_id(conn, table, "default", batch_size=500)
except sqlite3.OperationalError:
pass # 表不存在则跳过
# 6. 创建 default Card(如果不存在)
try:
existing = conn.execute(
"SELECT id FROM cards WHERE id='default'"
).fetchone()
if not existing:
conn.execute(
"INSERT INTO cards (id, name, status, card_type, stages_json, labels_json, created_at) "
"VALUES ('default', 'Default', 'active', 'default', '[]', '[]', datetime('now'))"
)
except sqlite3.OperationalError:
pass # cards 表不存在则跳过(不应该发生)
def _batch_update_card_id(conn: sqlite3.Connection, table: str,
card_id: str, batch_size: int = 500) -> None:
"""分批更新 card_id,避免大表长时间锁"""
while True:
cursor = conn.execute(
f"UPDATE {table} SET card_id=? WHERE rowid IN ("
f"SELECT rowid FROM {table} WHERE card_id IS NULL LIMIT {batch_size})",
(card_id,),
)
if cursor.rowcount == 0:
break
conn.commit()
def _safe_add_column(conn: sqlite3.Connection, table: str,
column: str, col_type: str) -> None:
@@ -141,6 +80,9 @@ VALID_STATUSES = frozenset({
TERMINAL_STATUSES = frozenset({"done", "cancelled"})
# 手动状态(不参与聚合推导)
MANUAL_STATUSES = frozenset({"cancelled"})
VALID_TRANSITIONS = {
"pending": {"claimed", "cancelled"},
"claimed": {"working", "pending", "cancelled"},
@@ -188,8 +130,7 @@ ATTEMPT_OUTCOMES = frozenset({
# ---------------------------------------------------------------------------
# Schema - split into individual statements to avoid SQLite 3.51 CHECK bug
# (table-level CHECK as non-last column definition causes parse error)
# Schema
# ---------------------------------------------------------------------------
_SCHEMA_STATEMENTS = [
@@ -220,8 +161,8 @@ _SCHEMA_STATEMENTS = [
current_agent TEXT,
previous_agent TEXT,
next_capability TEXT,
card_id TEXT DEFAULT 'default',
stage TEXT
stage TEXT,
stages_json TEXT DEFAULT '[]'
)""",
"CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status)",
"CREATE INDEX IF NOT EXISTS idx_tasks_assignee ON tasks(assignee)",
@@ -386,24 +327,3 @@ _SCHEMA_STATEMENTS = [
"CREATE INDEX IF NOT EXISTS idx_routing_mode ON routing_decisions(mode)",
"CREATE INDEX IF NOT EXISTS idx_routing_time ON routing_decisions(created_at)",
]
# ---------------------------------------------------------------------------
# Cards Schema (v2.7)
# ---------------------------------------------------------------------------
_CARDS_SCHEMA = [
"""CREATE TABLE IF NOT EXISTS cards (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT DEFAULT '',
card_type TEXT DEFAULT 'default' CHECK (card_type IN ('default','strategy','data_pipeline','research','platform','bugfix','mail')),
stages_json TEXT DEFAULT '[]',
labels_json TEXT DEFAULT '[]',
status TEXT DEFAULT 'active' CHECK (status IN ('active','pending','working','review','done','failed','blocked','cancelled','archived','deleted')),
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT,
archived_at TEXT
)""",
"CREATE INDEX IF NOT EXISTS idx_cards_id ON cards(id)",
"CREATE INDEX IF NOT EXISTS idx_cards_status ON cards(status)",
]