flower-trellis 0.3.1 → 0.4.0-beta.1
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.
- package/README.md +1 -1
- package/enhancements/0.6/.agents/skills/trellis-auto-loop/SKILL.md +133 -0
- package/enhancements/0.6/.agents/skills/trellis-push/SKILL.md +18 -1
- package/enhancements/0.6/.agents/skills/trellis-route/SKILL.md +21 -16
- package/enhancements/0.6/.agents/skills/trellis-route/scripts/route_state.py +119 -3
- package/enhancements/0.6/.claude/skills/trellis-auto-loop/SKILL.md +133 -0
- package/enhancements/0.6/.claude/skills/trellis-push/SKILL.md +18 -1
- package/enhancements/0.6/.claude/skills/trellis-route/SKILL.md +21 -16
- package/enhancements/0.6/.claude/skills/trellis-route/scripts/route_state.py +119 -3
- package/enhancements/0.6/overrides/workflow-states/in_progress-inline.md +1 -0
- package/enhancements/0.6/overrides/workflow-states/in_progress.md +1 -0
- package/enhancements/0.6/overrides/workflow-states/no_task.md +1 -0
- package/enhancements/0.6/overrides/workflow-states/planning-inline.md +2 -0
- package/enhancements/0.6/overrides/workflow-states/planning.md +2 -0
- package/enhancements/0.6/overrides/workflow.md +24 -1
- package/enhancements/0.6/scripts/auto_loop.py +1014 -0
- package/enhancements/0.6/scripts/spec_router.py +417 -0
- package/enhancements/MANIFEST.json +12 -4
- package/package.json +2 -2
- package/src/cli.js +2 -1
- package/src/constants.js +3 -0
- package/src/lib/apply-enhancements.js +11 -2
- package/src/lib/copy-scripts.js +46 -0
- package/src/lib/pick-platforms.js +4 -1
|
@@ -8,6 +8,8 @@ description: "提交并推送配置仓库,可选合并到目标分支,并同
|
|
|
8
8
|
|
|
9
9
|
核心原则:**先计划、一次确认、后执行**。在任何 `git add`、`git commit`、`git push`、`git merge` 之前,必须先展示完整执行计划,并获得用户确认。
|
|
10
10
|
|
|
11
|
+
例外:当 `trellis-auto-loop` 已显式以 `profile=commit-only` 启动,且 runner 当前有 `outstanding_action.action=commit_only` 时,用户启动 auto-loop 本身就是本次 run 内任务相关本地提交的预授权。此时仍必须由 AI 生成并自检提交计划,但可跳过二次聊天确认;计划只允许 commit-only、不 push/merge/release/archive,并在成功后把 commit hash 回写 runner。预检不安全时只标记当前 auto-loop item blocked/skipped,后续队列仍可继续。
|
|
12
|
+
|
|
11
13
|
支持多仓库(frontend / backend 等),merge 目标分支记录在 `.trellis/config.yaml` 的 `packages.<name>.merge_target` 中。
|
|
12
14
|
|
|
13
15
|
---
|
|
@@ -62,9 +64,24 @@ Step 6 输出结果
|
|
|
62
64
|
| 重新配置 | 本次允许重新指定 merge 目标,并回写 `merge_target` | `重新配置 push 目标分支` / `reconfigure push` |
|
|
63
65
|
| 临时目标 | 本次临时指定 merge 目标,不修改配置 | `push 到 hotfix 分支` |
|
|
64
66
|
| snapshot-only | 不提交业务代码,只写入 / 同步任务进度快照 | `只更新 snapshot` / `snapshot-only` |
|
|
67
|
+
| auto-loop commit-only | 由 `trellis-auto-loop` runner 的 `commit_only` action 触发,只提交本任务可归属文件,不二次确认、不 push | `trellis-auto-loop` 内部触发 |
|
|
65
68
|
|
|
66
69
|
`snapshot-only` 只在用户明确要求时使用。它仍必须展示统一执行计划;`pushed_commits` 取计划中确认的现有 commit,或按用户说明记录。
|
|
67
70
|
|
|
71
|
+
### 0.1.1 auto-loop commit-only 判定
|
|
72
|
+
|
|
73
|
+
只有同时满足以下条件,才可走 auto-loop 预授权路径:
|
|
74
|
+
|
|
75
|
+
- `.trellis/scripts/auto_loop.py status` 显示当前 `run_status=running`,profile 为 `commit-only`。
|
|
76
|
+
- status 摘要里的 `outstanding_action.action` 是 `commit_only`,且 `outstanding_action.task` 等于当前活动任务。
|
|
77
|
+
- 本次 `trellis-push` 语义是 commit-only,不包含 push / merge / release / archive。
|
|
78
|
+
- 计划拟提交文件全部能归属当前任务;未识别 dirty 文件不纳入提交。
|
|
79
|
+
- 执行前复核 git 状态与计划一致。
|
|
80
|
+
|
|
81
|
+
任一条件不满足时,不得使用预授权。普通 `trellis-push` 继续走“展示计划并等待确认”的规则。
|
|
82
|
+
|
|
83
|
+
auto-loop 预授权路径不使用额外提交 helper。AI 负责根据当前任务 artifacts、`git status`、`git diff` 和必要的文件内容判断文件归属,输出 planned files / retained files / commit message / 归属理由;`trellis-push` 负责边界复核:当前 action/profile/task 匹配、staged 区为空、无冲突、planned files 当前 dirty、planned files 不含 `.trellis/.runtime/`、`.trellis/.route-prefs.tmp`、其他任务目录或未解释文件。通过后只 `git add` planned files 并执行本地 commit,随后回写 `auto_loop.py record --action commit_only --result ok --commit <hash> ...`。预检失败时回写 `record --result blocked`,该 blocked 只影响当前 item;auto-loop runner 后续 `next` 应继续寻找后续 pending 任务。只有 merge/rebase 冲突、repo 状态不可读、脚本损坏或用户明确 stop 才停止整个 run。
|
|
84
|
+
|
|
68
85
|
### 0.2 发现候选 Git 仓库
|
|
69
86
|
|
|
70
87
|
读取 `.trellis/config.yaml` 中的 `packages` 配置,但不要把 `git: true` 当作唯一仓库发现规则。`git: true` 主要用于 Trellis session context 展示独立包仓库状态;`trellis-push` 必须以实际 Git root 为准发现可提交仓库:
|
|
@@ -131,7 +148,7 @@ git log <base_branch>..HEAD --oneline
|
|
|
131
148
|
|
|
132
149
|
## Step 2: 生成统一执行计划
|
|
133
150
|
|
|
134
|
-
这是唯一的常规确认点。**确认前禁止执行任何 `git add` / commit / push / merge / task.json 写入。**
|
|
151
|
+
这是唯一的常规确认点。**确认前禁止执行任何 `git add` / commit / push / merge / task.json 写入。** 唯一例外是已满足 Step 0.1.1 的 auto-loop commit-only 预授权;该路径仍要生成计划并执行自检,只是不再等待用户二次确认。
|
|
135
152
|
|
|
136
153
|
### 2.1 生成业务提交计划
|
|
137
154
|
|
|
@@ -13,9 +13,9 @@ description: |
|
|
|
13
13
|
|
|
14
14
|
# Trellis 路由器:implement / check 执行模式选择
|
|
15
15
|
|
|
16
|
-
主 agent 进入 Phase 2.1 实现路由或 Phase 2.2 检查路由时调用本 skill。当前上下文或 session runtime state
|
|
16
|
+
主 agent 进入 Phase 2.1 实现路由或 Phase 2.2 检查路由时调用本 skill。当前上下文或 session runtime state 内已有合法来源、target 匹配、且 task 等于当前任务路径的最近 route 决策时,后续实现、修复、重检默认复用该决策;没有合法决策时才进入本 skill 或同编号 fallback。提交前确实需要最终复查时,回到 Phase 2.2 并复用当前任务的合法 check route,除非用户明确要求重选。
|
|
17
17
|
|
|
18
|
-
个人配置只写入 `.trellis/.route-prefs.tmp`。该文件匹配 `.trellis/.gitignore` 的 `*.tmp` 规则,属于开发者本地偏好,不纳入 git,也不影响其他开发者。
|
|
18
|
+
个人配置只写入 `.trellis/.route-prefs.tmp`。该文件匹配 `.trellis/.gitignore` 的 `*.tmp` 规则,属于开发者本地偏好,不纳入 git,也不影响其他开发者。auto-loop 可在 `.trellis/.runtime/auto-loop/<run-id>.json` 写入临时 route 授权;它不是个人偏好,优先级低于 `.route-prefs.tmp`,只用于减少 auto 模式下的交互打断。
|
|
19
19
|
|
|
20
20
|
本轮 route 决策写入当前 session runtime 文件 `.trellis/.runtime/sessions/<context-key>.json` 的 `route_decisions` 字段。该文件匹配 `.trellis/.gitignore` 的 `.runtime/` 规则,只保存当前 AI session/window 的执行状态,用于压缩后恢复;它不是任务属性,不写入 `.trellis/tasks/**`,也不是长期团队配置。
|
|
21
21
|
|
|
@@ -25,9 +25,9 @@ description: |
|
|
|
25
25
|
|
|
26
26
|
个人 route 配置只决定“已获准执行后的模式”,不是开工授权。调用 helper 前,必须确认当前 workflow 已允许进入对应 target:implement 需要任务已完成规划确认并处于 `in_progress`;check 用于 Phase 2.2 检查执行,或用户明确要求最终复查 / 轻量检查。最终复查只有在 Phase 2.2 结果缺失、风险较高或用户明确要求复查时才回到 Phase 2.2;回到 Phase 2.2 后优先复用当前任务的合法 check route,除非用户明确要求重选/临时改/清除默认。如果仍在 planning、等待用户确认,或用户表达“等一下 / 我再想想”,停止,不读取 runtime/prefs。
|
|
27
27
|
|
|
28
|
-
合法 route 决策必须能追溯到 `trellis-route`、同编号 fallback
|
|
28
|
+
合法 route 决策必须能追溯到 `trellis-route`、同编号 fallback 选项、由本 skill 读取到的有效 `.trellis/.route-prefs.tmp` 配置,或由 route helper 校验过的 auto-loop 临时 route 授权,并且 `task` 字段必须等于当前 `task.py current --source` 返回的任务路径。runtime state 只能保存和恢复这些原始合法来源,不能把 `.runtime` 自身当成新的 `route_decision.source`。用户自然语言说过“inline/subagent”、compact summary、SessionStart 摘要、`codex-mode`、空 `.route-prefs.tmp`、旧单值偏好,都不能单独作为有效 route 决策。
|
|
29
29
|
|
|
30
|
-
当前上下文内已有 target
|
|
30
|
+
当前上下文内已有 target 匹配、task 等于当前任务路径、且来源合法的 route 决策时,后续实现、check 发现问题、用户指出刚检查过的实现有问题、修复后重检、提交前复查均默认复用最近 implement/check 路由;除非用户明确要求重选/临时改/清除默认,不再调用本 skill。当前上下文没有 route 决策但 runtime state 命中时,本 skill 恢复该决策并输出同样的结构化 `route_decision`。如果上下文里只有上一个任务的 `route_decision`,必须忽略并重新解析当前任务。
|
|
31
31
|
|
|
32
32
|
Codex inline mode 只表示主会话默认直接执行,不是 route 选项过滤器。即使当前上下文出现 `<codex-mode>inline...do not dispatch...</codex-mode>` 或 `workflow-state:in_progress-inline`,也不能推断“只能 inline”或跳过 subagent 选项;仍必须通过 helper resolve runtime/prefs,或在无有效配置时展示正常 inline/subagent 选项。若本 skill 的紧邻路由决定是 subagent,本步骤允许主 agent dispatch 对应 implement/check sub-agent;禁止的是绕过 `trellis-route` 直接 dispatch。
|
|
33
33
|
|
|
@@ -50,7 +50,7 @@ Codex inline mode 只表示主会话默认直接执行,不是 route 选项过
|
|
|
50
50
|
|
|
51
51
|
## Step 0.5: 解析已有 route state
|
|
52
52
|
|
|
53
|
-
仅在没有覆盖意图、当前上下文没有 target 匹配的合法 `route_decision` 时调用 helper 解析已有状态。helper 的解析顺序固定为:当前 session runtime 文件里的 `route_decisions` → `.trellis/.route-prefs.tmp
|
|
53
|
+
仅在没有覆盖意图、当前上下文没有 target + 当前 task 匹配的合法 `route_decision` 时调用 helper 解析已有状态。helper 的解析顺序固定为:当前 session runtime 文件里的 `route_decisions` → `.trellis/.route-prefs.tmp` → `.trellis/.runtime/auto-loop/<run-id>.json` 临时授权。命中 `.route-prefs.tmp` 或 auto-loop 临时授权时,helper 会自动把对应决策写回当前 session runtime,后续压缩恢复不需要再次读 prefs 或 auto-loop 状态。
|
|
54
54
|
|
|
55
55
|
调用随本 skill 分发的 helper;不要在对话中内嵌或改写 helper 逻辑:
|
|
56
56
|
|
|
@@ -60,7 +60,7 @@ python3 .agents/skills/trellis-route/scripts/route_state.py resolve --target <im
|
|
|
60
60
|
python3 .claude/skills/trellis-route/scripts/route_state.py resolve --target <implement|check>
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
helper 只接受当前 session 或唯一 session fallback 的 `.trellis/.runtime/sessions/<context-key>.json`,并只从 `route_decisions.<target>`
|
|
63
|
+
helper 只接受当前 session 或唯一 session fallback 的 `.trellis/.runtime/sessions/<context-key>.json`,并只从 `route_decisions.<target>` 恢复当前任务的决策。命中时输出 `{"status":"hit", ...}`,其中默认输出里的 `task` / `mode` / `source` 已经过 task/target/source/mode/scope 校验,可跳过 Step 2 并进入 Step 3 输出决策。`origin=route-prefs` 表示来自个人 route 配置,并且 helper 已写回 session runtime state;`origin=auto-loop` 表示来自 auto-loop 临时授权且 helper 已写回 session runtime state;`origin=runtime` 表示来自 session runtime state。
|
|
64
64
|
|
|
65
65
|
helper 默认输出为精简 JSON,只包含 route 执行必需的 `status`、`origin`、`mode`、`source`/`reason` 等字段。需要排查完整 `decision`、session 文件、context key、任务路径、个人配置路径或写回标记时,在同一命令末尾加 `--verbose`;不要为了诊断信息额外读取 runtime 文件。
|
|
66
66
|
|
|
@@ -181,7 +181,9 @@ python3 .agents/skills/trellis-route/scripts/route_state.py clear-pref --target
|
|
|
181
181
|
python3 .claude/skills/trellis-route/scripts/route_state.py clear-pref --target <implement|check>
|
|
182
182
|
```
|
|
183
183
|
|
|
184
|
-
helper 写入规则:保留另一个 target 的 runtime 决策和偏好;覆盖当前 target;`source` 保持原始合法来源,正常 skill 交互用 `trellis-route`,普通聊天编号 fallback 用 `numbered-fallback`,prefs 命中由 helper 写 `route-prefs`;保留 session runtime 文件中的 `platform`、`current_task`、`current_run` 等既有字段;内部 `task` 必须写当前 `task.py current --source` 的任务路径。写入失败不阻塞本次 route 输出,但要在回复中简短说明未持久化,压缩后可能再次询问。
|
|
184
|
+
helper 写入规则:保留另一个 target 的 runtime 决策和偏好;覆盖当前 target;`source` 保持原始合法来源,正常 skill 交互用 `trellis-route`,普通聊天编号 fallback 用 `numbered-fallback`,prefs 命中由 helper 写 `route-prefs`,auto-loop 临时授权命中由 helper 写 `auto-loop`;保留 session runtime 文件中的 `platform`、`current_task`、`current_run`、`current_auto_run` 等既有字段;内部 `task` 必须写当前 `task.py current --source` 的任务路径。写入失败不阻塞本次 route 输出,但要在回复中简短说明未持久化,压缩后可能再次询问。
|
|
185
|
+
|
|
186
|
+
当同一 session 从一个任务切换到另一个任务时,helper 写入当前任务任一 target 的决策前会清理 runtime 中属于其他任务的 `route_decisions`。个人默认仍保留在 `.trellis/.route-prefs.tmp`;清理只影响当前 session 的临时恢复状态,目的是避免新任务的 check 阶段误复用上一个任务的 check 路由。
|
|
185
187
|
|
|
186
188
|
---
|
|
187
189
|
|
|
@@ -205,6 +207,7 @@ helper 写入规则:保留另一个 target 的 runtime 决策和偏好;覆
|
|
|
205
207
|
```markdown
|
|
206
208
|
路由决定:<inline/subagent> <implement | check-all | check>
|
|
207
209
|
[来自个人 route 配置:`.trellis/.route-prefs.tmp` (<key>=<value>)。]
|
|
210
|
+
[来自 auto-loop 临时 route 授权:`.trellis/.runtime/auto-loop/<run-id>.json`。]
|
|
208
211
|
[来自 session runtime route state:`.trellis/.runtime/sessions/<context-key>.json` 的 `route_decisions`。]
|
|
209
212
|
[已写入 session runtime route state:`.trellis/.runtime/sessions/<context-key>.json` 的 `route_decisions`。]
|
|
210
213
|
[说明:用户明确请求轻量检查,使用隐藏逃生口。]
|
|
@@ -212,8 +215,9 @@ helper 写入规则:保留另一个 target 的 runtime 决策和偏好;覆
|
|
|
212
215
|
route_decision:
|
|
213
216
|
target: <implement | check>
|
|
214
217
|
mode: <inline | subagent | check-all-inline | check-all-subagent | check-inline | check-subagent>
|
|
215
|
-
source: <trellis-route | route-prefs | numbered-fallback>
|
|
218
|
+
source: <trellis-route | route-prefs | auto-loop | numbered-fallback>
|
|
216
219
|
scope: task
|
|
220
|
+
task: <current task path>
|
|
217
221
|
|
|
218
222
|
接下来主 agent 应当:
|
|
219
223
|
- <路由表里对应的工具调用形式>
|
|
@@ -223,7 +227,7 @@ route_decision:
|
|
|
223
227
|
- <要避免的工具调用>
|
|
224
228
|
```
|
|
225
229
|
|
|
226
|
-
中括号内行为条件性出现:仅命中个人配置时显示配置行;仅命中 runtime state 时显示“来自”行;写入 runtime state 成功时显示“已写入”行;仅轻量 check 时显示隐藏逃生口说明;仅 implement subagent + skip_compile=true 时附加“跳过编译”段。`route_decision`
|
|
230
|
+
中括号内行为条件性出现:仅命中个人配置时显示配置行;仅命中 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 当证据。
|
|
227
231
|
|
|
228
232
|
---
|
|
229
233
|
|
|
@@ -233,13 +237,14 @@ route_decision:
|
|
|
233
237
|
2. **runtime state 私有**:`.trellis/.runtime/sessions/` 是 session/window 状态,gitignored,不能进入提交计划。
|
|
234
238
|
3. **压缩恢复少打断**:当前上下文没有 route 决策时,先读 runtime state;命中当前任务/target 的合法决策就复用,不查 `trellis mem`,也不重问。
|
|
235
239
|
4. **个人默认次于本轮决策**:runtime state 表示“本轮已选”,优先于 `.route-prefs.tmp`。
|
|
236
|
-
5.
|
|
237
|
-
6.
|
|
238
|
-
7.
|
|
239
|
-
8.
|
|
240
|
-
9.
|
|
241
|
-
10.
|
|
242
|
-
11.
|
|
240
|
+
5. **auto 授权低于个人默认**:auto-loop 临时授权只在 runtime 和个人偏好都 miss 时生效。
|
|
241
|
+
6. **显式覆盖优先于一切**:用户要求临时改、重新选择或清除默认时,必须重新展示选项,不能让 runtime state 或配置优先。
|
|
242
|
+
7. **当前任务复用路由**:当前任务内已有合法来源的最近 implement/check 路由时,后续实现、修复、重检和复查默认沿用,不再次询问模式。
|
|
243
|
+
8. **check 默认全面检查**:普通 check 路由只展示 `check-all` inline/subagent,不推荐轻量 `trellis-check`。
|
|
244
|
+
9. **轻量 check 是隐藏逃生口**:只有用户明确请求 `light check` / `轻量检查` 时才可走轻量 `trellis-check`。
|
|
245
|
+
10. **决策与执行分离**:本 skill 只输出指令,下一轮由主 agent 调工具。
|
|
246
|
+
11. **严格执行用户选择**:路由结论一旦输出,主 agent 必须按指令执行,不可“出于谨慎”再换路径。
|
|
247
|
+
12. **Codex inline 不裁剪选项**:Codex inline 是默认执行模式,不是只能 inline 的强制模式;route 明确选中 subagent 时,本步骤可按 subagent 路径执行。
|
|
243
248
|
|
|
244
249
|
---
|
|
245
250
|
|
|
@@ -12,7 +12,7 @@ from pathlib import Path
|
|
|
12
12
|
from typing import Any
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
VALID_SOURCES = {"trellis-route", "numbered-fallback", "route-prefs"}
|
|
15
|
+
VALID_SOURCES = {"trellis-route", "numbered-fallback", "route-prefs", "auto-loop"}
|
|
16
16
|
VALID_MODES = {
|
|
17
17
|
"implement": {"inline", "subagent"},
|
|
18
18
|
"check": {
|
|
@@ -83,6 +83,7 @@ def _output(args: argparse.Namespace, data: dict[str, Any], verbose: dict[str, A
|
|
|
83
83
|
def _decision_summary(decision: dict[str, Any]) -> dict[str, Any]:
|
|
84
84
|
"""提取默认输出需要的最小 route 决策字段。"""
|
|
85
85
|
return {
|
|
86
|
+
"task": decision.get("task"),
|
|
86
87
|
"mode": decision.get("mode"),
|
|
87
88
|
"source": decision.get("source"),
|
|
88
89
|
}
|
|
@@ -129,6 +130,16 @@ def _pref_path(repo_root: Path) -> Path:
|
|
|
129
130
|
return repo_root / ".trellis/.route-prefs.tmp"
|
|
130
131
|
|
|
131
132
|
|
|
133
|
+
def _auto_loop_dir(repo_root: Path) -> Path:
|
|
134
|
+
"""返回 auto-loop runtime 目录。"""
|
|
135
|
+
return repo_root / ".trellis/.runtime/auto-loop"
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _auto_loop_pointer(repo_root: Path) -> Path:
|
|
139
|
+
"""返回当前 auto-loop run 指针文件。"""
|
|
140
|
+
return _auto_loop_dir(repo_root) / "current.json"
|
|
141
|
+
|
|
142
|
+
|
|
132
143
|
def _read_prefs(repo_root: Path) -> dict[str, str]:
|
|
133
144
|
"""读取个人 route 默认配置,只保留合法 key-value。"""
|
|
134
145
|
path = _pref_path(repo_root)
|
|
@@ -149,6 +160,74 @@ def _read_prefs(repo_root: Path) -> dict[str, str]:
|
|
|
149
160
|
return prefs
|
|
150
161
|
|
|
151
162
|
|
|
163
|
+
def _running_auto_run_paths(repo_root: Path) -> list[Path]:
|
|
164
|
+
"""扫描当前项目内所有 running auto-loop run。"""
|
|
165
|
+
running: list[Path] = []
|
|
166
|
+
for path in sorted(_auto_loop_dir(repo_root).glob("auto-*.json")):
|
|
167
|
+
state = _read_json(path)
|
|
168
|
+
if state.get("status") == "running":
|
|
169
|
+
running.append(path)
|
|
170
|
+
return running
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _auto_state_path(repo_root: Path, run_id: Any) -> Path | None:
|
|
174
|
+
"""把 run id 转成状态文件路径,非法值返回 None。"""
|
|
175
|
+
if not isinstance(run_id, str) or not run_id.strip():
|
|
176
|
+
return None
|
|
177
|
+
return _auto_loop_dir(repo_root) / f"{run_id.strip()}.json"
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _auto_route_mode(repo_root: Path, context_key: str, target: str) -> tuple[str | None, Path | None, str | None]:
|
|
181
|
+
"""读取当前 running auto-loop run 的临时 route 授权。
|
|
182
|
+
|
|
183
|
+
auto 授权低于个人 `.route-prefs.tmp`,只在当前 session runtime 绑定了
|
|
184
|
+
running `current_auto_run`,或全局 current 指针能指向 running run 时生效。
|
|
185
|
+
如果这些指针 stale,则忽略 stale pointer,并 fallback 到唯一 running run。
|
|
186
|
+
"""
|
|
187
|
+
session_path = _session_path(repo_root, context_key)
|
|
188
|
+
session = _read_json(session_path)
|
|
189
|
+
candidate_paths: list[Path] = []
|
|
190
|
+
stale_paths: list[Path] = []
|
|
191
|
+
|
|
192
|
+
for run_id in (session.get("current_auto_run"), _read_json(_auto_loop_pointer(repo_root)).get("run_id")):
|
|
193
|
+
path = _auto_state_path(repo_root, run_id)
|
|
194
|
+
if path is None:
|
|
195
|
+
continue
|
|
196
|
+
state = _read_json(path)
|
|
197
|
+
if state.get("status") == "running":
|
|
198
|
+
candidate_paths.append(path)
|
|
199
|
+
else:
|
|
200
|
+
stale_paths.append(path)
|
|
201
|
+
|
|
202
|
+
if not candidate_paths:
|
|
203
|
+
candidate_paths = _running_auto_run_paths(repo_root)
|
|
204
|
+
unique_paths = []
|
|
205
|
+
seen: set[str] = set()
|
|
206
|
+
for path in candidate_paths:
|
|
207
|
+
key = str(path)
|
|
208
|
+
if key in seen:
|
|
209
|
+
continue
|
|
210
|
+
seen.add(key)
|
|
211
|
+
unique_paths.append(path)
|
|
212
|
+
if len(unique_paths) != 1:
|
|
213
|
+
reason = "no-unique-auto-run"
|
|
214
|
+
if stale_paths and not unique_paths:
|
|
215
|
+
reason = "stale-auto-run-pointer"
|
|
216
|
+
return None, stale_paths[0] if stale_paths else None, reason
|
|
217
|
+
|
|
218
|
+
path = unique_paths[0]
|
|
219
|
+
state = _read_json(path)
|
|
220
|
+
|
|
221
|
+
auth = state.get("route_authorization")
|
|
222
|
+
if not isinstance(auth, dict):
|
|
223
|
+
return None, path, "no-route-authorization"
|
|
224
|
+
|
|
225
|
+
mode = auth.get(target)
|
|
226
|
+
if mode in PREF_MODES[target]:
|
|
227
|
+
return mode, path, None
|
|
228
|
+
return None, path, "invalid-auto-route-mode"
|
|
229
|
+
|
|
230
|
+
|
|
152
231
|
def _write_prefs(repo_root: Path, prefs: dict[str, str]) -> None:
|
|
153
232
|
"""写入个人 route 默认配置;为空则删除文件。"""
|
|
154
233
|
path = _pref_path(repo_root)
|
|
@@ -218,6 +297,13 @@ def _write_runtime_decision(
|
|
|
218
297
|
decisions = context.get("route_decisions")
|
|
219
298
|
if not isinstance(decisions, dict):
|
|
220
299
|
decisions = {}
|
|
300
|
+
# 同一 AI session 可能连续处理多个 Trellis 任务。写入新任务的任一路由时,
|
|
301
|
+
# 先丢弃旧任务的 runtime 决策,避免后续 check 阶段绕过 helper 时误复用上个任务的选择。
|
|
302
|
+
decisions = {
|
|
303
|
+
key: value
|
|
304
|
+
for key, value in decisions.items()
|
|
305
|
+
if isinstance(value, dict) and value.get("task") == current_task
|
|
306
|
+
}
|
|
221
307
|
decision = _decision(target, mode, source, current_task)
|
|
222
308
|
decision["decided_at"] = now
|
|
223
309
|
decisions[target] = decision
|
|
@@ -280,7 +366,7 @@ def read_runtime(args: argparse.Namespace) -> int:
|
|
|
280
366
|
|
|
281
367
|
|
|
282
368
|
def resolve_route(args: argparse.Namespace) -> int:
|
|
283
|
-
"""按 runtime → prefs 的优先级解析 route 决策。"""
|
|
369
|
+
"""按 runtime → prefs → auto-loop 的优先级解析 route 决策。"""
|
|
284
370
|
repo_root = _repo_root()
|
|
285
371
|
if repo_root is None:
|
|
286
372
|
return _print({"status": "miss", "reason": "not-trellis-project"})
|
|
@@ -337,15 +423,45 @@ def resolve_route(args: argparse.Namespace) -> int:
|
|
|
337
423
|
}
|
|
338
424
|
)
|
|
339
425
|
|
|
426
|
+
auto_mode, auto_path, auto_reason = _auto_route_mode(repo_root, context_key, args.target)
|
|
427
|
+
if auto_mode in PREF_MODES[args.target]:
|
|
428
|
+
written_path, auto_decision = _write_runtime_decision(
|
|
429
|
+
repo_root,
|
|
430
|
+
context_key,
|
|
431
|
+
current_task,
|
|
432
|
+
args.target,
|
|
433
|
+
auto_mode,
|
|
434
|
+
"auto-loop",
|
|
435
|
+
)
|
|
436
|
+
return _output(
|
|
437
|
+
args,
|
|
438
|
+
{
|
|
439
|
+
"status": "hit",
|
|
440
|
+
"origin": "auto-loop",
|
|
441
|
+
**_decision_summary(auto_decision),
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
"decision": auto_decision,
|
|
445
|
+
"path": _rel_path(repo_root, written_path),
|
|
446
|
+
"auto_path": _rel_path(repo_root, auto_path) if auto_path else None,
|
|
447
|
+
"pref_path": _rel_path(repo_root, _pref_path(repo_root)),
|
|
448
|
+
"context_key": context_key,
|
|
449
|
+
"task": current_task,
|
|
450
|
+
"wrote_runtime": True,
|
|
451
|
+
}
|
|
452
|
+
)
|
|
453
|
+
|
|
340
454
|
return _output(
|
|
341
455
|
args,
|
|
342
456
|
{
|
|
343
457
|
"status": "miss",
|
|
344
|
-
"reason": "no-valid-decision-or-
|
|
458
|
+
"reason": "no-valid-decision-pref-or-auto",
|
|
345
459
|
},
|
|
346
460
|
{
|
|
347
461
|
"path": _rel_path(repo_root, path),
|
|
348
462
|
"pref_path": _rel_path(repo_root, _pref_path(repo_root)),
|
|
463
|
+
"auto_reason": auto_reason,
|
|
464
|
+
"auto_path": _rel_path(repo_root, auto_path) if auto_path else None,
|
|
349
465
|
"context_key": context_key,
|
|
350
466
|
"task": current_task,
|
|
351
467
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
HIGHEST PRIORITY SKILL-GARDEN STATE GUARD (in_progress-inline):
|
|
3
3
|
This state block is a breadcrumb; the top-level skill-garden hub is the source of truth for route details.
|
|
4
4
|
Before the first implement route, read `<task>/brief.md` if present and restate the task brief in chat. If it is missing, read the task artifacts and suggest backfilling brief; do not silently rely on memory.
|
|
5
|
+
Before procedural or high-impact actions, run `.trellis/scripts/spec_router.py` with a short query describing the intended action and read any matched SOP/spec before acting.
|
|
5
6
|
Inline workflow-state is not an inline route decision. At Phase 2.1/2.2, reuse only an explicit target-matched `route_decision`; otherwise MUST load/read/use `trellis-route(implement|check)` (or its local `SKILL.md`) to resolve session runtime state/prefs, write the resolved decision, or show numbered fallback and wait.
|
|
6
7
|
Plain preferences, ordinary summaries, `codex-mode`, raw `.runtime` files, and empty/old prefs are not route evidence by themselves; only `trellis-route` may validate runtime route state.
|
|
7
8
|
User reselect/override/use-X-this-time/clear-default wins over remembered route evidence, runtime state, and prefs.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
HIGHEST PRIORITY SKILL-GARDEN STATE GUARD (in_progress):
|
|
3
3
|
This state block is a breadcrumb; the top-level skill-garden hub is the source of truth for route details.
|
|
4
4
|
Before the first implement route, read `<task>/brief.md` if present and restate the task brief in chat. If it is missing, read the task artifacts and suggest backfilling brief; do not silently rely on memory.
|
|
5
|
+
Before procedural or high-impact actions, run `.trellis/scripts/spec_router.py` with a short query describing the intended action and read any matched SOP/spec before acting.
|
|
5
6
|
At Phase 2.1/2.2, reuse only an explicit target-matched `route_decision`; otherwise MUST load/read/use `trellis-route(implement|check)` (or its local `SKILL.md`) to resolve session runtime state/prefs, write the resolved decision, or show numbered fallback and wait.
|
|
6
7
|
Plain preferences, ordinary summaries, `codex-mode`, raw `.runtime` files, and empty/old prefs are not route evidence by themselves; only `trellis-route` may validate runtime route state.
|
|
7
8
|
User reselect/override/use-X-this-time/clear-default wins over remembered route evidence, runtime state, and prefs.
|
|
@@ -3,6 +3,7 @@ HIGHEST PRIORITY SKILL-GARDEN STATE GUARD (no_task):
|
|
|
3
3
|
Creating or resuming a task is not implementation permission.
|
|
4
4
|
After PRD is ready and the task is started, the next implementation action is Phase 2.1 `trellis-route(implement)` unless a valid current-task implement route decision already exists.
|
|
5
5
|
If no active task exists, scan `.trellis/tasks/*/task.json` once per session for in-progress tasks with `last_push_snapshot`; surface `completed_steps` + `next_step` and suggest rebinding the active task before resuming.
|
|
6
|
+
Before procedural or high-impact actions, run `.trellis/scripts/spec_router.py` with a short query describing the intended action and read any matched SOP/spec before acting.
|
|
6
7
|
Do NOT call the harness built-in plan mode (`EnterPlanMode` / `ExitPlanMode`) for Trellis planning. It is not a substitute for Trellis task-creation consent, Trellis planning, or the route gate. For complex work, classify the turn, ask for task-creation consent, then use `trellis-brainstorm`.
|
|
7
8
|
If the turn is a meta edit to Trellis itself and Trellis tracking would be overkill, say so and ask to skip Trellis; never silently swap built-in plan mode in for the consent gate.
|
|
8
9
|
<!-- END skill-garden workflow-state no_task v0.6 -->
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
HIGHEST PRIORITY SKILL-GARDEN STATE GUARD (planning-inline):
|
|
3
3
|
Planning is not implementation permission.
|
|
4
4
|
Complete prd.md + required context first.
|
|
5
|
+
If the active workflow later routes to sub-agent execution, required context includes real curated entries in both `implement.jsonl` and `check.jsonl`; the seed `_example` row alone is not ready.
|
|
5
6
|
Before `task.py start`, use `trellis-task-brief` to refresh `brief.md` from the latest task artifacts and display it in chat for review.
|
|
7
|
+
Before procedural or high-impact actions, run `.trellis/scripts/spec_router.py` with a short query describing the intended action and read any matched SOP/spec before acting.
|
|
6
8
|
After status becomes in_progress, next action = `trellis-route(implement)`, not direct edits.
|
|
7
9
|
<!-- END skill-garden workflow-state planning_inline v0.6 -->
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
HIGHEST PRIORITY SKILL-GARDEN STATE GUARD (planning):
|
|
3
3
|
Planning is not implementation permission.
|
|
4
4
|
Complete prd.md + required context first.
|
|
5
|
+
For sub-agent-dispatch platforms, required context includes real curated entries in both `implement.jsonl` and `check.jsonl`; the seed `_example` row alone is not ready.
|
|
5
6
|
Before `task.py start`, use `trellis-task-brief` to refresh `brief.md` from the latest task artifacts and display it in chat for review.
|
|
7
|
+
Before procedural or high-impact actions, run `.trellis/scripts/spec_router.py` with a short query describing the intended action and read any matched SOP/spec before acting.
|
|
6
8
|
After status becomes in_progress, next action = `trellis-route(implement)`, not direct edits.
|
|
7
9
|
<!-- END skill-garden workflow-state planning v0.6 -->
|
|
@@ -6,10 +6,25 @@
|
|
|
6
6
|
|
|
7
7
|
**Priority**: This hub overrides any conflicting Trellis workflow, skill, or command text for the scoped behaviors below.
|
|
8
8
|
|
|
9
|
-
**Scope**: Phase 1.4 task brief handoff, Phase 2.1 implement routing, Phase 2.2 check/check-all routing, current-task route reuse, post-check stop, Phase 3.4 trellis-push, explicit Phase 3.5 finish-work bookkeeping, and push-progress recovery. State blocks should keep one short skill-garden sentinel; long-form rules live here.
|
|
9
|
+
**Scope**: project knowledge discovery for procedural/high-impact actions, Phase 1.4 task brief handoff, Phase 2.1 implement routing, Phase 2.2 check/check-all routing, current-task route reuse, post-check stop, auto-loop commit-only preauthorization, Phase 3.4 trellis-push, explicit Phase 3.5 finish-work bookkeeping, and push-progress recovery. State blocks should keep one short skill-garden sentinel; long-form rules live here.
|
|
10
10
|
|
|
11
11
|
**Mechanical rule**: use this hub as the source of truth. Do not add separate top-level skill-garden override sections or multiple skill-garden sentinels inside the same `workflow-state:*` block.
|
|
12
12
|
|
|
13
|
+
#### Project Knowledge Discovery
|
|
14
|
+
|
|
15
|
+
Before procedural or high-impact actions, run project knowledge discovery:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
python3 ./.trellis/scripts/spec_router.py "<short query describing the intended action>"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Build the query from the current user request plus relevant immediate context:
|
|
22
|
+
the intended action, commands about to run, files or systems involved, package/layer,
|
|
23
|
+
and domain words such as release, publish, deploy, migration, config, CI, workflow,
|
|
24
|
+
hooks, rollback, data fix, or destructive command.
|
|
25
|
+
|
|
26
|
+
Read any matched SOP/spec files before acting; if nothing matches, continue normally.
|
|
27
|
+
|
|
13
28
|
#### Task Brief Handoff
|
|
14
29
|
|
|
15
30
|
Before Phase 1.4 `task.py start`, use `trellis-task-brief` to refresh `<task>/brief.md` from latest task artifacts, display it in chat, and wait for user confirmation.
|
|
@@ -41,6 +56,8 @@ After `trellis-check` or `trellis-check-all` finishes, stop and report the resul
|
|
|
41
56
|
|
|
42
57
|
If checks pass, the next allowed workflow steps are Phase 3.3 `trellis-update-spec` and Phase 3.4 `trellis-push`/commit confirmation. `/trellis:finish-work` is explicit-only: run it only after Phase 3.4 is complete and the user asks to wrap up, archive, or finish the task.
|
|
43
58
|
|
|
59
|
+
During a running `trellis-auto-loop`, the runner's `record` + `next` replaces the post-check stop gate: after a check pass, record the result, then continue to spec update / commit-only according to `.trellis/scripts/auto_loop.py`. Outside auto-loop, keep the normal stop gate.
|
|
60
|
+
|
|
44
61
|
#### Code Commit Confirmation Gate
|
|
45
62
|
|
|
46
63
|
Code commit/push belongs only to Phase 3.4 and must go through `trellis-push`; the main session must not run bare `git commit` / `git push` for code.
|
|
@@ -49,6 +66,12 @@ Code commit/push belongs only to Phase 3.4 and must go through `trellis-push`; t
|
|
|
49
66
|
|
|
50
67
|
For "commit now, push later", use `trellis-push` commit-only mode; the later push still goes through `trellis-push`. `session_auto_commit` never authorizes code commits; it only affects bookkeeping commits below.
|
|
51
68
|
|
|
69
|
+
#### Auto-loop Commit-only Preauthorization
|
|
70
|
+
|
|
71
|
+
When the user explicitly starts `trellis-auto-loop` with `profile=commit-only`, that start preauthorizes only task-related local commits inside that run. When `.trellis/scripts/auto_loop.py status` reports `run_status=running`, `profile=commit-only`, and `outstanding_action.action=commit_only` for the active task, `trellis-push` may execute commit-only without an additional chat confirmation if the plan contains only files attributable to the current task, performs no push/merge/release/archive, and records the commit hash back to the runner.
|
|
72
|
+
|
|
73
|
+
This exception does not apply to ordinary `trellis-push`. If the plan contains unrecognized staged files, conflicts, dirty files that cannot be attributed safely, push/merge/release/archive intent, external systems, credentials, or production data effects, stop or mark the current auto-loop task blocked.
|
|
74
|
+
|
|
52
75
|
#### Bookkeeping Auto-commit Scope
|
|
53
76
|
|
|
54
77
|
`session_auto_commit` only governs the bookkeeping commits `task.py archive` / `add_session.py` make for their own `.trellis/tasks/**` and `.trellis/workspace/**` files — never code (gated above). When `false`, those archive/journal writes stay disk-only (no compensating `git commit`).
|