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

+63
View File
@@ -14,6 +14,47 @@ import pytest
import artemis.runtime.task_control as task_control
def test_transition_timing_keeps_repeated_states_and_separates_pause_and_resource_wait(
tmp_path, monkeypatch
):
monkeypatch.setattr(task_control, "TRACES_PATH", tmp_path)
clock = [10]
monkeypatch.setattr(
task_control,
"time",
SimpleNamespace(**{**vars(task_control.time), "time": lambda: clock[0]}),
)
for at, status in (
(10, "queued"),
(20, "running"),
(25, "running"),
(30, "task_paused"),
(40, "resuming"),
(50, "running"),
):
clock[0] = at
task_control.write_control_state("timed-task", status)
assert task_control.read_state("timed-task")["timing"] == {
"started_at": 10,
"state_started_at": 50,
"seconds": {"queued": 10, "running": 10, "task_paused": 10, "resuming": 10},
}
def test_non_object_control_state_and_invalid_timing_can_be_replaced(tmp_path, monkeypatch):
monkeypatch.setattr(task_control, "TRACES_PATH", tmp_path)
path = task_control.control_dir("broken-state") / "task_control_state.json"
path.parent.mkdir(parents=True)
path.write_text("[]", encoding="utf-8")
assert task_control.read_state("broken-state") == {}
task_control.write_control_state("broken-state", "running")
state = task_control.read_state("broken-state")
state["timing"] = "invalid"
task_control._write_atomic(path, state)
task_control.write_control_state("broken-state", "task_paused")
assert task_control.read_state("broken-state")["timing"]["seconds"] == {}
def _windows_access_error(code: int) -> PermissionError:
error = PermissionError(errno.EACCES, "state file is in use")
error.winerror = code
@@ -423,6 +464,28 @@ def test_guidance_history_distinguishes_submission_from_runner_consumption(tmp_p
assert all(item["status"] == "consumed" and item["consumed_at"] for item in history)
def test_terminal_guidance_reports_no_consumption_and_keeps_original_receipt(tmp_path, monkeypatch):
monkeypatch.setattr(task_control, "TRACES_PATH", tmp_path)
receipt = task_control.add_instruction("task-123", "检查新入口", instruction_id="guidance")
history = task_control.list_instructions("task-123", task_status="cancelled")
assert history[0]["status"] == "unapplied"
assert history[0]["accepted_at"] == receipt["timestamp"]
assert "consumed_at" not in history[0]
assert task_control.list_instructions("task-123")[0]["status"] == "pending"
def test_claimed_guidance_is_visible_and_not_falsely_reported_as_consumed(tmp_path, monkeypatch):
monkeypatch.setattr(task_control, "TRACES_PATH", tmp_path)
task_control.add_instruction("task-123", "检查新入口", instruction_id="guidance")
directory = task_control.control_dir("task-123") / "instructions"
(directory / "guidance.json").rename(directory / "guidance.reading")
assert task_control.list_instructions("task-123")[0]["status"] == "reading"
assert (
task_control.list_instructions("task-123", task_status="completed")[0]["status"]
== "unconfirmed"
)
def test_guidance_history_endpoint_returns_pending_and_consumed(tmp_path, monkeypatch):
from fastapi import FastAPI
from fastapi.testclient import TestClient