升级 Trellis 并完成项目审查(07-26-trellis-upgrade-project-audit)

这个提交包含在:
2026-07-26 18:10:49 +08:00
父节点 b3dadfa1bf
当前提交 f223f559ad
共修改 77 个文件,包含 5850 行新增和 1327 行删除
+46 -13
查看文件
@@ -43,6 +43,11 @@ _KNOWN_PLATFORMS = {
"kiro",
"copilot",
"pi",
"trae",
"grok",
"kimi",
"zcode",
"snow",
}
_ENV_SESSION_KEYS: tuple[tuple[str, tuple[str, ...]], ...] = (
@@ -57,6 +62,15 @@ _ENV_SESSION_KEYS: tuple[tuple[str, tuple[str, ...]], ...] = (
("kiro", ("KIRO_SESSION_ID",)),
("copilot", ("COPILOT_SESSION_ID", "COPILOT_SESSIONID")),
("pi", ("PI_SESSION_ID", "PI_SESSIONID")),
("trae", ("TRAE_SESSION_ID",)),
# ZCode reuses CLAUDE_SESSION_ID (it does not document a ZCODE_SESSION_ID).
# Platform-scoped lookup (_iter_env_keys filters by platform name), so this
# only fires when the resolver already detected "zcode" — no collision with
# the claude entry above.
("zcode", ("CLAUDE_SESSION_ID",)),
# Snow CLI exports SNOW_SESSION_ID into hook/terminal/sub-agent children.
# TRELLIS_CONTEXT_ID remains the preferred override when present.
("snow", ("SNOW_SESSION_ID",)),
)
_ENV_CONVERSATION_KEYS: tuple[tuple[str, tuple[str, ...]], ...] = (
("cursor", ("CURSOR_CONVERSATION_ID", "CURSOR_CONVERSATIONID")),
@@ -76,6 +90,12 @@ _ENV_PLATFORM_ALIASES = {
"factory-ai": "droid",
"github-copilot": "copilot",
}
# ZCode intentionally reuses CLAUDE_SESSION_ID. Hooks know the host is ZCode,
# while later shell commands see only the shared env name and resolve it through
# the Claude entry. Canonicalize both paths to one runtime filename.
_CONTEXT_KEY_PLATFORM_ALIASES = {
"zcode": "claude",
}
@dataclass(frozen=True)
@@ -189,6 +209,7 @@ def _detect_platform(platform_input: dict[str, Any] | None, platform: str | None
def _context_key(platform_name: str, kind: str, value: str) -> str:
platform_name = _CONTEXT_KEY_PLATFORM_ALIASES.get(platform_name, platform_name)
if kind == "transcript":
return f"{platform_name}_transcript_{_hash_value(value)}"
safe_value = _sanitize_key(value)
@@ -380,15 +401,18 @@ def _lookup_cursor_shell_ticket_context_key() -> str | None:
def resolve_context_key(
platform_input: dict[str, Any] | None = None,
platform: str | None = None,
*,
allow_environment_context: bool = True,
) -> str | None:
"""Resolve a stable session/window context key, if one is available.
`TRELLIS_CONTEXT_ID` is an explicit context-key override used by CLI
scripts and subprocesses. It does not store the task itself.
"""
override = _string_value(os.environ.get("TRELLIS_CONTEXT_ID"))
if override:
return _sanitize_key(override) or _hash_value(override)
if allow_environment_context:
override = _string_value(os.environ.get("TRELLIS_CONTEXT_ID"))
if override:
return _sanitize_key(override) or _hash_value(override)
data = _as_dict(platform_input)
platform_name = _detect_platform(data, platform) if data or platform else None
@@ -406,11 +430,12 @@ def resolve_context_key(
if transcript_path:
return _context_key(platform_name or "session", "transcript", transcript_path)
env_context_key = _lookup_env_context_key(platform_name)
if env_context_key:
return env_context_key
if allow_environment_context:
env_context_key = _lookup_env_context_key(platform_name)
if env_context_key:
return env_context_key
if platform_name in (None, "session", "cursor"):
if allow_environment_context and platform_name in (None, "session", "cursor"):
return _lookup_cursor_shell_ticket_context_key()
return None
@@ -469,17 +494,24 @@ def resolve_active_task(
repo_root: Path,
platform_input: dict[str, Any] | None = None,
platform: str | None = None,
*,
allow_single_session_fallback: bool = True,
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 class-2 platform sub-agents (codex,
copilot, gemini, qoder) that don't inherit the parent's session id. ≥2
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.
"""
context_key = resolve_context_key(platform_input, platform)
context_key = resolve_context_key(
platform_input,
platform,
allow_environment_context=allow_environment_context,
)
if context_key:
context = _read_json(_context_path(repo_root, context_key)) or {}
task_ref = _string_value(context.get("current_task"))
@@ -487,9 +519,10 @@ def resolve_active_task(
if active:
return active
fallback = _resolve_single_session_fallback(repo_root)
if fallback is not None:
return fallback
if allow_single_session_fallback:
fallback = _resolve_single_session_fallback(repo_root)
if fallback is not None:
return fallback
return ActiveTask(None, "none", context_key)