feat: prepare 2.2.0 with UI and execution fixes

Add dark theme, richer Markdown and readable plugin results.
Improve Android input evidence, response integrity and diagnostics.
Unify lifecycle, guidance receipts and evidence sources across clients.
Keep direct action dispatch without an added AI quota approval layer.
Align version metadata at 2.2.0 and bundle Helper 1.2.2.

Validation: 3063 backend tests before the version bump; 44 after.
Frontend: 317 tests and production build passed.
This commit is contained in:
chenmingxuan committed 2026-10-26 00:44:13 +08:00
1 parent 83bcfd54d5
commit fac4ccb760
146 files changed
+5689 -2033

No files matched your search

@@ -0,0 +1,82 @@
"""One read-only lifecycle view for web, MCP and exported reports."""
import json
from pathlib import Path
import sqlite3
from artemis.config import DB_PATH
from artemis.runtime.task_control import list_instructions, read_state
from artemis.runtime.task_progress import progress_snapshot
def _records(session_id: str, path: Path):
if not path.is_file():
return None, None, []
with sqlite3.connect(path.resolve().as_uri() + "?mode=ro", uri=True) as conn:
conn.row_factory = sqlite3.Row
tables = {
row[0] for row in conn.execute("SELECT name FROM sqlite_master WHERE type='table'")
}
session = (
conn.execute("SELECT * FROM sessions WHERE session_id=?", (session_id,)).fetchone()
if "sessions" in tables
else None
)
record = (
conn.execute(
"SELECT payload FROM automation_jobs WHERE session_id=?", (session_id,)
).fetchone()
if "automation_jobs" in tables
else None
)
rows = (
conn.execute(
"SELECT payload FROM traces WHERE session_id=? AND type='final_review_diagnostic'",
(session_id,),
).fetchall()
if "traces" in tables
else []
)
return session, record, rows
def task_lifecycle(session_id: str, *, db_path=None, now=None) -> dict:
session, record, rows = _records(session_id, Path(db_path) if db_path else DB_PATH)
try:
job = json.loads(record[0]) if record else {}
except (ValueError, TypeError):
job = {}
reviews = []
for row in rows:
try:
value = json.loads(row[0])
except (ValueError, TypeError):
continue
if isinstance(value, dict):
reviews.append(value)
session = dict(session) if session else {}
control = read_state(session_id)
if session.get("pid") and control.get("pid") != session["pid"]:
control = {}
value = progress_snapshot(
job=job if isinstance(job, dict) else {},
session=session,
control=control,
reviews=reviews,
now=now,
)
instructions = list_instructions(session_id, task_status=value["status"])
value["guidance_counts"] = {
status: sum(item["status"] == status for item in instructions)
for status in ("pending", "reading", "consumed", "unapplied", "unconfirmed")
}
return value
def guidance_details(session_id: str, *, db_path=None) -> dict:
lifecycle = task_lifecycle(session_id, db_path=db_path)
return {
"session_id": session_id,
"lifecycle": lifecycle,
"instructions": list_instructions(session_id, task_status=lifecycle["status"]),
}