flower-trellis 0.5.0-beta.0 → 0.5.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/README.md +9 -6
  2. package/enhancements/0.6/.agents/skills/trellis-auto-loop/SKILL.md +17 -4
  3. package/enhancements/0.6/.agents/skills/trellis-check-all/SKILL.md +74 -20
  4. package/enhancements/0.6/.agents/skills/trellis-route/SKILL.md +15 -40
  5. package/enhancements/0.6/.agents/skills/trellis-route/scripts/route_state.py +53 -24
  6. package/enhancements/0.6/.claude/skills/trellis-auto-loop/SKILL.md +17 -4
  7. package/enhancements/0.6/.claude/skills/trellis-check-all/SKILL.md +74 -20
  8. package/enhancements/0.6/.claude/skills/trellis-route/SKILL.md +15 -40
  9. package/enhancements/0.6/.claude/skills/trellis-route/scripts/route_state.py +53 -24
  10. package/enhancements/0.6/overrides/bundles/finish-work.json +7 -0
  11. package/enhancements/0.6/overrides/bundles/intent-routing.json +25 -0
  12. package/enhancements/0.6/overrides/bundles/shared-hook-runtime.json +7 -0
  13. package/enhancements/0.6/overrides/bundles/update-spec-flow.json +7 -0
  14. package/enhancements/0.6/overrides/compatibility.json +13 -0
  15. package/enhancements/0.6/overrides/conflicts.json +145 -0
  16. package/enhancements/0.6/overrides/patches/hooks/claude-session-start/no-task-routing/patch.json +13 -0
  17. package/enhancements/0.6/overrides/patches/hooks/codex-session-start/no-task-routing/patch.json +13 -0
  18. package/enhancements/0.6/overrides/patches/hooks/inject-workflow-state/shared-runtime/patch.json +17 -0
  19. package/enhancements/0.6/overrides/patches/hooks/inject-workflow-state/shared-runtime/selector.py +408 -0
  20. package/enhancements/0.6/overrides/patches/skills/trellis-brainstorm/auto-task-create/patch.json +30 -0
  21. package/enhancements/0.6/overrides/patches/skills/trellis-brainstorm/planning-authorization/patch.json +30 -0
  22. package/enhancements/0.6/overrides/patches/skills/trellis-finish-work/exact-bookkeeping/baseline-agent.md +66 -0
  23. package/enhancements/0.6/overrides/patches/skills/trellis-finish-work/exact-bookkeeping/baseline-command.md +66 -0
  24. package/enhancements/0.6/overrides/patches/skills/trellis-finish-work/exact-bookkeeping/content.md +86 -0
  25. package/enhancements/0.6/overrides/patches/skills/trellis-finish-work/exact-bookkeeping/patch.json +20 -0
  26. package/enhancements/0.6/overrides/patches/skills/trellis-start/no-task-routing/patch.json +27 -0
  27. package/enhancements/0.6/overrides/patches/skills/trellis-update-spec/autonomous-evaluation/baseline.md +30 -0
  28. package/enhancements/0.6/overrides/patches/skills/trellis-update-spec/autonomous-evaluation/content.md +59 -0
  29. package/enhancements/0.6/overrides/patches/skills/trellis-update-spec/autonomous-evaluation/patch.json +19 -0
  30. package/enhancements/0.6/overrides/{workflow.md → patches/workflow/hub/content.md} +13 -17
  31. package/enhancements/0.6/overrides/patches/workflow/hub/patch.json +14 -0
  32. package/enhancements/0.6/overrides/patches/workflow/intent-routing/create-task-command/patch.json +13 -0
  33. package/enhancements/0.6/overrides/patches/workflow/intent-routing/create-task-rule/patch.json +13 -0
  34. package/enhancements/0.6/overrides/patches/workflow/intent-routing/customization-intent-invariant/patch.json +13 -0
  35. package/enhancements/0.6/overrides/patches/workflow/intent-routing/phase-index-create-task/patch.json +13 -0
  36. package/enhancements/0.6/overrides/patches/workflow/intent-routing/phase-one-goal/patch.json +13 -0
  37. package/enhancements/0.6/overrides/patches/workflow/intent-routing/phase-summary/patch.json +13 -0
  38. package/enhancements/0.6/overrides/patches/workflow/intent-routing/request-triage/patch.json +13 -0
  39. package/enhancements/0.6/overrides/patches/workflow/phase-ownership/active-task-routing-baseline.md +19 -0
  40. package/enhancements/0.6/overrides/patches/workflow/phase-ownership/active-task-routing-content.md +10 -0
  41. package/enhancements/0.6/overrides/patches/workflow/phase-ownership/patch.json +47 -0
  42. package/enhancements/0.6/overrides/patches/workflow/phase-ownership/phase-2-check-baseline.md +30 -0
  43. package/enhancements/0.6/overrides/patches/workflow/phase-ownership/phase-2-check-content.md +7 -0
  44. package/enhancements/0.6/overrides/patches/workflow/phase-ownership/phase-2-implement-baseline.md +53 -0
  45. package/enhancements/0.6/overrides/patches/workflow/phase-ownership/phase-2-implement-content.md +10 -0
  46. package/enhancements/0.6/overrides/patches/workflow/phase-ownership/phase-3-commit-baseline.md +51 -0
  47. package/enhancements/0.6/overrides/patches/workflow/phase-ownership/phase-3-commit-content.md +7 -0
  48. package/enhancements/0.6/overrides/patches/workflow/phase-ownership/phase-3-update-spec-baseline.md +8 -0
  49. package/enhancements/0.6/overrides/patches/workflow/phase-ownership/phase-3-update-spec-content.md +9 -0
  50. package/enhancements/0.6/overrides/patches/workflow/state-no-task/patch.json +15 -0
  51. package/enhancements/0.6/overrides/patches/workflow/states-in-progress/common-content.md +5 -0
  52. package/enhancements/0.6/overrides/patches/workflow/states-in-progress/in-progress-baseline.md +4 -0
  53. package/enhancements/0.6/overrides/patches/workflow/states-in-progress/in-progress-inline-baseline.md +3 -0
  54. package/enhancements/0.6/overrides/patches/workflow/states-in-progress/inline-content.md +1 -0
  55. package/enhancements/0.6/overrides/patches/workflow/states-in-progress/patch.json +27 -0
  56. package/enhancements/0.6/overrides/patches/workflow/states-in-progress/subagent-content.md +1 -0
  57. package/enhancements/0.6/overrides/patches/workflow/states-planning/common-content.md +5 -0
  58. package/enhancements/0.6/overrides/patches/workflow/states-planning/inline-content.md +1 -0
  59. package/enhancements/0.6/overrides/patches/workflow/states-planning/patch.json +27 -0
  60. package/enhancements/0.6/overrides/patches/workflow/states-planning/planning-baseline.md +4 -0
  61. package/enhancements/0.6/overrides/patches/workflow/states-planning/planning-inline-baseline.md +4 -0
  62. package/enhancements/0.6/overrides/patches/workflow/states-planning/subagent-content.md +1 -0
  63. package/enhancements/0.6/scripts/auto_loop.py +136 -6
  64. package/enhancements/MANIFEST.json +92 -51
  65. package/package.json +4 -4
  66. package/src/commands/self-update.js +6 -6
  67. package/src/lib/apply-enhancements.js +88 -77
  68. package/src/lib/backup.js +24 -0
  69. package/src/lib/enhancement-catalog.js +4 -5
  70. package/src/lib/legacy-blocks.js +1 -1
  71. package/src/lib/patch-conflicts.js +404 -0
  72. package/src/lib/patch-engine.js +986 -0
  73. package/src/lib/platform-patch-adapters.js +315 -0
  74. package/src/lib/self-check.js +25 -23
  75. package/src/lib/update-check.js +66 -6
  76. package/src/lib/workflow-inject.js +15 -33
  77. package/src/patches/bundles/flower-platform-integration.json +12 -0
  78. package/src/patches/platforms/claude/startup-update-hook/patch.json +28 -0
  79. package/src/patches/platforms/codex/dispatch-mode/patch.json +17 -0
  80. package/src/patches/platforms/codex/remove-multi-agent-v2/patch.json +16 -0
  81. package/src/patches/platforms/codex/session-start-hooks/patch.json +51 -0
  82. package/enhancements/0.6/overrides/skills/trellis-finish-work.md +0 -92
  83. package/enhancements/0.6/overrides/transforms/intent-routing.json +0 -248
  84. package/enhancements/0.6/overrides/workflow-states/in_progress-inline.md +0 -15
  85. package/enhancements/0.6/overrides/workflow-states/in_progress.md +0 -15
  86. package/enhancements/0.6/overrides/workflow-states/planning-inline.md +0 -12
  87. package/enhancements/0.6/overrides/workflow-states/planning.md +0 -12
  88. package/src/lib/enhancement-transform.js +0 -422
  89. package/src/lib/hook-override-inject.js +0 -94
  90. package/src/lib/skill-override-inject.js +0 -154
  91. /package/enhancements/0.6/overrides/{transforms/content/claude-session-start-no-task.py → patches/hooks/claude-session-start/no-task-routing/content.py} +0 -0
  92. /package/enhancements/0.6/overrides/{transforms/matches/claude-session-start-no-task.py → patches/hooks/claude-session-start/no-task-routing/selector.py} +0 -0
  93. /package/enhancements/0.6/overrides/{transforms/content/codex-session-start-no-task.py → patches/hooks/codex-session-start/no-task-routing/content.py} +0 -0
  94. /package/enhancements/0.6/overrides/{transforms/matches/codex-session-start-no-task.py → patches/hooks/codex-session-start/no-task-routing/selector.py} +0 -0
  95. /package/enhancements/0.6/overrides/{hooks/shared/inject-workflow-state.py → patches/hooks/inject-workflow-state/shared-runtime/content.py} +0 -0
  96. /package/enhancements/0.6/overrides/{transforms/content/brainstorm-auto-task-create.md → patches/skills/trellis-brainstorm/auto-task-create/content.md} +0 -0
  97. /package/enhancements/0.6/overrides/{transforms/matches/brainstorm-auto-task-create.md → patches/skills/trellis-brainstorm/auto-task-create/selector.md} +0 -0
  98. /package/enhancements/0.6/overrides/{transforms/content/brainstorm-planning-authorization.md → patches/skills/trellis-brainstorm/planning-authorization/content.md} +0 -0
  99. /package/enhancements/0.6/overrides/{transforms/matches/brainstorm-planning-authorization.md → patches/skills/trellis-brainstorm/planning-authorization/selector.md} +0 -0
  100. /package/enhancements/0.6/overrides/{transforms/content/start-no-task-routing.md → patches/skills/trellis-start/no-task-routing/content.md} +0 -0
  101. /package/enhancements/0.6/overrides/{transforms/matches/start-no-task-routing.md → patches/skills/trellis-start/no-task-routing/selector.md} +0 -0
  102. /package/enhancements/0.6/overrides/{transforms/content/workflow-create-task-command.md → patches/workflow/intent-routing/create-task-command/content.md} +0 -0
  103. /package/enhancements/0.6/overrides/{transforms/matches/workflow-create-task-command.md → patches/workflow/intent-routing/create-task-command/selector.md} +0 -0
  104. /package/enhancements/0.6/overrides/{transforms/content/workflow-create-task-rule.md → patches/workflow/intent-routing/create-task-rule/content.md} +0 -0
  105. /package/enhancements/0.6/overrides/{transforms/matches/workflow-create-task-rule.md → patches/workflow/intent-routing/create-task-rule/selector.md} +0 -0
  106. /package/enhancements/0.6/overrides/{transforms/content/workflow-customization-intent-invariant.md → patches/workflow/intent-routing/customization-intent-invariant/content.md} +0 -0
  107. /package/enhancements/0.6/overrides/{transforms/matches/workflow-customization-intent-invariant.md → patches/workflow/intent-routing/customization-intent-invariant/selector.md} +0 -0
  108. /package/enhancements/0.6/overrides/{transforms/content/workflow-phase-index-create-task.md → patches/workflow/intent-routing/phase-index-create-task/content.md} +0 -0
  109. /package/enhancements/0.6/overrides/{transforms/matches/workflow-phase-index-create-task.md → patches/workflow/intent-routing/phase-index-create-task/selector.md} +0 -0
  110. /package/enhancements/0.6/overrides/{transforms/content/workflow-phase-one-goal.md → patches/workflow/intent-routing/phase-one-goal/content.md} +0 -0
  111. /package/enhancements/0.6/overrides/{transforms/matches/workflow-phase-one-goal.md → patches/workflow/intent-routing/phase-one-goal/selector.md} +0 -0
  112. /package/enhancements/0.6/overrides/{transforms/content/workflow-phase-summary.md → patches/workflow/intent-routing/phase-summary/content.md} +0 -0
  113. /package/enhancements/0.6/overrides/{transforms/matches/workflow-phase-summary.md → patches/workflow/intent-routing/phase-summary/selector.md} +0 -0
  114. /package/enhancements/0.6/overrides/{transforms/content/workflow-request-triage.md → patches/workflow/intent-routing/request-triage/content.md} +0 -0
  115. /package/enhancements/0.6/overrides/{transforms/matches/workflow-request-triage.md → patches/workflow/intent-routing/request-triage/selector.md} +0 -0
  116. /package/enhancements/0.6/overrides/{transforms/content/workflow-no-task-body.md → patches/workflow/state-no-task/content.md} +0 -0
  117. /package/enhancements/0.6/overrides/{transforms/matches/workflow-no-task-body.md → patches/workflow/state-no-task/selector.md} +0 -0
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  > 一条命令装好 [Trellis](https://docs.trytrellis.app/) 工程框架,并自动融合 **skill-garden** 强化包。
8
8
 
9
- `flower-trellis` 是 Trellis 的 npm 封装 CLI,把原本要分两步的工作合并为一键完成:安装/升级 Trellis 本体,并在其上叠加 skill-garden 的强化包(一组 `trellis-*` 技能与 workflow / skill override)。强化包以快照形式随包发布,安装过程**零网络依赖**。
9
+ `flower-trellis` 是 Trellis 的 npm 封装 CLI,把原本要分两步的工作合并为一键完成:安装/升级 Trellis 本体,并在其上叠加 skill-garden 的强化包(一组 `trellis-*` 技能与统一 Patch catalog)。强化包以快照形式随包发布,安装过程**零网络依赖**。
10
10
 
11
11
  底层调用官方 `@mindfoldhq/trellis` 的 `init` / `update`,并按目标项目的 Trellis 版本自动选择匹配的强化包变体(`old` / `0.5` / `0.6`)。
12
12
 
@@ -104,9 +104,9 @@ flower-trellis -v
104
104
 
105
105
  运行 `init` / `update` 时,flower-trellis 会顺带检测**自身**在 npm 上是否有新版本:
106
106
 
107
- - **联网、尽力而为**:带 2.5s 超时,离线 / 超时 / 失败一律静默跳过,绝不阻断安装/升级主流程。
108
- - **稳定版安装**:只跟随 npm `latest` 通道;发现稳定新版时提示 `npm i -g flower-trellis@latest`。
109
- - **beta 版安装**:版本号形如 `0.3.0-beta.1`,会同时检查 `beta` 与 `latest`;若 `latest` 已高于当前 beta,优先提示 `npm i -g flower-trellis@latest`,否则提示更新到 `npm i -g flower-trellis@beta`。
107
+ - **联网、尽力而为**:带 5s 超时,离线 / 超时 / 失败一律静默跳过,绝不阻断安装/升级主流程。
108
+ - **稳定版安装**:只跟随 npm `latest` 通道;发现稳定新版时安装已确认的精确版本,并使用 `--prefer-online` 避免旧 metadata 缓存。
109
+ - **beta 版安装**:版本号形如 `0.3.0-beta.1`,会同时检查 `beta` 与 `latest`;若 `latest` 已高于当前 beta,优先回归稳定版,否则安装已确认的精确 beta 版本。
110
110
  - **发现新版**(交互终端):提示并询问是否立即升级;同意则执行推荐的安装命令,成功后请按提示重新运行命令(升级后强化包随新版更新,可再跑一次 `ft update` 重新叠加)。
111
111
  - **非交互**(`-y` 或非 TTY):仅打印一行升级提示,不弹确认、不阻塞。
112
112
  - **跳过检测**:经 `npx` 运行(本就是最新版)、或显式 `--no-update-check` / `FLOWER_NO_UPDATE_CHECK=1` 时不检测。
@@ -209,8 +209,9 @@ flower banner → 平台多选菜单 → Trellis 原生交互(模板 / monorepo
209
209
 
210
210
  - **统一品牌头部**:Trellis 子进程在伪终端(`node-pty`)中运行,其原生的模板 / monorepo / 冲突等交互完整保留,但重复打印的启动 banner 被过滤,全程只呈现一个 flower banner。
211
211
  - **按平台铺设技能**:Claude 铺到 `.claude/skills`,Codex / Gemini 等铺到 `.agents/skills`;并做平台后处理:Codex 兼容清理旧 `config.toml` 的 `[features.multi_agent_v2]`,在保留上游 hooks 的基础上补全 `SessionStart`;Claude Code 只在 `startup` SessionStart 挂载启动更新检查。
212
- - **幂等执行**:`workflow.md` 注入前先按 `BEGIN/END` 标记清除旧块再重注入(块数恒定,不会翻倍,首次注入前备份到 `.trellis/.backup-flower/`);技能文件覆盖式铺设,并通过 `.trellis/.flower-manifest.json` 记录已铺路径,升级时删除已淘汰项。
213
- - **上线事项账本**:强化包通过 finish-work skill override 在归档前智能识别 SQL、配置、批处理 / 部署脚本 / 数据修复、外部系统 / 依赖平台等上线事项,必要时写入任务 `release.md`;`trellis-release` 可在正式上线前核对任务文档、`release.md` 和 git 证据,生成 `YYYY-MM-DD-<release-slug>.md` 格式的版本 / 批次操作单。
212
+ - **幂等执行**:0.6 Patch 使用受管 marker 原位升级,完整预检通过后只写 changed 文件,首次修改前备份到 `.trellis/.backup-flower/`;技能资产覆盖式铺设,并通过 `.trellis/.flower-manifest.json` 精确清理已淘汰路径。0.5/old 继续使用兼容注入路径。
213
+ - **结构化 Patch**:Trellis 0.6 workflow、skill、hook 与平台配置统一通过 `insert / replace / remove` 预检后应用;selector/baseline 或已知最终协议冲突时在写入前停止。
214
+ - **上线事项账本**:强化包通过 Finish-Work Patch 在归档前智能识别 SQL、配置、批处理 / 部署脚本 / 数据修复、外部系统 / 依赖平台等上线事项,必要时写入任务 `release.md`;`trellis-release` 可在正式上线前核对任务文档、`release.md` 和 git 证据,生成 `YYYY-MM-DD-<release-slug>.md` 格式的版本 / 批次操作单。
214
215
  - **安全中止**:`Ctrl+C` 取消后不会继续叠加。
215
216
 
216
217
  ## 强化包与更新
@@ -224,6 +225,8 @@ flower banner → 平台多选菜单 → Trellis 原生交互(模板 / monorepo
224
225
  npm i -g flower-trellis@latest && flower-trellis update
225
226
  ```
226
227
 
228
+ - **0.6 兼容门禁**:当前强化快照已登记 Trellis `0.6.5`。未登记的同一 `0.6.x` 会显示 `untested-upstream` 警告,并在完整 Patch/冲突检查通过后继续;`0.7+` / `1.x` 不会自动复用 0.6 baseline。遇到未支持的新版本时,先升级 flower-trellis,或使用 `--no-enhance` 只运行纯上游 Trellis。
229
+
227
230
  - **通用技能**:`flower-trellis update` 会用新版快照覆盖仓库中已经启用的 common skill,
228
231
  未启用项不会自动安装;若某个已安装 common skill 已从新版快照移除,更新会精确删除其
229
232
  `.codex/skills` / `.claude/skills` 或历史 `.agents/skills` 副本。
@@ -20,6 +20,7 @@ description: "启动、恢复和推进 Trellis 自动任务循环。用于用户
20
20
  - 启动 runner 前先完成 route 准备度判断:已有当前任务 runtime route 决策或个人 `.trellis/.route-prefs.tmp` 时可启动;没有时先进入 `trellis-route` 正常询问 / fallback,写入真实决策后再启动。
21
21
  - auto-loop 不默认写 `route_authorization`;只有用户本次明确给出的临时 route 策略,才能通过 `--route-implement` / `--route-check` 传给 runner,且不能当成模型真实执行结果。
22
22
  - auto-loop 启动前若 implement 与 check 都缺 route,优先展示 auto-loop 专用的合并选择,不要把 `trellis-route` 的两套完整 fallback 原样贴给用户。仍允许用户回复高级格式 `implement 1, check 1`。
23
+ - 检查深度由 run 级 `--check-depth auto|light|full` 控制,默认 `auto`,与 `--route-check` 独立;历史 run 缺少该字段时按 `full` 兼容。
23
24
  - 代码提交必须复用 `trellis-push` 的内部 commit-only 执行能力;auto-loop 自己负责预授权校验和 runner 回写,不要裸 `git commit` / `git push`。
24
25
 
25
26
  ## 启动
@@ -60,10 +61,13 @@ auto-loop 需要你先选执行路线,才能启动。
60
61
  python3 ./.trellis/scripts/auto_loop.py start \
61
62
  --tasks <task> [<task> ...] \
62
63
  --profile commit-only \
64
+ [--check-depth auto|light|full] \
63
65
  [--route-implement inline|subagent] \
64
66
  [--route-check check-all-inline|check-all-subagent]
65
67
  ```
66
68
 
69
+ 除非用户明确指定 light/full,启动时使用默认 `--check-depth auto`。显式 light 仍必须进入 Check-All,命中 hard-full 时由 Check-All 升级 full;不得把它映射到顶层 `trellis-check`。
70
+
67
71
  多任务队列中,当前任务切换到下一个任务且缺少该任务 route 决策时,回到 `trellis-route` 获取该任务真实选择,再继续 `next` / `record`。个人 `.trellis/.route-prefs.tmp` 会由 `trellis-route` 统一复用并写回 runtime。
68
72
 
69
73
  启动后立即运行:
@@ -91,6 +95,7 @@ python3 ./.trellis/scripts/auto_loop.py next
91
95
  python3 ./.trellis/scripts/auto_loop.py retry-blocked \
92
96
  [--run-id <run-id>] \
93
97
  [--task <task>] \
98
+ [--check-depth auto|light|full] \
94
99
  [--route-implement inline|subagent] \
95
100
  [--route-check check-all-inline|check-all-subagent]
96
101
  python3 ./.trellis/scripts/auto_loop.py next
@@ -105,10 +110,10 @@ python3 ./.trellis/scripts/auto_loop.py next
105
110
  | `refresh_brief` | 使用 `trellis-task-brief` 生成并展示 brief | `record --action refresh_brief --result ok` |
106
111
  | `start_task` | 执行返回的 `task.py start ...` 命令 | `record --action start_task --result ok` |
107
112
  | `run_implement` | 进入 Phase 2.1,先用 `trellis-route(target=implement)` 决定 inline/subagent,再实现 | `record --action run_implement --result ok --route-mode <mode> --route-source <source>` |
108
- | `run_check_all` | 进入 Phase 2.2,先用 `trellis-route(target=check)`,执行 check-all | `record --action run_check_all --result ok --route-mode <mode> --route-source <source>` |
113
+ | `run_check_all` | 进入 Phase 2.2,先用 `trellis-route(target=check)`,按 action 的 requested depth 执行 Check-All | `record --action run_check_all --result ok --route-mode <mode> --route-source <source> --effective-check-depth <light|full> --check-depth-reason "<摘要>"` |
109
114
  | `run_fix` | 根据 `last_failure` 修复,复用当前任务 implement route | `record --action run_fix --result ok --route-mode <mode> --route-source <source>` |
110
- | `run_recheck` | 复用当前任务 check route,重新 check-all | `record --action run_recheck --result ok --route-mode <mode> --route-source <source>` |
111
- | `run_spec_update` | 有代码/测试证据时用 `trellis-update-spec`;无必要更新也 record ok | `record --action run_spec_update --result ok` |
115
+ | `run_recheck` | 复用当前任务 check route,按 action 的 requested/minimum depth 重新 Check-All | `record --action run_recheck --result ok --route-mode <mode> --route-source <source> --effective-check-depth <light|full> --check-depth-reason "<摘要>"` |
116
+ | `run_spec_update` | 调用 `trellis-update-spec` 自主返回三态 | `no-op` / `written`:`record --action run_spec_update --result ok` 后立即 `next`;`needs-review`:`record --action run_spec_update --result blocked --failure-type spec-needs-review` |
112
117
  | `commit_only` | 校验本 run 的预授权与文件归属,再把 exact files/message 交给 `trellis-push` 内部 commit-only 执行 | auto-loop 执行 `record --action commit_only --result ok --commit <hash>` |
113
118
 
114
119
  失败时写回:
@@ -119,6 +124,8 @@ python3 ./.trellis/scripts/auto_loop.py record \
119
124
  --result failed \
120
125
  --failure-type <type> \
121
126
  --summary "<失败摘要>" \
127
+ [--effective-check-depth light|full] \
128
+ [--check-depth-reason "<深度原因>"] \
122
129
  --files <file> [<file> ...]
123
130
  ```
124
131
 
@@ -129,7 +136,9 @@ python3 ./.trellis/scripts/auto_loop.py record \
129
136
  --action <action> \
130
137
  --result blocked \
131
138
  --failure-type <type> \
132
- --summary "<阻塞原因>"
139
+ --summary "<阻塞原因>" \
140
+ [--effective-check-depth light|full] \
141
+ [--check-depth-reason "<深度原因>"]
133
142
  ```
134
143
 
135
144
  runner 会按 3 轮 fix/recheck 预算决定继续、跳过当前任务或结束队列。
@@ -140,6 +149,10 @@ route action 成功回写时必须带上 `trellis-route` 输出里的真实 `mod
140
149
  `--route-mode inline --route-source route-prefs` 或
141
150
  `--route-mode check-all-subagent --route-source trellis-route`;不要写 auto-loop 默认值。
142
151
 
152
+ `run_check_all` / `run_recheck` 无论结果为 ok、failed 还是 blocked,都必须回写 Check-All 实际产生的 effective depth 和原因。更新后的 runner 会保存 `item.last_check`;旧调用缺字段时只能按 `full / legacy-default-full` 记录,不能推断为 light。recheck action 的 `minimum_check_depth=full` 时不得降级。
153
+
154
+ 检查 action 完成后,validated auto-loop 不适用普通 Post-Check Stop Gate:inline Check-All 直接执行匹配 action 的 `record` 并立即 `next`;subagent 只返回 audit-only 报告和 `check_profile`,主会话收到后立即完成同样的 `record + next`。只有 runner action mismatch、真正产品决策、越权、生产副作用或破坏性安全边界才停止等待用户。
155
+
143
156
  ## Commit-Only 预授权
144
157
 
145
158
  auto-loop 的 `commit-only` profile 是用户对“当前 run 内任务相关本地提交”的一次性预授权。预授权判断和 runner 状态写回全部由本 skill 负责,不能下放给 `trellis-push`。
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: trellis-check-all
3
- description: "提交前或 PR 前的全维度只读审查:规划三件套实现正确性 -> 关键假设验证 -> 跨层完整性与规范。默认 collect-all,不在用户确认修复范围前修改代码。触发:全面检查、提交前检查、check-all、从 PRD/三件套到代码过一遍。仅需 lint/spec 时使用 trellis-check。"
3
+ description: "统一只读检查入口:结合任务、实际 diff、风险与运行上下文智能选择 light/full 深度,再执行规划实现、关键假设、完整性与规范审查。默认 collect-all,不在用户确认修复范围前修改代码。触发:检查、轻量检查、全面检查、提交前检查、check-all、从 PRD/三件套到代码过一遍。"
4
4
  ---
5
5
  # Check All 全维度代码检查
6
6
 
@@ -31,6 +31,7 @@ description: "提交前或 PR 前的全维度只读审查:规划三件套实
31
31
  - `subagent check-all`:subagent 只负责 audit-only 检查并返回结构化结果;主会话负责展示报告、询问一次修复范围和协调后续修复。
32
32
  - subagent 不得自行修复,也不得代替用户选择修复范围。
33
33
  - 路由由 `trellis-route(target=check)` 决定;本 skill 不自行切换 inline/subagent。
34
+ - 所有普通、最终、显式 light/full 和 auto-loop 检查都进入本 skill;`trellis-route` 只决定执行位置,不决定检查深度。
34
35
 
35
36
  ---
36
37
 
@@ -77,19 +78,69 @@ git log --oneline -10
77
78
 
78
79
  不得只依赖 session 摘要推断规划内容,必须读取实际文件。
79
80
 
80
- ### 0.3 选择快速路径或完整路径
81
+ ### 0.3 验证运行上下文
81
82
 
82
- **局部低风险路径**:文案、普通配置值、局部样式或单点条件修改,只追踪受影响的规划条目、直接引用点和必要回归路径。
83
+ 默认 `context=interactive`。只有调用方声称来自 auto-loop 时,才通过 runner 的 `status` / `next` 验证以下事实:
83
84
 
84
- **完整适用范围路径**:存在以下任一条件时,对所有适用条目执行完整检查:
85
+ - run 为 `running`;
86
+ - 当前 task 与本次检查任务一致;
87
+ - outstanding action 为 `run_check_all` 或 `run_recheck`。
85
88
 
86
- - API 契约或跨层数据流变化;
87
- - 数据模型、迁移或历史数据兼容变化;
88
- - 权限、鉴权、安全或资金相关变化;
89
- - 并发、时序、状态机或回滚机制变化;
90
- - 用户明确要求最终发布检查或完整审查。
89
+ 不得用聊天摘要、自然语言声明或直接读取 raw runtime JSON 代替 runner 验证。验证失败时不得使用 auto-loop 授权;报告失败原因,并按 interactive 边界处理。
91
90
 
92
- Step 2 各 Dimension 必须先判断 Trigger。未命中 Trigger 时标记 `N/A` 并立即跳过,不展开无关检查。
91
+ ### 0.4 解析请求深度
92
+
93
+ `requested_depth` 只允许 `auto`、`light`、`full`,优先级固定为:
94
+
95
+ 1. 当前用户请求里最新的显式深度意图;
96
+ 2. validated auto-loop action 的 `requested_check_depth`;
97
+ 3. 默认 `auto`。
98
+
99
+ 显式意图按语义识别:`简单检查`、`轻量检查`、`light check` 表示 light;`全面检查`、`全量检查`、`最终检查`、`提交前检查`、`full check` 表示 full。同一请求出现多次切换时,以最后一次明确表达为准。单独说 `check` / `check-all` 只是调用统一入口,不自动等同 full。
100
+
101
+ 历史 auto-loop state 缺少深度字段时,runner 会返回 `full`。不得根据文件数、diff 行数或“看起来简单”单独判定 light。
102
+
103
+ ### 0.5 选择有效深度
104
+
105
+ 按以下顺序生成检查画像:
106
+
107
+ ```yaml
108
+ check_profile:
109
+ context: interactive | auto-loop
110
+ requested_depth: auto | light | full
111
+ effective_depth: light | full
112
+ confidence: high | fallback-full | escalated
113
+ reasons: [string]
114
+ ```
115
+
116
+ 决策顺序:
117
+
118
+ 1. `requested=full` -> `effective=full`。
119
+ 2. 命中任一 hard-full -> `effective=full`;若请求为 light,使用 `confidence=escalated` 并记录原因。
120
+ 3. `requested=light` 且无 hard-full -> `effective=light`。
121
+ 4. `requested=auto` 且高置信满足全部 light eligibility -> `effective=light`。
122
+ 5. 其它情况 -> `effective=full`、`confidence=fallback-full`;不询问用户。
123
+
124
+ **hard-full 信号**:
125
+
126
+ - 复杂任务存在 design/implement,且本次变更需要完整验收映射;
127
+ - 跨层、跨包、跨仓、submodule 或影响面尚未完全展开;
128
+ - 公共 API、CLI、schema、持久化状态、缓存契约、迁移或历史数据兼容;
129
+ - 权限、鉴权、安全、资金、并发、时序、状态机或回滚;
130
+ - workflow、skill、command、hook 注入或生成快照;
131
+ - 安装、升级、发布、push/commit 工作流控制面;
132
+ - 正在重检既有 full `CHK-*` 修复结果;
133
+ - light 执行中发现未知 dirty path、真实影响面扩大或关键验证缺口。
134
+
135
+ **light eligibility 必须全部满足**:
136
+
137
+ - 变更可完整归属,且集中在单一局部行为;
138
+ - 无 hard-full 信号;
139
+ - 受影响规划条目、直接引用点和回归路径可穷举;
140
+ - 存在可运行的定向验证,或仅为无行为风险的文案、注释、局部样式;
141
+ - 不在既有 full 修复/重检链中。
142
+
143
+ light 执行中命中 hard-full 时,立即单向升级 full 并补齐所有适用维度;同一修复/重检循环内 full 不得降级。Step 2 各 Dimension 仍须先判断 Trigger,未命中时标记 `N/A` 并跳过。
93
144
 
94
145
  ---
95
146
 
@@ -101,7 +152,7 @@ Step 2 各 Dimension 必须先判断 Trigger。未命中 Trigger 时标记 `N/A`
101
152
  - Design API、数据模型、数据流、关键决策和 rollback:技术基线。
102
153
  - Implement 有序步骤、review gate 和 rollback point:落地基线。
103
154
 
104
- 局部低风险路径只提取受影响条目;完整路径提取所有适用条目。每条记录来源位置,实际阅读对应代码后再判断。
155
+ light 只提取可穷举的受影响条目;full 提取所有适用条目。每条记录来源位置,实际阅读对应代码后再判断。
105
156
 
106
157
  ### 1.2 必查类型
107
158
 
@@ -231,7 +282,7 @@ Step 2 各 Dimension 必须先判断 Trigger。未命中 Trigger 时标记 `N/A`
231
282
 
232
283
  ## 输出:统一检查报告
233
284
 
234
- 普通模式完成所有可继续检查后,严格按以下顺序输出:
285
+ interactive 模式完成所有可继续检查后,严格按以下顺序输出:
235
286
 
236
287
  ```markdown
237
288
  ## Trellis Check-All 结果
@@ -240,6 +291,7 @@ Step 2 各 Dimension 必须先判断 Trigger。未命中 Trigger 时标记 `N/A`
240
291
 
241
292
  任务:<任务名称或无活动任务>
242
293
  范围:<文件数与层级摘要>
294
+ 画像:requested=<auto/light/full> · effective=<light/full> · confidence=<high/fallback-full/escalated> · <原因摘要>
243
295
  结论:<一句话结论>
244
296
 
245
297
  ### 维度结果
@@ -278,6 +330,7 @@ Step 2 各 Dimension 必须先判断 Trigger。未命中 Trigger 时标记 `N/A`
278
330
  - 有问题时只在报告末尾提供一次修复范围选择,不再逐项提问。
279
331
  - 独立问题不得因数量多而静默省略;先合并同根因重复项,再完整列出剩余问题。
280
332
  - 报告不得包含 commit message、拟提交/暂存文件、commit-only 决策或提交确认。
333
+ - light 通过正式满足 Phase 2.2 检查门禁;未执行维度必须标记 `N/A`,不得伪装为已验证。
281
334
 
282
335
  ---
283
336
 
@@ -289,7 +342,7 @@ Step 2 各 Dimension 必须先判断 Trigger。未命中 Trigger 时标记 `N/A`
289
342
  2. 修复过程中不对每个问题重复确认。
290
343
  3. 新增业务歧义、破坏性风险或范围扩张时才暂停,并一次性说明受影响问题。
291
344
  4. 完成定向验证后复用当前 check route 重新执行 Check-All。
292
- 5. 原问题沿用 ID;新根因继续递增编号。
345
+ 5. 原问题沿用 ID;新根因继续递增编号。上次 `effective_depth=full` 时,本次最小深度为 full。
293
346
 
294
347
  修复完成后输出:
295
348
 
@@ -313,20 +366,21 @@ Step 2 各 Dimension 必须先判断 Trigger。未命中 Trigger 时标记 `N/A`
313
366
 
314
367
  ---
315
368
 
316
- ## Auto-Loop 规则
369
+ ## Auto-Loop Return Gate
317
370
 
318
- 运行中的 auto-loop 复用相同的 audit-only 检查和问题模型,但不展示普通模式的修复选择:
371
+ validated auto-loop 复用相同的 audit-only 检查、画像和问题模型,但不展示普通模式的修复选择:
319
372
 
320
- - 有问题:向 runner `record --result failed`,摘要包含最高严重度、问题 ID、根因和受影响文件;随后由 runner 进入 `run_fix`。
321
- - 真正需要用户产品决策或越权:`record --result blocked`。
322
- - 无问题:`record --result ok`,继续 runner 返回的下一步。
373
+ - 有问题:向 runner `record --result failed --effective-check-depth <light|full> --check-depth-reason <summary>`,摘要包含最高严重度、问题 ID、根因和受影响文件;随后立即 `next`,由 runner 进入 `run_fix`。
374
+ - 真正需要用户产品决策、越权、生产副作用或破坏性安全决策:使用同样深度字段 `record --result blocked`,随后按 runner 状态停止。
375
+ - 无问题:`record --result ok --effective-check-depth <light|full> --check-depth-reason <summary>`,随后立即 `next`。
376
+ - subagent 只返回结构化报告和 `check_profile`;主会话收到后必须立即完成匹配 action 的 `record + next`,不得先套用 interactive 停止边界。
323
377
  - 不修改 runner 的 fix/recheck 预算、commit-only 授权或队列行为。
324
378
 
325
379
  ---
326
380
 
327
- ## Post-Check 停止边界
381
+ ## Interactive Post-Check Stop Gate
328
382
 
329
- 普通检查报告输出后立即停止并等待用户选择。允许输出的内容只有:
383
+ 非 validated auto-loop 的检查报告输出后立即停止并等待用户选择。允许输出的内容只有:
330
384
 
331
385
  - 各维度状态、问题数和问题清单;
332
386
  - 已执行验证及结果;
@@ -2,8 +2,8 @@
2
2
  name: trellis-route
3
3
  description: |
4
4
  Route trellis-implement / trellis-check execution mode with a gitignored personal preference file.
5
- Implement can route inline or subagent. Check defaults to check-all inline/subagent; lightweight
6
- trellis-check is hidden and only available when the user explicitly requests "light check" / "轻量检查".
5
+ Implement can route inline or subagent. Check always routes the unified trellis-check-all entry
6
+ inline or subagent; check-all itself selects light/full depth from intent and risk.
7
7
  Invoked from Phase 2.1 target=implement and Phase 2.2 target=check/check-all of the routing-aware workflow.
8
8
  Current-task repair/recheck loops reuse the latest valid route decision instead of prompting again.
9
9
  Compacted resumes recover same-session route choices from gitignored runtime state before prefs or prompting.
@@ -34,8 +34,7 @@ Codex inline mode 只表示主会话默认直接执行,不是 route 选项过
34
34
  先判断本次路由目标:
35
35
 
36
36
  - `target=implement`:决定 `inline` / `subagent`。
37
- - `target=check`:普通入口只决定 `check-all inline` / `check-all subagent`。
38
- - `target=check` 且用户明确说 `light check` / `轻量检查` / `轻量 check`:进入轻量检查隐藏逃生口。
37
+ - `target=check`:只决定 `check-all inline` / `check-all subagent`。用户明确说 light/full 时,把该意图交给 Check-All 作为 requested depth,不改变 route mode。
39
38
 
40
39
  再判断用户是否要求覆盖个人配置:
41
40
 
@@ -99,7 +98,7 @@ helper 默认输出为精简 JSON,只包含 route 执行必需的 `status`、`
99
98
 
100
99
  ### target = check,且 resolve 未命中
101
100
 
102
- 普通 check 路由不展示轻量 `trellis-check`。
101
+ check 路由始终展示统一 Check-All 入口;深度由 Check-All 决定。
103
102
 
104
103
  - **question**: "本次 check 走哪种模式?"
105
104
  - **header**: "Check 模式"
@@ -111,7 +110,7 @@ helper 默认输出为精简 JSON,只包含 route 执行必需的 `status`、`
111
110
 
112
111
  ### target = check,且用户要求临时改 / 重新选择
113
112
 
114
- 普通选项仍只展示 `check-all` 路径。
113
+ 选项仍只展示 `check-all` 路径。
115
114
 
116
115
  - **question**: "当前默认:check=<当前值或无>。本次要怎么处理?"
117
116
  - **header**: "Check 覆盖"
@@ -122,25 +121,6 @@ helper 默认输出为精简 JSON,只包含 route 执行必需的 `status`、`
122
121
  4. label "4. 更新默认为 Check-all subagent", description "本次使用 check-all subagent,并写入个人配置"
123
122
  5. label "5. 清除默认", description "删除 check 默认,然后重新显示无配置选项"
124
123
 
125
- ### target = check,且用户明确请求轻量检查
126
-
127
- 轻量 `trellis-check` 是隐藏逃生口,不写入个人默认。
128
-
129
- 如果用户已经明确 inline / subagent:
130
-
131
- - `轻量检查 inline` / `light check inline` → 直接输出 `inline check`
132
- - `轻量检查 subagent` / `light check subagent` → 直接输出 `subagent check`
133
-
134
- 如果用户只说轻量检查但未指定执行方式:
135
-
136
- - **question**: "用户明确请求轻量检查。本次轻量 check 走哪种模式?"
137
- - **header**: "轻量 Check"
138
- - **options**:
139
- 1. label "1. 轻量 Check inline", description "主 agent 执行 trellis-check,只影响这一次"
140
- 2. label "2. 轻量 Check subagent", description "dispatch trellis-check,只影响这一次"
141
-
142
- ---
143
-
144
124
  ## Step 2.5: 读 subagent_skip_compile
145
125
 
146
126
  仅 `target=implement` 且最终选择 `subagent` 时读取:
@@ -201,8 +181,6 @@ helper 写入规则:保留另一个 target 的 runtime 决策和偏好;覆
201
181
  | `subagent implement` | `Agent({subagent_type: "trellis-implement"})`;若 `subagent_skip_compile=true`,dispatch prompt 附加“跳过 mvn install / npm run build / tsc 等耗时编译类检查(已由主 agent 验证或最终统一执行)” |
202
182
  | `inline check-all` | `Skill({skill: "trellis-check-all"})` |
203
183
  | `subagent check-all` | 优先使用明确 audit-only 的 `trellis-check-all` agent;不存在时使用平台通用 subagent,并用下方 dispatch 契约执行本地 `trellis-check-all`。禁止 fallback 到会直接修改工作区的 `trellis-check` agent;无兼容 subagent 时停止并请用户改选 inline |
204
- | `inline check` | 仅轻量检查隐藏逃生口;`Skill({skill: "trellis-check"})` |
205
- | `subagent check` | 仅轻量检查隐藏逃生口;`Agent({subagent_type: "trellis-check"})` |
206
184
 
207
185
  ### Subagent Check-All Dispatch 契约
208
186
 
@@ -228,17 +206,16 @@ Active task: <task path from task.py current>
228
206
  ### 输出模板
229
207
 
230
208
  ```markdown
231
- 路由决定:<inline/subagent> <implement | check-all | check>
209
+ 路由决定:<inline/subagent> <implement | check-all>
232
210
  [来自个人 route 配置:`.trellis/.route-prefs.tmp` (<key>=<value>)。]
233
211
  [来自 auto-loop 临时 route 授权:`.trellis/.runtime/auto-loop/<run-id>.json`。]
234
212
  [来自 session runtime route state:`.trellis/.runtime/sessions/<context-key>.json` 的 `route_decisions`。]
235
213
  [已写入 session runtime route state:`.trellis/.runtime/sessions/<context-key>.json` 的 `route_decisions`。]
236
- [说明:用户明确请求轻量检查,使用隐藏逃生口。]
237
214
  [仅当本消息刚展示 route 选项并等待用户回答时:用户下一条紧邻裸数字回复才可按本 target 解释;摘要、历史消息或旧 target 的裸数字无效。]
238
215
 
239
216
  route_decision:
240
217
  target: <implement | check>
241
- mode: <inline | subagent | check-all-inline | check-all-subagent | check-inline | check-subagent>
218
+ mode: <inline | subagent | check-all-inline | check-all-subagent>
242
219
  source: <trellis-route | route-prefs | auto-loop | numbered-fallback>
243
220
  scope: task
244
221
  task: <current task path>
@@ -251,7 +228,7 @@ route_decision:
251
228
  - <要避免的工具调用>
252
229
  ```
253
230
 
254
- 中括号内行为条件性出现:仅命中个人配置时显示配置行;仅命中 runtime state 时显示“来自”行;写入 runtime state 成功时显示“已写入”行;仅轻量 check 时显示隐藏逃生口说明;仅展示选项并等待用户时显示裸数字有效性提醒;仅 implement subagent + skip_compile=true 时附加“跳过编译”段。`route_decision` 必须保留在回复中,并至少保留 target/mode/source/scope/task;需要 path/decided_at 等诊断字段时重新调用 helper 并加 `--verbose`。compact summary 若只有自然语言描述,后续 agent 仍应优先读取 runtime state,而不是把 summary 当证据。
231
+ 中括号内行为条件性出现:仅命中个人配置时显示配置行;仅命中 runtime state 时显示“来自”行;写入 runtime state 成功时显示“已写入”行;仅展示选项并等待用户时显示裸数字有效性提醒;仅 implement subagent + skip_compile=true 时附加“跳过编译”段。`route_decision` 必须保留在回复中,并至少保留 target/mode/source/scope/task;需要 path/decided_at 等诊断字段时重新调用 helper 并加 `--verbose`。compact summary 若只有自然语言描述,后续 agent 仍应优先读取 runtime state,而不是把 summary 当证据。
255
232
 
256
233
  ---
257
234
 
@@ -264,12 +241,11 @@ route_decision:
264
241
  5. **auto 授权低于个人默认**:auto-loop 临时授权只在 runtime 和个人偏好都 miss 时生效。
265
242
  6. **显式覆盖优先于一切**:用户要求临时改、重新选择或清除默认时,必须重新展示选项,不能让 runtime state 或配置优先。
266
243
  7. **当前任务复用路由**:当前任务内已有合法来源的最近 implement/check 路由时,后续实现、修复、重检和复查默认沿用,不再次询问模式。
267
- 8. **check 默认全面检查**:普通 check 路由只展示 `check-all` inline/subagent,不推荐轻量 `trellis-check`。
268
- 9. **轻量 check 是隐藏逃生口**:只有用户明确请求 `light check` / `轻量检查` 时才可走轻量 `trellis-check`。
269
- 10. **check-all subagent 保持只读**:不得 fallback 到强制自修复的 `trellis-check` agent;不兼容时显式阻塞并让用户重选。
270
- 11. **决策与执行分离**:本 skill 只输出指令,下一轮由主 agent 调工具。
271
- 12. **严格执行用户选择**:路由结论一旦输出,主 agent 必须按指令执行,不可“出于谨慎”再换路径。
272
- 13. **Codex inline 不裁剪选项**:Codex inline 是默认执行模式,不是只能 inline 的强制模式;route 明确选中 subagent 时,本步骤可按 subagent 路径执行。
244
+ 8. **check 入口统一**:check 路由只展示 `check-all` inline/subagent;light/full 是 Check-All 的 requested depth,不是 route mode。
245
+ 9. **check-all subagent 保持只读**:不得 fallback 到强制自修复的 `trellis-check` agent;不兼容时显式阻塞并让用户重选。
246
+ 10. **决策与执行分离**:本 skill 只输出指令,下一轮由主 agent 调工具。
247
+ 11. **严格执行用户选择**:路由结论一旦输出,主 agent 必须按指令执行,不可“出于谨慎”再换路径。
248
+ 12. **Codex inline 不裁剪选项**:Codex inline 是默认执行模式,不是只能 inline 的强制模式;route 明确选中 subagent 时,本步骤可按 subagent 路径执行。
273
249
 
274
250
  ---
275
251
 
@@ -280,12 +256,11 @@ route_decision:
280
256
  - 把 `.trellis/.route-prefs.tmp` 加入 git 暂存或提交计划。
281
257
  - 把 `.trellis/.runtime/sessions/` 加入 git 暂存或提交计划。
282
258
  - runtime state 的 task/target/source/mode 不匹配时仍复用。
283
- - 在普通 check 选项里展示 `Check inline` / `Check subagent`。
284
- - 没有用户明确请求时,把 check 降级到轻量 `trellis-check`。
259
+ - 把显式 light/full 当成新的 route mode,或绕过 Check-All 直达 `trellis-check`。
285
260
  - check-all subagent 不存在专用 agent 时,fallback 到带自修复语义的 `trellis-check` agent。
286
261
  - 平台没有兼容的 audit-only subagent 时,静默改成 inline 或继续执行。
287
262
  - `AskUserQuestion` / `request_user_input` 不可用时,记录为 inline 或 subagent 路径并继续。
288
- - 没有有效 check 配置、用户选择或最近本轮 check 路由决定时,自动执行 inline check
263
+ - 没有有效 check 配置、用户选择或最近本轮 check 路由决定时,自动执行 Check-All inline。
289
264
  - 没有 `source` 合法的 `route_decision`,就把“用户说过 inline/subagent”或 compact summary 当成已路由。
290
265
  - 把 compact summary、ordinary summary、SessionStart 摘要、replacement history 或历史消息里的裸数字 `1` 当成当前 target 的 numbered fallback 选择。
291
266
  - 用户裸数字回复不是紧邻当前 route 选项消息时,仍调用 `write --source numbered-fallback`。
@@ -15,11 +15,12 @@ from typing import Any
15
15
  VALID_SOURCES = {"trellis-route", "numbered-fallback", "route-prefs", "auto-loop"}
16
16
  VALID_MODES = {
17
17
  "implement": {"inline", "subagent"},
18
+ "check": {"check-all-inline", "check-all-subagent"},
19
+ }
20
+ LEGACY_MODE_ALIASES = {
18
21
  "check": {
19
- "check-all-inline",
20
- "check-all-subagent",
21
- "check-inline",
22
- "check-subagent",
22
+ "check-inline": "check-all-inline",
23
+ "check-subagent": "check-all-subagent",
23
24
  },
24
25
  }
25
26
  PREF_MODES = {
@@ -89,6 +90,13 @@ def _decision_summary(decision: dict[str, Any]) -> dict[str, Any]:
89
90
  }
90
91
 
91
92
 
93
+ def _normalize_mode(target: str, mode: Any) -> str | None:
94
+ """把历史 route mode 归一为当前统一入口,非法值返回 None。"""
95
+ aliases = LEGACY_MODE_ALIASES.get(target, {})
96
+ normalized = aliases.get(mode, mode)
97
+ return str(normalized) if normalized in VALID_MODES[target] else None
98
+
99
+
92
100
  def _current_task(repo_root: Path) -> tuple[str | None, str | None, str | None]:
93
101
  """通过 task.py current --source 获取当前任务和 session key。"""
94
102
  result = subprocess.run(
@@ -155,8 +163,10 @@ def _read_prefs(repo_root: Path) -> dict[str, str]:
155
163
  key, value = raw.split("=", 1)
156
164
  key = key.strip()
157
165
  value = value.strip()
158
- if key in PREF_MODES and value in PREF_MODES[key]:
159
- prefs[key] = value
166
+ if key in PREF_MODES:
167
+ normalized = _normalize_mode(key, value)
168
+ if normalized in PREF_MODES[key]:
169
+ prefs[key] = normalized
160
170
  return prefs
161
171
 
162
172
 
@@ -222,7 +232,7 @@ def _auto_route_mode(repo_root: Path, context_key: str, target: str) -> tuple[st
222
232
  if not isinstance(auth, dict):
223
233
  return None, path, "no-route-authorization"
224
234
 
225
- mode = auth.get(target)
235
+ mode = _normalize_mode(target, auth.get(target))
226
236
  if mode in PREF_MODES[target]:
227
237
  return mode, path, None
228
238
  return None, path, "invalid-auto-route-mode"
@@ -252,17 +262,22 @@ def _write_prefs(repo_root: Path, prefs: dict[str, str]) -> None:
252
262
  path.write_text("\n".join(lines) + "\n", encoding="utf-8")
253
263
 
254
264
 
255
- def _valid_decision(decision: Any, target: str, current_task: str) -> bool:
256
- """校验 runtime 中的 route 决策是否能复用。"""
265
+ def _normalized_decision(decision: Any, target: str, current_task: str) -> dict[str, Any] | None:
266
+ """校验并归一化 runtime route 决策,非法时返回 None。"""
257
267
  if not isinstance(decision, dict):
258
- return False
259
- return (
268
+ return None
269
+ mode = _normalize_mode(target, decision.get("mode"))
270
+ if not (
260
271
  decision.get("target") == target
261
- and decision.get("mode") in VALID_MODES[target]
272
+ and mode is not None
262
273
  and decision.get("source") in VALID_SOURCES
263
274
  and decision.get("scope") == "task"
264
275
  and decision.get("task") == current_task
265
- )
276
+ ):
277
+ return None
278
+ normalized = dict(decision)
279
+ normalized["mode"] = mode
280
+ return normalized
266
281
 
267
282
 
268
283
  def _decision(target: str, mode: str, source: str, current_task: str) -> dict[str, str]:
@@ -336,15 +351,16 @@ def read_runtime(args: argparse.Namespace) -> int:
336
351
  path = _session_path(repo_root, context_key)
337
352
  context = _read_json(path)
338
353
  decision = context.get("route_decisions", {}).get(args.target)
339
- if _valid_decision(decision, args.target, current_task):
354
+ normalized = _normalized_decision(decision, args.target, current_task)
355
+ if normalized is not None:
340
356
  return _output(
341
357
  args,
342
358
  {
343
359
  "status": "hit",
344
- **_decision_summary(decision),
360
+ **_decision_summary(normalized),
345
361
  },
346
362
  {
347
- "decision": decision,
363
+ "decision": normalized,
348
364
  "path": _rel_path(repo_root, path),
349
365
  "context_key": context_key,
350
366
  "task": current_task,
@@ -379,19 +395,31 @@ def resolve_route(args: argparse.Namespace) -> int:
379
395
  path = _session_path(repo_root, context_key)
380
396
  context = _read_json(path)
381
397
  decision = context.get("route_decisions", {}).get(args.target)
382
- if _valid_decision(decision, args.target, current_task):
398
+ normalized = _normalized_decision(decision, args.target, current_task)
399
+ if normalized is not None:
400
+ written_path = path
401
+ if normalized.get("mode") != decision.get("mode"):
402
+ written_path, normalized = _write_runtime_decision(
403
+ repo_root,
404
+ context_key,
405
+ current_task,
406
+ args.target,
407
+ str(normalized["mode"]),
408
+ str(normalized["source"]),
409
+ )
383
410
  return _output(
384
411
  args,
385
412
  {
386
413
  "status": "hit",
387
414
  "origin": "runtime",
388
- **_decision_summary(decision),
415
+ **_decision_summary(normalized),
389
416
  },
390
417
  {
391
- "decision": decision,
392
- "path": _rel_path(repo_root, path),
418
+ "decision": normalized,
419
+ "path": _rel_path(repo_root, written_path),
393
420
  "context_key": context_key,
394
421
  "task": current_task,
422
+ "normalized_legacy_mode": normalized.get("mode") != decision.get("mode"),
395
423
  }
396
424
  )
397
425
 
@@ -472,7 +500,8 @@ def write_route(args: argparse.Namespace) -> int:
472
500
  """写入当前 target 的 route 决策并保留 session 文件的其他字段。"""
473
501
  if args.source not in VALID_SOURCES:
474
502
  return _print({"status": "error", "reason": "invalid-source", "source": args.source})
475
- if args.mode not in VALID_MODES[args.target]:
503
+ mode = _normalize_mode(args.target, args.mode)
504
+ if mode is None:
476
505
  return _print(
477
506
  {
478
507
  "status": "error",
@@ -487,7 +516,7 @@ def write_route(args: argparse.Namespace) -> int:
487
516
  return _print({"status": "skipped", "reason": "not-trellis-project"})
488
517
 
489
518
  if args.save_pref:
490
- if args.mode not in PREF_MODES[args.target]:
519
+ if mode not in PREF_MODES[args.target]:
491
520
  return _print(
492
521
  {
493
522
  "status": "error",
@@ -497,7 +526,7 @@ def write_route(args: argparse.Namespace) -> int:
497
526
  }
498
527
  )
499
528
  prefs = _read_prefs(repo_root)
500
- prefs[args.target] = args.mode
529
+ prefs[args.target] = mode
501
530
  _write_prefs(repo_root, prefs)
502
531
 
503
532
  current_task, source, context_key = _current_task(repo_root)
@@ -511,7 +540,7 @@ def write_route(args: argparse.Namespace) -> int:
511
540
  context_key,
512
541
  current_task,
513
542
  args.target,
514
- args.mode,
543
+ mode,
515
544
  args.source,
516
545
  )
517
546
  return _output(