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:
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"]),
|
||||
}
|
||||
Reference in new issue
Block a user