升级Trellis并精简项目知识(09-05-trellis-upgrade-rule-cleanup)

更新Trellis适配、任务归属与归档失败恢复,精简技能入口和知识读取规则。
保留权限、证据、事务及独立复核合同;纳入对应任务及已完成复核记录。
仅本地提交,不启用新平台适配,不推送或部署。
这个提交包含在:
2026-09-19 13:10:06 +08:00
父节点 b1d25d3c99
当前提交 729d90576f
共修改 25 个文件,包含 550 行新增和 1328 行删除
+4 -6
查看文件
@@ -648,17 +648,15 @@ def resolve_active_task(
platform_input: dict[str, Any] | None = None,
platform: str | None = None,
*,
allow_single_session_fallback: bool = True,
allow_single_session_fallback: bool = False,
allow_environment_context: bool = True,
) -> ActiveTask:
"""Resolve the active task from session runtime state only.
A stale session task is returned as stale. Missing context identity or a
missing/empty session context falls back to single-session inference: if
exactly one session file exists in the runtime, return its task with
source_type="session-fallback" — covers pull-based platform sub-agents
(copilot, gemini, qoder) that don't inherit the parent's session id. ≥2
files or 0 files yield ActiveTask(None) — refuses to guess across windows.
Missing or unmatched session identity does not infer ownership from the
number of session files. Pull-based child-agent callers that cannot inherit
a parent identity must opt into the compatibility fallback explicitly.
"""
context_key = resolve_context_key(
platform_input,
+57 -1
查看文件
@@ -196,6 +196,40 @@ def _report_write_failure(path: Path) -> None:
)
def _restore_child_links(unlinked: dict[Path, str | None]) -> None:
"""Put back the parent links this archive attempt already removed.
The unlink loop below walks a parent's children one at a time, so a
failure part-way through leaves the earlier children carrying
``parent: null`` while their parent is still in the active tree. That is
the mirror image of the dangling reference the same loop already refuses
to create, and nothing repairs it later either, so undo it before the
failure is reported.
Restoring is best-effort: if a child cannot be written back, name it so
the caller can re-link it by hand instead of guessing which one broke.
"""
broken: list[str] = []
for child_json, original_parent in unlinked.items():
child_data, _ = read_json_checked(child_json)
if child_data is None:
broken.append(child_json.parent.name)
continue
child_data["parent"] = original_parent
if not write_json(child_json, child_data):
broken.append(child_json.parent.name)
if broken:
print(
colored(
f"Warning: could not restore the parent link on: {', '.join(broken)}. "
"Re-link each one with `python3 .trellis/scripts/task.py "
"add-subtask <parent> <child>`.",
Colors.RED,
),
file=sys.stderr,
)
# =============================================================================
# Sub-agent platform detection + JSONL context files
# =============================================================================
@@ -1332,7 +1366,13 @@ def cmd_archive(args: argparse.Namespace) -> int:
# missing from the active set are treated as completed.
task_children = data.get("children", [])
# If this is a parent, clear parent field in all children
# If this is a parent, clear parent field in all children.
# Remember each link removed so a later failure in this loop can
# put it back (see _restore_child_links). Keyed by the child's
# task.json: a `children` list that names the same child twice
# would otherwise record a second, already-cleared snapshot and
# the restore would write that `null` back over the real parent.
unlinked_children: dict[Path, str | None] = {}
if task_children:
for child_name in task_children:
child_dir_path = find_task_by_name(child_name, tasks_dir)
@@ -1351,13 +1391,29 @@ def cmd_archive(args: argparse.Namespace) -> int:
file=sys.stderr,
)
continue
# Only the first visit to a child records its original
# parent: a `children` list naming the same child twice
# would otherwise snapshot the already-cleared value and
# the restore would write that `null` back over the link.
first_visit = child_json not in unlinked_children
original_parent = child_data.get("parent")
if first_visit:
unlinked_children[child_json] = original_parent
child_data["parent"] = None
if not write_json(child_json, child_data):
# Stop before the move: a child pointing at a
# parent that has left .trellis/tasks/ is a
# dangling reference nothing repairs later.
# Put back the children already unlinked above —
# their parent is staying, so losing the link the
# other way round is just as unrecoverable.
# Retrying is safe — every step so far is
# idempotent.
if first_visit:
# The link never came off, so there is nothing
# to put back for this child.
del unlinked_children[child_json]
_restore_child_links(unlinked_children)
_report_write_failure(child_json)
print(
f"Not archived: {_repo_relative_path(task_dir, repo_root)} is "