跳转到主要内容
Phase 1.3 改为由 AI 按任务自行挑选条目。移除 task.py init-context;在 sub-agent 平台上,task.py create 会给 implement.jsonlcheck.jsonl 各自预写一行自描述的 _example seed,之后由 AI 按 workflow.md Phase 1.3 填入真实的 spec + research 条目。4 个 session-start 实现的 READY gate 现在要求至少一条 curated 条目才算就绪。Skill Routing 表按平台分支。发版脚本新增 manifest 连续性前置检查,堵掉已发版 manifest 被重写或删除的路径。非破坏性,trellis update 对既有任务无感。

功能变动

workflow.md 的 Phase 1.3 由 agent 生成,不再由脚本生成预填充的内容

之前的 task.py init-context 会按照 dev_type + package 进行 implement.jsonl / check.jsonl 的预填充,模板路径假设的是 spec/<package>/{backend,frontend}/index.md,但如果按语言分包的 monorepo(如 package = backend + package = frontend)会产出指向不存在的文件,进而会导致 agent 自主填充,多轮 tool call 调用导致模型注意力涣散,遗忘 trellis 工作流。 Seed 行格式(每个 jsonl 一行,没有 file 字段,所有读取端都会跳过):
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line when done."}

Skill Routing 表按平台分支

workflow.md 的 Skill Routing 和 DO-NOT-skip 表现在有两种派发方式,分别是有 sub agent 的 IDE/CLI,会调用 trellis-implement 实际 coding;而没有 sub agent 的平台会在主 agent 里加载 trellis-before-dev 自己 coding。
有 sub agent 的平台无 sub agent 的平台
Claude / Cursor / OpenCode / Codex / Kiro / Gemini / Qoder / CodeBuddy / Copilot / DroidKilo / Antigravity / Windsurf
按 Phase 2.1 派 trellis-implement sub-agent加载 trellis-before-dev skill(主线程流程)

4 个 session-start 实现的 READY gate 统一

此前所有 4 个 session-start 实现都以”implement.jsonl 文件存在”为”Phase 2 就绪”判据。task.py create seed 完 jsonl 后,面包屑直接跳到 Status: READY,AI 会跳过 Phase 1.3 curate。 现在每个实现扫描 jsonl,要求至少一行带 file 字段。只有 seed 的 jsonl 现在显示为 Status: PLANNING (Phase 1.3),Next-Action 指向 curate 步骤。
def _has_curated_jsonl_entry(jsonl_path: Path) -> bool:
    """刚 seed 完的 jsonl 只有 `{"_example": ...}`——那不算 ready。"""
    for line in jsonl_path.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line:
            continue
        try:
            row = json.loads(line)
        except json.JSONDecodeError:
            continue
        if isinstance(row, dict) and row.get("file"):
            return True
    return False
实现被谁消费
shared-hooks/session-start.pyClaude、Cursor、Kiro、CodeBuddy、Droid、Gemini、Qoder
codex/hooks/session-start.pyCodex
copilot/hooks/session-start.pyCopilot
opencode/plugins/session-start.jsOpenCode(JS plugin 运行时)

Hook + prelude 对只有 seed 的 jsonl 做兼容处理

shared-hooks/inject-subagent-context.py:read_jsonl_entries 静默过滤不带 file 的行(不报错),但在结果为空时打一条 stderr warning。 configurators/shared.ts:buildPullBasedPrelude 告诉 Class-2 sub-agent(Codex / Copilot / Gemini / Qoder)跳过没有 file 的行,并在 jsonl 只有 seed 时退回到读 prd.md + 自己判断 spec。

内部优化

Manifest 连续性前置检查

