> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trytrellis.app/llms.txt
> Use this file to discover all available pages before exploring further.

# v0.5.0-beta.12

> 2026-04-23

Phase 1.3 改为由 AI 按任务自行挑选条目。移除 `task.py init-context`；在 sub-agent 平台上，`task.py create` 会给 `implement.jsonl` 和 `check.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` 字段，所有读取端都会跳过）：

```jsonl theme={null}
{"_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 / Droid | Kilo / 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 步骤。

```python theme={null}
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.py`     | Claude、Cursor、Kiro、CodeBuddy、Droid、Gemini、Qoder |
| `codex/hooks/session-start.py`      | Codex                                           |
| `copilot/hooks/session-start.py`    | Copilot                                         |
| `opencode/plugins/session-start.js` | OpenCode（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.js` 查 `npm view @mindfoldhq/trellis versions --json` 并和本地 `src/migrations/manifests/*.json` 对比。任何 npm 上存在但本地缺失的版本都会让检查 exit 非零。

背景：`trellis update` 按 `v > installed && v <= current` 应用迁移。某版本在 npm 上但本地没对应 manifest，会让从相邻版本升级的用户静默漏掉那批迁移——参见 `.trellis/spec/cli/backend/migrations.md` 里的 beta.10 事件。

| Release 脚本                                        | 前置流程                                                                                  |
| ------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `release` / `release:minor` / `release:major`     | `check-manifest-continuity.js` → `pnpm test` → bump → commit → tag → push             |
| `release:beta` / `release:rc` / `release:promote` | `check-manifest-continuity.js` → `check-docs-changelog.js` → `pnpm 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 exceeded`，`trellis update` 在确认后的备份阶段崩溃。

| 修复点                                                                                                         | 位置                                        |
| ----------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| `collectAllFiles` 改成迭代栈遍历，避免递归 + 大数组 spread                                                                 | `packages/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.ts` 和 `test/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.ts` 和 `init-joiner.integration.test.ts` 原本把 `execSync` stub 成对所有命令返回空字符串。`init()` 内部会调 `requireSupportedPython()` → `execSync("python3 --version")`，空字符串被判为"Python 未找到"抛异常，任何后续断言都跑不到。

```typescript theme={null}
// 之前——对所有命令返回空字符串：
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 通过。

## 升级

既有项目：

```bash theme={null}
trellis update
```

拉取更新后的 scripts + hooks。既有的 `implement.jsonl` / `check.jsonl` 继续可用——没有 `file` 的 seed 行会被所有读取端忽略。如果你早先 `init-context` 生成的 jsonl 指向 monorepo spec 布局里不存在的路径（典型场景是 `package = backend | frontend` 项目），按 `workflow.md` Phase 1.3 重 curate：

```bash theme={null}
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`。

全新安装：

```bash theme={null}
npm i -g @mindfoldhq/trellis@0.5.0-beta.12
```
