auto-sync: 2026-05-18 11:36:11
This commit is contained in:
+10
-90
@@ -14,11 +14,9 @@ def init_db(db_path: Path) -> None:
|
|||||||
try:
|
try:
|
||||||
for stmt in _SCHEMA_STATEMENTS:
|
for stmt in _SCHEMA_STATEMENTS:
|
||||||
conn.execute(stmt)
|
conn.execute(stmt)
|
||||||
for stmt in _CARDS_SCHEMA:
|
|
||||||
conn.execute(stmt)
|
|
||||||
# v2.6.1 迁移:旧 DB 可能缺少新字段
|
# v2.6.1 迁移:旧 DB 可能缺少新字段
|
||||||
_migrate_v261(conn)
|
_migrate_v261(conn)
|
||||||
# v2.7 迁移:cards 表 + card_id + stage
|
# v2.7 迁移:stages_json
|
||||||
_migrate_v27(conn)
|
_migrate_v27(conn)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
finally:
|
finally:
|
||||||
@@ -41,70 +39,11 @@ def _migrate_v261(conn: sqlite3.Connection) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def _migrate_v27(conn: sqlite3.Connection) -> None:
|
def _migrate_v27(conn: sqlite3.Connection) -> None:
|
||||||
"""v2.7 数据迁移:cards 表 + 所有表加 card_id/stage"""
|
"""v2.7 数据迁移:stages_json 字段(动态 Stage 定义)"""
|
||||||
# 1. cards 表(CREATE IF NOT EXISTS 已处理)
|
_safe_add_column(conn, "tasks", "stages_json", "TEXT DEFAULT '[]'")
|
||||||
for stmt in _CARDS_SCHEMA:
|
# 确保 stage 列存在(旧 v2.7 迁移可能已添加)
|
||||||
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
|
|
||||||
_safe_add_column(conn, "tasks", "stage", "TEXT")
|
_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,
|
def _safe_add_column(conn: sqlite3.Connection, table: str,
|
||||||
column: str, col_type: str) -> None:
|
column: str, col_type: str) -> None:
|
||||||
@@ -141,6 +80,9 @@ VALID_STATUSES = frozenset({
|
|||||||
|
|
||||||
TERMINAL_STATUSES = frozenset({"done", "cancelled"})
|
TERMINAL_STATUSES = frozenset({"done", "cancelled"})
|
||||||
|
|
||||||
|
# 手动状态(不参与聚合推导)
|
||||||
|
MANUAL_STATUSES = frozenset({"cancelled"})
|
||||||
|
|
||||||
VALID_TRANSITIONS = {
|
VALID_TRANSITIONS = {
|
||||||
"pending": {"claimed", "cancelled"},
|
"pending": {"claimed", "cancelled"},
|
||||||
"claimed": {"working", "pending", "cancelled"},
|
"claimed": {"working", "pending", "cancelled"},
|
||||||
@@ -188,8 +130,7 @@ ATTEMPT_OUTCOMES = frozenset({
|
|||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Schema - split into individual statements to avoid SQLite 3.51 CHECK bug
|
# Schema
|
||||||
# (table-level CHECK as non-last column definition causes parse error)
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
_SCHEMA_STATEMENTS = [
|
_SCHEMA_STATEMENTS = [
|
||||||
@@ -220,8 +161,8 @@ _SCHEMA_STATEMENTS = [
|
|||||||
current_agent TEXT,
|
current_agent TEXT,
|
||||||
previous_agent TEXT,
|
previous_agent TEXT,
|
||||||
next_capability 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_status ON tasks(status)",
|
||||||
"CREATE INDEX IF NOT EXISTS idx_tasks_assignee ON tasks(assignee)",
|
"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_mode ON routing_decisions(mode)",
|
||||||
"CREATE INDEX IF NOT EXISTS idx_routing_time ON routing_decisions(created_at)",
|
"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)",
|
|
||||||
]
|
|
||||||
|
|||||||
Reference in New Issue
Block a user