feat: release 2.2.0 with PC-only tests and execution reliability fixes
Unify task scheduling and queue state, fix Android input and observation recovery, preserve screenshot paths, and match final review criteria accurately. Add collapsible copyable results and publish the complete 2.1.0 upgrade notes. Validation: 3189 backend tests, 326 frontend tests, 24 client tests, production build and quality gates.
This commit is contained in:
1 parent
fac4ccb760
commit
be6e8c2abd
79 files changed
+2263
-277
No files matched your search
+41
-2
@@ -53,7 +53,11 @@ SAVE_NOTE_DOCSTRING = (
|
||||
" will be overwritten."
|
||||
)
|
||||
SAVE_NOTE_ARG_KEY_DESC = "The unique key under which to save or overwrite the note."
|
||||
SAVE_NOTE_ARG_CONTENT_DESC = "The text content to write to the note."
|
||||
_ARTIFACT_REFERENCE_RULE = (
|
||||
" Copy artifact paths exactly from successful tool receipts (trace_path for task-local "
|
||||
"evidence); never rebuild a path from the session directory and filename."
|
||||
)
|
||||
SAVE_NOTE_ARG_CONTENT_DESC = "The text content to write to the note." + _ARTIFACT_REFERENCE_RULE
|
||||
|
||||
APPEND_NOTE_DOCSTRING = (
|
||||
"[NOTE] Appends text content to an existing note in persistent memory with"
|
||||
@@ -62,7 +66,7 @@ APPEND_NOTE_DOCSTRING = (
|
||||
" note does not exist, it will be created."
|
||||
)
|
||||
APPEND_NOTE_ARG_KEY_DESC = "The key of the note to append to."
|
||||
APPEND_NOTE_ARG_CONTENT_DESC = "The text content to append to the note."
|
||||
APPEND_NOTE_ARG_CONTENT_DESC = "The text content to append to the note." + _ARTIFACT_REFERENCE_RULE
|
||||
|
||||
UPDATE_NOTE_DOCSTRING = (
|
||||
"[NOTE] Updates a note by replacing a specific target string with"
|
||||
@@ -77,6 +81,7 @@ UPDATE_NOTE_ARG_TARGET_DESC = (
|
||||
)
|
||||
UPDATE_NOTE_ARG_REPLACEMENT_DESC = (
|
||||
"The new replacement content to insert instead of the target content."
|
||||
+ _ARTIFACT_REFERENCE_RULE
|
||||
)
|
||||
|
||||
|
||||
@@ -146,8 +151,40 @@ def read_note_content(
|
||||
return content
|
||||
|
||||
|
||||
def validate_artifact_note_paths(base_dir: str | Path, content: str) -> None:
|
||||
"""Reject missing root-level references to existing task artifacts, without guessing."""
|
||||
root = Path(base_dir).resolve()
|
||||
if not any(prefix in content for prefix in (str(root), root.as_posix())):
|
||||
return
|
||||
artifacts = root / "artifacts"
|
||||
if not artifacts.is_dir() or not artifacts.resolve().is_relative_to(root):
|
||||
return
|
||||
candidates: dict[Path, list[str]] = {}
|
||||
for path in artifacts.rglob("*"):
|
||||
if not path.is_file() or not path.resolve().is_relative_to(root):
|
||||
continue
|
||||
misplaced = root / path.name
|
||||
if misplaced.exists():
|
||||
continue
|
||||
for spelling in {str(misplaced), misplaced.as_posix()}:
|
||||
if re.search(re.escape(spelling) + r"(?![\w./\\-])", content):
|
||||
candidates.setdefault(misplaced, []).append(str(path))
|
||||
break
|
||||
if candidates:
|
||||
details = "; ".join(
|
||||
f"{missing} does not exist; saved candidates: {', '.join(paths)}"
|
||||
for missing, paths in candidates.items()
|
||||
)
|
||||
raise ValueError(
|
||||
"Artifact reference has omitted its artifact directory. "
|
||||
+ details
|
||||
+ ". Re-read the tool receipt and use its exact trace_path; note was not changed."
|
||||
)
|
||||
|
||||
|
||||
def save_note_content(base_dir: str | Path, key: str, content: str) -> None:
|
||||
"""Saves or overwrites the raw content of a note."""
|
||||
validate_artifact_note_paths(base_dir, content)
|
||||
notes_dir = get_notes_dir(base_dir)
|
||||
notes_dir.mkdir(parents=True, exist_ok=True)
|
||||
file_path = get_note_file_path(base_dir, key)
|
||||
@@ -211,6 +248,7 @@ def save_verified_note(base_dir: str | Path, key: str, content: str) -> dict:
|
||||
|
||||
def append_note_content(base_dir: str | Path, key: str, content: str) -> None:
|
||||
"""Appends raw content to a note, inserting a newline if the file is not empty and lacks a trailing newline."""
|
||||
validate_artifact_note_paths(base_dir, content)
|
||||
notes_dir = get_notes_dir(base_dir)
|
||||
notes_dir.mkdir(parents=True, exist_ok=True)
|
||||
file_path = get_note_file_path(base_dir, key)
|
||||
@@ -379,6 +417,7 @@ def update_note_content(
|
||||
|
||||
# Phase 4: Write and Return, or Not Found Error
|
||||
if new_content_to_write is not None:
|
||||
validate_artifact_note_paths(base_dir, replacement)
|
||||
file_path.write_text(new_content_to_write, encoding="utf-8")
|
||||
if key == "task_plan":
|
||||
try:
|
||||
|
||||
Reference in new issue
Block a user