packages/cli/scripts/check-manifest-continuity.jsnpm view @mindfoldhq/trellis versions --json 并和本地 src/migrations/manifests/*.json 对比。任何 npm 上存在但本地缺失的版本都会让检查 exit 非零。 背景:trellis updatev > installed && v <= current 应用迁移。某版本在 npm 上但本地没对应 manifest,会让从相邻版本升级的用户静默漏掉那批迁移——参见 .trellis/spec/cli/backend/migrations.md 里的 beta.10 事件。
Release 脚本前置流程
release / release:minor / release:majorcheck-manifest-continuity.jspnpm test → bump → commit → tag → push
release:beta / release:rc / release:promotecheck-manifest-continuity.jscheck-docs-changelog.jspnpm test → bump → …
历史 gap(pre-manifest-system 的 0.1.0–0.1.8、0.2.1–0.2.11;早期公开 prerelease 0.3.10-beta.0)写进 KNOWN_GAPS 冻结。注释注明这个列表不该扩展——出现新 gap 意味着应该修根因,不是加白名单。 紧急绕过:SKIP_MANIFEST_CONTINUITY=1 pnpm release:beta。设置时会打一条醒目的警告横幅。

trellis update 备份阶段的爆栈修复

createFullBackup().trellis/ 时会递归进入旧的 .trellis/.backup-* 目录,而旧备份里还套着 .opencode/node_modules(数万个文件)。原来的 collectAllFiles() 用递归 + files.push(...largeArray),文件量一大直接触发 V8 Maximum call stack size exceededtrellis update 在确认后的备份阶段崩溃。
修复点位置
collectAllFiles 改成迭代栈遍历,避免递归 + 大数组 spreadpackages/cli/src/commands/update.ts:770
扫描阶段直接跳过 node_modules.backup-* 等 exclude 目录(不只是复制阶段跳)packages/cli/src/commands/update.ts:683
BACKUP_EXCLUDE_PATTERNS 匹配前把路径反斜杠统一成正斜杠,和 isManagedPath 的正则化对齐,Windows 上 .claude\worktrees\... 这种也能匹配packages/cli/src/commands/update.ts:689
collectAllFiles 跳过 symlink / Windows NTFS junction(isSymbolicLink() 对 junction 也返回 true),防止环形路径导致无限扫描packages/cli/src/commands/update.ts:787
DEBUG=1 / TRELLIS_DEBUG=1 时打完整堆栈,方便定位同类问题packages/cli/src/cli/index.ts:130
回归覆盖加在 test/commands/update-internals.test.tstest/commands/update.integration.test.ts 临时绕过(如果还在用已发布的旧 CLI):rm -rf .trellis/.backup-* 删掉旧备份,再跑 trellis update 就不会触发爆栈。

create-manifest.js 守卫:禁止重写已发版 manifest

脚本现在拒绝(重)写 npm 上已存在版本的 manifest,即使传 force: true 也拒绝。交互模式在原有”本地文件已存在”prompt 之前先做 npm 查询检查。
$ node scripts/create-manifest.js --stdin <<< '{"version": "0.5.0-beta.11", ...}'
✗ Version 0.5.0-beta.11 is already published on npm.
  Its manifest is part of the update contract and must NOT be rewritten.
  If you need to release additional migrations, use the NEXT version number.

vi.mock("node:child_process") 给 Python 版本探测一个合法返回值

update.integration.test.tsinit-joiner.integration.test.ts 原本把 execSync stub 成对所有命令返回空字符串。init() 内部会调 requireSupportedPython()execSync("python3 --version"),空字符串被判为”Python 未找到”抛异常,任何后续断言都跑不到。
// 之前——对所有命令返回空字符串:
vi.mock("node:child_process", () => ({
  execSync: vi.fn().mockReturnValue(""),
}));

// 之后——只给 python --version 探测返回合法版本字符串:
vi.mock("node:child_process", () => ({
  execSync: vi.fn().mockImplementation((cmd: string) => {
    const py = process.platform === "win32" ? "python" : "python3";
    return cmd === `${py} --version` ? "Python 3.11.12" : "";
  }),
}));
解决 36 个遗留失败。全套测试:664/664 通过。

升级

既有项目:
trellis update
拉取更新后的 scripts + hooks。既有的 implement.jsonl / check.jsonl 继续可用——没有 file 的 seed 行会被所有读取端忽略。如果你早先 init-context 生成的 jsonl 指向 monorepo spec 布局里不存在的路径(典型场景是 package = backend | frontend 项目),按 workflow.md Phase 1.3 重 curate:
python3 ./.trellis/scripts/get_context.py --mode packages       # 查有哪些 spec
python3 ./.trellis/scripts/task.py add-context <task-dir> implement \
  ".trellis/spec/<pkg>/<layer>/index.md" "为什么适用"
写下第一条真实条目后,session-start 面包屑从 PLANNING (Phase 1.3) 翻到 READY 全新安装:
npm i -g @mindfoldhq/[email protected]